summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/stitches/auto_fill.py38
-rw-r--r--lib/stitches/circular_fill.py2
-rw-r--r--lib/stitches/guided_fill.py2
-rw-r--r--lib/stitches/linear_gradient_fill.py2
-rw-r--r--lib/stitches/tartan_fill.py2
-rw-r--r--lib/tartan/svg.py2
6 files changed, 32 insertions, 16 deletions
diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py
index a1e88d5d..4800c994 100644
--- a/lib/stitches/auto_fill.py
+++ b/lib/stitches/auto_fill.py
@@ -111,7 +111,7 @@ def auto_fill(shape,
if not travel_graph:
return fallback(shape, running_stitch_length, running_stitch_tolerance)
- path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
+ path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point, underpath)
path = fill_gaps(path, round_to_multiple_of_2(gap_fill_rows))
result = path_to_stitches(shape, path, travel_graph, fill_stitch_graph, angle, row_spacing,
max_stitch_length, running_stitch_length, running_stitch_tolerance,
@@ -375,13 +375,13 @@ def graph_make_valid(graph):
graph.add_edge(start, end, key=f'segment-{key}', **data)
elif 'outline' in graph_edges.keys():
data = graph_edges['outline']
- graph.add_edge(start, end, key='outline-{key}', **data)
+ graph.add_edge(start, end, key=f'outline-{key}', **data)
elif 'extra' in graph_edges.keys():
data = graph_edges['extra']
- graph.add_edge(start, end, key='extra-{key}', **data)
+ graph.add_edge(start, end, key=f'extra-{key}', **data)
elif 'initial' in graph_edges.keys():
data = graph_edges['initial']
- graph.add_edge(start, end, key='initial-{key}', **data)
+ graph.add_edge(start, end, key=f'initial-{key}', **data)
def fallback(shape, running_stitch_length, running_stitch_tolerance):
@@ -600,7 +600,7 @@ def nearest_node(nodes, point, attr=None):
@debug.time
-def find_stitch_path(graph, travel_graph, starting_point=None, ending_point=None):
+def find_stitch_path(graph, travel_graph, starting_point=None, ending_point=None, underpath=True):
"""find a path that visits every grating segment exactly once
Theoretically, we just need to find an Eulerian Path in the graph.
@@ -623,6 +623,7 @@ def find_stitch_path(graph, travel_graph, starting_point=None, ending_point=None
"""
graph = graph.copy()
+ composed_graph = networkx.compose(graph, travel_graph)
if not starting_point:
starting_point = list(graph.nodes.keys())[0]
@@ -641,6 +642,10 @@ def find_stitch_path(graph, travel_graph, starting_point=None, ending_point=None
last_vertex = None
last_key = None
+ # get the outline index for starting and ending node
+ outline_start = travel_graph[starting_node][list(travel_graph[starting_node])[0]]['outline']['outline']
+ outline_end = travel_graph[ending_node][list(travel_graph[ending_node])[0]]['outline']['outline']
+
while vertex_stack:
current_vertex, current_key = vertex_stack[-1]
if graph.degree(current_vertex) == 0:
@@ -664,8 +669,21 @@ def find_stitch_path(graph, travel_graph, starting_point=None, ending_point=None
# Note, it's quite possible that part of this PathEdge will be eliminated by
# collapse_sequential_outline_edges().
- if starting_node is not ending_node:
- path.insert(0, PathEdge((starting_node, ending_node), key="initial"))
+ if underpath or outline_start == outline_end:
+ if starting_node is not ending_node:
+ path.insert(0, PathEdge((starting_node, ending_node), key="initial"))
+ else:
+ # If underpath is disabled, we only have the option travel along the outline edges.
+ # The user chose to start and end on different oultines, so there is no way to travel
+ # along the edge from start to end. Add an additional path from start to end along existing
+ # graph and travel edges (they will be duplicated).
+ start_path = networkx.shortest_path(composed_graph, starting_node, ending_node, weight='weight')
+ for i, edge in enumerate(list(zip(start_path, start_path[1:]))):
+ # add as segment so it won't be collapsed
+ if 'segment' in composed_graph[edge[0]][edge[1]].keys():
+ path.insert(i, PathEdge(edge, key=f'segment-start{i}'))
+ else:
+ path.insert(i, PathEdge(edge, key=f'outline-start{i}'))
# If the starting and/or ending point falls far away from the end of a row
# of stitches (like can happen at the top of a square), then we need to
@@ -872,10 +890,8 @@ def travel(shape, travel_graph, edge, running_stitch_length, running_stitch_tole
try:
path = networkx.shortest_path(travel_graph, start, end, weight='weight')
except networkx.NetworkXNoPath:
- # TODO: find a better solution, this may produce unwanted jump stitches
- # but at least it renders the requested shape
- # test case: underpath disabled, starts and ends on different outlines
- return
+ # This may not look good, but it prevents the fill from failing (which hopefully never happens)
+ path = [start, end]
if underpath and path != (start, end):
path = smooth_path(path, 2)
diff --git a/lib/stitches/circular_fill.py b/lib/stitches/circular_fill.py
index 7be9469a..8b7fae41 100644
--- a/lib/stitches/circular_fill.py
+++ b/lib/stitches/circular_fill.py
@@ -93,7 +93,7 @@ def circular_fill(shape,
graph_make_valid(fill_stitch_graph)
travel_graph = build_travel_graph(fill_stitch_graph, shape, angle, underpath)
- path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
+ path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point, underpath)
result = path_to_stitches(shape, path, travel_graph, fill_stitch_graph, running_stitch_length, running_stitch_tolerance, skip_last, underpath)
result = _apply_bean_stitch_and_repeats(result, repeats, bean_stitch_repeats)
return result
diff --git a/lib/stitches/guided_fill.py b/lib/stitches/guided_fill.py
index dcf9971a..79eff6b5 100644
--- a/lib/stitches/guided_fill.py
+++ b/lib/stitches/guided_fill.py
@@ -53,7 +53,7 @@ def guided_fill(shape,
graph_make_valid(fill_stitch_graph)
travel_graph = build_travel_graph(fill_stitch_graph, shape, angle, underpath)
- path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
+ path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point, underpath)
result = path_to_stitches(shape, path, travel_graph, fill_stitch_graph,
max_stitch_length, running_stitch_length, running_stitch_tolerance, skip_last,
underpath)
diff --git a/lib/stitches/linear_gradient_fill.py b/lib/stitches/linear_gradient_fill.py
index c0c07e0d..3b2d0938 100644
--- a/lib/stitches/linear_gradient_fill.py
+++ b/lib/stitches/linear_gradient_fill.py
@@ -289,7 +289,7 @@ def _get_stitch_groups(fill, shape, colors, color_lines, starting_point, ending_
graph_make_valid(fill_stitch_graph)
travel_graph = build_travel_graph(fill_stitch_graph, shape, fill.angle, False)
- path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
+ path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point, False)
stitches = path_to_stitches(
shape,
path,
diff --git a/lib/stitches/tartan_fill.py b/lib/stitches/tartan_fill.py
index ad3e0370..5eeed473 100644
--- a/lib/stitches/tartan_fill.py
+++ b/lib/stitches/tartan_fill.py
@@ -781,7 +781,7 @@ def _segments_to_stitch_group(
return None
graph_make_valid(fill_stitch_graph)
travel_graph = build_travel_graph(fill_stitch_graph, shape, fill.angle, False)
- path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
+ path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point, False)
stitches = path_to_stitches(
shape,
path,
diff --git a/lib/tartan/svg.py b/lib/tartan/svg.py
index a1f78fc9..0fd8b579 100644
--- a/lib/tartan/svg.py
+++ b/lib/tartan/svg.py
@@ -224,7 +224,7 @@ class TartanSvgGroup:
return []
graph_make_valid(fill_stitch_graph)
travel_graph = build_travel_graph(fill_stitch_graph, outline_shape, 0, False)
- path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
+ path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point, False)
return self._path_to_shapes(path, fill_stitch_graph, polygons, geometry_type, outline_shape)
def _path_to_shapes(