- added the Exclusion zones processing to Excellon GCode generation
- fixed a non frequent plotting problem for CNCJob objects made out of Excellon objects
This commit is contained in:
parent
facbdf0fd7
commit
51c9023bbe
|
@ -3404,7 +3404,8 @@ class MainGUI(QtWidgets.QMainWindow):
|
|||
elif modifiers == QtCore.Qt.NoModifier:
|
||||
if key == QtCore.Qt.Key_Escape or key == 'Escape':
|
||||
sel_obj = self.app.collection.get_active()
|
||||
assert sel_obj.kind == 'geometry', "Expected a Geometry Object, got %s" % type(sel_obj)
|
||||
assert sel_obj.kind == 'geometry' or sel_obj.kind == 'excellon', \
|
||||
"Expected a Geometry or Excellon Object, got %s" % type(sel_obj)
|
||||
|
||||
sel_obj.area_disconnect()
|
||||
return
|
||||
|
|
|
@ -7,6 +7,11 @@ CHANGELOG for FlatCAM beta
|
|||
|
||||
=================================================
|
||||
|
||||
21.05.2020
|
||||
|
||||
- added the Exclusion zones processing to Excellon GCode generation
|
||||
- fixed a non frequent plotting problem for CNCJob objects made out of Excellon objects
|
||||
|
||||
19.05.2020
|
||||
|
||||
- updated the Italian language (translation incomplete)
|
||||
|
|
265
Common.py
265
Common.py
|
@ -12,11 +12,13 @@
|
|||
# ##########################################################
|
||||
from PyQt5 import QtCore
|
||||
|
||||
from shapely.geometry import Polygon, MultiPolygon
|
||||
from shapely.geometry import Polygon, MultiPolygon, Point, LineString
|
||||
|
||||
from AppGUI.VisPyVisuals import ShapeCollection
|
||||
from AppTool import AppTool
|
||||
|
||||
from copy import deepcopy
|
||||
|
||||
import numpy as np
|
||||
|
||||
import gettext
|
||||
|
@ -167,8 +169,8 @@ class ExclusionAreas(QtCore.QObject):
|
|||
{
|
||||
"obj_type": string ("excellon" or "geometry") <- self.obj_type
|
||||
"shape": Shapely polygon
|
||||
"strategy": string ("over" or "around") <- self.strategy
|
||||
"overz": float <- self.over_z
|
||||
"strategy": string ("over" or "around") <- self.strategy_button
|
||||
"overz": float <- self.over_z_button
|
||||
}
|
||||
'''
|
||||
self.exclusion_areas_storage = []
|
||||
|
@ -178,9 +180,9 @@ class ExclusionAreas(QtCore.QObject):
|
|||
self.solid_geometry = []
|
||||
self.obj_type = None
|
||||
|
||||
self.shape_type = 'square' # TODO use the self.app.defaults when made general (not in Geo object Pref UI)
|
||||
self.over_z = 0.1
|
||||
self.strategy = None
|
||||
self.shape_type_button = None
|
||||
self.over_z_button = None
|
||||
self.strategy_button = None
|
||||
self.cnc_button = None
|
||||
|
||||
def on_add_area_click(self, shape_button, overz_button, strategy_radio, cnc_button, solid_geo, obj_type):
|
||||
|
@ -188,21 +190,25 @@ class ExclusionAreas(QtCore.QObject):
|
|||
|
||||
:param shape_button: a FCButton that has the value for the shape
|
||||
:param overz_button: a FCDoubleSpinner that holds the Over Z value
|
||||
:param strategy_radio: a RadioSet button with the strategy value
|
||||
:param strategy_radio: a RadioSet button with the strategy_button value
|
||||
:param cnc_button: a FCButton in Object UI that when clicked the CNCJob is created
|
||||
We have a reference here so we can change the color signifying that exclusion areas are
|
||||
available.
|
||||
:param solid_geo: reference to the object solid geometry for which we add exclusion areas
|
||||
:param obj_type: Type of FlatCAM object that called this method
|
||||
:type obj_type: String: "excellon" or "geometry"
|
||||
:return:
|
||||
:param obj_type: Type of FlatCAM object that called this method. String: "excellon" or "geometry"
|
||||
:type obj_type: str
|
||||
:return: None
|
||||
"""
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the start point of the area."))
|
||||
self.app.call_source = 'geometry'
|
||||
|
||||
self.shape_type = shape_button.get_value()
|
||||
self.over_z = overz_button.get_value()
|
||||
self.strategy = strategy_radio.get_value()
|
||||
self.shape_type_button = shape_button
|
||||
|
||||
# TODO use the self.app.defaults when made general (not in Geo object Pref UI)
|
||||
# self.shape_type_button.set_value('square')
|
||||
|
||||
self.over_z_button = overz_button
|
||||
self.strategy_button = strategy_radio
|
||||
self.cnc_button = cnc_button
|
||||
|
||||
self.solid_geometry = solid_geo
|
||||
|
@ -240,11 +246,11 @@ class ExclusionAreas(QtCore.QObject):
|
|||
|
||||
x1, y1 = curr_pos[0], curr_pos[1]
|
||||
|
||||
# shape_type = self.ui.area_shape_radio.get_value()
|
||||
# shape_type_button = self.ui.area_shape_radio.get_value()
|
||||
|
||||
# do clear area only for left mouse clicks
|
||||
if event.button == 1:
|
||||
if self.shape_type == "square":
|
||||
if self.shape_type_button.get_value() == "square":
|
||||
if self.first_click is False:
|
||||
self.first_click = True
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Click the end point of the area."))
|
||||
|
@ -268,14 +274,14 @@ class ExclusionAreas(QtCore.QObject):
|
|||
# {
|
||||
# "obj_type": string("excellon" or "geometry") < - self.obj_type
|
||||
# "shape": Shapely polygon
|
||||
# "strategy": string("over" or "around") < - self.strategy
|
||||
# "overz": float < - self.over_z
|
||||
# "strategy_button": string("over" or "around") < - self.strategy_button
|
||||
# "overz": float < - self.over_z_button
|
||||
# }
|
||||
new_el = {
|
||||
"obj_type": self.obj_type,
|
||||
"shape": new_rectangle,
|
||||
"strategy": self.strategy,
|
||||
"overz": self.over_z
|
||||
"strategy": self.strategy_button.get_value(),
|
||||
"overz": self.over_z_button.get_value()
|
||||
}
|
||||
self.exclusion_areas_storage.append(new_el)
|
||||
|
||||
|
@ -305,7 +311,7 @@ class ExclusionAreas(QtCore.QObject):
|
|||
return ""
|
||||
elif event.button == right_button and self.mouse_is_dragging is False:
|
||||
|
||||
shape_type = self.shape_type
|
||||
shape_type = self.shape_type_button.get_value()
|
||||
|
||||
if shape_type == "square":
|
||||
self.first_click = False
|
||||
|
@ -326,17 +332,19 @@ class ExclusionAreas(QtCore.QObject):
|
|||
pol = Polygon(self.points)
|
||||
# do not add invalid polygons even if they are drawn by utility geometry
|
||||
if pol.is_valid:
|
||||
# {
|
||||
# "obj_type": string("excellon" or "geometry") < - self.obj_type
|
||||
# "shape": Shapely polygon
|
||||
# "strategy": string("over" or "around") < - self.strategy
|
||||
# "overz": float < - self.over_z
|
||||
# }
|
||||
"""
|
||||
{
|
||||
"obj_type": string("excellon" or "geometry") < - self.obj_type
|
||||
"shape": Shapely polygon
|
||||
"strategy": string("over" or "around") < - self.strategy_button
|
||||
"overz": float < - self.over_z_button
|
||||
}
|
||||
"""
|
||||
new_el = {
|
||||
"obj_type": self.obj_type,
|
||||
"shape": pol,
|
||||
"strategy": self.strategy,
|
||||
"overz": self.over_z
|
||||
"strategy": self.strategy_button.get_value(),
|
||||
"overz": self.over_z_button.get_value()
|
||||
}
|
||||
self.exclusion_areas_storage.append(new_el)
|
||||
|
||||
|
@ -382,9 +390,9 @@ class ExclusionAreas(QtCore.QObject):
|
|||
if len(self.exclusion_areas_storage) == 0:
|
||||
return
|
||||
|
||||
self.app.inform.emit(
|
||||
"[success] %s" % _("Exclusion areas added. Checking overlap with the object geometry ..."))
|
||||
|
||||
# since the exclusion areas should apply to all objects in the app collection, this check is limited to
|
||||
# only the current object therefore it will not guarantee success
|
||||
self.app.inform.emit("%s" % _("Exclusion areas added. Checking overlap with the object geometry ..."))
|
||||
for el in self.exclusion_areas_storage:
|
||||
if el["shape"].intersects(MultiPolygon(self.solid_geometry)):
|
||||
self.on_clear_area_click()
|
||||
|
@ -406,8 +414,6 @@ class ExclusionAreas(QtCore.QObject):
|
|||
)
|
||||
|
||||
self.e_shape_modified.emit()
|
||||
for k in self.exclusion_areas_storage:
|
||||
print(k)
|
||||
|
||||
def area_disconnect(self):
|
||||
if self.app.is_legacy is False:
|
||||
|
@ -436,7 +442,7 @@ class ExclusionAreas(QtCore.QObject):
|
|||
|
||||
# called on mouse move
|
||||
def on_mouse_move(self, event):
|
||||
shape_type = self.shape_type
|
||||
shape_type = self.shape_type_button.get_value()
|
||||
|
||||
if self.app.is_legacy is False:
|
||||
event_pos = event.pos
|
||||
|
@ -573,3 +579,194 @@ class ExclusionAreas(QtCore.QObject):
|
|||
self.cnc_button.setToolTip('%s' % _("Generate the CNC Job object."))
|
||||
|
||||
self.app.inform.emit('[success] %s' % _("All exclusion zones deleted."))
|
||||
|
||||
def travel_coordinates(self, start_point, end_point, tooldia):
|
||||
"""
|
||||
WIll create a path the go around the exclusion areas on the shortest path
|
||||
|
||||
:param start_point: X,Y coordinates for the start point of the travel line
|
||||
:type start_point: tuple
|
||||
:param end_point: X,Y coordinates for the destination point of the travel line
|
||||
:type end_point: tuple
|
||||
:param tooldia: THe tool diameter used and which generates the travel lines
|
||||
:type tooldia float
|
||||
:return: A list of x,y tuples that describe the avoiding path
|
||||
:rtype: list
|
||||
"""
|
||||
|
||||
ret_list = []
|
||||
|
||||
# Travel lines: rapids. Should not pass through Exclusion areas
|
||||
travel_line = LineString([start_point, end_point])
|
||||
origin_point = Point(start_point)
|
||||
|
||||
buffered_storage = []
|
||||
# add a little something to the half diameter, to make sure that we really don't enter in the exclusion zones
|
||||
buffered_distance = (tooldia / 2.0) + (0.1 if self.app.defaults['units'] == 'MM' else 0.00393701)
|
||||
|
||||
for area in self.exclusion_areas_storage:
|
||||
new_area = deepcopy(area)
|
||||
new_area['shape'] = area['shape'].buffer(buffered_distance, join_style=2)
|
||||
buffered_storage.append(new_area)
|
||||
|
||||
# sort the Exclusion areas from the closest to the start_point to the farthest
|
||||
tmp = []
|
||||
for area in buffered_storage:
|
||||
dist = Point(start_point).distance(area['shape'])
|
||||
tmp.append((dist, area))
|
||||
tmp.sort(key=lambda k: k[0])
|
||||
|
||||
sorted_area_storage = [k[1] for k in tmp]
|
||||
|
||||
# process the ordered exclusion areas list
|
||||
for area in sorted_area_storage:
|
||||
outline = area['shape'].exterior
|
||||
if travel_line.intersects(outline):
|
||||
intersection_pts = travel_line.intersection(outline)
|
||||
|
||||
if isinstance(intersection_pts, Point):
|
||||
# it's just a touch, continue
|
||||
continue
|
||||
|
||||
entry_pt = nearest_point(origin_point, intersection_pts)
|
||||
exit_pt = farthest_point(origin_point, intersection_pts)
|
||||
|
||||
if area['strategy'] == 'around':
|
||||
full_vertex_points = [Point(x) for x in list(outline.coords)]
|
||||
|
||||
# the last coordinate in outline, a LinearRing, is the closing one
|
||||
# therefore a duplicate of the first one; discard it
|
||||
vertex_points = full_vertex_points[:-1]
|
||||
|
||||
# dist_from_entry = [(entry_pt.distance(vt), vertex_points.index(vt)) for vt in vertex_points]
|
||||
# closest_point_entry = nsmallest(1, dist_from_entry, key=lambda x: x[0])
|
||||
# start_idx = closest_point_entry[0][1]
|
||||
#
|
||||
# dist_from_exit = [(exit_pt.distance(vt), vertex_points.index(vt)) for vt in vertex_points]
|
||||
# closest_point_exit = nsmallest(1, dist_from_exit, key=lambda x: x[0])
|
||||
# end_idx = closest_point_exit[0][1]
|
||||
|
||||
pts_line_entry = None
|
||||
pts_line_exit = None
|
||||
for i in range(len(full_vertex_points) - 1):
|
||||
line = LineString(
|
||||
[
|
||||
(full_vertex_points[i].x, full_vertex_points[i].y),
|
||||
(full_vertex_points[i + 1].x, full_vertex_points[i + 1].y)
|
||||
]
|
||||
)
|
||||
if entry_pt.intersects(line) or entry_pt.almost_equals(Point(line.coords[0]), decimal=3) or \
|
||||
entry_pt.almost_equals(Point(line.coords[1]), decimal=3):
|
||||
pts_line_entry = [Point(x) for x in line.coords]
|
||||
|
||||
if exit_pt.intersects(line) or exit_pt.almost_equals(Point(line.coords[0]), decimal=3) or \
|
||||
exit_pt.almost_equals(Point(line.coords[1]), decimal=3):
|
||||
pts_line_exit = [Point(x) for x in line.coords]
|
||||
|
||||
closest_point_entry = nearest_point(entry_pt, pts_line_entry)
|
||||
start_idx = vertex_points.index(closest_point_entry)
|
||||
|
||||
closest_point_exit = nearest_point(exit_pt, pts_line_exit)
|
||||
end_idx = vertex_points.index(closest_point_exit)
|
||||
|
||||
# calculate possible paths: one clockwise the other counterclockwise on the exterior of the
|
||||
# exclusion area outline (Polygon.exterior)
|
||||
vp_len = len(vertex_points)
|
||||
if end_idx > start_idx:
|
||||
path_1 = vertex_points[start_idx:(end_idx + 1)]
|
||||
path_2 = [vertex_points[start_idx]]
|
||||
idx = start_idx
|
||||
for __ in range(vp_len):
|
||||
idx = idx - 1 if idx > 0 else (vp_len - 1)
|
||||
path_2.append(vertex_points[idx])
|
||||
if idx == end_idx:
|
||||
break
|
||||
else:
|
||||
path_1 = vertex_points[end_idx:(start_idx + 1)]
|
||||
path_2 = [vertex_points[end_idx]]
|
||||
idx = end_idx
|
||||
for __ in range(vp_len):
|
||||
idx = idx - 1 if idx > 0 else (vp_len - 1)
|
||||
path_2.append(vertex_points[idx])
|
||||
if idx == start_idx:
|
||||
break
|
||||
path_1.reverse()
|
||||
path_2.reverse()
|
||||
|
||||
# choose the one with the lesser length
|
||||
length_path_1 = 0
|
||||
for i in range(len(path_1)):
|
||||
try:
|
||||
length_path_1 += path_1[i].distance(path_1[i + 1])
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
length_path_2 = 0
|
||||
for i in range(len(path_2)):
|
||||
try:
|
||||
length_path_2 += path_2[i].distance(path_2[i + 1])
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
path = path_1 if length_path_1 < length_path_2 else path_2
|
||||
|
||||
# transform the list of Points into a list of Points coordinates
|
||||
path_coords = [[None, (p.x, p.y)] for p in path]
|
||||
ret_list += path_coords
|
||||
|
||||
else:
|
||||
path_coords = [[float(area['overz']), (entry_pt.x, entry_pt.y)], [None, (exit_pt.x, exit_pt.y)]]
|
||||
ret_list += path_coords
|
||||
|
||||
# create a new LineString to test again for possible other Exclusion zones
|
||||
last_pt_in_path = path_coords[-1][1]
|
||||
travel_line = LineString([last_pt_in_path, end_point])
|
||||
|
||||
ret_list.append([None, end_point])
|
||||
return ret_list
|
||||
|
||||
|
||||
def farthest_point(origin, points_list):
|
||||
"""
|
||||
Calculate the farthest Point in a list from another Point
|
||||
|
||||
:param origin: Reference Point
|
||||
:type origin: Point
|
||||
:param points_list: List of Points or a MultiPoint
|
||||
:type points_list: list
|
||||
:return: Farthest Point
|
||||
:rtype: Point
|
||||
"""
|
||||
old_dist = 0
|
||||
fartherst_pt = None
|
||||
|
||||
for pt in points_list:
|
||||
dist = abs(origin.distance(pt))
|
||||
if dist >= old_dist:
|
||||
fartherst_pt = pt
|
||||
old_dist = dist
|
||||
|
||||
return fartherst_pt
|
||||
|
||||
|
||||
def nearest_point(origin, points_list):
|
||||
"""
|
||||
Calculate the nearest Point in a list from another Point
|
||||
|
||||
:param origin: Reference Point
|
||||
:type origin: Point
|
||||
:param points_list: List of Points or a MultiPoint
|
||||
:type points_list: list
|
||||
:return: Nearest Point
|
||||
:rtype: Point
|
||||
"""
|
||||
old_dist = np.Inf
|
||||
nearest_pt = None
|
||||
|
||||
for pt in points_list:
|
||||
dist = abs(origin.distance(pt))
|
||||
if dist <= old_dist:
|
||||
nearest_pt = pt
|
||||
old_dist = dist
|
||||
|
||||
return nearest_pt
|
||||
|
|
159
camlib.py
159
camlib.py
|
@ -2630,16 +2630,17 @@ class CNCjob(Geometry):
|
|||
|
||||
def generate_from_excellon_by_tool(self, exobj, tools="all", use_ui=False):
|
||||
"""
|
||||
Creates gcode for this object from an Excellon object
|
||||
Creates Gcode for this object from an Excellon object
|
||||
for the specified tools.
|
||||
|
||||
:param exobj: Excellon object to process
|
||||
:type exobj: Excellon
|
||||
:param tools: Comma separated tool names
|
||||
:type: tools: str
|
||||
:param use_ui: Bool, if True the method will use parameters set in UI
|
||||
:return: None
|
||||
:rtype: None
|
||||
:param exobj: Excellon object to process
|
||||
:type exobj: Excellon
|
||||
:param tools: Comma separated tool names
|
||||
:type tools: str
|
||||
:param use_ui: if True the method will use parameters set in UI
|
||||
:type use_ui: bool
|
||||
:return: None
|
||||
:rtype: None
|
||||
"""
|
||||
|
||||
# create a local copy of the exobj.drills so it can be used for creating drill CCode geometry
|
||||
|
@ -2780,7 +2781,7 @@ class CNCjob(Geometry):
|
|||
|
||||
self.app.inform.emit(_("Creating a list of points to drill..."))
|
||||
|
||||
# Points (Group by tool)
|
||||
# Points (Group by tool): a dictionary of shapely Point geo elements grouped by tool number
|
||||
points = {}
|
||||
for drill in exobj.drills:
|
||||
if self.app.abort_flag:
|
||||
|
@ -2795,6 +2796,17 @@ class CNCjob(Geometry):
|
|||
|
||||
# log.debug("Found %d drills." % len(points))
|
||||
|
||||
# check if there are drill points in the exclusion areas.
|
||||
# If we find any within the exclusion areas return 'fail'
|
||||
for tool in points:
|
||||
for pt in points[tool]:
|
||||
for area in self.app.exc_areas.exclusion_areas_storage:
|
||||
pt_buf = pt.buffer(exobj.tools[tool]['C'] / 2.0)
|
||||
if pt_buf.within(area['shape']) or pt_buf.intersects(area['shape']):
|
||||
self.app.inform.emit("[ERROR_NOTCL] %s" % _("Failed. Drill points inside the exclusion zones."))
|
||||
return 'fail'
|
||||
|
||||
# this holds the resulting GCode
|
||||
self.gcode = []
|
||||
|
||||
self.f_plunge = self.app.defaults["excellon_f_plunge"]
|
||||
|
@ -3042,7 +3054,41 @@ class CNCjob(Geometry):
|
|||
locx = locations[k][0]
|
||||
locy = locations[k][1]
|
||||
|
||||
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
|
||||
travels = self.app.exc_areas.travel_coordinates(start_point=(self.oldx, self.oldy),
|
||||
end_point=(locx, locy),
|
||||
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 = exobj.tools[tool]['data']['travelz']
|
||||
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 = exobj.tools[tool]['data']['travelz']
|
||||
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=locx, y=locy)
|
||||
|
||||
if self.multidepth and abs(self.z_cut) > abs(self.z_depthpercut):
|
||||
doc = deepcopy(self.z_cut)
|
||||
|
@ -3260,7 +3306,41 @@ class CNCjob(Geometry):
|
|||
locx = locations[k][0]
|
||||
locy = locations[k][1]
|
||||
|
||||
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
|
||||
travels = self.app.exc_areas.travel_coordinates(start_point=(self.oldx, self.oldy),
|
||||
end_point=(locx, locy),
|
||||
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 = exobj.tools[tool]['data']['travelz']
|
||||
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 = exobj.tools[tool]['data']['travelz']
|
||||
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=locx, y=locy)
|
||||
|
||||
if self.multidepth and abs(self.z_cut) > abs(self.z_depthpercut):
|
||||
doc = deepcopy(self.z_cut)
|
||||
|
@ -3429,7 +3509,41 @@ class CNCjob(Geometry):
|
|||
locx = point[0]
|
||||
locy = point[1]
|
||||
|
||||
gcode += self.doformat(p.rapid_code, x=locx, y=locy)
|
||||
travels = self.app.exc_areas.travel_coordinates(start_point=(self.oldx, self.oldy),
|
||||
end_point=(locx, locy),
|
||||
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 = exobj.tools[tool]['data']['travelz']
|
||||
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 = exobj.tools[tool]['data']['travelz']
|
||||
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=locx, y=locy)
|
||||
|
||||
if self.multidepth and abs(self.z_cut) > abs(self.z_depthpercut):
|
||||
doc = deepcopy(self.z_cut)
|
||||
|
@ -4827,14 +4941,27 @@ class CNCjob(Geometry):
|
|||
# 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)
|
||||
if geo['kind'][0] == 'T':
|
||||
# if the geos are travel lines it will enter into Exception
|
||||
poly = geo['geom'].buffer(distance=(tooldia / 1.99999999),
|
||||
resolution=self.steps_per_circle)
|
||||
else:
|
||||
poly = Polygon(geo['geom'])
|
||||
|
||||
poly = poly.simplify(tool_tolerance)
|
||||
except Exception:
|
||||
# deal here with unexpected plot errors due of LineStrings not valid
|
||||
continue
|
||||
|
||||
# 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)
|
||||
# except Exception:
|
||||
# # deal here with unexpected plot errors due of LineStrings not valid
|
||||
# continue
|
||||
else:
|
||||
# plot the geometry of any objects other than Excellon
|
||||
poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle)
|
||||
|
|
Loading…
Reference in New Issue