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.
pull/1/head
Lex Neva 2016-01-18 18:18:30 -05:00
rodzic 3e3d540089
commit 521be47402
2 zmienionych plików z 57 dodań i 23 usunięć

Wyświetl plik

@ -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>

Wyświetl plik

@ -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 = {}
ids = [line.split(',')[0] for line in output.splitlines()]
self.stacking_order = {id: order for order, id in enumerate(ids)}
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
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"]