def purge_create_layers(x, y, w, h): global solidlayer, emptylayer, filllayer solidlayer = [] emptylayer = [] filllayer = [] ew = v.extrusion_width if ew == 0: ew = 0.45 gui.log_warning("Extrusion Width of 0 detected, using default 0.45mm") w = int(w / ew) * ew h = int(h / ew) * ew solidlayer.append(gcode.create_command(";---- SOLID WIPE -------")) generate_rectangle(solidlayer, x, y, w, h) emptylayer.append(gcode.create_command(";---- EMPTY WIPE -------")) generate_rectangle(emptylayer, x, y, w, h) filllayer.append(gcode.create_command(";---- FILL LAYER -------")) generate_rectangle(filllayer, x, y, w, h) _purge_create_sequence(solidlayer, "G1 X{:.3f} Y{:.3f} F%SPEED%", x, y, w, h, ew) _purge_create_sequence(emptylayer, "G1 Y{:.3f} X{:.3f} F%SPEED%", y, x, h, w, 2) _purge_create_sequence(filllayer, "G1 Y{:.3f} X{:.3f} F%SPEED%", y, x, h, w, 15) _purge_generate_tower_brim(x, y, w, h) _purge_calculate_sequences_length() v.purge_sequence_x = x v.purge_sequence_y = y
def _purge_create_sequence(code, pformat, x, y, w, h, step1): generate_front = False ew = v.extrusion_width cw = w - 4 * ew start1 = x + 2 * ew + (cw % step1) / 2 end1 = x + 2 * ew + cw - (cw % step1) / 2 start2 = y + 2 * ew - ew * 0.15 end2 = y + h - 2 * ew + ew * 0.15 code.append(gcode.create_command(pformat.format(start1, start2))) pformat = (pformat + " E{:.4f}") while start1 < end1: if generate_front: code.append(gcode.create_command(pformat.format(start1, start2, calculate_purge(step1)))) else: generate_front = True code.append(gcode.create_command(pformat.format(start1, end2, calculate_purge(end2 - start2)))) start1 += step1 if start1 < end1: code.append(gcode.create_command(pformat.format(start1, end2, calculate_purge(step1)))) code.append(gcode.create_command(pformat.format(start1, start2, calculate_purge(end2 - start2)))) start1 += step1
def generate_rectangle(result, x, y, w, h): ew = v.extrusion_width x2 = x + w y2 = y + h result.append(gcode.create_command("G1 X{:.3f} Y{:.3f} F8640".format(x, y))) result.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format(x2, y, calculate_purge(w)))) result.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format(x2, y2, calculate_purge(h)))) result.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format(x, y2, calculate_purge(w)))) result.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format(x, y, calculate_purge(h)))) result.append(gcode.create_command("G1 X{:.3f} Y{:.3f} F8640".format(x + ew, y + ew))) result.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f}".format(x2 - ew, y + ew, calculate_purge(w - 2 * ew)))) result.append( gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format(x2 - ew, y2 - ew, calculate_purge(h - 2 * ew)))) result.append( gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format(x + ew, y2 - ew, calculate_purge(w - 2 * ew)))) result.append( gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format(x + ew, y + ew, calculate_purge(h - 2 * ew))))
def find_alternative_tower(): v.wipe_tower_info_maxx = v.wipe_tower_posx v.wipe_tower_info_minx = v.wipe_tower_posx v.wipe_tower_info_maxy = v.wipe_tower_posy v.wipe_tower_info_miny = v.wipe_tower_posy if v.wipe_tower_posx and v.wipe_tower_posy: state = 0 for i in range(len(v.input_gcode)): line = v.input_gcode[i] if line.startswith(";"): if line.startswith(";TYPE:Wipe tower"): state = 1 continue if state == 1 and line.startswith(";TYPE"): check_tower_update(False) purgetower.purge_create_layers(v.wipe_tower_info_minx, v.wipe_tower_info_miny, v.wipe_tower_xsize, v.wipe_tower_ysize) gui.create_logitem( "Tower detected from ({}, {}) to ({}, {})".format( v.wipe_tower_info_minx, v.wipe_tower_info_miny, v.wipe_tower_info_maxx, v.wipe_tower_info_maxy)) break if state == 1: gc = gcode.create_command(line) if gc[gcode.EXTRUDE]: if gc[gcode.X] is not None: v.wipe_tower_info_maxx = max( v.wipe_tower_info_maxx, gc[gcode.X] + 6 * v.extrusion_width) v.wipe_tower_info_minx = min( v.wipe_tower_info_minx, gc[gcode.X] - 6 * v.extrusion_width) if gc[gcode.Y] is not None: v.wipe_tower_info_maxy = max( v.wipe_tower_info_maxy, gc[gcode.Y] + 6 * v.extrusion_width) v.wipe_tower_info_miny = min( v.wipe_tower_info_miny, gc[gcode.Y] - 6 * v.extrusion_width)
def _purge_generate_tower_brim(x, y, w, h): global brimlayer, last_brim_x, last_brim_y ew = v.extrusion_width brimlayer = [] y -= ew w += ew h += 2 * ew brimlayer.append(gcode.create_command("; P2PP - BRIM CODE")) brimlayer.append(gcode.create_command("G1 X{:.3f} Y{:.3f} F8640".format(x, y))) brimlayer.append(gcode.create_command("G1 Z{:.3f}".format(v.layer_height))) for i in range(4): brimlayer.append( gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f} F{}".format(x + w, y, calculate_purge(w), 1200))) brimlayer.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f}".format(x + w, y + h, calculate_purge(h)))) x -= ew w += 2 * ew brimlayer.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f}".format(x, y + h, calculate_purge(w)))) y -= ew h += 2 * ew brimlayer.append(gcode.create_command("G1 X{:.3f} Y{:.3f} E{:.4f}".format(x, y, calculate_purge(h))))
def parse_gcode_second_pass(): idx = 0 intower = False purge = False total_line_count = len(v.parsed_gcode) v.retraction = 0 v.last_parsed_layer = -1 v.previous_block_classification = v.parsed_gcode[0][gcode.CLASS] # include firmware purge length accounting v.total_material_extruded = v.firmwarepurge v.material_extruded_per_color[v.current_tool] = v.firmwarepurge for process_line_count in range(total_line_count): try: if process_line_count >= v.layer_end[0]: v.last_parsed_layer += 1 v.layer_end.pop(0) v.current_layer_is_skippable = v.skippable_layer[ v.last_parsed_layer] and not v.last_parsed_layer == 0 if v.current_layer_is_skippable: if v.last_parsed_layer == 0: v.cur_tower_z_delta += v.first_layer_height else: v.cur_tower_z_delta += v.layer_height except IndexError: pass g = v.parsed_gcode[idx] idx = idx + 1 # ----- MEMORY MANAGEMENT - when 100K lines are processed, remove the top of the list if idx > 100000: v.parsed_gcode = v.parsed_gcode[idx:] idx = 0 if process_line_count % 10000 == 0: gui.progress_string(50 + 50 * process_line_count // total_line_count) current_block_class = g[gcode.CLASS] # ---- FIRST SECTION HANDLES DELAYED TEMPERATURE COMMANDS ---- if current_block_class not in [ CLS_TOOL_PURGE, CLS_TOOL_START, CLS_TOOL_UNLOAD ] and v.current_temp != v.new_temp: gcode.issue_code(v.temp1_stored_command) v.temp1_stored_command = "" # BLOCK Added 27/11/2021 - PS2.4 - P3 - showinf lines between print and tower if current_block_class != v.previous_block_classification and not v.side_wipe and not v.full_purge_reduction: if v.previous_block_classification == CLS_TOOL_UNLOAD: if v.restore_move_point: v.restore_move_point = False gcode.issue_code( "G1 X{:0.3f} Y{:0.3f} F8640 ; P2PP positional alignment" .format(v.current_position_x, v.current_position_y)) # BLOCK END # ---- SECOND SECTION HANDLES COMMENTS AND NONE-MOVEMENT COMMANDS ---- if g[gcode.COMMAND] is None: if v.disable_z and g[gcode.COMMENT].endswith("END"): v.disable_z = False if v.needpurgetower and g[gcode.COMMENT].endswith("BRIM END"): v.needpurgetower = False purgetower.purge_create_layers(v.wipe_tower_info_minx, v.wipe_tower_info_miny, v.wipe_tower_xsize, v.wipe_tower_ysize) purgetower.purge_generate_brim() v.toolchange_processed = False gcode.issue_command(g) continue elif g[gcode.MOVEMENT] == 0: if g[gcode.COMMAND].startswith('T'): if v.manual_filament_swap and not ( v.side_wipe or v.full_purge_reduction or v.tower_delta) and (v.current_tool != -1): swap.swap_pause("M25") swap.swap_unpause() gcode_process_toolchange(int(g[gcode.COMMAND][1:])) if not v.debug_leaveToolCommands: gcode.move_to_comment(g, "--P2PP-- Color Change") v.toolchange_processed = (current_block_class != CLS_NORMAL) elif v.klipper and g[gcode.COMMAND] == "ACTIVATE_EXTRUDER": extruder = g[gcode.OTHER].strip() if extruder.startswith("EXTRUDER=extruder"): if len(extruder) == 17: extruder_num = 0 else: try: extruder_num = int(extruder[17:]) except (ValueError, IndexError): extruder_num = None gui.log_warning( "KLIPPER - Named extruders are not supported ({})" .format(extruder)) if extruder_num is not None: gcode_process_toolchange(extruder_num) if not v.debug_leaveToolCommands: gcode.move_to_comment(g, "--P2PP-- Color Change") v.toolchange_processed = True else: gui.log_warning( "KLIPPER - Named extruders are not supported ({})". format(extruder)) else: if current_block_class == CLS_TOOL_UNLOAD: if g[gcode.COMMAND] in ["G4", "M900", "M400"]: gcode.move_to_comment(g, "--P2PP-- tool unload") if g[gcode.COMMAND] is not None and g[ gcode.COMMAND].startswith('M'): try: command_num = int(g[gcode.COMMAND][1:]) except (ValueError, KeyError): command_num = 0 if command_num in [104, 109]: if v.process_temp: if current_block_class not in [ CLS_TOOL_PURGE, CLS_TOOL_START, CLS_TOOL_UNLOAD ]: g[gcode.COMMENT] += " Unprocessed temp " v.new_temp = gcode.get_parameter( g, gcode.S, v.current_temp) v.current_temp = v.new_temp else: v.new_temp = gcode.get_parameter( g, gcode.S, v.current_temp) if v.new_temp >= v.current_temp: g[gcode.COMMAND] = "M109" v.temp2_stored_command = gcode.create_commandstring( g) gcode.move_to_comment( g, "--P2PP-- delayed temp rise until after purge {}-->{}" .format(v.current_temp, v.new_temp)) v.current_temp = v.new_temp else: v.temp1_stored_command = gcode.create_commandstring( g) gcode.move_to_comment( g, "--P2PP-- delayed temp drop until after purge {}-->{}" .format(v.current_temp, v.new_temp)) elif command_num == 107: v.saved_fanspeed = 0 elif command_num == 106: v.saved_fanspeed = gcode.get_parameter( g, gcode.S, v.saved_fanspeed) elif command_num == 221: v.extrusion_multiplier = float( gcode.get_parameter( g, gcode.S, v.extrusion_multiplier * 100.0)) / 100.0 elif command_num == 220: gcode.move_to_comment( g, "--P2PP-- Feed Rate Adjustments are removed") elif command_num == 572: for i in range(1, v.filament_count): g[gcode.OTHER] = g[gcode.OTHER].replace( "D{}".format(i), "D0") elif not v.generate_M0 and g[gcode.COMMAND] == "M0": gcode.move_to_comment(g, "--P2PP-- remove M0 command") gcode.issue_command(g) continue classupdate = not current_block_class == v.previous_block_classification v.previous_block_classification = current_block_class # ---- AS OF HERE ONLY MOVEMENT COMMANDS ---- if g[gcode.MOVEMENT] & 1: v.previous_purge_keep_x = v.purge_keep_x v.purge_keep_x = g[gcode.X] v.current_position_x = g[gcode.X] if g[gcode.MOVEMENT] & 2: v.previous_purge_keep_y = v.purge_keep_y v.purge_keep_y = g[gcode.Y] v.current_position_y = g[gcode.Y] if g[gcode.MOVEMENT] & 4: if v.disable_z: gcode.move_to_comment(g, "-- P2PP - invalid move in delta tower") gcode.issue_command(g) continue else: v.current_position_z = g[gcode.Z] if g[gcode.MOVEMENT] & 16: v.keep_speed = g[gcode.F] # this goes for all situations: START and UNLOAD are not needed if current_block_class in [CLS_TOOL_START, CLS_TOOL_UNLOAD]: # BLOCK Added 27/11/2021 - PS2.4 - P3 - showinf lines between print and tower if not (v.side_wipe or v.full_purge_reduction): v.restore_move_point = True # BLOCK END gcode.move_to_comment(g, "--P2PP-- tool unload") gcode.issue_command(g) continue # --------------------- TOWER DELTA PROCESSING if v.tower_delta: if classupdate: if current_block_class == CLS_TOOL_PURGE: gcode.issue_command(g) entertower(v.last_parsed_layer * v.layer_height + v.first_layer_height) continue if current_block_class == CLS_EMPTY and not v.towerskipped: v.towerskipped = ( g[gcode.MOVEMENT] & gcode.INTOWER ) == gcode.INTOWER and v.current_layer_is_skippable if not v.towerskipped: gcode.issue_command(g) entertower(v.last_parsed_layer * v.layer_height + v.first_layer_height) continue if current_block_class == CLS_NORMAL: if v.towerskipped: gcode.issue_code("G1 Z{:.2f} F10810".format( v.current_position_z)) v.towerskipped = False if current_block_class == CLS_TOOL_PURGE: speed_limiter(g) if current_block_class == CLS_TOOL_PURGE: if g[gcode.F] is not None and g[ gcode.F] > v.purgetopspeed and g[gcode.E]: g[gcode.F] = v.purgetopspeed g[gcode.COMMENT] += " prugespeed topped" if v.towerskipped: gcode.move_to_comment(g, "--P2PP-- tower skipped") gcode.issue_command(g) continue # --------------------- SIDE WIPE PROCESSING elif v.side_wipe: if classupdate: if current_block_class == CLS_BRIM: v.towerskipped = True v.side_wipe_state = 0 if not v.towerskipped and (g[gcode.MOVEMENT] & 3) != 0: if (g[gcode.MOVEMENT] & gcode.INTOWER) == gcode.INTOWER: v.towerskipped = True v.side_wipe_state = 1 if (current_block_class == CLS_TOOL_PURGE) else 0 if v.towerskipped and current_block_class == CLS_NORMAL and ( g[gcode.MOVEMENT] & 3) == 3: if (v.bed_origin_x <= g[gcode.X] <= v.bed_max_x) and ( v.bed_origin_y <= g[gcode.Y] <= v.bed_max_y): v.towerskipped = False v.side_wipe_state = 0 if v.toolchange_processed and v.side_wipe_length: create_side_wipe() v.toolchange_processed = False if v.towerskipped: inc = "NO_E" if current_block_class in [ CLS_TOOL_PURGE, CLS_ENDPURGE ] or (current_block_class == CLS_EMPTY and v.side_wipe_state == 1): if g[gcode.EXTRUDE]: v.side_wipe_length += g[gcode.E] inc = "INC_E" gcode.move_to_comment( g, "--P2PP-- side wipe skipped ({})".format(inc)) gcode.issue_command(g) continue # for PS2.4 # before first extrusion prime the nozzle if not v.mechpurge_hasprimed and g[gcode.EXTRUDE]: if v.bigbrain3d_purge_enabled or v.blobster_purge_enabled: create_side_wipe(v.mechpurge_prime_blobs * v.mechpurge_blob_size) v.mechpurge_hasprimed = True # --------------------- FULL PURGE PROCESSING elif v.full_purge_reduction: if (g[gcode.MOVEMENT] & 3) > 0: # if there is a movement intower = (g[gcode.MOVEMENT] & gcode.INTOWER) == gcode.INTOWER if classupdate: if current_block_class == CLS_NORMAL: v.towerskipped = False purge = False if current_block_class == CLS_TOOL_PURGE: purge = True if not v.towerskipped and current_block_class == CLS_EMPTY and v.current_layer_is_skippable: v.towerskipped = (g[gcode.MOVEMENT] & gcode.INTOWER) == gcode.INTOWER if v.towerskipped or current_block_class in [ CLS_BRIM, CLS_ENDGRID ]: gcode.move_to_comment( g, "--P2PP-- full purge skipped [Excluded]") gcode.issue_command(g) continue if current_block_class in [ CLS_TOOL_PURGE, CLS_ENDPURGE, CLS_EMPTY ]: if purge and g[gcode.EXTRUDE]: v.side_wipe_length += g[gcode.E] gcode.move_to_comment( g, "--P2PP-- full purge skipped [Included]") else: gcode.move_to_comment( g, "--P2PP-- full purge skipped [Excluded]") gcode.issue_command(g) continue if v.toolchange_processed and current_block_class == CLS_NORMAL: if v.side_wipe_length and ( g[gcode.MOVEMENT] & 3) == 3 and not (g[gcode.MOVEMENT] & gcode.INTOWER) == gcode.INTOWER: purgetower.purge_generate_sequence() v.toolchange_processed = False # do not issue code here as the next code might require further processing such as retractioncorrection else: gcode.move_to_comment(g, "--P2PP-- full purge skipped") gcode.issue_command(g) continue if v.expect_retract and (g[gcode.MOVEMENT] & 3): v.expect_retract = False if v.retraction >= 0 and g[gcode.RETRACT]: purgetower.retract(v.current_tool) if v.retract_move and g[gcode.RETRACT]: g[gcode.X] = v.retract_x g[gcode.Y] = v.retract_y g[gcode.MOVEMENT] |= 3 v.retract_move = False if v.retraction <= -v.retract_length[v.current_tool]: gcode.move_to_comment(g, "--P2PP-- Double Retract") else: v.retraction += g[gcode.E] if intower: gcode.move_to_comment( g, "--P2PP-- full purge skipped [Excluded]") gcode.issue_command(g) continue # --------------------- NO TOWER PROCESSING else: if current_block_class in [CLS_TOOL_PURGE, CLS_EMPTY ] and g[gcode.E]: if v.acc_ping_left <= 0: pings.check_accessorymode_first() v.enterpurge = True # TOEE - Added to limit the speed of the extrusions during purge to defined WIPEFEEDRATE if current_block_class == CLS_TOOL_PURGE: speed_limiter(g) if v.toolchange_processed: if v.temp2_stored_command != "": wait_location = calculate_temp_wait_position() gcode.issue_code( "G1 X{:.3f} Y{:.3f} F8640; temp wait position\n". format(wait_location[0], wait_location[0])) gcode.issue_code(v.temp2_stored_command) v.temp2_stored_command = "" gcode.issue_code("G1 F8640 ; correct speed") gcode.issue_command(g) if v.wipe_remove_sparse_layers: gcode.issue_code( "G1 X{} Y{} F8640 ;P2PP Position XY to avoid tower crash" .format(v.current_position_x, v.current_position_y)) v.z_correction = "G1 Z{} F10800 ;P2PP correct z-moves".format( v.current_position_z) v.toolchange_processed = False continue if current_block_class == CLS_TOOL_PURGE: if g[gcode.F] is not None and g[ gcode.F] > v.purgetopspeed and g[gcode.E]: g[gcode.F] = v.purgetopspeed g[gcode.COMMENT] += " prugespeed topped" # --------------------- GLOBAL PROCEDDING if g[gcode.UNRETRACT]: g[gcode.E] = min(-v.retraction, g[gcode.E]) v.retraction += g[gcode.E] elif g[gcode.RETRACT]: v.retraction += g[gcode.E] elif (g[gcode.MOVEMENT] & 3) and g[gcode.EXTRUDE]: if v.z_correction is not None or v.retraction < -0.01: if current_block_class != CLS_TOOL_START: gcode.issue_code(";P2PP START Z/E alignment processing") if v.z_correction is not None: gcode.issue_code(v.z_correction) v.z_correction = None if v.retraction < -0.01: purgetower.unretract(v.retraction, -1, ";--- P2PP --- fixup retracts") gcode.issue_code(";P2PP END Z/E alignment processing") else: gcode.issue_command(g) gcode.issue_code(";P2PP START Z/E alignment processing") if v.z_correction is not None: gcode.issue_code(v.z_correction) v.z_correction = None if v.retraction < -0.01: purgetower.unretract(v.retraction, -1, ";--- P2PP --- fixup retracts") g = gcode.create_command( ";P2PP END Z/E alignment processing") # --------------------- PING PROCESSING if v.accessory_mode and g[gcode.EXTRUDE]: if not pings.check_accessorymode_second(g[gcode.E]): gcode.issue_command(g) else: gcode.issue_command(g) if g[gcode.EXTRUDE] and v.side_wipe_length == 0: pings.check_connected_ping() v.previous_position_x = v.current_position_x v.previous_position_y = v.current_position_y # LAST STEP IS ADDING AN EXTRA TOOL UNLOAD TO DETERMINE THE LENGTH OF THE LAST SPLICE gcode_process_toolchange(-1)
def parse_gcode_first_pass(): v.layer_toolchange_counter = 0 v.layer_emptygrid_counter = 0 v.block_classification = CLS_NORMAL v.previous_block_classification = CLS_NORMAL total_line_count = len(v.input_gcode) flh = int(v.first_layer_height * 100) olh = int(v.layer_height * 100) backpass_line = -1 jndex = 0 find_alternative_tower() for index in range(total_line_count): v.previous_block_classification = v.block_classification # memory management, reduce size of data structures when data is processed line = v.input_gcode[jndex] jndex += 1 if jndex == 100000: gui.progress_string(4 + 46 * index // total_line_count) v.input_gcode = v.input_gcode[jndex:] jndex = 0 # actual line processing, starting with comments processing if line.startswith(';'): is_comment = True # extract thumbnail from gcode file if not v.p3_processing_thumbnail_end: if line.startswith("; thumbnail"): v.p3_thumbnail = not v.p3_thumbnail if not v.p3_thumbnail: v.p3_processing_thumbnail_end = True v.p3_thumbnail_data = v.p3_thumbnail_data.replace( "; ", "") elif v.p3_thumbnail: v.p3_thumbnail_data += line # extract the main gcode building blocks if line.startswith( '; CP' ): # code block assignment, based on Prusa Slicer injected CP comments update_class(hash(line[5:])) # determine the layerheight at which we're printing elif line.startswith( ';LAYERHEIGHT' ): # Layer instructions, used to calculate the layer number fields = line.split(' ') try: lv = float(fields[1]) lv = int((lv + 0.001) * 100) - flh if lv % olh == 0: process_layer(int(lv / olh), index) except (ValueError, IndexError): pass else: is_comment = False try: if line[0] == 'T': if v.set_tool == -1: # ignore the first tool setting for purging v.block_classification = CLS_NORMAL else: v.block_classification = CLS_TOOL_PURGE cur_tool = int(line[1]) v.set_tool = cur_tool except (TypeError, ValueError): gui.log_warning("Unknown T-command: {}".format(line)) except IndexError: # in case there is an empty line there will be no line[0] pass code = gcode.create_command(line, is_comment, v.block_classification) v.parsed_gcode.append(code) if v.block_classification != v.previous_block_classification: if v.block_classification in [ CLS_TOOL_START, CLS_TOOL_UNLOAD, CLS_EMPTY, CLS_BRIM ]: for idx in range(backpass_line, len(v.parsed_gcode)): v.parsed_gcode[idx][gcode.CLASS] = v.block_classification # determine tower size - old method if v.tower_measure: code[gcode.MOVEMENT] += gcode.INTOWER if code[gcode.X]: v.wipe_tower_info_minx = min( v.wipe_tower_info_minx, code[gcode.X] - 2 * v.extrusion_width) v.wipe_tower_info_maxx = max( v.wipe_tower_info_maxx, code[gcode.X] + 2 * v.extrusion_width) if code[gcode.Y]: v.wipe_tower_info_miny = min( v.wipe_tower_info_miny, code[gcode.Y] - 4 * 2 * v.extrusion_width) v.wipe_tower_info_maxy = max( v.wipe_tower_info_maxy, code[gcode.Y] + 4 * 2 * v.extrusion_width) if v.bedtrace: if (code[gcode.MOVEMENT] & (gcode.X + gcode.Y)) and v.bed is not None: if code[gcode.EXTRUDE]: v.bed.line(code[gcode.X], code[gcode.Y]) else: v.bed.position(code[gcode.X], code[gcode.Y]) # determine block separators by looking at the last full XY positioning move if (code[gcode.MOVEMENT] & 3) == 3: if (code[gcode.MOVEMENT] & 12) == 0: backpass_line = len(v.parsed_gcode) - 1 # add if v.side_wipe_towerdefined: if ((v.wipe_tower_info_minx <= code[gcode.X] <= v.wipe_tower_info_maxx) and (v.wipe_tower_info_miny <= code[gcode.Y] <= v.wipe_tower_info_maxy)): code[gcode.MOVEMENT] += gcode.INTOWER if v.block_classification in [CLS_ENDGRID, CLS_ENDPURGE]: if not (code[gcode.MOVEMENT] & gcode.INTOWER): v.parsed_gcode[-1][gcode.CLASS] = CLS_NORMAL v.block_classification = CLS_NORMAL if v.block_classification == CLS_BRIM_END: v.block_classification = CLS_NORMAL v.input_gcode = None