summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLex Neva <github@lexneva.name>2016-01-18 18:18:30 -0500
committerLex Neva <github@lexneva.name>2016-01-18 18:18:30 -0500
commit521be47402de0ff955c8b2499ebec226938cdfc7 (patch)
tree6dda7ce5067d12ba495fd0285c19ef18c3e8abcf
parent3e3d54008937e0195c88143986ab6dc44c21facb (diff)
really fix "preserve order"
My previous fix didn't really do the job. It took patches in Z-order, but runs of patches of the same color were fed into the TSP algorithm and it could embroider them in whatever order it chose. This resulted in underlays for my fill regions being embroidered AFTER the fill. Now, the "preserve order" option has been changed to "preserve layers". Patches on different layers are gauranteed to be stitched in layer order. Patches of the same color within the same layer can be stitched in any order as chosen by the TSP algorithm.
-rw-r--r--embroider.inx3
-rw-r--r--embroider.py77
2 files changed, 57 insertions, 23 deletions
diff --git a/embroider.inx b/embroider.inx
index 1dd59464..d2682eba 100644
--- a/embroider.inx
+++ b/embroider.inx
@@ -9,8 +9,9 @@
<param name="max_stitch_len_mm" type="float" min="0.1" max="100.0" _gui-text="Maximum stitch length (mm)">3.0</param>
<param name="running_stitch_len_mm" type="float" min="0.1" max="100.0" _gui-text="Running stitch length (mm)">3.0</param>
<param name="collapse_len_mm" type="float" min="0.0" max="10.0" _gui-text="Maximum collapse length (mm)">0.0</param>
- <param name="preserve_order" type="boolean" _gui-text="Preserve stacking order" description="if false, sorts by color, which saves thread changes. True preserves stacking order, important if you're laying colors over each other.">false</param>
+ <param name="preserve_layers" type="boolean" _gui-text="Stitch layers in order" description="if false, sorts by color, which saves thread changes. True preserves layer order, important if you're laying colors over each other.">true</param>
<param name="hatch_filled_paths" type="boolean" _gui-text="Hatch filled paths" description="If false, filled paths are filled using equally-spaced lines. If true, filled paths are filled using hatching lines.">false</param>
+ <param name="hide_layers" type="boolean" _gui-text="Hide other layers" description="Hide all other top-level layers when the embroidery layer is generated, in order to make stitching discernable.">true</param>
<param name="add_preamble" type="optiongroup" _gui-text="Add preamble" appearance="minimal">
<_option value="0">None</_option>
<_option value="010">0-1-0</_option>
diff --git a/embroider.py b/embroider.py
index a13fa0b2..320c214a 100644
--- a/embroider.py
+++ b/embroider.py
@@ -217,7 +217,7 @@ class PatchList:
out = []
lastPatch = None
for patch in self.patches:
- if (lastPatch!=None and patch.color==lastPatch.color):
+ if (lastPatch!=None and patch.sortorder==lastPatch.sortorder):
out[-1].patches.append(patch)
else:
out.append(PatchList([patch]))
@@ -511,7 +511,7 @@ class EmbroideryObject:
inkex.addNS('path', 'svg'),
{ 'style':simplestyle.formatStyle(
{ 'stroke': color if color is not None else '#000000',
- 'stroke-width':str(self.row_spacing_px*0.5),
+ 'stroke-width':"1",
'fill': 'none' }),
'd':simplepath.formatPath(path),
})
@@ -526,14 +526,14 @@ class EmbroideryObject:
return (min(x), min(y), max(x), max(y))
class SortOrder:
- def __init__(self, threadcolor, stacking_order, preserve_order):
+ def __init__(self, threadcolor, layer, preserve_layers):
self.threadcolor = threadcolor
- if (preserve_order):
- dbg.write("preserve_order is true: %s %s\n" % (stacking_order, threadcolor));
- self.sorttuple = (stacking_order, threadcolor)
+ if (preserve_layers):
+ #dbg.write("preserve_layers is true: %s %s\n" % (layer, threadcolor));
+ self.sorttuple = (layer, threadcolor)
else:
- #dbg.write("preserve_order is false:\n");
- self.sorttuple = (threadcolor, stacking_order)
+ #dbg.write("preserve_layers is false:\n");
+ self.sorttuple = (threadcolor,)
def __cmp__(self, other):
return cmp(self.sorttuple, other.sorttuple)
@@ -570,16 +570,21 @@ class Embroider(inkex.Effect):
action="store", type="float",
dest="flat", default=0.1,
help="Minimum flatness of the subdivided curves")
- self.OptionParser.add_option("-o", "--preserve_order",
+ self.OptionParser.add_option("-o", "--preserve_layers",
action="store", type="choice",
choices=["true","false"],
- dest="preserve_order", default="false",
+ dest="preserve_layers", default="false",
help="Sort by stacking order instead of color")
self.OptionParser.add_option("-H", "--hatch_filled_paths",
action="store", type="choice",
choices=["true","false"],
dest="hatch_filled_paths", default="false",
help="Use hatching lines instead of equally-spaced lines to fill paths")
+ self.OptionParser.add_option("--hide_layers",
+ action="store", type="choice",
+ choices=["true","false"],
+ dest="hide_layers", default="true",
+ help="Hide all other layers when the embroidery layer is generated")
self.OptionParser.add_option("-p", "--add_preamble",
action="store", type="choice",
choices=["0","010","01010","01210","012101210"],
@@ -595,10 +600,11 @@ class Embroider(inkex.Effect):
dest="filename", default="embroider-output.exp",
help="Name (and possibly path) of output file")
self.patches = []
- self.stacking_order = {}
+ self.layer_cache = {}
def get_sort_order(self, threadcolor, node):
- return SortOrder(threadcolor, self.stacking_order.get(node.get("id")), self.options.preserve_order=="true")
+ #print >> sys.stderr, "node", node.get("id"), self.layer_cache.get(node.get("id"))
+ return SortOrder(threadcolor, self.layer_cache.get(node.get("id")), self.options.preserve_layers=="true")
def process_one_path(self, node, shpath, threadcolor, sortorder, angle):
#self.add_shapely_geo_to_svg(shpath.boundary, color="#c0c000")
@@ -732,15 +738,33 @@ class Embroider(inkex.Effect):
return None
return value
- def cache_stacking_order(self):
- output = subprocess.check_output('inkscape --query-all "%s" 2>/dev/null' % self.args[-1], shell=True)
+ def cache_layers(self):
+ self.layer_cache = {}
+
+ layer_tag = inkex.addNS("g", "svg")
+ group_attr = inkex.addNS('groupmode', 'inkscape')
+
+
+ def is_layer(node):
+ return node.tag == layer_tag and node.get(group_attr) == "layer"
+
+ def process(node, layer=0):
+ if is_layer(node):
+ layer += 1
+ else:
+ self.layer_cache[node.get("id")] = layer
- ids = [line.split(',')[0] for line in output.splitlines()]
- self.stacking_order = {id: order for order, id in enumerate(ids)}
+ for child in node:
+ layer = process(child, layer)
+
+ return layer
+
+ process(self.document.getroot())
def effect(self):
- if self.options.preserve_order == "true":
- self.cache_stacking_order()
+ if self.options.preserve_layers == "true":
+ self.cache_layers()
+ #print >> sys.stderr, "cached stacking order:", self.stacking_order
self.row_spacing_px = self.options.row_spacing_mm * pixels_per_millimeter
self.zigzag_spacing_px = self.options.zigzag_spacing_mm * pixels_per_millimeter
@@ -761,15 +785,19 @@ class Embroider(inkex.Effect):
self.patchList = self.patchList.tsp_by_color()
#dbg.write("patch count: %d\n" % len(self.patchList.patches))
+ if self.options.hide_layers:
+ self.hide_layers()
+
eo = EmbroideryObject(self.patchList, self.row_spacing_px)
emb = eo.emit_file(self.options.filename, self.options.output_format,
self.collapse_len_px, self.options.add_preamble)
- new_group = inkex.etree.SubElement(self.current_layer,
+ new_layer = inkex.etree.SubElement(self.document.getroot(),
inkex.addNS('g', 'svg'), {})
- eo.emit_inkscape(new_group, emb)
-
- self.emit_inkscape_bbox(new_group, eo)
+ new_layer.set('id', self.uniqueId("embroidery"))
+ new_layer.set(inkex.addNS('label', 'inkscape'), 'Embroidery')
+ new_layer.set(inkex.addNS('groupmode', 'inkscape'), 'layer')
+ eo.emit_inkscape(new_layer, emb)
def emit_inkscape_bbox(self, parent, eo):
(x0, y0, x1, y1) = eo.bbox()
@@ -788,6 +816,11 @@ class Embroider(inkex.Effect):
'd':simplepath.formatPath(new_path),
})
+ def hide_layers(self):
+ for g in self.document.getroot().findall(inkex.addNS("g","svg")):
+ if g.get(inkex.addNS("groupmode", "inkscape")) == "layer":
+ g.set("style", "display:none")
+
def path_to_patch_list(self, node):
threadcolor = simplestyle.parseStyle(node.get("style"))["stroke"]
stroke_width_str = simplestyle.parseStyle(node.get("style"))["stroke-width"]