1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
5 from xml.etree import ElementTree
12 width = float(e.get('width'))
13 height = float(e.get('height'))
14 return [[complex(x, -y), complex(x+width, -y), complex(x+width, -(y+height)), complex(x, -(y+height)), complex(x, -y)]]
17 d = e.get('d').replace(',', ' ')
25 if c in "-+.0123456789e":
29 param.append(float(num))
31 if c in "MmZzLlHhVvCcSsQqTtAa#":
33 p = complex(param[0], -param[1])
40 p = complex(param[i], -param[i+1])
44 p += complex(param[0], -param[1])
51 p += complex(param[i], -param[i+1])
60 p = complex(param[i], -param[i+1])
69 p += complex(param[i], -param[i+1])
79 addCurve(curPath, p, complex(param[i], -param[i+1]), complex(param[i+2], -param[i+3]), complex(param[i+4], -param[i+5]))
80 p = complex(param[i+4], -param[i+5])
89 addCurve(curPath, p, p + complex(param[i], -param[i+1]), p + complex(param[i+2], -param[i+3]), p + complex(param[i+4], -param[i+5]))
90 p += complex(param[i+4], -param[i+5])
100 endPoint = p + complex(param[i+5], -param[i+6])
101 addArc(curPath, p, endPoint, complex(param[i], param[i+1]), param[i+2], param[i+3], param[i+4])
105 elif cmd == 'Z' or cmd == 'z':
106 curPath.append(curPath[0])
113 def interpolate(p0, p1, f):
114 return complex(p0.real + (p1.real - p0.real) * f, p0.imag + (p1.imag - p0.imag) * f)
116 def addCurve(path, p0, q0, q1, p1):
118 for n in xrange(0, 100):
120 r0 = interpolate(p0, q0, k);
121 r1 = interpolate(q0, q1, k);
122 r2 = interpolate(q1, p1, k);
123 b0 = interpolate(r0, r1, k);
124 b1 = interpolate(r1, r2, k);
125 s = interpolate(b0, b1, k);
126 if abs(s - oldPoint) > 1.0:
130 def addArc(path, begin, end, radius, xAxisRotation, largeArcFlag, sweepFlag):
131 xAxisRotationComplex = complex(math.cos(math.radians(xAxisRotation)), math.sin(math.radians(xAxisRotation)))
132 reverseXAxisRotationComplex = complex(xAxisRotationComplex.real, -xAxisRotationComplex.imag)
133 beginRotated = begin * reverseXAxisRotationComplex
134 endRotated = end * reverseXAxisRotationComplex
135 beginTransformed = complex(beginRotated.real / radius.real, beginRotated.imag / radius.imag)
136 endTransformed = complex(endRotated.real / radius.real, endRotated.imag / radius.imag)
137 midpointTransformed = 0.5 * (beginTransformed + endTransformed)
138 midMinusBeginTransformed = midpointTransformed - beginTransformed
139 midMinusBeginTransformedLength = abs(midMinusBeginTransformed)
141 if midMinusBeginTransformedLength > 1.0:
142 radius *= midMinusBeginTransformedLength
143 beginTransformed /= midMinusBeginTransformedLength
144 endTransformed /= midMinusBeginTransformedLength
145 midpointTransformed /= midMinusBeginTransformedLength
146 midMinusBeginTransformed /= midMinusBeginTransformedLength
147 midMinusBeginTransformedLength = 1.0
148 midWiddershinsTransformed = complex(-midMinusBeginTransformed.imag, midMinusBeginTransformed.real)
149 midWiddershinsLengthSquared = 1.0 - midMinusBeginTransformedLength * midMinusBeginTransformedLength
150 if midWiddershinsLengthSquared < 0.0:
151 midWiddershinsLengthSquared = 0.0
152 midWiddershinsLength = math.sqrt(midWiddershinsLengthSquared)
153 midWiddershinsTransformed *= midWiddershinsLength / abs(midWiddershinsTransformed)
154 centerTransformed = midpointTransformed
155 if largeArcFlag == sweepFlag:
156 centerTransformed -= midWiddershinsTransformed
158 centerTransformed += midWiddershinsTransformed
159 beginMinusCenterTransformed = beginTransformed - centerTransformed
160 beginMinusCenterTransformedLength = abs(beginMinusCenterTransformed)
161 if beginMinusCenterTransformedLength <= 0.0:
163 beginAngle = math.atan2(beginMinusCenterTransformed.imag, beginMinusCenterTransformed.real)
164 endMinusCenterTransformed = endTransformed - centerTransformed
165 angleDifference = getAngleDifferenceByComplex(endMinusCenterTransformed, beginMinusCenterTransformed)
167 if angleDifference < 0.0:
168 angleDifference += 2.0 * math.pi
170 if angleDifference > 0.0:
171 angleDifference -= 2.0 * math.pi
173 center = complex(centerTransformed.real * radius.real, centerTransformed.imag * radius.imag) * xAxisRotationComplex
174 for side in xrange(1, 32):
175 a = beginAngle + float(side) * math.pi * 2 / 32
176 circumferential = complex(math.cos(a) * radius.real, math.sin(a) * radius.imag) * beginMinusCenterTransformedLength
177 point = center + circumferential * xAxisRotationComplex
180 def getAngleDifferenceByComplex( subtractFromComplex, subtractComplex ):
181 subtractComplexMirror = complex( subtractComplex.real , - subtractComplex.imag )
182 differenceComplex = subtractComplexMirror * subtractFromComplex
183 return math.atan2( differenceComplex.imag, differenceComplex.real )
186 def movePath(p, offset):
187 return map(lambda _p: _p - offset, p)
190 def __init__(self, filename):
192 tagProcess['rect'] = processRect
193 tagProcess['path'] = processPath
196 for e in ElementTree.parse(open(filename, "r")).getiterator():
197 tag = e.tag[e.tag.find('}')+1:]
198 if not tag in tagProcess:
199 #print 'unknown tag: %s' % (tag)
201 self.paths.extend(tagProcess[tag](e))
203 def center(self, centerPoint):
204 offset = complex(0, 0)
206 for path in self.paths:
211 offset -= centerPoint
213 self.paths = [movePath(p, offset) for p in self.paths]
215 if __name__ == '__main__':
216 svg = SVG("../logo.svg")
217 f = open("../../test_export.gcode", "w")
219 f.write(';TYPE:CUSTOM\n')
220 f.write(profile.getAlterationFileContents('start.gcode'))
221 svg.center(complex(profile.getMachineSettingFloat('machine_width') / 2, profile.getMachineSettingFloat('machine_depth') / 2))
224 filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
225 filamentArea = math.pi * filamentRadius * filamentRadius
226 lineWidth = profile.getProfileSettingFloat('nozzle_size') * 2
231 for n in xrange(0, 20):
232 f.write("G1 Z%f F%f\n" % (z, profile.getProfileSettingFloat('max_z_speed')*60))
233 for path in svg.paths:
235 extrusionMMperDist = lineWidth * layerThickness / filamentArea
236 f.write("G1 X%f Y%f F%f\n" % (oldPoint.real, oldPoint.imag, profile.getProfileSettingFloat('travel_speed')*60))
237 f.write("G1 F%f\n" % (profile.getProfileSettingFloat('print_speed')*60))
238 for point in path[1:]:
239 dist = abs(oldPoint - point)
240 e += dist * extrusionMMperDist
241 f.write("G1 X%f Y%f E%f\n" % (point.real, point.imag, e))
244 f.write(profile.getAlterationFileContents('end.gcode'))