# HG changeset patch # User mdd # Date 1611139023 -3600 # Node ID 3c27b4ee6feca46a46a580c185694b2c6ca8c519 # Parent dcc64b767b6410c15a067a4dd24c1857a4e5b6ae reimplemented lasercutter changes diff -r dcc64b767b64 -r 3c27b4ee6fec printrun-src/printrun/gui/controls.py --- a/printrun-src/printrun/gui/controls.py Wed Jan 20 10:17:01 2021 +0100 +++ b/printrun-src/printrun/gui/controls.py Wed Jan 20 11:37:03 2021 +0100 @@ -1,3 +1,6 @@ +# FILE MODIFIED BY NEOSOFT - MALTE DI DONATO +# Embed Lasercut controls + # This file is part of the Printrun suite. # # Printrun is free software: you can redistribute it and/or modify @@ -50,6 +53,8 @@ else: e_base_line = base_line + 2 + lasercut_base_line = 11 + pos_mapping = { "htemp_label": (base_line + 0, 0), "htemp_off": (base_line + 0, 2), @@ -68,6 +73,14 @@ "tempdisp": (tempdisp_line, 0), "extrude": (3, 0), "reverse": (3, 2), + "lasercut_optionsbtn": (lasercut_base_line, 0), + "lasercut_printbtn": (lasercut_base_line, 2), + "lasercut_material_thickness": (lasercut_base_line+1, 4), + "lasercut_material_thickness_label": (lasercut_base_line+1, 0), + "lasercut_pass_count": (lasercut_base_line+2, 4), + "lasercut_pass_count_label": (lasercut_base_line+2, 0), + "lasercut_pass_zdiff": (lasercut_base_line+3, 4), + "lasercut_pass_zdiff_label": (lasercut_base_line+3, 0), } span_mapping = { @@ -125,6 +138,30 @@ container = self container.Add(widget, *args, **kwargs) + # Lasercutter quick controls # + + root.lc_optionsbtn = make_button(parentpanel, _("Lasercutter options"), lambda e: PronterOptions(root, "Laser"), _("Open Lasercutter options"), style = wx.BU_EXACTFIT) + root.printerControls.append(root.lc_optionsbtn) + add("lasercut_optionsbtn", root.lc_optionsbtn, flag = wx.EXPAND) + + root.lc_printbtn = make_button(parentpanel, _("Start cutting"), root.on_lc_printfile, _("Start printjob with lasercutting features"), style = wx.BU_EXACTFIT) + root.printerControls.append(root.lc_printbtn) + add("lasercut_printbtn", root.lc_printbtn, flag = wx.EXPAND) + + + root.lc_pass_count = speed_spin = FloatSpin(parentpanel, -1, value = root.settings.lc_pass_count, min_val = 1, max_val = 10, digits = 0, style = wx.ALIGN_LEFT, size = (80, -1)) + add("lasercut_pass_count", root.lc_pass_count) + add("lasercut_pass_count_label", wx.StaticText(parentpanel, -1, _("Number of cutting passes:")), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT) + + root.lc_pass_zdiff = speed_spin = FloatSpin(parentpanel, -1, increment = 0.1, value = root.settings.lc_pass_zdiff, min_val = -2, max_val = 2, digits = 1, style = wx.ALIGN_LEFT, size = (80, -1)) + add("lasercut_pass_zdiff", root.lc_pass_zdiff) + add("lasercut_pass_zdiff_label", wx.StaticText(parentpanel, -1, _("Z movement after each cut:")), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT) + + root.lc_material_thickness = speed_spin = FloatSpin(parentpanel, -1, increment = 0.1, value = root.settings.lc_material_thickness, min_val = 0, max_val = 75, digits = 1, style = wx.ALIGN_LEFT, size = (80, -1)) + add("lasercut_material_thickness", root.lc_material_thickness) + add("lasercut_material_thickness_label", wx.StaticText(parentpanel, -1, _("Material Thickness:")), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT) + + # Hotend & bed temperatures # # Hotend temp diff -r dcc64b767b64 -r 3c27b4ee6fec printrun-src/printrun/gui/widgets.py --- a/printrun-src/printrun/gui/widgets.py Wed Jan 20 10:17:01 2021 +0100 +++ b/printrun-src/printrun/gui/widgets.py Wed Jan 20 11:37:03 2021 +0100 @@ -1,3 +1,6 @@ +# FILE MODIFIED BY NEOSOFT - MALTE DI DONATO +# Add Lasercut settings panel + # This file is part of the Printrun suite. # # Printrun is free software: you can redistribute it and/or modify @@ -120,7 +123,8 @@ "UI": _("User interface"), "Viewer": _("Viewer"), "Colors": _("Colors"), - "External": _("External commands")} + "External": _("External commands"), + "Laser": "Lasercut options"} class PronterOptionsDialog(wx.Dialog): """Options editor""" @@ -134,7 +138,7 @@ all_settings = pronterface.settings._all_settings() group_list = [] groups = {} - for group in ["Printer", "UI", "Viewer", "Colors", "External"]: + for group in ["Printer", "UI", "Viewer", "Colors", "External", "Laser"]: group_list.append(group) groups[group] = [] for setting in all_settings: diff -r dcc64b767b64 -r 3c27b4ee6fec printrun-src/printrun/pronterface.py --- a/printrun-src/printrun/pronterface.py Wed Jan 20 10:17:01 2021 +0100 +++ b/printrun-src/printrun/pronterface.py Wed Jan 20 11:37:03 2021 +0100 @@ -1,3 +1,15 @@ +# FILE MODIFIED BY NEOSOFT - MALTE DI DONATO +# Embed Lasercut functions from laser.py +from . import laser +try: + from . import module_watcher + mw = module_watcher.ModuleWatcher() + mw.watch_module('laser') + mw.start_watching() +except Exception, e: + print e + print "ModuleWatcher not loaded, skipping autoreloading of changed modules" + # This file is part of the Printrun suite. # # Printrun is free software: you can redistribute it and/or modify @@ -247,6 +259,89 @@ self.update_monitor() # -------------------------------------------------------------- + # Lasercutter methods + # -------------------------------------------------------------- + + def on_lc_printfile(self, event): + # lc print button + self.log("Priming Z axis to initial focus") + line = self.precmd("G1 Z%.2f" % (self.settings.lc_z_focus + self.lc_material_thickness.GetValue())) + wx.CallAfter(self.onecmd, line) + self.lc_printing = True + wx.CallAfter(self.printfile, None) + + def endcb_lasercut(self): + # LASERCUT: Now check if we should do another print pass? + self.log("event: endcb_lasercut") + if self.lc_printing: + self.log(" -> checking if something to do...") + pass_count = self.lc_pass_count.GetValue() + if pass_count > 1: + time.sleep(0.5) + if self.pass_current < pass_count: + self.pass_current += 1 + self.log("Starting lasercut pass # %i of %i" % (self.pass_current, pass_count)) + if self.lc_pass_zdiff.GetValue() != 0: + # move Z focus + new_z = self.settings.lc_z_focus + self.lc_material_thickness.GetValue() + ( + self.lc_pass_zdiff.GetValue() * (self.pass_current - 1)) + self.log("Re-Positioning laser focus by %.1f mm to %.1f" % (self.lc_pass_zdiff.GetValue(), new_z)) + line = self.precmd("G1 Z%.2f" % (new_z)) + self.onecmd(line) + time.sleep(0.5) + + # "click" print button again + tmp = self.pass_current + self.printfile(None) + self.pass_current = tmp + else: + self.lc_printing = False + wx.CallAfter(self.lc_printbtn.Enable) + wx.CallAfter(self.lc_printbtn.SetLabel, _("Start cutting")) + + self.log("Resetting Z axis to initial focus") + line = self.precmd("G1 Z%.2f" % (self.settings.lc_z_focus + self.lc_material_thickness.GetValue())) + self.onecmd(line) + else: + self.lc_printing = False + wx.CallAfter(self.lc_printbtn.Enable) + wx.CallAfter(self.lc_printbtn.SetLabel, _("Start cutting")) + + + def update_lc_settings(self, key, value): + return True + + def _lc_add_settings(self, size): + # first add the lasercutter options + self.settings._add(StaticTextSetting("separator_lc_general", "General laser settings", "", group = "Laser")) + self.settings._add(BooleanSetting("lc_melzi_hack", False, "Use Melzi M571 Hack instead M3/M5", "no description :)", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_travel_speed", 120, 1, 300, "Travel speed in mm/s", "", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_engrave_speed", 10, 1, 300, "Engrave speed in mm/s", "", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_z_focus", 16, -80, 80, "Laser Z focus position", "", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_pass_count", 1, 0, 20, "Default Number of cutting passes", "", "Laser"), self.reload_ui) + self.settings._add(FloatSpinSetting("lc_pass_zdiff", -0.25, -2.0, 2.0, "Default Z movement after each cut", "", "Laser"), self.reload_ui) + self.settings._add(FloatSpinSetting("lc_material_thickness", 4.0, 0.0, 80.0, "Default Material Thickness", "", "Laser"), self.reload_ui) + + self.settings._add(StaticTextSetting("separator_lc_bitmap", "PNG Bitmap processing", "", group = "Laser")) + self.settings._add(FloatSpinSetting("lc_bitmap_speed_factor", 1.0, 0.1, 2.0, "Engrave speed factor", "", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_dpi", 300, 25, 600, "Image DPI", "Image resolution for scaling", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_grey_threshold", 0, 0, 255, "Grey threshold value for RGB", "", "Laser"), self.update_lc_settings) + self.settings._add(BooleanSetting("lc_invert_cut", True, "PNG: Invert grey threshold", "Invert laser on/off logic", "Laser"), self.update_lc_settings) + self.settings._add(BooleanSetting("lc_change_dir", True, "PNG: Change direction", "Engrave in both directions on Y Axis", "Laser"), self.update_lc_settings) + + self.settings._add(StaticTextSetting("separator_lc_hpgl", "HPGL processing", "", group = "Laser")) + self.settings._add(FloatSpinSetting("lc_hpgl_speed_factor", 1.0, 0.1, 2.0, "Engrave speed factor", "", "Laser"), self.update_lc_settings) + + self.settings._add(StaticTextSetting("separator_lc_svg", "SVG processing", "", group = "Laser")) + self.settings._add(FloatSpinSetting("lc_svg_speed_factor", 1.0, 0.1, 2.0, "Engrave speed factor", "", "Laser"), self.update_lc_settings) + self.settings._add(FloatSpinSetting("lc_svg_smoothness", 0.2, 0.1, 10.0, "Smoothness", "Smoothness of curves (smaller value = smoother curve)", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_svg_width", 50, 1, 9999, "Width (mm)", "Image width", "Laser"), self.update_lc_settings) + self.settings._add(SpinSetting("lc_svg_height", 50, 1, 9999, "Height (mm)", "Image height", "Laser"), self.update_lc_settings) + self.settings._add(ComboSetting("lc_svg_scalemode", "original", ["original", "scale", "stretch"], "Scaling mode", "scale/stretch to above dimensions", "Laser"), self.update_lc_settings) + self.settings._add(BooleanSetting("lc_svg_offset", True, "Calculate offset to X=0, Y=0", "If enabled, move image to origin position", "Laser"), self.update_lc_settings) + + + # -------------------------------------------------------------- # Main interface handling # -------------------------------------------------------------- @@ -944,6 +1039,7 @@ info.SetLicence(licence) info.AddDeveloper('Kliment Yanev') info.AddDeveloper('Guillaume Seguin') + info.AddDeveloper('Malte Di Donato') wx.adv.AboutBox(info) @@ -952,6 +1048,8 @@ # -------------------------------------------------------------- def _add_settings(self, size): + self._lc_add_settings(size) + self.settings._add(BooleanSetting("monitor", True, _("Monitor printer status"), _("Regularly monitor printer temperatures (required to have functional temperature graph or gauges)"), "Printer"), self.update_monitor) self.settings._add(StringSetting("simarrange_path", "", _("Simarrange command"), _("Path to the simarrange binary to use in the STL plater"), "External")) self.settings._add(BooleanSetting("circular_bed", False, _("Circular build platform"), _("Draw a circular (or oval) build platform instead of a rectangular one"), "Printer"), self.update_bed_viz) @@ -1486,7 +1584,8 @@ dlg = None if filename is None: dlg = wx.FileDialog(self, _("Open file to print"), basedir, style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) - dlg.SetWildcard(_("OBJ, STL, and GCODE files (*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ)|*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ|GCODE files (*.gcode;*.gco;*.g)|*.gcode;*.gco;*.g|OBJ, STL files (*.stl;*.STL;*.obj;*.OBJ)|*.stl;*.STL;*.obj;*.OBJ|All Files (*.*)|*.*")) + # add image files to GCODE file list + dlg.SetWildcard(_("GCODE and Image files|*.gcode;*.gco;*.g;*.png;*.svg;*.hpgl;*.plt|OBJ, STL, and GCODE files (*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ)|*.gcode;*.gco;*.g;*.stl;*.STL;*.obj;*.OBJ|GCODE files (*.gcode;*.gco;*.g)|*.gcode;*.gco;*.g|OBJ, STL files (*.stl;*.STL;*.obj;*.OBJ)|*.stl;*.STL;*.obj;*.OBJ|All Files (*.*)|*.*")) try: dlg.SetFilterIndex(self.settings.last_file_filter) except: @@ -1521,8 +1620,27 @@ except: self.logError(_("Could not update recent files list:") + "\n" + traceback.format_exc()) + + # reload the library local so we dont have to restart the whole app when making code changes + reload(laser) + if name.lower().endswith(".stl") or name.lower().endswith(".obj"): self.slice(name) + elif name.lower().endswith(".png") or name.lower().endswith(".jpg") or name.lower().endswith(".gif"): + # Generate GCODE from IMAGE + lc = laser.Lasercutter(pronterwindow = self) + lc.image2gcode(name) + wx.CallAfter(self.endcb_lasercut) + elif name.lower().endswith(".svg"): + # Generate GCODE from SVG + lc = laser.Lasercutter(pronterwindow = self) + lc.svg2gcode(name) + wx.CallAfter(self.endcb_lasercut) + elif name.lower().endswith(".hpgl") or name.lower().endswith(".plt"): + # Generate GCODE from HPGL + lc = laser.Lasercutter(pronterwindow = self) + lc.hpgl2gcode(name) + wx.CallAfter(self.endcb_lasercut) else: self.load_gcode_async(name) else: @@ -1737,6 +1855,7 @@ wx.CallAfter(self.pausebtn.Disable) wx.CallAfter(self.printbtn.SetLabel, _("&Print")) wx.CallAfter(self.toolbarsizer.Layout) + wx.CallAfter(self.endcb_lasercut) def online(self): """Callback when printer goes online"""