summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaalleen <36401965+kaalleen@users.noreply.github.com>2023-05-06 18:31:54 +0200
committerGitHub <noreply@github.com>2023-05-06 18:31:54 +0200
commit2e62ba7926a19e2952148c6ced3b6ebf1a96d78a (patch)
tree611df4000c633b66746b64589bb4fafc4f310cf9
parent909df7b33b07420b086f9a70b1107dfd81f9175b (diff)
Avoid duplicated points in make_spiral (#2268)
* avoid duplicated points in make_spiral * circular fill: add end_row_spacing, repeats and bean repeats * fix circular fill if original shape is a circle
-rw-r--r--lib/elements/fill_stitch.py10
-rw-r--r--lib/elements/stroke.py5
-rw-r--r--lib/stitches/circular_fill.py68
-rw-r--r--lib/stitches/contour_fill.py6
4 files changed, 76 insertions, 13 deletions
diff --git a/lib/elements/fill_stitch.py b/lib/elements/fill_stitch.py
index 9e2eed45..a2d4855f 100644
--- a/lib/elements/fill_stitch.py
+++ b/lib/elements/fill_stitch.py
@@ -285,6 +285,7 @@ class FillStitch(EmbroideryElement):
sort_index=24,
type='float',
select_items=[('fill_method', 'auto_fill'),
+ ('fill_method', 'circular_fill'),
('fill_method', 'legacy_fill')],
default=None)
def end_row_spacing(self):
@@ -378,7 +379,8 @@ class FillStitch(EmbroideryElement):
tooltip=_('Defines how many times to run down and back along the path.'),
type='int',
default="1",
- select_items=[('fill_method', 'meander_fill')],
+ select_items=[('fill_method', 'meander_fill'),
+ ('fill_method', 'circular_fill')],
sort_index=33)
def repeats(self):
return max(1, self.get_int_param("repeats", 1))
@@ -391,7 +393,8 @@ class FillStitch(EmbroideryElement):
'A value of 2 would quintuple each stitch, etc.\n\n'
'A pattern with various repeats can be created with a list of values separated by a space.'),
type='str',
- select_items=[('fill_method', 'meander_fill')],
+ select_items=[('fill_method', 'meander_fill'),
+ ('fill_method', 'circular_fill')],
default=0,
sort_index=34)
def bean_stitch_repeats(self):
@@ -922,9 +925,12 @@ class FillStitch(EmbroideryElement):
shape,
self.angle,
self.row_spacing,
+ self.end_row_spacing,
self.staggers,
self.running_stitch_length,
self.running_stitch_tolerance,
+ self.bean_stitch_repeats,
+ self.repeats,
self.skip_last,
starting_point,
ending_point,
diff --git a/lib/elements/stroke.py b/lib/elements/stroke.py
index ba525c2d..7ec6b76c 100644
--- a/lib/elements/stroke.py
+++ b/lib/elements/stroke.py
@@ -188,9 +188,10 @@ class Stroke(EmbroideryElement):
@property
@param('staggers',
- _('Stagger lines this many times before repeating. For linear ripples only.'),
+ _('Stagger lines this many times before repeating'),
tooltip=_('Length of the cycle by which successive stitch lines are staggered. '
- 'Fractional values are allowed and can have less visible diagonals than integer values.'),
+ 'Fractional values are allowed and can have less visible diagonals than integer values. '
+ 'For linear ripples only.'),
type='int',
select_items=[('stroke_method', 'ripple_stitch')],
default=1,
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):
diff --git a/lib/stitches/contour_fill.py b/lib/stitches/contour_fill.py
index f5f2a3ee..2ea61afb 100644
--- a/lib/stitches/contour_fill.py
+++ b/lib/stitches/contour_fill.py
@@ -574,6 +574,10 @@ def _make_spiral(rings, stitch_length, starting_point):
check_stop_flag()
spiral_part = _interpolate_linear_rings(ring1, ring2, stitch_length, starting_point)
- path.extend(spiral_part.coords)
+ # skip last to avoid duplicated points
+ path.extend(spiral_part.coords[:-1])
+
+ # at the end add last point
+ path.append(spiral_part.coords[-1])
return path