From 9ae97154d689b188c796e5d11820e026ed1f9326 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Wed, 12 Dec 2018 20:26:22 -0500 Subject: add option to skip last stitch in fill rows --- lib/stitches/auto_fill.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'lib/stitches/auto_fill.py') diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py index 28c79eff..0b5782e5 100644 --- a/lib/stitches/auto_fill.py +++ b/lib/stitches/auto_fill.py @@ -1,13 +1,14 @@ +from collections import deque +from itertools import groupby, izip import sys -import shapely + import networkx -from itertools import groupby, izip -from collections import deque +import shapely -from .fill import intersect_region_with_grating, row_num, stitch_row -from .running_stitch import running_stitch from ..i18n import _ from ..utils.geometry import Point as InkstitchPoint, cut +from .fill import intersect_region_with_grating, row_num, stitch_row +from .running_stitch import running_stitch class MaxQueueLengthExceeded(Exception): @@ -39,7 +40,7 @@ class PathEdge(object): return self.key == self.SEGMENT_KEY -def auto_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, running_stitch_length, staggers, starting_point, ending_point=None): +def auto_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, running_stitch_length, staggers, skip_last, starting_point, ending_point=None): stitches = [] rows_of_segments = intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing) @@ -48,7 +49,7 @@ def auto_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, run graph = build_graph(shape, segments, angle, row_spacing) path = find_stitch_path(graph, segments, starting_point, ending_point) - stitches.extend(path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, running_stitch_length, staggers)) + stitches.extend(path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, running_stitch_length, staggers, skip_last)) return stitches @@ -513,7 +514,10 @@ def connect_points(shape, start, end, running_stitch_length, row_spacing): # Now do running stitch along the path we've found. running_stitch() will # avoid cutting sharp corners. path = [InkstitchPoint(*p) for p in points] - return running_stitch(path, running_stitch_length) + stitches = running_stitch(path, running_stitch_length) + + # The row of stitches already stitched the first point, so skip it. + return stitches[1:] def trim_end(path): @@ -521,14 +525,14 @@ def trim_end(path): path.pop() -def path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, running_stitch_length, staggers): +def path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, running_stitch_length, staggers, skip_last): path = collapse_sequential_outline_edges(graph, path) stitches = [] for edge in path: if edge.is_segment(): - stitch_row(stitches, edge[0], edge[1], angle, row_spacing, max_stitch_length, staggers) + stitch_row(stitches, edge[0], edge[1], angle, row_spacing, max_stitch_length, staggers, skip_last) else: stitches.extend(connect_points(shape, edge[0], edge[1], running_stitch_length, row_spacing)) -- cgit v1.2.3 From 8f3c922011a5c39a6154863160ea8354a502ed42 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Thu, 13 Dec 2018 20:10:50 -0500 Subject: fix style --- lib/stitches/auto_fill.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'lib/stitches/auto_fill.py') diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py index 0b5782e5..4a0fbed7 100644 --- a/lib/stitches/auto_fill.py +++ b/lib/stitches/auto_fill.py @@ -40,7 +40,16 @@ class PathEdge(object): return self.key == self.SEGMENT_KEY -def auto_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, running_stitch_length, staggers, skip_last, starting_point, ending_point=None): +def auto_fill(shape, + angle, + row_spacing, + end_row_spacing, + max_stitch_length, + running_stitch_length, + staggers, + skip_last, + starting_point, + ending_point=None): stitches = [] rows_of_segments = intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing) -- cgit v1.2.3 From 6a8edfc1cdc19e90b85c4023ef8611f506317e2d Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 4 Jan 2019 20:22:10 -0500 Subject: fix crash if fill start and end points are very close --- lib/stitches/auto_fill.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/stitches/auto_fill.py') diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py index 4a0fbed7..c7e65473 100644 --- a/lib/stitches/auto_fill.py +++ b/lib/stitches/auto_fill.py @@ -327,14 +327,16 @@ def get_outline_nodes(graph, outline_index=0): def find_initial_path(graph, starting_point, ending_point=None): starting_node = nearest_node_on_outline(graph, starting_point) - if ending_point is None: + if ending_point is not None: + ending_node = nearest_node_on_outline(graph, ending_point) + + if ending_point is None or starting_node is ending_node: # If they didn't give an ending point, pick either neighboring node # along the outline -- doesn't matter which. We do this because # the algorithm requires we start with _some_ path. neighbors = [n for n, keys in graph.adj[starting_node].iteritems() if 'outline' in keys] return [PathEdge((starting_node, neighbors[0]), "initial")] else: - ending_node = nearest_node_on_outline(graph, ending_point) outline_nodes = get_outline_nodes(graph) # Multiply the outline_nodes list by 2 (duplicate it) because -- cgit v1.2.3 From be7d0af82da95d64261351b6281153db1944c0b4 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Fri, 15 Feb 2019 20:51:10 -0500 Subject: improve error message when trying to autofill tiny shapes --- lib/stitches/auto_fill.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'lib/stitches/auto_fill.py') diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py index c7e65473..1c0be0a0 100644 --- a/lib/stitches/auto_fill.py +++ b/lib/stitches/auto_fill.py @@ -5,13 +5,18 @@ import sys import networkx import shapely +from ..exceptions import InkstitchException from ..i18n import _ from ..utils.geometry import Point as InkstitchPoint, cut from .fill import intersect_region_with_grating, row_num, stitch_row from .running_stitch import running_stitch -class MaxQueueLengthExceeded(Exception): +class MaxQueueLengthExceeded(InkstitchException): + pass + + +class InvalidPath(InkstitchException): pass @@ -55,7 +60,7 @@ def auto_fill(shape, rows_of_segments = intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing) segments = [segment for row in rows_of_segments for segment in row] - graph = build_graph(shape, segments, angle, row_spacing) + graph = build_graph(shape, segments, angle, row_spacing, max_stitch_length) path = find_stitch_path(graph, segments, starting_point, ending_point) stitches.extend(path_to_stitches(graph, path, shape, angle, row_spacing, max_stitch_length, running_stitch_length, staggers, skip_last)) @@ -90,7 +95,7 @@ def project(shape, coords, outline_index): return outline.project(shapely.geometry.Point(*coords)) -def build_graph(shape, segments, angle, row_spacing): +def build_graph(shape, segments, angle, row_spacing, max_stitch_length): """build a graph representation of the grating segments This function builds a specialized graph (as in graph theory) that will @@ -173,8 +178,12 @@ def build_graph(shape, segments, angle, row_spacing): if i % 2 == edge_set: graph.add_edge(node1, node2, key="extra") - if not networkx.is_eulerian(graph): - raise Exception(_("Unable to autofill. This most often happens because your shape is made up of multiple sections that aren't connected.")) + if networkx.is_empty(graph) or not networkx.is_eulerian(graph): + if shape.area < max_stitch_length ** 2: + raise InvalidPath(_("This shape is so small that it cannot be filled with rows of stitches. " + "It would probably look best as a satin column or running stitch.")) + else: + raise InvalidPath(_("Cannot parse shape. This most often happens because your shape is made up of multiple sections that aren't connected.")) return graph -- cgit v1.2.3 From fa3236372bcee28f4aaa78da47b68c5d7f32cca4 Mon Sep 17 00:00:00 2001 From: Lex Neva Date: Sat, 16 Feb 2019 16:46:16 -0500 Subject: fix style --- lib/stitches/auto_fill.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'lib/stitches/auto_fill.py') diff --git a/lib/stitches/auto_fill.py b/lib/stitches/auto_fill.py index 1c0be0a0..0f07b795 100644 --- a/lib/stitches/auto_fill.py +++ b/lib/stitches/auto_fill.py @@ -178,14 +178,19 @@ def build_graph(shape, segments, angle, row_spacing, max_stitch_length): if i % 2 == edge_set: graph.add_edge(node1, node2, key="extra") + check_graph(graph, shape, max_stitch_length) + + return graph + + +def check_graph(graph, shape, max_stitch_length): if networkx.is_empty(graph) or not networkx.is_eulerian(graph): if shape.area < max_stitch_length ** 2: raise InvalidPath(_("This shape is so small that it cannot be filled with rows of stitches. " "It would probably look best as a satin column or running stitch.")) else: - raise InvalidPath(_("Cannot parse shape. This most often happens because your shape is made up of multiple sections that aren't connected.")) - - return graph + raise InvalidPath(_("Cannot parse shape. " + "This most often happens because your shape is made up of multiple sections that aren't connected.")) def node_list_to_edge_list(node_list): -- cgit v1.2.3