#138 WIP Validity
* adds geometry validity checks for SimpleGeomForm is_valid() * shows validity problems on the form if a feature is invalid * optimizes merging of different features into one MultiPolygon * further enhances tests * adds as_feature_collection() method on Geometry model for converting geom MultiPolygon attribute into FeatureCollection json holding each polygon as an own feature -> makes each polygon selectable in new netgis map client
This commit is contained in:
parent
8d34580090
commit
5e65156b54
@ -128,6 +128,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
|
||||
new_identifier = self.create_dummy_string()
|
||||
new_comment = self.create_dummy_string()
|
||||
new_geometry = MultiPolygon(srid=4326) # Create an empty geometry
|
||||
geojson = self.create_geojson(new_geometry)
|
||||
|
||||
check_on_elements = {
|
||||
self.compensation.title: new_title,
|
||||
@ -142,7 +143,7 @@ class CompensationWorkflowTestCase(BaseWorkflowTestCase):
|
||||
"title": new_title,
|
||||
"intervention": self.intervention.id, # just keep the intervention as it is
|
||||
"comment": new_comment,
|
||||
"geom": new_geometry.geojson,
|
||||
"geom": geojson,
|
||||
}
|
||||
self.client_user.post(url, post_data)
|
||||
self.compensation.refresh_from_db()
|
||||
|
@ -17,8 +17,8 @@ from django.db.models.fields.files import FieldFile
|
||||
|
||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
||||
from user.models import User
|
||||
from django.contrib.gis.forms import OSMWidget, MultiPolygonField
|
||||
from django.contrib.gis.geos import MultiPolygon, GEOSGeometry, Polygon
|
||||
from django.contrib.gis.forms import MultiPolygonField
|
||||
from django.contrib.gis.geos import MultiPolygon, Polygon
|
||||
from django.db import transaction
|
||||
from django.http import HttpRequest, HttpResponseRedirect
|
||||
from django.shortcuts import render
|
||||
@ -291,11 +291,13 @@ class SimpleGeomForm(BaseForm):
|
||||
# Initialize geometry
|
||||
try:
|
||||
geom = self.instance.geometry.geom
|
||||
geom.transform(ct=DEFAULT_SRID_RLP)
|
||||
self.empty = geom.empty
|
||||
|
||||
if self.empty:
|
||||
raise AttributeError
|
||||
geom = geom.geojson
|
||||
|
||||
geojson = self.instance.geometry.as_feature_collection(srid=DEFAULT_SRID_RLP)
|
||||
geom = json.dumps(geojson)
|
||||
except AttributeError:
|
||||
# If no geometry exists for this form, we simply set the value to None and zoom to the maximum level
|
||||
geom = ""
|
||||
@ -326,19 +328,26 @@ class SimpleGeomForm(BaseForm):
|
||||
self.add_error("geom", _("Only surfaces allowed. Points or lines must be buffered."))
|
||||
is_valid = False
|
||||
return is_valid
|
||||
features.append(g)
|
||||
if len(features) > 0:
|
||||
form_geom = features[0]
|
||||
for g in features[1:]:
|
||||
form_geom = form_geom.union(g)
|
||||
form_geom.transform(coord_trans=DEFAULT_SRID)
|
||||
|
||||
polygon = Polygon.from_ewkt(g.ewkt)
|
||||
is_valid = polygon.valid
|
||||
if not is_valid:
|
||||
self.add_error("geom", polygon.valid_reason)
|
||||
return is_valid
|
||||
|
||||
features.append(polygon)
|
||||
form_geom = MultiPolygon(srid=DEFAULT_SRID_RLP)
|
||||
for feature in features:
|
||||
form_geom = form_geom.union(feature)
|
||||
|
||||
# Make sure to convert into a MultiPolygon. Relevant if a single Polygon is provided.
|
||||
if form_geom.geom_type != "MultiPolygon":
|
||||
form_geom = MultiPolygon(MultiPolygon.from_ewkt(form_geom.ewkt))
|
||||
form_geom = MultiPolygon(form_geom, srid=DEFAULT_SRID_RLP)
|
||||
|
||||
# Write unioned Multipolygon into cleaned data
|
||||
if self.cleaned_data is None:
|
||||
self.cleaned_data = {}
|
||||
self.cleaned_data["geom"] = form_geom.wkt
|
||||
self.cleaned_data["geom"] = form_geom.ewkt
|
||||
|
||||
return is_valid
|
||||
|
||||
|
@ -5,11 +5,15 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 15.11.21
|
||||
|
||||
"""
|
||||
import json
|
||||
|
||||
from django.contrib.gis.db.models import MultiPolygonField
|
||||
from django.contrib.gis.geos import Polygon
|
||||
from django.db import models, transaction
|
||||
from django.utils import timezone
|
||||
|
||||
from konova.models import BaseResource, UuidModel
|
||||
from konova.sub_settings.lanis_settings import DEFAULT_SRID_RLP
|
||||
from konova.utils.wfs.spatial import ParcelWFSFetcher
|
||||
|
||||
|
||||
@ -179,6 +183,34 @@ class Geometry(BaseResource):
|
||||
|
||||
return parcels
|
||||
|
||||
def as_feature_collection(self, srid=DEFAULT_SRID_RLP):
|
||||
""" Returns a FeatureCollection structure holding all polygons of the MultiPolygon as single features
|
||||
|
||||
This method is used to convert a single MultiPolygon into multiple Polygons, which can be used as separated
|
||||
features in the NETGIS map client.
|
||||
|
||||
Args:
|
||||
srid (int): The spatial reference system identifier to be transformed to
|
||||
|
||||
Returns:
|
||||
geojson (dict): The FeatureCollection json (as dict)
|
||||
"""
|
||||
geom = self.geom
|
||||
geom.transform(ct=srid)
|
||||
|
||||
polygons = []
|
||||
for coords in geom.coords:
|
||||
p = Polygon(coords[0], srid=geom.srid)
|
||||
polygons.append(p)
|
||||
geojson = {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
json.loads(x.geojson) for x in polygons
|
||||
]
|
||||
}
|
||||
return geojson
|
||||
|
||||
|
||||
|
||||
class GeometryConflict(UuidModel):
|
||||
"""
|
||||
|
@ -432,11 +432,12 @@ class BaseTestCase(TestCase):
|
||||
return
|
||||
|
||||
if geom1.srid != geom2.srid:
|
||||
tolerance = 0.001
|
||||
# Due to prior possible transformation of any of these geometries, we need to make sure there exists a
|
||||
# transformation from one coordinate system into the other, which is valid
|
||||
geom1_t = geom1.transform(geom2.srid, clone=True)
|
||||
geom2_t = geom2.transform(geom1.srid, clone=True)
|
||||
self.assertTrue(geom1_t.equals(geom2) or geom2_t.equals(geom1))
|
||||
self.assertTrue(geom1_t.equals_exact(geom2, tolerance) or geom2_t.equals_exact(geom1, tolerance))
|
||||
else:
|
||||
self.assertTrue(geom1.equals(geom2))
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user