add running stitch tolerance param (#1701)

pull/1702/head
Lex Neva 2022-06-22 09:26:37 -04:00 zatwierdzone przez GitHub
rodzic b6bde000fe
commit e884fb78db
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 66 dodań i 30 usunięć

Wyświetl plik

@ -366,6 +366,19 @@ class FillStitch(EmbroideryElement):
def running_stitch_length(self):
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
@property
@param('running_stitch_tolerance_mm',
_('Running stitch tolerance'),
tooltip=_('All stitches must be within this distance of the path. ' +
'A lower tolerance means stitches will be closer together. ' +
'A higher tolerance means sharp corners may be rounded.'),
unit='mm',
type='float',
default=0.2,
sort_index=6)
def running_stitch_tolerance(self):
return max(self.get_float_param("running_stitch_tolerance_mm", 0.2), 0.01)
@property
@param('fill_underlay', _('Underlay'), type='toggle', group=_('Fill Underlay'), default=True)
def fill_underlay(self):
@ -560,6 +573,7 @@ class FillStitch(EmbroideryElement):
self.fill_underlay_row_spacing,
self.fill_underlay_max_stitch_length,
self.running_stitch_length,
self.running_stitch_tolerance,
self.staggers,
self.fill_underlay_skip_last,
starting_point,
@ -580,6 +594,7 @@ class FillStitch(EmbroideryElement):
self.end_row_spacing,
self.max_stitch_length,
self.running_stitch_length,
self.running_stitch_tolerance,
self.staggers,
self.skip_last,
starting_point,
@ -601,6 +616,7 @@ class FillStitch(EmbroideryElement):
tree,
self.row_spacing,
self.max_stitch_length,
self.running_stitch_tolerance,
starting_point,
self.avoid_self_crossing
)
@ -608,12 +624,14 @@ class FillStitch(EmbroideryElement):
stitches = contour_fill.single_spiral(
tree,
self.max_stitch_length,
self.running_stitch_tolerance,
starting_point
)
elif self.contour_strategy == 2:
stitches = contour_fill.double_spiral(
tree,
self.max_stitch_length,
self.running_stitch_tolerance,
starting_point
)

Wyświetl plik

@ -111,6 +111,19 @@ class Stroke(EmbroideryElement):
def running_stitch_length(self):
return max(self.get_float_param("running_stitch_length_mm", 1.5), 0.01)
@property
@param('running_stitch_tolerance_mm',
_('Running stitch tolerance'),
tooltip=_('All stitches must be within this distance from the path. ' +
'A lower tolerance means stitches will be closer together. ' +
'A higher tolerance means sharp corners may be rounded.'),
unit='mm',
type='float',
default=0.2,
sort_index=4)
def running_stitch_tolerance(self):
return max(self.get_float_param("running_stitch_tolerance_mm", 0.2), 0.01)
@property
@param('zigzag_spacing_mm',
_('Zig-zag spacing (peak-to-peak)'),
@ -360,7 +373,7 @@ class Stroke(EmbroideryElement):
# `self.zigzag_spacing` is the length for a zig and a zag
# together (a V shape). Start with running stitch at half
# that length:
patch = self.running_stitch(path, zigzag_spacing / 2.0)
patch = self.running_stitch(path, zigzag_spacing / 2.0, self.running_stitch_tolerance)
# Now move the points left and right. Consider each pair
# of points in turn, and move perpendicular to them,
@ -385,7 +398,7 @@ class Stroke(EmbroideryElement):
return patch
def running_stitch(self, path, stitch_length):
def running_stitch(self, path, stitch_length, tolerance):
repeated_path = []
# go back and forth along the path as specified by self.repeats
@ -398,7 +411,7 @@ class Stroke(EmbroideryElement):
repeated_path.extend(this_path)
stitches = running_stitch(repeated_path, stitch_length)
stitches = running_stitch(repeated_path, stitch_length, tolerance)
return StitchGroup(self.color, stitches)
@ -429,7 +442,7 @@ class Stroke(EmbroideryElement):
patch = StitchGroup(color=self.color, stitches=path, stitch_as_is=True)
# running stitch
elif self.is_running_stitch():
patch = self.running_stitch(path, self.running_stitch_length)
patch = self.running_stitch(path, self.running_stitch_length, self.running_stitch_tolerance)
if self.bean_stitch_repeats > 0:
patch.stitches = self.do_bean_repeats(patch.stitches)
# simple satin

Wyświetl plik

@ -53,6 +53,7 @@ def auto_fill(shape,
end_row_spacing,
max_stitch_length,
running_stitch_length,
running_stitch_tolerance,
staggers,
skip_last,
starting_point,
@ -64,15 +65,16 @@ def auto_fill(shape,
fill_stitch_graph = build_fill_stitch_graph(shape, segments, starting_point, ending_point)
except ValueError:
# Small shapes will cause the graph to fail - min() arg is an empty sequence through insert node
return fallback(shape, running_stitch_length)
return fallback(shape, running_stitch_length, running_stitch_tolerance)
if not graph_is_valid(fill_stitch_graph, shape, max_stitch_length):
return fallback(shape, running_stitch_length)
return fallback(shape, running_stitch_length, running_stitch_tolerance)
travel_graph = build_travel_graph(fill_stitch_graph, shape, angle, underpath)
path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
result = path_to_stitches(path, travel_graph, fill_stitch_graph, angle, row_spacing,
max_stitch_length, running_stitch_length, staggers, skip_last)
max_stitch_length, running_stitch_length, running_stitch_tolerance,
staggers, skip_last)
return result
@ -251,7 +253,7 @@ def graph_is_valid(graph, shape, max_stitch_length):
return not networkx.is_empty(graph) and networkx.is_eulerian(graph)
def fallback(shape, running_stitch_length):
def fallback(shape, running_stitch_length, running_stitch_tolerance):
"""Generate stitches when the auto-fill algorithm fails.
If graph_is_valid() returns False, we're not going to be able to run the
@ -263,7 +265,7 @@ def fallback(shape, running_stitch_length):
boundary = ensure_multi_line_string(shape.boundary)
outline = boundary.geoms[0]
return running_stitch(line_string_to_point_list(outline), running_stitch_length)
return running_stitch(line_string_to_point_list(outline), running_stitch_length, running_stitch_tolerance)
@debug.time
@ -583,12 +585,12 @@ def collapse_sequential_outline_edges(path):
return new_path
def travel(travel_graph, start, end, running_stitch_length, skip_last):
def travel(travel_graph, start, end, running_stitch_length, running_stitch_tolerance, skip_last):
"""Create stitches to get from one point on an outline of the shape to another."""
path = networkx.shortest_path(travel_graph, start, end, weight='weight')
path = [Stitch(*p) for p in path]
stitches = running_stitch(path, running_stitch_length)
stitches = running_stitch(path, running_stitch_length, running_stitch_tolerance)
for stitch in stitches:
stitch.add_tag('auto_fill_travel')
@ -610,7 +612,8 @@ def travel(travel_graph, start, end, running_stitch_length, skip_last):
@debug.time
def path_to_stitches(path, travel_graph, fill_stitch_graph, angle, row_spacing, max_stitch_length, running_stitch_length, staggers, skip_last):
def path_to_stitches(path, travel_graph, fill_stitch_graph, angle, row_spacing, max_stitch_length, running_stitch_length, running_stitch_tolerance,
staggers, skip_last):
path = collapse_sequential_outline_edges(path)
stitches = []
@ -624,6 +627,6 @@ def path_to_stitches(path, travel_graph, fill_stitch_graph, angle, row_spacing,
stitch_row(stitches, edge[0], edge[1], angle, row_spacing, max_stitch_length, staggers, skip_last)
travel_graph.remove_edges_from(fill_stitch_graph[edge[0]][edge[1]]['segment'].get('underpath_edges', []))
else:
stitches.extend(travel(travel_graph, edge[0], edge[1], running_stitch_length, skip_last))
stitches.extend(travel(travel_graph, edge[0], edge[1], running_stitch_length, running_stitch_tolerance, skip_last))
return stitches

Wyświetl plik

@ -391,12 +391,12 @@ def _find_path_inner_to_outer(tree, node, offset, starting_point, avoid_self_cro
return LineString(result_coords)
def inner_to_outer(tree, offset, stitch_length, starting_point, avoid_self_crossing):
def inner_to_outer(tree, offset, stitch_length, tolerance, starting_point, avoid_self_crossing):
"""Fill a shape with spirals, from innermost to outermost."""
stitch_path = _find_path_inner_to_outer(tree, 'root', offset, starting_point, avoid_self_crossing)
points = [Stitch(*point) for point in stitch_path.coords]
stitches = running_stitch(points, stitch_length)
stitches = running_stitch(points, stitch_length, tolerance)
return stitches
@ -490,24 +490,24 @@ def _check_and_prepare_tree_for_valid_spiral(tree):
return process_node('root')
def single_spiral(tree, stitch_length, starting_point):
def single_spiral(tree, stitch_length, tolerance, starting_point):
"""Fill a shape with a single spiral going from outside to center."""
return _spiral_fill(tree, stitch_length, starting_point, _make_spiral)
return _spiral_fill(tree, stitch_length, tolerance, starting_point, _make_spiral)
def double_spiral(tree, stitch_length, starting_point):
def double_spiral(tree, stitch_length, tolerance, starting_point):
"""Fill a shape with a double spiral going from outside to center and back to outside. """
return _spiral_fill(tree, stitch_length, starting_point, _make_fermat_spiral)
return _spiral_fill(tree, stitch_length, tolerance, starting_point, _make_fermat_spiral)
def _spiral_fill(tree, stitch_length, close_point, spiral_maker):
def _spiral_fill(tree, stitch_length, tolerance, close_point, spiral_maker):
starting_point = close_point.coords[0]
rings = _get_spiral_rings(tree)
path = spiral_maker(rings, stitch_length, starting_point)
path = [Stitch(*stitch) for stitch in path]
return running_stitch(path, stitch_length)
return running_stitch(path, stitch_length, tolerance)
def _get_spiral_rings(tree):

Wyświetl plik

@ -30,7 +30,7 @@ def ripple_stitch(stroke):
if stroke.grid_size != 0:
ripple_points.extend(_do_grid(stroke, helper_lines))
stitches = running_stitch(ripple_points, stroke.running_stitch_length)
stitches = running_stitch(ripple_points, stroke.running_stitch_length, stroke.running_stitch_tolerance)
return _repeat_coords(stitches, stroke.repeats)
@ -57,7 +57,9 @@ def _get_helper_lines(stroke):
if len(lines) > 1:
return True, _get_satin_ripple_helper_lines(stroke)
else:
outline = LineString(running_stitch(line_string_to_point_list(lines[0]), stroke.grid_size or stroke.running_stitch_length))
outline = LineString(running_stitch(line_string_to_point_list(lines[0]),
stroke.grid_size or stroke.running_stitch_length,
stroke.running_stitch_tolerance))
if stroke.is_closed:
return False, _get_circular_ripple_helper_lines(stroke, outline)
@ -146,7 +148,7 @@ def _get_guided_helper_lines(stroke, outline, max_distance):
def _generate_guided_helper_lines(stroke, outline, max_distance, guide_line):
# helper lines are generated by making copies of the outline alog the guide line
line_point_dict = defaultdict(list)
outline = LineString(running_stitch(line_string_to_point_list(outline), max_distance))
outline = LineString(running_stitch(line_string_to_point_list(outline), max_distance, stroke.running_stitch_tolerance))
center = outline.centroid
center = InkstitchPoint(center.x, center.y)

Wyświetl plik

@ -3,16 +3,15 @@
# Copyright (c) 2010 Authors
# Licensed under the GNU GPL version 3.0 or later. See the file LICENSE for details.
from ..debug import debug
import math
from copy import copy
from shapely.geometry import LineString
""" Utility functions to produce running stitches. """
@debug.time
def running_stitch(points, stitch_length):
def running_stitch(points, stitch_length, tolerance):
"""Generate running stitch along a path.
Given a path and a stitch length, walk along the path in increments of the
@ -28,9 +27,9 @@ def running_stitch(points, stitch_length):
return []
# simplify will remove as many points as possible while ensuring that the
# resulting path stays within 0.75 pixels (0.2mm) of the original path.
# resulting path stays within the specified tolerance of the original path.
path = LineString(points)
simplified = path.simplify(0.75, preserve_topology=False)
simplified = path.simplify(tolerance, preserve_topology=False)
# save the points that simplify picked and make sure we stitch them
important_points = set(simplified.coords)
@ -50,7 +49,7 @@ def running_stitch(points, stitch_length):
section_length = section_ls.length
if section_length > stitch_length:
# a fractional stitch needs to be rounded up, which will make all
# of the stitches shorter
# the stitches shorter
num_stitches = math.ceil(section_length / stitch_length)
actual_stitch_length = section_length / num_stitches

Wyświetl plik

@ -95,6 +95,7 @@ inkstitch_attribs = [
'bean_stitch_repeats',
'repeats',
'running_stitch_length_mm',
'running_stitch_tolerance_mm',
# satin column
'satin_column',
'running_stitch_length_mm',