chiark / gitweb /
Fixed the imports.
[cura.git] / Cura / util / svg.py
1 from __future__ import absolute_import
2
3 import math
4 from xml.etree import ElementTree
5
6 import profile
7
8 def processRect(e):
9         x = float(e.get('x'))
10         y = float(e.get('y'))
11         width = float(e.get('width'))
12         height = float(e.get('height'))
13         return [[complex(x, -y), complex(x+width, -y), complex(x+width, -(y+height)), complex(x, -(y+height)), complex(x, -y)]]
14
15 def processPath(e):
16         d = e.get('d').replace(',', ' ')
17         num = ""
18         cmd = None
19         paths = []
20         curPath = None
21         
22         p = complex(0, 0)
23         for c in d + "#":
24                 if c in "-+.0123456789e":
25                         num += c
26                 if c in " \t\n\r#":
27                         if len(num) > 0:
28                                 param.append(float(num))
29                         num = ""
30                 if c in "MmZzLlHhVvCcSsQqTtAa#":
31                         if cmd == 'M':
32                                 p = complex(param[0], -param[1])
33                                 curPath = None
34                                 i = 2
35                                 while i < len(param):
36                                         if curPath == None:
37                                                 curPath = [p]
38                                                 paths.append(curPath)
39                                         p = complex(param[i], -param[i+1])
40                                         curPath.append(p)
41                                         i += 2
42                         elif cmd == 'm':
43                                 p += complex(param[0], -param[1])
44                                 curPath = None
45                                 i = 2
46                                 while i < len(param):
47                                         if curPath == None:
48                                                 curPath = [p]
49                                                 paths.append(curPath)
50                                         p += complex(param[i], -param[i+1])
51                                         curPath.append(p)
52                                         i += 2
53                         elif cmd == 'L':
54                                 if curPath == None:
55                                         curPath = [p]
56                                         paths.append(curPath)
57                                 i = 0
58                                 while i < len(param):
59                                         p = complex(param[i], -param[i+1])
60                                         curPath.append(p)
61                                         i += 2
62                         elif cmd == 'l':
63                                 if curPath == None:
64                                         curPath = [p]
65                                         paths.append(curPath)
66                                 i = 0
67                                 while i < len(param):
68                                         p += complex(param[i], -param[i+1])
69                                         curPath.append(p)
70                                         i += 2
71                                 curPath.append(p)
72                         elif cmd == 'C':
73                                 if curPath == None:
74                                         curPath = [p]
75                                         paths.append(curPath)
76                                 i = 0
77                                 while i < len(param):
78                                         addCurve(curPath, p, complex(param[i], -param[i+1]), complex(param[i+2], -param[i+3]), complex(param[i+4], -param[i+5]))
79                                         p = complex(param[i+4], -param[i+5])
80                                         curPath.append(p)
81                                         i += 6
82                         elif cmd == 'c':
83                                 if curPath == None:
84                                         curPath = [p]
85                                         paths.append(curPath)
86                                 i = 0
87                                 while i < len(param):
88                                         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]))
89                                         p += complex(param[i+4], -param[i+5])
90                                         curPath.append(p)
91                                         i += 6
92                         elif cmd == 'a':
93                                 if curPath == None:
94                                         curPath = [p]
95                                         paths.append(curPath)
96                                 i = 0
97                                 print(param)
98                                 while i < len(param):
99                                         endPoint = p + complex(param[i+5], -param[i+6])
100                                         addArc(curPath, p, endPoint, complex(param[i], param[i+1]), param[i+2], param[i+3], param[i+4])
101                                         p = endPoint
102                                         curPath.append(p)
103                                         i += 7
104                         elif cmd == 'Z' or cmd == 'z':
105                                 curPath.append(curPath[0])
106                         elif cmd != None:
107                                 print(cmd)
108                         cmd = c
109                         param = []
110         return paths
111
112 def interpolate(p0, p1, f):
113         return complex(p0.real + (p1.real - p0.real) * f, p0.imag + (p1.imag - p0.imag) * f)
114
115 def addCurve(path, p0, q0, q1, p1):
116         oldPoint = p0
117         for n in xrange(0, 100):
118                 k = n / 100.0
119                 r0 = interpolate(p0, q0, k);
120                 r1 = interpolate(q0, q1, k);
121                 r2 = interpolate(q1, p1, k);
122                 b0 = interpolate(r0, r1, k);
123                 b1 = interpolate(r1, r2, k);
124                 s = interpolate(b0, b1, k);
125                 if abs(s - oldPoint) > 1.0:
126                         path.append(s)
127                         oldPoint = s
128
129 def addArc(path, begin, end, radius, xAxisRotation, largeArcFlag, sweepFlag):
130         xAxisRotationComplex = complex(math.cos(math.radians(xAxisRotation)), math.sin(math.radians(xAxisRotation)))
131         reverseXAxisRotationComplex = complex(xAxisRotationComplex.real, -xAxisRotationComplex.imag)
132         beginRotated = begin * reverseXAxisRotationComplex
133         endRotated = end * reverseXAxisRotationComplex
134         beginTransformed = complex(beginRotated.real / radius.real, beginRotated.imag / radius.imag)
135         endTransformed = complex(endRotated.real / radius.real, endRotated.imag / radius.imag)
136         midpointTransformed = 0.5 * (beginTransformed + endTransformed)
137         midMinusBeginTransformed = midpointTransformed - beginTransformed
138         midMinusBeginTransformedLength = abs(midMinusBeginTransformed)
139
140         if midMinusBeginTransformedLength > 1.0:
141                 radius *= midMinusBeginTransformedLength
142                 beginTransformed /= midMinusBeginTransformedLength
143                 endTransformed /= midMinusBeginTransformedLength
144                 midpointTransformed /= midMinusBeginTransformedLength
145                 midMinusBeginTransformed /= midMinusBeginTransformedLength
146                 midMinusBeginTransformedLength = 1.0
147         midWiddershinsTransformed = complex(-midMinusBeginTransformed.imag, midMinusBeginTransformed.real)
148         midWiddershinsLengthSquared = 1.0 - midMinusBeginTransformedLength * midMinusBeginTransformedLength
149         if midWiddershinsLengthSquared < 0.0:
150                 midWiddershinsLengthSquared = 0.0
151         midWiddershinsLength = math.sqrt(midWiddershinsLengthSquared)
152         midWiddershinsTransformed *= midWiddershinsLength / abs(midWiddershinsTransformed)
153         centerTransformed = midpointTransformed
154         if largeArcFlag == sweepFlag:
155                 centerTransformed -= midWiddershinsTransformed
156         else:
157                 centerTransformed += midWiddershinsTransformed
158         beginMinusCenterTransformed = beginTransformed - centerTransformed
159         beginMinusCenterTransformedLength = abs(beginMinusCenterTransformed)
160         if beginMinusCenterTransformedLength <= 0.0:
161                 return end
162         beginAngle = math.atan2(beginMinusCenterTransformed.imag, beginMinusCenterTransformed.real)
163         endMinusCenterTransformed = endTransformed - centerTransformed
164         angleDifference = getAngleDifferenceByComplex(endMinusCenterTransformed, beginMinusCenterTransformed)
165         if sweepFlag:
166                 if angleDifference < 0.0:
167                         angleDifference += 2.0 * math.pi
168         else:
169                 if angleDifference > 0.0:
170                         angleDifference -= 2.0 * math.pi
171
172         center = complex(centerTransformed.real * radius.real, centerTransformed.imag * radius.imag) * xAxisRotationComplex
173         for side in xrange(1, 32):
174                 a = beginAngle + float(side) * math.pi * 2 / 32
175                 circumferential = complex(math.cos(a) * radius.real, math.sin(a) * radius.imag) * beginMinusCenterTransformedLength
176                 point = center + circumferential * xAxisRotationComplex
177                 path.append(point)
178
179 def getAngleDifferenceByComplex( subtractFromComplex, subtractComplex ):
180         subtractComplexMirror = complex( subtractComplex.real , - subtractComplex.imag )
181         differenceComplex = subtractComplexMirror * subtractFromComplex
182         return math.atan2( differenceComplex.imag, differenceComplex.real )
183
184
185 def movePath(p, offset):
186         return map(lambda _p: _p - offset, p)
187
188 class SVG(object):
189         def __init__(self, filename):
190                 tagProcess = {}
191                 tagProcess['rect'] = processRect
192                 tagProcess['path'] = processPath
193
194                 self.paths = []
195                 for e in ElementTree.parse(open(filename, "r")).getiterator():
196                         tag = e.tag[e.tag.find('}')+1:]
197                         if not tag in tagProcess:
198                                 #print 'unknown tag: %s' % (tag)
199                                 continue
200                         self.paths.extend(tagProcess[tag](e))
201         
202         def center(self, centerPoint):
203                 offset = complex(0, 0)
204                 n = 0
205                 for path in self.paths:
206                         for point in path:
207                                 offset += point
208                                 n += 1
209                 offset /= n
210                 offset -= centerPoint
211                 
212                 self.paths = [movePath(p, offset) for p in self.paths]
213
214 if __name__ == '__main__':
215         svg = SVG("../logo.svg")
216         f = open("../../test_export.gcode", "w")
217
218         f.write(';TYPE:CUSTOM\n')
219         f.write(profile.getAlterationFileContents('start.gcode'))
220         svg.center(complex(profile.getPreferenceFloat('machine_width') / 2, profile.getPreferenceFloat('machine_depth') / 2))
221
222         layerThickness = 0.4
223         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
224         filamentArea = math.pi * filamentRadius * filamentRadius
225         lineWidth = profile.getProfileSettingFloat('nozzle_size') * 2
226
227         e = 0
228         z = layerThickness
229
230         for n in xrange(0, 20):
231                 f.write("G1 Z%f F%f\n" % (z, profile.getProfileSettingFloat('max_z_speed')*60))
232                 for path in svg.paths:
233                         oldPoint = path[0]
234                         extrusionMMperDist = lineWidth * layerThickness / filamentArea
235                         f.write("G1 X%f Y%f F%f\n" % (oldPoint.real, oldPoint.imag, profile.getProfileSettingFloat('travel_speed')*60))
236                         f.write("G1 F%f\n" % (profile.getProfileSettingFloat('print_speed')*60))
237                         for point in path[1:]:
238                                 dist = abs(oldPoint - point)
239                                 e += dist * extrusionMMperDist
240                                 f.write("G1 X%f Y%f E%f\n" % (point.real, point.imag, e))
241                                 oldPoint = point
242                 z += layerThickness
243         f.write(profile.getAlterationFileContents('end.gcode'))
244         f.close()
245