Commit af109a0e authored by Guillaume Seguin's avatar Guillaume Seguin

Initial excluder tool implementation (#266)

parent 8e6fa0d8
...@@ -74,6 +74,7 @@ class printcore(): ...@@ -74,6 +74,7 @@ class printcore():
self.tempcb = None #impl (wholeline) self.tempcb = None #impl (wholeline)
self.recvcb = None #impl (wholeline) self.recvcb = None #impl (wholeline)
self.sendcb = None #impl (wholeline) self.sendcb = None #impl (wholeline)
self.preprintsendcb = None #impl (wholeline)
self.printsendcb = None #impl (wholeline) self.printsendcb = None #impl (wholeline)
self.layerchangecb = None #impl (wholeline) self.layerchangecb = None #impl (wholeline)
self.errorcb = None #impl (wholeline) self.errorcb = None #impl (wholeline)
...@@ -414,7 +415,9 @@ class printcore(): ...@@ -414,7 +415,9 @@ class printcore():
if self.startcb: if self.startcb:
#callback for printing started #callback for printing started
try: self.startcb(resuming) try: self.startcb(resuming)
except: pass except:
print "Print start callback failed with:"
traceback.print_exc(file = sys.stdout)
while self.printing and self.printer and self.online: while self.printing and self.printer and self.online:
self._sendnext() self._sendnext()
self.sentlines = {} self.sentlines = {}
...@@ -423,10 +426,12 @@ class printcore(): ...@@ -423,10 +426,12 @@ class printcore():
if self.endcb: if self.endcb:
#callback for printing done #callback for printing done
try: self.endcb() try: self.endcb()
except: pass except:
print "Print end callback failed with:"
traceback.print_exc(file = sys.stdout)
except: except:
print "Print thread died due to the following error:" print "Print thread died due to the following error:"
traceback.print_exc() traceback.print_exc(file = sys.stdout)
finally: finally:
self.print_thread = None self.print_thread = None
self._start_sender() self._start_sender()
...@@ -466,10 +471,17 @@ class printcore(): ...@@ -466,10 +471,17 @@ class printcore():
if prev_layer != layer: if prev_layer != layer:
try: self.layerchangecb(layer) try: self.layerchangecb(layer)
except: traceback.print_exc() except: traceback.print_exc()
if self.preprintsendcb:
gline = self.preprintsendcb(gline)
if gline == None:
self.queueindex += 1
self.clear = True
return
tline = gline.raw tline = gline.raw
if tline.lstrip().startswith(";@"): # check for host command if tline.lstrip().startswith(";@"): # check for host command
self.processHostCommand(tline) self.processHostCommand(tline)
self.queueindex += 1 self.queueindex += 1
self.clear = True
return return
tline = tline.split(";")[0] tline = tline.split(";")[0]
......
# This file is part of the Printrun suite.
#
# Printrun is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Printrun is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Printrun. If not, see <http://www.gnu.org/licenses/>.
import wx
from printrun import gviz
from printrun_utils import imagefile, install_locale
install_locale('pronterface')
class ExcluderWindow(gviz.GvizWindow):
def __init__(self, excluder, *args, **kwargs):
super(ExcluderWindow, self).__init__(*args, **kwargs)
self.SetTitle(_("Part excluder: draw rectangles where print instructions should be ignored"))
self.toolbar.AddLabelTool(128, " " + _("Reset selection"), wx.Image(imagefile('reset.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap(), shortHelp = _("Reset selection"), longHelp = "")
self.Bind(wx.EVT_TOOL, self.reset_selection, id = 128)
self.parent = excluder
self.p.paint_overlay = self.paint_selection
self.p.layerup()
def real_to_gcode(self, x, y):
return (x + self.p.build_dimensions[3],
self.p.build_dimensions[4] + self.p.build_dimensions[1] - y)
def gcode_to_real(self, x, y):
return (x - self.p.build_dimensions[3],
self.p.build_dimensions[1] - (y - self.p.build_dimensions[4]))
def mouse(self, event):
if event.ButtonUp(wx.MOUSE_BTN_LEFT) or event.ButtonUp(wx.MOUSE_BTN_RIGHT):
self.initpos = None
elif event.Dragging() and event.RightIsDown():
e = event.GetPositionTuple()
if not self.initpos or not hasattr(self, "basetrans"):
self.initpos = e
self.basetrans = self.p.translate
self.p.translate = [self.basetrans[0] + (e[0] - self.initpos[0]),
self.basetrans[1] + (e[1] - self.initpos[1])]
self.p.dirty = 1
wx.CallAfter(self.p.Refresh)
elif event.Dragging() and event.LeftIsDown():
x, y = event.GetPositionTuple()
if not hasattr(self, "basetrans"):
self.basetrans = self.p.translate
x = (x - self.basetrans[0]) / self.p.scale[0]
y = (y - self.basetrans[1]) / self.p.scale[1]
x, y = self.real_to_gcode(x, y)
if not self.initpos:
self.initpos = (x, y)
self.basetrans = self.p.translate
self.parent.rectangles.append((0, 0, 0, 0))
else:
pos = (x, y)
x0 = min(self.initpos[0], pos[0])
y0 = min(self.initpos[1], pos[1])
x1 = max(self.initpos[0], pos[0])
y1 = max(self.initpos[1], pos[1])
self.parent.rectangles[-1] = (x0, y0, x1, y1)
wx.CallAfter(self.p.Refresh)
else:
event.Skip()
def _line_scaler(self, orig):
x0, y0 = self.gcode_to_real(orig[0], orig[1])
x0 = self.p.scale[0]*x0 + self.p.translate[0]
y0 = self.p.scale[1]*y0 + self.p.translate[1]
x1, y1 = self.gcode_to_real(orig[2], orig[3])
x1 = self.p.scale[0]*x1 + self.p.translate[0]
y1 = self.p.scale[1]*y1 + self.p.translate[1]
width = max(x0, x1) - min(x0, x1) + 1
height = max(y0, y1) - min(y0, y1) + 1
return (min(x0, x1), min(y0, y1), width, height,)
def paint_selection(self, dc):
dc = wx.GCDC(dc)
dc.SetPen(wx.TRANSPARENT_PEN)
dc.DrawRectangleList([self._line_scaler(rect) for rect in self.parent.rectangles],
None, wx.Brush((200, 200, 200, 150)))
def reset_selection(self, event):
self.parent.rectangles = []
wx.CallAfter(self.p.Refresh)
class Excluder(object):
def __init__(self):
self.rectangles = []
self.window = None
def pop_window(self, gcode, *args, **kwargs):
if not self.window:
self.window = ExcluderWindow(self, *args, **kwargs)
self.window.p.addfile(gcode)
self.window.p.layerup()
self.window.Bind(wx.EVT_CLOSE, self.close_window)
self.window.Show()
else:
self.window.Show()
self.window.Raise()
def close_window(self, event = None):
if self.window:
self.window.Destroy()
self.window = None
if __name__ == '__main__':
import sys
gcode = gcoder.GCode(open(sys.argv[1]))
app = wx.App(False)
ex = Excluder()
ex.pop_window(gcode)
app.MainLoop()
...@@ -45,6 +45,7 @@ if os.name == "nt": ...@@ -45,6 +45,7 @@ if os.name == "nt":
import printcore import printcore
from printrun.printrun_utils import pixmapfile, configfile from printrun.printrun_utils import pixmapfile, configfile
from printrun.gui import MainWindow from printrun.gui import MainWindow
from printrun.excluder import Excluder
import pronsole import pronsole
from pronsole import dosify, wxSetting, HiddenSetting, StringSetting, SpinSetting, FloatSpinSetting, BooleanSetting, StaticTextSetting from pronsole import dosify, wxSetting, HiddenSetting, StringSetting, SpinSetting, FloatSpinSetting, BooleanSetting, StaticTextSetting
from printrun import gcoder from printrun import gcoder
...@@ -175,6 +176,15 @@ class ComboSetting(wxSetting): ...@@ -175,6 +176,15 @@ class ComboSetting(wxSetting):
return self.widget return self.widget
class PronterWindow(MainWindow, pronsole.pronsole): class PronterWindow(MainWindow, pronsole.pronsole):
_fgcode = None
def _get_fgcode(self):
return self._fgcode
def _set_fgcode(self, value):
self._fgcode = value
self.excluder = None
fgcode = property(_get_fgcode, _set_fgcode)
def __init__(self, filename = None, size = winsize): def __init__(self, filename = None, size = winsize):
pronsole.pronsole.__init__(self) pronsole.pronsole.__init__(self)
#default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed and endstops at 0, 0 and 0 #default build dimensions are 200x200x100 with 0, 0, 0 in the corner of the bed and endstops at 0, 0 and 0
...@@ -218,6 +228,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -218,6 +228,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.userm105 = 0 self.userm105 = 0
self.monitor = 0 self.monitor = 0
self.fgcode = None self.fgcode = None
self.excluder = None
self.skeinp = None self.skeinp = None
self.monitor_interval = 3 self.monitor_interval = 3
self.current_pos = [0, 0, 0] self.current_pos = [0, 0, 0]
...@@ -292,6 +303,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -292,6 +303,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.skeining = 0 self.skeining = 0
self.mini = False self.mini = False
self.p.sendcb = self.sentcb self.p.sendcb = self.sentcb
self.p.preprintsendcb = self.preprintsendcb
self.p.printsendcb = self.printsentcb self.p.printsendcb = self.printsentcb
self.p.layerchangecb = self.layer_change_cb self.p.layerchangecb = self.layer_change_cb
self.p.startcb = self.startcb self.p.startcb = self.startcb
...@@ -395,6 +407,18 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -395,6 +407,18 @@ class PronterWindow(MainWindow, pronsole.pronsole):
return return
self.sentlines.put_nowait(line) self.sentlines.put_nowait(line)
def preprintsendcb(self, gline):
if not self.excluder or not self.excluder.rectangles:
return gline
for (x0, y0, x1, y1) in self.excluder.rectangles:
if not gline.is_move: continue
if x0 <= gline.current_x <= x1 and y0 <= gline.current_y <= y1:
if gline.e != None and not gline.relative_e:
return gcoder.Line("G92 E%.5f" % gline.e)
else:
return None
return gline
def printsentcb(self, gline): def printsentcb(self, gline):
if gline.is_move and hasattr(self.gwindow, "set_current_gline"): if gline.is_move and hasattr(self.gwindow, "set_current_gline"):
wx.CallAfter(self.gwindow.set_current_gline, gline) wx.CallAfter(self.gwindow.set_current_gline, gline)
...@@ -538,6 +562,14 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -538,6 +562,14 @@ class PronterWindow(MainWindow, pronsole.pronsole):
from printrun import projectlayer from printrun import projectlayer
projectlayer.SettingsFrame(self, self.p).Show() projectlayer.SettingsFrame(self, self.p).Show()
def exclude(self, event):
if not self.fgcode:
wx.CallAfter(self.statusbar.SetStatusText, _("No file loaded. Please use load first."))
return
if not self.excluder:
self.excluder = Excluder()
self.excluder.pop_window(self.fgcode, bgcolor = self.settings.bgcolor)
def popmenu(self): def popmenu(self):
self.menustrip = wx.MenuBar() self.menustrip = wx.MenuBar()
# File menu # File menu
...@@ -545,6 +577,7 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -545,6 +577,7 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.Bind(wx.EVT_MENU, self.loadfile, m.Append(-1, _("&Open..."), _(" Opens file"))) self.Bind(wx.EVT_MENU, self.loadfile, m.Append(-1, _("&Open..."), _(" Opens file")))
self.Bind(wx.EVT_MENU, self.do_editgcode, m.Append(-1, _("&Edit..."), _(" Edit open file"))) self.Bind(wx.EVT_MENU, self.do_editgcode, m.Append(-1, _("&Edit..."), _(" Edit open file")))
self.Bind(wx.EVT_MENU, self.clearOutput, m.Append(-1, _("Clear console"), _(" Clear output console"))) self.Bind(wx.EVT_MENU, self.clearOutput, m.Append(-1, _("Clear console"), _(" Clear output console")))
self.Bind(wx.EVT_MENU, self.exclude, m.Append(-1, _("Excluder"), _(" Exclude parts of the bed from being printed")))
self.Bind(wx.EVT_MENU, self.project, m.Append(-1, _("Projector"), _(" Project slices"))) self.Bind(wx.EVT_MENU, self.project, m.Append(-1, _("Projector"), _(" Project slices")))
self.Bind(wx.EVT_MENU, self.OnExit, m.Append(wx.ID_EXIT, _("E&xit"), _(" Closes the Window"))) self.Bind(wx.EVT_MENU, self.OnExit, m.Append(wx.ID_EXIT, _("E&xit"), _(" Closes the Window")))
self.menustrip.Append(m, _("&File")) self.menustrip.Append(m, _("&File"))
...@@ -1121,6 +1154,8 @@ class PronterWindow(MainWindow, pronsole.pronsole): ...@@ -1121,6 +1154,8 @@ class PronterWindow(MainWindow, pronsole.pronsole):
self.save_in_rc("set xy_feedrate", "set xy_feedrate %d" % self.settings.xy_feedrate) self.save_in_rc("set xy_feedrate", "set xy_feedrate %d" % self.settings.xy_feedrate)
self.save_in_rc("set z_feedrate", "set z_feedrate %d" % self.settings.z_feedrate) self.save_in_rc("set z_feedrate", "set z_feedrate %d" % self.settings.z_feedrate)
self.save_in_rc("set e_feedrate", "set e_feedrate %d" % self.settings.e_feedrate) self.save_in_rc("set e_feedrate", "set e_feedrate %d" % self.settings.e_feedrate)
if self.excluder:
self.excluder.close_window()
wx.CallAfter(self.gwindow.Destroy) wx.CallAfter(self.gwindow.Destroy)
wx.CallAfter(self.Destroy) wx.CallAfter(self.Destroy)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment