diff --git a/boranga/components/spatial/utils.py b/boranga/components/spatial/utils.py
index 2c5ef773c..00a09e5c8 100644
--- a/boranga/components/spatial/utils.py
+++ b/boranga/components/spatial/utils.py
@@ -50,6 +50,8 @@ def invert_xy_coordinates(geometries):
def intersect_geometry_with_layer(geometry, intersect_layer, geometry_name="SHAPE"):
+ """Query a geoserver WFS layer with a geometry and return the intersecting features as JSON."""
+
geoserver_url = intersect_layer.geoserver_url
intersect_layer_name = intersect_layer.layer_name
invert_xy = intersect_layer.invert_xy
@@ -58,6 +60,22 @@ def intersect_geometry_with_layer(geometry, intersect_layer, geometry_name="SHAP
if invert_xy:
test_geom = invert_xy_coordinates([geometry])[0]
+ if test_geom.geom_type in ["MultiPoint"]:
+ # For some unknown silly reason, geoserver's jts cannot handle valid single-bracketed multipoint geometries,
+ # e.g. MULTIPOINT (3 1, 4 1, 5 2), and rather throws unintelligible java class exceptions at me, so we
+ # have to convert them to a double-bracket notation in the form of MULTIPOINT ((3 1), (4 1), (5 2)). Even
+ # though both forms are (topologically) valid by OGC definition, the jts (java topology suite) library only
+ # seems to except singleton lists (https://www.tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/io/WKTReader.html)
+ logger.warn(
+ f"Converting MultiPoint geometry {test_geom} to double-bracket notation"
+ )
+ test_geom_wkt = (
+ f'MULTIPOINT ({", ".join([f"({c[0]} {c[1]})" for c in test_geom.coords])})'
+ )
+ else:
+ test_geom_wkt = test_geom.wkt
+
+ wkt.loads(test_geom.wkt)
params = {
"service": "WFS",
"version": "2.0.0",
@@ -67,7 +85,7 @@ def intersect_geometry_with_layer(geometry, intersect_layer, geometry_name="SHAP
"srsName": "EPSG:4326", # using the default projection for open layers and geodjango
"outputFormat": "application/json",
"propertyName": f"{geometry_name},CAD_OWNER_NAME,CAD_OWNER_COUNT",
- "CQL_FILTER": f"INTERSECTS({geometry_name}, {test_geom.wkt})",
+ "CQL_FILTER": f"INTERSECTS({geometry_name}, {test_geom_wkt})",
}
request_path = (
@@ -142,16 +160,15 @@ def populate_occurrence_tenure_data(geometry_instance, features, request):
else:
occurrence_tenures = OccurrenceTenure.objects.filter(
tenure_area_id=feature_id
- ).exclude(occurrence_geometry=None,tenure_area_id=None)
+ ).exclude(occurrence_geometry=None, tenure_area_id=None)
occurrence_tenures_current = occurrence_tenures.filter(
- occurrence_geometry=geometry_instance,
- status="current"
+ occurrence_geometry=geometry_instance, status="current"
)
occurrence_tenures_historical = occurrence_tenures.filter(
historical_occurrence=geometry_instance.occurrence.id,
- status="historical"
+ status="historical",
)
if occurrence_tenures_current.exists():
@@ -298,7 +315,7 @@ def save_geometry(
InstanceCopiedFrom
)
- opacity = feature.get("properties", {}).get("opacity", .5)
+ opacity = feature.get("properties", {}).get("opacity", 0.5)
geom_4326 = feature_json_to_geosgeometry(feature)
@@ -454,9 +471,20 @@ def save_geometry(
# or have been drawn by another user
geometry_ids = list(geometry_id_intersect_data.keys())
if instance_fk_field_name == "occurrence":
- affected_tenure_ids = list(OccurrenceTenure.objects.filter(occurrence_geometry__in=(InstanceGeometry.objects.filter(**{instance_fk_field_name: instance})
- .exclude(Q(id__in=geometry_ids) | Q(locked=True) | ~Q(drawn_by=request.user.id)))).values_list("id",flat=True))
-
+ affected_tenure_ids = list(
+ OccurrenceTenure.objects.filter(
+ occurrence_geometry__in=(
+ InstanceGeometry.objects.filter(
+ **{instance_fk_field_name: instance}
+ ).exclude(
+ Q(id__in=geometry_ids)
+ | Q(locked=True)
+ | ~Q(drawn_by=request.user.id)
+ )
+ )
+ ).values_list("id", flat=True)
+ )
+
deleted_geometries = (
InstanceGeometry.objects.filter(**{instance_fk_field_name: instance})
.exclude(Q(id__in=geometry_ids) | Q(locked=True) | ~Q(drawn_by=request.user.id))
@@ -466,9 +494,9 @@ def save_geometry(
logger.info(
f"Deleted {instance_model_name} geometries: {deleted_geometries} for {instance}"
)
-
+
if instance_fk_field_name == "occurrence":
- #we save affected tenures to record the historical change
+ # we save affected tenures to record the historical change
affected_tenures = OccurrenceTenure.objects.filter(id__in=affected_tenure_ids)
for i in affected_tenures:
i.save(version_user=request.user)
diff --git a/boranga/frontend/boranga/src/components/common/component_map.vue b/boranga/frontend/boranga/src/components/common/component_map.vue
index 1b03702d7..2e48a2214 100644
--- a/boranga/frontend/boranga/src/components/common/component_map.vue
+++ b/boranga/frontend/boranga/src/components/common/component_map.vue
@@ -364,6 +364,53 @@
stroke-width="2"
/>
+