diff options
Diffstat (limited to 'lib/utils')
| -rw-r--r-- | lib/utils/clamp_path.py | 21 | ||||
| -rw-r--r-- | lib/utils/smoothing.py | 10 |
2 files changed, 19 insertions, 12 deletions
diff --git a/lib/utils/clamp_path.py b/lib/utils/clamp_path.py index e5ef78d8..f9b8991a 100644 --- a/lib/utils/clamp_path.py +++ b/lib/utils/clamp_path.py @@ -1,6 +1,6 @@ from shapely.geometry import LineString, Point as ShapelyPoint, MultiPolygon from shapely.prepared import prep -from .geometry import Point, ensure_multi_line_string +from .geometry import Point, ensure_geometry_collection def path_to_segments(path): @@ -66,23 +66,34 @@ def find_border(polygon, point): def clamp_path_to_polygon(path, polygon): """Constrain a path to a Polygon. + The path is expected to have at least some part inside the Polygon. + Description: https://gis.stackexchange.com/questions/428848/clamp-linestring-to-polygon """ - path = LineString(path) + start = path[0] + end = path[-1] # 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_multi_line_string(path.difference(polygon.boundary)) + split_path = ensure_geometry_collection(LineString(path).difference(polygon.boundary)) + + if len(split_path.geoms) == 1: + # The path never intersects with the polygon, so it's entirely inside. + return path + + # Add the start and end points to avoid losing part of the path if the + # start or end coincides with the polygon boundary + split_path = [ShapelyPoint(start), *split_path.geoms, ShapelyPoint(end)] - # contains() checks can fail without this. + # contains() checks can fail without the buffer. buffered_polygon = prep(polygon.buffer(1e-9)) last_segment_inside = None was_inside = False result = [] - for segment in split_path.geoms: + for segment in split_path: if buffered_polygon.contains(segment): if not was_inside: if last_segment_inside is not None: diff --git a/lib/utils/smoothing.py b/lib/utils/smoothing.py index 1bb250c5..2c210e37 100644 --- a/lib/utils/smoothing.py +++ b/lib/utils/smoothing.py @@ -3,7 +3,6 @@ from scipy.interpolate import splprep, splev from .geometry import Point, coordinate_list_to_point_list from ..stitches.running_stitch import running_stitch -from ..debug import debug def _remove_duplicate_coordinates(coords_array): @@ -23,7 +22,6 @@ def _remove_duplicate_coordinates(coords_array): return coords_array[keepers] -@debug.time def smooth_path(path, smoothness=1.0): """Smooth a path of coordinates. @@ -70,8 +68,7 @@ def smooth_path(path, smoothness=1.0): # .T transposes the array (for some reason splprep expects # [[x1, x2, ...], [y1, y2, ...]] - with debug.time_this("splprep"): - tck, fp, ier, msg = splprep(coords.T, s=s, k=3, nest=-1, full_output=1) + tck, fp, ier, msg = splprep(coords.T, s=s, k=3, nest=-1, full_output=1) if ier > 0: debug.log(f"error {ier} smoothing path: {msg}") return path @@ -79,8 +76,7 @@ def smooth_path(path, smoothness=1.0): # Evaluate the spline curve at many points along its length to produce the # smoothed point list. 2 * num_points seems to be a good number, but it # does produce a lot of points. - with debug.time_this("splev"): - smoothed_x_values, smoothed_y_values = splev(np.linspace(0, 1, int(num_points * 2)), tck[0]) - coords = np.array([smoothed_x_values, smoothed_y_values]).T + smoothed_x_values, smoothed_y_values = splev(np.linspace(0, 1, int(num_points * 2)), tck[0]) + coords = np.array([smoothed_x_values, smoothed_y_values]).T return [Point(x, y) for x, y in coords] |
