From a2a3f1c1eda350a6681f66427fe0243aee09b3c9 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Wed, 4 Sep 2019 17:41:17 +0300 Subject: [PATCH] - added support for G91 coordinates - working in plotting the CNCjob generated with G91 coordinates --- FlatCAMApp.py | 2 + README.md | 2 + camlib.py | 501 +++++++++++++++++++++++++++++---------- flatcamGUI/FlatCAMGUI.py | 42 +++- 4 files changed, 412 insertions(+), 135 deletions(-) diff --git a/FlatCAMApp.py b/FlatCAMApp.py index 34f4b81e..881ff785 100644 --- a/FlatCAMApp.py +++ b/FlatCAMApp.py @@ -572,6 +572,7 @@ class App(QtCore.QObject): "cncjob_annotation_fontcolor": self.ui.cncjob_defaults_form.cncjob_gen_group.annotation_fontcolor_entry, "cncjob_tooldia": self.ui.cncjob_defaults_form.cncjob_gen_group.tooldia_entry, + "cncjob_coords_type": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_type_radio, "cncjob_coords_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.coords_dec_entry, "cncjob_fr_decimals": self.ui.cncjob_defaults_form.cncjob_gen_group.fr_dec_entry, "cncjob_steps_per_circle": self.ui.cncjob_defaults_form.cncjob_gen_group.steps_per_circle_entry, @@ -961,6 +962,7 @@ class App(QtCore.QObject): "cncjob_annotation_fontsize": 9, "cncjob_annotation_fontcolor": '#990000', "cncjob_tooldia": 0.0393701, + "cncjob_coords_type": "G90", "cncjob_coords_decimals": 4, "cncjob_fr_decimals": 2, "cncjob_steps_per_circle": 128, diff --git a/README.md b/README.md index b0bd3998..ff88fc3b 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing. 4.09.2019 - started to work on support for G91 in Gcode (relative coordinates) +- added support for G91 coordinates +- working in plotting the CNCjob generated with G91 coordinates 3.09.2019 diff --git a/camlib.py b/camlib.py index 503f949c..508c1643 100644 --- a/camlib.py +++ b/camlib.py @@ -5039,8 +5039,9 @@ class CNCjob(Geometry): self.unitcode = {"IN": "G20", "MM": "G21"} self.feedminutecode = "G94" - self.absolutecode = "G90" - self.relativecode = "G91" + # self.absolutecode = "G90" + # self.incrementalcode = "G91" + self.coordinates_type = self.app.defaults["cncjob_coords_type"] self.gcode = "" self.gcode_parsed = None @@ -5442,27 +5443,51 @@ class CNCjob(Geometry): z_offset = 0 self.z_cut += z_offset - # Drillling! - for k in node_list: - locx = locations[k][0] - locy = locations[k][1] + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # Drillling! for Absolute coordinates type G90 + for k in node_list: + locx = locations[k][0] + locy = locations[k][1] - gcode += self.doformat(p.rapid_code, x=locx, y=locy) - gcode += self.doformat(p.down_code, x=locx, y=locy) + gcode += self.doformat(p.rapid_code, x=locx, y=locy) + gcode += self.doformat(p.down_code, x=locx, y=locy) - measured_down_distance += abs(self.z_cut) + abs(self.z_move) + measured_down_distance += abs(self.z_cut) + abs(self.z_move) - if self.f_retract is False: - gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy) - measured_up_to_zero_distance += abs(self.z_cut) - measured_lift_distance += abs(self.z_move) - else: - measured_lift_distance += abs(self.z_cut) + abs(self.z_move) + if self.f_retract is False: + gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy) + measured_up_to_zero_distance += abs(self.z_cut) + measured_lift_distance += abs(self.z_move) + else: + measured_lift_distance += abs(self.z_cut) + abs(self.z_move) - gcode += self.doformat(p.lift_code, x=locx, y=locy) - measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy)) - self.oldx = locx - self.oldy = locy + gcode += self.doformat(p.lift_code, x=locx, y=locy) + measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy)) + self.oldx = locx + self.oldy = locy + else: + # Drillling! for Incremental coordinates type G91 + for k in node_list: + locx = locations[k][0] - self.oldx + locy = locations[k][1] - self.oldy + + gcode += self.doformat(p.rapid_code, x=locx, y=locy) + gcode += self.doformat(p.down_code, x=locx, y=locy) + + measured_down_distance += abs(self.z_cut) + abs(self.z_move) + + if self.f_retract is False: + gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy) + measured_up_to_zero_distance += abs(self.z_cut) + measured_lift_distance += abs(self.z_move) + else: + measured_lift_distance += abs(self.z_cut) + abs(self.z_move) + + gcode += self.doformat(p.lift_code, x=locx, y=locy) + measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy)) + self.oldx = locx + self.oldy = locy else: log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> " "The loaded Excellon file has no drills ...") @@ -5548,27 +5573,51 @@ class CNCjob(Geometry): z_offset = 0 self.z_cut += z_offset - # Drillling! - for k in node_list: - locx = locations[k][0] - locy = locations[k][1] + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # Drillling! for Absolute coordinates type G90 + for k in node_list: + locx = locations[k][0] + locy = locations[k][1] - gcode += self.doformat(p.rapid_code, x=locx, y=locy) - gcode += self.doformat(p.down_code, x=locx, y=locy) + gcode += self.doformat(p.rapid_code, x=locx, y=locy) + gcode += self.doformat(p.down_code, x=locx, y=locy) - measured_down_distance += abs(self.z_cut) + abs(self.z_move) + measured_down_distance += abs(self.z_cut) + abs(self.z_move) - if self.f_retract is False: - gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy) - measured_up_to_zero_distance += abs(self.z_cut) - measured_lift_distance += abs(self.z_move) - else: - measured_lift_distance += abs(self.z_cut) + abs(self.z_move) + if self.f_retract is False: + gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy) + measured_up_to_zero_distance += abs(self.z_cut) + measured_lift_distance += abs(self.z_move) + else: + measured_lift_distance += abs(self.z_cut) + abs(self.z_move) - gcode += self.doformat(p.lift_code, x=locx, y=locy) - measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy)) - self.oldx = locx - self.oldy = locy + gcode += self.doformat(p.lift_code, x=locx, y=locy) + measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy)) + self.oldx = locx + self.oldy = locy + else: + # Drillling! for Incremental coordinates type G91 + for k in node_list: + locx = locations[k][0] - self.oldx + locy = locations[k][1] - self.oldy + + gcode += self.doformat(p.rapid_code, x=locx, y=locy) + gcode += self.doformat(p.down_code, x=locx, y=locy) + + measured_down_distance += abs(self.z_cut) + abs(self.z_move) + + if self.f_retract is False: + gcode += self.doformat(p.up_to_zero_code, x=locx, y=locy) + measured_up_to_zero_distance += abs(self.z_cut) + measured_lift_distance += abs(self.z_move) + else: + measured_lift_distance += abs(self.z_cut) + abs(self.z_move) + + gcode += self.doformat(p.lift_code, x=locx, y=locy) + measured_distance += abs(distance_euclidian(locx, locy, self.oldx, self.oldy)) + self.oldx = locx + self.oldy = locy else: log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> " "The loaded Excellon file has no drills ...") @@ -5613,28 +5662,56 @@ class CNCjob(Geometry): z_offset = 0 self.z_cut += z_offset - # Drillling! - altPoints = [] - for point in points[tool]: - altPoints.append((point.coords.xy[0][0], point.coords.xy[1][0])) + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # Drillling! for Absolute coordinates type G90 + altPoints = [] + for point in points[tool]: + altPoints.append((point.coords.xy[0][0], point.coords.xy[1][0])) - for point in self.optimized_travelling_salesman(altPoints): - gcode += self.doformat(p.rapid_code, x=point[0], y=point[1]) - gcode += self.doformat(p.down_code, x=point[0], y=point[1]) + for point in self.optimized_travelling_salesman(altPoints): + gcode += self.doformat(p.rapid_code, x=point[0], y=point[1]) + gcode += self.doformat(p.down_code, x=point[0], y=point[1]) - measured_down_distance += abs(self.z_cut) + abs(self.z_move) + measured_down_distance += abs(self.z_cut) + abs(self.z_move) - if self.f_retract is False: - gcode += self.doformat(p.up_to_zero_code, x=point[0], y=point[1]) - measured_up_to_zero_distance += abs(self.z_cut) - measured_lift_distance += abs(self.z_move) - else: - measured_lift_distance += abs(self.z_cut) + abs(self.z_move) + if self.f_retract is False: + gcode += self.doformat(p.up_to_zero_code, x=point[0], y=point[1]) + measured_up_to_zero_distance += abs(self.z_cut) + measured_lift_distance += abs(self.z_move) + else: + measured_lift_distance += abs(self.z_cut) + abs(self.z_move) - gcode += self.doformat(p.lift_code, x=point[0], y=point[1]) - measured_distance += abs(distance_euclidian(point[0], point[1], self.oldx, self.oldy)) - self.oldx = point[0] - self.oldy = point[1] + gcode += self.doformat(p.lift_code, x=point[0], y=point[1]) + measured_distance += abs(distance_euclidian(point[0], point[1], self.oldx, self.oldy)) + self.oldx = point[0] + self.oldy = point[1] + else: + # Drillling! for Incremental coordinates type G91 + altPoints = [] + for point in points[tool]: + altPoints.append((point.coords.xy[0][0], point.coords.xy[1][0])) + + for point in self.optimized_travelling_salesman(altPoints): + point[0] = point[0] - self.oldx + point[1] = point[1] - self.oldy + + gcode += self.doformat(p.rapid_code, x=point[0], y=point[1]) + gcode += self.doformat(p.down_code, x=point[0], y=point[1]) + + measured_down_distance += abs(self.z_cut) + abs(self.z_move) + + if self.f_retract is False: + gcode += self.doformat(p.up_to_zero_code, x=point[0], y=point[1]) + measured_up_to_zero_distance += abs(self.z_cut) + measured_lift_distance += abs(self.z_move) + else: + measured_lift_distance += abs(self.z_cut) + abs(self.z_move) + + gcode += self.doformat(p.lift_code, x=point[0], y=point[1]) + measured_distance += abs(distance_euclidian(point[0], point[1], self.oldx, self.oldy)) + self.oldx = point[0] + self.oldy = point[1] else: log.debug("camlib.CNCJob.generate_from_excellon_by_tool() --> " "The loaded Excellon file has no drills ...") @@ -5864,7 +5941,7 @@ class CNCjob(Geometry): # calculate the cut distance total_cut = total_cut + geo.length - self.gcode += self.create_gcode_single_pass(geo, extracut, tolerance) + self.gcode += self.create_gcode_single_pass(geo, extracut, tolerance, old_point=current_pt) # --------- Multi-pass --------- else: @@ -5879,7 +5956,7 @@ class CNCjob(Geometry): total_cut += (geo.length * nr_cuts) self.gcode += self.create_gcode_multi_pass(geo, extracut, tolerance, - postproc=p, current_point=current_pt) + postproc=p, old_point=current_pt) # calculate the total distance total_travel = total_travel + abs(distance(pt1=current_pt, pt2=pt)) @@ -6157,7 +6234,7 @@ class CNCjob(Geometry): if not multidepth: # calculate the cut distance total_cut += geo.length - self.gcode += self.create_gcode_single_pass(geo, extracut, tolerance) + self.gcode += self.create_gcode_single_pass(geo, extracut, tolerance, old_point=current_pt) # --------- Multi-pass --------- else: @@ -6172,7 +6249,7 @@ class CNCjob(Geometry): total_cut += (geo.length * nr_cuts) self.gcode += self.create_gcode_multi_pass(geo, extracut, tolerance, - postproc=p, current_point=current_pt) + postproc=p, old_point=current_pt) # calculate the travel distance total_travel += abs(distance(pt1=current_pt, pt2=pt)) @@ -6283,7 +6360,7 @@ class CNCjob(Geometry): if pt != geo.coords[0] and pt == geo.coords[-1]: geo.coords = list(geo.coords)[::-1] - self.gcode += self.create_soldepaste_gcode(geo, p=p) + self.gcode += self.create_soldepaste_gcode(geo, p=p, old_point=current_pt) current_pt = geo.coords[-1] pt, geo = storage.nearest(current_pt) # Next @@ -6298,13 +6375,23 @@ class CNCjob(Geometry): return self.gcode - def create_soldepaste_gcode(self, geometry, p): + def create_soldepaste_gcode(self, geometry, p, old_point=(0, 0)): gcode = '' path = geometry.coords + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + first_x = path[0][0] + first_y = path[0][1] + else: + # For Incremental coordinates type G91 + first_x = path[0][0] - old_point[0] + first_y = path[0][1] - old_point[1] + if type(geometry) == LineString or type(geometry) == LinearRing: # Move fast to 1st point - gcode += self.doformat(p.rapid_code, x=path[0][0], y=path[0][1]) # Move to first point + gcode += self.doformat(p.rapid_code, x=first_x, y=first_y) # Move to first point # Move down to cutting depth gcode += self.doformat(p.z_feedrate_code) @@ -6316,8 +6403,20 @@ class CNCjob(Geometry): gcode += self.doformat(p.feedrate_xy_code) # Cutting... + prev_x = first_x + prev_y = first_y for pt in path[1:]: - gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1]) # Linear motion to point + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + next_x = pt[0] + next_y = pt[1] + else: + # For Incremental coordinates type G91 + next_x = pt[0] - prev_x + next_y = pt[1] - prev_y + gcode += self.doformat(p.linear_code, x=next_x, y=next_y) # Linear motion to point + prev_x = next_x + prev_y = next_y # Up to travelling height. gcode += self.doformat(p.spindle_off_code) # Stop dispensing @@ -6328,7 +6427,7 @@ class CNCjob(Geometry): gcode += self.doformat(p.z_feedrate_code) gcode += self.doformat(p.lift_code) elif type(geometry) == Point: - gcode += self.doformat(p.linear_code, x=path[0][0], y=path[0][1]) # Move to first point + gcode += self.doformat(p.linear_code, x=first_x, y=first_y) # Move to first point gcode += self.doformat(p.feedrate_z_dispense_code) gcode += self.doformat(p.down_z_start_code) @@ -6345,18 +6444,18 @@ class CNCjob(Geometry): gcode += self.doformat(p.lift_code) return gcode - def create_gcode_single_pass(self, geometry, extracut, tolerance): + def create_gcode_single_pass(self, geometry, extracut, tolerance, old_point=(0, 0)): # G-code. Note: self.linear2gcode() and self.point2gcode() will lower and raise the tool every time. gcode_single_pass = '' if type(geometry) == LineString or type(geometry) == LinearRing: if extracut is False: - gcode_single_pass = self.linear2gcode(geometry, tolerance=tolerance) + gcode_single_pass = self.linear2gcode(geometry, tolerance=tolerance, old_point=old_point) else: if geometry.is_ring: - gcode_single_pass = self.linear2gcode_extra(geometry, tolerance=tolerance) + gcode_single_pass = self.linear2gcode_extra(geometry, tolerance=tolerance, old_point=old_point) else: - gcode_single_pass = self.linear2gcode(geometry, tolerance=tolerance) + gcode_single_pass = self.linear2gcode(geometry, tolerance=tolerance, old_point=old_point) elif type(geometry) == Point: gcode_single_pass = self.point2gcode(geometry) else: @@ -6365,7 +6464,7 @@ class CNCjob(Geometry): return gcode_single_pass - def create_gcode_multi_pass(self, geometry, extracut, tolerance, postproc, current_point): + def create_gcode_multi_pass(self, geometry, extracut, tolerance, postproc, old_point=(0, 0)): gcode_multi_pass = '' @@ -6394,17 +6493,19 @@ class CNCjob(Geometry): # is inconsequential. if type(geometry) == LineString or type(geometry) == LinearRing: if extracut is False: - gcode_multi_pass += self.linear2gcode(geometry, tolerance=tolerance, z_cut=depth, up=False) + gcode_multi_pass += self.linear2gcode(geometry, tolerance=tolerance, z_cut=depth, up=False, + old_point=old_point) else: if geometry.is_ring: gcode_multi_pass += self.linear2gcode_extra(geometry, tolerance=tolerance, z_cut=depth, - up=False) + up=False, old_point=old_point) else: - gcode_multi_pass += self.linear2gcode(geometry, tolerance=tolerance, z_cut=depth, up=False) + gcode_multi_pass += self.linear2gcode(geometry, tolerance=tolerance, z_cut=depth, up=False, + old_point=old_point) # Ignore multi-pass for points. elif type(geometry) == Point: - gcode_multi_pass += self.point2gcode(geometry) + gcode_multi_pass += self.point2gcode(geometry, old_point=old_point) break # Ignoring ... else: log.warning("G-code generation not implemented for %s" % (str(type(geometry)))) @@ -6420,7 +6521,7 @@ class CNCjob(Geometry): geometry.coords = list(geometry.coords)[::-1] # Lift the tool - gcode_multi_pass += self.doformat(postproc.lift_code, x=current_point[0], y=current_point[1]) + gcode_multi_pass += self.doformat(postproc.lift_code, x=old_point[0], y=old_point[1]) return gcode_multi_pass def codes_split(self, gline): @@ -6692,43 +6793,134 @@ class CNCjob(Geometry): else: text = [] pos = [] - for geo in gcode_parsed: - if geo['kind'][0] == 'T': - current_position = geo['geom'].coords[0] - if current_position not in pos: - pos.append(current_position) - path_num += 1 - text.append(str(path_num)) - current_position = geo['geom'].coords[-1] - if current_position not in pos: - pos.append(current_position) - path_num += 1 - text.append(str(path_num)) + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + for geo in gcode_parsed: + if geo['kind'][0] == 'T': + current_position = geo['geom'].coords[0] + if current_position not in pos: + pos.append(current_position) + path_num += 1 + text.append(str(path_num)) - # plot the geometry of Excellon objects - if self.origin_kind == 'excellon': - try: - poly = Polygon(geo['geom']) - except ValueError: - # if the geos are travel lines it will enter into Exception + current_position = geo['geom'].coords[-1] + if current_position not in pos: + pos.append(current_position) + path_num += 1 + text.append(str(path_num)) + + # plot the geometry of Excellon objects + if self.origin_kind == 'excellon': + try: + poly = Polygon(geo['geom']) + except ValueError: + # if the geos are travel lines it will enter into Exception + poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle) + poly = poly.simplify(tool_tolerance) + else: + # plot the geometry of any objects other than Excellon poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle) poly = poly.simplify(tool_tolerance) - else: - # plot the geometry of any objects other than Excellon - poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle) - poly = poly.simplify(tool_tolerance) - if kind == 'all': - obj.add_shape(shape=poly, color=color[geo['kind'][0]][1], face_color=color[geo['kind'][0]][0], - visible=visible, layer=1 if geo['kind'][0] == 'C' else 2) - elif kind == 'travel': + if kind == 'all': + obj.add_shape(shape=poly, color=color[geo['kind'][0]][1], face_color=color[geo['kind'][0]][0], + visible=visible, layer=1 if geo['kind'][0] == 'C' else 2) + elif kind == 'travel': + if geo['kind'][0] == 'T': + obj.add_shape(shape=poly, color=color['T'][1], face_color=color['T'][0], + visible=visible, layer=2) + elif kind == 'cut': + if geo['kind'][0] == 'C': + obj.add_shape(shape=poly, color=color['C'][1], face_color=color['C'][0], + visible=visible, layer=1) + else: + # For Incremental coordinates type G91 + current_x = gcode_parsed[0]['geom'].coords[0][0] + current_y = gcode_parsed[0]['geom'].coords[0][1] + old_pos = ( + current_x, + current_y + ) + + for geo in gcode_parsed: + print(list(geo['geom'].coordsner)) if geo['kind'][0] == 'T': - obj.add_shape(shape=poly, color=color['T'][1], face_color=color['T'][0], - visible=visible, layer=2) - elif kind == 'cut': - if geo['kind'][0] == 'C': - obj.add_shape(shape=poly, color=color['C'][1], face_color=color['C'][0], - visible=visible, layer=1) + current_position = ( + geo['geom'].coords[0][0] + old_pos[0], + geo['geom'].coords[0][1] + old_pos[1] + ) + if current_position not in pos: + pos.append(current_position) + path_num += 1 + text.append(str(path_num)) + + delta = ( + geo['geom'].coords[-1][0] - geo['geom'].coords[0][0], + geo['geom'].coords[-1][1] - geo['geom'].coords[0][1] + ) + current_position = ( + current_position[0] + geo['geom'].coords[-1][0], + current_position[1] + geo['geom'].coords[-1][1] + ) + if current_position not in pos: + pos.append(current_position) + path_num += 1 + text.append(str(path_num)) + + # plot the geometry of Excellon objects + if self.origin_kind == 'excellon': + if isinstance(geo['geom'], Point): + # if geo is Point + current_position = ( + current_position[0] + geo['geom'].x, + current_position[1] + geo['geom'].y + ) + poly = Polygon(Point(current_position)) + elif isinstance(geo['geom'], LineString): + # if the geos are travel lines (LineStrings) + new_line_pts = [] + old_line_pos = deepcopy(current_position) + for p in list(geo['geom'].coords): + current_position = ( + current_position[0] + p[0], + current_position[1] + p[1] + ) + new_line_pts.append(current_position) + old_line_pos = p + new_line = LineString(new_line_pts) + + poly = new_line.buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle) + poly = poly.simplify(tool_tolerance) + else: + # plot the geometry of any objects other than Excellon + new_line_pts = [] + old_line_pos = deepcopy(current_position) + for p in list(geo['geom'].coords): + current_position = ( + current_position[0] + p[0], + current_position[1] + p[1] + ) + new_line_pts.append(current_position) + old_line_pos = p + new_line = LineString(new_line_pts) + + poly = new_line.buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle) + poly = poly.simplify(tool_tolerance) + + old_pos = deepcopy(current_position) + + if kind == 'all': + obj.add_shape(shape=poly, color=color[geo['kind'][0]][1], face_color=color[geo['kind'][0]][0], + visible=visible, layer=1 if geo['kind'][0] == 'C' else 2) + elif kind == 'travel': + if geo['kind'][0] == 'T': + obj.add_shape(shape=poly, color=color['T'][1], face_color=color['T'][0], + visible=visible, layer=2) + elif kind == 'cut': + if geo['kind'][0] == 'C': + obj.add_shape(shape=poly, color=color['C'][1], face_color=color['C'][0], + visible=visible, layer=1) try: obj.annotation.set(text=text, pos=pos, visible=obj.options['plot'], font_size=self.app.defaults["cncjob_annotation_fontsize"], @@ -6798,7 +6990,7 @@ class CNCjob(Geometry): def linear2gcode(self, linear, tolerance=0, down=True, up=True, z_cut=None, z_move=None, zdownrate=None, - feedrate=None, feedrate_z=None, feedrate_rapid=None, cont=False): + feedrate=None, feedrate_z=None, feedrate_rapid=None, cont=False, old_point=(0, 0)): """ Generates G-code to cut along the linear feature. @@ -6845,30 +7037,51 @@ class CNCjob(Geometry): p = self.pp_geometry + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + first_x = path[0][0] + first_y = path[0][1] + else: + # For Incremental coordinates type G91 + first_x = path[0][0] - old_point[0] + first_y = path[0][1] - old_point[1] + # Move fast to 1st point if not cont: - gcode += self.doformat(p.rapid_code, x=path[0][0], y=path[0][1]) # Move to first point + gcode += self.doformat(p.rapid_code, x=first_x, y=first_y) # Move to first point # Move down to cutting depth if down: # Different feedrate for vertical cut? gcode += self.doformat(p.z_feedrate_code) # gcode += self.doformat(p.feedrate_code) - gcode += self.doformat(p.down_code, x=path[0][0], y=path[0][1], z_cut=z_cut) + gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut=z_cut) gcode += self.doformat(p.feedrate_code, feedrate=feedrate) # Cutting... + prev_x = first_x + prev_y = first_y for pt in path[1:]: - gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1], z=z_cut) # Linear motion to point - + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + next_x = pt[0] + next_y = pt[1] + else: + # For Incremental coordinates type G91 + next_x = pt[0] - prev_x + next_y = pt[1] - prev_y + gcode += self.doformat(p.linear_code, x=next_x, y=next_y, z=z_cut) # Linear motion to point + prev_x = pt[0] + prev_y = pt[1] # Up to travelling height. if up: - gcode += self.doformat(p.lift_code, x=pt[0], y=pt[1], z_move=z_move) # Stop cutting + gcode += self.doformat(p.lift_code, x=prev_x, y=prev_y, z_move=z_move) # Stop cutting return gcode def linear2gcode_extra(self, linear, tolerance=0, down=True, up=True, z_cut=None, z_move=None, zdownrate=None, - feedrate=None, feedrate_z=None, feedrate_rapid=None, cont=False): + feedrate=None, feedrate_z=None, feedrate_rapid=None, cont=False, old_point=(0, 0)): """ Generates G-code to cut along the linear feature. @@ -6913,9 +7126,19 @@ class CNCjob(Geometry): path = list(target_linear.coords) p = self.pp_geometry + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + first_x = path[0][0] + first_y = path[0][1] + else: + # For Incremental coordinates type G91 + first_x = path[0][0] - old_point[0] + first_y = path[0][1] - old_point[1] + # Move fast to 1st point if not cont: - gcode += self.doformat(p.rapid_code, x=path[0][0], y=path[0][1]) # Move to first point + gcode += self.doformat(p.rapid_code, x=first_x, y=first_y) # Move to first point # Move down to cutting depth if down: @@ -6923,40 +7146,72 @@ class CNCjob(Geometry): if self.z_feedrate is not None: gcode += self.doformat(p.z_feedrate_code) # gcode += self.doformat(p.feedrate_code) - gcode += self.doformat(p.down_code, x=path[0][0], y=path[0][1], z_cut=z_cut) + gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut=z_cut) gcode += self.doformat(p.feedrate_code, feedrate=feedrate) else: - gcode += self.doformat(p.down_code, x=path[0][0], y=path[0][1], z_cut=z_cut) # Start cutting + gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut=z_cut) # Start cutting # Cutting... + prev_x = first_x + prev_y = first_y for pt in path[1:]: - gcode += self.doformat(p.linear_code, x=pt[0], y=pt[1], z=z_cut) # Linear motion to point + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + next_x = pt[0] + next_y = pt[1] + else: + # For Incremental coordinates type G91 + next_x = pt[0] - prev_x + next_y = pt[1] - prev_y + gcode += self.doformat(p.linear_code, x=next_x, y=next_y, z=z_cut) # Linear motion to point + prev_x = pt[0] + prev_y = pt[1] # this line is added to create an extra cut over the first point in patch # to make sure that we remove the copper leftovers - gcode += self.doformat(p.linear_code, x=path[1][0], y=path[1][1]) # Linear motion to the 1st point in the cut path + # Linear motion to the 1st point in the cut path + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + last_x = path[1][0] + last_y = path[1][1] + else: + # For Incremental coordinates type G91 + last_x = path[1][0] - first_x + last_y = path[1][1] - first_y + gcode += self.doformat(p.linear_code, x=last_x, y=last_y) # Up to travelling height. if up: - gcode += self.doformat(p.lift_code, x=path[1][0], y=path[1][1], z_move=z_move) # Stop cutting + gcode += self.doformat(p.lift_code, x=last_x, y=last_y, z_move=z_move) # Stop cutting return gcode - def point2gcode(self, point): + def point2gcode(self, point, old_point=(0, 0)): gcode = "" path = list(point.coords) p = self.pp_geometry - gcode += self.doformat(p.linear_code, x=path[0][0], y=path[0][1]) # Move to first point + + self.coordinates_type = self.app.defaults["cncjob_coords_type"] + if self.coordinates_type == "G90": + # For Absolute coordinates type G90 + first_x = path[0][0] + first_y = path[0][1] + else: + # For Incremental coordinates type G91 + first_x = path[0][0] - old_point[0] + first_y = path[0][1] - old_point[1] + + gcode += self.doformat(p.linear_code, x=first_x, y=first_y) # Move to first point if self.z_feedrate is not None: gcode += self.doformat(p.z_feedrate_code) - gcode += self.doformat(p.down_code, x=path[0][0], y=path[0][1], z_cut = self.z_cut) + gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut = self.z_cut) gcode += self.doformat(p.feedrate_code) else: - gcode += self.doformat(p.down_code, x=path[0][0], y=path[0][1], z_cut = self.z_cut) # Start cutting + gcode += self.doformat(p.down_code, x=first_x, y=first_y, z_cut = self.z_cut) # Start cutting - gcode += self.doformat(p.lift_code, x=path[0][0], y=path[0][1]) # Stop cutting + gcode += self.doformat(p.lift_code, x=first_x, y=first_y) # Stop cutting return gcode def export_svg(self, scale_factor=0.00): diff --git a/flatcamGUI/FlatCAMGUI.py b/flatcamGUI/FlatCAMGUI.py index 5a80dd06..9dd7572c 100644 --- a/flatcamGUI/FlatCAMGUI.py +++ b/flatcamGUI/FlatCAMGUI.py @@ -6119,8 +6119,8 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI): grid0 = QtWidgets.QGridLayout() self.layout.addLayout(grid0) - grid0.setColumnStretch(1, 1) - grid0.setColumnStretch(2, 1) + # grid0.setColumnStretch(1, 1) + # grid0.setColumnStretch(2, 1) # Plot CB # self.plot_cb = QtWidgets.QCheckBox('Plot') @@ -6129,7 +6129,7 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.plot_cb, 0, 0) # Plot Kind - self.cncplot_method_label = QtWidgets.QLabel('%s:' % _("Plot kind:")) + self.cncplot_method_label = QtWidgets.QLabel('%s:' % _("Plot kind")) self.cncplot_method_label.setToolTip( _("This selects the kind of geometries on the canvas to plot.\n" "Those can be either of type 'Travel' which means the moves\n" @@ -6205,34 +6205,52 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI): grid0.addWidget(self.steps_per_circle_entry, 5, 1) # Tool dia for plot - tdlabel = QtWidgets.QLabel('%s:' % _('Tool dia')) + tdlabel = QtWidgets.QLabel('%s:' % _('Travel dia')) tdlabel.setToolTip( - _("Diameter of the tool to be\n" + _("The width of the travel lines to be\n" "rendered in the plot.") ) - grid0.addWidget(tdlabel, 6, 0) self.tooldia_entry = LengthEntry() + grid0.addWidget(tdlabel, 6, 0) grid0.addWidget(self.tooldia_entry, 6, 1) + # add a space + grid0.addWidget(QtWidgets.QLabel(''), 7, 0) + # Number of decimals to use in GCODE coordinates - cdeclabel = QtWidgets.QLabel('%s:' % _('Coords dec.')) + cdeclabel = QtWidgets.QLabel('%s:' % _('Coordinates decimals')) cdeclabel.setToolTip( _("The number of decimals to be used for \n" "the X, Y, Z coordinates in CNC code (GCODE, etc.)") ) - grid0.addWidget(cdeclabel, 7, 0) self.coords_dec_entry = IntEntry() - grid0.addWidget(self.coords_dec_entry, 7, 1) + grid0.addWidget(cdeclabel, 8, 0) + grid0.addWidget(self.coords_dec_entry, 8, 1) # Number of decimals to use in GCODE feedrate - frdeclabel = QtWidgets.QLabel('%s:' % _('Feedrate dec.')) + frdeclabel = QtWidgets.QLabel('%s:' % _('Feedrate decimals')) frdeclabel.setToolTip( _("The number of decimals to be used for \n" "the Feedrate parameter in CNC code (GCODE, etc.)") ) - grid0.addWidget(frdeclabel, 8, 0) self.fr_dec_entry = IntEntry() - grid0.addWidget(self.fr_dec_entry, 8, 1) + grid0.addWidget(frdeclabel, 9, 0) + grid0.addWidget(self.fr_dec_entry, 9, 1) + + # The type of coordinates used in the Gcode: Absolute or Incremental + coords_type_label = QtWidgets.QLabel('%s:' % _('Coordinates type')) + coords_type_label.setToolTip( + _("The type of coordinates to be used in Gcode.\n" + "Can be:\n" + "- Absolute G90 -> the reference is the origin x=0, y=0\n" + "- Incremental G91 -> the reference is the previous position") + ) + self.coords_type_radio = RadioSet([ + {"label": _("Absolute G90"), "value": "G90"}, + {"label": _("Incremental G91"), "value": "G91"} + ], orientation='vertical', stretch=False) + grid0.addWidget(coords_type_label, 10, 0) + grid0.addWidget(self.coords_type_radio, 10, 1) self.layout.addStretch()