diff options
| author | Lex Neva <github.com@lexneva.name> | 2022-05-03 14:34:21 -0400 |
|---|---|---|
| committer | Kaalleen <reni@allenka.de> | 2022-05-04 19:18:33 +0200 |
| commit | 5a69fa3e9c582a3bc21660342cea35837ae1eb9a (patch) | |
| tree | d2ce77282fdb4aa5376d490e420d7c18b5389462 | |
| parent | 68ee0eea8733d613543a28627bd21a4481da8b46 (diff) | |
add double (fermat) spiral
| -rw-r--r-- | lib/elements/fill_stitch.py | 2 | ||||
| -rw-r--r-- | lib/stitches/tangential_fill_stitch_line_creator.py | 14 | ||||
| -rw-r--r-- | lib/stitches/tangential_fill_stitch_pattern_creator.py | 66 |
3 files changed, 64 insertions, 18 deletions
diff --git a/lib/elements/fill_stitch.py b/lib/elements/fill_stitch.py index 2f8687a1..70d4f356 100644 --- a/lib/elements/fill_stitch.py +++ b/lib/elements/fill_stitch.py @@ -103,7 +103,7 @@ class FillStitch(EmbroideryElement): @property @param('tangential_strategy', _('Tangential strategy'), type='dropdown', default=1, - options=[_("Inner to Outer"), _("Single spiral")], select_items=[('fill_method', 1)], sort_index=2) + options=[_("Inner to Outer"), _("Single spiral"), _("Double spiral")], select_items=[('fill_method', 1)], sort_index=2) def tangential_strategy(self): return self.get_int_param('tangential_strategy', 1) diff --git a/lib/stitches/tangential_fill_stitch_line_creator.py b/lib/stitches/tangential_fill_stitch_line_creator.py index 78213384..69bb13f2 100644 --- a/lib/stitches/tangential_fill_stitch_line_creator.py +++ b/lib/stitches/tangential_fill_stitch_line_creator.py @@ -84,7 +84,8 @@ def make_tree_uniform(tree, clockwise=True): # Used to define which stitching strategy shall be used class StitchingStrategy(IntEnum): INNER_TO_OUTER = 0 - SPIRAL = 1 + SINGLE_SPIRAL = 1 + DOUBLE_SPIRAL = 2 def check_and_prepare_tree_for_valid_spiral(tree): @@ -158,7 +159,7 @@ def offset_poly(poly, offset, join_style, stitch_distance, min_stitch_distance, at this position """ - if strategy == StitchingStrategy.SPIRAL and len(poly.interiors) > 1: + if strategy in (StitchingStrategy.SINGLE_SPIRAL, StitchingStrategy.DOUBLE_SPIRAL) and len(poly.interiors) > 1: raise ValueError( "Single spiral geometry must not have more than one hole!") @@ -293,10 +294,15 @@ def offset_poly(poly, offset, join_style, stitch_distance, min_stitch_distance, tree, 'root', abs(offset), stitch_distance, min_stitch_distance, starting_point, offset_by_half, avoid_self_crossing) path = [Stitch(*point) for point in connected_line.coords] return running_stitch(path, stitch_distance), "whatever" - elif strategy == StitchingStrategy.SPIRAL: + elif strategy == StitchingStrategy.SINGLE_SPIRAL: if not check_and_prepare_tree_for_valid_spiral(tree): raise ValueError("Geometry cannot be filled with one spiral!") - (connected_line, connected_line_origin) = tangential_fill_stitch_pattern_creator.connect_raster_tree_spiral( + (connected_line, connected_line_origin) = tangential_fill_stitch_pattern_creator.connect_raster_tree_single_spiral( + tree, offset, stitch_distance, min_stitch_distance, starting_point, offset_by_half) + elif strategy == StitchingStrategy.DOUBLE_SPIRAL: + if not check_and_prepare_tree_for_valid_spiral(tree): + raise ValueError("Geometry cannot be filled with a double spiral!") + (connected_line, connected_line_origin) = tangential_fill_stitch_pattern_creator.connect_raster_tree_double_spiral( tree, offset, stitch_distance, min_stitch_distance, starting_point, offset_by_half) else: raise ValueError("Invalid stitching stratety!") diff --git a/lib/stitches/tangential_fill_stitch_pattern_creator.py b/lib/stitches/tangential_fill_stitch_pattern_creator.py index 2556d58c..edc6e0af 100644 --- a/lib/stitches/tangential_fill_stitch_pattern_creator.py +++ b/lib/stitches/tangential_fill_stitch_pattern_creator.py @@ -1,5 +1,5 @@ -import math from collections import namedtuple +from itertools import chain import networkx as nx import numpy as np import trimesh @@ -259,7 +259,7 @@ def interpolate_linear_rings(ring1, ring2, max_stitch_length, start=None): return result.simplify(constants.simplification_threshold, False) -def connect_raster_tree_spiral(tree, used_offset, stitch_distance, min_stitch_distance, close_point, offset_by_half): # noqa: C901 +def connect_raster_tree_single_spiral(tree, used_offset, stitch_distance, min_stitch_distance, close_point, offset_by_half): # noqa: C901 """ Takes the offsetted curves organized as tree, connects and samples them as a spiral. It expects that each node in the tree has max. one child @@ -281,21 +281,61 @@ def connect_raster_tree_spiral(tree, used_offset, stitch_distance, min_stitch_di placed at this position """ - if not tree['root']: # if node has no children - stitches = [Stitch(*point) for point in tree.nodes['root'].val.coords] - return running_stitch(stitches, stitch_distance) + starting_point = close_point.coords[0] + + rings = [tree.nodes[node].val for node in nx.dfs_preorder_nodes(tree, 'root')] + + path = make_spiral(rings, stitch_distance, starting_point) + path = [Stitch(*stitch) for stitch in path] + + return running_stitch(path, stitch_distance), None + + +def connect_raster_tree_double_spiral(tree, used_offset, stitch_distance, min_stitch_distance, close_point, offset_by_half): # noqa: C901 + """ + Takes the offsetted curves organized as tree, connects and samples them as a spiral. + It expects that each node in the tree has max. one child + Input: + -tree: contains the offsetted curves in a hierarchical organized + data structure. + -used_offset: used offset when the offsetted curves were generated + -stitch_distance: maximum allowed distance between two points + after sampling + -min_stitch_distance stitches within a row shall be at least min_stitch_distance apart. Stitches connecting + offsetted paths might be shorter. + -close_point: defines the beginning point for stitching + (stitching starts always from the undisplaced curve) + -offset_by_half: If true the resulting points are interlaced otherwise not. + Return values: + -All offsetted curves connected to one spiral and sampled with + points obeying stitch_distance and offset_by_half + -Tag (origin) of each point to analyze why a point was + placed at this position + """ starting_point = close_point.coords[0] - path = [] - for node in nx.dfs_preorder_nodes(tree, 'root'): - if tree[node]: - ring1 = tree.nodes[node].val - child = list(tree.successors(node))[0] - ring2 = tree.nodes[child].val - spiral_part = interpolate_linear_rings(ring1, ring2, stitch_distance, starting_point) - path.extend(spiral_part.coords) + rings = [tree.nodes[node].val for node in nx.dfs_preorder_nodes(tree, 'root')] + path = make_fermat_spiral(rings, stitch_distance, starting_point) path = [Stitch(*stitch) for stitch in path] return running_stitch(path, stitch_distance), None + + +def make_fermat_spiral(rings, stitch_distance, starting_point): + forward = make_spiral(rings[::2], stitch_distance, starting_point) + back = make_spiral(rings[1::2], stitch_distance, starting_point) + back.reverse() + + return chain(forward, back) + + +def make_spiral(rings, stitch_distance, starting_point): + path = [] + + for ring1, ring2 in zip(rings[:-1], rings[1:]): + spiral_part = interpolate_linear_rings(ring1, ring2, stitch_distance, starting_point) + path.extend(spiral_part.coords) + + return path |
