From 59c8de628a4c715f5abdf70d9348254c27b5525c Mon Sep 17 00:00:00 2001 From: Christian Heider Nielsen Date: Wed, 6 Dec 2023 10:48:55 +0100 Subject: [PATCH] is multi test and grouping --- jord/qgis_utilities/__init__.py | 12 +++-- jord/qgis_utilities/data_provider.py | 19 ++++---- jord/qgis_utilities/geometry_types.py | 6 +-- jord/qgis_utilities/layer_creation.py | 24 ++++++---- jord/qgis_utilities/layer_serialisation.py | 6 +++ jord/qgis_utilities/plugin_version.py | 7 ++- jord/qlive_utilities/procedures.py | 6 ++- jord/shapely_utilities/__init__.py | 1 + jord/shapely_utilities/geometry_types.py | 21 +++++++- jord/shapely_utilities/grouping.py | 56 ++++++++++++++++++++++ tests/shapely/geometry_types.py | 56 ++++++++++++++++++++++ 11 files changed, 183 insertions(+), 31 deletions(-) create mode 100644 jord/shapely_utilities/grouping.py create mode 100644 tests/shapely/geometry_types.py diff --git a/jord/qgis_utilities/__init__.py b/jord/qgis_utilities/__init__.py index 929d93d..8cf0dd9 100755 --- a/jord/qgis_utilities/__init__.py +++ b/jord/qgis_utilities/__init__.py @@ -17,14 +17,16 @@ try: from .importing import * from .configuration import * - from .helpers import * - from .numpy_utilities import * + + # from .helpers import * # import issues + # from .numpy_utilities import * from .data_provider import * from .geometry_types import * from .conversion import * - from .categorisation import * - from .styling import * - from .plugin_version import * + + # from .categorisation import * + # from .styling import * + # from .plugin_version import * except ImportError as ix: this_package_name = Path(__file__).parent.name print(f"Make sure qgis module is available for {this_package_name}") diff --git a/jord/qgis_utilities/data_provider.py b/jord/qgis_utilities/data_provider.py index 998928f..265fda2 100755 --- a/jord/qgis_utilities/data_provider.py +++ b/jord/qgis_utilities/data_provider.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- - from enum import Enum __all__ = ["CommonVectorDataProviderLibEnum"] @@ -21,15 +20,15 @@ def auishd(iface) -> None: from PyQt5.QtCore import QSettings """ - connection_type - connection_name - authcfg - password - referer - url - username - zmax - zmin +connection_type +connection_name +authcfg +password +referer +url +username +zmax +zmin """ # Sources diff --git a/jord/qgis_utilities/geometry_types.py b/jord/qgis_utilities/geometry_types.py index 0ec41e0..8528d7a 100755 --- a/jord/qgis_utilities/geometry_types.py +++ b/jord/qgis_utilities/geometry_types.py @@ -6,7 +6,7 @@ __all__ = [ "VectorGeometryTypeEnum", - "CommonCordinateReferenceSystemEnum", + "CommonCoordinateReferenceSystemEnum", "FieldTypeEnum", ] @@ -24,12 +24,12 @@ class VectorGeometryTypeEnum(Enum): multi_polygon = "multipolygon" # + Geopackage -class CommonCordinateReferenceSystemEnum(Enum): +class CommonCoordinateReferenceSystemEnum(Enum): epsg4326 = "epsg:4326" # WGS 84 epsg3857 = "EPSG:3857" # WGS 84 / Pseudo-Mercator" -class FieldTypeEnum: +class FieldTypeEnum(Enum): integer = "integer" double = "double" string = "string" diff --git a/jord/qgis_utilities/layer_creation.py b/jord/qgis_utilities/layer_creation.py index 8dd1903..c264e3c 100755 --- a/jord/qgis_utilities/layer_creation.py +++ b/jord/qgis_utilities/layer_creation.py @@ -144,9 +144,13 @@ def add_qgis_single_feature_layer( else: qgis_instance_handle.qgis_project.addMapLayer(sub_layer) - qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( - sub_layer.id() - ).setItemVisibilityChecked(visible) + layer_tree_handle = ( + qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( + sub_layer.id() + ) + ) + if layer_tree_handle: + layer_tree_handle.setItemVisibilityChecked(visible) else: uri += "?" @@ -196,9 +200,11 @@ def add_qgis_single_feature_layer( else: qgis_instance_handle.qgis_project.addMapLayer(layer) - qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( + layer_tree_handle = qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( layer.id() - ).setItemVisibilityChecked(visible) + ) + if layer_tree_handle: + layer_tree_handle.setItemVisibilityChecked(visible) actions = qgis.utils.iface.layerTreeView().defaultActions() actions.showFeatureCount() @@ -390,12 +396,14 @@ def add_qgis_multi_feature_layer( else: qgis_instance_handle.qgis_project.addMapLayer(layer) - qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( + layer_tree_handle = qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( layer.id() - ).setItemVisibilityChecked(visible) + ) + if layer_tree_handle: + layer_tree_handle.setItemVisibilityChecked(visible) actions = qgis.utils.iface.layerTreeView().defaultActions() - actions.showFeatureCount() + actions.showFeatureCount() # TODO: Twice? actions.showFeatureCount() return_collection.append(layer) diff --git a/jord/qgis_utilities/layer_serialisation.py b/jord/qgis_utilities/layer_serialisation.py index db12de5..354bdb3 100755 --- a/jord/qgis_utilities/layer_serialisation.py +++ b/jord/qgis_utilities/layer_serialisation.py @@ -91,3 +91,9 @@ def serialise_qgis_layer(qgis_instance_handle: Any, layer: Any) -> None: 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. + + return layer_geojson_rep + + +if __name__ == "__main__": + print("A") diff --git a/jord/qgis_utilities/plugin_version.py b/jord/qgis_utilities/plugin_version.py index b43a50b..f91a2ee 100755 --- a/jord/qgis_utilities/plugin_version.py +++ b/jord/qgis_utilities/plugin_version.py @@ -1,16 +1,19 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# noinspection PyUnresolvedReferences -from pyplugin_installer.installer_data import repositories, plugins __all__ = ["plugin_status"] def plugin_status(plugin_key: str) -> str: + # noinspection PyUnresolvedReferences + from pyplugin_installer.installer_data import repositories, plugins # QGIS CODE! + all_plugins = plugins.all() + if plugin_key in all_plugins: return all_plugins[plugin_key]["status"] + return "Not Found" diff --git a/jord/qlive_utilities/procedures.py b/jord/qlive_utilities/procedures.py index 4cd3410..83bdb2c 100755 --- a/jord/qlive_utilities/procedures.py +++ b/jord/qlive_utilities/procedures.py @@ -646,9 +646,11 @@ def add_raster( else: qgis_instance_handle.qgis_project.addMapLayer(layer) - qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( + layer_tree_handle = qgis_instance_handle.qgis_project.layerTreeRoot().findLayer( layer.id() - ).setItemVisibilityChecked(visible) + ) + if layer_tree_handle: + layer_tree_handle.setItemVisibilityChecked(visible) @passes_kws_to(add_raster, no_pass_filter=["name"]) diff --git a/jord/shapely_utilities/__init__.py b/jord/shapely_utilities/__init__.py index 3c6d3e0..fa8bad7 100755 --- a/jord/shapely_utilities/__init__.py +++ b/jord/shapely_utilities/__init__.py @@ -23,3 +23,4 @@ from .transformation import * from .rings import * from .selection import * +from .grouping import * diff --git a/jord/shapely_utilities/geometry_types.py b/jord/shapely_utilities/geometry_types.py index b30bd71..dfc0150 100755 --- a/jord/shapely_utilities/geometry_types.py +++ b/jord/shapely_utilities/geometry_types.py @@ -4,6 +4,7 @@ from enum import Enum +import shapely from shapely.geometry import ( Point, LineString, @@ -15,7 +16,7 @@ GeometryCollection, ) -__all__ = ["ShapelyGeometryTypesEnum"] +__all__ = ["ShapelyGeometryTypesEnum", "is_multi"] class ShapelyGeometryTypesEnum(Enum): @@ -44,5 +45,23 @@ class ShapelyGeometryTypesEnum(Enum): geometry_collection = GeometryCollection # GeometryCollection([geoms]) # A collection of one or more geometries that may contain more than one type of geometry. +MULTI_GEOMS = ( + shapely.MultiPolygon, + shapely.MultiPoint, + shapely.MultiLineString, + shapely.GeometryCollection, +) + + +def is_multi(geom: shapely.geometry.base.BaseGeometry) -> bool: + """ + Tests whether a geometry is multi-geometry + + :param geom: geometry to be tested + :return: whether a geometry is multi-geometry + """ + return isinstance(geom, MULTI_GEOMS) + + if __name__ == "__main__": print([p.value.__name__ for p in ShapelyGeometryTypesEnum]) diff --git a/jord/shapely_utilities/grouping.py b/jord/shapely_utilities/grouping.py new file mode 100644 index 0000000..15a10d1 --- /dev/null +++ b/jord/shapely_utilities/grouping.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +from typing import Mapping, Sequence, Union + +import shapely +from shapely import unary_union + +from jord.shapely_utilities.geometry_types import is_multi + +__all__ = ["overlap_groups"] + + +def overlap_groups(to_be_grouped: Union[Sequence, Mapping]) -> Sequence[Mapping]: + if isinstance(to_be_grouped, Mapping): + ... + else: + to_be_grouped = dict(zip((i for i in range(len(to_be_grouped))), to_be_grouped)) + + union = unary_union(list(to_be_grouped.values())) + groups = [] + already_grouped = [] + + if not is_multi(union): + groups.append(to_be_grouped) + else: + for union_part in union.geoms: + intersectors = {} + for k, v in to_be_grouped.items(): + if shapely.intersects(v, union_part): + assert k not in already_grouped + intersectors[k] = v + already_grouped.append(k) + groups.append(intersectors) + + return groups + + +if __name__ == "__main__": + + def demo(): + from shapely.geometry import box + from pprint import pprint + + data = [ + box(1, 1, 3, 3), + box(2, 2, 3, 3), + box(4, 4, 6, 6), + box(4, 4, 5, 5), + box(5, 5, 6, 6), + box(7, 7, 8, 8), + box(1, 1, 2, 2), + box(4, 4, 6, 6), + ] + + pprint(overlap_groups(data)) + + demo() diff --git a/tests/shapely/geometry_types.py b/tests/shapely/geometry_types.py new file mode 100644 index 0000000..7d0c206 --- /dev/null +++ b/tests/shapely/geometry_types.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +import shapely + +from jord.shapely_utilities import is_multi + + +def test_line_string_is_multi(): + assert is_multi(shapely.LineString([[0, 0], [1, 0], [1, 1]])) == False + + +def test_point_is_multi(): + assert is_multi(shapely.Point([[0, 0]])) == False + + +def test_linear_ring_is_multi(): + assert is_multi(shapely.LinearRing(((0, 0), (0, 1), (1, 1), (1, 0)))) == False + + +def test_polygon_is_multi(): + assert ( + is_multi( + shapely.Polygon( + ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0), (0.0, 0.0)) + ) + ) + == False + ) + + +def test_multi_point_is_multi(): + assert is_multi(shapely.MultiPoint([[0.0, 0.0], [1.0, 2.0]])) + + +def test_multi_line_string_is_multi(): + assert is_multi(shapely.MultiLineString([[[0, 0], [1, 2]], [[4, 4], [5, 6]]])) + + +def test_multi_polygon_is_multi(): + assert is_multi( + shapely.MultiPolygon( + [ + ( + ((0.0, 0.0), (0.0, 1.0), (1.0, 1.0), (1.0, 0.0)), + [((0.1, 0.1), (0.1, 0.2), (0.2, 0.2), (0.2, 0.1))], + ) + ] + ) + ) + + +def test_geometry_collection_is_multi(): + assert is_multi( + shapely.GeometryCollection( + [shapely.Point(51, -1), shapely.LineString([(52, -1), (49, 2)])] + ) + )