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.GCodeCommand(pformat.format(start1, start2))) pformat = (pformat + " E{:.4f}") while start1 < end1: if generate_front: code.append(gcode.GCodeCommand(pformat.format(start1, start2, calculate_purge(step1)))) else: generate_front = True code.append(gcode.GCodeCommand(pformat.format(start1, end2, calculate_purge(end2 - start2)))) start1 += step1 if start1 < end1: code.append(gcode.GCodeCommand(pformat.format(start1, end2, calculate_purge(step1)))) code.append(gcode.GCodeCommand(pformat.format(start1, start2, calculate_purge(end2 - start2)))) start1 += step1
def generate_rectangle(result, x, y, w, h): x2 = x + w y2 = y + h result.append(gcode.GCodeCommand("G1 X{:.3f} Y{:.3f}".format(x, y))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x2, y, calculate_purge(w)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x2, y2, calculate_purge(h)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x, y2, calculate_purge(w)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x, y, calculate_purge(h)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f}".format(x + ew, y + ew))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x2 - ew, y + ew, calculate_purge(w - 2 * ew)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x2 - ew, y2 - ew, calculate_purge(h - 2 * ew)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x + ew, y2 - ew, calculate_purge(w - 2 * ew)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x + ew, y + ew, calculate_purge(h - 2 * ew))))
def purge_create_layers(x, y, w, h): global solidlayer, emptylayer, filllayer solidlayer = [] emptylayer = [] filllayer = [] ew = v.extrusion_width w = int(w / ew) * ew h = int(h / ew) * ew solidlayer.append(gcode.GCodeCommand(";---- SOLID WIPE -------")) generate_rectangle(solidlayer, x, y, w, h) emptylayer.append(gcode.GCodeCommand(";---- EMPTY WIPE -------")) generate_rectangle(emptylayer, x, y, w, h) filllayer.append(gcode.GCodeCommand(";---- 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 generate_rectangle(result, x, y, w, h): ew = v.extrusion_width x2 = x + w y2 = y + h result.append(gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} F8640".format(x, y))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format( x2, y, calculate_purge(w)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format( x2, y2, calculate_purge(h)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format( x, y2, calculate_purge(w)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format( x, y, calculate_purge(h)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} F8640".format(x + ew, y + ew))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x2 - ew, y + ew, calculate_purge(w - 2 * ew)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format( x2 - ew, y2 - ew, calculate_purge(h - 2 * ew)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format( x + ew, y2 - ew, calculate_purge(w - 2 * ew)))) result.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F%SPEED%".format( x + ew, y + ew, calculate_purge(h - 2 * ew))))
def purge_create_layers(x, y, w, h): global solidlayer, emptylayer, filllayer, ew solidlayer = [] emptylayer = [] filllayer = [] ew = v.extrusion_width w = int(w / ew) * ew h = int(h / ew) * ew solidlayer.append(gcode.GCodeCommand(";-----------------------")) solidlayer.append(gcode.GCodeCommand(";---- SOLID WIPE -------")) solidlayer.append(gcode.GCodeCommand(";-----------------------")) generate_rectangle(solidlayer, x, y, w, h) emptylayer.append(gcode.GCodeCommand(";-----------------------")) emptylayer.append(gcode.GCodeCommand(";---- EMPTY WIPE -------")) emptylayer.append(gcode.GCodeCommand(";-----------------------")) generate_rectangle(emptylayer, x, y, w, h) filllayer.append(gcode.GCodeCommand(";-----------------------")) filllayer.append(gcode.GCodeCommand(";---- FILL WIPE -------")) filllayer.append(gcode.GCodeCommand(";-----------------------")) generate_rectangle(filllayer, x, y, w, h) _purge_create_sequence(solidlayer, "X", x, y, w, h, ew) _purge_create_sequence(emptylayer, "Y", y, x, h, w, 2) _purge_generate_hatch(filllayer, 1, x + 1.85 * ew, y + 1.85 * ew, x + w - 1.85 * ew, y + h - 1.85 * ew, 5) _purge_generate_tower_brim(x, y, w, h) _purge_calculate_sequences_length()
def _purge_generate_hatch(code, slope, x1, y1, x2, y2, infill): assert infill > 0, "Infill must be >0" assert abs(slope) == 1, "Slope value must be -1 or 1" step = 100 / infill * ew if slope > 0: last_x = x1 last_y = y1 start_x = x1 - (y2 - y1) + step endx = x2 else: last_x = x1 last_y = y1 start_x = x1 + step endx = x2 + (y2 - y1) - step index = 0 code.append(gcode.GCodeCommand("G1 X{:3f} Y{:.3f}".format(last_x, last_y))) while start_x < endx: next_points = clipline(slope, x1, y1, x2, y2, start_x) start_x = start_x + step if next_points: if dist(last_x, last_y, next_points[index][0], next_points[index][1]) > dist( last_x, last_y, next_points[1 - index][0], next_points[1 - index][1]): index = 1 - index strokelength = dist(last_x, last_y, next_points[index][0], next_points[index][1]) code.append( gcode.GCodeCommand("G1 X{:3f} Y{:.3f} E{:.4f}".format( next_points[index][0], next_points[index][1], calculate_purge(strokelength)))) last_x = next_points[index][0] last_y = next_points[index][1] index = 1 - index strokelength = dist(last_x, last_y, next_points[index][0], next_points[index][1]) code.append( gcode.GCodeCommand("G1 X{:3f} Y{:.3f} E{:.4f}".format( next_points[index][0], next_points[index][1], calculate_purge(strokelength)))) last_x = next_points[index][0] last_y = next_points[index][1]
def convert_to_absolute(): absolute = -9999 for i in range(len(v.processed_gcode)): if absolute > 3000.0: v.processed_gcode.insert(i, "G92 E0.000 ;Extruder counter reset ") absolute = 0.00 line = gcode.GCodeCommand(v.processed_gcode[i]) if line.is_movement_command(): if line.has_E(): # if there is no filament reset code, make sure one is inserted before first extrusion # this should not be needed if absolute == -9999: v.processed_gcode.insert(i, "G92 E0.00") absolute = 0.0 i += 1 absolute += line.E line.update_parameter("E", absolute) v.processed_gcode[i] = line.__str__() if line.fullcommand == "M83": v.processed_gcode[i] = "M82\n" if line.fullcommand == "G92": absolute = line.E
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.GCodeCommand("; P2PP - BRIM CODE")) brimlayer.append( gcode.GCodeCommand("G0 X{:.3f} Y{:.3f} F8640".format(x, y))) brimlayer.append(gcode.GCodeCommand("G0 Z{:.3f}".format(v.layer_height))) for i in range(4): brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F{}".format( x + w, y, calculate_purge(w), 1200))) brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x + w, y + h, calculate_purge(h)))) x -= ew w += 2 * ew brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x, y + h, calculate_purge(w)))) y -= ew h += 2 * ew brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x, y, calculate_purge(h))))
def _purge_create_sequence(code, main_axis, x, y, w, h, step1): cw = w - 4 * ew ch = h - 4 * ew offset_x = x + 2 * ew offset_y = y + 2 * ew start1 = offset_x - ew * 0.15 end1 = offset_x + cw + ew * 0.15 start2 = offset_y - ew * 0.15 end2 = offset_y + ch + ew * 0.15 if main_axis == "Y": # start1, end1, start2, end2 = start2, end2, start1, end1 short_axis = "X" code.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f}".format(start2, start1))) else: short_axis = "Y" code.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f}".format(start1, start2))) stroke_length = abs(end2 - start2) stroke_num = False while start1 < end1: stroke_num = not stroke_num stroke = min(end1 - start1, step1) start1 = start1 + stroke if stroke_num: code.append( gcode.GCodeCommand("G1 {}{:.3f} E{:.4f}".format( short_axis, end2, calculate_purge(stroke_length)))) else: code.append( gcode.GCodeCommand("G1 {}{:.3f} E{:.4f}".format( short_axis, start2, calculate_purge(stroke_length)))) code.append( gcode.GCodeCommand("G1 {}{:.3f} E{:.4f}".format( main_axis, start1, calculate_purge(stroke))))
def _purge_generate_tower_brim(x, y, w, h): global brimlayer, last_brim_x, last_brim_y brimlayer = [] y -= ew w += ew h += 2 * ew brimlayer.append( gcode.GCodeCommand("G0 X{:.3f} Y{:.3f} F4000".format(x, y))) brimlayer.append(gcode.GCodeCommand("G0 Z{:.3f}".format(v.layer_height))) for i in range(4): brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} F{}".format( x + w, y, calculate_purge(w), v.wipe_feedrate1))) brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x + w, y + h, calculate_purge(h)))) x -= ew w += 2 * ew brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x, y + h, calculate_purge(w)))) y -= ew h += 2 * ew brimlayer.append( gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f}".format( x, y, calculate_purge(h)))) last_brim_x = x last_brim_y = y
def remove_previous_move_in_tower(): idx = len(v.processed_gcode) - 10 while idx < len(v.processed_gcode): line = v.processed_gcode[idx] tmp = gcode.GCodeCommand(line) if tmp.X and tmp.Y: if coordinate_in_tower(tmp.X, tmp.Y): if tmp.is_movement_command() and tmp.has_E(): v.total_material_extruded -= tmp.E v.material_extruded_per_color[v.current_tool] -= tmp.E tmp.move_to_comment("tower skipped") v.processed_gcode[idx] = tmp.__str__() idx = idx + 1
def patchup_toolchanges(): # when we have only 4 extruders defined, keep the user defined input settings from PrusaSlicer if v.m4c_numberoffilaments == 4: return # otherwise replace the color with the right color offset. for idx in range(len(v.m4c_toolchange_source_positions)): try: old = v.parsed_gcode[v.m4c_toolchange_source_positions[idx]] except: old = v.parsed_gcode[v.m4c_toolchange_source_positions[-1]] _ip = calculate_input_index(idx, int(old.Command_value)) v.parsed_gcode[v.m4c_toolchange_source_positions[idx]] = gcode.GCodeCommand( "T{} ; INPUT MAPPING MORE THAN 4 COLORS {} --> {}".format(_ip, _ip, int(old.Command_value)))
def purge_complete_layer(): global last_posx, last_posy, intermediate actual = 0 if current_purge_index == 0: return 0 purge_start_sequence(0) if intermediate: gcode.GCodeCommand("G1 X{:.3f} Y{:.3f} E{:.4f} ;inter resume ".format( tmp_pos_x, tmp_pos_y, tmpe)).issue_command() intermediate = False while current_purge_index: _purge_get_nextcommand_in_sequence().issue_command() _purge_update_sequence_index(0) purge_end_sequence()
def gcode_parseline(index): g = v.parsed_gcode[index] if g.Command == 'T': gcode_process_toolchange(int(g.Command_value), v.total_material_extruded, g.Layer) if not v.debug_leaveToolCommands: g.move_to_comment("Color Change") g.issue_command() v.toolchange_processed = True return if g.fullcommand in [ "M140", "M190", "M73", "M84", "M201", "M204"]: g.issue_command() return if g.fullcommand in [ "M104" , "M109" ]: if not v.process_temp or not g.Class in [CLS_TOOL_PURGE, CLS_TOOL_START, CLS_TOOL_UNLOAD]: g.add_comment(" Unprocessed temp ") g.issue_command() v.new_temp = g.get_parameter("S", v.current_temp) v.current_temp = v.new_temp else: v.new_temp = g.get_parameter("S", v.current_temp) if v.new_temp >= v.current_temp: g.fullcommand = "M109" v.temp2_stored_command = g.__str__(); g.move_to_comment("delayed temp rise until after purge {}-->{}".format(v.current_temp, v.new_temp)) v.current_temp = v.new_temp else: v.temp1_stored_command = g.__str__(); g.move_to_comment("delayed temp drop until after purge {}-->{}".format(v.current_temp,v.new_temp)) g.issue_command() return if not g.Class in [CLS_TOOL_PURGE, CLS_TOOL_START, CLS_TOOL_UNLOAD] and v.current_temp != v.new_temp: print(v.temp1_stored_command) gcode.issue_code(v.temp1_stored_command) v.temp1_stored_command = "" # fan speed command if g.fullcommand == "M107": g.issue_command() v.saved_fanspeed = 0 return if g.fullcommand == "M106": g.issue_command() v.saved_fanspeed = g.get_parameter("S", v.saved_fanspeed) return # flow rate changes have an effect on the filament consumption. The effect is taken into account for ping generation if g.fullcommand == "M221": v.extrusion_multiplier = float(g.get_parameter("S", v.extrusion_multiplier * 100)) / 100 g.issue_command() return # feed rate changes in the code are removed as they may interfere with the Palette P2 settings if g.fullcommand in ["M220"]: g.move_to_comment("Feed Rate Adjustments are removed") g.issue_command() return if g.is_movement_command(): if g.has_X(): v.previous_purge_keep_x = v.purge_keep_x v.purge_keep_x = g.X if g.has_Y(): v.previous_purge_keep_y = v.purge_keep_y v.purge_keep_y = g.Y v.keep_speed = g.get_parameter("F", v.keep_speed) previous_block_class = v.parsed_gcode[max(0, index - 1)].Class classupdate = g.Class != previous_block_class if classupdate and previous_block_class in [CLS_TOOL_PURGE, CLS_EMPTY]: if v.purge_count > 0: gcode.issue_code( ";>>> Total purge {:4.0f}mm3 - {:4.0f}mm <<<\n".format(purgetower.volfromlength(v.purge_count), v.purge_count)) if classupdate and g.Class in [CLS_TOOL_PURGE, CLS_EMPTY]: v.purge_count = 0 if classupdate and g.Class == CLS_BRIM and v.side_wipe and v.bigbrain3d_purge_enabled: v.side_wipe_length = v.bigbrain3d_prime * v.bigbrain3d_blob_size create_sidewipe_BigBrain3D() if not v.side_wipe: if x_coordinate_in_tower(g.X): v.keep_x = g.X if y_coordinate_in_tower(g.Y): v.keep_y = g.Y # remove M900 K0 commands during unload if g.Class == CLS_TOOL_UNLOAD: if (g.fullcommand == "G4" or (g.fullcommand in ["M900"] and g.get_parameter("K", 0) == 0)): g.move_to_comment("tool unload") ## ALL SITUATIONS ############################################## if g.Class in [CLS_TOOL_START, CLS_TOOL_UNLOAD]: if g.is_movement_command(): if v.side_wipe or v.tower_delta or v.full_purge_reduction: g.move_to_comment("tool unload") else: if g.has_Z(): g.remove_parameter("X") g.remove_parameter("Y") g.remove_parameter("F") g.remove_parameter("E") else: g.move_to_comment("tool unload") g.issue_command() return if g.Class == CLS_TOOL_PURGE and not (v.side_wipe or v.full_purge_reduction): if g.is_movement_command() and g.has_E(): _x = g.get_parameter("X", v.current_position_x) _y = g.get_parameter("Y", v.current_position_y) # removepositive extrusions while moving into the tower if not (coordinate_in_tower(_x, _y) and coordinate_in_tower(v.purge_keep_x, v.purge_keep_y)) and g.E > 0: g.remove_parameter("E") if v.side_wipe: _x = g.get_parameter("X", v.current_position_x) _y = g.get_parameter("Y", v.current_position_y) if not coordinate_on_bed(_x, _y): g.remove_parameter("X") g.remove_parameter("Y") # top off the purge speed in the tower during tower delta or during no tower processing if not v.full_purge_reduction and not v.side_wipe and g.is_movement_command() and g.has_E() and g.has_parameter( "F"): f = int(g.get_parameter("F", 0)) if f > v.purgetopspeed: g.update_parameter("F", v.purgetopspeed) g.add_comment(" prugespeed topped") ## SIDEWIPE / FULLPURGEREDUCTION / TOWER DELTA ############################################### if v.pathprocessing: if g.Class == CLS_TONORMAL: if not g.is_comment(): g.move_to_comment("post block processing") g.issue_command() return # remove any commands that are part of the purge tower and still perofrm actions WITHIN the tower if g.is_movement_command() and g.Class in [CLS_ENDPURGE, CLS_ENDGRID] and g.has_X() and g.has_Y(): if coordinate_in_tower(g.X, g.Y): g.remove_parameter("X") g.remove_parameter("Y") ################################### # sepcific for FULL_PURGE_REDUCTION ################################### if v.full_purge_reduction: if g.Class == CLS_BRIM_END: create_tower_gcode() purgetower.purge_generate_brim() ################################### # sepcific for SIDEWIPE ################################### if v.side_wipe: # side wipe does not need a brim if g.Class == CLS_BRIM: g.move_to_comment("side wipe - removed") g.issue_command() return ####################################### # specific for TOWER DELTA ####################################### # changed for version 4.09.0 moves in tower were going all wrong. if not v.side_wipe and classupdate and g.Class == CLS_TOOL_PURGE: g.issue_command() gcode.issue_code("G1 X{} Y{} F8640;\n".format(v.keep_x, v.keep_y)) v.current_position_x = v.keep_x v.current_position_x = v.keep_y if v.tower_delta: if classupdate and g.Class == CLS_TOOL_PURGE: entertower(g.Layer * v.layer_height + v.first_layer_height) return if classupdate and previous_block_class == CLS_TOOL_PURGE: leavetower() ################################################################ # EMPTY GRID SKIPPING CHECK FOR SIDE WIPE/TOWER DELTA/FULLPURGE ################################################################ if g.Class == CLS_EMPTY and "EMPTY GRID START" in g.get_comment(): if g.Layer < len(v.skippable_layer) and v.skippable_layer[g.Layer]: v.towerskipped = True remove_previous_move_in_tower() if v.tower_delta: v. cur_tower_z_delta += v.layer_height gcode.issue_code(";-------------------------------------\n") gcode.issue_code("; GRID SKIP --TOWER DELTA {:6.2f}mm\n".format(v.cur_tower_z_delta)) gcode.issue_code(";-------------------------------------\n") else: if "EMPTY GRID START" in g.get_comment() and not v.side_wipe: entertower(g.Layer * v.layer_height + v.first_layer_height) # changing from EMPTY to NORMAL ############################### if (previous_block_class == CLS_ENDGRID) and (g.Class == CLS_NORMAL): v.towerskipped = False if v.towerskipped: if not g.is_comment(): g.move_to_comment("tower skipped") g.issue_command() return else: if classupdate and g.Class in [CLS_TOOL_PURGE, CLS_EMPTY]: if v.acc_ping_left <= 0: pings.check_accessorymode_first() v.enterpurge = True if v.enterpurge and g.is_movement_command(): v.enterpurge = False if g.has_X(): _x = v.previous_purge_keep_x else: _x = v.purge_keep_x if g.has_Y(): _y = v.previous_purge_keep_y else: _y = v.purge_keep_y if not coordinate_in_tower(_x, _y): _x = v.purge_keep_x _y = v.purge_keep_y if v.retraction == 0: purgetower.retract(v.current_tool, 3000) gcode.issue_code( "G1 X{:.3f} Y{:.3f} F8640; P2PP Inserted to realign\n".format(v.purge_keep_x, v.purge_keep_y)) v.current_position_x = _x v.current_position_x = _y if v.temp2_stored_command != "": gcode.issue_code(v.temp2_stored_command) v.temp2_stored_command = "" g.remove_parameter("E") if g.get_parameter("X") == _x: g.remove_parameter("X") if len(g.Parameters) == 0: g.move_to_comment("-useless command-") if v.tower_delta: if g.has_E() and g.Class in [CLS_TOOL_UNLOAD, CLS_TOOL_PURGE]: if not inrange(g.X, v.wipe_tower_info['minx'], v.wipe_tower_info['maxx']): g.remove_parameter("E") if not inrange(g.Y, v.wipe_tower_info['miny'], v.wipe_tower_info['maxy']): g.remove_parameter("E") # process movement commands ########################### if not g.has_E(): g.E = 0 if v.full_purge_reduction and g.Class == CLS_NORMAL and classupdate: purgetower.purge_generate_sequence() if g.is_movement_command(): if v.expect_retract and g.has_X() or g.has_Y(): if not v.retraction < 0: if not g.has_E and g.E < 0: purgetower.retract(v.current_tool) v.expect_retract = False if v.retract_move and g.is_retract_command(): # This is going to break stuff, G10 cannot take X and Y, what to do? if v.retract_x: g.update_parameter("X", v.retract_x) else: g.remove_parameter("X") if v.retract_y: g.update_parameter("Y", v.retract_y) else: g.remove_parameter("Y") v.retract_move = False v.current_position_x = g.get_parameter("X", v.current_position_x) v.current_position_y = g.get_parameter("Y", v.current_position_y) v.current_position_z = g.get_parameter("Z", v.current_position_z) if g.Class == CLS_BRIM and v.full_purge_reduction: g.move_to_comment("replaced by P2PP brim code") g.remove_parameter("E") if v.side_wipe or v.full_purge_reduction: if g.Class in [CLS_TOOL_PURGE, CLS_ENDPURGE, CLS_EMPTY]: if g.Layer < len(v.skippable_layer) and v.skippable_layer[g.Layer]: g.move_to_comment("skipped purge") else: v.side_wipe_length += g.E g.move_to_comment("side wipe/full purge") if v.toolchange_processed: if v.side_wipe and g.Class == CLS_NORMAL and classupdate: if v.bigbrain3d_purge_enabled: create_sidewipe_BigBrain3D() else: create_side_wipe() v.toolchange_processed = False if g.Class == CLS_NORMAL: gcode.GCodeCommand(";TOOLCHANGE PROCESSED").issue_command() v.toolchange_processed = False # check here issue with unretract ################################# # g.Comment = " ; - {}".format(v.total_material_extruded) if g.is_retract_command(): if v.retraction <= - (v.retract_length[v.current_tool] - 0.02): g.move_to_comment("Double Retract") else: if g.has_E(): v.retraction += g.E else: v.retraction -= 1 if g.is_unretract_command(): if g.has_E(): g.update_parameter("E", min(-v.retraction, g.E)) v.retraction += g.E else: v.retraction = 0 if (g.has_X() or g.has_Y()) and (g.has_E() and g.E > 0) and v.retraction < 0 and abs(v.retraction) > 0.01: gcode.issue_code(";fixup retracts\n") purgetower.unretract(v.current_tool) # v.retracted = False g.issue_command() ### PING PROCESSING ################### if v.accessory_mode: pings.check_accessorymode_second(g.E) if (g.has_E() and g.E > 0) 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
def parse_gcode(): cur_tool = 0 toolchange = 0 emptygrid = 0 v.block_classification = CLS_NORMAL v.previous_block_classification = CLS_NORMAL total_line_count = len(v.input_gcode) index = 0 for line in v.input_gcode: gui.progress_string(4 + 46 * index // total_line_count) if line.startswith(';'): m = v.regex_p2pp.match(line) if m: parameters.check_config_parameters(m.group(1), m.group(2)) if line.startswith(";P2PP MATERIAL_"): algorithm_process_material_configuration(line[15:]) layer = -1 # if not supports are printed or layers are synced, there is no need to look at the layerheight, # otherwise look at the layerheight to determine the layer progress lm = layer_regex.match(line) if lm is not None: llm = len(lm.group(1)) lmv = float(lm.group(2)) if v.synced_support or not v.prints_support: if llm == 5: # LAYER layer = int(lmv) else: if llm == 11: # LAYERHEIGHT layer = int((lmv - v.first_layer_height + 0.005) / v.layer_height) if layer == v.parsedlayer: layer = -1 if layer >= 0: v.parsedlayer = layer if layer > 0: v.skippable_layer.append((emptygrid > 0) and (toolchange == 0)) toolchange = 0 emptygrid = 0 update_class(line) code = gcode.GCodeCommand(line) if code.Command == 'T': cur_tool = int(code.Command_value) v.set_tool = cur_tool v.m4c_toolchanges.append(cur_tool) v.m4c_toolchange_source_positions.append(len(v.parsed_gcode)) code.Tool = cur_tool code.Class = v.block_classification # code.add_comment("[{}]".format(v.classes[v.block_classification])) v.parsed_gcode.append(code) if v.block_classification != v.previous_block_classification: if v.block_classification == CLS_TOOL_START: toolchange += 1 if v.block_classification == CLS_EMPTY: emptygrid += 1 if v.block_classification == CLS_BRIM or v.block_classification == CLS_TOOL_START or v.block_classification == CLS_TOOL_UNLOAD or v.block_classification == CLS_EMPTY: backpass(v.block_classification) if v.tower_measure: calculate_tower(code.X, code.Y) if v.block_classification == CLS_ENDGRID or v.block_classification == CLS_ENDPURGE: if code.has_X() and code.has_Y(): if not coordinate_in_tower(code.X, code.Y): v.parsed_gcode[-1].Class = CLS_NORMAL v.block_classification = CLS_NORMAL if v.block_classification == CLS_BRIM_END: v.block_classification = CLS_NORMAL index += 1
def purge_generate_sequence(purgelength): global last_posx, last_posy, tmp_pos_x, tmp_pos_y, intermediate, tmpe if not purgelength > 0: return 0 actual = 0 purge_start_sequence(purgelength) # generate wipe code while purgelength > 1: if not intermediate: next_command = _purge_get_nextcommand_in_sequence() while not next_command.E or not next_command.E > 0: next_command.issue_command() _purge_update_sequence_index(purgelength) next_command = _purge_get_nextcommand_in_sequence() else: next_command = gcode.GCodeCommand( "G1 X{:.3f} Y{:.3f} E{:.4f} ;inter resume ".format( tmp_pos_x, tmp_pos_y, tmpe)) intermediate = False if float(next_command.E) > (purgelength + 1): tmp_pos_x = float(if_defined(next_command.X, last_posx)) tmp_pos_y = float(if_defined(next_command.Y, last_posy)) last_posx = last_posx + (tmp_pos_x - last_posx) * ( purgelength / float(next_command.E)) last_posy = last_posy + (tmp_pos_y - last_posy) * ( purgelength / float(next_command.E)) tmpe = float(next_command.E) - purgelength intermediate = True actual += purgelength gcode.GCodeCommand( "G1 X{:.3f} Y{:.3f} E{:.4f} ;inter {:.3f} {:.3f}".format( last_posx, last_posy, purgelength, tmp_pos_x, tmp_pos_y)).issue_command() purgelength = 0 else: last_posx = if_defined(next_command.X, last_posx) last_posy = if_defined(next_command.Y, last_posy) purgelength -= if_defined(next_command.E, 0) actual += if_defined(next_command.E, 0) next_command.issue_command() if not intermediate: _purge_update_sequence_index(purgelength) purge_end_sequence() # if we extruded more we need to account for that in the total count return actual
def parse_gcode(): cur_z = -999 cur_tool = 0 retract = 0.6 layer = -1 toolchange = 0 emptygrid = 0 v.block_classification = CLS_NORMAL v.previous_block_classification = CLS_NORMAL total_line_count = len(v.input_gcode) index = 0 for line in v.input_gcode: gui.progress_string(4 + 46 * index // total_line_count) specifier = 0 code = gcode.GCodeCommand(line) v.parsedgcode.append(code) classupdate = False if line.startswith(';'): ## P2PP SPECIFIC SETP COMMANDS ######################################################## if line.startswith(";P2PP"): parameters.check_config_parameters(line) if line.startswith(";P2PP MATERIAL_"): algorithm_process_material_configuration(line[15:]) ## LAYER DISCRIMINATION COMMANDS ######################################################## if line.startswith(";LAYER"): layer = 0 try: layer = int(line[7:]) except ValueError: fields = line[7:].split(" ") for field in fields: try: layer = int(field) break except ValueError: pass v.parsedlayer = layer if layer > 0: v.skippable_layer.append((emptygrid > 0) and (toolchange == 0)) toolchange = 0 emptygrid = 0 ## Update block class from comments information ######################################################### classupdate = update_class(line) # # if line.startswith('T'): # classupdate = update_class(line) if classupdate: if v.block_classification == CLS_TOOL_START: toolchange += 1 if v.block_classification == CLS_EMPTY: emptygrid += 1 ## Z-HOPS detection ################### if code.has_E() and code.is_movement_command(): to_z = code.get_parameter("Z", 0) delta = (to_z - cur_z) if abs(delta - retract) < 0.0001: specifier |= SPEC_HOPUP if v.block_classification == CLS_TONORMAL: v.previous_block_classification = v.block_classification = CLS_NORMAL if abs(-delta - retract) < 0.0001: specifier |= SPEC_HOPDOWN cur_z = to_z ## retract detections ##################### if code.is_retract_command(): specifier |= SPEC_RETRACTS ## tool change detection ######################## if code.Command == 'T': cur_tool = int(code.Command_value) retract = v.retract_lift[cur_tool] specifier |= SPEC_TOOLCHANGE if v.tower_measure: if code.is_movement_command(): if code.X is not None: v.wipe_tower_info['minx'] = min(v.wipe_tower_info['minx'], code.X) v.wipe_tower_info['maxx'] = max(v.wipe_tower_info['maxx'], code.X) if code.Y is not None: v.wipe_tower_info['miny'] = min(v.wipe_tower_info['miny'], code.Y) v.wipe_tower_info['maxy'] = max(v.wipe_tower_info['maxy'], code.Y) ## Extend block backwards towards last hop up ############################################# if v.block_classification in [ CLS_TOOL_START, CLS_TOOL_UNLOAD, CLS_EMPTY, CLS_BRIM ]: # and not v.full_purge_reduction: backpass(v.block_classification) if v.block_classification in [CLS_ENDGRID, CLS_ENDPURGE]: if code.fullcommand == "G1": if code.has_X() and code.has_Y(): specifier |= SPEC_INTOWER if CLS_ENDGRID: code = v.parsedgcode[-1] if code.has_X and code.has_Y(): if not coordinate_in_tower(code.X, code.Y): v.block_classification = CLS_NORMAL # if v.parsedgcode[-1].fullcommand == "G1" and v.parsedgcode[-1].Z: # v.block_classification = CLS_NORMAL else: if flagset(specifier, SPEC_RETRACTS): v.block_classification = CLS_NORMAL ## Put obtained values in global variables ########################################## v.gcodeclass.append(v.block_classification) v.layernumber.append(layer) v.linetool.append(cur_tool) v.parsecomment.append(specifier) v.classupdates.append( v.block_classification != v.previous_block_classification) v.previous_block_classification = v.block_classification index = index + 1 if v.block_classification == CLS_BRIM_END: v.block_classification = CLS_NORMAL
def process_gcode(): gui.comment("Processing " + v.filename) line_count = len(v.rawfile) line_idx = 0 for line in v.rawfile: line_idx += 1 gui.setprogress(int(50 * line_idx / line_count)) # skip fully empty lines if len(line) == 0: continue # parse comments if line.startswith(";"): line = parameters.parse_comment(line) tmp = gcode.GCodeCommand(line) # we calculate the purge for tower position # afterwards this code is removed ######################################################### if v.mode == parameters.MODE_PURGE: if tmp.E: v.purge_minx = min(v.purge_minx, tmp.get_parameter("X", 9999)) v.purge_maxx = max(v.purge_maxx, tmp.get_parameter("X", -9999)) v.purge_miny = min(v.purge_miny, tmp.get_parameter("Y", 9999)) v.purge_maxy = max(v.purge_maxy, tmp.get_parameter("Y", -9999)) if tmp.is_comment() and tmp.comment.startswith(' process'): v.gcodes.append(tmp) else: v.gcodes.append(tmp) toolchange = tmp.is_toolchange() if toolchange in [0, 1, 2, 3]: # keep track of the tools used if not v.toolsused[toolchange]: if not v.filament_type[toolchange]: error( "TOOL_{} setting command missing - output file cannot be created" .format(toolchange)) v.toolsused[toolchange] = True # calculate the purge if not (v.parse_curtool == -1): v.layer_toolchange_count[-1] += 1 if v.filament_type[toolchange] and v.filament_type[ v.parse_curtool] and not (v.parse_curtool == toolchange): v.layer_purge_volume[-1] += purgetower.calc_purge_length( v.parse_curtool, toolchange) v.parse_prevtool = v.parse_curtool v.parse_curtool = toolchange else: v.parse_curtool = v.parse_prevtool = toolchange comment("filament Info: " + v.filament_type.__str__()) comment("Tool unload info: " + v.unloadinfo.__str__()) comment("Tool load info: " + v.loadinfo.__str__()) comment("Algorithms:" + v.algorithm.__str__()) comment("Maximum purge needed per layer: {}mm".format( max(v.layer_purge_volume))) comment("Autotower function active: {}".format(v.autotower)) if v.autotower: autotower.init_autotower() _x = 0.0 _y = 0.0 for g in v.gcodes: if g.is_movement_command(): _ux = g.get_parameter("X", _x) _uy = g.get_parameter("Y", _y) _ue = g.get_parameter("E", 0) if _ue > 0: autotower.filament_mark(_x, _y, _ux, _uy) _x = _ux _y = _uy autotower.calculate_purgevolume() tower_fits = False while not tower_fits: purgetower.purge_create_layers( autotower.purge_minx - 1, autotower.purge_miny - 1, autotower.purge_maxx - autotower.purge_minx + 2, autotower.purge_maxy - autotower.purge_miny + 2) tower_fits = purgetower.simulate_tower( purgetower.sequence_length_solid, purgetower.sequence_length_empty, purgetower.sequence_length_fill, 5) if not tower_fits: if not autotower.tower_expand(): error("COULD NOT GENERATE SUITABLE TOWER") tower_fits = True v.purge_minx = autotower.purge_minx v.purge_miny = autotower.purge_miny v.purge_maxx = autotower.purge_maxx v.purge_maxy = autotower.purge_maxy else: expand = 0 tower_fits = False while not tower_fits: purgetower.purge_create_layers(v.purge_minx - 1, v.purge_miny - 1, v.purge_maxx - v.purge_minx + 2, v.purge_maxy - v.purge_miny + 2) tower_fits = purgetower.simulate_tower( purgetower.sequence_length_solid, purgetower.sequence_length_empty, purgetower.sequence_length_fill, 5) if not tower_fits: purgetower.tower_auto_expand(10) expand += 10 if expand > 0: warning("Tower expanded by {}mm".format(expand)) comment('Calculated purge volume : {:.3f},{:.3f} -> {:.3f},{:.3f}'.format( v.purge_minx, v.purge_miny, v.purge_maxx, v.purge_maxy)) line_idx = 0 line_count = len(v.gcodes) layer = -1 for g in v.gcodes: if g.layer != layer: layer = g.layer purgetower.checkfill(g.layer, v.maxtowerdelta / v.layer_height) line_idx += 1 gui.setprogress(50 + int(50 * line_idx / line_count)) if g.command in ["M220"]: g.move_to_comment("IGNORED COMMAND") g.issue_command() continue # no further mcf required if g.command == "M221": v.extrusion_multiplier = g.get_parameter( "S", v.extrusion_multiplier * 100) / 100 g.issue_command() continue # no further mcf required if g.command in ["T0", "T1", "T2", "T3"]: gcode.GCodeCommand(";---- {} TOOLCHANGE -----".format( g.command)).issue_command() process_tool_change(g) g.issue_command() continue # no further mcf required if g.command in [ "M104", "M106", "M109", "M140", "M190", "M73", "M900", "M84" ]: g.issue_command() continue # no further mcf required if g.is_movement_command(): v.current_position_x = g.get_parameter("X", v.current_position_x) v.current_position_y = g.get_parameter("Y", v.current_position_y) v.current_position_z = g.get_parameter("Z", v.current_position_z) if purgetower.moveintower(): error("MODEL COLLIDES WITH TOWER.") g.issue_command() process_tool_change(None) if v.maxdelta > 1 or v.mindelta < -1: warning( "Tower hight deviates {:.2f}mm above and {:.2f}mm below print level" .format(-v.mindelta, v.maxdelta)) warning( "Make sure to keep enough distance between tower and object to avoid collisions" ) warning( "If the tower grows over the print height, consider increasing the prime pillar width in S3D" ) gui.completed()