summaryrefslogtreecommitdiff
path: root/inkstitch.py
diff options
context:
space:
mode:
Diffstat (limited to 'inkstitch.py')
-rw-r--r--inkstitch.py86
1 files changed, 75 insertions, 11 deletions
diff --git a/inkstitch.py b/inkstitch.py
index 8a87b160..ba120be0 100644
--- a/inkstitch.py
+++ b/inkstitch.py
@@ -14,6 +14,7 @@ import simpletransform
from bezmisc import bezierlength, beziertatlength, bezierpointatt
from cspsubdiv import cspsubdiv
import cubicsuperpath
+from shapely import geometry as shgeo
try:
@@ -127,11 +128,16 @@ def convert_length(length):
@cache
+def get_doc_size(svg):
+ doc_width = convert_length(svg.get('width'))
+ doc_height = convert_length(svg.get('height'))
+
+ return doc_width, doc_height
+
+@cache
def get_viewbox_transform(node):
# somewhat cribbed from inkscape-silhouette
-
- doc_width = convert_length(node.get('width'))
- doc_height = convert_length(node.get('height'))
+ doc_width, doc_height = get_doc_size(node)
viewbox = node.get('viewBox').strip().replace(',', ' ').split()
@@ -504,12 +510,70 @@ def get_flags(stitch):
return flags
-def write_embroidery_file(file_path, stitches):
- # Embroidery machines don't care about our canvas size, so we relocate the
- # design to the origin. It might make sense to center it about the origin
- # instead.
- min_x = min(stitch.x for stitch in stitches)
- min_y = min(stitch.y for stitch in stitches)
+
+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, stitches, svg):
+ origin = get_origin(svg)
pattern = libembroidery.embPattern_create()
last_color = None
@@ -520,9 +584,9 @@ def write_embroidery_file(file_path, stitches):
last_color = stitch.color
flags = get_flags(stitch)
- libembroidery.embPattern_addStitchAbs(pattern, stitch.x - min_x, stitch.y - min_y, flags, 1)
+ libembroidery.embPattern_addStitchAbs(pattern, stitch.x - origin.x, stitch.y - origin.y, flags, 1)
- libembroidery.embPattern_addStitchAbs(pattern, stitch.x - min_x, stitch.y - min_y, libembroidery.END, 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)