- added the Exclusion zones processing to Geometry GCode generation

This commit is contained in:
Marius Stanciu 2020-05-23 04:32:57 +03:00 committed by Marius
parent 48fbc10f6d
commit 2e8d5b3b96
5 changed files with 346 additions and 63 deletions

View File

@ -989,7 +989,6 @@ class CNCJobObject(FlatCAMObj, CNCjob):
for key in self.cnc_tools:
ppg = self.cnc_tools[key]['data']['ppname_g']
if 'toolchange_custom' not in str(ppg).lower():
print(ppg)
if self.ui.toolchange_cb.get_value():
self.ui.toolchange_cb.set_value(False)
self.app.inform.emit('[WARNING_NOTCL] %s' %
@ -1107,7 +1106,7 @@ class CNCJobObject(FlatCAMObj, CNCjob):
except ValueError:
# we may have a tuple with only one element and a comma
dia_plot = [float(el) for el in self.options["tooldia"].split(',') if el != ''][0]
self.plot2(dia_plot, obj=self, visible=visible, kind=kind)
self.plot2(tooldia=dia_plot, obj=self, visible=visible, kind=kind)
else:
# multiple tools usage
if self.cnc_tools:
@ -1117,12 +1116,16 @@ class CNCJobObject(FlatCAMObj, CNCjob):
self.plot2(tooldia=tooldia, obj=self, visible=visible, gcode_parsed=gcode_parsed, kind=kind)
# TODO: until the gcode parsed will be stored on each Excellon tool this will not get executed
if self.exc_cnc_tools:
for tooldia_key in self.exc_cnc_tools:
tooldia = float('%.*f' % (self.decimals, float(tooldia_key)))
# gcode_parsed = self.cnc_tools[tooldia_key]['gcode_parsed']
gcode_parsed = self.gcode_parsed
self.plot2(tooldia=tooldia, obj=self, visible=visible, gcode_parsed=gcode_parsed, kind=kind)
# I do this so the travel lines thickness will reflect the tool diameter
# may work only for objects created within the app and not Gcode imported from elsewhere for which we
# don't know the origin
if self.origin_kind == "excellon":
if self.exc_cnc_tools:
for tooldia_key in self.exc_cnc_tools:
tooldia = float('%.*f' % (self.decimals, float(tooldia_key)))
# gcode_parsed = self.exc_cnc_tools[tooldia_key]['gcode_parsed']
gcode_parsed = self.gcode_parsed
self.plot2(tooldia=tooldia, obj=self, visible=visible, gcode_parsed=gcode_parsed, kind=kind)
self.shapes.redraw()
except (ObjectDeleted, AttributeError):

View File

@ -14,8 +14,8 @@ import urllib.error
import getopt
import random
import simplejson as json
import lzma
import shutil
import lzma
from datetime import datetime
import time
import ctypes

View File

@ -10,6 +10,7 @@ CHANGELOG for FlatCAM beta
22.05.2020
- fixed the algorithm for calculating closest points in the Exclusion areas
- added the Exclusion zones processing to Geometry GCode generation
21.05.2020

383
camlib.py
View File

@ -1103,15 +1103,17 @@ class Geometry(object):
"""
Imports shapes from an IMAGE file into the object's geometry.
:param filename: Path to the IMAGE file.
:type filename: str
:param flip: Flip the object vertically.
:type flip: bool
:param units: FlatCAM units
:param dpi: dots per inch on the imported image
:param mode: how to import the image: as 'black' or 'color'
:param mask: level of detail for the import
:return: None
:param filename: Path to the IMAGE file.
:type filename: str
:param flip: Flip the object vertically.
:type flip: bool
:param units: FlatCAM units
:type units: str
:param dpi: dots per inch on the imported image
:param mode: how to import the image: as 'black' or 'color'
:type mode: str
:param mask: level of detail for the import
:return: None
"""
if mask is None:
mask = [128, 128, 128, 128]
@ -1985,7 +1987,7 @@ class Geometry(object):
it again in descendents.
:param obj_units: "IN" or "MM"
:type units: str
:type obj_units: str
:return: Scaling factor resulting from unit change.
:rtype: float
"""
@ -2550,9 +2552,23 @@ class CNCjob(Geometry):
@property
def postdata(self):
"""
This will return all the attributes of the class in the form of a dictionary
:return: Class attributes
:rtype: dict
"""
return self.__dict__
def convert_units(self, units):
"""
Will convert the parameters in the class that are relevant, from metric to imperial and reverse
:param units: FlatCAM units
:type units: str
:return: conversion factor
:rtype: float
"""
log.debug("camlib.CNCJob.convert_units()")
factor = Geometry.convert_units(self, units)
@ -2573,6 +2589,17 @@ class CNCjob(Geometry):
return self.doformat2(fun, **kwargs) + "\n"
def doformat2(self, fun, **kwargs):
"""
This method will call one of the current preprocessor methods having as parameters all the attributes of
current class to which will add the kwargs parameters
:param fun: One of the methods inside the preprocessor classes which get loaded here in the 'p' object
:type fun: class 'function'
:param kwargs: keyword args which will update attributes of the current class
:type kwargs: dict
:return: Gcode line
:rtype: str
"""
attributes = AttrDict()
attributes.update(self.postdata)
attributes.update(kwargs)
@ -2584,6 +2611,16 @@ class CNCjob(Geometry):
return ''
def parse_custom_toolchange_code(self, data):
"""
Will parse a text and get a toolchange sequence in text format suitable to be included in a Gcode file.
The '%' symbol is used to surround class variables name and must be removed in the returned string.
After that, the class variables (attributes) are replaced with the current values. The result is returned.
:param data: Toolchange sequence
:type data: str
:return: Processed toolchange sequence
:rtype: str
"""
text = data
match_list = self.re_toolchange_custom.findall(text)
@ -2615,6 +2652,13 @@ class CNCjob(Geometry):
[2, 3], [2, 4], [3, 4], [3, 3], [3, 2], [3, 1], [3, 0], [4, 0], [4, 1], [4, 2], [4, 3], [4, 4]]
>>> optimized_travelling_salesman([[0,0],[10,0],[6,0]])
[[0, 0], [6, 0], [10, 0]]
:param points: List of tuples with x, y coordinates
:type points: list
:param start: a tuple with a x,y coordinates of the start point
:type start: tuple
:return: List of points ordered in a optimized way
:rtype: list
"""
if start is None:
@ -3899,7 +3943,9 @@ class CNCjob(Geometry):
# calculate the cut distance
total_cut = total_cut + geo.length
self.gcode += self.create_gcode_single_pass(geo, extracut, extracut_length, tolerance,
self.gcode += self.create_gcode_single_pass(geo, current_tooldia, extracut, extracut_length,
tolerance,
z_move=z_move, postproc=p,
old_point=current_pt)
# --------- Multi-pass ---------
@ -3914,8 +3960,10 @@ class CNCjob(Geometry):
total_cut += (geo.length * nr_cuts)
self.gcode += self.create_gcode_multi_pass(geo, extracut, extracut_length, tolerance,
postproc=p, old_point=current_pt)
self.gcode += self.create_gcode_multi_pass(geo, current_tooldia, extracut, extracut_length,
tolerance,
z_move=z_move, postproc=p,
old_point=current_pt)
# calculate the total distance
total_travel = total_travel + abs(distance(pt1=current_pt, pt2=pt))
@ -4216,20 +4264,24 @@ class CNCjob(Geometry):
# this is the tool diameter, it is used as such to accommodate the preprocessor who need the tool diameter
# given under the name 'toolC'
# this is a fancy way of adding a class attribute (which should be added in the __init__ method) without doing
# it there :)
self.postdata['toolC'] = self.tooldia
# Initial G-Code
self.pp_geometry = self.app.preprocessors[self.pp_geometry_name]
# the 'p' local attribute is a reference to the current preprocessor class
p = self.pp_geometry
self.oldx = 0.0
self.oldy = 0.0
self.gcode = self.doformat(p.start_code)
self.gcode += self.doformat(p.feedrate_code) # sets the feed rate
if toolchange is False:
# all the x and y parameters in self.doformat() are used only by some preprocessors not by all
self.gcode += self.doformat(p.lift_code, x=self.oldx, y=self.oldy) # Move (up) to travel height
self.gcode += self.doformat(p.startz_code, x=self.oldx, y=self.oldy)
@ -4277,6 +4329,9 @@ class CNCjob(Geometry):
path_count = 0
current_pt = (0, 0)
pt, geo = storage.nearest(current_pt)
# when nothing is left in the storage a StopIteration exception will be raised therefore stopping
# the whole process including the infinite loop while True below.
try:
while True:
if self.app.abort_flag:
@ -4297,7 +4352,9 @@ class CNCjob(Geometry):
if not multidepth:
# calculate the cut distance
total_cut += geo.length
self.gcode += self.create_gcode_single_pass(geo, extracut, self.extracut_length, tolerance,
self.gcode += self.create_gcode_single_pass(geo, current_tooldia, extracut, self.extracut_length,
tolerance,
z_move=z_move, postproc=p,
old_point=current_pt)
# --------- Multi-pass ---------
@ -4312,8 +4369,10 @@ class CNCjob(Geometry):
total_cut += (geo.length * nr_cuts)
self.gcode += self.create_gcode_multi_pass(geo, extracut, self.extracut_length, tolerance,
postproc=p, old_point=current_pt)
self.gcode += self.create_gcode_multi_pass(geo, current_tooldia, extracut, self.extracut_length,
tolerance,
z_move=z_move,_postproc=p,
old_point=current_pt)
# calculate the travel distance
total_travel += abs(distance(pt1=current_pt, pt2=pt))
@ -4321,6 +4380,7 @@ class CNCjob(Geometry):
pt, geo = storage.nearest(current_pt) # Next
# update the activity counter (lower left side of the app, status bar)
disp_number = int(np.interp(path_count, [0, geo_len], [0, 100]))
if old_disp_number < disp_number <= 100:
self.app.proc_container.update_view_text(' %d%%' % disp_number)
@ -4535,27 +4595,76 @@ class CNCjob(Geometry):
gcode += self.doformat(p.lift_code)
return gcode
def create_gcode_single_pass(self, geometry, extracut, extracut_length, tolerance, old_point=(0, 0)):
def create_gcode_single_pass(self, geometry, cdia, extracut, extracut_length, tolerance, z_move, postproc,
old_point=(0, 0)):
"""
# G-code. Note: self.linear2gcode() and self.point2gcode() will lower and raise the tool every time.
:param geometry: A Shapely Geometry (LineString or LinearRing) which is the path to be cut
:type geometry: LineString, LinearRing
:param cdia: Tool diameter
:type cdia: float
:param extracut: Will add an extra cut over the point where start of the cut is met with the end cut
:type extracut: bool
:param extracut_length: The length of the extra cut: half before the meeting point, half after
:type extracut_length: float
:param tolerance: Tolerance used to simplify the paths (making them mre rough)
:type tolerance: float
:param z_move: Travel Z
:type z_move: float
:param postproc: Preprocessor class
:type postproc: class
:param old_point: Previous point
:type old_point: tuple
:return: Gcode
:rtype: str
"""
# p = postproc
if type(geometry) == LineString or type(geometry) == LinearRing:
if extracut is False:
gcode_single_pass = self.linear2gcode(geometry, tolerance=tolerance, old_point=old_point)
gcode_single_pass = self.linear2gcode(geometry, z_move=z_move, dia=cdia, tolerance=tolerance,
old_point=old_point)
else:
if geometry.is_ring:
gcode_single_pass = self.linear2gcode_extra(geometry, extracut_length, tolerance=tolerance,
z_move=z_move, dia=cdia,
old_point=old_point)
else:
gcode_single_pass = self.linear2gcode(geometry, tolerance=tolerance, old_point=old_point)
gcode_single_pass = self.linear2gcode(geometry, tolerance=tolerance, z_move=z_move, dia=cdia,
old_point=old_point)
elif type(geometry) == Point:
gcode_single_pass = self.point2gcode(geometry)
gcode_single_pass = self.point2gcode(geometry, dia=cdia, z_move=z_move, old_point=old_point)
else:
log.warning("G-code generation not implemented for %s" % (str(type(geometry))))
return
return gcode_single_pass
def create_gcode_multi_pass(self, geometry, extracut, extracut_length, tolerance, postproc, old_point=(0, 0)):
def create_gcode_multi_pass(self, geometry, cdia, extracut, extracut_length, tolerance, postproc, z_move,
old_point=(0, 0)):
"""
:param geometry: A Shapely Geometry (LineString or LinearRing) which is the path to be cut
:type geometry: LineString, LinearRing
:param cdia: Tool diameter
:type cdia: float
:param extracut: Will add an extra cut over the point where start of the cut is met with the end cut
:type extracut: bool
:param extracut_length: The length of the extra cut: half before the meeting point, half after
:type extracut_length: float
:param tolerance: Tolerance used to simplify the paths (making them mre rough)
:type tolerance: float
:param postproc: Preprocessor class
:type postproc: class
:param z_move: Travel Z
:type z_move: float
:param old_point: Previous point
:type old_point: tuple
:return: Gcode
:rtype: str
"""
p = postproc
gcode_multi_pass = ''
@ -4585,18 +4694,20 @@ class CNCjob(Geometry):
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,
old_point=old_point)
z_move=z_move, dia=cdia, old_point=old_point)
else:
if geometry.is_ring:
gcode_multi_pass += self.linear2gcode_extra(geometry, extracut_length, tolerance=tolerance,
z_cut=depth, up=False, old_point=old_point)
dia=cdia, z_move=z_move, z_cut=depth, up=False,
old_point=old_point)
else:
gcode_multi_pass += self.linear2gcode(geometry, tolerance=tolerance, z_cut=depth, up=False,
dia=cdia, z_move=z_move,
old_point=old_point)
# Ignore multi-pass for points.
elif type(geometry) == Point:
gcode_multi_pass += self.point2gcode(geometry, old_point=old_point)
gcode_multi_pass += self.point2gcode(geometry, dia=cdia, z_move=z_move, old_point=old_point)
break # Ignoring ...
else:
log.warning("G-code generation not implemented for %s" % (str(type(geometry))))
@ -4612,7 +4723,7 @@ class CNCjob(Geometry):
geometry.coords = list(geometry.coords)[::-1]
# Lift the tool
gcode_multi_pass += self.doformat(postproc.lift_code, x=old_point[0], y=old_point[1])
gcode_multi_pass += self.doformat(p.lift_code, x=old_point[0], y=old_point[1])
return gcode_multi_pass
def codes_split(self, gline):
@ -4620,8 +4731,10 @@ class CNCjob(Geometry):
Parses a line of G-Code such as "G01 X1234 Y987" into
a dictionary: {'G': 1.0, 'X': 1234.0, 'Y': 987.0}
:param gline: G-Code line string
:return: Dictionary with parsed line.
:param gline: G-Code line string
:type gline: str
:return: Dictionary with parsed line.
:rtype: dict
"""
command = {}
@ -4690,6 +4803,18 @@ class CNCjob(Geometry):
G-Code parser (from self.gcode). Generates dictionary with
single-segment LineString's and "kind" indicating cut or travel,
fast or feedrate speed.
Will return a dict in the format:
{
"geom": LineString(path),
"kind": kind
}
where kind can be either ["C", "F"] # T=travel, C=cut, F=fast, S=slow
:param force_parsing:
:type force_parsing:
:return:
:rtype: dict
"""
kind = ["C", "F"] # T=travel, C=cut, F=fast, S=slow
@ -4879,16 +5004,28 @@ class CNCjob(Geometry):
"""
Plots the G-code job onto the given axes.
:param tooldia: Tool diameter.
:param dpi: Not used!
:param margin: Not used!
:param color: Color specification.
:param alpha: Transparency specification.
:param tool_tolerance: Tolerance when drawing the toolshape.
:param obj
:param visible
:param kind
:return: None
:param tooldia: Tool diameter.
:type tooldia: float
:param dpi: Not used!
:type dpi: float
:param margin: Not used!
:type margin: float
:param gcode_parsed: Parsed Gcode
:type gcode_parsed: str
:param color: Color specification.
:type color: str
:param alpha: Transparency specification.
:type alpha: dict
:param tool_tolerance: Tolerance when drawing the toolshape.
:type tool_tolerance: float
:param obj: The object for whih to plot
:type obj: class
:param visible: Visibility status
:type visible: bool
:param kind: Can be: "travel", "cut", "all"
:type kind: str
:return: None
:rtype:
"""
# units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
@ -5045,9 +5182,17 @@ class CNCjob(Geometry):
log.debug("CNCJob.plot2() --> annotations --> %s" % str(e))
def create_geometry(self):
self.app.inform.emit('%s: %s' % (_("Unifying Geometry from parsed Geometry segments"),
str(len(self.gcode_parsed))))
"""
It is used by the Excellon objects. Will create the solid_geometry which will be an attribute of the
Excellon object class.
:return: List of Shapely geometry elements
:rtype: list
"""
# TODO: This takes forever. Too much data?
# self.app.inform.emit('%s: %s' % (_("Unifying Geometry from parsed Geometry segments"),
# str(len(self.gcode_parsed))))
# self.solid_geometry = cascaded_union([geo['geom'] for geo in self.gcode_parsed])
# This is much faster but not so nice to look at as you can see different segments of the geometry
@ -5055,10 +5200,15 @@ class CNCjob(Geometry):
return self.solid_geometry
# code snippet added by Lei Zheng in a rejected pull request on FlatCAM https://bitbucket.org/realthunder/
def segment(self, coords):
"""
break long linear lines to make it more auto level friendly
Break long linear lines to make it more auto level friendly.
Code snippet added by Lei Zheng in a rejected pull request on FlatCAM https://bitbucket.org/realthunder/
:param coords: List of coordinates tuples
:type coords: list
:return: A path; list with the multiple coordinates breaking a line.
:rtype: list
"""
if len(coords) < 2 or self.segx <= 0 and self.segy <= 0:
@ -5110,7 +5260,7 @@ class CNCjob(Geometry):
return path
def linear2gcode(self, linear, tolerance=0, down=True, up=True, z_cut=None, z_move=None, zdownrate=None,
def linear2gcode(self, linear, dia, tolerance=0, down=True, up=True, z_cut=None, z_move=None, zdownrate=None,
feedrate=None, feedrate_z=None, feedrate_rapid=None, cont=False, old_point=(0, 0)):
"""
@ -5118,6 +5268,8 @@ class CNCjob(Geometry):
:param linear: The path to cut along.
:type: Shapely.LinearRing or Shapely.Linear String
:param dia: The tool diameter that is going on the path
:type dia: float
:param tolerance: All points in the simplified object will be within the
tolerance distance of the original geometry.
:type tolerance: float
@ -5177,7 +5329,42 @@ class CNCjob(Geometry):
# Move fast to 1st point
if not cont:
gcode += self.doformat(p.rapid_code, x=first_x, y=first_y) # Move to first point
current_tooldia = dia
travels = self.app.exc_areas.travel_coordinates(start_point=(old_point[0], old_point[1]),
end_point=(first_x, first_y),
tooldia=current_tooldia)
prev_z = None
for travel in travels:
locx = travel[1][0]
locy = travel[1][1]
if travel[0] is not None:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# raise to safe Z (travel[0]) each time because safe Z may be different
self.z_move = travel[0]
gcode += self.doformat(p.lift_code, x=locx, y=locy)
# restore z_move
self.z_move = z_move
else:
if prev_z is not None:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# we assume that previously the z_move was altered therefore raise to
# the travel_z (z_move)
self.z_move = z_move
gcode += self.doformat(p.lift_code, x=locx, y=locy)
else:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# store prev_z
prev_z = travel[0]
# gcode += self.doformat(p.rapid_code, x=first_x, y=first_y) # Move to first point
# Move down to cutting depth
if down:
@ -5216,7 +5403,7 @@ class CNCjob(Geometry):
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, extracut_length, tolerance=0, down=True, up=True,
def linear2gcode_extra(self, linear, dia, extracut_length, tolerance=0, down=True, up=True,
z_cut=None, z_move=None, zdownrate=None,
feedrate=None, feedrate_z=None, feedrate_rapid=None, cont=False, old_point=(0, 0)):
"""
@ -5225,6 +5412,8 @@ class CNCjob(Geometry):
:param linear: The path to cut along.
:type: Shapely.LinearRing or Shapely.Linear String
:param dia: The tool diameter that is going on the path
:type dia: float
:param extracut_length: how much to cut extra over the first point at the end of the path
:param tolerance: All points in the simplified object will be within the
tolerance distance of the original geometry.
@ -5284,7 +5473,42 @@ class CNCjob(Geometry):
# Move fast to 1st point
if not cont:
gcode += self.doformat(p.rapid_code, x=first_x, y=first_y) # Move to first point
current_tooldia = dia
travels = self.app.exc_areas.travel_coordinates(start_point=(old_point[0], old_point[1]),
end_point=(first_x, first_y),
tooldia=current_tooldia)
prev_z = None
for travel in travels:
locx = travel[1][0]
locy = travel[1][1]
if travel[0] is not None:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# raise to safe Z (travel[0]) each time because safe Z may be different
self.z_move = travel[0]
gcode += self.doformat(p.lift_code, x=locx, y=locy)
# restore z_move
self.z_move = z_move
else:
if prev_z is not None:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# we assume that previously the z_move was altered therefore raise to
# the travel_z (z_move)
self.z_move = z_move
gcode += self.doformat(p.lift_code, x=locx, y=locy)
else:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# store prev_z
prev_z = travel[0]
# gcode += self.doformat(p.rapid_code, x=first_x, y=first_y) # Move to first point
# Move down to cutting depth
if down:
@ -5450,7 +5674,20 @@ class CNCjob(Geometry):
return gcode
def point2gcode(self, point, old_point=(0, 0)):
def point2gcode(self, point, dia, z_move=None, old_point=(0, 0)):
"""
:param point: A Shapely Point
:type point: Point
:param dia: The tool diameter that is going on the path
:type dia: float
:param z_move: Travel Z
:type z_move: float
:param old_point: Old point coordinates from which we moved to the 'point'
:type old_point: tuple
:return: G-code to cut on the Point feature.
:rtype: str
"""
gcode = ""
if self.app.abort_flag:
@ -5474,7 +5711,42 @@ class CNCjob(Geometry):
first_x = path[0][0]
first_y = path[0][1]
gcode += self.doformat(p.linear_code, x=first_x, y=first_y) # Move to first point
current_tooldia = dia
travels = self.app.exc_areas.travel_coordinates(start_point=(old_point[0], old_point[1]),
end_point=(first_x, first_y),
tooldia=current_tooldia)
prev_z = None
for travel in travels:
locx = travel[1][0]
locy = travel[1][1]
if travel[0] is not None:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# raise to safe Z (travel[0]) each time because safe Z may be different
self.z_move = travel[0]
gcode += self.doformat(p.lift_code, x=locx, y=locy)
# restore z_move
self.z_move = z_move
else:
if prev_z is not None:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# we assume that previously the z_move was altered therefore raise to
# the travel_z (z_move)
self.z_move = z_move
gcode += self.doformat(p.lift_code, x=locx, y=locy)
else:
# move to next point
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
# store prev_z
prev_z = travel[0]
# 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)
@ -5490,8 +5762,10 @@ class CNCjob(Geometry):
"""
Exports the CNC Job as a SVG Element
:scale_factor: float
:return: SVG Element string
:param scale_stroke_factor: A factor to scale the SVG geometry
:type scale_stroke_factor: float
:return: SVG Element string
:rtype: str
"""
# scale_factor is a multiplication factor for the SVG stroke-width used within shapely's svg export
# If not specified then try and use the tool diameter
@ -5511,6 +5785,9 @@ class CNCjob(Geometry):
# This way we can add different formatting / colors to both
cuts = []
travels = []
cutsgeom = ''
travelsgeom = ''
for g in self.gcode_parsed:
if self.app.abort_flag:
# graceful abort requested by the user
@ -5548,10 +5825,12 @@ class CNCjob(Geometry):
def bounds(self, flatten=None):
"""
Returns coordinates of rectangular bounds
of geometry: (xmin, ymin, xmax, ymax).
Returns coordinates of rectangular bounds of geometry: (xmin, ymin, xmax, ymax).
:param flatten: Not used, it is here for compatibility with base class method
:type flatten: bool
:return: Bounding values in format (xmin, ymin, xmax, ymax)
:rtype: tuple
"""
log.debug("camlib.CNCJob.bounds()")

View File

@ -106,10 +106,10 @@ class Toolchange_Probe_MACH3(PreProc):
return g
def lift_code(self, p):
return 'G00 Z' + self.coordinate_format%(p.coords_decimals, p.z_move)
return 'G00 Z' + self.coordinate_format % (p.coords_decimals, p.z_move)
def down_code(self, p):
return 'G01 Z' + self.coordinate_format%(p.coords_decimals, p.z_cut)
return 'G01 Z' + self.coordinate_format % (p.coords_decimals, p.z_cut)
def toolchange_code(self, p):
z_toolchange = p.z_toolchange