Skip to content

Commit 312256b

Browse files
committedDec 1, 2023
Added more geometry checks
1 parent 6a672f6 commit 312256b

File tree

3 files changed

+88
-27
lines changed

3 files changed

+88
-27
lines changed
 

‎DEV/test3.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
from shapely.geometry import Polygon
22

33
# Define two polygons
4-
polygon1 = Polygon([(0, 0), (2, 0), (2, 2), (0, 2)])
5-
polygon2 = Polygon([(0, 0), (2, 0), (3, 2), (1, 2)])
4+
polygon1 = Polygon([(0, 0), (1, 0), (1, 1), (0, 1)])
5+
polygon2 = Polygon([(1, 0), (2, 0), (2, 1) ])
66

7-
# Check if they share part of the boundary
8-
share_boundary = polygon1.intersects(polygon2) and polygon1.touches(polygon2) and not (polygon1.contains(polygon2) or polygon2.contains(polygon1))
7+
# Perform the union operation
8+
union_polygon = polygon1.union(polygon2)
99

10-
print("Do the polygons share part of the boundary? ", share_boundary)
10+
# Print the result
11+
print(union_polygon, union_polygon.is_valid)
12+
13+
for elem in union_polygon:
14+
print(elem)

‎source/geometry.py

+78-21
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
from source.guistatics import GUIStatics
3232
import copy
3333
from PIL import ImageTk
34-
from shapely.geometry import Polygon
34+
from shapely.geometry import Polygon, Point, MultiPolygon
35+
from shapely.ops import unary_union
36+
import numpy as np
3537

3638
class Geometry(tk.Toplevel):
3739
"""
@@ -875,48 +877,103 @@ def check_geometry_detail(self):
875877
Detailed check for geometry
876878
:return:
877879
"""
880+
# TODO: this needs a lot of bugfixing. detects problems for good geometry...
878881
check_passed = True
879-
880882
check_fail_str = ''
881883
check_failed_list = []
884+
882885
for ip1, poly1 in enumerate(self.polygons.values()):
883886
poly1_shapely = Polygon([(node[0], node[1]) for node in poly1['coordinates']])
887+
888+
# check polygon shape
889+
# check if > 1 node have same position
890+
nodes_polygon = np.array(poly1['coordinates'])
891+
nodes_polygon_complex = [node[0] + 1j * node[1] for node in nodes_polygon]
892+
if len(set(nodes_polygon_complex)) != len(nodes_polygon):
893+
check_fail_str = f"Geometry error: At least two nodes of polygon {ip1} are identical"
894+
check_failed_list.append(check_fail_str)
895+
# check if polygon is valid (lines not crossing, area > 0)
896+
if not poly1_shapely.is_valid:
897+
check_fail_str = f"Geometry error: Polygon {ip1} invalid (Segments crossing/Zero Area)"
898+
check_failed_list.append(check_fail_str)
899+
900+
# check single points
901+
if self.points and self.points != {'None'}:
902+
for sp, point in enumerate(self.points.values()):
903+
p_in_pos_poly = False
904+
if poly1_shapely.touches(Point(point[0], point[1])):
905+
check_fail_str = f"Geometry error: Point {sp} on boundary of Polygon {ip1}"
906+
check_failed_list.append(check_fail_str)
907+
if poly1_shapely.contains(Point(point[0], point[1])):
908+
p_in_pos_poly = True
909+
if poly1['area_neg_pos'] == 'Negative':
910+
p_in_pos_poly = False
911+
check_fail_str = f"Geometry error: Point {sp} inside of negative Polygon {ip1}"
912+
check_failed_list.append(check_fail_str)
913+
if not p_in_pos_poly:
914+
check_fail_str = f"Geometry error: Point {sp} not inside of any positive Polygon"
915+
check_failed_list.append(check_fail_str)
916+
# check two polygons
884917
for ip2, poly2 in enumerate(list(self.polygons.values())[ip1 + 1:], start=ip1+1):
885918
poly2_shapely = Polygon([(node[0], node[1]) for node in poly2['coordinates']])
919+
886920
# check if positive polygons overlap
887921
if poly1['area_neg_pos'] == 'Positive' and poly2['area_neg_pos'] == 'Positive':
888922
if poly1_shapely.overlaps(poly2_shapely):
889-
check_fail_str = f"Geometryerror: Positive Polygon {ip1} and Positive Polygon {ip2} overlap"
923+
check_fail_str = f"Geometry error: Positive Polygon {ip1} and Positive Polygon {ip2} overlap"
890924
check_failed_list.append(check_fail_str)
891925
# check if negative polygons overlap
892926
if poly1['area_neg_pos'] == 'Negative' and poly2['area_neg_pos'] == 'Negative':
893927
if poly1_shapely.overlaps(poly2_shapely):
894-
check_fail_str = f"Geometryerror: Negative Polygon {ip1} and Negative Polygon {ip2} overlap"
928+
check_fail_str = f"Geometry error: Negative Polygon {ip1} and Negative Polygon {ip2} overlap"
929+
check_failed_list.append(check_fail_str)
930+
if poly1_shapely.touches(poly2_shapely):
931+
check_fail_str = f"Geometry error: Negative Polygon {ip1} and Negative Polygon {ip2} intersect/touch at least once"
895932
check_failed_list.append(check_fail_str)
896933
# check if negative polygon inside positive polygon
897934
if poly1['area_neg_pos'] == 'Positive' and poly2['area_neg_pos'] == 'Negative':
898-
if poly1_shapely.intersects(poly2_shapely):
899-
if not poly1_shapely.contains(poly2_shapely):
900-
check_fail_str = f"Geometryerror: Positive Polygon {ip1} and Negative Polygon {ip2} intersect"
935+
if poly1_shapely.contains(poly2_shapely):
936+
for node in poly2['coordinates']:
937+
if poly1_shapely.touches(Point(node[0], node[1])):
938+
check_fail_str = f"Geometry error: Positive Polygon {ip1} and Negative Polygon {ip2} overlap (on boundary)"
901939
check_failed_list.append(check_fail_str)
940+
break
902941
if poly1['area_neg_pos'] == 'Negative' and poly2['area_neg_pos'] == 'Positive':
903-
if poly1_shapely.intersects(poly2_shapely):
904-
if not poly2_shapely.contains(poly1_shapely):
905-
check_fail_str = f"Geometryerror: Negative Polygon {ip1} and Positive Polygon {ip2} intersect"
942+
if poly2_shapely.contains(poly1_shapely):
943+
for node in poly1['coordinates']:
944+
if poly2_shapely.touches(Point(node[0], node[1])):
945+
check_fail_str = f"Geometry error: Negative Polygon {ip1} and Positive Polygon {ip2} overlap (on boundary)"
906946
check_failed_list.append(check_fail_str)
947+
break
948+
# check if two adjacent positive polygons share the same nodes
949+
if poly1['area_neg_pos'] == 'Positive' and poly2['area_neg_pos'] == 'Positive':
950+
shared_boundary = poly1_shapely.intersection(poly2_shapely)
951+
if shared_boundary.geom_type == 'LineString':
952+
coords = list(shared_boundary.coords)
953+
elif shared_boundary.geom_type == 'MultiLineString':
954+
coords = [list(line.coords) for line in shared_boundary]
955+
elif shared_boundary.geom_type == 'Point':
956+
check_fail_str = f"Geometry error: Polygon {ip1} and Polygon {ip2} share only one node"
957+
check_failed_list.append(check_fail_str)
958+
else:
959+
coords = []
960+
poly1nodes_complex = [node[0] + 1j * node[1] for node in np.array(poly1['coordinates'])]
961+
poly2nodes_complex = [node[0] + 1j * node[1] for node in np.array(poly2['coordinates'])]
962+
shared_nodes_complex = [node[0] + 1j * node[1] for node in coords]
963+
in_poly1 = len(set(poly1nodes_complex).intersection(set(shared_nodes_complex)))
964+
in_poly2 = len(set(poly2nodes_complex).intersection(set(shared_nodes_complex)))
965+
if in_poly1 != in_poly2:
966+
check_fail_str = f"Geometry error: Polygon {ip1} and Polygon {ip2} do not share same nodes on common boundary"
967+
check_failed_list.append(check_fail_str)
907968

969+
# check if all positive polygons are connected
970+
all_pos_polygons = [Polygon(poly['coordinates']) for poly in self.polygons.values() if poly['area_neg_pos'] == 'Positive']
971+
unioned_polygons = unary_union(all_pos_polygons)
972+
if isinstance(unioned_polygons, MultiPolygon):
973+
check_fail_str = f"Geometry error: Positive Polygons are not connected properly"
974+
check_failed_list.append(check_fail_str)
908975

909-
910-
# # Check if negative polygon intersects with positive polygon (boundary crossed/shared)
911-
# if poly1['area_neg_pos'] == 'Positive' and poly2['area_neg_pos'] == 'Negative':
912-
# if poly1_shapely.intersects(poly2_shapely) and not poly1_shapely.contains(poly2_shapely):
913-
# check_fail_str = f"Geometryerror: Positive Polygon {ip1} and Negative Polygon {ip2} intersect"
914-
# check_failed_list.append(check_fail_str)
915-
# if poly1['area_neg_pos'] == 'Negative' and poly2['area_neg_pos'] == 'Positive':
916-
# if poly1_shapely.intersects(poly2_shapely) and not poly2_shapely.contains(poly1_shapely):
917-
# check_fail_str = f"Geometryerror: Negative Polygon {ip1} and Positive Polygon {ip2} intersect"
918-
# check_failed_list.append(check_fail_str)
919-
976+
check_failed_list = list(set(check_failed_list))
920977
for elem in check_failed_list:
921978
print(elem)
922979

‎testing/geom_overlapping.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"polygons": {"0": {"coordinates": [[0.5, 0.5], [1.5, 0.5], [1.5, 1.5], [0.5, 1.5]], "area_neg_pos": "Positive"}, "1": {"coordinates": [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]], "area_neg_pos": "Positive"}, "2": {"coordinates": [[-1.0, -1.0], [0.0, -1.0], [0.0, 0.0], [-1.0, 0.0]], "area_neg_pos": "Positive"}, "3": {"coordinates": [[-2.0, 1.0], [-1.0, 1.0], [-2.0, 2.0]], "area_neg_pos": "Positive"}, "4": {"coordinates": [[0.2, 0.2], [0.5, 0.2], [0.5, 0.3]], "area_neg_pos": "Negative"}, "5": {"coordinates": [[0.0, 1.0], [0.25, 1.0], [0.1, 0.5]], "area_neg_pos": "Negative"}, "6": {"coordinates": [[-0.5, -0.5], [-0.25, -0.5], [-0.1, -0.1]], "area_neg_pos": "Negative"}, "7": {"coordinates": [[0.6, 1.8], [0.9, 1.8], [0.7, 1.1]], "area_neg_pos": "Negative"}, "8": {"coordinates": [[0.55, 1.2], [1.0, 1.2], [1.0, 1.3]], "area_neg_pos": "Negative"}, "9": {"coordinates": [[-1.0, -1.0], [0.0, -1.0], [-0.5, -0.9]], "area_neg_pos": "Negative"}}, "points": {"None": "None"}, "units": "m", "other": "None"}
1+
{"polygons": {"0": {"coordinates": [[0.5, 0.5], [1.5, 0.5], [1.5, 1.5], [0.5, 1.5]], "area_neg_pos": "Positive"}, "1": {"coordinates": [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0]], "area_neg_pos": "Positive"}, "2": {"coordinates": [[-1.0, -1.0], [0.0, -1.0], [0.0, 0.0], [-1.0, 0.0]], "area_neg_pos": "Positive"}, "3": {"coordinates": [[-2.0, 1.0], [-1.0, 1.0], [-2.0, 2.0]], "area_neg_pos": "Positive"}, "4": {"coordinates": [[0.2, 0.2], [0.5, 0.2], [0.5, 0.3]], "area_neg_pos": "Negative"}, "5": {"coordinates": [[0.0, 1.0], [0.25, 1.0], [0.1, 0.5]], "area_neg_pos": "Negative"}, "6": {"coordinates": [[-0.5, -0.5], [-0.25, -0.5], [-0.1, -0.1]], "area_neg_pos": "Negative"}, "7": {"coordinates": [[0.6, 1.8], [0.9, 1.8], [0.7, 1.1]], "area_neg_pos": "Negative"}, "8": {"coordinates": [[0.55, 1.2], [1.0, 1.2], [1.0, 1.3]], "area_neg_pos": "Negative"}, "9": {"coordinates": [[-1.0, -1.0], [0.0, -1.0], [-0.5, -0.9]], "area_neg_pos": "Negative"}, "10": {"coordinates": [[-2.0, 1.0], [-1.0, 1.0], [-1.0, 0.0]], "area_neg_pos": "Positive"}}, "points": {"0": [-2.0, 0.0], "1": [-0.5, 0.0], "2": [-0.5, -0.1], "3": [0.1, 0.8]}, "units": "m", "other": "None"}

0 commit comments

Comments
 (0)