def list(args, gcodes, clearance_height): m = Machine() print("The line numbers where a cut is possible are:") for gcode in gcodes: m.process_gcodes(gcode['gcode']) if clearance_height == m.pos._value['Z']: print(" {:7} at {:6.2f}% in {}".format(gcode["line_no"], gcode["line_no"]*100/gcodes[-1]["line_no"],m.pos))
def getClearanceHeight(gcodes): m = Machine() last = m.pos clearance_height = m.pos._value['Z'] for gcode in gcodes: m.process_gcodes(gcode['gcode']) if clearance_height < m.pos._value['Z']: clearance_height = m.pos._value['Z'] return clearance_height
def get_positions(data): t1 = dt.now() machine = Machine() positions = [] last = [] for i in data.split('\n'): line = Line(i) block = line.block.gcodes for g in block: machine.process_gcodes(g) keys = [] for key in machine.pos.values.keys(): keys.append(machine.pos.values[key]) #positions.append(keys) position = machine.pos.values if position != last: positions.append(position) last = position timer(t1, "processing gcode") return positions
def cut(args, gcodes, clearance_height): non_motion = [] # Select where to cut m = Machine() last = m.pos checkpoint = {'gcode': None, 'pos': m.pos, 'mode': m.mode.distance} for idx, gcode in enumerate(gcodes): m.process_gcodes(gcode['gcode']) if gcode["line_no"] > args.line: break if m.pos == last: non_motion.append(gcode) last = m.pos if clearance_height == m.pos._value['Z']: checkpoint = {'idx': idx, 'gcode': gcode, 'pos': m.pos, 'mode': m.mode.distance} #print("Checkpoint at {}".format(checkpoint)) # If the user wants to cut before the first clearance height, do nothing if checkpoint['gcode'] is None: print("The provided line is not a valid one, use list subcommand for more info. Exiting") return # Dump the non motion commands first for gcode in non_motion: # if not isinstance(gcode['gcode'], GCodeFeedRate): # Ignore feedrates please print(FORMAT.format(str(gcode['gcode']), str(gcode['line_no']), gcode['gcode'].__class__.__name__), file=args.output) # Insert the travel until the checkpoint position gcode = GCodeAbsoluteDistanceMode() print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output) gcode = GCodeRapidMove(Z=clearance_height) print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output) gcode = GCodeRapidMove(X=checkpoint['pos']._value['X'], Y=checkpoint['pos']._value['Y'], Z=checkpoint['pos']._value['Z']) print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output) gcode = checkpoint['mode'] print(FORMAT.format(str(gcode), "Cut comp.", gcode.__class__.__name__), file=args.output) print(CHECKPOINT_TAG, file=args.output) # Dump the rest of the codes from the original file (to preserve formatting) try: args.input.seek(gcodes[checkpoint['idx']+1]['offset']) for line in args.input: print(line, file=args.output, end="") except: pass if args.verify: s = Machine() t = Machine() # Run input gcodes until the selected for gcode in gcodes[:checkpoint['idx']+1]: s.process_gcodes(gcode['gcode']) # Run output gcodes until checkpoint args.output.seek(0) line = args.output.readline() while line: if CHECKPOINT_TAG in line: break for gcode in Line(line).block.gcodes: t.process_gcodes(gcode) line = args.output.readline() args.input.seek(gcodes[checkpoint['idx']+1]['offset']) sline = args.output.readline() tline = args.input.readline() while sline and tline: for gcode in Line(sline).block.gcodes: s.process_gcodes(gcode) for gcode in Line(tline).block.gcodes: t.process_gcodes(gcode) if s.pos!=t.pos: print("\nOutput gcode not verified (source: {}, target: {})".format(s.pos, t.pos)) return sline = args.output.readline() tline = args.input.readline() print("\nOutput gcode verified")
class parse_gcode(object): def __init__(self, gcode): self.gcode = gcode # gcode stored in plain text or whatever self.all_positions = [] # list of every xyz position the gcode contains, including 'strokes' and 'seeks'. without separating strokes and # seeks, the order of the self.all_positions cannot be changed self.machine = Machine() # Virtual machine that will simulate running the gcode and extract coordinates self.cities = [] # in TSP parlance, each uninterrupted line to be drawn on the paper is considered a city # unlike usual TSP, our cities must have a different start and end rather than being a single point # therefore each city is a list coordinates. self.cities_lite = [] # in order to find the best tour we only need the start and end points of each city. # we will need the whole city only when we come to output new gcode one day. # so to keep it lite we strip all the in between coordinates plus the z values # also format the data as a simple array for numpy reasons # format is [startX, startY, endX, endY] self.seek_threshold = self.guess_seek_threshold() print('seek threshold is', self.seek_threshold) # if the Z position of the pen is above this value, we will assume it's a seek (flight), not a stroke (city) # self.original_tour = [x for x in range(len(self.cities_lite))] # in TSP parlance the tour is the order in which we visit the cities, ie the whole thing we want to find # we keep the original order of strokes for reference self.parse() def parse(self): # use the machine to populate the all_positions variable with xyz coordinates t1 = dt.now() previous_position = [] for i in self.gcode.split('\n'): line = Line(i) block = line.block.gcodes for g in block: self.machine.process_gcodes(g) keys = [] for key in self.machine.pos.values.keys(): keys.append(self.machine.pos.values[key]) this_position = self.machine.pos.values if this_position != previous_position: self.all_positions.append(this_position) previous_position = this_position timer(t1, 'parsing') self.get_cities() return self.all_positions def guess_seek_threshold(self): minZ = 0 maxZ = 0 for i in self.all_positions: if "Z" in i.keys(): minZ = min(minZ, i["Z"]) maxZ = max(maxZ, i["Z"]) return (minZ + maxZ) / 2 def get_cities(self): this_city = [] for x, this_position in enumerate(self.all_positions): if x == 0: pass # current_pos = self.all_positions[0] # # if current_pos['Z'] <= self.seek_threshold: # this_city.append(this_position) else: if this_position['Z'] <= self.seek_threshold: this_city.append(this_position) else: if this_city: self.cities.append(this_city) this_city = [] self.cities_lite = [[i[0]['X'], i[0]['Y'], i[-1]['X'], i[-1]['Y']] for i in self.cities] return self.cities