Merge pull request #135 from lexelby/lexelby-manual-stitch

add manual stitch mode
pull/152/head
Lex Neva 2018-04-09 20:15:30 -04:00 zatwierdzone przez GitHub
commit 69c64bf3a7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
7 zmienionych plików z 66 dodań i 32 usunięć

Wyświetl plik

@ -161,16 +161,17 @@ def get_stroke_scale(node):
class Stitch(Point):
def __init__(self, x, y, color=None, jump=False, stop=False, trim=False):
def __init__(self, x, y, color=None, jump=False, stop=False, trim=False, no_ties=False):
self.x = x
self.y = y
self.color = color
self.jump = jump
self.trim = trim
self.stop = stop
self.no_ties = no_ties
def __repr__(self):
return "Stitch(%s, %s, %s, %s, %s, %s)" % (self.x, self.y, self.color, "JUMP" if self.jump else "", "TRIM" if self.trim else "", "STOP" if self.stop else "")
return "Stitch(%s, %s, %s, %s, %s, %s, %s)" % (self.x, self.y, self.color, "JUMP" if self.jump else " ", "TRIM" if self.trim else " ", "STOP" if self.stop else " ", "NO TIES" if self.no_ties else " ")
def make_thread(color):

Wyświetl plik

@ -14,11 +14,12 @@ from cspsubdiv import cspsubdiv
class Patch:
"""A raw collection of stitches with attached instructions."""
def __init__(self, color=None, stitches=None, trim_after=False, stop_after=False):
def __init__(self, color=None, stitches=None, trim_after=False, stop_after=False, stitch_as_is=False):
self.color = color
self.stitches = stitches or []
self.trim_after = trim_after
self.stop_after = stop_after
self.stitch_as_is = stitch_as_is
def __add__(self, other):
if isinstance(other, Patch):
@ -203,25 +204,18 @@ class EmbroideryElement(object):
# apply the combined transform to this node's path
simpletransform.applyTransformToPath(transform, path)
return path
def strip_control_points(self, subpath):
return [point for control_before, point, control_after in subpath]
def flatten(self, path):
"""approximate a path containing beziers with a series of points"""
path = deepcopy(path)
cspsubdiv(path, 0.1)
flattened = []
for comp in path:
vertices = []
for ctl in comp:
vertices.append((ctl[1][0], ctl[1][1]))
flattened.append(vertices)
return flattened
return [self.strip_control_points(subpath) for subpath in path]
@property
@param('trim_after',

Wyświetl plik

@ -37,7 +37,17 @@ class Stroke(EmbroideryElement):
@property
def paths(self):
return self.flatten(self.parse_path())
path = self.parse_path()
if self.manual_stitch_mode:
return [self.strip_control_points(subpath) for subpath in path]
else:
return self.flatten(path)
@property
@param('manual_stitch', _('Manual stitch placement'), tooltip=_("Stitch every node in the path. Stitch length and zig-zag spacing are ignored."), type='boolean', default=False)
def manual_stitch_mode(self):
return self.get_boolean_param('manual_stitch')
def is_running_stitch(self):
# stroke width <= 0.5 pixels is deprecated in favor of dashed lines
@ -99,7 +109,9 @@ class Stroke(EmbroideryElement):
for path in self.paths:
path = [Point(x, y) for x, y in path]
if self.is_running_stitch():
if self.manual_stitch_mode:
patch = Patch(color=self.color, stitches=path, stitch_as_is=True)
elif self.is_running_stitch():
patch = self.stroke_points(path, self.running_stitch_length, stroke_width=0.0)
else:
patch = self.stroke_points(path, self.zigzag_spacing / 2.0, stroke_width=self.stroke_width)

Wyświetl plik

@ -36,6 +36,7 @@ def patches_to_stitch_plan(patches, collapse_len=3.0 * PIXELS_PER_MM):
if color_block.last_stitch:
if (patch.stitches[0] - color_block.last_stitch).length() > collapse_len:
color_block.add_stitch(patch.stitches[0].x, patch.stitches[0].y, jump=True)
else:
# add a color change
color_block.add_stitch(color_block.last_stitch.x, color_block.last_stitch.y, stop=True)
@ -43,7 +44,7 @@ def patches_to_stitch_plan(patches, collapse_len=3.0 * PIXELS_PER_MM):
color_block.color = patch.color
color_block.filter_duplicate_stitches()
color_block.add_stitches(patch.stitches)
color_block.add_stitches(patch.stitches, no_ties=patch.stitch_as_is)
if patch.trim_after:
# a trim needs to be followed by a jump to the next stitch, so
@ -75,6 +76,9 @@ class StitchPlan(object):
def __len__(self):
return len(self.color_blocks)
def __repr__(self):
return "StitchPlan(%s)" % ", ".join(repr(cb) for cb in self.color_blocks)
@property
def num_colors(self):
"""Number of unique colors in the stitch plan."""
@ -109,6 +113,9 @@ class ColorBlock(object):
def __iter__(self):
return iter(self.stitches)
def __repr__(self):
return "ColorBlock(%s, %s)" % (self.color, self.stitches)
def has_color(self):
return self._color is not None
@ -159,10 +166,14 @@ class ColorBlock(object):
stitches = [self.stitches[0]]
for stitch in self.stitches[1:]:
l = (stitch - stitches[-1]).length()
if l <= 0.1:
# duplicate stitch, skip this one
continue
if stitches[-1].jump or stitch.stop or stitch.trim:
# Don't consider jumps, stops, or trims as candidates for filtering
pass
else:
l = (stitch - stitches[-1]).length()
if l <= 0.1:
# duplicate stitch, skip this one
continue
stitches.append(stitch)
@ -172,16 +183,16 @@ class ColorBlock(object):
if isinstance(args[0], Stitch):
self.stitches.append(args[0])
elif isinstance(args[0], Point):
self.stitches.append(Stitch(args[0].x, args[0].y))
self.stitches.append(Stitch(args[0].x, args[0].y, *args[1:], **kwargs))
else:
self.stitches.append(Stitch(*args, **kwargs))
def add_stitches(self, stitches):
def add_stitches(self, stitches, *args, **kwargs):
for stitch in stitches:
if isinstance(stitch, (Stitch, Point)):
self.add_stitch(stitch)
self.add_stitch(stitch, *args, **kwargs)
else:
self.add_stitch(*stitch)
self.add_stitch(*(list(stitch) + args), **kwargs)
def replace_stitches(self, stitches):
self.stitches = stitches

Wyświetl plik

@ -4,6 +4,11 @@ from .. import Stitch
from copy import deepcopy
def add_tie(stitches, tie_path):
if stitches[-1].no_ties:
# It's from a manual stitch block, so don't add tie stitches. The user
# will add them if they want them.
return
tie_path = cut_path(tie_path, 0.6)
tie_stitches = running_stitch(tie_path, 0.3)
tie_stitches = [Stitch(stitch.x, stitch.y) for stitch in tie_stitches]

Wyświetl plik

@ -1,5 +1,5 @@
import simpletransform, simplestyle, inkex
from . import _, get_viewbox_transform, cache, SVG_GROUP_TAG, INKSCAPE_LABEL, INKSCAPE_GROUPMODE, SVG_POLYLINE_TAG
from . import _, get_viewbox_transform, cache, SVG_GROUP_TAG, INKSCAPE_LABEL, INKSCAPE_GROUPMODE, SVG_PATH_TAG
def color_block_to_point_lists(color_block):
point_lists = [[]]
@ -27,18 +27,21 @@ def get_correction_transform(svg):
return transform
def color_block_to_polylines(color_block, svg):
def color_block_to_paths(color_block, svg):
polylines = []
# We could emit just a single path with one subpath per point list, but
# emitting multiple paths makes it easier for the user to manipulate them.
for point_list in color_block_to_point_lists(color_block):
color = color_block.color.visible_on_white.to_hex_str()
polylines.append(inkex.etree.Element(
SVG_POLYLINE_TAG,
SVG_PATH_TAG,
{'style': simplestyle.formatStyle(
{'stroke': color,
'stroke-width': "0.4",
'fill': 'none'}),
'points': " ".join(",".join(str(coord) for coord in point) for point in point_list),
'transform': get_correction_transform(svg)
'd': "M" + " ".join(" ".join(str(coord) for coord in point) for point in point_list),
'transform': get_correction_transform(svg),
'embroider_manual_stitch': 'true'
}))
return polylines
@ -63,6 +66,6 @@ def render_stitch_plan(svg, stitch_plan):
SVG_GROUP_TAG,
{'id': '__color_block_%d__' % i,
INKSCAPE_LABEL: "color block %d" % (i + 1)})
group.extend(color_block_to_polylines(color_block, svg))
group.extend(color_block_to_paths(color_block, svg))
svg.append(layer)

Wyświetl plik

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2018-03-30 20:26-0400\n"
"POT-Creation-Date: 2018-04-02 22:11-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -272,6 +272,14 @@ msgstr ""
msgid "Repeats"
msgstr ""
msgid "Manual stitch placement"
msgstr ""
msgid ""
"Stitch every node in the path. Stitch length and zig-zag spacing are "
"ignored."
msgstr ""
msgid ""
"Unable to autofill. This most often happens because your shape is made "
"up of multiple sections that aren't connected."