diff --git a/lib/stitches/tangential_fill_stitch_pattern_creator.py b/lib/stitches/tangential_fill_stitch_pattern_creator.py index 92a508cd1..c3ad00471 100644 --- a/lib/stitches/tangential_fill_stitch_pattern_creator.py +++ b/lib/stitches/tangential_fill_stitch_pattern_creator.py @@ -14,6 +14,7 @@ from ..stitches import constants from ..stitches import point_transfer from ..stitches import sample_linestring from ..stitch_plan import Stitch +from ..utils.geometry import cut, reverse_line_string, roll_linear_ring nearest_neighbor_tuple = namedtuple( "nearest_neighbor_tuple", @@ -26,34 +27,6 @@ nearest_neighbor_tuple = namedtuple( ) -def cut(line, distance): - """ - Cuts a closed line so that the new closed line starts at the - point with "distance" to the beginning of the old line. - """ - if distance <= 0.0 or distance >= line.length: - return [LineString(line)] - coords = list(line.coords) - for i, p in enumerate(coords): - if i > 0 and p == coords[0]: - pd = line.length - else: - pd = line.project(Point(p)) - if pd == distance: - if coords[0] == coords[-1]: - return LineString(coords[i:] + coords[1: i + 1]) - else: - return LineString(coords[i:] + coords[:i]) - if pd > distance: - cp = line.interpolate(distance) - if coords[0] == coords[-1]: - return LineString( - [(cp.x, cp.y)] + coords[i:] + coords[1:i] + [(cp.x, cp.y)] - ) - else: - return LineString([(cp.x, cp.y)] + coords[i:] + coords[:i]) - - def get_nearest_points_closer_than_thresh(travel_line, next_line, thresh): """ Takes a line and calculates the nearest distance along this @@ -237,7 +210,7 @@ def connect_raster_tree_from_inner_to_outer(tree, node, used_offset, stitch_dist start_distance = current_coords.project(close_point) # We cut the current path so that its index 0 is closest to close_point if start_distance > 0: - current_coords = cut(current_coords, start_distance) + current_coords = roll_linear_ring(current_coords, start_distance) current_node.val = current_coords if not current_node.transferred_point_priority_deque.is_empty(): @@ -254,6 +227,7 @@ def connect_raster_tree_from_inner_to_outer(tree, node, used_offset, stitch_dist # We try to use always the opposite stitching direction with respect to the # parent to avoid crossings when entering and leaving the child + # LEX: this seems like a lie ^^ parent_stitching_direction = -1 if current_node.parent is not None: parent_stitching_direction = tree.nodes[current_node.parent].stitching_direction diff --git a/lib/utils/geometry.py b/lib/utils/geometry.py index bce278ed4..ed1e2c0e7 100644 --- a/lib/utils/geometry.py +++ b/lib/utils/geometry.py @@ -5,7 +5,7 @@ import math -from shapely.geometry import LineString +from shapely.geometry import LineString, LinearRing from shapely.geometry import Point as ShapelyPoint @@ -39,6 +39,33 @@ def cut(line, distance, normalized=False): LineString([(cp.x, cp.y)] + coords[i:])] +def roll_linear_ring(ring, distance, normalized=False): + """Make a linear ring start at a different point. + + Example: A B C D E F G A -> D E F G A B C + + Same linear ring, different ordering of the coordinates. + """ + + if not isinstance(ring, LinearRing): + # In case they handed us a LineString + ring = LinearRing(ring) + + pieces = cut(LinearRing(ring), distance, normalized=False) + + if None in pieces: + # We cut exactly at the start or end. + return ring + + # The first and last point in a linear ring are duplicated, so we omit one + # copy + return LinearRing(pieces[1].coords[:] + pieces[0].coords[1:]) + + +def reverse_line_string(line_string): + return LineString(line_string.coords[::-1]) + + def cut_path(points, length): """Return a subsection of at the start of the path that is length units long.