From 77d729cf4acc5a78ed99c4976b605e4a758ad9db Mon Sep 17 00:00:00 2001 From: Janne Forsman Date: Mon, 3 Feb 2025 17:24:41 +0200 Subject: [PATCH] fix: Plan WFS now uses convex_hull instead of Multipolygon as geometry type * This is done so QGIS knows how to show locations as with MultiPolygons behaviour was very wierd * does not affect json rendering Refs: LIIK-723 --- traffic_control/models/plan.py | 6 ++++++ traffic_control/tests/wfs/test_plan.py | 22 ++++++++++------------ traffic_control/views/wfs/plan.py | 4 ++-- traffic_control/views/wfs/utils.py | 5 +++++ 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/traffic_control/models/plan.py b/traffic_control/models/plan.py index 43474700..53827eca 100644 --- a/traffic_control/models/plan.py +++ b/traffic_control/models/plan.py @@ -10,6 +10,7 @@ from django.core.validators import RegexValidator from django.utils.translation import gettext_lazy as _ +from traffic_control.geometry_utils import get_3d_geometry from traffic_control.mixins.models import ( BoundaryCheckedLocationMixin, SoftDeleteModel, @@ -103,6 +104,11 @@ class Meta: def __str__(self): return f"{self.decision_id} {self.name}" + @property + def convex_hull_location(self): + """This always forces 3d geometry""" + return get_3d_geometry(self.location.convex_hull, 0.0) + def save(self, *args, **kwargs): # Make drawing numbers a unique sorted list self.drawing_numbers = sorted(set(self.drawing_numbers or [])) diff --git a/traffic_control/tests/wfs/test_plan.py b/traffic_control/tests/wfs/test_plan.py index cd4c56c4..0c66feaf 100644 --- a/traffic_control/tests/wfs/test_plan.py +++ b/traffic_control/tests/wfs/test_plan.py @@ -16,16 +16,6 @@ wfs_get_features_gml, ) -EXPECTED_MULTIPOLYGON_XML = ( - '6645450.071 25487920.144 0.0 6645451.071 25487920.144 0.0 ' - "6645451.071 25487921.144 0.0 6645450.071 25487921.144 0.0 6645450.071 " - "25487920.144 " - "0.0" -) - EXPECTED_MULTIPOLYGON_COORDINATES = [ [ [ @@ -38,6 +28,14 @@ ] ] +EXPECTED_POLYGON_LOCATION = ( + "6645450.071 25487920.144 0.0 " + "6645451.071 25487920.144 0.0 " + "6645451.071 25487921.144 0.0 " + "6645450.071 25487921.144 0.0 " + "6645450.071 25487920.144 0.0" +) + @pytest.mark.django_db def test__wfs_plan__gml(): @@ -51,8 +49,8 @@ def test__wfs_plan__gml(): assert gml_feature_id(feature) == f"plan.{plan.id}" # Ensure the coordinate order is [Y,X,Z] EPSG:3879 - assert gml_feature_geometry(feature, "MultiPolygon") == EXPECTED_MULTIPOLYGON_XML.format(object_id=plan.id) - assert gml_feature_crs(feature, "MultiPolygon") == EPSG_3879_URN + assert gml_feature_geometry(feature, "Polygon") == EXPECTED_POLYGON_LOCATION + assert gml_feature_crs(feature, "Polygon") == EPSG_3879_URN _assert_envelope(feature) diff --git a/traffic_control/views/wfs/plan.py b/traffic_control/views/wfs/plan.py index f26ff514..83f8d91e 100644 --- a/traffic_control/views/wfs/plan.py +++ b/traffic_control/views/wfs/plan.py @@ -9,11 +9,12 @@ SOURCE_CONTROLLED_MODEL_FIELDS, USER_CONTROLLED_MODEL_FIELDS, ) +from traffic_control.views.wfs.utils import ConvexHullLocationXsdElement _fields = ( [ FeatureField("id", abstract="ID of the Plan."), - FeatureField("location", abstract="Plan's location (Multipolygon) in EPSG:3879 coordinates."), + FeatureField("location", xsd_class=ConvexHullLocationXsdElement, abstract="Location of the Plan."), FeatureField("name", abstract="Name of the Plan."), FeatureField("decision_id", abstract="Decision ID of the Plan."), FeatureField("diary_number", abstract="Diary numbger of the Plan."), @@ -23,7 +24,6 @@ abstract="Derive the plan location (geometry area) from the locations of related devices.", ), FeatureField("decision_date", abstract="Decision date of the Plan."), - FeatureField("decision_url", abstract="Decision date of the Plan."), FeatureField("decision_url", abstract="URL to the decision of the Plan."), ] + deepcopy(SOURCE_CONTROLLED_MODEL_FIELDS) diff --git a/traffic_control/views/wfs/utils.py b/traffic_control/views/wfs/utils.py index b21a0f3b..e6ffd195 100644 --- a/traffic_control/views/wfs/utils.py +++ b/traffic_control/views/wfs/utils.py @@ -141,3 +141,8 @@ def get_value(self, instance: models.Model): class CentroidLocationXsdElement(XsdElement): def get_value(self, instance: models.Model): return getattr(instance, "centroid_location", None) + + +class ConvexHullLocationXsdElement(XsdElement): + def get_value(self, instance: models.Model): + return getattr(instance, "convex_hull_location", None)