1 """
2 Gcode visualisation class extracted from Printrun application.
3
4 Credits:
5 Original Author: Kliment (https://github.com/kliment/Printrun)
6
7 """
8 import wx, time, sys
9
11 - def __init__(self, f, title="Layer view",size=(600, 600), bedsize=(200, 200), grid=(10, 50), extrusion_width=0.5):
12 wx.Frame.__init__(self, None, title="%s (Use shift+mousewheel to switch layers)"%title, size=(size[0], size[1]))
13 self.p = gviz(self, size=size, bedsize=bedsize, grid=grid, extrusion_width=extrusion_width)
14 s = time.time()
15 for i in f:
16 self.p.addgcode(i)
17 self.initpos = [0, 0]
18 self.p.Bind(wx.EVT_CHAR_HOOK, self.key)
19 self.Bind(wx.EVT_CHAR_HOOK, self.key)
20 self.p.Bind(wx.EVT_MOUSEWHEEL, self.zoom)
21 self.Bind(wx.EVT_MOUSEWHEEL, self.zoom)
22 self.p.Bind(wx.EVT_MOUSE_EVENTS, self.mouse)
23 self.Bind(wx.EVT_MOUSE_EVENTS, self.mouse)
24
26 if event.ButtonUp(wx.MOUSE_BTN_LEFT):
27 if(self.initpos is not None):
28 self.initpos = None
29 elif event.Dragging():
30 e = event.GetPositionTuple()
31 if self.initpos is None or not hasattr(self, "basetrans"):
32 self.initpos = e
33 self.basetrans = self.p.translate
34 self.p.translate = [ self.basetrans[0] + (e[0] - self.initpos[0]),
35 self.basetrans[1] + (e[1] - self.initpos[1]) ]
36 self.p.repaint()
37 self.p.Refresh()
38
39 else:
40 event.Skip()
41
42 - def key(self, event):
43 x = event.GetKeyCode()
44 if x == wx.WXK_UP:
45 self.p.layerup()
46 if x == wx.WXK_DOWN:
47 self.p.layerdown()
48
49 - def zoom(self, event):
50 z = event.GetWheelRotation()
51 if event.ShiftDown():
52 if z > 0: self.p.layerdown()
53 elif z < 0: self.p.layerup()
54 else:
55 if z > 0: self.p.zoom(event.GetX(), event.GetY(), 1.2)
56 elif z < 0: self.p.zoom(event.GetX(), event.GetY(), 1 / 1.2)
57
58 -class gviz(wx.Panel):
59 - def __init__(self, parent, size=(200, 200), bedsize=(200, 200), grid=(10, 50), extrusion_width=0.5):
60 wx.Panel.__init__(self, parent, -1, size=(size[0], size[1]))
61 self.size = size
62 self.bedsize = bedsize
63 self.grid = grid
64 self.lastpos = [0, 0, 0, 0, 0, 0, 0]
65 self.hilightpos = self.lastpos[:]
66 self.Bind(wx.EVT_PAINT, self.paint)
67 self.Bind(wx.EVT_SIZE, lambda * e:(wx.CallAfter(self.repaint), wx.CallAfter(self.Refresh)))
68 self.lines = {}
69 self.pens = {}
70 self.arcs = {}
71 self.arcpens = {}
72 self.layers = []
73 self.layerindex = 0
74 self.filament_width = extrusion_width
75 self.scale = [min(float(size[0]) / bedsize[0], float(size[1]) / bedsize[1])] * 2
76 penwidth = max(1.0, self.filament_width * ((self.scale[0] + self.scale[1]) / 2.0))
77 self.translate = [0.0, 0.0]
78 self.mainpen = wx.Pen(wx.Colour(0, 0, 0), penwidth)
79 self.arcpen = wx.Pen(wx.Colour(255, 0, 0), penwidth)
80 self.travelpen = wx.Pen(wx.Colour(10, 80, 80), penwidth)
81 self.hlpen = wx.Pen(wx.Colour(200, 50, 50), penwidth)
82 self.fades = [wx.Pen(wx.Colour(250 - 0.6 ** i * 100, 250 - 0.6 ** i * 100, 200 - 0.4 ** i * 50), penwidth) for i in xrange(6)]
83 self.penslist = [self.mainpen, self.travelpen, self.hlpen] + self.fades
84 self.showall = 0
85 self.hilight = []
86 self.hilightarcs = []
87 self.dirty = 1
88 self.blitmap = wx.EmptyBitmap(self.GetClientSize()[0], self.GetClientSize()[1], -1)
89
91 self.lastpos = [0, 0, 0, 0, 0, 0, 0]
92 self.lines = {}
93 self.pens = {}
94 self.layers = []
95 self.layerindex = 0
96 self.showall = 0
97 self.dirty = 1
98
100 if(self.layerindex + 1 < len(self.layers)):
101 self.layerindex += 1
102 self.repaint()
103 self.Refresh()
104
106 if(self.layerindex > 0):
107 self.layerindex -= 1
108 self.repaint()
109 self.Refresh()
110
112 try:
113 self.layerindex = self.layers.index(layer)
114 self.repaint()
115 wx.CallAfter(self.Refresh)
116 self.showall = 0
117 except:
118 pass
119
120 - def zoom(self, x, y, factor):
121 self.scale = [s * factor for s in self.scale]
122 self.translate = [ x - (x - self.translate[0]) * factor,
123 y - (y - self.translate[1]) * factor]
124 penwidth = max(1.0, self.filament_width * ((self.scale[0] + self.scale[1]) / 2.0))
125 for pen in self.penslist:
126 pen.SetWidth(penwidth)
127 self.repaint()
128 self.Refresh()
129
131 self.blitmap = wx.EmptyBitmap(self.GetClientSize()[0], self.GetClientSize()[1], -1)
132 dc = wx.MemoryDC()
133 dc.SelectObject(self.blitmap)
134 dc.SetBackground(wx.Brush((250, 250, 200)))
135 dc.Clear()
136 dc.SetPen(wx.Pen(wx.Colour(180, 180, 150)))
137 for grid_unit in self.grid:
138 if grid_unit > 0:
139 for x in xrange(int(self.bedsize[0] / grid_unit) + 1):
140 dc.DrawLine(self.translate[0] + x * self.scale[0] * grid_unit, self.translate[1], self.translate[0] + x * self.scale[0] * grid_unit, self.translate[1] + self.scale[1] * self.bedsize[1])
141 for y in xrange(int(self.bedsize[1] / grid_unit) + 1):
142 dc.DrawLine(self.translate[0], self.translate[1] + y * self.scale[1] * grid_unit, self.translate[0] + self.scale[0] * self.bedsize[0], self.translate[1] + y * self.scale[1] * grid_unit)
143 dc.SetPen(wx.Pen(wx.Colour(0, 0, 0)))
144 if not self.showall:
145 self.size = self.GetSize()
146 dc.SetBrush(wx.Brush((43, 144, 255)))
147 dc.DrawRectangle(self.size[0] - 15, 0, 15, self.size[1])
148 dc.SetBrush(wx.Brush((0, 255, 0)))
149 if len(self.layers):
150 dc.DrawRectangle(self.size[0] - 14, (1.0 - (1.0 * (self.layerindex + 1)) / len(self.layers)) * self.size[1], 13, self.size[1] - 1)
151
152 def _drawlines(lines, pens):
153 def _scaler(x):
154 return (self.scale[0] * x[0] + self.translate[0],
155 self.scale[1] * x[1] + self.translate[1],
156 self.scale[0] * x[2] + self.translate[0],
157 self.scale[1] * x[3] + self.translate[1],)
158 scaled_lines = map(_scaler, lines)
159 dc.DrawLineList(scaled_lines, pens)
160
161 def _drawarcs(arcs, pens):
162 def _scaler(x):
163 return (self.scale[0] * x[0] + self.translate[0],
164 self.scale[1] * x[1] + self.translate[1],
165 self.scale[0] * x[2] + self.translate[0],
166 self.scale[1] * x[3] + self.translate[1],
167 self.scale[0] * x[4] + self.translate[0],
168 self.scale[1] * x[5] + self.translate[1],)
169 scaled_arcs = map(_scaler, arcs)
170 for i in range(len(scaled_arcs)):
171 dc.SetPen(pens[i] if type(pens).__name__ == 'list' else pens)
172 dc.SetBrush(wx.TRANSPARENT_BRUSH)
173 dc.DrawArc(*scaled_arcs[i])
174
175 if self.showall:
176 l = []
177 for i in self.layers:
178 dc.DrawLineList(l, self.fades[0])
179 _drawlines(self.lines[i], self.pens[i])
180 _drawarcs(self.arcs[i], self.arcpens[i])
181 return
182 if self.layerindex < len(self.layers) and self.layers[self.layerindex] in self.lines.keys():
183 for layer_i in xrange(max(0, self.layerindex - 6), self.layerindex):
184 _drawlines(self.lines[self.layers[layer_i]], self.fades[self.layerindex - layer_i - 1])
185 _drawarcs(self.arcs[self.layers[layer_i]], self.fades[self.layerindex - layer_i - 1])
186 _drawlines(self.lines[self.layers[self.layerindex]], self.pens[self.layers[self.layerindex]])
187 _drawarcs(self.arcs[self.layers[self.layerindex]], self.arcpens[self.layers[self.layerindex]])
188
189 _drawlines(self.hilight, self.hlpen)
190 _drawarcs(self.hilightarcs, self.hlpen)
191
192 dc.SelectObject(wx.NullBitmap)
193
195 dc = wx.PaintDC(self)
196 if(self.dirty):
197 self.repaint()
198 self.dirty = 0
199 sz = self.GetClientSize()
200 dc.DrawBitmap(self.blitmap, 0, 0)
201 del dc
202
203 - def addgcode(self, gcode="M105", hilight=0):
204 gcode = gcode.split("*")[0]
205 gcode = gcode.split(";")[0]
206 gcode = gcode.lower().strip().split()
207 if len(gcode) == 0:
208 return
209
210 def _readgcode():
211 target = self.lastpos[:]
212 if hilight:
213 target = self.hilightpos[:]
214 for i in gcode:
215 if i[0] == "x":
216 target[0] = float(i[1:])
217 elif i[0] == "y":
218 target[1] = float(i[1:])
219 elif i[0] == "z":
220 target[2] = float(i[1:])
221 elif i[0] == "e":
222 target[3] = float(i[1:])
223 elif i[0] == "f":
224 target[4] = float(i[1:])
225 elif i[0] == "i":
226 target[5] = float(i[1:])
227 elif i[0] == "j":
228 target[6] = float(i[1:])
229 if not hilight:
230 if not target[2] in self.lines.keys():
231 self.lines[target[2]] = []
232 self.pens[target[2]] = []
233 self.arcs[target[2]] = []
234 self.arcpens[target[2]] = []
235 self.layers += [target[2]]
236 return target
237
238 def _y(y):
239 return self.bedsize[1] - y
240
241 start_pos = self.hilightpos[:] if hilight else self.lastpos[:]
242
243 if gcode[0] == "g1":
244 target = _readgcode()
245 line = [ start_pos[0], _y(start_pos[1]), target[0], _y(target[1]) ]
246 if not hilight:
247 self.lines[ target[2] ] += [line]
248 self.pens[ target[2] ] += [self.mainpen if target[3] != self.lastpos[3] else self.travelpen]
249 self.lastpos = target
250 else:
251 self.hilight += [line]
252 self.hilightpos = target
253 self.dirty = 1
254
255 if gcode[0] in [ "g2", "g3" ]:
256 target = _readgcode()
257 arc = []
258 arc += [ start_pos[0], _y(start_pos[1]) ]
259 arc += [ target[0], _y(target[1]) ]
260 arc += [ start_pos[0] + target[5], _y(start_pos[1] + target[6]) ]
261 if gcode[0] == "g2":
262 arc[0], arc[1], arc[2], arc[3] = arc[2], arc[3], arc[0], arc[1]
263
264 if not hilight:
265 self.arcs[ target[2] ] += [arc]
266 self.arcpens[ target[2] ] += [self.arcpen]
267 self.lastpos = target
268 else:
269 self.hilightarcs += [arc]
270 self.hilightpos = target
271 self.dirty = 1
272
273 -def main(argv=None):
274 if argv is None:
275 argv = sys.argv[1:]
276 app = wx.App(False)
277 main = window(open(argv[0]))
278 main.Show()
279 app.MainLoop()
280
281 if __name__ == '__main__':
282 main()
283