Compare commits

..

No commits in common. "a7a0044fc5de4ccdb4f5ff05353a87e069e262de" and "36552b3886b8e0edb547774d409c10ec71be38cd" have entirely different histories.

3 changed files with 17 additions and 36 deletions

View File

@ -35,7 +35,6 @@ class SimpleGeomForm(BaseForm):
disabled=False, disabled=False,
) )
_num_geometries_ignored: int = 0 _num_geometries_ignored: int = 0
empty = False
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.read_only = kwargs.pop("read_only", True) self.read_only = kwargs.pop("read_only", True)
@ -50,7 +49,7 @@ class SimpleGeomForm(BaseForm):
raise AttributeError raise AttributeError
geojson = self.instance.geometry.as_feature_collection(srid=DEFAULT_SRID_RLP) geojson = self.instance.geometry.as_feature_collection(srid=DEFAULT_SRID_RLP)
geojson = self._set_geojson_properties(geojson, title=self.instance.identifier or None) self._set_geojson_properties(geojson, title=self.instance.identifier or None)
geom = json.dumps(geojson) geom = json.dumps(geojson)
except AttributeError: except AttributeError:
# If no geometry exists for this form, we simply set the value to None and zoom to the maximum level # If no geometry exists for this form, we simply set the value to None and zoom to the maximum level
@ -63,29 +62,21 @@ class SimpleGeomForm(BaseForm):
super().is_valid() super().is_valid()
is_valid = True is_valid = True
# Make sure invalid geometry is properly rendered again to the user # Get geojson from form
# Therefore: write submitted data back into form field
# (does not matter whether we know if it is valid or invalid)
submitted_data = self.data["output"]
submitted_data = json.loads(submitted_data)
submitted_data = self._set_geojson_properties(submitted_data)
self.initialize_form_field("output", json.dumps(submitted_data))
# Get geojson from form for validity checking
geom = self.data.get("output", None) geom = self.data.get("output", None)
geom_is_empty = geom is None or len(geom) == 0 if geom is None or len(geom) == 0:
if geom_is_empty: # empty geometry is a valid geometry
# If no geometry has been submitted, we create an empty geometry object since
# an empty geometry is a valid geometry
self.cleaned_data["output"] = MultiPolygon(srid=DEFAULT_SRID_RLP).ewkt self.cleaned_data["output"] = MultiPolygon(srid=DEFAULT_SRID_RLP).ewkt
return is_valid return is_valid
geom = json.loads(geom)
# Write submitted data back into form field to make sure invalid geometry
# will be rendered again on failed submit
self.initialize_form_field("output", self.data["output"])
# Initialize features list with empty MultiPolygon, so that an empty input will result in a # Initialize features list with empty MultiPolygon, so that an empty input will result in a
# proper empty MultiPolygon object # proper empty MultiPolygon object
features = [] features = []
# Prepare geometry for validity checks (create iterable dict)
geom = json.loads(geom)
features_json = geom.get("features", []) features_json = geom.get("features", [])
accepted_ogr_types = [ accepted_ogr_types = [
"Polygon", "Polygon",
@ -93,23 +84,20 @@ class SimpleGeomForm(BaseForm):
"MultiPolygon", "MultiPolygon",
"MultiPolygon25D", "MultiPolygon25D",
] ]
# Check validity for each feature of the geometry
for feature in features_json: for feature in features_json:
feature_geom = feature.get("geometry", feature) feature_geom = feature.get("geometry", feature)
if feature_geom is None: if feature_geom is None:
# Fallback for rare cases where a feature does not contain any geometry # Fallback for rare cases where a feature does not contain any geometry
continue continue
# Try to create a geometry object from the single feature
feature_geom = json.dumps(feature_geom) feature_geom = json.dumps(feature_geom)
g = gdal.OGRGeometry(feature_geom, srs=DEFAULT_SRID_RLP) g = gdal.OGRGeometry(feature_geom, srs=DEFAULT_SRID_RLP)
geometry_has_unwanted_dimensions = g.coord_dim > 2 flatten_geometry = g.coord_dim > 2
if geometry_has_unwanted_dimensions: if flatten_geometry:
g = self.__flatten_geom_to_2D(g) g = self.__flatten_geom_to_2D(g)
geometry_type_is_accepted = g.geom_type not in accepted_ogr_types if g.geom_type not in accepted_ogr_types:
if geometry_type_is_accepted:
self.add_error("output", _("Only surfaces allowed. Points or lines must be buffered.")) self.add_error("output", _("Only surfaces allowed. Points or lines must be buffered."))
is_valid &= False is_valid &= False
return is_valid return is_valid
@ -121,23 +109,18 @@ class SimpleGeomForm(BaseForm):
self._num_geometries_ignored += 1 self._num_geometries_ignored += 1
continue continue
# Whatever this geometry object is -> try to create a Polygon from it
# The resulting polygon object automatically detects whether a valid polygon has been created or not
g = Polygon.from_ewkt(g.ewkt) g = Polygon.from_ewkt(g.ewkt)
is_valid &= g.valid is_valid &= g.valid
if not g.valid: if not g.valid:
self.add_error("output", g.valid_reason) self.add_error("output", g.valid_reason)
return is_valid return is_valid
# If the resulting polygon is just a single polygon, we add it to the list of properly casted features
if isinstance(g, Polygon): if isinstance(g, Polygon):
features.append(g) features.append(g)
elif isinstance(g, MultiPolygon): elif isinstance(g, MultiPolygon):
# The resulting polygon could be of type MultiPolygon (due to multiple surfaces)
# If so, we extract all polygons from the MultiPolygon and extend the casted features list
features.extend(list(g)) features.extend(list(g))
# Unionize all polygon features into one new MultiPolygon # Unionize all geometry features into one new MultiPolygon
if features: if features:
form_geom = MultiPolygon(*features, srid=DEFAULT_SRID_RLP).unary_union form_geom = MultiPolygon(*features, srid=DEFAULT_SRID_RLP).unary_union
else: else:
@ -146,7 +129,7 @@ class SimpleGeomForm(BaseForm):
# Make sure to convert into a MultiPolygon. Relevant if a single Polygon is provided. # Make sure to convert into a MultiPolygon. Relevant if a single Polygon is provided.
form_geom = Geometry.cast_to_multipolygon(form_geom) form_geom = Geometry.cast_to_multipolygon(form_geom)
# Write unionized Multipolygon back into cleaned data # Write unioned Multipolygon into cleaned data
if self.cleaned_data is None: if self.cleaned_data is None:
self.cleaned_data = {} self.cleaned_data = {}
self.cleaned_data["output"] = form_geom.ewkt self.cleaned_data["output"] = form_geom.ewkt
@ -269,8 +252,6 @@ class SimpleGeomForm(BaseForm):
""" """
features = geojson.get("features", []) features = geojson.get("features", [])
for feature in features: for feature in features:
if not feature.get("properties", None):
feature["properties"] = {}
feature["properties"]["editable"] = not self.read_only feature["properties"]["editable"] = not self.read_only
if title: if title:
feature["properties"]["title"] = title feature["properties"]["title"] = title

View File

@ -11,4 +11,4 @@ BASE_TITLE = "KSP - Kompensationsverzeichnis Service Portal"
BASE_FRONTEND_TITLE = "Kompensationsverzeichnis Service Portal" BASE_FRONTEND_TITLE = "Kompensationsverzeichnis Service Portal"
TAB_TITLE_IDENTIFIER = "tab_title" TAB_TITLE_IDENTIFIER = "tab_title"
HELP_LINK = "https://dienste.naturschutz.rlp.de/doku/doku.php?id=ksp2:start" HELP_LINK = "https://dienste.naturschutz.rlp.de/doku/doku.php?id=ksp2:start"
IMPRESSUM_LINK = "https://naturschutz.rlp.de/ueber-uns/impressum" IMPRESSUM_LINK = "https://naturschutz.rlp.de/index.php?q=impressum"

View File

@ -13,9 +13,9 @@
</div> </div>
{% endif %} {% endif %}
{% if geom_form.output.errors %} {% if geom_form.geom.errors %}
<div class="alert-danger p-2"> <div class="alert-danger p-2">
{% for error in geom_form.output.errors %} {% for error in geom_form.geom.errors %}
<strong class="invalid">{{ error }}</strong> <strong class="invalid">{{ error }}</strong>
<br> <br>
{% endfor %} {% endfor %}