diff options
| author | Kaalleen <36401965+kaalleen@users.noreply.github.com> | 2024-01-25 17:54:08 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-01-25 17:54:08 +0100 |
| commit | 2677c30a0f210d14586c83016f45e5a75fb9d647 (patch) | |
| tree | 04a91f0ee9a7f5723abe362890006ed383ddf74e /lib/utils | |
| parent | f44eff9e74b36507cd512aea7aa6f4d698a374d5 (diff) | |
Second chance for invalid fill stitch graphs (#2643)
Diffstat (limited to 'lib/utils')
| -rw-r--r-- | lib/utils/clamp_path.py | 9 | ||||
| -rw-r--r-- | lib/utils/geometry.py | 62 |
2 files changed, 43 insertions, 28 deletions
diff --git a/lib/utils/clamp_path.py b/lib/utils/clamp_path.py index 432f618a..f6db66a8 100644 --- a/lib/utils/clamp_path.py +++ b/lib/utils/clamp_path.py @@ -56,8 +56,10 @@ def adjust_line_end(line, end): def find_border(polygon, point): + """Finds subpath of polygon which intersects with the point. + Ignores small border fragments""" for border in polygon.interiors: - if border.intersects(point): + if border.length > 0.1 and border.intersects(point): return border else: return polygon.exterior @@ -76,7 +78,10 @@ def clamp_path_to_polygon(path, polygon): # This splits the path at the points where it intersects with the polygon # border and returns the pieces in the same order as the original path. - split_path = ensure_geometry_collection(LineString(path).difference(polygon.boundary)) + try: + split_path = ensure_geometry_collection(LineString(path).difference(polygon.boundary)) + except FloatingPointError: + return path if len(split_path.geoms) == 1: # The path never intersects with the polygon, so it's entirely inside. diff --git a/lib/utils/geometry.py b/lib/utils/geometry.py index 6ef0d439..47347a02 100644 --- a/lib/utils/geometry.py +++ b/lib/utils/geometry.py @@ -7,7 +7,8 @@ import math import typing import numpy -from shapely.geometry import LineString, LinearRing, MultiLineString, MultiPolygon, MultiPoint, GeometryCollection +from shapely.geometry import (GeometryCollection, LinearRing, LineString, + MultiLineString, MultiPolygon) from shapely.geometry import Point as ShapelyPoint @@ -102,47 +103,56 @@ def reverse_line_string(line_string): return LineString(line_string.coords[::-1]) -def ensure_multi_line_string(thing): - """Given either a MultiLineString, a single LineString or GeometryCollection, return a MultiLineString""" +def ensure_multi_line_string(thing, min_size=0): + """Given a shapely geometry, return a MultiLineString""" + multi_line_string = MultiLineString() if thing.is_empty: - return thing - if thing.geom_type == "LineString": - return MultiLineString([thing]) - if thing.geom_type == "GeometryCollection": + return multi_line_string + if thing.geom_type == "MultiLineString": + multi_line_string = thing + elif thing.geom_type == "LineString": + multi_line_string = MultiLineString([thing]) + elif thing.geom_type == "GeometryCollection": multilinestring = [] for line in thing.geoms: if line.geom_type == "LineString": multilinestring.append(line) - if multilinestring: - return MultiLineString(multilinestring) - return thing + multi_line_string = MultiLineString(multilinestring) + if min_size > 0: + multi_line_string = MultiLineString([line for line in multi_line_string.geoms if line.length > min_size]) + return multi_line_string def ensure_geometry_collection(thing): - """Given either some kind of geometry or a GeometryCollection, return a GeometryCollection""" - - if isinstance(thing, (MultiLineString, MultiPolygon, MultiPoint)): - return GeometryCollection(thing.geoms) - elif isinstance(thing, GeometryCollection): + """Given a shapely geometry, return a GeometryCollection""" + if thing.is_empty: + return GeometryCollection() + if thing.geom_type == "GeometryCollection": return thing - else: - return GeometryCollection([thing]) + if thing.geom_type in ["MultiLineString", "MultiPolygon", "MultiPoint"]: + return GeometryCollection(thing.geoms) + # LineString, Polygon, Point + return GeometryCollection([thing]) -def ensure_multi_polygon(thing): - """Given either a MultiPolygon or a single Polygon, return a MultiPolygon""" +def ensure_multi_polygon(thing, min_size=0): + """Given a shapely geometry, return a MultiPolygon""" + multi_polygon = MultiPolygon() if thing.is_empty: - return thing - if thing.geom_type == "Polygon": - return MultiPolygon([thing]) - if thing.geom_type == "GeometryCollection": + return multi_polygon + if thing.geom_type == "MultiPolygon": + multi_polygon = thing + elif thing.geom_type == "Polygon": + multi_polygon = MultiPolygon([thing]) + elif thing.geom_type == "GeometryCollection": multipolygon = [] for polygon in thing.geoms: if polygon.geom_type == "Polygon": multipolygon.append(polygon) - if multipolygon: - return MultiPolygon(multipolygon) - return thing + multi_polygon = MultiPolygon(multipolygon) + if min_size > 0: + multi_polygon = MultiPolygon([polygon for polygon in multi_polygon.geoms if polygon.area > min_size]) + return multi_polygon def cut_path(points, length): |
