#49 Parcels and Districts

* fixes bug in GeometryConflict conflict checking
* WIP: introduces new konova/utils/wfs/spatial holding SpatialWFSFetcher, which can be fed any geometry and it returns found features
* WIP: adds tests for wfs fetching
* updates requirements.txt
This commit is contained in:
2021-12-17 17:30:12 +01:00
parent 93d1cb9330
commit 46e237f0e2
5 changed files with 131 additions and 9 deletions

View File

@@ -0,0 +1,92 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 17.12.21
"""
from abc import abstractmethod
import requests
import xmltodict
from django.contrib.gis.db.models.functions import AsGML, Transform
from django.contrib.gis.geos import MultiPolygon
from owslib.wfs import WebFeatureService
from konova.models import Geometry
from konova.settings import DEFAULT_SRID_RLP
class BaseWFSFetcher:
# base_url represents not the capabilities url but the parameter-free base url
base_url = ""
version = ""
wfs = None
def __init__(self, base_url: str, version: str = "1.1.0", *args, **kwargs):
self.base_url = base_url
self.version = version
self.wfs = WebFeatureService(
url=base_url,
version=version,
)
@abstractmethod
def get_features(self, feature_identifier: str, filter: str):
raise NotImplementedError
class SpatialWFSFetcher(BaseWFSFetcher):
""" Fetches features from a parcel WFS
"""
geometry = None
geometry_property_name = ""
def __init__(self, geometry: MultiPolygon, geometry_property_name: str = "msGeometry", *args, **kwargs):
super().__init__(*args, **kwargs)
self.geometry = geometry
self.geometry_property_name = geometry_property_name
def _create_geometry_filter(self, geometry_operation: str, filter_srid: str = None):
""" Creates an
Args:
geometry_operation ():
filter_srid ():
Returns:
"""
if filter_srid is None:
filter_srid = DEFAULT_SRID_RLP
geom_gml = Geometry.objects.filter(
id=self.geometry.id
).annotate(
transformed=Transform(srid=filter_srid, expression="geom")
).annotate(
gml=AsGML('transformed')
).first().gml
_filter = f"<Filter><{geometry_operation}><PropertyName>{self.geometry_property_name}</PropertyName>{geom_gml}</{geometry_operation}></Filter>"
return _filter
def get_features(self, typenames: str, geometry_operation: str = "Intersects", filter_srid: str = None, filter: str = None):
if filter is None:
filter = self._create_geometry_filter(geometry_operation, filter_srid)
response = requests.post(
url=f"{self.base_url}?request=GetFeature&service=WFS&version={self.version}&typenames={typenames}&count=10",
data={
"filter": filter,
}
)
content = response.content.decode("utf-8")
content = xmltodict.parse(content)
features = content.get(
"wfs:FeatureCollection",
{},
).get(
"gml:featureMember",
[],
)
return features