diff options
| author | Lex Neva <github.com@lexneva.name> | 2022-08-25 23:10:16 -0400 |
|---|---|---|
| committer | Lex Neva <github.com@lexneva.name> | 2023-02-20 15:27:35 -0500 |
| commit | 8cead6e3d9f9223bd4d74b30ec6964802f52d9b2 (patch) | |
| tree | 48b567090614aaee995c1a8ffdfa92321182d9cb | |
| parent | 0ace1ce72c72aa3293d97e5d55e9e614b66d5ee2 (diff) | |
add smoothness option for contour fill
| -rw-r--r-- | lib/elements/fill_stitch.py | 16 | ||||
| -rw-r--r-- | lib/stitches/contour_fill.py | 7 | ||||
| -rw-r--r-- | lib/svg/tags.py | 1 | ||||
| -rw-r--r-- | lib/utils/geometry.py | 12 |
4 files changed, 31 insertions, 5 deletions
diff --git a/lib/elements/fill_stitch.py b/lib/elements/fill_stitch.py index 77b4ac7c..fb8838cc 100644 --- a/lib/elements/fill_stitch.py +++ b/lib/elements/fill_stitch.py @@ -138,6 +138,20 @@ class FillStitch(EmbroideryElement): return self.get_boolean_param('avoid_self_crossing', False) @property + @param('smoothness_mm', _('Smoothness'), + tooltip=_( + 'Smooth the stitch path. Smoothness limits how far the smoothed stitch path ' + + 'is allowed to deviate from the original path. Hint: a lower stitchc tolerance may be needed too.' + ), + type='integer', + unit='mm', + default=0, + select_items=[('fill_method', 1)], + sort_index=5) + def smoothness(self): + return self.get_float_param('smoothness_mm', 0) + + @property @param('clockwise', _('Clockwise'), type='boolean', default=True, select_items=[('fill_method', 1)], sort_index=5) def clockwise(self): return self.get_boolean_param('clockwise', True) @@ -651,9 +665,11 @@ class FillStitch(EmbroideryElement): if self.contour_strategy == 0: stitches = contour_fill.inner_to_outer( tree, + polygon, self.row_spacing, self.max_stitch_length, self.running_stitch_tolerance, + self.smoothness, starting_point, self.avoid_self_crossing ) diff --git a/lib/stitches/contour_fill.py b/lib/stitches/contour_fill.py index 885a7e6c..8e47518f 100644 --- a/lib/stitches/contour_fill.py +++ b/lib/stitches/contour_fill.py @@ -406,11 +406,16 @@ 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, tolerance, starting_point, avoid_self_crossing): +def inner_to_outer(tree, polygon, offset, stitch_length, tolerance, smoothness, 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] + + if smoothness > 0: + smoothed = smooth_path(points, smoothness) + points = clamp_path_to_polygon(smoothed, polygon) + stitches = running_stitch(points, stitch_length, tolerance) return stitches diff --git a/lib/svg/tags.py b/lib/svg/tags.py index 64f6c2f3..8c1dd558 100644 --- a/lib/svg/tags.py +++ b/lib/svg/tags.py @@ -66,6 +66,7 @@ inkstitch_attribs = [ 'guided_fill_strategy', 'join_style', 'avoid_self_crossing', + 'smoothness_mm', 'clockwise', 'reverse', 'expand_mm', diff --git a/lib/utils/geometry.py b/lib/utils/geometry.py index c07172c7..2903bc56 100644 --- a/lib/utils/geometry.py +++ b/lib/utils/geometry.py @@ -182,13 +182,17 @@ def smooth_path(path, smoothness=100.0): coords = _remove_duplicate_coordinates(np.array(path)) num_points = len(coords) - # splprep's s parameter seems to depend on the number of points you pass - # as per the docs, so let's normalize it. - s = round(smoothness / 100 * num_points) + # s is explained in this issue: https://github.com/scipy/scipy/issues/11916 + # the smoothness parameter limits how much the smoothed path can deviate + # from the original path. The standard deviation of the distance between + # the smoothed path and the original path is equal to the smoothness. + # In practical terms, if smoothness is 1mm, then the smoothed path can be + # up to 1mm away from the original path. + s = num_points * smoothness ** 2 # .T transposes the array (for some reason splprep expects # [[x1, x2, ...], [y1, y2, ...]] - tck, fp, ier, msg = splprep(coords.T, s=s, nest=-1, full_output=1) + tck, fp, ier, msg = splprep(coords.T, s=s, k=3, nest=-1, full_output=1) if ier > 0: from ..debug import debug debug.log(f"error {ier} smoothing path: {msg}") |
