summaryrefslogtreecommitdiff
path: root/lib/stitches
diff options
context:
space:
mode:
authorLex Neva <github.com@lexneva.name>2023-01-17 21:44:23 -0500
committerLex Neva <github.com@lexneva.name>2023-02-20 15:27:55 -0500
commit847e133f97d570e2967dfa7dcfc16a212dc2bbbc (patch)
treedf2fb20547bea95ad437155a1fac91290a9d07f3 /lib/stitches
parente2965e78f03fb41c9a02c92ef120caf038b837ae (diff)
meander fill: more work
Diffstat (limited to 'lib/stitches')
-rw-r--r--lib/stitches/meander_fill.py72
1 files changed, 59 insertions, 13 deletions
diff --git a/lib/stitches/meander_fill.py b/lib/stitches/meander_fill.py
index 2ac3cd03..cb6e3f4e 100644
--- a/lib/stitches/meander_fill.py
+++ b/lib/stitches/meander_fill.py
@@ -1,21 +1,33 @@
+import networkx as nx
from shapely.geometry import MultiPoint, Point
from shapely.ops import nearest_points
-import networkx as nx
+from .running_stitch import running_stitch
from .. import tiles
from ..debug import debug
+from ..stitch_plan import Stitch
+from ..utils import smooth_path
+from ..utils.geometry import Point as InkStitchPoint
from ..utils.list import poprandom
+from ..utils.prng import iter_uniform_floats
-def meander_fill(fill, shape, starting_point, ending_point):
+def meander_fill(fill, shape, shape_index, starting_point, ending_point):
+ debug.log(f"meander pattern: {fill.meander_pattern}")
tile = get_tile(fill.meander_pattern)
if not tile:
return []
- graph = tile.to_graph(shape)
- start, end = find_starting_and_ending_nodes(graph, starting_point, ending_point)
+ debug.log(f"tile name: {tile.name}")
- return generate_meander_path(graph, start, end)
+ # debug.log_line_strings(ensure_geometry_collection(shape.boundary).geoms, 'Meander shape')
+ graph = tile.to_graph(shape, fill.meander_scale, fill.meander_padding)
+ # debug.log_graph(graph, 'Meander graph')
+ # debug.log(f"graph connected? {nx.is_connected(graph)}")
+ start, end = find_starting_and_ending_nodes(graph, shape, starting_point, ending_point)
+ rng = iter_uniform_floats(fill.random_seed, 'meander-fill', shape_index)
+
+ return post_process(generate_meander_path(graph, start, end, rng), fill)
def get_tile(tile_name):
@@ -27,7 +39,16 @@ def get_tile(tile_name):
return None
-def find_starting_and_ending_nodes(graph, starting_point, ending_point):
+def find_starting_and_ending_nodes(graph, shape, starting_point, ending_point):
+ if starting_point is None:
+ starting_point = shape.exterior.coords[0]
+ starting_point = Point(starting_point)
+
+ if ending_point is None:
+ ending_point = starting_point
+ else:
+ ending_point = Point(ending_point)
+
all_points = MultiPoint(list(graph))
starting_node = nearest_points(starting_point, all_points)[1].coords[0]
@@ -49,7 +70,8 @@ def find_initial_path(graph, start, end):
return nx.shortest_path(graph, start, end)
-def generate_meander_path(graph, start, end):
+@debug.time
+def generate_meander_path(graph, start, end, rng):
path = find_initial_path(graph, start, end)
path_edges = list(zip(path[:-1], path[1:]))
graph.remove_edges_from(path_edges)
@@ -59,15 +81,16 @@ def generate_meander_path(graph, start, end):
meander_path = path_edges
while edges_to_consider:
while edges_to_consider:
- edge = poprandom(edges_to_consider)
+ edge = poprandom(edges_to_consider, rng)
edges_to_consider.extend(replace_edge(meander_path, edge, graph, graph_nodes))
- edge_pairs = list(zip(path[:-1], path[1:]))
+ edge_pairs = list(zip(meander_path[:-1], meander_path[1:]))
while edge_pairs:
- edge1, edge2 = poprandom(edge_pairs)
+ edge1, edge2 = poprandom(edge_pairs, rng)
edges_to_consider.extend(replace_edge_pair(meander_path, edge1, edge2, graph, graph_nodes))
+ break
- return meander_path
+ return path_to_points(meander_path)
def replace_edge(path, edge, graph, graph_nodes):
@@ -81,8 +104,9 @@ def replace_edge(path, edge, graph, graph_nodes):
i = path.index(edge)
path[i:i + 1] = new_path
graph.remove_edges_from(new_path)
+ # do I need to remove the last one too?
graph_nodes.difference_update(start for start, end in new_path)
- debug.log(f"found new path of length {len(new_path)} at position {i}")
+ # debug.log(f"found new path of length {len(new_path)} at position {i}")
return new_path
@@ -98,7 +122,29 @@ def replace_edge_pair(path, edge1, edge2, graph, graph_nodes):
i = path.index(edge1)
path[i:i + 2] = new_path
graph.remove_edges_from(new_path)
+ # do I need to remove the last one too?
graph_nodes.difference_update(start for start, end in new_path)
- debug.log(f"found new pair path of length {len(new_path)} at position {i}")
+ # debug.log(f"found new pair path of length {len(new_path)} at position {i}")
return new_path
+
+
+@debug.time
+def post_process(points, fill):
+ debug.log(f"smoothness: {fill.smoothness}")
+ # debug.log_line_string(LineString(points), "pre-smoothed", "#FF0000")
+ smoothed_points = smooth_path(points, fill.smoothness)
+ smoothed_points = [InkStitchPoint.from_tuple(point) for point in smoothed_points]
+
+ stitches = running_stitch(smoothed_points, fill.running_stitch_length, fill.running_stitch_tolerance)
+ stitches = [Stitch(point) for point in stitches]
+
+ return stitches
+
+
+def path_to_points(path):
+ points = [start for start, end in path]
+ if path:
+ points.append(path[-1][1])
+
+ return points