From ccca49876304974efffbb7dd96a1476d31ed2b3f Mon Sep 17 00:00:00 2001 From: "Carles S. Soriano Perez" Date: Thu, 19 Oct 2023 15:25:35 +0200 Subject: [PATCH 1/7] chore: added logic to deal with MultiPolygon geometries --- .../reinforcement_layers_wrapper.py | 16 ++++---- koswat/core/geometries/calc_library.py | 6 ++- koswat/plots/dike/koswat_layer_plot.py | 40 ++++++++++++++----- poetry.lock | 38 +++++++++++++++++- pyproject.toml | 1 + 5 files changed, 81 insertions(+), 20 deletions(-) diff --git a/koswat/calculations/reinforcement_layers_wrapper.py b/koswat/calculations/reinforcement_layers_wrapper.py index 8b675af0..abc06cec 100644 --- a/koswat/calculations/reinforcement_layers_wrapper.py +++ b/koswat/calculations/reinforcement_layers_wrapper.py @@ -1,8 +1,8 @@ from __future__ import annotations -from typing import List, Protocol, runtime_checkable +from typing import Protocol, runtime_checkable -from shapely.geometry import LineString, Polygon +from shapely.geometry import LineString, Polygon, MultiPolygon from koswat.core.geometries.calc_library import get_polygon_coordinates from koswat.dike.layers import KoswatLayerProtocol @@ -14,18 +14,18 @@ @runtime_checkable class ReinforcementLayerProtocol(KoswatLayerProtocol, Protocol): - new_layer_geometry: Polygon + new_layer_geometry: Polygon | MultiPolygon new_layer_surface: LineString old_layer_geometry: Polygon -class ReinforcementCoatingLayer(KoswatLayerProtocol): +class ReinforcementCoatingLayer(ReinforcementLayerProtocol): material_type: KoswatMaterialType outer_geometry: Polygon material_geometry: Polygon upper_points: LineString old_layer_geometry: Polygon - new_layer_geometry: Polygon + new_layer_geometry: Polygon | MultiPolygon new_layer_surface: LineString removal_layer_geometry: Polygon @@ -84,7 +84,7 @@ class ReinforcementBaseLayer(ReinforcementLayerProtocol): outer_geometry: Polygon material_geometry: Polygon upper_points: LineString - new_layer_geometry: Polygon + new_layer_geometry: Polygon | MultiPolygon new_layer_surface: LineString old_layer_geometry: Polygon @@ -115,7 +115,7 @@ def from_koswat_base_layer( class ReinforcementLayersWrapper(KoswatLayersWrapperProtocol): base_layer: ReinforcementBaseLayer - coating_layers: List[ReinforcementCoatingLayer] + coating_layers: list[ReinforcementCoatingLayer] def __init__(self) -> None: self.base_layer = None @@ -143,7 +143,7 @@ def get_layer(self, material_type: KoswatMaterialType) -> ReinforcementCoatingLa return _found_layer @property - def layers(self) -> List[ReinforcementLayerProtocol]: + def layers(self) -> list[ReinforcementLayerProtocol]: """ All the stored layers being the `KoswatBaseLayer` the latest one in the collection. diff --git a/koswat/core/geometries/calc_library.py b/koswat/core/geometries/calc_library.py index 0ec39b38..a02ba5de 100644 --- a/koswat/core/geometries/calc_library.py +++ b/koswat/core/geometries/calc_library.py @@ -100,7 +100,7 @@ def get_polygon_coordinates( """ if isinstance(pol_geometry, geometry.Polygon): return geometry.LineString(pol_geometry.exterior.coords) - raise NotImplementedError(f"Geometry type {geometry.geom_type} not supported.") + raise NotImplementedError(f"Geometry type {pol_geometry.geom_type} not supported.") def get_groundlevel_surface(pol_geometry: geometry.Polygon) -> geometry.LineString: @@ -144,7 +144,7 @@ def _last_point_intersects() -> bool: def get_normalized_polygon_difference( left_geom: geometry.Polygon, right_geom: geometry.Polygon -) -> geometry.Polygon: +) -> geometry.Polygon | geometry.MultiPolygon: """ Given two polygons calculates the difference between them and removes any residual polygon due to minor precission errors. @@ -156,6 +156,8 @@ def get_normalized_polygon_difference( geometry.Polygon: Resulting normalized substraction polygon. """ _result_geom = order_geometry_points(left_geom.difference(right_geom)) + if isinstance(_result_geom, geometry.MultiPolygon): + return _result_geom return _get_normalized_polygon(_result_geom) diff --git a/koswat/plots/dike/koswat_layer_plot.py b/koswat/plots/dike/koswat_layer_plot.py index fb4c32b7..ac19f549 100644 --- a/koswat/plots/dike/koswat_layer_plot.py +++ b/koswat/plots/dike/koswat_layer_plot.py @@ -3,6 +3,8 @@ from koswat.dike.layers.koswat_layer_protocol import KoswatLayerProtocol from koswat.dike.material.koswat_material_type import KoswatMaterialType from koswat.plots.koswat_plot_protocol import KoswatPlotProtocol +from shapely import geometry +from numpy import concatenate class KoswatLayerPlot(KoswatPlotProtocol): @@ -39,13 +41,33 @@ def plot(self, color: str) -> None: ) if isinstance(self.koswat_object, ReinforcementLayerProtocol): - _surface_x, _surface_y = self.koswat_object.new_layer_surface.coords.xy - self.subplot.plot( - _surface_x, - _surface_y, - color="#000", - linewidth=2, - zorder=1, - linestyle="solid", - ) + if isinstance(self.koswat_object.new_layer_surface, geometry.Polygon): + _surface_x, _surface_y = self.koswat_object.new_layer_surface.coords.xy + self.subplot.plot( + _surface_x, + _surface_y, + color="#000", + linewidth=2, + zorder=1, + linestyle="solid", + ) + if isinstance(self.koswat_object.new_layer_surface, geometry.MultiPolygon): + _combined_xy = list( + map( + concatenate( + zip( + self.koswat_object.new_layer_surface.geoms[0].coords.xy, + self.koswat_object.new_layer_surface.geoms[1].coords.xy, + ) + ) + ) + ) + self.subplot.plot( + _combined_xy[0], + _combined_xy[1], + color="#000", + linewidth=2, + zorder=1, + linestyle="solid", + ) return self.subplot diff --git a/poetry.lock b/poetry.lock index 90087d2e..c445fb8f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -347,6 +347,21 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "execnet" +version = "2.0.2" +description = "execnet: rapid multi-Python deployment" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, + {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, +] + +[package.extras] +testing = ["hatch", "pre-commit", "pytest", "tox"] + [[package]] name = "fonttools" version = "4.39.4" @@ -1247,6 +1262,27 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +[[package]] +name = "pytest-xdist" +version = "3.3.1" +description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-xdist-3.3.1.tar.gz", hash = "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93"}, + {file = "pytest_xdist-3.3.1-py3-none-any.whl", hash = "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"}, +] + +[package.dependencies] +execnet = ">=1.1" +pytest = ">=6.2.0" + +[package.extras] +psutil = ["psutil (>=3.0)"] +setproctitle = ["setproctitle"] +testing = ["filelock"] + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1728,4 +1764,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = "^3.9, <3.11" -content-hash = "fd848f26a550f0ebc0231c9511351b1894ea9359aca68dc998bea95b8ec29433" +content-hash = "ec717581abe1b84563eb3deb8ec7480d15a7b5ea76ca9f6a275072a90f4c373e" diff --git a/pyproject.toml b/pyproject.toml index e8b05cec..1e8a9a10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,6 +38,7 @@ pytest-cov = "^3.0.0" coverage = "^6.4.4" teamcity-messages = "^1.32" opencv-python = "^4.8.1.78" +pytest-xdist = "^3.3.1" [tool.poetry.group.dev.dependencies] black = "^22.8.0" From adfea61bd5c7e52848bf59ba5b3a410e05138f4c Mon Sep 17 00:00:00 2001 From: "Carles S. Soriano Perez" Date: Thu, 19 Oct 2023 15:30:52 +0200 Subject: [PATCH 2/7] chore: Removed unrequired import --- koswat/core/geometries/calc_library.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/koswat/core/geometries/calc_library.py b/koswat/core/geometries/calc_library.py index a02ba5de..3bfccdfd 100644 --- a/koswat/core/geometries/calc_library.py +++ b/koswat/core/geometries/calc_library.py @@ -1,5 +1,4 @@ import logging -from typing import List, Union from shapely import affinity, geometry, ops @@ -36,13 +35,13 @@ def order_geometry_points(dike_polygon: geometry.Polygon) -> geometry.Polygon: def as_unified_geometry( - source_geom: Union[geometry.Polygon, geometry.MultiPolygon] + source_geom: geometry.Polygon | geometry.MultiPolygon, ) -> geometry.Polygon: """ Ensures the calculated geometry is returned as a single polygon. Args: - source_geom (Union[geometry.Polygon, geometry.MultiPolygon]): Calculated source geometry. + source_geom (geometry.Polygon | geometry.MultiPolygon): Calculated source geometry. Returns: geometry.Polygon: Unified resulting geometry with its points ordered (first one is the most-left x coordinate). @@ -84,13 +83,13 @@ def get_relative_core_layer( def get_polygon_coordinates( - pol_geometry: Union[geometry.Polygon, geometry.MultiPolygon] + pol_geometry: geometry.Polygon | geometry.MultiPolygon, ) -> geometry.LineString: """ Given a single or multi geometry returns the coordinates composing its outer layout. Args: - pol_geometry (Union[geometry.Polygon, geometry.MultiPolygon]): Source geometry. + pol_geometry (geometry.Polygon | geometry.MultiPolygon): Source geometry. Raises: NotImplementedError: When the provided geometry is not yet supported. @@ -181,7 +180,7 @@ def _get_single_polygon_surface_points( def get_polygon_surface_points( - base_geometry: Union[geometry.Polygon, geometry.MultiPolygon] + base_geometry: geometry.Polygon | geometry.MultiPolygon, ) -> geometry.LineString: """ Gets all the points composing the upper surface of a 'dike' geometry. @@ -202,7 +201,7 @@ def get_polygon_surface_points( return base_geometry -def profile_points_to_polygon(points_list: List[geometry.Point]) -> geometry.Polygon: +def profile_points_to_polygon(points_list: list[geometry.Point]) -> geometry.Polygon: """ Transforms a list of points into a valid 'dike' polygon. When there is a difference in height between left and right side then we correct it in the x = 0 coordinate. From 5850f008a973dbb951db80bda09f29cdd7f1f45b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carles=20S=2E=20Soriano=20P=C3=A9rez?= Date: Mon, 23 Oct 2023 10:36:15 +0200 Subject: [PATCH 3/7] Apply suggestions from code review Co-authored-by: Ardt Klapwijk <59741981+ArdtK@users.noreply.github.com> --- koswat/core/geometries/calc_library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koswat/core/geometries/calc_library.py b/koswat/core/geometries/calc_library.py index 3bfccdfd..1f108905 100644 --- a/koswat/core/geometries/calc_library.py +++ b/koswat/core/geometries/calc_library.py @@ -145,7 +145,7 @@ def get_normalized_polygon_difference( left_geom: geometry.Polygon, right_geom: geometry.Polygon ) -> geometry.Polygon | geometry.MultiPolygon: """ - Given two polygons calculates the difference between them and removes any residual polygon due to minor precission errors. + Given two polygons calculates the difference between them and removes any residual polygon due to minor precision errors. Args: left_geom (geometry.Polygon): Base polygon from where to substract. From e4bcb05a240c2b96e55c1391975c674b7436d687 Mon Sep 17 00:00:00 2001 From: "Carles S. Soriano Perez" Date: Mon, 23 Oct 2023 12:03:29 +0200 Subject: [PATCH 4/7] chore: Processed review remarks --- koswat/plots/dike/koswat_layer_plot.py | 68 +++++++++++++++----------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/koswat/plots/dike/koswat_layer_plot.py b/koswat/plots/dike/koswat_layer_plot.py index ac19f549..30b3b250 100644 --- a/koswat/plots/dike/koswat_layer_plot.py +++ b/koswat/plots/dike/koswat_layer_plot.py @@ -41,33 +41,43 @@ def plot(self, color: str) -> None: ) if isinstance(self.koswat_object, ReinforcementLayerProtocol): - if isinstance(self.koswat_object.new_layer_surface, geometry.Polygon): - _surface_x, _surface_y = self.koswat_object.new_layer_surface.coords.xy - self.subplot.plot( - _surface_x, - _surface_y, - color="#000", - linewidth=2, - zorder=1, - linestyle="solid", - ) - if isinstance(self.koswat_object.new_layer_surface, geometry.MultiPolygon): - _combined_xy = list( - map( - concatenate( - zip( - self.koswat_object.new_layer_surface.geoms[0].coords.xy, - self.koswat_object.new_layer_surface.geoms[1].coords.xy, - ) - ) - ) - ) - self.subplot.plot( - _combined_xy[0], - _combined_xy[1], - color="#000", - linewidth=2, - zorder=1, - linestyle="solid", - ) + _surface_x, _surface_y = self.koswat_object.new_layer_surface.coords.xy + self.subplot.plot( + _surface_x, + _surface_y, + color="#000", + linewidth=2, + zorder=1, + linestyle="solid", + ) + # elif isinstance(self.koswat_object.new_layer_surface, geometry.Polygon): + # _surface_x, _surface_y = self.koswat_object.new_layer_surface.coords.xy + # self.subplot.plot( + # _surface_x, + # _surface_y, + # color="#000", + # linewidth=2, + # zorder=1, + # linestyle="solid", + # ) + # elif isinstance( + # self.koswat_object.new_layer_surface, geometry.MultiPolygon + # ): + # _combined_xy = list( + # map( + # concatenate, + # zip( + # self.koswat_object.new_layer_surface.geoms[0].coords.xy, + # self.koswat_object.new_layer_surface.geoms[1].coords.xy, + # ), + # ) + # ) + # self.subplot.plot( + # _combined_xy[0], + # _combined_xy[1], + # color="#000", + # linewidth=2, + # zorder=1, + # linestyle="solid", + # ) return self.subplot From fcab6863d1a907c2157104044b2ea4a35026642e Mon Sep 17 00:00:00 2001 From: "Carles S. Soriano Perez" Date: Mon, 23 Oct 2023 12:09:26 +0200 Subject: [PATCH 5/7] chore: We now normalzie multipolygons as well. --- koswat/core/geometries/calc_library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/koswat/core/geometries/calc_library.py b/koswat/core/geometries/calc_library.py index 1f108905..705f9781 100644 --- a/koswat/core/geometries/calc_library.py +++ b/koswat/core/geometries/calc_library.py @@ -156,7 +156,7 @@ def get_normalized_polygon_difference( """ _result_geom = order_geometry_points(left_geom.difference(right_geom)) if isinstance(_result_geom, geometry.MultiPolygon): - return _result_geom + return geometry.MultiPolygon(map(_get_normalized_polygon, _result_geom.geoms)) return _get_normalized_polygon(_result_geom) From b2f76f944bb97dd0092a56e2c900b2992607b497 Mon Sep 17 00:00:00 2001 From: "Carles S. Soriano Perez" Date: Mon, 23 Oct 2023 12:11:28 +0200 Subject: [PATCH 6/7] chore: Removed commented out code --- koswat/plots/dike/koswat_layer_plot.py | 30 -------------------------- 1 file changed, 30 deletions(-) diff --git a/koswat/plots/dike/koswat_layer_plot.py b/koswat/plots/dike/koswat_layer_plot.py index 30b3b250..cefbc07f 100644 --- a/koswat/plots/dike/koswat_layer_plot.py +++ b/koswat/plots/dike/koswat_layer_plot.py @@ -50,34 +50,4 @@ def plot(self, color: str) -> None: zorder=1, linestyle="solid", ) - # elif isinstance(self.koswat_object.new_layer_surface, geometry.Polygon): - # _surface_x, _surface_y = self.koswat_object.new_layer_surface.coords.xy - # self.subplot.plot( - # _surface_x, - # _surface_y, - # color="#000", - # linewidth=2, - # zorder=1, - # linestyle="solid", - # ) - # elif isinstance( - # self.koswat_object.new_layer_surface, geometry.MultiPolygon - # ): - # _combined_xy = list( - # map( - # concatenate, - # zip( - # self.koswat_object.new_layer_surface.geoms[0].coords.xy, - # self.koswat_object.new_layer_surface.geoms[1].coords.xy, - # ), - # ) - # ) - # self.subplot.plot( - # _combined_xy[0], - # _combined_xy[1], - # color="#000", - # linewidth=2, - # zorder=1, - # linestyle="solid", - # ) return self.subplot From 478b1b690b3547837d4684a211977606445d1b86 Mon Sep 17 00:00:00 2001 From: "Carles S. Soriano Perez" Date: Mon, 23 Oct 2023 12:12:29 +0200 Subject: [PATCH 7/7] chore: Removed unrequired imports --- koswat/plots/dike/koswat_layer_plot.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/koswat/plots/dike/koswat_layer_plot.py b/koswat/plots/dike/koswat_layer_plot.py index cefbc07f..fb4c32b7 100644 --- a/koswat/plots/dike/koswat_layer_plot.py +++ b/koswat/plots/dike/koswat_layer_plot.py @@ -3,8 +3,6 @@ from koswat.dike.layers.koswat_layer_protocol import KoswatLayerProtocol from koswat.dike.material.koswat_material_type import KoswatMaterialType from koswat.plots.koswat_plot_protocol import KoswatPlotProtocol -from shapely import geometry -from numpy import concatenate class KoswatLayerPlot(KoswatPlotProtocol):