diff options
Diffstat (limited to 'lib/stitches/circular_fill.py')
| -rw-r--r-- | lib/stitches/circular_fill.py | 68 |
1 files changed, 60 insertions, 8 deletions
diff --git a/lib/stitches/circular_fill.py b/lib/stitches/circular_fill.py index 91943b90..233e326e 100644 --- a/lib/stitches/circular_fill.py +++ b/lib/stitches/circular_fill.py @@ -1,4 +1,5 @@ from shapely import geometry as shgeo +from shapely.ops import substring from ..stitch_plan import Stitch from ..utils.geometry import reverse_line_string @@ -6,15 +7,18 @@ from .auto_fill import (build_fill_stitch_graph, build_travel_graph, collapse_sequential_outline_edges, fallback, find_stitch_path, graph_is_valid, travel) from .contour_fill import _make_fermat_spiral -from .running_stitch import running_stitch +from .running_stitch import bean_stitch, running_stitch def circular_fill(shape, angle, row_spacing, + end_row_spacing, num_staggers, running_stitch_length, running_stitch_tolerance, + bean_stitch_repeats, + repeats, skip_last, starting_point, ending_point, @@ -24,16 +28,27 @@ def circular_fill(shape, # get furthest distance of the target point to a shape border # so we know how many circles we will need - distance = shape.hausdorff_distance(target) + 1 + distance = shape.hausdorff_distance(target) radius = row_spacing center = shgeo.Point(target) + if radius > distance: + # if the shape is smaller than row_spacing, return a simple circle in the size of row_spacing + stitches = running_stitch([Stitch(*point) for point in center.buffer(radius).exterior.coords], + running_stitch_length, running_stitch_tolerance) + return _apply_bean_stitch_and_repeats(stitches, repeats, bean_stitch_repeats) + circles = [] # add a small inner circle to make sure that the spiral ends close to the center circles.append(shgeo.LineString(center.buffer(0.1).exterior.coords)) - while distance > radius: + # add twice the size of the (end_)row_spacing to make sure we go big enough + stopp_at_distance = distance + (end_row_spacing or row_spacing) * 2 + while radius < stopp_at_distance: circles.append(shgeo.LineString(center.buffer(radius).exterior.coords)) - radius += row_spacing + if end_row_spacing: + radius += row_spacing + (end_row_spacing - row_spacing) * (radius / distance) + else: + radius += row_spacing circles.reverse() # Use double spiral from contour fill (we don't want to get stuck in the middle of the spiral) @@ -41,6 +56,13 @@ def circular_fill(shape, double_spiral = shgeo.LineString(list(double_spiral)) intersection = double_spiral.intersection(shape) + if isinstance(intersection, shgeo.LineString): + # if we get a single linestrig (original shape is a circle), apply start and end commands and return path + path = list(intersection.coords) + path = _apply_start_end_commands(shape, path, starting_point, ending_point) + stitches = running_stitch([Stitch(*point) for point in path], running_stitch_length, running_stitch_tolerance) + return _apply_bean_stitch_and_repeats(stitches, repeats, bean_stitch_repeats) + segments = [] for line in intersection.geoms: if isinstance(line, shgeo.LineString): @@ -55,11 +77,41 @@ def circular_fill(shape, result = path_to_stitches(path, travel_graph, fill_stitch_graph, running_stitch_length, running_stitch_tolerance, skip_last) # use running stitch to adjust the stitch length - result = running_stitch(result, - running_stitch_length, - running_stitch_tolerance) + result = running_stitch(result, running_stitch_length, running_stitch_tolerance) + return _apply_bean_stitch_and_repeats(result, repeats, bean_stitch_repeats) + + +def _apply_bean_stitch_and_repeats(stitches, repeats, bean_stitch_repeats): + if any(bean_stitch_repeats): + stitches = bean_stitch(stitches, bean_stitch_repeats) + + if repeats: + for i in range(1, repeats): + if i % 2 == 1: + # reverse every other pass + stitches.extend(stitches[::-1]) + else: + stitches.extend(stitches) + + return stitches + + +def _apply_start_end_commands(shape, path, starting_point, ending_point): + if starting_point or ending_point: + outline = shape.boundary + if starting_point: + start = _get_start_end_sequence(outline, shgeo.Point(*starting_point), shgeo.Point(*path[0])) + path = list(start.coords) + path + if ending_point: + end = _get_start_end_sequence(outline, shgeo.Point(*path[-1]), shgeo.Point(*ending_point)) + path.extend(list(end.coords)) + return path + - return result +def _get_start_end_sequence(outline, start, end): + start_dist = outline.project(start) + end_dist = outline.project(end) + return substring(outline, start_dist, end_dist) def path_to_stitches(path, travel_graph, fill_stitch_graph, running_stitch_length, running_stitch_tolerance, skip_last): |
