summaryrefslogtreecommitdiff
path: root/lib/output.py
diff options
context:
space:
mode:
authorLex Neva <github.com@lexneva.name>2018-05-01 21:21:07 -0400
committerLex Neva <github.com@lexneva.name>2018-05-01 21:21:07 -0400
commit05daffb7e01db55879eb24f3c00532324a5d41af (patch)
tree43ff5d954e035e0e8b5a507b9c1bf9d6b4d3338d /lib/output.py
parent1b31806423c8fec4040fed6d1009db016860b763 (diff)
refactor everything out of lib/__init__.py
Diffstat (limited to 'lib/output.py')
-rw-r--r--lib/output.py130
1 files changed, 130 insertions, 0 deletions
diff --git a/lib/output.py b/lib/output.py
new file mode 100644
index 00000000..f1651357
--- /dev/null
+++ b/lib/output.py
@@ -0,0 +1,130 @@
+import libembroidery
+import inkex
+import simpletransform
+
+from .utils import Point
+from .svg import PIXELS_PER_MM, get_doc_size, get_viewbox_transform
+
+
+def make_thread(color):
+ thread = libembroidery.EmbThread()
+ thread.color = libembroidery.embColor_make(*color.rgb)
+
+ thread.description = color.name
+ thread.catalogNumber = ""
+
+ return thread
+
+def add_thread(pattern, thread):
+ """Add a thread to a pattern and return the thread's index"""
+
+ libembroidery.embPattern_addThread(pattern, thread)
+
+ return libembroidery.embThreadList_count(pattern.threadList) - 1
+
+def get_flags(stitch):
+ flags = 0
+
+ if stitch.jump:
+ flags |= libembroidery.JUMP
+
+ if stitch.trim:
+ flags |= libembroidery.TRIM
+
+ if stitch.stop:
+ flags |= libembroidery.STOP
+
+ return flags
+
+
+def _string_to_floats(string):
+ floats = string.split(',')
+ return [float(num) for num in floats]
+
+
+def get_origin(svg):
+ # The user can specify the embroidery origin by defining two guides
+ # named "embroidery origin" that intersect.
+
+ namedview = svg.find(inkex.addNS('namedview', 'sodipodi'))
+ all_guides = namedview.findall(inkex.addNS('guide', 'sodipodi'))
+ label_attribute = inkex.addNS('label', 'inkscape')
+ guides = [guide for guide in all_guides
+ if guide.get(label_attribute, "").startswith("embroidery origin")]
+
+ # document size used below
+ doc_size = list(get_doc_size(svg))
+
+ # convert the size from viewbox-relative to real-world pixels
+ viewbox_transform = get_viewbox_transform(svg)
+ simpletransform.applyTransformToPoint(simpletransform.invertTransform(viewbox_transform), doc_size)
+
+ default = [doc_size[0] / 2.0, doc_size[1] / 2.0]
+ simpletransform.applyTransformToPoint(viewbox_transform, default)
+ default = Point(*default)
+
+ if len(guides) < 2:
+ return default
+
+ # Find out where the guides intersect. Only pay attention to the first two.
+ guides = guides[:2]
+
+ lines = []
+ for guide in guides:
+ # inkscape's Y axis is reversed from SVG's, and the guide is in inkscape coordinates
+ position = Point(*_string_to_floats(guide.get('position')))
+ position.y = doc_size[1] - position.y
+
+
+ # This one baffles me. I think inkscape might have gotten the order of
+ # their vector wrong?
+ parts = _string_to_floats(guide.get('orientation'))
+ direction = Point(parts[1], parts[0])
+
+ # We have a theoretically infinite line defined by a point on the line
+ # and a vector direction. Shapely can only deal in concrete line
+ # segments, so we'll pick points really far in either direction on the
+ # line and call it good enough.
+ lines.append(shgeo.LineString((position + 100000 * direction, position - 100000 * direction)))
+
+ intersection = lines[0].intersection(lines[1])
+
+ if isinstance(intersection, shgeo.Point):
+ origin = [intersection.x, intersection.y]
+ simpletransform.applyTransformToPoint(viewbox_transform, origin)
+ return Point(*origin)
+ else:
+ # Either the two guides are the same line, or they're parallel.
+ return default
+
+
+def write_embroidery_file(file_path, stitch_plan, svg):
+ origin = get_origin(svg)
+
+ pattern = libembroidery.embPattern_create()
+
+ for color_block in stitch_plan:
+ add_thread(pattern, make_thread(color_block.color))
+
+ for stitch in color_block:
+ if stitch.stop and stitch is not color_block.last_stitch:
+ # A STOP stitch that is not at the end of a color block
+ # occurs when the user specified "STOP after". "STOP" is the
+ # same thing as a color change, and the user will assign a
+ # special color at the machine that tells it to pause after.
+ # We need to add another copy of the same color here so that
+ # the stitches after the STOP are still the same color.
+ add_thread(pattern, make_thread(color_block.color))
+
+ flags = get_flags(stitch)
+ libembroidery.embPattern_addStitchAbs(pattern, stitch.x - origin.x, stitch.y - origin.y, flags, 1)
+
+ libembroidery.embPattern_addStitchAbs(pattern, stitch.x - origin.x, stitch.y - origin.y, libembroidery.END, 1)
+
+ # convert from pixels to millimeters
+ libembroidery.embPattern_scale(pattern, 1/PIXELS_PER_MM)
+
+ # SVG and embroidery disagree on the direction of the Y axis
+ libembroidery.embPattern_flipVertical(pattern)
+
+ libembroidery.embPattern_write(pattern, file_path)