Merge pull request '565 unify geometry quality checking' (#582) from 565_Unify_geometry_quality_checking into master

Reviewed-on: #582
This commit was merged in pull request #582.
This commit is contained in:
2026-09-12 17:58:55 +02:00
14 changed files with 431 additions and 352 deletions
@@ -1,5 +1,5 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
],
"properties": {
@@ -1,5 +1,5 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
],
"properties": {
@@ -1,5 +1,5 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
],
"properties": {
@@ -1,5 +1,5 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
],
"properties": {
@@ -1,46 +1,28 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
[
[
[
[
7.845568656921382,
50.79829702304368
],
[
7.837371826171871,
50.80155187891526
],
[
7.835698127746578,
50.805267562209806
],
[
7.841062545776364,
50.806623577403386
],
[
7.848916053771969,
50.808359219420474
],
[
7.855696678161618,
50.807057493952975
],
[
7.854666709899899,
50.80423696434001
],
[
7.850461006164548,
50.80217570040005
],
[
7.845568656921382,
50.79829702304368
]
]
7.489245186249832,
50.29519575559556
],
[
7.5244137991026605,
50.29519575559556
],
[
7.5244137991026605,
50.275124048323875
],
[
7.489245186249832,
50.275124048323875
],
[
7.489245186249832,
50.29519575559556
]
]
],
"properties": {
"title": "TEST_compensation_CHANGED",
@@ -1,46 +1,28 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
[
[
[
[
7.845568656921382,
50.79829702304368
],
[
7.837371826171871,
50.80155187891526
],
[
7.835698127746578,
50.805267562209806
],
[
7.841062545776364,
50.806623577403386
],
[
7.848916053771969,
50.808359219420474
],
[
7.855696678161618,
50.807057493952975
],
[
7.854666709899899,
50.80423696434001
],
[
7.850461006164548,
50.80217570040005
],
[
7.845568656921382,
50.79829702304368
]
]
7.489245186249832,
50.29519575559556
],
[
7.5244137991026605,
50.29519575559556
],
[
7.5244137991026605,
50.275124048323875
],
[
7.489245186249832,
50.275124048323875
],
[
7.489245186249832,
50.29519575559556
]
]
],
"properties": {
"title": "TEST_account_CHANGED",
+21 -39
View File
@@ -1,46 +1,28 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
[
[
[
[
7.845568656921382,
50.79829702304368
],
[
7.837371826171871,
50.80155187891526
],
[
7.835698127746578,
50.805267562209806
],
[
7.841062545776364,
50.806623577403386
],
[
7.848916053771969,
50.808359219420474
],
[
7.855696678161618,
50.807057493952975
],
[
7.854666709899899,
50.80423696434001
],
[
7.850461006164548,
50.80217570040005
],
[
7.845568656921382,
50.79829702304368
]
]
7.489245186249832,
50.29519575559556
],
[
7.5244137991026605,
50.29519575559556
],
[
7.5244137991026605,
50.275124048323875
],
[
7.489245186249832,
50.275124048323875
],
[
7.489245186249832,
50.29519575559556
]
]
],
"properties": {
"title": "TEST_EMA_CHANGED",
@@ -1,46 +1,28 @@
{
"type": "MultiPolygon",
"type": "Polygon",
"coordinates": [
[
[
[
[
7.845568656921382,
50.79829702304368
],
[
7.837371826171871,
50.80155187891526
],
[
7.835698127746578,
50.805267562209806
],
[
7.841062545776364,
50.806623577403386
],
[
7.848916053771969,
50.808359219420474
],
[
7.855696678161618,
50.807057493952975
],
[
7.854666709899899,
50.80423696434001
],
[
7.850461006164548,
50.80217570040005
],
[
7.845568656921382,
50.79829702304368
]
]
7.489245186249832,
50.29519575559556
],
[
7.5244137991026605,
50.29519575559556
],
[
7.5244137991026605,
50.275124048323875
],
[
7.489245186249832,
50.275124048323875
],
[
7.489245186249832,
50.29519575559556
]
]
],
"properties": {
"title": "Test_intervention_CHANGED",
+10 -9
View File
@@ -9,10 +9,11 @@ Created on: 28.01.22
import json
from django.contrib.gis import geos
from django.contrib.gis.geos import MultiPolygon
from django.urls import reverse
from api.tests.v1.share.test_api_sharing import BaseAPIV1TestCase
from konova.models import Geometry
from konova.utils.geometry.geometry_validator import GeometryProcessor
class APIV1UpdateTestCase(BaseAPIV1TestCase):
@@ -64,8 +65,8 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
put_props = put_body["properties"]
put_geom = geos.fromstr(json.dumps(put_body))
put_geom = Geometry.cast_to_rlp_srid(put_geom)
self.assertEqual(put_geom, self.intervention.geometry.geom)
put_geom = MultiPolygon(GeometryProcessor.cast_to_rlp_srid(put_geom))
self.assertTrue(put_geom.equals_exact(self.intervention.geometry.geom,0.00001))
self.assertEqual(put_props["title"], self.intervention.title)
self.assertNotEqual(modified_on, self.intervention.modified)
self.assertEqual(put_props["responsible"]["registration_file_number"], self.intervention.responsible.registration_file_number)
@@ -94,8 +95,8 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
put_props = put_body["properties"]
put_geom = geos.fromstr(json.dumps(put_body))
put_geom = Geometry.cast_to_rlp_srid(put_geom)
self.assertEqual(put_geom, self.compensation.geometry.geom)
put_geom = MultiPolygon(GeometryProcessor.cast_to_rlp_srid(put_geom))
self.assertTrue(put_geom.equals_exact(self.compensation.geometry.geom, 0.00001))
self.assertEqual(put_props["title"], self.compensation.title)
self.assertNotEqual(modified_on, self.compensation.modified)
self.assertEqual(put_props["is_cef"], self.compensation.is_cef)
@@ -124,8 +125,8 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
put_props = put_body["properties"]
put_geom = geos.fromstr(json.dumps(put_body))
put_geom = Geometry.cast_to_rlp_srid(put_geom)
self.assertEqual(put_geom, self.eco_account.geometry.geom)
put_geom = MultiPolygon(GeometryProcessor.cast_to_rlp_srid(put_geom))
self.assertTrue(put_geom.equals_exact(self.eco_account.geometry.geom, 0.00001))
self.assertEqual(put_props["title"], self.eco_account.title)
self.assertNotEqual(modified_on, self.eco_account.modified)
self.assertEqual(put_props["deductable_surface"], str(self.eco_account.deductable_surface))
@@ -156,8 +157,8 @@ class APIV1UpdateTestCase(BaseAPIV1TestCase):
put_props = put_body["properties"]
put_geom = geos.fromstr(json.dumps(put_body))
put_geom = Geometry.cast_to_rlp_srid(put_geom)
self.assertEqual(put_geom, self.ema.geometry.geom)
put_geom = MultiPolygon(GeometryProcessor.cast_to_rlp_srid(put_geom))
self.assertTrue(put_geom.equals_exact(self.ema.geometry.geom,0.00001))
self.assertEqual(put_props["title"], self.ema.title)
self.assertNotEqual(modified_on, self.ema.modified)
self.assertEqual(put_props["responsible"]["conservation_office"], self.ema.responsible.conservation_office)
+16 -10
View File
@@ -17,6 +17,8 @@ from django.db.models import Q
from api.models import ExternalIdentifier
from konova.models import Geometry
from konova.sub_settings.lanis_settings import DEFAULT_SRID
from konova.utils.geometry.geometry_validator import GeoJsonValidator
from konova.utils.message_templates import DATA_UNSHARED
@@ -156,16 +158,20 @@ class AbstractModelAPISerializer:
Returns:
geometry (GEOSGeometry)
"""
if isinstance(geojson, dict):
geojson = json.dumps(geojson)
geometry = geos.fromstr(geojson)
if not geometry.valid:
raise ValueError(f"Invalid geometry: {geometry.valid_reason}")
is_4326 = Geometry.is_valid_4326(geometry)
if not is_4326:
raise ValueError("Geometry not in EPSG:4326 (WGS84). Unknown spatial reference system.")
geometry = Geometry.cast_to_rlp_srid(geometry)
geometry = Geometry.cast_to_multipolygon(geometry)
if isinstance(geojson, str):
geojson = json.loads(geojson)
geojson_validator = GeoJsonValidator(geojson, DEFAULT_SRID)
geojson_validator.validate()
if geojson_validator.errors:
raise ValueError(geojson_validator.errors)
geometry = geojson_validator.validated_geometry
is_input_geometry_too_small = geometry.area == 0.0 and geojson_validator.num_ignored_geometries > 0
if is_input_geometry_too_small:
raise ValueError(f"Your area was too small to be processed! Must be > 1m²!")
return geometry
def _get_obj_from_db(self, id, user):