Wed, 20 Jan 2021 11:37:03 +0100
reimplemented lasercutter changes
15 | 1 | # This file is part of the Printrun suite. |
2 | # | |
3 | # Printrun is free software: you can redistribute it and/or modify | |
4 | # it under the terms of the GNU General Public License as published by | |
5 | # the Free Software Foundation, either version 3 of the License, or | |
6 | # (at your option) any later version. | |
7 | # | |
8 | # Printrun is distributed in the hope that it will be useful, | |
9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | # GNU General Public License for more details. | |
12 | # | |
13 | # You should have received a copy of the GNU General Public License | |
14 | # along with Printrun. If not, see <http://www.gnu.org/licenses/>. | |
15 | ||
46 | 16 | from queue import Queue |
15 | 17 | from collections import deque |
18 | import numpy | |
19 | import wx | |
20 | import time | |
21 | from . import gcoder | |
22 | from .injectgcode import injector, injector_edit | |
23 | ||
24 | from .utils import imagefile, install_locale, get_home_pos | |
25 | install_locale('pronterface') | |
26 | ||
27 | class GvizBaseFrame(wx.Frame): | |
28 | ||
29 | def create_base_ui(self): | |
30 | self.CreateStatusBar(1) | |
31 | self.SetStatusText(_("Layer number and Z position show here when you scroll")) | |
32 | ||
33 | hpanel = wx.Panel(self, -1) | |
34 | hbox = wx.BoxSizer(wx.HORIZONTAL) | |
35 | ||
36 | panel = wx.Panel(hpanel, -1) | |
37 | vbox = wx.BoxSizer(wx.VERTICAL) | |
38 | ||
39 | vbox = wx.BoxSizer(wx.VERTICAL) | |
40 | self.toolbar = wx.ToolBar(panel, -1, style = wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_HORZ_TEXT) | |
46 | 41 | self.toolbar.AddTool(1, '', wx.Image(imagefile('zoom_in.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Zoom In [+]"),) |
42 | self.toolbar.AddTool(2, '', wx.Image(imagefile('zoom_out.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Zoom Out [-]")) | |
15 | 43 | self.toolbar.AddSeparator() |
46 | 44 | self.toolbar.AddTool(3, '', wx.Image(imagefile('arrow_up.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Move Up a Layer [U]")) |
45 | self.toolbar.AddTool(4, '', wx.Image(imagefile('arrow_down.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), _("Move Down a Layer [D]")) | |
46 | self.toolbar.AddTool(5, " " + _("Reset view"), wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Reset view")) | |
15 | 47 | self.toolbar.AddSeparator() |
46 | 48 | self.toolbar.AddTool(6, '', wx.Image(imagefile('inject.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), wx.NullBitmap, shortHelp = _("Inject G-Code"), longHelp = _("Insert code at the beginning of this layer")) |
49 | self.toolbar.AddTool(7, '', wx.Image(imagefile('edit.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), wx.NullBitmap, shortHelp = _("Edit layer"), longHelp = _("Edit the G-Code of this layer")) | |
15 | 50 | |
51 | vbox.Add(self.toolbar, 0, border = 5) | |
52 | ||
53 | panel.SetSizer(vbox) | |
54 | ||
55 | hbox.Add(panel, 1, flag = wx.EXPAND) | |
56 | self.layerslider = wx.Slider(hpanel, style = wx.SL_VERTICAL | wx.SL_AUTOTICKS | wx.SL_LEFT | wx.SL_INVERSE) | |
57 | self.layerslider.Bind(wx.EVT_SCROLL, self.process_slider) | |
58 | hbox.Add(self.layerslider, 0, border = 5, flag = wx.LEFT | wx.EXPAND) | |
59 | hpanel.SetSizer(hbox) | |
60 | ||
61 | return panel, vbox | |
62 | ||
63 | def setlayercb(self, layer): | |
64 | self.layerslider.SetValue(layer) | |
65 | ||
66 | def process_slider(self, event): | |
67 | raise NotImplementedError | |
68 | ||
69 | ID_ABOUT = 101 | |
70 | ID_EXIT = 110 | |
71 | class GvizWindow(GvizBaseFrame): | |
72 | def __init__(self, f = None, size = (600, 600), build_dimensions = [200, 200, 100, 0, 0, 0], grid = (10, 50), extrusion_width = 0.5, bgcolor = "#000000"): | |
73 | super(GvizWindow, self).__init__(None, title = _("Gcode view, shift to move view, mousewheel to set layer"), size = size) | |
74 | ||
75 | panel, vbox = self.create_base_ui() | |
76 | ||
77 | self.p = Gviz(panel, size = size, build_dimensions = build_dimensions, grid = grid, extrusion_width = extrusion_width, bgcolor = bgcolor, realparent = self) | |
78 | ||
79 | self.toolbar.Realize() | |
80 | vbox.Add(self.p, 1, wx.EXPAND) | |
81 | ||
82 | self.SetMinSize(self.ClientToWindowSize(vbox.GetMinSize())) | |
83 | self.Bind(wx.EVT_TOOL, lambda x: self.p.zoom(-1, -1, 1.2), id = 1) | |
84 | self.Bind(wx.EVT_TOOL, lambda x: self.p.zoom(-1, -1, 1 / 1.2), id = 2) | |
85 | self.Bind(wx.EVT_TOOL, lambda x: self.p.layerup(), id = 3) | |
86 | self.Bind(wx.EVT_TOOL, lambda x: self.p.layerdown(), id = 4) | |
87 | self.Bind(wx.EVT_TOOL, self.resetview, id = 5) | |
88 | self.Bind(wx.EVT_TOOL, lambda x: self.p.inject(), id = 6) | |
89 | self.Bind(wx.EVT_TOOL, lambda x: self.p.editlayer(), id = 7) | |
90 | ||
91 | self.initpos = None | |
92 | self.p.Bind(wx.EVT_KEY_DOWN, self.key) | |
93 | self.Bind(wx.EVT_KEY_DOWN, self.key) | |
94 | self.p.Bind(wx.EVT_MOUSEWHEEL, self.zoom) | |
95 | self.Bind(wx.EVT_MOUSEWHEEL, self.zoom) | |
96 | self.p.Bind(wx.EVT_MOUSE_EVENTS, self.mouse) | |
97 | self.Bind(wx.EVT_MOUSE_EVENTS, self.mouse) | |
98 | ||
99 | if f: | |
100 | gcode = gcoder.GCode(f, get_home_pos(self.p.build_dimensions)) | |
101 | self.p.addfile(gcode) | |
102 | ||
103 | def set_current_gline(self, gline): | |
104 | return | |
105 | ||
106 | def process_slider(self, event): | |
107 | self.p.layerindex = self.layerslider.GetValue() | |
108 | z = self.p.get_currentz() | |
109 | wx.CallAfter(self.SetStatusText, _("Layer %d - Z = %.03f mm") % (self.p.layerindex + 1, z), 0) | |
110 | self.p.dirty = True | |
111 | wx.CallAfter(self.p.Refresh) | |
112 | ||
113 | def resetview(self, event): | |
114 | self.p.translate = [0.0, 0.0] | |
115 | self.p.scale = self.p.basescale | |
116 | self.p.zoom(0, 0, 1.0) | |
117 | ||
118 | def mouse(self, event): | |
119 | if event.ButtonUp(wx.MOUSE_BTN_LEFT) or event.ButtonUp(wx.MOUSE_BTN_RIGHT): | |
120 | if self.initpos is not None: | |
121 | self.initpos = None | |
122 | elif event.Dragging(): | |
46 | 123 | e = event.GetPosition() |
15 | 124 | if self.initpos is None: |
125 | self.initpos = e | |
126 | self.basetrans = self.p.translate | |
127 | self.p.translate = [self.basetrans[0] + (e[0] - self.initpos[0]), | |
128 | self.basetrans[1] + (e[1] - self.initpos[1])] | |
129 | self.p.dirty = True | |
130 | wx.CallAfter(self.p.Refresh) | |
131 | else: | |
132 | event.Skip() | |
133 | ||
134 | def key(self, event): | |
135 | # Keycode definitions | |
136 | kup = [85, 315] # Up keys | |
137 | kdo = [68, 317] # Down Keys | |
138 | kzi = [388, 316, 61] # Zoom In Keys | |
139 | kzo = [390, 314, 45] # Zoom Out Keys | |
140 | x = event.GetKeyCode() | |
141 | cx, cy = self.p.translate | |
142 | if x in kup: | |
143 | self.p.layerup() | |
144 | if x in kdo: | |
145 | self.p.layerdown() | |
146 | if x in kzi: | |
147 | self.p.zoom(cx, cy, 1.2) | |
148 | if x in kzo: | |
149 | self.p.zoom(cx, cy, 1 / 1.2) | |
150 | ||
151 | def zoom(self, event): | |
152 | z = event.GetWheelRotation() | |
153 | if event.ShiftDown(): | |
154 | if z > 0: self.p.layerdown() | |
155 | elif z < 0: self.p.layerup() | |
156 | else: | |
157 | if z > 0: self.p.zoom(event.GetX(), event.GetY(), 1.2) | |
158 | elif z < 0: self.p.zoom(event.GetX(), event.GetY(), 1 / 1.2) | |
159 | ||
46 | 160 | from printrun.gui.viz import BaseViz |
161 | class Gviz(wx.Panel, BaseViz): | |
15 | 162 | |
163 | # Mark canvas as dirty when setting showall | |
164 | _showall = 0 | |
165 | ||
166 | def _get_showall(self): | |
167 | return self._showall | |
168 | ||
169 | def _set_showall(self, showall): | |
170 | if showall != self._showall: | |
171 | self.dirty = True | |
172 | self._showall = showall | |
173 | showall = property(_get_showall, _set_showall) | |
174 | ||
175 | def __init__(self, parent, size = (200, 200), build_dimensions = [200, 200, 100, 0, 0, 0], grid = (10, 50), extrusion_width = 0.5, bgcolor = "#000000", realparent = None): | |
176 | wx.Panel.__init__(self, parent, -1) | |
177 | self.widget = self | |
178 | size = [max(1.0, x) for x in size] | |
179 | ratio = size[0] / size[1] | |
180 | self.SetMinSize((150, 150 / ratio)) | |
181 | self.parent = realparent if realparent else parent | |
182 | self.size = size | |
183 | self.build_dimensions = build_dimensions | |
184 | self.grid = grid | |
185 | self.Bind(wx.EVT_PAINT, self.paint) | |
186 | self.Bind(wx.EVT_SIZE, self.resize) | |
187 | self.hilight = deque() | |
188 | self.hilightarcs = deque() | |
189 | self.hilightqueue = Queue(0) | |
190 | self.hilightarcsqueue = Queue(0) | |
191 | self.clear() | |
192 | self.filament_width = extrusion_width # set it to 0 to disable scaling lines with zoom | |
193 | self.update_basescale() | |
194 | self.scale = self.basescale | |
195 | penwidth = max(1.0, self.filament_width * ((self.scale[0] + self.scale[1]) / 2.0)) | |
196 | self.translate = [0.0, 0.0] | |
197 | self.mainpen = wx.Pen(wx.Colour(0, 0, 0), penwidth) | |
198 | self.arcpen = wx.Pen(wx.Colour(255, 0, 0), penwidth) | |
199 | self.travelpen = wx.Pen(wx.Colour(10, 80, 80), penwidth) | |
200 | self.hlpen = wx.Pen(wx.Colour(200, 50, 50), penwidth) | |
46 | 201 | self.fades = [wx.Pen(wx.Colour(int(250 - 0.6 ** i * 100), int(250 - 0.6 ** i * 100), int(200 - 0.4 ** i * 50)), penwidth) for i in range(6)] |
202 | self.penslist = [self.mainpen, self.arcpen, self.travelpen, self.hlpen] + self.fades | |
15 | 203 | self.bgcolor = wx.Colour() |
46 | 204 | self.bgcolor.Set(bgcolor) |
205 | self.blitmap = wx.Bitmap(self.GetClientSize()[0], self.GetClientSize()[1], -1) | |
15 | 206 | self.paint_overlay = None |
207 | ||
208 | def inject(self): | |
46 | 209 | layer = self.layers[self.layerindex] |
15 | 210 | injector(self.gcode, self.layerindex, layer) |
211 | ||
212 | def editlayer(self): | |
46 | 213 | layer = self.layers[self.layerindex] |
15 | 214 | injector_edit(self.gcode, self.layerindex, layer) |
215 | ||
216 | def clearhilights(self): | |
217 | self.hilight.clear() | |
218 | self.hilightarcs.clear() | |
219 | while not self.hilightqueue.empty(): | |
220 | self.hilightqueue.get_nowait() | |
221 | while not self.hilightarcsqueue.empty(): | |
222 | self.hilightarcsqueue.get_nowait() | |
223 | ||
224 | def clear(self): | |
225 | self.gcode = None | |
226 | self.lastpos = [0, 0, 0, 0, 0, 0, 0] | |
227 | self.hilightpos = self.lastpos[:] | |
228 | self.lines = {} | |
229 | self.pens = {} | |
230 | self.arcs = {} | |
231 | self.arcpens = {} | |
232 | self.layers = {} | |
233 | self.layersz = [] | |
234 | self.clearhilights() | |
235 | self.layerindex = 0 | |
236 | self.showall = 0 | |
237 | self.dirty = True | |
238 | self.partial = False | |
239 | self.painted_layers = set() | |
240 | wx.CallAfter(self.Refresh) | |
241 | ||
242 | def get_currentz(self): | |
243 | z = self.layersz[self.layerindex] | |
244 | z = 0. if z is None else z | |
245 | return z | |
246 | ||
247 | def layerup(self): | |
248 | if self.layerindex + 1 < len(self.layers): | |
249 | self.layerindex += 1 | |
250 | z = self.get_currentz() | |
251 | wx.CallAfter(self.parent.SetStatusText, _("Layer %d - Going Up - Z = %.03f mm") % (self.layerindex + 1, z), 0) | |
252 | self.dirty = True | |
253 | self.parent.setlayercb(self.layerindex) | |
254 | wx.CallAfter(self.Refresh) | |
255 | ||
256 | def layerdown(self): | |
257 | if self.layerindex > 0: | |
258 | self.layerindex -= 1 | |
259 | z = self.get_currentz() | |
260 | wx.CallAfter(self.parent.SetStatusText, _("Layer %d - Going Down - Z = %.03f mm") % (self.layerindex + 1, z), 0) | |
261 | self.dirty = True | |
262 | self.parent.setlayercb(self.layerindex) | |
263 | wx.CallAfter(self.Refresh) | |
264 | ||
265 | def setlayer(self, layer): | |
266 | if layer in self.layers: | |
267 | self.clearhilights() | |
268 | self.layerindex = self.layers[layer] | |
269 | self.dirty = True | |
270 | self.showall = 0 | |
271 | wx.CallAfter(self.Refresh) | |
272 | ||
273 | def update_basescale(self): | |
274 | self.basescale = 2 * [min(float(self.size[0] - 1) / self.build_dimensions[0], | |
275 | float(self.size[1] - 1) / self.build_dimensions[1])] | |
276 | ||
277 | def resize(self, event): | |
278 | old_basescale = self.basescale | |
46 | 279 | width, height = self.GetClientSize() |
15 | 280 | if width < 1 or height < 1: |
281 | return | |
282 | self.size = (width, height) | |
283 | self.update_basescale() | |
284 | zoomratio = float(self.basescale[0]) / old_basescale[0] | |
285 | wx.CallLater(200, self.zoom, 0, 0, zoomratio) | |
286 | ||
287 | def zoom(self, x, y, factor): | |
288 | if x == -1 and y == -1: | |
289 | side = min(self.size) | |
290 | x = y = side / 2 | |
291 | self.scale = [s * factor for s in self.scale] | |
292 | ||
293 | self.translate = [x - (x - self.translate[0]) * factor, | |
294 | y - (y - self.translate[1]) * factor] | |
295 | penwidth = max(1.0, self.filament_width * ((self.scale[0] + self.scale[1]) / 2.0)) | |
296 | for pen in self.penslist: | |
297 | pen.SetWidth(penwidth) | |
298 | self.dirty = True | |
299 | wx.CallAfter(self.Refresh) | |
300 | ||
301 | def _line_scaler(self, x): | |
302 | return (self.scale[0] * x[0], | |
303 | self.scale[1] * x[1], | |
304 | self.scale[0] * x[2], | |
305 | self.scale[1] * x[3],) | |
306 | ||
307 | def _arc_scaler(self, x): | |
308 | return (self.scale[0] * x[0], | |
309 | self.scale[1] * x[1], | |
310 | self.scale[0] * x[2], | |
311 | self.scale[1] * x[3], | |
312 | self.scale[0] * x[4], | |
313 | self.scale[1] * x[5],) | |
314 | ||
315 | def _drawlines(self, dc, lines, pens): | |
46 | 316 | scaled_lines = [self._line_scaler(l) for l in lines] |
15 | 317 | dc.DrawLineList(scaled_lines, pens) |
318 | ||
319 | def _drawarcs(self, dc, arcs, pens): | |
46 | 320 | scaled_arcs = [self._arc_scaler(a) for a in arcs] |
15 | 321 | dc.SetBrush(wx.TRANSPARENT_BRUSH) |
322 | for i in range(len(scaled_arcs)): | |
46 | 323 | dc.SetPen(pens[i] if isinstance(pens, numpy.ndarray) else pens) |
15 | 324 | dc.DrawArc(*scaled_arcs[i]) |
325 | ||
326 | def repaint_everything(self): | |
327 | width = self.scale[0] * self.build_dimensions[0] | |
328 | height = self.scale[1] * self.build_dimensions[1] | |
46 | 329 | self.blitmap = wx.Bitmap(width + 1, height + 1, -1) |
15 | 330 | dc = wx.MemoryDC() |
331 | dc.SelectObject(self.blitmap) | |
332 | dc.SetBackground(wx.Brush((250, 250, 200))) | |
333 | dc.Clear() | |
334 | dc.SetPen(wx.Pen(wx.Colour(180, 180, 150))) | |
335 | for grid_unit in self.grid: | |
336 | if grid_unit > 0: | |
46 | 337 | for x in range(int(self.build_dimensions[0] / grid_unit) + 1): |
15 | 338 | draw_x = self.scale[0] * x * grid_unit |
339 | dc.DrawLine(draw_x, 0, draw_x, height) | |
46 | 340 | for y in range(int(self.build_dimensions[1] / grid_unit) + 1): |
15 | 341 | draw_y = self.scale[1] * (self.build_dimensions[1] - y * grid_unit) |
342 | dc.DrawLine(0, draw_y, width, draw_y) | |
343 | dc.SetPen(wx.Pen(wx.Colour(0, 0, 0))) | |
344 | ||
345 | if not self.showall: | |
346 | # Draw layer gauge | |
347 | dc.SetBrush(wx.Brush((43, 144, 255))) | |
348 | dc.DrawRectangle(width - 15, 0, 15, height) | |
349 | dc.SetBrush(wx.Brush((0, 255, 0))) | |
350 | if self.layers: | |
351 | dc.DrawRectangle(width - 14, (1.0 - (1.0 * (self.layerindex + 1)) / len(self.layers)) * height, 13, height - 1) | |
352 | ||
353 | if self.showall: | |
354 | for i in range(len(self.layersz)): | |
355 | self.painted_layers.add(i) | |
356 | self._drawlines(dc, self.lines[i], self.pens[i]) | |
357 | self._drawarcs(dc, self.arcs[i], self.arcpens[i]) | |
358 | dc.SelectObject(wx.NullBitmap) | |
359 | return | |
360 | ||
361 | if self.layerindex < len(self.layers) and self.layerindex in self.lines: | |
362 | for layer_i in range(max(0, self.layerindex - 6), self.layerindex): | |
363 | self._drawlines(dc, self.lines[layer_i], self.fades[self.layerindex - layer_i - 1]) | |
364 | self._drawarcs(dc, self.arcs[layer_i], self.fades[self.layerindex - layer_i - 1]) | |
365 | self._drawlines(dc, self.lines[self.layerindex], self.pens[self.layerindex]) | |
366 | self._drawarcs(dc, self.arcs[self.layerindex], self.arcpens[self.layerindex]) | |
367 | ||
368 | self._drawlines(dc, self.hilight, self.hlpen) | |
369 | self._drawarcs(dc, self.hilightarcs, self.hlpen) | |
370 | ||
371 | self.paint_hilights(dc) | |
372 | ||
373 | dc.SelectObject(wx.NullBitmap) | |
374 | ||
375 | def repaint_partial(self): | |
376 | if self.showall: | |
377 | dc = wx.MemoryDC() | |
378 | dc.SelectObject(self.blitmap) | |
379 | for i in set(range(len(self.layersz))).difference(self.painted_layers): | |
380 | self.painted_layers.add(i) | |
381 | self._drawlines(dc, self.lines[i], self.pens[i]) | |
382 | self._drawarcs(dc, self.arcs[i], self.arcpens[i]) | |
383 | dc.SelectObject(wx.NullBitmap) | |
384 | ||
385 | def paint_hilights(self, dc = None): | |
386 | if self.hilightqueue.empty() and self.hilightarcsqueue.empty(): | |
387 | return | |
388 | hl = [] | |
389 | if not dc: | |
390 | dc = wx.MemoryDC() | |
391 | dc.SelectObject(self.blitmap) | |
392 | while not self.hilightqueue.empty(): | |
393 | hl.append(self.hilightqueue.get_nowait()) | |
394 | self._drawlines(dc, hl, self.hlpen) | |
395 | hlarcs = [] | |
396 | while not self.hilightarcsqueue.empty(): | |
397 | hlarcs.append(self.hilightarcsqueue.get_nowait()) | |
398 | self._drawarcs(dc, hlarcs, self.hlpen) | |
399 | dc.SelectObject(wx.NullBitmap) | |
400 | ||
401 | def paint(self, event): | |
402 | if self.dirty: | |
403 | self.dirty = False | |
404 | self.partial = False | |
405 | self.repaint_everything() | |
406 | elif self.partial: | |
407 | self.partial = False | |
408 | self.repaint_partial() | |
409 | self.paint_hilights() | |
410 | dc = wx.PaintDC(self) | |
411 | dc.SetBackground(wx.Brush(self.bgcolor)) | |
412 | dc.Clear() | |
413 | dc.DrawBitmap(self.blitmap, self.translate[0], self.translate[1]) | |
414 | if self.paint_overlay: | |
415 | self.paint_overlay(dc) | |
416 | ||
417 | def addfile_perlayer(self, gcode, showall = False): | |
418 | self.clear() | |
419 | self.gcode = gcode | |
420 | self.showall = showall | |
421 | generator = self.add_parsed_gcodes(gcode) | |
46 | 422 | generator_output = next(generator) |
15 | 423 | while generator_output is not None: |
424 | yield generator_output | |
46 | 425 | generator_output = next(generator) |
15 | 426 | max_layers = len(self.layers) |
427 | if hasattr(self.parent, "layerslider"): | |
428 | self.parent.layerslider.SetRange(0, max_layers - 1) | |
429 | self.parent.layerslider.SetValue(0) | |
430 | yield None | |
431 | ||
432 | def addfile(self, gcode = None, showall = False): | |
433 | generator = self.addfile_perlayer(gcode, showall) | |
46 | 434 | while next(generator) is not None: |
15 | 435 | continue |
436 | ||
437 | def _get_movement(self, start_pos, gline): | |
438 | """Takes a start position and a gcode, and returns a 3-uple containing | |
439 | (final position, line, arc), with line and arc being None if not | |
440 | used""" | |
441 | target = start_pos[:] | |
442 | target[5] = 0.0 | |
443 | target[6] = 0.0 | |
444 | if gline.current_x is not None: target[0] = gline.current_x | |
445 | if gline.current_y is not None: target[1] = gline.current_y | |
446 | if gline.current_z is not None: target[2] = gline.current_z | |
447 | if gline.e is not None: | |
448 | if gline.relative_e: | |
449 | target[3] += gline.e | |
450 | else: | |
451 | target[3] = gline.e | |
452 | if gline.f is not None: target[4] = gline.f | |
453 | if gline.i is not None: target[5] = gline.i | |
454 | if gline.j is not None: target[6] = gline.j | |
455 | ||
456 | if gline.command in ["G0", "G1"]: | |
457 | line = [self._x(start_pos[0]), | |
458 | self._y(start_pos[1]), | |
459 | self._x(target[0]), | |
460 | self._y(target[1])] | |
461 | return target, line, None | |
462 | elif gline.command in ["G2", "G3"]: | |
463 | # startpos, endpos, arc center | |
464 | arc = [self._x(start_pos[0]), self._y(start_pos[1]), | |
465 | self._x(target[0]), self._y(target[1]), | |
466 | self._x(start_pos[0] + target[5]), self._y(start_pos[1] + target[6])] | |
467 | if gline.command == "G2": # clockwise, reverse endpoints | |
468 | arc[0], arc[1], arc[2], arc[3] = arc[2], arc[3], arc[0], arc[1] | |
469 | return target, None, arc | |
470 | ||
471 | def _y(self, y): | |
472 | return self.build_dimensions[1] - (y - self.build_dimensions[4]) | |
473 | ||
474 | def _x(self, x): | |
475 | return x - self.build_dimensions[3] | |
476 | ||
477 | def add_parsed_gcodes(self, gcode): | |
478 | start_time = time.time() | |
479 | ||
480 | layer_idx = 0 | |
481 | while layer_idx < len(gcode.all_layers): | |
482 | layer = gcode.all_layers[layer_idx] | |
483 | has_move = False | |
484 | for gline in layer: | |
485 | if gline.is_move: | |
486 | has_move = True | |
487 | break | |
488 | if not has_move: | |
489 | yield layer_idx | |
490 | layer_idx += 1 | |
491 | continue | |
492 | viz_layer = len(self.layers) | |
493 | self.lines[viz_layer] = [] | |
494 | self.pens[viz_layer] = [] | |
495 | self.arcs[viz_layer] = [] | |
496 | self.arcpens[viz_layer] = [] | |
497 | for gline in layer: | |
498 | if not gline.is_move: | |
499 | continue | |
500 | ||
501 | target, line, arc = self._get_movement(self.lastpos[:], gline) | |
502 | ||
503 | if line is not None: | |
504 | self.lines[viz_layer].append(line) | |
46 | 505 | self.pens[viz_layer].append(self.mainpen if target[3] != self.lastpos[3] or gline.extruding else self.travelpen) |
15 | 506 | elif arc is not None: |
507 | self.arcs[viz_layer].append(arc) | |
508 | self.arcpens[viz_layer].append(self.arcpen) | |
509 | ||
510 | self.lastpos = target | |
511 | # Transform into a numpy array for memory efficiency | |
512 | self.lines[viz_layer] = numpy.asarray(self.lines[viz_layer], dtype = numpy.float32) | |
513 | self.pens[viz_layer] = numpy.asarray(self.pens[viz_layer]) | |
514 | self.arcs[viz_layer] = numpy.asarray(self.arcs[viz_layer], dtype = numpy.float32) | |
515 | self.arcpens[viz_layer] = numpy.asarray(self.arcpens[viz_layer]) | |
516 | # Only add layer to self.layers now to prevent the display of an | |
517 | # unfinished layer | |
518 | self.layers[layer_idx] = viz_layer | |
519 | self.layersz.append(layer.z) | |
520 | ||
521 | # Refresh display if more than 0.2s have passed | |
522 | if time.time() - start_time > 0.2: | |
523 | start_time = time.time() | |
524 | self.partial = True | |
525 | wx.CallAfter(self.Refresh) | |
526 | ||
527 | yield layer_idx | |
528 | layer_idx += 1 | |
529 | ||
530 | self.dirty = True | |
531 | wx.CallAfter(self.Refresh) | |
532 | yield None | |
533 | ||
534 | def addgcodehighlight(self, gline): | |
535 | if gline.command not in ["G0", "G1", "G2", "G3"]: | |
536 | return | |
537 | ||
538 | target, line, arc = self._get_movement(self.hilightpos[:], gline) | |
539 | ||
540 | if line is not None: | |
541 | self.hilight.append(line) | |
542 | self.hilightqueue.put_nowait(line) | |
543 | elif arc is not None: | |
544 | self.hilightarcs.append(arc) | |
545 | self.hilightarcsqueue.put_nowait(arc) | |
546 | ||
547 | self.hilightpos = target | |
548 | wx.CallAfter(self.Refresh) | |
549 | ||
550 | if __name__ == '__main__': | |
551 | import sys | |
552 | app = wx.App(False) | |
553 | main = GvizWindow(open(sys.argv[1], "rU")) | |
554 | main.Show() | |
555 | app.MainLoop() |