diff options
Diffstat (limited to 'lib/utils/clamp_path.py')
| -rw-r--r-- | lib/utils/clamp_path.py | 23 |
1 files changed, 23 insertions, 0 deletions
diff --git a/lib/utils/clamp_path.py b/lib/utils/clamp_path.py index 0f58f83c..fcb34a4b 100644 --- a/lib/utils/clamp_path.py +++ b/lib/utils/clamp_path.py @@ -1,5 +1,6 @@ from shapely.geometry import LineString, MultiPolygon from shapely.geometry import Point as ShapelyPoint +from shapely.ops import nearest_points from shapely.prepared import prep from .geometry import (Point, ensure_geometry_collection, @@ -14,6 +15,9 @@ def path_to_segments(path): def segments_to_path(segments): """Convert a list of contiguous LineStrings into a list of Points.""" + if not segments: + return [] + coords = [segments[0].coords[0]] for segment in segments: @@ -68,6 +72,22 @@ def find_border(polygon, point): return polygon.exterior +def clamp_fully_external_path(path, polygon): + """Clamp a path that lies entirely outside a polygon.""" + + start = ShapelyPoint(path[0]) + end = ShapelyPoint(path[-1]) + + start_on_outline = nearest_points(start, polygon.exterior)[1].buffer(0.01, resolution=1) + end_on_outline = nearest_points(end, polygon.exterior)[1].buffer(0.01, resolution=1) + + border_pieces = ensure_multi_line_string(polygon.exterior.difference(MultiPolygon((start_on_outline, end_on_outline)))).geoms + border_pieces = fix_starting_point(border_pieces) + shorter = min(border_pieces, key=lambda piece: piece.length) + + return adjust_line_end(shorter, start) + + def clamp_path_to_polygon(path, polygon): """Constrain a path to a Polygon. @@ -143,4 +163,7 @@ def clamp_path_to_polygon(path, polygon): else: was_inside = False + if not result: + return clamp_fully_external_path(path, polygon) + return segments_to_path(result) |
