summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--inkstitch/__init__.py5
-rw-r--r--inkstitch/elements/element.py18
-rw-r--r--inkstitch/elements/stroke.py16
-rw-r--r--inkstitch/stitch_plan/stitch_plan.py29
-rw-r--r--inkstitch/stitch_plan/ties.py5
-rw-r--r--inkstitch/svg.py15
-rw-r--r--messages.po10
7 files changed, 66 insertions, 32 deletions
diff --git a/inkstitch/__init__.py b/inkstitch/__init__.py
index 2e7a55f6..45eed3a6 100644
--- a/inkstitch/__init__.py
+++ b/inkstitch/__init__.py
@@ -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):
diff --git a/inkstitch/elements/element.py b/inkstitch/elements/element.py
index 7a029eac..cfca3782 100644
--- a/inkstitch/elements/element.py
+++ b/inkstitch/elements/element.py
@@ -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',
diff --git a/inkstitch/elements/stroke.py b/inkstitch/elements/stroke.py
index b0e7d23f..0ce3fa67 100644
--- a/inkstitch/elements/stroke.py
+++ b/inkstitch/elements/stroke.py
@@ -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)
diff --git a/inkstitch/stitch_plan/stitch_plan.py b/inkstitch/stitch_plan/stitch_plan.py
index 3a7b8f18..82584bbc 100644
--- a/inkstitch/stitch_plan/stitch_plan.py
+++ b/inkstitch/stitch_plan/stitch_plan.py
@@ -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
diff --git a/inkstitch/stitch_plan/ties.py b/inkstitch/stitch_plan/ties.py
index 9c688e6b..1207ea51 100644
--- a/inkstitch/stitch_plan/ties.py
+++ b/inkstitch/stitch_plan/ties.py
@@ -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]
diff --git a/inkstitch/svg.py b/inkstitch/svg.py
index d9258f19..66806d7a 100644
--- a/inkstitch/svg.py
+++ b/inkstitch/svg.py
@@ -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)
diff --git a/messages.po b/messages.po
index 92630bb0..aa2a0523 100644
--- a/messages.po
+++ b/messages.po
@@ -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."