kopia lustrzana https://github.com/inkstitch/inkstitch
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 circlepull/2274/head
rodzic
909df7b33b
commit
2e62ba7926
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
||||
return result
|
||||
|
||||
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
|
||||
|
||||
|
||||
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):
|
||||
|
|
|
@ -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
|
||||
|
|
Ładowanie…
Reference in New Issue