From 60b64d70beb37d3c29afdf0a5012a9d9f30346ab Mon Sep 17 00:00:00 2001 From: GregValiant <64202104+GregValiant@users.noreply.github.com> Date: Sat, 21 Dec 2024 09:21:44 -0500 Subject: [PATCH] Update PurgeLinesAndUnload.py Added a "quick purge" option before the actual unload to insure the filament is free to pull back. Made adjustments for "Machine Disallowed Areas". Added some comments. Re-ordered some of the code. --- .../scripts/PurgeLinesAndUnload.py | 721 ++++++++++-------- 1 file changed, 403 insertions(+), 318 deletions(-) diff --git a/plugins/PostProcessingPlugin/scripts/PurgeLinesAndUnload.py b/plugins/PostProcessingPlugin/scripts/PurgeLinesAndUnload.py index 407201f4ef5..ac848f706b0 100644 --- a/plugins/PostProcessingPlugin/scripts/PurgeLinesAndUnload.py +++ b/plugins/PostProcessingPlugin/scripts/PurgeLinesAndUnload.py @@ -1,18 +1,19 @@ # August 2024 - GregValiant (Greg Foresi) # # NOTE: You may have purge lines in your startup, or you may use this script, you should not do both. The script will attempt to comment out existing StartUp purge lines. -# 'Add Purge Lines to StartUp' Allows the user to determine where the purge lines are on the build plate, or to not use purge lines if a print extends to the limits of the build surface. Any Purge lines currently in the StartUp should be removed before using this script. +# 'Add Purge Lines to StartUp' Allows the user to determine where the purge lines are on the build plate, or to not use purge lines if a print extends to the limits of the build surface. +# This script will attempt to recognize and comment out purge lines in the StartUp Gcode but they should be removed if using this script. # The setting 'Purge Line Length' is only avaialble for rectangular beds because I was too lazy to calculate the 45° arcs. # 'Move to Start' takes an orthogonal path around the periphery before moving in to the print start location. It eliminates strings across the print area. # 'Adjust Starting E' is a correction in the E location before the skirt/brim starts. The user can make an adjustment so that the skirt / brim / raft starts where it should. # 'Unload' adds code to the Ending Gcode that will unload the filament from the machine. The unlaod distance is broken into chunks to avoid overly long E distances. # Added extra moves to account for Cura adding a "Travel to Prime Tower" move that can cross the middle of the build surface. +# Added ability to take 'disallowed areas' into account. from ..Script import Script from UM.Application import Application from UM.Message import Message import re -import os from UM.Logger import Logger class PurgeLinesAndUnload(Script): @@ -20,19 +21,21 @@ class PurgeLinesAndUnload(Script): def initialize(self) -> None: super().initialize() # Get the StartUp Gcode from Cura and attempt to catch if it contains purge lines. Message the user if an extrusion is in the startup. - curaApp = Application.getInstance().getGlobalContainerStack() - startup_gcode = curaApp.getProperty("machine_start_gcode", "value") + self.curaApp = Application.getInstance().getGlobalContainerStack() + startup_gcode = self.curaApp.getProperty("machine_start_gcode", "value") start_lines = startup_gcode.splitlines() for line in start_lines: - if line.startswith("G1") and " E" in line and (" X" in line or " Y" in line): + if "G1" in line and " E" in line and (" X" in line or " Y" in line): Message(title = "[Purge Lines and Unload]", text = "It appears that there are 'purge lines' in the StartUp Gcode. Using the 'Add Purge Lines' function of this script will comment them out.").show() break - self._instance.setProperty("is_rectangular", "value", True if curaApp.getProperty("machine_shape", "value") == "rectangular" else False) - self._extruder = curaApp.extruderList + # 'is rectangular' is used to disable half-length purge lines for elliptic beds. + self._instance.setProperty("is_rectangular", "value", True if self.curaApp.getProperty("machine_shape", "value") == "rectangular" else False) + self._instance.setProperty("move_to_prime_tower", "value", True if self.curaApp.getProperty("machine_extruder_count", "value") > 1 else False) + self.extruder = self.curaApp.extruderList #This is set in 'Add Purge Lines' and is used by 'Move to Start' to indicate which corner the nozzle is in after the purge lines - self._purge_end_loc = None + self.start_location = "LF" # Set the default E adjustment - self._instance.setProperty("adjust_e_loc_to", "value", -abs(round(float(self._extruder[0].getProperty("retraction_amount", "value")), 1))) + self._instance.setProperty("adjust_e_loc_to", "value", -abs(round(float(self.extruder[0].getProperty("retraction_amount", "value")), 1))) def getSettingDataString(self): return """{ @@ -118,6 +121,22 @@ def getSettingDataString(self): "unit": "mm ", "enabled": "enable_unload" }, + "unload_quick_purge": + { + "label": " Quick purge before unload", + "description": "When printing something fine that has a lot of retractions in a short space (like lettering or spires) right before the unload, the filament can get hung up in the hot end and unload can fail. A quick purge will soften the end of the filament so it will retract correctly. This 'quick puge' will take place at the last position of the nozzle.", + "type": "bool", + "default_value": false, + "enabled": "enable_unload" + }, + "move_to_prime_tower": + { + "label": "Hidden setting", + "description": "Hidden setting that enables 'move_to_prime_tower' for multi extruder machines.", + "type": "bool", + "default_value": false, + "enabled": false + }, "is_rectangular": { "label": "Bed is rectangular", @@ -130,10 +149,39 @@ def getSettingDataString(self): }""" def execute(self, data): + # Exit if the Gcode has already been processed. + for num in range(0, len(data)): + layer = data[num].split("\n") + for line in layer: + if ";LAYER:" in line: + break + elif "PurgeLinesAndUnload" in line: + Logger.log("i", "[Add Purge Lines and Unload Filament] has already run on this gcode.") + return data + # This will be True when there are more than 4 'machine_disallowed_areas' + self.show_warning = False + self.disallowed_areas = self.curaApp.getProperty("machine_disallowed_areas", "value") + self.extruder = self.curaApp.extruderList + self.extruder_count = self.curaApp.getProperty("machine_extruder_count", "value") + self.bed_shape = self.curaApp.getProperty("machine_shape", "value") + self.origin_at_center = self.curaApp.getProperty("machine_center_is_zero", "value") + self.machine_width = self.curaApp.getProperty("machine_width", "value") + self.machine_depth = self.curaApp.getProperty("machine_depth", "value") + self.machine_left = 1.0 + self.machine_right = self.machine_width - 1.0 + self.machine_front = 1.0 + self.machine_back = self.machine_depth - 1.0 + # Adjust the usable size of the bed per any 'disallowed areas' + max_print_size = self._get_build_plate_extents() + self.speed_travel = self.extruder[0].getProperty("speed_travel", "value") * 60 + # The start location changes according to which quadrant the nozzle is in at the beginning + self.start_location = self._get_real_start_point(data[1]) + # Run the selected procedures # Mapping settings to corresponding methods procedures = { "add_purge_lines": self._add_purge_lines, + "move_to_prime_tower": self._move_to_prime_tower, "move_to_start": self._move_to_start, "adjust_starting_e": self._adjust_starting_e, "enable_unload": self._unload_filament @@ -145,162 +193,321 @@ def execute(self, data): # Format the startup and ending gcodes data[1] = self._format_string(data[1]) data[-1] = self._format_string(data[-1]) + if self.getSettingValueByKey("add_purge_lines"): + if self.show_warning: + msg_text = "The printer has ( " + str(len(self.disallowed_areas)) + " ) 'disallowed areas'. That can cause the area available for the purge lines to be small.\nOpen the Gcode file for preview in Cura and check the purge line location to insure it is acceptable." + else: + msg_text = "Open the Gcode file for preview in Cura. Make sure the 'Purge Lines' don't run underneath something else and are acceptable." + Message(title = "[Purge Lines and Unload]", text = msg_text).show() return data + def _get_real_start_point(self, first_section: str) -> str: + last_x = 0.0 + last_y = 0.0 + start_quadrant = "LF" + startup = first_section.split("\n") + for line in startup: + if (line.startswith(";") and not line.startswith(";LAYER_COUNT")) or line == "": + continue + if line.startswith("G28"): + last_x = 0 + last_y = 0 + elif line[:3] in ["G0 ", "G1 "]: + if " X" in line: + last_x = self.getValue(line, "X") + if " Y" in line: + last_y = self.getValue(line, "Y") + # Stop at the Layer Count line to exclude a possible move to the prime tower + elif "LAYER_COUNT" in line: + break + if self.bed_shape == "rectangular" and not self.origin_at_center: + midpoint_x = self.machine_width / 2 + midpoint_y = self.machine_depth / 2 + elif self.origin_at_center: + midpoint_x = 0.0 + midpoint_y = 0.0 + if last_x <= midpoint_x and last_y <= midpoint_y: + start_quadrant = "LF" + elif last_x > midpoint_x and last_y < midpoint_y: + start_quadrant = "RF" + elif last_x > midpoint_x and last_y > midpoint_y: + start_quadrant = "RR" + elif last_x < midpoint_x and last_y > midpoint_y: + start_quadrant = "LR" + return start_quadrant + + # For some multi-extruder printers. Takes into account a 'Move to Prime Tower' if there is one and adds orthogonal travel moves to get there. + # 'Move to Prime Tower' does not require that the prime tower is enabled, only that 'machine_extruder_start_position_?' is in the definition file. + def _move_to_prime_tower(self, first_section: str) -> str: + if self.extruder_count == 1: + return first_section + adjustment_lines = "" + move_to_prime_present = False + prime_tower_x = self.curaApp.getProperty("prime_tower_position_x", "value") + prime_tower_y = self.curaApp.getProperty("prime_tower_position_y", "value") + prime_tower_loc = self._prime_tower_quadrant(prime_tower_x, prime_tower_y) + # Shortstop an error if Start Location comes through as None + if self.start_location == None: + self.start_location = "LF" + if prime_tower_loc != self.start_location: + startup = first_section[1].split("\n") + for index, line in enumerate(startup): + if ";LAYER_COUNT:" in line: + try: + if startup[index + 1].startswith("G0"): + prime_move = startup[index + 1] + " ; Move to Prime Tower" + adjustment_lines = self._get_adjustment_lines(prime_tower_loc) + startup[index + 1] = adjustment_lines + prime_move + "\n" + startup[index] + startup.pop(index) + first_section[1] = "\n".join(startup) + move_to_prime_present = True + except: + pass + # The start_location changes to the prime tower location in case 'Move to Start' is enabled. + if move_to_prime_present: + self.start_location = prime_tower_loc + return first_section + + # Determine the quadrant that the prime tower rests in so the orthogonal moves can be calculated + def _prime_tower_quadrant(self, prime_tower_x: float, prime_tower_y: float): + if not self.origin_at_center: + midpoint_x = self.machine_width / 2 + midpoint_y = self.machine_depth / 2 + max_x = self.machine_width - 1 + min_x = 1 + max_y = self.machine_depth - 1 + min_y = 1 + elif self.origin_at_center: + midpoint_x = 0 + midpoint_y = 0 + max_x = (self.machine_width / 2) - 1 + min_x = -abs((self.machine_width / 2) - 1) + max_y = (self.machine_depth / 2) - 1 + min_y = -abs((self.machine_depth / 2) - 1) + if prime_tower_x < midpoint_x and prime_tower_y < midpoint_y: + self.prime_tower_location = "LF" + elif prime_tower_x > midpoint_x and prime_tower_y < midpoint_y: + self.prime_tower_location = "RF" + elif prime_tower_x > midpoint_x and prime_tower_y > midpoint_y: + self.prime_tower_location = "RR" + elif prime_tower_x < midpoint_x and prime_tower_y > midpoint_y: + self.prime_tower_location = "LR" + return self.prime_tower_location + + # This puts the 'Move to Prime' tower lines together when they are required + def _get_adjustment_lines(self, prime_tower_loc: str): + adj_lines = ";MESH:NONMESH---------[Move to Prime Tower]" + if self.start_location == "LF": + if prime_tower_loc == "RF": + adj_lines += f"\nG0 F{self.speed_travel} X{self.machine_right} ; Start move\nG0 F600 Z0 ; Nail down the string\nG0 F600 Z2 ; Move up\n" + if prime_tower_loc == "RR": + adj_lines += f"\nG0 F{self.speed_travel} X{self.machine_right} ; Start move\nG0 F600 Z0 ; Nail down the string\nG0 F600 Z2 ; Move up\n" + if prime_tower_loc == "LR": + adj_lines += f"\nG0 F{self.speed_travel} Y{self.machine_back} ; Start move\nG0 F600 Z0 ; Nail down the string\nG0 F600 Z2 ; Move up\n" + elif self.start_location == "RR": + if prime_tower_loc == "LF": + adj_lines += f"\nG0 F{self.speed_travel} X{self.machine_left} ; Start move\nG0 F600 Z0 ; Nail down the string\nG0 F600 Z2 ; Move up\n" + if prime_tower_loc == "RF": + adj_lines += f"\nG0 F{self.speed_travel} Y{self.machine_front} ; Start move\nG0 F600 Z0 ; Nail down the string\nG0 F600 Z2 ; Move up\n" + if prime_tower_loc == "LR": + adj_lines += f"\nG0 F{self.speed_travel} X{self.machine_left} ; Start move to Prime Tower\nG0 F600 Z0 ; Nail down the string\nG0 F600 Z2 ; Move up\n" + return adj_lines + + def _get_build_plate_extents(self) -> float: + # Machine disallwed areas can be ordered at the whim of the definition author and cannot be counted on when parsed + # This determines a simple rectangle that will be available for the purge lines. For some machines (Ex: UM3) it can be a small rectangle. + if self.bed_shape == "rectangular": + if self.disallowed_areas != []: + if len(self.disallowed_areas) > 4: + self.show_warning = True + mid_x = 0 + mid_y = 0 + left_x = -(self.machine_width / 2) + right_x = (self.machine_width / 2) + front_y = (self.machine_depth / 2) + back_y = -(self.machine_depth / 2) + for rect in self.disallowed_areas: + for corner in rect: + x = corner[0] + if x < mid_x and x > left_x: + left_x = x + if x > mid_x and x < right_x: + right_x = x + y = corner[1] + if y > mid_y and y < front_y: + front_y = y + if y < mid_y and y > back_y: + back_y = y + if self.origin_at_center: + self.machine_left = round(left_x + 1, 2) + self.machine_right = round(right_x - 1, 2) + self.machine_front = round(front_y - 1, 2) + self.machine_back = round(back_y + 1, 2) + else: + self.machine_left = round(left_x + 1 + self.machine_width / 2, 2) + self.machine_right = round(right_x - 1 + self.machine_width / 2, 2) + self.machine_front = round((self.machine_depth / 2) - front_y - 1, 2) + self.machine_back = round((self.machine_depth / 2) - back_y + 1 , 2) + else: + if self.origin_at_center: + self.machine_left = round(-(self.machine_width/2) + 1, 2) + self.machine_right = round((self.machine_width/2) - 1, 2) + self.machine_front = round(-(self.machine_depth/2) + 1, 2) + self.machine_back = round((self.machine_depth/2) - 1, 2) + else: + self.machine_left = 1 + self.machine_right = self.machine_width - 1 + self.machine_front = 1 + self.machine_back = self.machine_depth - 1 + return + # Add Purge Lines to the user defined position on the build plate - def _add_purge_lines(self, data: str): - curaApp = Application.getInstance().getGlobalContainerStack() - retract_dist = self._extruder[0].getProperty("retraction_amount", "value") - retract_enable = self._extruder[0].getProperty("retraction_enable", "value") - retract_speed = self._extruder[0].getProperty("retraction_retract_speed", "value") * 60 - bed_shape = str(curaApp.getProperty("machine_shape", "value")) - origin_at_center = bool(curaApp.getProperty("machine_center_is_zero", "value")) - machine_width = curaApp.getProperty("machine_width", "value") - machine_depth = curaApp.getProperty("machine_depth", "value") - material_diameter = self._extruder[0].getProperty("material_diameter", "value") + def _add_purge_lines(self, data_1: str): + retract_dist = self.extruder[0].getProperty("retraction_amount", "value") + retract_enable = self.extruder[0].getProperty("retraction_enable", "value") + retract_speed = self.extruder[0].getProperty("retraction_retract_speed", "value") * 60 + material_diameter = self.extruder[0].getProperty("material_diameter", "value") mm3_per_mm = (material_diameter / 2)**2 * 3.14159 - init_line_width = self._extruder[0].getProperty("skirt_brim_line_width", "value") + init_line_width = self.extruder[0].getProperty("skirt_brim_line_width", "value") where_at = self.getSettingValueByKey("purge_line_location") - travel_speed = self._extruder[0].getProperty("speed_travel", "value") * 60 - print_speed = round(self._extruder[0].getProperty("speed_print", "value") * 60 * .75) + print_speed = round(self.extruder[0].getProperty("speed_print", "value") * 60 * .75) purge_extrusion_full = True if self.getSettingValueByKey("purge_line_length") == "purge_full" else False purge_str = ";TYPE:CUSTOM----------[Purge Lines]\nG0 F600 Z2 ; Move up\nG92 E0 ; Reset extruder\n" # Normal cartesian printer with origin at the left front corner - if bed_shape == "rectangular" and not origin_at_center: + if self.bed_shape == "rectangular" and not self.origin_at_center: if where_at == "purge_left": - purge_len = int(machine_depth) - 20 if purge_extrusion_full else int(machine_depth / 2) - y_stop = int(machine_depth - 10) if purge_extrusion_full else int(machine_depth / 2) + purge_len = int(self.machine_back - 20) if purge_extrusion_full else int((self.machine_back - self.machine_front) / 2) + y_stop = int(self.machine_back - 10) if purge_extrusion_full else int(self.machine_depth / 2) purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) purge_str = purge_str.replace("Lines", "Lines at MinX") - purge_str += f"G0 F{travel_speed} X0 Y10 ; Move to start\n" + purge_str += f"G0 F{self.speed_travel} X{self.machine_left} Y{self.machine_front + 10} ; Move to start\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X0 Y{y_stop} E{purge_volume} ; First line\n" - purge_str += f"G0 X3 Y{y_stop} ; Move over\n" - purge_str += f"G1 F{print_speed} X3 Y10 E{round(purge_volume * 2,5)} ; Second line\n" + purge_str += f"G1 F{print_speed} X{self.machine_left} Y{y_stop} E{purge_volume} ; First line\n" + purge_str += f"G0 X{self.machine_left + 3} Y{y_stop} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_left + 3} Y{self.machine_front + 10} E{round(purge_volume * 2,5)} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist,5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait for 1 second\n" - purge_str += f"G0 F{print_speed} X3 Y20 Z0.3 ; Slide over and down\n" - purge_str += "G0 X3 Y35 ; Wipe\n" - self._purge_end_loc = "LF" + purge_str += f"G0 F{print_speed} X{self.machine_left + 3} Y{self.machine_front + 20} Z0.3 ; Slide over and down\n" + purge_str += f"G0 X{self.machine_left + 3} Y{self.machine_front + 35} ; Wipe\n" + self.start_location = "LF" elif where_at == "purge_right": - purge_len = int(machine_depth) - 20 if purge_extrusion_full else int(machine_depth / 2) - y_stop = 10 if purge_extrusion_full else int(machine_depth / 2) + purge_len = int(self.machine_depth - 20) if purge_extrusion_full else int((self.machine_back - self.machine_front) / 2) + y_stop = int(self.machine_front + 10) if purge_extrusion_full else int(self.machine_depth / 2) purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) purge_str = purge_str.replace("Lines", "Lines at MaxX") - purge_str += f"G0 F{travel_speed} X{machine_width} ; Move\nG0 Y{machine_depth - 10} ; Move\n" + purge_str += f"G0 F{self.speed_travel} X{self.machine_right} ; Move\nG0 Y{self.machine_back - 10} ; Move\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X{machine_width} Y{y_stop} E{purge_volume} ; First line\n" - purge_str += f"G0 X{machine_width - 3} Y{y_stop} ; Move over\n" - purge_str += f"G1 F{print_speed} X{machine_width - 3} Y{machine_depth - 10} E{purge_volume * 2} ; Second line\n" + purge_str += f"G1 F{print_speed} X{self.machine_right} Y{y_stop} E{purge_volume} ; First line\n" + purge_str += f"G0 X{self.machine_right - 3} Y{y_stop} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_right - 3} Y{self.machine_back - 10} E{purge_volume * 2} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist,5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait for 1 second\n" - purge_str += f"G0 F{print_speed} X{machine_width - 3} Y{machine_depth - 20} Z0.3 ; Slide over and down\n" - purge_str += f"G0 X{machine_width - 3} Y{machine_depth - 35} ; Wipe\n" - self._purge_end_loc = "RR" + purge_str += f"G0 F{print_speed} X{self.machine_right - 3} Y{self.machine_back - 20} Z0.3 ; Slide over and down\n" + purge_str += f"G0 X{self.machine_right - 3} Y{self.machine_back - 35} ; Wipe\n" + self.start_location = "RR" elif where_at == "purge_bottom": - purge_len = int(machine_width) - 20 if purge_extrusion_full else int(machine_width / 2) - x_stop = int(machine_width - 10) if purge_extrusion_full else int(machine_width / 2) + purge_len = int(self.machine_width) - 20 if purge_extrusion_full else int((self.machine_right - self.machine_left) / 2) + x_stop = int(self.machine_right - 10) if purge_extrusion_full else int(self.machine_width/2) purge_str = purge_str.replace("Lines", "Lines at MinY") purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) - purge_str += f"G0 F{travel_speed} X10 Y0 ; Move to start\n" + purge_str += f"G0 F{self.speed_travel} X{self.machine_left + 10} Y{self.machine_front} ; Move to start\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X{x_stop} Y0 E{purge_volume} ; First line\n" - purge_str += f"G0 X{x_stop} Y3 ; Move over\n" - purge_str += f"G1 F{print_speed} X10 Y3 E{purge_volume * 2} ; Second line\n" + purge_str += f"G1 F{print_speed} X{x_stop} Y{self.machine_front} E{purge_volume} ; First line\n" + purge_str += f"G0 X{x_stop} Y{self.machine_front + 3} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_left + 10} Y{self.machine_front + 3} E{purge_volume * 2} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist,5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait for 1 second\n" - purge_str += f"G0 F{print_speed} X20 Y3 Z0.3 ; Slide over and down\n" - purge_str += "G0 X35 Y3 ; Wipe\n" - self._purge_end_loc = "LF" + purge_str += f"G0 F{print_speed} X{self.machine_left + 20} Y{self.machine_front + 3} Z0.3 ; Slide over and down\n" + purge_str += f"G0 X{self.machine_left + 35} Y{self.machine_front + 3} ; Wipe\n" + self.start_location = "LF" elif where_at == "purge_top": - purge_len = int(machine_width - 20) if purge_extrusion_full else int(machine_width / 2) - x_stop = 10 if purge_extrusion_full else int(machine_width / 2) + purge_len = int(self.machine_width - 20) if purge_extrusion_full else int((self.machine_right - self.machine_left)/2) + x_stop = int(self.machine_left + 10) if purge_extrusion_full else int(self.machine_width/2) purge_str = purge_str.replace("Lines", "Lines at MaxY") - purge_len = int(machine_width) - 20 purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) - purge_str += f"G0 F{travel_speed} Y{machine_depth} ; Ortho Move to back\n" - purge_str += f"G0 X{machine_width - 10} ; Ortho move to start\n" + purge_str += f"G0 F{self.speed_travel} Y{self.machine_back} ; Ortho Move to back\n" + purge_str += f"G0 X{self.machine_right - 10} ; Ortho move to start\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X{x_stop} Y{machine_depth} E{purge_volume} ; First line\n" - purge_str += f"G0 X{x_stop} Y{machine_depth - 3} ; Move over\n" - purge_str += f"G1 F{print_speed} X{machine_width - 10} Y{machine_depth - 3} E{purge_volume * 2} ; Second line\n" + purge_str += f"G1 F{print_speed} X{x_stop} Y{self.machine_back} E{purge_volume} ; First line\n" + purge_str += f"G0 X{x_stop} Y{self.machine_back - 3} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_right - 10} Y{self.machine_back - 3} E{purge_volume * 2} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist,5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait 1 second\n" - purge_str += f"G0 F{print_speed} X{machine_width - 20} Y{machine_depth - 3} Z0.3 ; Slide over and down\n" - purge_str += f"G0 X{machine_width - 35} Y{machine_depth - 3} ; Wipe\n" - self._purge_end_loc = "RR" + purge_str += f"G0 F{print_speed} X{self.machine_right - 20} Y{self.machine_back - 3} Z0.3 ; Slide over and down\n" + purge_str += f"G0 X{self.machine_right - 35} Y{self.machine_back - 3} ; Wipe\n" + self.start_location = "RR" - # Some cartesian printers (BIBO, Weedo, etc.) are Origin at Center - elif bed_shape == "rectangular" and origin_at_center: + # Some cartesian printers (BIBO, Weedo, MethodX, etc.) are Origin at Center + elif self.bed_shape == "rectangular" and self.origin_at_center: if where_at == "purge_left": - purge_len = int(machine_depth - 20) if purge_extrusion_full else int(machine_depth / 2) - y_stop = int((machine_depth / 2) - 10) if purge_extrusion_full else 0 + purge_len = int(self.machine_back - self.machine_front-20) if purge_extrusion_full else abs(int(self.machine_front - 10)) + y_stop = int(self.machine_back - 10) if purge_extrusion_full else 0 purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) - purge_str += f"G0 F{travel_speed} X-{machine_width / 2} Y-{(machine_depth / 2) - 10} ; Move to start\n" + purge_str += f"G0 F{self.speed_travel} X{self.machine_left} Y{self.machine_front + 10} ; Move to start\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X-{machine_width / 2} Y{y_stop} E{purge_volume} ; First line\n" - purge_str += f"G0 X-{(machine_width / 2) - 3} Y{y_stop} ; Move over\n" - purge_str += f"G1 F{print_speed} X-{(machine_width / 2) - 3} Y-{(machine_depth / 2) - 10} E{round(purge_volume * 2, 5)} ; Second line\n" + purge_str += f"G1 F{print_speed} X{self.machine_left} Y{y_stop} E{purge_volume} ; First line\n" + purge_str += f"G0 X{self.machine_left + 3} Y{y_stop} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_left + 3} Y{self.machine_front + 10} E{round(purge_volume * 2, 5)} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist, 5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait for 1 second\n" - purge_str += f"G0 F{print_speed} X-{(machine_width / 2) - 3} Y-{(machine_depth / 2) - 20} Z0.3 ; Slide over and down\n" - purge_str += f"G0 X-{(machine_width / 2) - 3} Y-{(machine_depth / 2) - 35} ; Wipe\n" - self._purge_end_loc = "LF" + purge_str += f"G0 F{print_speed} X{self.machine_left + 3} Y{self.machine_front + 20} Z0.3 ; Slide over and down\n" + purge_str += f"G0 X{self.machine_left + 3} Y{self.machine_front + 35} ; Wipe\n" + self.start_location = "LF" elif where_at == "purge_right": - purge_len = int(machine_depth - 20) if purge_extrusion_full else int(machine_depth / 2) - y_stop = int((machine_depth / 2) - 10) if purge_extrusion_full else 0 + purge_len = int(self.machine_back - 20) if purge_extrusion_full else int((self.machine_back - self.machine_front)/2) + y_stop = int(self.machine_front + 10) if purge_extrusion_full else 0 purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) - purge_str += f"G0 F{travel_speed} X{machine_width / 2} Z2 ; Move\nG0 Y{(machine_depth / 2) - 10} Z2 ; Move to start\n" + purge_str += f"G0 F{self.speed_travel} X{self.machine_right} Z2 ; Move\nG0 Y{self.machine_back - 10} Z2 ; Move to start\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X{machine_width / 2} Y-{y_stop} E{purge_volume} ; First line\n" - purge_str += f"G0 X{(machine_width / 2) - 3} Y-{y_stop} ; Move over\n" - purge_str += f"G1 F{print_speed} X{(machine_width / 2) - 3} Y{(machine_depth / 2) - 10} E{purge_volume * 2} ; Second line\n" + purge_str += f"G1 F{print_speed} X{self.machine_right} Y{y_stop} E{purge_volume} ; First line\n" + purge_str += f"G0 X{self.machine_right - 3} Y{y_stop} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_right - 3} Y{self.machine_back - 10} E{purge_volume * 2} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist,5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait for 1 second\n" - purge_str += f"G0 F{print_speed} X{(machine_width / 2) - 3} Y{(machine_depth / 2) - 20} Z0.3 ; Slide over and down\n" - purge_str += f"G0 F{travel_speed} X{(machine_width / 2) - 3} Y{(machine_depth / 2) - 35} ; Wipe\n" - self._purge_end_loc = "RR" + purge_str += f"G0 F{print_speed} X{self.machine_right - 3} Y{self.machine_back - 20} Z0.3 ; Slide over and down\n" + purge_str += f"G0 F{self.speed_travel} X{self.machine_right - 3} Y{self.machine_back - 35} ; Wipe\n" + self.start_location = "RR" elif where_at == "purge_bottom": - purge_len = int(machine_width - 20) if purge_extrusion_full else int(machine_width / 2) - x_stop = int((machine_width / 2) - 10) if purge_extrusion_full else 0 + purge_len = int(self.machine_right - self.machine_left - 20) if purge_extrusion_full else int((self.machine_right - self.machine_left) / 2) + x_stop = int(self.machine_right - 10) if purge_extrusion_full else 0 purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) - purge_str += f"G0 F{travel_speed} X-{machine_width / 2 - 10} Z2 ; Move\nG0 Y-{machine_depth / 2} Z2 ; Move to start\n" + purge_str += f"G0 F{self.speed_travel} X{self.machine_left + 10} Z2 ; Move\nG0 Y{self.machine_front} Z2 ; Move to start\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X{x_stop} Y-{machine_depth / 2} E{purge_volume} ; First line\n" - purge_str += f"G0 X{x_stop} Y-{machine_depth / 2 - 3} ; Move over\n" - purge_str += f"G1 F{print_speed} X-{machine_width / 2 - 10} Y-{machine_depth / 2 - 3} E{purge_volume * 2} ; Second line\n" + purge_str += f"G1 F{print_speed} X{x_stop} Y{self.machine_front} E{purge_volume} ; First line\n" + purge_str += f"G0 X{x_stop} Y{self.machine_front + 3} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_left + 10} Y{self.machine_front + 3} E{purge_volume * 2} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist,5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait for 1 second\n" - purge_str += f"G0 F{print_speed} X-{(machine_width / 2) - 20} Y-{(machine_depth / 2) - 3} Z0.3 ; Slide over and down\n" - purge_str += f"G0 F{print_speed} X-{(machine_width / 2) - 35} Y-{(machine_depth / 2) - 3} ; Wipe\n" - self._purge_end_loc = "LF" + purge_str += f"G0 F{print_speed} X{self.machine_left + 20} Y{self.machine_front + 3} Z0.3 ; Slide over and down\n" + purge_str += f"G0 F{print_speed} X{self.machine_left + 35} Y{self.machine_front + 3} ; Wipe\n" + self.start_location = "LF" elif where_at == "purge_top": - purge_len = int(machine_width - 20) if purge_extrusion_full else int(machine_width / 2) - x_stop = int((machine_width / 2) - 10) if purge_extrusion_full else 0 + purge_len = int(self.machine_right - self.machine_left - 20) if purge_extrusion_full else abs(int(self.machine_right - 10)) + x_stop = int(self.machine_left + 10) if purge_extrusion_full else 0 purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) - purge_str += f"G0 F{travel_speed} Y{machine_depth / 2} Z2; Ortho Move to back\n" - purge_str += f"G0 X{machine_width / 2 - 10} Z2 ; Ortho Move to start\n" + purge_str += f"G0 F{self.speed_travel} Y{self.machine_back} Z2; Ortho Move to back\n" + purge_str += f"G0 X{self.machine_right - 10} Z2 ; Ortho Move to start\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" - purge_str += f"G1 F{print_speed} X-{x_stop} Y{machine_depth / 2} E{purge_volume} ; First line\n" - purge_str += f"G0 X-{x_stop} Y{machine_depth / 2 - 3} ; Move over\n" - purge_str += f"G1 F{print_speed} X{machine_width / 2 - 10} Y{machine_depth / 2 - 3} E{purge_volume * 2} ; Second line\n" + purge_str += f"G1 F{print_speed} X{x_stop} Y{self.machine_back} E{purge_volume} ; First line\n" + purge_str += f"G0 X{x_stop} Y{self.machine_back - 3} ; Move over\n" + purge_str += f"G1 F{print_speed} X{self.machine_right - 10} Y{self.machine_back - 3} E{purge_volume * 2} ; Second line\n" purge_str += f"G1 F{int(retract_speed)} E{round(purge_volume * 2 - retract_dist,5)} ; Retract\n" if retract_enable else "" purge_str += "G0 F600 Z8 ; Move Up\nG4 S1 ; Wait for 1 second\n" - purge_str += f"G0 F{print_speed} X{machine_width / 2 - 20} Y{machine_depth / 2 - 3} Z0.3 ; Slide over and down\n" - purge_str += f"G0 F{print_speed} X{machine_width / 2 - 35} Y{machine_depth / 2 - 3} ; Wipe\n" - self._purge_end_loc = "RR" + purge_str += f"G0 F{print_speed} X{self.machine_right - 20} Y{self.machine_back - 3} Z0.3 ; Slide over and down\n" + purge_str += f"G0 F{print_speed} X{self.machine_right - 35} Y{self.machine_back - 3} ; Wipe\n" + self.start_location = "RR" # Elliptic printers with Origin at Center - elif bed_shape == "elliptic": + elif self.bed_shape == "elliptic": if where_at in ["purge_left","purge_right"]: - radius_1 = round((machine_width / 2) - 1,2) + radius_1 = round((self.machine_width / 2) - 1,2) elif where_at in ["purge_bottom", "purge_top"]: - radius_1 = round((machine_depth / 2) - 1,2) + radius_1 = round((self.machine_depth / 2) - 1,2) purge_len = int(radius_1) * 3.14159 / 4 purge_volume = round((init_line_width * 0.3 * purge_len) * 1.25 / mm3_per_mm, 5) if where_at == "purge_left": - purge_str += f"G0 F{travel_speed} X-{round(radius_1 * .707, 2)} Y-{round(radius_1 * .707,2)} ; Travel\n" + purge_str += f"G0 F{self.speed_travel} X-{round(radius_1 * .707, 2)} Y-{round(radius_1 * .707,2)} ; Travel\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" purge_str += f"G2 F{print_speed} X-{round(radius_1 * .707,2)} Y{round(radius_1 * .707,2)} I{round(radius_1 * .707,2)} J{round(radius_1 * .707,2)} E{purge_volume} ; First Arc\n" purge_str += f"G0 X-{round((radius_1 - 3) * .707,2)} Y{round((radius_1 - 3) * .707,2)} ; Move Over\n" @@ -310,9 +517,9 @@ def _add_purge_lines(self, data: str): purge_str += "G0 F600 Z5 ; Move Up\nG4 S1 ; Wait 1 Second\n" purge_str += f"G0 F{print_speed} X-{round((radius_1 - 3) * .707 - 15,2)} Z0.3 ; Slide Over\n" purge_str += f"G0 F{print_speed} X-{round((radius_1 - 3) * .707,2)} ; Wipe\n" - self.purge_end_loc = "LF" + self.start_location = "LF" elif where_at == "purge_right": - purge_str += f"G0 F{travel_speed} X{round(radius_1 * .707, 2)} Y-{round(radius_1 * .707,2)} ; Travel\n" + purge_str += f"G0 F{self.speed_travel} X{round(radius_1 * .707, 2)} Y-{round(radius_1 * .707,2)} ; Travel\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" purge_str += f"G3 F{print_speed} X{round(radius_1 * .707,2)} Y{round(radius_1 * .707,2)} I-{round(radius_1 * .707,2)} J{round(radius_1 * .707,2)} E{purge_volume} ; First Arc\n" purge_str += f"G0 X{round((radius_1 - 3) * .707,2)} Y{round((radius_1 - 3) * .707,2)} ; Move Over\n" @@ -322,9 +529,9 @@ def _add_purge_lines(self, data: str): purge_str += "G0 F600 Z5 ; Move Up\nG4 S1 ; Wait 1 Second\n" purge_str += f"G0 F{print_speed} X{round((radius_1 - 3) * .707 - 15,2)} Z0.3 ; Slide Over\n" purge_str += f"G0 F{print_speed} X{round((radius_1 - 3) * .707,2)}\n" - self.purge_end_loc = "RR" + self.start_location = "RR" elif where_at == "purge_bottom": - purge_str += f"G0 F{travel_speed} X-{round(radius_1 * .707, 2)} Y-{round(radius_1 * .707,2)} ; Travel\n" + purge_str += f"G0 F{self.speed_travel} X-{round(radius_1 * .707, 2)} Y-{round(radius_1 * .707,2)} ; Travel\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" purge_str += f"G3 F{print_speed} X{round(radius_1 * .707,2)} Y-{round(radius_1 * .707,2)} I{round(radius_1 * .707,2)} J{round(radius_1 * .707,2)} E{purge_volume} ; First Arc\n" purge_str += f"G0 X{round((radius_1 - 3) * .707,2)} Y-{round((radius_1 - 3) * .707,2)} ; Move Over\n" @@ -334,9 +541,9 @@ def _add_purge_lines(self, data: str): purge_str += "G0 F600 Z5 ; Move Up\nG4 S1 ; Wait 1 Second\n" purge_str += f"G0 F{print_speed} Y-{round((radius_1 - 3) * .707 - 15,2)} Z0.3 ; Slide Over\n" purge_str += f"G0 F{print_speed} Y-{round((radius_1 - 3) * .707,2)}\n" - self.purge_end_loc = "LF" + self.start_location = "LF" elif where_at == "purge_top": - purge_str += f"G0 F{travel_speed} X{round(radius_1 * .707, 2)} Y{round(radius_1 * .707,2)} ; Travel\n" + purge_str += f"G0 F{self.speed_travel} X{round(radius_1 * .707, 2)} Y{round(radius_1 * .707,2)} ; Travel\n" purge_str += f"G0 F600 Z0.3 ; Move down\n" purge_str += f"G3 F{print_speed} X-{round(radius_1 * .707,2)} Y{round(radius_1 * .707,2)} I-{round(radius_1 * .707,2)} J-{round(radius_1 * .707,2)} E{purge_volume} ; First Arc\n" purge_str += f"G0 X-{round((radius_1 - 3) * .707,2)} Y{round((radius_1 - 3) * .707,2)} ; Move Over\n" @@ -346,19 +553,15 @@ def _add_purge_lines(self, data: str): purge_str += "G0 F600 Z5\nG4 S1\n" purge_str += f"G0 F{print_speed} Y{round((radius_1 - 3) * .707 - 15,2)} Z0.3 ; Slide Over\n" purge_str += f"G0 F{print_speed} Y{round((radius_1 - 3) * .707,2)}\n" - self.purge_end_loc = "RR" + self.start_location = "RR" # Common ending for purge_str purge_str += "G0 F600 Z2 ; Move Z\n;---------------------[End of Purge]" - # If there is a move to the prime tower location after purging then it needs to be accounted for - if curaApp.getProperty("machine_extruder_count", "value") > 1: - data[1] = self._move_to_prime_tower(data[1], bed_shape, origin_at_center, machine_width, machine_depth, travel_speed) - - # Comment out any existing purge lines in Data[1] - startup = data[1].split("\n") + # Comment out any existing purge lines in data_1 + startup = data_1[1].split("\n") for index, line in enumerate(startup): - if line.startswith("G1") and " E" in line and (" X" in line or " Y" in line): + if "G1"in line and " E" in line and (" X" in line or " Y" in line): next_line = index try: while not startup[next_line].startswith ("G92 E0"): @@ -366,11 +569,12 @@ def _add_purge_lines(self, data: str): next_line += 1 except: break - data[1] = "\n".join(startup) + data_1[1] = "\n".join(startup) - # Find the insertion location in data[1] + # Find the insertion location in data_1 purge_str = self._format_string(purge_str) - startup_section = data[1].split("\n") + startup_section = data_1[1].split("\n") + insert_index = len(startup_section)-1 for num in range(len(startup_section) - 1, 0, -1): # In Absolute Extrusion mode - insert above the last G92 E0 line if "G92 E0" in startup_section[num]: @@ -381,21 +585,14 @@ def _add_purge_lines(self, data: str): insert_index = num break startup_section.insert(insert_index, purge_str) - data[1] = "\n".join(startup_section) - return + data_1[1] = "\n".join(startup_section) + return data_1 # Travel moves around the bed periphery to keep strings from crossing the footprint of the model. def _move_to_start(self, data: str) -> str: - curaApp = Application.getInstance().getGlobalContainerStack() - bed_shape = str(curaApp.getProperty("machine_shape", "value")) - origin_at_center = bool(curaApp.getProperty("machine_center_is_zero", "value")) - machine_width = curaApp.getProperty("machine_width", "value") - machine_depth = curaApp.getProperty("machine_depth", "value") - if curaApp.getProperty("machine_extruder_count", "value") > 1: - self._purge_end_loc = self._get_real_start_point(data[1], bed_shape, origin_at_center, machine_width, machine_depth) - layer = data[2].split("\n") start_x = None start_y = None + layer = data[2].split("\n") for line in layer: if line.startswith("G0") and " X" in line and " Y" in line: start_x = self.getValue(line, "X") @@ -403,15 +600,12 @@ def _move_to_start(self, data: str) -> str: break if start_x == None: start_x = 0 if start_y == None: start_y = 0 - if self._purge_end_loc == None: - purge_end_loc = "LF" - else: - purge_end_loc = self._purge_end_loc - travel_speed = round(self._extruder[0].getProperty("speed_travel", "value") * 60) + if self.start_location == None: + self.start_location = "LF" move_str = f";MESH:NONMESH---------[Travel to Layer Start]\nG0 F600 Z2 ; Move up\n" - midpoint_x = machine_width / 2 - midpoint_y = machine_depth / 2 - if not origin_at_center: + midpoint_x = self.machine_width / 2 + midpoint_y = self.machine_depth / 2 + if not self.origin_at_center: if float(start_x) <= float(midpoint_x): goto_str = "Lt" else: @@ -430,136 +624,131 @@ def _move_to_start(self, data: str) -> str: else: goto_str += "Bk" - # If purge lines was not selected, and the printer is multi-extruder, there may be a move to the purge tower that needs to be considered - if not self.getSettingValueByKey("add_purge_lines"): - if curaApp.getProperty("machine_extruder_count", "value") > 1: - data[1] = self._move_to_prime_tower(data[1], bed_shape, origin_at_center, machine_width, machine_depth, travel_speed) - # Depending on which quadrant the XY layer start is, move around the periphery before coming in to the start position - if bed_shape == "rectangular" and not origin_at_center: - if purge_end_loc == "LF": + if self.bed_shape == "rectangular" and not self.origin_at_center: + if self.start_location == "LF": if goto_str == "LtFrt": - move_str += f"G0 F{travel_speed} X5 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y5 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_front + 5} ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtFrt": - move_str += f"G0 F{travel_speed} X5 Z2; Ortho Move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_left + 5} Z2; Ortho Move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y5 Z2 ; Ortho Move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_front + 5} Z2 ; Ortho Move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} X{start_x} ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{start_x} ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "LtBk": - move_str += f"G0 F{travel_speed} X5 ; Ortho Move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_left + 5} ; Ortho Move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y5 Z2 ; Move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_front + 5} Z2 ; Move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y{start_y} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{start_y} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtBk": - move_str += f"G0 F{travel_speed} X5 ; Move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_left + 5} ; Move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y5 Z2 ; Move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_front + 5} Z2 ; Move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} X{machine_width - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y{start_y} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{start_y} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - elif purge_end_loc == "RR": + elif self.start_location == "RR": if goto_str == "LtFrt": - move_str += f"G0 F{travel_speed} X5 Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_left + 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y5 Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_front + 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtFrt": - move_str += f"G0 F{travel_speed} X{start_x} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{start_x} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y5 Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_front + 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "LtBk": - move_str += f"G0 F{travel_speed} X5 Z2 ; Move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_left + 5} Z2 ; Move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtBk": - move_str += f"G0 F{travel_speed} X{machine_width - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y{start_y} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{start_y} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - elif bed_shape == "rectangular" and origin_at_center: - if purge_end_loc == "LF": + elif self.bed_shape == "rectangular" and self.origin_at_center: + if self.start_location == "LF": if goto_str == "LtFrt": - move_str += f"G0 F{travel_speed} X-{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_left + 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y-{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtFrt": - move_str += f"G0 F{travel_speed} X{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y-{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "LtBk": - move_str += f"G0 F{travel_speed} X-{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtBk": - move_str += f"G0 F{travel_speed} X{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - elif purge_end_loc == "RR": + elif self.start_location == "RR": if goto_str == "LtFrt": - move_str += f"G0 F{travel_speed} X{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y-{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtFrt": - move_str += f"G0 F{travel_speed} X{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y-{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "LtBk": - move_str += f"G0 F{travel_speed} X-{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" elif goto_str == "RtBk": - move_str += f"G0 F{travel_speed} X{machine_width / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{self.machine_right - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - move_str += f"G0 F{travel_speed} Y{machine_depth / 2 - 5} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} Y{self.machine_back - 5} Z2 ; Ortho move\n" move_str += f"G0 F600 Z0 ; Nail down the string\nG0 Z2 ; Move up\n" - elif bed_shape == "elliptic" and origin_at_center: - radius = machine_width / 2 + elif self.bed_shape == "elliptic" and self.origin_at_center: + radius = self.machine_width / 2 offset_sin = round(2**.5 / 2 * radius, 2) - if purge_end_loc == "LR": + if self.start_location == "LR": if goto_str == "LtFrt": - move_str += f"G0 F{travel_speed} X-{offset_sin} Z2 ; Move\nG0 Y-{offset_sin} Z2 ; Move to start\n" + move_str += f"G0 F{self.speed_travel} X-{offset_sin} Z2 ; Move\nG0 Y-{offset_sin} Z2 ; Move to start\n" elif goto_str == "LtBk": move_str += f"G2 X0 Y{offset_sin} I{offset_sin} J{offset_sin} ; Move around to start\n" elif goto_str == "RtFrt": - move_str += f"G0 F{travel_speed} X{offset_sin} Z2 ; Ortho move\nG0 Y-{offset_sin} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{offset_sin} Z2 ; Ortho move\nG0 Y-{offset_sin} Z2 ; Ortho move\n" elif goto_str == "RtBk": - move_str += f"G0 F{travel_speed} X{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" - elif purge_end_loc == "RR": + move_str += f"G0 F{self.speed_travel} X{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" + elif self.start_location == "RR": if goto_str == "LtFrt": - move_str += f"G0 F{travel_speed} X-{offset_sin} Z2 ; Move\nG0 Y-{offset_sin} Z2 ; Move to start\n" + move_str += f"G0 F{self.speed_travel} X-{offset_sin} Z2 ; Move\nG0 Y-{offset_sin} Z2 ; Move to start\n" elif goto_str == "LtBk": - move_str += f"G0 F{travel_speed} X-{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X-{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" elif goto_str == "RtFrt": - move_str += f"G0 F{travel_speed} X{offset_sin} Z2 ; Ortho move\nG0 Y-{offset_sin} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{offset_sin} Z2 ; Ortho move\nG0 Y-{offset_sin} Z2 ; Ortho move\n" elif goto_str == "RtBk": - move_str += f"G0 F{travel_speed} X{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" - elif purge_end_loc == "LF": + move_str += f"G0 F{self.speed_travel} X{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" + elif self.start_location == "LF": if goto_str == "LtFrt": - move_str += f"G0 F{travel_speed} X-{offset_sin} Z2 ; Move\nG0 Y-{offset_sin} Z2 ; Move to start\n" + move_str += f"G0 F{self.speed_travel} X-{offset_sin} Z2 ; Move\nG0 Y-{offset_sin} Z2 ; Move to start\n" elif goto_str == "LtBk": - move_str += f"G0 F{travel_speed} X-{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X-{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" elif goto_str == "RtFrt": - move_str += f"G0 F{travel_speed} X{offset_sin} Z2 ; Ortho move\nG0 Y-{offset_sin} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{offset_sin} Z2 ; Ortho move\nG0 Y-{offset_sin} Z2 ; Ortho move\n" elif goto_str == "RtBk": - move_str += f"G0 F{travel_speed} X{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" + move_str += f"G0 F{self.speed_travel} X{offset_sin} Z2 ; Ortho move\nG0 Y{offset_sin} Z2 ; Ortho move\n" move_str += ";---------------------[End of layer start travels]" # Add the move_str to the end of the StartUp section and move 'LAYER_COUNT' to the end. startup = data[1].split("\n") @@ -577,15 +766,24 @@ def _move_to_start(self, data: str) -> str: data[1] = data[1].replace("\n\n", "\n") return - # Unloading a large amount of filament in a single command can trip the 'Overlong Extrusion' warning in some firmware. Unloads longer than 150mm are split into chunks. + # Unloading a large amount of filament in a single command can trip the 'Overlong Extrusion' warning in some firmware. Unloads longer than 150mm are split into individual 150mm segments. def _unload_filament(self, data: str) -> str: extrude_speed = 3000 + quick_purge_speed = 240 + retract_amount = self.extruder[0].getProperty("retraction_amount", "value") + if retract_amount < 2.0: + quick_purge_amount = retract_amount + 5 + else: + quick_purge_amount = retract_amount * 2 unload_distance = self.getSettingValueByKey("unload_distance") + quick_purge = self.getSettingValueByKey("unload_quick_purge") lines = data[len(data) - 1].split("\n") for index, line in enumerate(lines): # Unload the filament just before the hot end turns off. if line.startswith("M104") and "S0" in line: filament_str = "M83 ; [Unload] Relative extrusion\nM400 ; Complete all moves\n" + if quick_purge: + filament_str += f"G1 F{quick_purge_speed} E{quick_purge_amount} ; Quick Purge before unload\n" if unload_distance > 150: temp_unload = unload_distance while temp_unload > 150: @@ -602,14 +800,13 @@ def _unload_filament(self, data: str) -> str: # Make an adjustment to the starting E location so the skirt/brim/raft starts out when the nozzle starts out. def _adjust_starting_e(self, data: str) -> str: - curaApp = Application.getInstance().getGlobalContainerStack() - retract_enabled = self._extruder[0].getProperty("retraction_enable", "value") + retract_enabled = self.extruder[0].getProperty("retraction_enable", "value") if not retract_enabled: return adjust_amt = self.getSettingValueByKey("adjust_e_loc_to") lines = data[1].split("\n") lines.reverse() - if curaApp.getProperty("machine_firmware_retract", "value"): + if self.curaApp.getProperty("machine_firmware_retract", "value"): search_pattern = "G10" else: search_pattern = "G1 F(\d*) E-(\d.*)" @@ -637,116 +834,4 @@ def _format_string(self, any_gcode_str: str): elif temp_line.startswith(";") and ";" in temp_line[1:]: temp_lines[temp_index] = temp_line[1:].replace(temp_line[1:].split(";")[0], ";" + temp_line[1:].split(";")[0] + str(" " * (gap_len - 1 - len(temp_line[1:].split(";")[0]))),1) any_gcode_str = "\n".join(temp_lines) - return any_gcode_str - - # Get the actual layer start point of the print before adding movements - def _get_real_start_point(self, first_section: str, bed_shape: str, origin_at_center: bool, machine_width: int, machine_depth: int): - startup = first_section.split("\n") - last_line = startup[len(startup) - 1] - last_x = None - if last_line[:3] in ("G0 ", "G1 ") and " X" in last_line and " Y" in last_line: - last_x = self.getValue(last_line, "X") - last_y = self.getValue(last_line, "Y") - if last_x == None: - return self._purge_end_loc - else: - if bed_shape == "rectangular" and not origin_at_center: - midpoint_x = machine_width / 2 - midpoint_y = machine_depth / 2 - elif bed_shape in ("rectangular", "elliptic") and origin_at_center: - midpoint_x = 0 - midpoint_y = 0 - if last_x < midpoint_x and last_y < midpoint_y: - return "LF" - if last_x > midpoint_x and last_y < midpoint_y: - return "RF" - if last_x > midpoint_x and last_y > midpoint_y: - return "RR" - if last_x < midpoint_x and last_y > midpoint_y: - return "LR" - - # Multi-extruders may get a move to the prime tower just before layer 0 starts. The adjusted lines move around the periphery instead of across the middle. - def _get_adjustment_lines(self, prime_tower_loc: str, purge_end_loc: str, bed_shape: str, origin_at_center: bool, machine_width: int, machine_depth: int, travel_speed: int): - adj_lines = "" - if not origin_at_center: - midpoint_x = machine_width / 2 - midpoint_y = machine_depth / 2 - max_x = machine_width - 7 - min_x = 7 - max_y = machine_depth - 7 - min_y = 7 - elif origin_at_center: - midpoint_x = 0 - midpoint_y = 0 - max_x = (machine_width / 2) - 7 - min_x = -abs((machine_width / 2) - 7) - max_y = (machine_depth / 2) - 7 - min_y = -abs((machine_depth / 2) - 7) - if purge_end_loc == "LF": - if prime_tower_loc == "LF": - adj_lines = "" - if prime_tower_loc == "RF": - adj_lines = f"G0 F{travel_speed} X{max_x} ; Move to edge\nG0 F600 Z0 ; nail down the string\nG0 F600 Z2 ; move up\n" - if prime_tower_loc == "RR": - adj_lines = f"G0 F{travel_speed} X{max_x} ; Move to edge\nG0 F600 Z0 ; nail down the string\nG0 F600 Z2 ; move up\n" - if prime_tower_loc == "LR": - adj_lines = f"G0 F{travel_speed} Y{max_y} ; Move to edge\nG0 F600 Z0 ; nail down the string\nG0 F600 Z2 ; move up\n" - elif purge_end_loc == "RR": - if prime_tower_loc == "LF": - adj_lines = f"G0 F{travel_speed} X{min_x} ; Move to edge\nG0 F600 Z0 ; nail down the string\nG0 F600 Z2 ; move up\n" - if prime_tower_loc == "RF": - adj_lines = f"G0 F{travel_speed} Y{min_y} ; Move to edge\nG0 F600 Z0 ; nail down the string\nG0 F600 Z2 ; move up\n" - if prime_tower_loc == "RR": - adj_lines = "" - if prime_tower_loc == "LR": - adj_lines = f"G0 F{travel_speed} X{min_x} ; Move to edge\nG0 F600 Z0 ; nail down the string\nG0 F600 Z2 ; move up\n" - return adj_lines - - # Determine the quadrant that the prime tower rests in so the adjustments can be calculated - def _prime_tower_quadrant(self, prime_tower_x, prime_tower_y, bed_shape, origin_at_center, machine_width, machine_depth): - if not origin_at_center: - midpoint_x = machine_width / 2 - midpoint_y = machine_depth / 2 - max_x = machine_width - 7 - min_x = 7 - max_y = machine_depth - 7 - min_y = 7 - elif origin_at_center: - midpoint_x = 0 - midpoint_y = 0 - max_x = (machine_width / 2) - 7 - min_x = -abs((machine_width / 2) - 7) - max_y = (machine_depth / 2) - 7 - min_y = -abs((machine_depth / 2) - 7) - if prime_tower_x < midpoint_x and prime_tower_y < midpoint_y: - prime_tower_location = "LF" - elif prime_tower_x > midpoint_x and prime_tower_y < midpoint_y: - prime_tower_location = "RF" - elif prime_tower_x > midpoint_x and prime_tower_y > midpoint_y: - prime_tower_location = "RR" - elif prime_tower_x < midpoint_x and prime_tower_y > midpoint_y: - prime_tower_location = "LR" - return prime_tower_location - - # For some multi-extruder printers. Takes into account a 'Move to Prime Tower' if there is one and adds orthononal travel moves to get there. - def _move_to_prime_tower(self, startup_gcode: str, bed_shape: str, origin_at_center: bool, machine_width: int, machine_depth: int, travel_speed: int): - adjustment_lines = "" - curaApp = Application.getInstance().getGlobalContainerStack() - prime_tower_x = curaApp.getProperty("prime_tower_position_x", "value") - prime_tower_y = curaApp.getProperty("prime_tower_position_y", "value") - prime_tower_loc = self._prime_tower_quadrant(prime_tower_x, prime_tower_y, bed_shape, origin_at_center, machine_width, machine_depth) - if self._purge_end_loc == None: - self._purge_end_loc = "LF" - if prime_tower_loc != self._purge_end_loc: - startup = startup_gcode.split("\n") - for index, line in enumerate(startup): - if ";LAYER_COUNT:" in line: - try: - if startup[index + 1].startswith("G0"): - prime_move = startup[index + 1] + " ; move to Prime Tower" - adjustment_lines = self._get_adjustment_lines(prime_tower_loc, self._purge_end_loc, bed_shape, origin_at_center, machine_width, machine_depth, travel_speed) - startup[index + 1] = adjustment_lines + prime_move - startup_gcode = "\n".join(startup) - except: - pass - return startup_gcode \ No newline at end of file + return any_gcode_str \ No newline at end of file