chiark / gitweb /
Seperate the machine settings from the preference settings
[cura.git] / Cura / util / svg.py
1 from __future__ import absolute_import
2 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
3
4 import math
5 from xml.etree import ElementTree
6
7 import profile
8
9 def processRect(e):
10         x = float(e.get('x'))
11         y = float(e.get('y'))
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)]]
15
16 def processPath(e):
17         d = e.get('d').replace(',', ' ')
18         num = ""
19         cmd = None
20         paths = []
21         curPath = None
22         
23         p = complex(0, 0)
24         for c in d + "#":
25                 if c in "-+.0123456789e":
26                         num += c
27                 if c in " \t\n\r#":
28                         if len(num) > 0:
29                                 param.append(float(num))
30                         num = ""
31                 if c in "MmZzLlHhVvCcSsQqTtAa#":
32                         if cmd == 'M':
33                                 p = complex(param[0], -param[1])
34                                 curPath = None
35                                 i = 2
36                                 while i < len(param):
37                                         if curPath == None:
38                                                 curPath = [p]
39                                                 paths.append(curPath)
40                                         p = complex(param[i], -param[i+1])
41                                         curPath.append(p)
42                                         i += 2
43                         elif cmd == 'm':
44                                 p += complex(param[0], -param[1])
45                                 curPath = None
46                                 i = 2
47                                 while i < len(param):
48                                         if curPath == None:
49                                                 curPath = [p]
50                                                 paths.append(curPath)
51                                         p += complex(param[i], -param[i+1])
52                                         curPath.append(p)
53                                         i += 2
54                         elif cmd == 'L':
55                                 if curPath == None:
56                                         curPath = [p]
57                                         paths.append(curPath)
58                                 i = 0
59                                 while i < len(param):
60                                         p = complex(param[i], -param[i+1])
61                                         curPath.append(p)
62                                         i += 2
63                         elif cmd == 'l':
64                                 if curPath == None:
65                                         curPath = [p]
66                                         paths.append(curPath)
67                                 i = 0
68                                 while i < len(param):
69                                         p += complex(param[i], -param[i+1])
70                                         curPath.append(p)
71                                         i += 2
72                                 curPath.append(p)
73                         elif cmd == 'C':
74                                 if curPath == None:
75                                         curPath = [p]
76                                         paths.append(curPath)
77                                 i = 0
78                                 while i < len(param):
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])
81                                         curPath.append(p)
82                                         i += 6
83                         elif cmd == 'c':
84                                 if curPath == None:
85                                         curPath = [p]
86                                         paths.append(curPath)
87                                 i = 0
88                                 while i < len(param):
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])
91                                         curPath.append(p)
92                                         i += 6
93                         elif cmd == 'a':
94                                 if curPath == None:
95                                         curPath = [p]
96                                         paths.append(curPath)
97                                 i = 0
98                                 print(param)
99                                 while i < len(param):
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])
102                                         p = endPoint
103                                         curPath.append(p)
104                                         i += 7
105                         elif cmd == 'Z' or cmd == 'z':
106                                 curPath.append(curPath[0])
107                         elif cmd != None:
108                                 print(cmd)
109                         cmd = c
110                         param = []
111         return paths
112
113 def interpolate(p0, p1, f):
114         return complex(p0.real + (p1.real - p0.real) * f, p0.imag + (p1.imag - p0.imag) * f)
115
116 def addCurve(path, p0, q0, q1, p1):
117         oldPoint = p0
118         for n in xrange(0, 100):
119                 k = n / 100.0
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:
127                         path.append(s)
128                         oldPoint = s
129
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)
140
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
157         else:
158                 centerTransformed += midWiddershinsTransformed
159         beginMinusCenterTransformed = beginTransformed - centerTransformed
160         beginMinusCenterTransformedLength = abs(beginMinusCenterTransformed)
161         if beginMinusCenterTransformedLength <= 0.0:
162                 return end
163         beginAngle = math.atan2(beginMinusCenterTransformed.imag, beginMinusCenterTransformed.real)
164         endMinusCenterTransformed = endTransformed - centerTransformed
165         angleDifference = getAngleDifferenceByComplex(endMinusCenterTransformed, beginMinusCenterTransformed)
166         if sweepFlag:
167                 if angleDifference < 0.0:
168                         angleDifference += 2.0 * math.pi
169         else:
170                 if angleDifference > 0.0:
171                         angleDifference -= 2.0 * math.pi
172
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
178                 path.append(point)
179
180 def getAngleDifferenceByComplex( subtractFromComplex, subtractComplex ):
181         subtractComplexMirror = complex( subtractComplex.real , - subtractComplex.imag )
182         differenceComplex = subtractComplexMirror * subtractFromComplex
183         return math.atan2( differenceComplex.imag, differenceComplex.real )
184
185
186 def movePath(p, offset):
187         return map(lambda _p: _p - offset, p)
188
189 class SVG(object):
190         def __init__(self, filename):
191                 tagProcess = {}
192                 tagProcess['rect'] = processRect
193                 tagProcess['path'] = processPath
194
195                 self.paths = []
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)
200                                 continue
201                         self.paths.extend(tagProcess[tag](e))
202         
203         def center(self, centerPoint):
204                 offset = complex(0, 0)
205                 n = 0
206                 for path in self.paths:
207                         for point in path:
208                                 offset += point
209                                 n += 1
210                 offset /= n
211                 offset -= centerPoint
212                 
213                 self.paths = [movePath(p, offset) for p in self.paths]
214
215 if __name__ == '__main__':
216         svg = SVG("../logo.svg")
217         f = open("../../test_export.gcode", "w")
218
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))
222
223         layerThickness = 0.4
224         filamentRadius = profile.getProfileSettingFloat('filament_diameter') / 2
225         filamentArea = math.pi * filamentRadius * filamentRadius
226         lineWidth = profile.getProfileSettingFloat('nozzle_size') * 2
227
228         e = 0
229         z = layerThickness
230
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:
234                         oldPoint = path[0]
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))
242                                 oldPoint = point
243                 z += layerThickness
244         f.write(profile.getAlterationFileContents('end.gcode'))
245         f.close()
246