Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions traffic_control/models/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 []))
Expand Down
22 changes: 10 additions & 12 deletions traffic_control/tests/wfs/test_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,6 @@
wfs_get_features_gml,
)

EXPECTED_MULTIPOLYGON_XML = (
'<ns0:MultiGeometry xmlns:ns0="http://www.opengis.net/gml/3.2" '
'ns0:id="plan.{object_id}.1" '
'srsName="urn:ogc:def:crs:EPSG::3879"><ns0:Polygon><ns0:exterior><ns0:LinearRing><ns0:posList '
'srsDimension="3">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</ns0:posList></ns0:LinearRing></ns0:exterior></ns0:Polygon></ns0:MultiGeometry>"
)

EXPECTED_MULTIPOLYGON_COORDINATES = [
[
[
Expand All @@ -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():
Expand All @@ -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)


Expand Down
4 changes: 2 additions & 2 deletions traffic_control/views/wfs/plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."),
Expand All @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions traffic_control/views/wfs/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)