From 5a96fa073f2fc39c24483331493126c8fc4cde68 Mon Sep 17 00:00:00 2001 From: Christian Heider Nielsen Date: Tue, 28 Nov 2023 10:09:19 +0100 Subject: [PATCH] start support serialisation, not done --- .../layer_creation.py} | 4 +- jord/qgis_utilities/layer_serialisation.py | 93 +++++++++++++++++++ jord/qlive_utilities/procedures.py | 76 ++++++++++++++- jord/shapely_utilities/polygons.py | 46 +++++++-- 4 files changed, 211 insertions(+), 8 deletions(-) rename jord/{qlive_utilities/qgis_layer_creation.py => qgis_utilities/layer_creation.py} (98%) create mode 100755 jord/qgis_utilities/layer_serialisation.py diff --git a/jord/qlive_utilities/qgis_layer_creation.py b/jord/qgis_utilities/layer_creation.py similarity index 98% rename from jord/qlive_utilities/qgis_layer_creation.py rename to jord/qgis_utilities/layer_creation.py index 034fd47..9163377 100755 --- a/jord/qlive_utilities/qgis_layer_creation.py +++ b/jord/qgis_utilities/layer_creation.py @@ -159,7 +159,9 @@ def add_qgis_single_feature_layer( feat.setAttributes(list(columns.values())) layer = QgsVectorLayer(uri, layer_name, "memory") - layer_data_provider = layer.dataProvider() + layer_data_provider = ( + layer.dataProvider() + ) # DEFAULT DATA PROVIDER, MAYBE CHANGE THIS layer_data_provider.addFeatures([feat]) layer_data_provider.updateExtents() diff --git a/jord/qgis_utilities/layer_serialisation.py b/jord/qgis_utilities/layer_serialisation.py new file mode 100755 index 0000000..db12de5 --- /dev/null +++ b/jord/qgis_utilities/layer_serialisation.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +from typing import Any + +APPEND_TIMESTAMP = True +SKIP_MEMORY_LAYER_CHECK_AT_CLOSE = True +PIXEL_SIZE = 1 +DEFAULT_NUMBER = 0 +CONTRAST_ENHANCE = True +DEFAULT_LAYER_NAME = "TemporaryLayer" +DEFAULT_LAYER_CRS = "EPSG:4326" +VERBOSE = False + +__all__ = [ + "serialise_qgis_layer", +] + + +def serialise_qgis_layer(qgis_instance_handle: Any, layer: Any) -> None: + """ + https://qgis.org/pyqgis/3.28/core/QgsJsonUtils.html#qgis.core.QgsJsonUtils.exportAttributes + + https://qgis.org/pyqgis/3.28/core/QgsJsonExporter.html + + + asGeometryCollection + + Returns contents of the geometry as a list of geometries + + asJson + + Exports the geometry to a GeoJSON string. + + asMultiPoint + + Returns the contents of the geometry as a multi-point. + + asMultiPolygon + + Returns the contents of the geometry as a multi-polygon. + + asMultiPolyline + + Returns the contents of the geometry as a multi-linestring. + + asPoint + + Returns the contents of the geometry as a 2-dimensional point. + + asPolygon + + Returns the contents of the geometry as a polygon. + + asPolyline + + Returns the contents of the geometry as a polyline. + + asQPointF + + Returns contents of the geometry as a QPointF if wkbType is WKBPoint, otherwise returns a null QPointF. + + asQPolygonF + + Returns contents of the geometry as a QPolygonF. + + asWkb + + Export the geometry to WKB + + asWkt + + Exports the geometry to WKT + + + TODO: Figure this + + :param qgis_instance_handle: + :param layer: + :return: + """ + + # noinspection PyUnresolvedReferences + from qgis.core import QgsVectorLayer, QgsFeature, QgsJsonExporter + + # noinspection PyUnresolvedReferences + import qgis + + assert isinstance(layer, QgsVectorLayer) + + # geom_geojson_rep = layer.asJson(precision=17) + layer_geojson_rep = QgsJsonExporter( + layer, precision=17 + ) # Note that geometries will be automatically reprojected to WGS84 to match GeoJSON spec if either the source vector layer or source CRS is set. diff --git a/jord/qlive_utilities/procedures.py b/jord/qlive_utilities/procedures.py index 4c89eaf..9d92ca0 100755 --- a/jord/qlive_utilities/procedures.py +++ b/jord/qlive_utilities/procedures.py @@ -14,7 +14,7 @@ from warg import passes_kws_to, Number from jord import PROJECT_APP_PATH -from jord.qlive_utilities.qgis_layer_creation import ( +from jord.qgis_utilities.layer_creation import ( add_qgis_single_feature_layer, add_qgis_multi_feature_layer, ) @@ -101,6 +101,80 @@ def add_wkb_layer( ) +@passes_kws_to(add_qgis_multi_feature_layer) +def add_geojson_layer( + qgis_instance_handle: Any, geojsons: Iterable[str], *args, **kwargs +) -> None: + """ + + fromMultiPointXY + + Creates a new geometry from a QgsMultiPointXY object + + fromMultiPolygonXY + + Creates a new geometry from a QgsMultiPolygonXY. + + fromMultiPolylineXY + + Creates a new geometry from a QgsMultiPolylineXY object. + + fromPointXY + + Creates a new geometry from a QgsPointXY object + + fromPolygonXY + + Creates a new polygon geometry from a list of lists of QgsPointXY. + + fromPolyline + + Creates a new LineString geometry from a list of QgsPoint points. + + fromPolylineXY + + Creates a new LineString geometry from a list of QgsPointXY points. + + fromQPointF + + Construct geometry from a QPointF + + fromQPolygonF + + Construct geometry from a QPolygonF. + + fromRect + + Creates a new geometry from a QgsRectangle + + fromWkb + + Set the geometry, feeding in the buffer containing OGC Well-Known Binary + + fromWkt + + Creates a new geometry from a WKT string + + + TODO: IMPLEMENT THIS + + :param qgis_instance_handle: + :param wkbs: + :param args: + :param kwargs: + :return: + """ + # noinspection PyUnresolvedReferences + from qgis.core import QgsGeometry + + add_qgis_multi_feature_layer( + qgis_instance_handle, + # [gj for gj in geojsons], + *args, + **kwargs, + ) + + @passes_kws_to(add_qgis_single_feature_layer) def add_wkt(qgis_instance_handle: Any, wkt: str, *args, **kwargs) -> None: """ diff --git a/jord/shapely_utilities/polygons.py b/jord/shapely_utilities/polygons.py index 009b966..7251cee 100755 --- a/jord/shapely_utilities/polygons.py +++ b/jord/shapely_utilities/polygons.py @@ -12,6 +12,10 @@ Polygon, ) from shapely.geometry.base import BaseGeometry +from warg import pairs, Number + +from jord.shapely_utilities.morphology import opening, closing +from jord.shapely_utilities.rings import ensure_ccw_ring, ensure_cw_ring __all__ = [ "zero_buffer", @@ -23,10 +27,6 @@ "iter_polygons", ] -from warg import pairs -from jord.shapely_utilities.morphology import opening, closing -from jord.shapely_utilities.rings import ensure_ccw_ring, ensure_cw_ring - def zero_buffer( geom: BaseGeometry, @@ -204,6 +204,41 @@ def prune_rings(geom: BaseGeometry, eps: float = 1e-7) -> BaseGeometry: return poly_areas +def prune_holes( + geom: Union[MultiPolygon, Polygon], epsilon: Number = 1000 +) -> Union[MultiPolygon, Polygon]: + """ + + :param geom: + :return:""" + + if isinstance(geom, MultiPolygon): + parts = [] + + for polygon in geom.geoms: + interiors = [] + + for interior in polygon.interiors: + p = Polygon(interior) + + if p.area > epsilon: + interiors.append(interior) + + temp_pol = Polygon(polygon.exterior.coords, holes=interiors) + parts.append(temp_pol) + + return MultiPolygon(parts) + + interiors = [] + + for interior in geom.interiors: + p = Polygon(interior) + if p.area > epsilon: + interiors.append(interior) + + return Polygon(geom.exterior.coords, holes=interiors) + + def sanitise(geom: BaseGeometry, *args: callable) -> BaseGeometry: """ #A positive distance produces a dilation, a negative distance an erosion. A very small or zero distance may sometimes be used to “tidy” a polygon. @@ -273,11 +308,10 @@ def explode_polygons( return_index: bool = False, ) -> Union[Sequence[LineString], Tuple[Sequence[LineString], Sequence[int]]]: """ - returns main line features that make up the polygons :param polygons: :param return_index: - :return: + :return: main line features that make up the polygons """ lines_out = [] index = []