kopia lustrzana https://github.com/inkstitch/inkstitch
undo aggressive line wrapping
rodzic
469c32a497
commit
b30fce85db
lib
elements
stitches
|
@ -166,8 +166,7 @@ class EmbroideryElement(object):
|
|||
# Of course, transforms may also involve rotation, skewing, and translation.
|
||||
# All except translation can affect how wide the stroke appears on the screen.
|
||||
|
||||
node_transform = inkex.transforms.Transform(
|
||||
get_node_transform(self.node))
|
||||
node_transform = inkex.transforms.Transform(get_node_transform(self.node))
|
||||
|
||||
# First, figure out the translation component of the transform. Using a zero
|
||||
# vector completely cancels out the rotation, scale, and skew components.
|
||||
|
@ -201,8 +200,7 @@ class EmbroideryElement(object):
|
|||
@property
|
||||
@param('ties',
|
||||
_('Allow lock stitches'),
|
||||
tooltip=_(
|
||||
'Tie thread at the beginning and/or end of this object. Manual stitch will not add lock stitches.'),
|
||||
tooltip=_('Tie thread at the beginning and/or end of this object. Manual stitch will not add lock stitches.'),
|
||||
type='dropdown',
|
||||
# Ties: 0 = Both | 1 = Before | 2 = After | 3 = Neither
|
||||
# L10N options to allow lock stitch before and after objects
|
||||
|
@ -260,8 +258,7 @@ class EmbroideryElement(object):
|
|||
d = self.node.get("d", "")
|
||||
|
||||
if not d:
|
||||
self.fatal(_("Object %(id)s has an empty 'd' attribute. Please delete this object from your document.") % dict(
|
||||
id=self.node.get("id")))
|
||||
self.fatal(_("Object %(id)s has an empty 'd' attribute. Please delete this object from your document.") % dict(id=self.node.get("id")))
|
||||
|
||||
return inkex.paths.Path(d).to_superpath()
|
||||
|
||||
|
@ -276,8 +273,7 @@ class EmbroideryElement(object):
|
|||
|
||||
@property
|
||||
def shape(self):
|
||||
raise NotImplementedError(
|
||||
"INTERNAL ERROR: %s must implement shape()", self.__class__)
|
||||
raise NotImplementedError("INTERNAL ERROR: %s must implement shape()", self.__class__)
|
||||
|
||||
@property
|
||||
@cache
|
||||
|
@ -327,8 +323,7 @@ class EmbroideryElement(object):
|
|||
return self.get_boolean_param('stop_after', False)
|
||||
|
||||
def to_stitch_groups(self, last_patch):
|
||||
raise NotImplementedError(
|
||||
"%s must implement to_stitch_groups()" % self.__class__.__name__)
|
||||
raise NotImplementedError("%s must implement to_stitch_groups()" % self.__class__.__name__)
|
||||
|
||||
def embroider(self, last_patch):
|
||||
self.validate()
|
||||
|
@ -341,10 +336,8 @@ class EmbroideryElement(object):
|
|||
patch.force_lock_stitches = self.force_lock_stitches
|
||||
|
||||
if patches:
|
||||
patches[-1].trim_after = self.has_command(
|
||||
"trim") or self.trim_after
|
||||
patches[-1].stop_after = self.has_command(
|
||||
"stop") or self.stop_after
|
||||
patches[-1].trim_after = self.has_command("trim") or self.trim_after
|
||||
patches[-1].stop_after = self.has_command("stop") or self.stop_after
|
||||
|
||||
return patches
|
||||
|
||||
|
|
|
@ -213,8 +213,7 @@ class FillStitch(EmbroideryElement):
|
|||
# ensure path length
|
||||
for i, path in enumerate(paths):
|
||||
if len(path) < 3:
|
||||
paths[i] = [(path[0][0], path[0][1]), (path[0][0] +
|
||||
1.0, path[0][1]), (path[0][0], path[0][1]+1.0)]
|
||||
paths[i] = [(path[0][0], path[0][1]), (path[0][0] + 1.0, path[0][1]), (path[0][0], path[0][1] + 1.0)]
|
||||
return paths
|
||||
|
||||
@property
|
||||
|
|
|
@ -69,10 +69,8 @@ def auto_fill(shape,
|
|||
if not graph_is_valid(fill_stitch_graph, shape, max_stitch_length):
|
||||
return fallback(shape, running_stitch_length)
|
||||
|
||||
travel_graph = build_travel_graph(
|
||||
fill_stitch_graph, shape, angle, underpath)
|
||||
path = find_stitch_path(
|
||||
fill_stitch_graph, travel_graph, starting_point, ending_point)
|
||||
travel_graph = build_travel_graph(fill_stitch_graph, shape, angle, underpath)
|
||||
path = find_stitch_path(fill_stitch_graph, travel_graph, starting_point, ending_point)
|
||||
result = path_to_stitches(path, travel_graph, fill_stitch_graph, angle, row_spacing,
|
||||
max_stitch_length, running_stitch_length, staggers, skip_last)
|
||||
|
||||
|
@ -181,8 +179,7 @@ def insert_node(graph, shape, point):
|
|||
if key == "outline":
|
||||
edges.append(((start, end), data))
|
||||
|
||||
edge, data = min(edges, key=lambda edge_data: shgeo.LineString(
|
||||
edge_data[0]).distance(projected_point))
|
||||
edge, data = min(edges, key=lambda edge_data: shgeo.LineString(edge_data[0]).distance(projected_point))
|
||||
|
||||
graph.remove_edge(*edge, key="outline")
|
||||
graph.add_edge(edge[0], node, key="outline", **data)
|
||||
|
@ -195,8 +192,7 @@ def tag_nodes_with_outline_and_projection(graph, shape, nodes):
|
|||
outline_index = which_outline(shape, node)
|
||||
outline_projection = project(shape, node, outline_index)
|
||||
|
||||
graph.add_node(node, outline=outline_index,
|
||||
projection=outline_projection)
|
||||
graph.add_node(node, outline=outline_index, projection=outline_projection)
|
||||
|
||||
|
||||
def add_boundary_travel_nodes(graph, shape):
|
||||
|
@ -215,11 +211,9 @@ def add_boundary_travel_nodes(graph, shape):
|
|||
# resolution. A pixel is around a quarter of a millimeter.
|
||||
for i in range(1, int(length)):
|
||||
subpoint = segment.interpolate(i)
|
||||
graph.add_node((subpoint.x, subpoint.y), projection=outline.project(
|
||||
subpoint), outline=outline_index)
|
||||
graph.add_node((subpoint.x, subpoint.y), projection=outline.project(subpoint), outline=outline_index)
|
||||
|
||||
graph.add_node((point.x, point.y), projection=outline.project(
|
||||
point), outline=outline_index)
|
||||
graph.add_node((point.x, point.y), projection=outline.project(point), outline=outline_index)
|
||||
prev = point
|
||||
|
||||
|
||||
|
@ -303,8 +297,7 @@ def build_travel_graph(fill_stitch_graph, shape, fill_stitch_angle, underpath):
|
|||
graph.add_nodes_from(fill_stitch_graph.nodes(data=True))
|
||||
|
||||
if underpath:
|
||||
boundary_points, travel_edges = build_travel_edges(
|
||||
shape, fill_stitch_angle)
|
||||
boundary_points, travel_edges = build_travel_edges(shape, fill_stitch_angle)
|
||||
|
||||
# This will ensure that a path traveling inside the shape can reach its
|
||||
# target on the outline, which will be one of the points added above.
|
||||
|
@ -356,8 +349,7 @@ def process_travel_edges(graph, fill_stitch_graph, shape, travel_edges):
|
|||
|
||||
# This makes the distance calculations below a bit faster. We're
|
||||
# not looking for high precision anyway.
|
||||
outline = shape.boundary.simplify(
|
||||
0.5 * PIXELS_PER_MM, preserve_topology=False)
|
||||
outline = shape.boundary.simplify(0.5 * PIXELS_PER_MM, preserve_topology=False)
|
||||
|
||||
for ls in travel_edges:
|
||||
# In most cases, ls will be a simple line segment. If we're
|
||||
|
@ -435,12 +427,9 @@ def build_travel_edges(shape, fill_angle):
|
|||
else:
|
||||
scale = 1.0
|
||||
|
||||
grating1 = travel_grating(
|
||||
shape, fill_angle + math.pi / 4, scale * 2 * PIXELS_PER_MM)
|
||||
grating2 = travel_grating(
|
||||
shape, fill_angle - math.pi / 4, scale * 2 * PIXELS_PER_MM)
|
||||
grating3 = travel_grating(
|
||||
shape, fill_angle - math.pi / 2, scale * math.sqrt(2) * PIXELS_PER_MM)
|
||||
grating1 = travel_grating(shape, fill_angle + math.pi / 4, scale * 2 * PIXELS_PER_MM)
|
||||
grating2 = travel_grating(shape, fill_angle - math.pi / 4, scale * 2 * PIXELS_PER_MM)
|
||||
grating3 = travel_grating(shape, fill_angle - math.pi / 2, scale * math.sqrt(2) * PIXELS_PER_MM)
|
||||
|
||||
debug.add_layer("auto-fill travel")
|
||||
debug.log_line_strings(grating1, "grating1")
|
||||
|
@ -451,12 +440,10 @@ def build_travel_edges(shape, fill_angle):
|
|||
for ls in mls.geoms
|
||||
for coord in ls.coords]
|
||||
|
||||
diagonal_edges = ensure_multi_line_string(
|
||||
grating1.symmetric_difference(grating2))
|
||||
diagonal_edges = ensure_multi_line_string(grating1.symmetric_difference(grating2))
|
||||
|
||||
# without this, floating point inaccuracies prevent the intersection points from lining up perfectly.
|
||||
vertical_edges = ensure_multi_line_string(
|
||||
snap(grating3.difference(grating1), diagonal_edges, 0.005))
|
||||
vertical_edges = ensure_multi_line_string(snap(grating3.difference(grating1), diagonal_edges, 0.005))
|
||||
|
||||
return endpoints, chain(diagonal_edges.geoms, vertical_edges.geoms)
|
||||
|
||||
|
@ -518,8 +505,7 @@ def find_stitch_path(graph, travel_graph, starting_point=None, ending_point=None
|
|||
last_vertex, last_key = current_vertex, current_key
|
||||
vertex_stack.pop()
|
||||
else:
|
||||
ignore, next_vertex, next_key = pick_edge(
|
||||
graph.edges(current_vertex, keys=True))
|
||||
ignore, next_vertex, next_key = pick_edge(graph.edges(current_vertex, keys=True))
|
||||
vertex_stack.append((next_vertex, next_key))
|
||||
graph.remove_edge(current_vertex, next_vertex, next_key)
|
||||
|
||||
|
@ -548,8 +534,7 @@ def find_stitch_path(graph, travel_graph, starting_point=None, ending_point=None
|
|||
# relevant in the case that the user specifies an underlay with an inset
|
||||
# value, because the starting point (and possibly ending point) can be
|
||||
# inside the shape.
|
||||
outline_nodes = [node for node, outline in travel_graph.nodes(
|
||||
data="outline") if outline is not None]
|
||||
outline_nodes = [node for node, outline in travel_graph.nodes(data="outline") if outline is not None]
|
||||
real_end = nearest_node(outline_nodes, ending_point)
|
||||
path.append(PathEdge((ending_node, real_end), key="outline"))
|
||||
|
||||
|
@ -639,7 +624,6 @@ def path_to_stitches(path, travel_graph, fill_stitch_graph, angle, row_spacing,
|
|||
stitch_row(stitches, edge[0], edge[1], angle, row_spacing, max_stitch_length, staggers, skip_last)
|
||||
travel_graph.remove_edges_from(fill_stitch_graph[edge[0]][edge[1]]['segment'].get('underpath_edges', []))
|
||||
else:
|
||||
stitches.extend(
|
||||
travel(travel_graph, edge[0], edge[1], running_stitch_length, skip_last))
|
||||
stitches.extend(travel(travel_graph, edge[0], edge[1], running_stitch_length, skip_last))
|
||||
|
||||
return stitches
|
||||
|
|
|
@ -14,8 +14,7 @@ from ..utils import cache
|
|||
|
||||
|
||||
def legacy_fill(shape, angle, row_spacing, end_row_spacing, max_stitch_length, flip, staggers, skip_last):
|
||||
rows_of_segments = intersect_region_with_grating(
|
||||
shape, angle, row_spacing, end_row_spacing, flip)
|
||||
rows_of_segments = intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing, flip)
|
||||
groups_of_segments = pull_runs(rows_of_segments, shape, row_spacing)
|
||||
|
||||
return [section_to_stitches(group, angle, row_spacing, max_stitch_length, staggers, skip_last)
|
||||
|
@ -75,8 +74,7 @@ def stitch_row(stitches, beg, end, angle, row_spacing, max_stitch_length, stagge
|
|||
|
||||
stitches.append(beg)
|
||||
|
||||
first_stitch = adjust_stagger(
|
||||
beg, angle, row_spacing, max_stitch_length, staggers)
|
||||
first_stitch = adjust_stagger(beg, angle, row_spacing, max_stitch_length, staggers)
|
||||
|
||||
# we might have chosen our first stitch just outside this row, so move back in
|
||||
if (first_stitch - beg) * row_direction < 0:
|
||||
|
@ -85,8 +83,7 @@ def stitch_row(stitches, beg, end, angle, row_spacing, max_stitch_length, stagge
|
|||
offset = (first_stitch - beg).length()
|
||||
|
||||
while offset < segment_length:
|
||||
stitches.append(
|
||||
Stitch(beg + offset * row_direction, tags=('fill_row')))
|
||||
stitches.append(Stitch(beg + offset * row_direction, tags=('fill_row')))
|
||||
offset += max_stitch_length
|
||||
|
||||
if (end - stitches[-1]).length() > 0.1 * PIXELS_PER_MM and not skip_last:
|
||||
|
@ -119,8 +116,7 @@ def intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing=Non
|
|||
# angle degrees clockwise and ask for the new bounding box. The max
|
||||
# and min y tell me how far to go.
|
||||
|
||||
_, start, _, end = shapely.affinity.rotate(
|
||||
shape, angle, origin='center', use_radians=True).bounds
|
||||
_, start, _, end = shapely.affinity.rotate(shape, angle, origin='center', use_radians=True).bounds
|
||||
|
||||
# convert start and end to be relative to center (simplifies things later)
|
||||
start -= center.y
|
||||
|
@ -155,8 +151,7 @@ def intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing=Non
|
|||
runs = [res.coords]
|
||||
|
||||
if runs:
|
||||
runs.sort(key=lambda seg: (
|
||||
InkstitchPoint(*seg[0]) - upper_left).length())
|
||||
runs.sort(key=lambda seg: (InkstitchPoint(*seg[0]) - upper_left).length())
|
||||
|
||||
if flip:
|
||||
runs.reverse()
|
||||
|
@ -165,9 +160,7 @@ def intersect_region_with_grating(shape, angle, row_spacing, end_row_spacing=Non
|
|||
yield runs
|
||||
|
||||
if end_row_spacing:
|
||||
current_row_y += row_spacing + \
|
||||
(end_row_spacing - row_spacing) * \
|
||||
((current_row_y - start) / height)
|
||||
current_row_y += row_spacing + (end_row_spacing - row_spacing) * ((current_row_y - start) / height)
|
||||
else:
|
||||
current_row_y += row_spacing
|
||||
|
||||
|
@ -182,8 +175,7 @@ def section_to_stitches(group_of_segments, angle, row_spacing, max_stitch_length
|
|||
if (swap):
|
||||
(beg, end) = (end, beg)
|
||||
|
||||
stitch_row(stitches, beg, end, angle, row_spacing,
|
||||
max_stitch_length, staggers, skip_last)
|
||||
stitch_row(stitches, beg, end, angle, row_spacing, max_stitch_length, staggers, skip_last)
|
||||
|
||||
swap = not swap
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue