kopia lustrzana https://github.com/inkstitch/inkstitch
commit
69c64bf3a7
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
10
messages.po
10
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."
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue