svg2gcode/svg2gcode.py

Sat, 07 Nov 2015 15:51:29 +0100

author
mbayer
date
Sat, 07 Nov 2015 15:51:29 +0100
changeset 5
b41cdab37aab
parent 4
234ad2069fdd
child 6
ff679c15cb0e
permissions
-rwxr-xr-x

added generic infill support, alpha stage

4
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
1 #!/usr/bin/env python
5
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
2 # -*- coding: utf-8 -*-
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
3
4
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
4 import svg, sys
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
5 from gcode import Gcode
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
6 from optparse import OptionParser
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
7
5
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
8 from shapely.geometry import box, MultiLineString, Point, Polygon
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
9 from shapely.affinity import rotate
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
10 from shapely import speedups
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
11 from math import sqrt
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
12
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
13 # enable Shapely speedups, if possible
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
14 if speedups.available:
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
15 speedups.enable()
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
16
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
17 def hatchbox(rect, angle, spacing):
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
18 """
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
19 returns a Shapely geometry (MULTILINESTRING, or more rarely,
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
20 GEOMETRYCOLLECTION) for a simple hatched rectangle.
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
21
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
22 args:
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
23 rect - a Shapely geometry for the outer boundary of the hatch
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
24 Likely most useful if it really is a rectangle
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
25
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
26 angle - angle of hatch lines, conventional anticlockwise -ve
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
27
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
28 spacing - spacing between hatch lines
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
29
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
30 GEOMETRYCOLLECTION case occurs when a hatch line intersects with
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
31 the corner of the clipping rectangle, which produces a point
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
32 along with the usual lines.
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
33 """
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
34
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
35 (llx, lly, urx, ury) = rect.bounds
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
36 centre_x = (urx + llx) / 2
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
37 centre_y = (ury + lly) / 2
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
38 diagonal_length = sqrt((urx - llx) ** 2 + (ury - lly) ** 2)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
39 number_of_lines = 2 + int(diagonal_length / spacing)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
40 hatch_length = spacing * (number_of_lines - 1)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
41
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
42 # build a square (of side hatch_length) horizontal lines
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
43 # centred on centroid of the bounding box, 'spacing' units apart
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
44 coords = []
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
45 for i in range(number_of_lines):
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
46 # alternate lines l2r and r2l to keep HP-7470A plotter happy ☺
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
47 if i % 2:
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
48 coords.extend([((centre_x - hatch_length / 2, centre_y
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
49 - hatch_length / 2 + i * spacing), (centre_x
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
50 + hatch_length / 2, centre_y - hatch_length
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
51 / 2 + i * spacing))])
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
52 else:
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
53 coords.extend([((centre_x + hatch_length / 2, centre_y
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
54 - hatch_length / 2 + i * spacing), (centre_x
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
55 - hatch_length / 2, centre_y - hatch_length
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
56 / 2 + i * spacing))])
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
57 # turn array into Shapely object
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
58 lines = MultiLineString(coords)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
59 # Rotate by angle around box centre
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
60 lines = rotate(lines, angle, origin='centroid', use_radians=False)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
61 # return clipped array
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
62 return rect.intersection(lines)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
63
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
64 def infill(bbox, polygon, angle=0, spacing=10):
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
65 b1, b2 = bbox
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
66 x1, y1 = b1.coord()
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
67 x2, y2 = b2.coord()
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
68 page = box(x1, y1, x2, y2)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
69 hatching = hatchbox(page, angle, spacing)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
70 # create shape from polygon:
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
71 segments = []
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
72 for pnt in polygon:
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
73 x, y = pnt.coord()
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
74 segments.append((x, y))
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
75
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
76 shape = Polygon(segments)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
77 return shape.intersection(hatching)
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
78
4
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
79 parser = OptionParser()
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
80 parser.add_option("-f", "--file", dest="filename", default=None,
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
81 help="Load SVG file", metavar="FILE")
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
82 parser.add_option("-s", "--scale",
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
83 dest="scale", type="float", default=1.0,
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
84 help="set scale factor (default 1.0)")
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
85 parser.add_option("-e", "",
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
86 dest="engrave_speed", type="float", default=20,
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
87 help="engrave speed mm/sec (default 20)")
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
88 parser.add_option("-t", "",
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
89 dest="travel_speed", type="float", default=130,
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
90 help="travel speed mm/sec (default 130)")
5
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
91 parser.add_option("-o", "--outline", action="store_true",
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
92 dest="outline", default=False,
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
93 help="no infill, only outlines")
4
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
94
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
95
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
96 (options, args) = parser.parse_args()
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
97
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
98
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
99 if not options.filename:
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
100 print "no filename given!"
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
101 sys.exit(1)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
102
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
103 gcode = Gcode(scale=options.scale, travel_speed=options.travel_speed, engrave_speed=options.engrave_speed)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
104
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
105 im = svg.parse(options.filename)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
106 b1, b2 = im.bbox()
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
107 width, height = b2.coord()
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
108 print "Original dimension: %.2f x %.2f" % (width, height)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
109 width *= gcode.mm_pixel * options.scale
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
110 height *= gcode.mm_pixel * options.scale
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
111 print "Print dimension: %.2fmm x %.2fmm" % (width, height)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
112
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
113 def normalize(coord):
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
114 x = coord[0]
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
115 y = coord[1]
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
116 # flip y
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
117 y = (b2.coord()[1] - y)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
118 return (x, y)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
119
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
120 data = im.flatten()
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
121 for d in data:
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
122 if hasattr(d, "segments"):
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
123 for l in d.segments(1):
5
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
124 # THE OUTLINE
4
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
125 x, y = normalize(l[0].coord())
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
126 gcode.move(x, y)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
127 for pt in l[1:]:
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
128 x, y = normalize(pt.coord())
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
129 gcode.engrave(x, y)
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
130
5
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
131 if not options.outline:
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
132 # THE INFILL
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
133 for line in infill(im.bbox(), l, spacing=2):
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
134 start = normalize((line.coords[0][0], line.coords[0][1]))
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
135 end = normalize((line.coords[1][0], line.coords[1][1]))
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
136 gcode.move(start[0], start[1])
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
137 gcode.engrave(end[0], end[1])
b41cdab37aab added generic infill support, alpha stage
mbayer
parents: 4
diff changeset
138
4
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
139 # write gcode file
234ad2069fdd initial untested svg to gcode script
mbayer
parents:
diff changeset
140 gcode.write(options.filename + ".g")

mercurial