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 | ||
16 | import wx | |
17 | from math import log10, floor, ceil | |
46 | 18 | from bisect import bisect_left |
15 | 19 | |
20 | from printrun.utils import install_locale | |
21 | install_locale('pronterface') | |
22 | ||
23 | from .bufferedcanvas import BufferedCanvas | |
24 | ||
25 | class GraphWindow(wx.Frame): | |
26 | def __init__(self, root, parent_graph = None, size = (600, 600)): | |
46 | 27 | super().__init__(None, title = _("Temperature graph"), |
15 | 28 | size = size) |
46 | 29 | self.parentg = parent_graph |
30 | panel = wx.Panel(self) | |
15 | 31 | vbox = wx.BoxSizer(wx.VERTICAL) |
32 | self.graph = Graph(panel, wx.ID_ANY, root, parent_graph = parent_graph) | |
33 | vbox.Add(self.graph, 1, wx.EXPAND) | |
34 | panel.SetSizer(vbox) | |
35 | ||
46 | 36 | def Destroy(self): |
37 | self.graph.StopPlotting() | |
38 | if self.parentg is not None: | |
39 | self.parentg.window=None | |
40 | return super().Destroy() | |
41 | ||
42 | def __del__(self): | |
43 | if self.parentg is not None: | |
44 | self.parentg.window=None | |
45 | self.graph.StopPlotting() | |
46 | ||
15 | 47 | class Graph(BufferedCanvas): |
48 | '''A class to show a Graph with Pronterface.''' | |
49 | ||
50 | def __init__(self, parent, id, root, pos = wx.DefaultPosition, | |
51 | size = wx.Size(150, 80), style = 0, parent_graph = None): | |
52 | # Forcing a no full repaint to stop flickering | |
53 | style = style | wx.NO_FULL_REPAINT_ON_RESIZE | |
46 | 54 | super().__init__(parent, id, pos, size, style) |
15 | 55 | self.root = root |
56 | ||
57 | if parent_graph is not None: | |
58 | self.extruder0temps = parent_graph.extruder0temps | |
59 | self.extruder0targettemps = parent_graph.extruder0targettemps | |
60 | self.extruder1temps = parent_graph.extruder1temps | |
61 | self.extruder1targettemps = parent_graph.extruder1targettemps | |
62 | self.bedtemps = parent_graph.bedtemps | |
63 | self.bedtargettemps = parent_graph.bedtargettemps | |
46 | 64 | self.fanpowers=parent_graph.fanpowers |
15 | 65 | else: |
66 | self.extruder0temps = [0] | |
67 | self.extruder0targettemps = [0] | |
68 | self.extruder1temps = [0] | |
69 | self.extruder1targettemps = [0] | |
70 | self.bedtemps = [0] | |
71 | self.bedtargettemps = [0] | |
46 | 72 | self.fanpowers= [0] |
15 | 73 | |
74 | self.timer = wx.Timer(self) | |
75 | self.Bind(wx.EVT_TIMER, self.updateTemperatures, self.timer) | |
46 | 76 | self.Bind(wx.EVT_WINDOW_DESTROY, self.processDestroy) |
15 | 77 | |
78 | self.minyvalue = 0 | |
79 | self.maxyvalue = 260 | |
80 | self.rescaley = True # should the Y axis be rescaled dynamically? | |
81 | if self.rescaley: | |
82 | self._ybounds = Graph._YBounds(self) | |
83 | ||
84 | # If rescaley is set then ybars gives merely an estimate | |
85 | # Note that "bars" actually indicate the number of internal+external gridlines. | |
86 | self.ybars = 5 | |
87 | self.xbars = 7 # One bar per 10 second | |
88 | self.xsteps = 60 # Covering 1 minute in the graph | |
89 | ||
90 | self.window = None | |
46 | 91 | self.reserved = [] |
92 | ||
93 | def processDestroy(self, event): | |
94 | # print('processDestroy') | |
95 | self.StopPlotting() | |
96 | self.Unbind(wx.EVT_TIMER) | |
97 | event.Skip() | |
15 | 98 | |
99 | def show_graph_window(self, event = None): | |
46 | 100 | if self.window is None or not self.window: |
15 | 101 | self.window = GraphWindow(self.root, self) |
102 | self.window.Show() | |
103 | if self.timer.IsRunning(): | |
104 | self.window.graph.StartPlotting(self.timer.Interval) | |
105 | else: | |
106 | self.window.Raise() | |
107 | ||
108 | def __del__(self): | |
109 | if self.window: self.window.Close() | |
110 | ||
111 | def updateTemperatures(self, event): | |
46 | 112 | # print('updateTemperatures') |
15 | 113 | self.AddBedTemperature(self.bedtemps[-1]) |
114 | self.AddBedTargetTemperature(self.bedtargettemps[-1]) | |
115 | self.AddExtruder0Temperature(self.extruder0temps[-1]) | |
116 | self.AddExtruder0TargetTemperature(self.extruder0targettemps[-1]) | |
117 | self.AddExtruder1Temperature(self.extruder1temps[-1]) | |
118 | self.AddExtruder1TargetTemperature(self.extruder1targettemps[-1]) | |
46 | 119 | self.AddFanPower(self.fanpowers[-1]) |
15 | 120 | if self.rescaley: |
121 | self._ybounds.update() | |
122 | self.Refresh() | |
123 | ||
124 | def drawgrid(self, dc, gc): | |
125 | # cold, medium, hot = wx.Colour(0, 167, 223),\ | |
126 | # wx.Colour(239, 233, 119),\ | |
127 | # wx.Colour(210, 50.100) | |
128 | # col1 = wx.Colour(255, 0, 0, 255) | |
129 | # col2 = wx.Colour(255, 255, 255, 128) | |
130 | ||
131 | # b = gc.CreateLinearGradientBrush(0, 0, w, h, col1, col2) | |
132 | ||
133 | gc.SetPen(wx.Pen(wx.Colour(255, 0, 0, 0), 1)) | |
134 | ||
135 | # gc.SetBrush(wx.Brush(wx.Colour(245, 245, 255, 52))) | |
136 | ||
137 | # gc.SetBrush(gc.CreateBrush(wx.Brush(wx.Colour(0, 0, 0, 255)))) | |
138 | gc.SetPen(wx.Pen(wx.Colour(255, 0, 0, 255), 1)) | |
139 | ||
140 | # gc.DrawLines(wx.Point(0, 0), wx.Point(50, 10)) | |
141 | ||
142 | font = wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.BOLD) | |
143 | gc.SetFont(font, wx.Colour(23, 44, 44)) | |
144 | ||
145 | # draw vertical bars | |
146 | dc.SetPen(wx.Pen(wx.Colour(225, 225, 225), 1)) | |
46 | 147 | xscale = float(self.width - 1) / (self.xbars - 1) |
15 | 148 | for x in range(self.xbars + 1): |
46 | 149 | x = x * xscale |
150 | dc.DrawLine(x, 0, x, self.height) | |
15 | 151 | |
152 | # draw horizontal bars | |
153 | spacing = self._calculate_spacing() # spacing between bars, in degrees | |
154 | yspan = self.maxyvalue - self.minyvalue | |
155 | ybars = int(yspan / spacing) # Should be close to self.ybars | |
156 | firstbar = int(ceil(self.minyvalue / spacing)) # in degrees | |
157 | dc.SetPen(wx.Pen(wx.Colour(225, 225, 225), 1)) | |
158 | for y in range(firstbar, firstbar + ybars + 1): | |
159 | # y_pos = y*(float(self.height)/self.ybars) | |
160 | degrees = y * spacing | |
161 | y_pos = self._y_pos(degrees) | |
162 | dc.DrawLine(0, y_pos, self.width, y_pos) | |
46 | 163 | label = str(y * spacing) |
164 | label_y = y_pos - font.GetPointSize() / 2 | |
165 | self.layoutText(label, 1, label_y, gc) | |
166 | gc.DrawText(label, 1, label_y) | |
15 | 167 | |
46 | 168 | if not self.timer.IsRunning(): |
15 | 169 | font = wx.Font(14, wx.DEFAULT, wx.NORMAL, wx.BOLD) |
170 | gc.SetFont(font, wx.Colour(3, 4, 4)) | |
171 | gc.DrawText("Graph offline", | |
46 | 172 | self.width / 2 - font.GetPointSize() * 3, |
173 | self.height / 2 - font.GetPointSize() * 1) | |
15 | 174 | |
175 | # dc.DrawCircle(50, 50, 1) | |
176 | ||
177 | # gc.SetPen(wx.Pen(wx.Colour(255, 0, 0, 0), 1)) | |
178 | # gc.DrawLines([[20, 30], [10, 53]]) | |
179 | # dc.SetPen(wx.Pen(wx.Colour(255, 0, 0, 0), 1)) | |
180 | ||
181 | def _y_pos(self, temperature): | |
182 | """Converts a temperature, in degrees, to a pixel position""" | |
183 | # fraction of the screen from the bottom | |
184 | frac = (float(temperature - self.minyvalue) | |
185 | / (self.maxyvalue - self.minyvalue)) | |
186 | return int((1.0 - frac) * (self.height - 1)) | |
187 | ||
188 | def _calculate_spacing(self): | |
189 | # Allow grids of spacings 1,2.5,5,10,25,50,100,etc | |
190 | ||
191 | yspan = float(self.maxyvalue - self.minyvalue) | |
192 | log_yspan = log10(yspan / self.ybars) | |
193 | exponent = int(floor(log_yspan)) | |
194 | ||
195 | # calculate boundary points between allowed spacings | |
196 | log1_25 = log10(2) + log10(1) + log10(2.5) - log10(1 + 2.5) | |
197 | log25_5 = log10(2) + log10(2.5) + log10(5) - log10(2.5 + 5) | |
198 | log5_10 = log10(2) + log10(5) + log10(10) - log10(5 + 10) | |
199 | ||
200 | if log_yspan - exponent < log1_25: | |
201 | return 10 ** exponent | |
202 | elif log1_25 <= log_yspan - exponent < log25_5: | |
203 | return 25 * 10 ** (exponent - 1) | |
204 | elif log25_5 <= log_yspan - exponent < log5_10: | |
205 | return 5 * 10 ** exponent | |
206 | else: | |
207 | return 10 ** (exponent + 1) | |
208 | ||
209 | def drawtemperature(self, dc, gc, temperature_list, | |
210 | text, text_xoffset, r, g, b, a): | |
46 | 211 | color = self.timer.IsRunning() and (r, g, b, a) or [128] * 4 |
212 | dc.SetPen(wx.Pen(color, 1)) | |
15 | 213 | |
214 | x_add = float(self.width) / self.xsteps | |
215 | x_pos = 0.0 | |
216 | lastxvalue = 0.0 | |
217 | lastyvalue = temperature_list[-1] | |
218 | ||
46 | 219 | for temperature in temperature_list: |
15 | 220 | y_pos = self._y_pos(temperature) |
46 | 221 | if x_pos > 0: # One need 2 points to draw a line. |
15 | 222 | dc.DrawLine(lastxvalue, lastyvalue, x_pos, y_pos) |
223 | ||
224 | lastxvalue = x_pos | |
46 | 225 | x_pos += x_add |
15 | 226 | lastyvalue = y_pos |
227 | ||
46 | 228 | if text: |
15 | 229 | font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD) |
230 | # font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.NORMAL) | |
46 | 231 | gc.SetFont(font, color[:3]) |
15 | 232 | |
233 | text_size = len(text) * text_xoffset + 1 | |
46 | 234 | pos = self.layoutText(text, lastxvalue, lastyvalue, gc) |
235 | gc.DrawText(text, pos.x, pos.y) | |
236 | ||
237 | def layoutRect(self, rc): | |
238 | res = LtRect(rc) | |
239 | reserved = sorted((rs for rs in self.reserved | |
240 | if not (rc.bottom < rs.top or rc.top > rs.bottom)), | |
241 | key=wx.Rect.GetLeft) | |
242 | self.boundRect(res) | |
243 | # search to the left for gaps large enough to accomodate res | |
244 | rci = bisect_left(reserved, res) | |
245 | ||
246 | for i in range(rci, len(reserved)-1): | |
247 | res.x = reserved[i].right + 1 | |
248 | if res.right < reserved[i+1].left: | |
249 | #found good res | |
250 | break | |
251 | else: | |
252 | # did not find gap to the right | |
253 | if reserved: | |
254 | #try to respect rc.x at the cost of a gap (50...Bed) | |
255 | if res.left < reserved[-1].right: | |
256 | res.x = reserved[-1].right + 1 | |
257 | if res.right >= self.width: | |
258 | #goes beyond window bounds | |
259 | # try to the left | |
260 | for i in range(min(rci, len(reserved)-1), 0, -1): | |
261 | res.x = reserved[i].left - rc.width | |
262 | if reserved[i-1].right < res.left: | |
263 | break | |
264 | else: | |
265 | res = LtRect(self.layoutRectY(rc)) | |
266 | ||
267 | self.reserved.append(res) | |
268 | return res | |
269 | ||
270 | def boundRect(self, rc): | |
271 | rc.x = min(rc.x, self.width - rc.width) | |
272 | return rc | |
273 | ||
274 | def layoutRectY(self, rc): | |
275 | top = self.height | |
276 | bottom = 0 | |
277 | collision = False | |
278 | res = LtRect(rc) | |
279 | res.x = max(self.gridLabelsRight+1, min(rc.x, self.width-rc.width)) | |
280 | for rs in self.reserved: | |
281 | if not (res.right < rs.left or res.left > rs.right): | |
282 | collision = True | |
283 | top = min(top, rs.Top) | |
284 | bottom = max(bottom, rs.bottom) | |
285 | if collision: | |
286 | res.y = top - rc.height | |
287 | if res.y < 0: | |
288 | res.y = bottom+1 | |
289 | if res.bottom >= self.height: | |
290 | res.y = rc.y | |
291 | return res | |
292 | ||
293 | def layoutText(self, text, x, y, gc): | |
294 | ext = gc.GetTextExtent(text) | |
295 | rc = self.layoutRect(wx.Rect(x, y, *ext)) | |
296 | # print('layoutText', text, rc.TopLeft) | |
297 | return rc | |
15 | 298 | |
299 | def drawfanpower(self, dc, gc): | |
300 | self.drawtemperature(dc, gc, self.fanpowers, | |
301 | "Fan", 1, 0, 0, 0, 128) | |
302 | ||
303 | def drawbedtemp(self, dc, gc): | |
304 | self.drawtemperature(dc, gc, self.bedtemps, | |
305 | "Bed", 2, 255, 0, 0, 128) | |
306 | ||
307 | def drawbedtargettemp(self, dc, gc): | |
308 | self.drawtemperature(dc, gc, self.bedtargettemps, | |
309 | "Bed Target", 2, 255, 120, 0, 128) | |
310 | ||
311 | def drawextruder0temp(self, dc, gc): | |
312 | self.drawtemperature(dc, gc, self.extruder0temps, | |
313 | "Ex0", 1, 0, 155, 255, 128) | |
314 | ||
315 | def drawextruder0targettemp(self, dc, gc): | |
316 | self.drawtemperature(dc, gc, self.extruder0targettemps, | |
317 | "Ex0 Target", 2, 0, 5, 255, 128) | |
318 | ||
319 | def drawextruder1temp(self, dc, gc): | |
320 | self.drawtemperature(dc, gc, self.extruder1temps, | |
321 | "Ex1", 3, 55, 55, 0, 128) | |
322 | ||
323 | def drawextruder1targettemp(self, dc, gc): | |
324 | self.drawtemperature(dc, gc, self.extruder1targettemps, | |
325 | "Ex1 Target", 2, 55, 55, 0, 128) | |
326 | ||
327 | def SetFanPower(self, value): | |
328 | self.fanpowers.pop() | |
329 | self.fanpowers.append(value) | |
330 | ||
331 | def AddFanPower(self, value): | |
332 | self.fanpowers.append(value) | |
333 | if float(len(self.fanpowers) - 1) / self.xsteps > 1: | |
334 | self.fanpowers.pop(0) | |
335 | ||
336 | def SetBedTemperature(self, value): | |
337 | self.bedtemps.pop() | |
338 | self.bedtemps.append(value) | |
339 | ||
340 | def AddBedTemperature(self, value): | |
341 | self.bedtemps.append(value) | |
342 | if float(len(self.bedtemps) - 1) / self.xsteps > 1: | |
343 | self.bedtemps.pop(0) | |
344 | ||
345 | def SetBedTargetTemperature(self, value): | |
346 | self.bedtargettemps.pop() | |
347 | self.bedtargettemps.append(value) | |
348 | ||
349 | def AddBedTargetTemperature(self, value): | |
350 | self.bedtargettemps.append(value) | |
351 | if float(len(self.bedtargettemps) - 1) / self.xsteps > 1: | |
352 | self.bedtargettemps.pop(0) | |
353 | ||
354 | def SetExtruder0Temperature(self, value): | |
355 | self.extruder0temps.pop() | |
356 | self.extruder0temps.append(value) | |
357 | ||
358 | def AddExtruder0Temperature(self, value): | |
359 | self.extruder0temps.append(value) | |
360 | if float(len(self.extruder0temps) - 1) / self.xsteps > 1: | |
361 | self.extruder0temps.pop(0) | |
362 | ||
363 | def SetExtruder0TargetTemperature(self, value): | |
364 | self.extruder0targettemps.pop() | |
365 | self.extruder0targettemps.append(value) | |
366 | ||
367 | def AddExtruder0TargetTemperature(self, value): | |
368 | self.extruder0targettemps.append(value) | |
369 | if float(len(self.extruder0targettemps) - 1) / self.xsteps > 1: | |
370 | self.extruder0targettemps.pop(0) | |
371 | ||
372 | def SetExtruder1Temperature(self, value): | |
373 | self.extruder1temps.pop() | |
374 | self.extruder1temps.append(value) | |
375 | ||
376 | def AddExtruder1Temperature(self, value): | |
377 | self.extruder1temps.append(value) | |
378 | if float(len(self.extruder1temps) - 1) / self.xsteps > 1: | |
379 | self.extruder1temps.pop(0) | |
380 | ||
381 | def SetExtruder1TargetTemperature(self, value): | |
382 | self.extruder1targettemps.pop() | |
383 | self.extruder1targettemps.append(value) | |
384 | ||
385 | def AddExtruder1TargetTemperature(self, value): | |
386 | self.extruder1targettemps.append(value) | |
387 | if float(len(self.extruder1targettemps) - 1) / self.xsteps > 1: | |
388 | self.extruder1targettemps.pop(0) | |
389 | ||
390 | def StartPlotting(self, time): | |
391 | self.Refresh() | |
392 | self.timer.Start(time) | |
393 | if self.window: self.window.graph.StartPlotting(time) | |
394 | ||
46 | 395 | def Destroy(self): |
396 | # print(__class__, '.Destroy') | |
397 | self.StopPlotting() | |
398 | return super(BufferedCanvas, self).Destroy() | |
399 | ||
15 | 400 | def StopPlotting(self): |
401 | self.timer.Stop() | |
46 | 402 | #self.Refresh() # do not refresh when stopping in case the underlying object has been destroyed already |
15 | 403 | if self.window: self.window.graph.StopPlotting() |
404 | ||
405 | def draw(self, dc, w, h): | |
46 | 406 | dc.SetBackground(wx.Brush(self.root.settings.graph_color_background)) |
15 | 407 | dc.Clear() |
408 | gc = wx.GraphicsContext.Create(dc) | |
409 | self.width = w | |
410 | self.height = h | |
46 | 411 | |
412 | self.reserved.clear() | |
15 | 413 | self.drawgrid(dc, gc) |
46 | 414 | self.gridLabelsRight = self.reserved[-1].Right |
415 | ||
15 | 416 | self.drawbedtargettemp(dc, gc) |
417 | self.drawbedtemp(dc, gc) | |
418 | self.drawfanpower(dc, gc) | |
419 | self.drawextruder0targettemp(dc, gc) | |
420 | self.drawextruder0temp(dc, gc) | |
46 | 421 | if self.extruder1targettemps[-1]>0 or self.extruder1temps[-1]>5: |
422 | self.drawextruder1targettemp(dc, gc) | |
423 | self.drawextruder1temp(dc, gc) | |
15 | 424 | |
46 | 425 | class _YBounds: |
15 | 426 | """Small helper class to claculate y bounds dynamically""" |
427 | ||
428 | def __init__(self, graph, minimum_scale=5.0, buffer=0.10): | |
429 | """_YBounds(Graph,float,float) | |
430 | ||
431 | graph parent object to calculate scales for | |
432 | minimum_scale minimum range to show on the graph | |
433 | buffer amount of padding to add above & below the | |
434 | displayed temperatures. Given as a fraction of the | |
435 | total range. (Eg .05 to use 90% of the range for | |
436 | temperatures) | |
437 | """ | |
438 | self.graph = graph | |
439 | self.min_scale = minimum_scale | |
440 | self.buffer = buffer | |
441 | ||
442 | # Frequency to rescale the graph | |
443 | self.update_freq = 10 | |
444 | # number of updates since last full refresh | |
445 | self._last_update = self.update_freq | |
446 | ||
447 | def update(self, forceUpdate=False): | |
448 | """Updates graph.minyvalue and graph.maxyvalue based on current | |
449 | temperatures """ | |
450 | self._last_update += 1 | |
451 | # TODO Smart update. Only do full calculation every 10s. Otherwise, | |
452 | # just look at current graph & expand if necessary | |
453 | if forceUpdate or self._last_update >= self.update_freq: | |
454 | self.graph.minyvalue, self.graph.maxyvalue = self.getBounds() | |
455 | self._last_update = 0 | |
456 | else: | |
457 | bounds = self.getBoundsQuick() | |
458 | self.graph.minyvalue, self.graph.maxyvalue = bounds | |
459 | ||
460 | def getBounds(self): | |
461 | """ | |
462 | Calculates the bounds based on the current temperatures | |
463 | ||
464 | Rules: | |
465 | * Include the full extruder0 history | |
466 | * Include the current target temp (but not necessarily old | |
467 | settings) | |
468 | * Include the extruder1 and/or bed temp if | |
469 | 1) The target temp is >0 | |
470 | 2) The history has ever been above 5 | |
471 | * Include at least min_scale | |
472 | * Include at least buffer above & below the extreme temps | |
473 | """ | |
474 | extruder0_min = min(self.graph.extruder0temps) | |
475 | extruder0_max = max(self.graph.extruder0temps) | |
476 | extruder0_target = self.graph.extruder0targettemps[-1] | |
477 | extruder1_min = min(self.graph.extruder1temps) | |
478 | extruder1_max = max(self.graph.extruder1temps) | |
479 | extruder1_target = self.graph.extruder1targettemps[-1] | |
480 | bed_min = min(self.graph.bedtemps) | |
481 | bed_max = max(self.graph.bedtemps) | |
482 | bed_target = self.graph.bedtargettemps[-1] | |
483 | ||
484 | miny = min(extruder0_min, extruder0_target) | |
485 | maxy = max(extruder0_max, extruder0_target) | |
486 | if extruder1_target > 0 or extruder1_max > 5: # use extruder1 | |
487 | miny = min(miny, extruder1_min, extruder1_target) | |
488 | maxy = max(maxy, extruder1_max, extruder1_target) | |
489 | if bed_target > 0 or bed_max > 5: # use HBP | |
490 | miny = min(miny, bed_min, bed_target) | |
491 | maxy = max(maxy, bed_max, bed_target) | |
46 | 492 | miny = min(0, miny) |
493 | maxy = max(260, maxy) | |
15 | 494 | |
495 | padding = (maxy - miny) * self.buffer / (1.0 - 2 * self.buffer) | |
496 | miny -= padding | |
497 | maxy += padding | |
498 | ||
499 | if maxy - miny < self.min_scale: | |
500 | extrapadding = (self.min_scale - maxy + miny) / 2.0 | |
501 | miny -= extrapadding | |
502 | maxy += extrapadding | |
503 | ||
504 | return (miny, maxy) | |
505 | ||
506 | def getBoundsQuick(self): | |
507 | # Only look at current temps | |
508 | extruder0_min = self.graph.extruder0temps[-1] | |
509 | extruder0_max = self.graph.extruder0temps[-1] | |
510 | extruder0_target = self.graph.extruder0targettemps[-1] | |
511 | extruder1_min = self.graph.extruder1temps[-1] | |
512 | extruder1_max = self.graph.extruder1temps[-1] | |
513 | extruder1_target = self.graph.extruder1targettemps[-1] | |
514 | bed_min = self.graph.bedtemps[-1] | |
515 | bed_max = self.graph.bedtemps[-1] | |
516 | bed_target = self.graph.bedtargettemps[-1] | |
517 | ||
518 | miny = min(extruder0_min, extruder0_target) | |
519 | maxy = max(extruder0_max, extruder0_target) | |
520 | if extruder1_target > 0 or extruder1_max > 5: # use extruder1 | |
521 | miny = min(miny, extruder1_min, extruder1_target) | |
522 | maxy = max(maxy, extruder1_max, extruder1_target) | |
523 | if bed_target > 0 or bed_max > 5: # use HBP | |
524 | miny = min(miny, bed_min, bed_target) | |
525 | maxy = max(maxy, bed_max, bed_target) | |
46 | 526 | miny = min(0, miny) |
527 | maxy = max(260, maxy) | |
15 | 528 | |
529 | # We have to rescale, so add padding | |
530 | bufratio = self.buffer / (1.0 - self.buffer) | |
531 | if miny < self.graph.minyvalue: | |
532 | padding = (self.graph.maxyvalue - miny) * bufratio | |
533 | miny -= padding | |
534 | if maxy > self.graph.maxyvalue: | |
535 | padding = (maxy - self.graph.minyvalue) * bufratio | |
536 | maxy += padding | |
537 | ||
538 | return (min(miny, self.graph.minyvalue), | |
539 | max(maxy, self.graph.maxyvalue)) | |
46 | 540 | |
541 | class LtRect(wx.Rect): | |
542 | def __lt__(self, other): | |
543 | return self.x < other.x |