- Cutout Tool - rectangular and freeform cutouts are done in a threaded way
- Cutout Tool - added the Mouse Bites feature for the Rectangular and Freeform cutouts and right now it fails in case of using a Geometry object and Freeform cutout (weird result) - some changes in camlib due of warnigns for future changes in Shapely 2.0
This commit is contained in:
@@ -13,6 +13,9 @@ CHANGELOG for FlatCAM beta
|
|||||||
- 2Sided Tool - modified the UI such that some of the fields will allow only numbers and some special characters ([,],(,),/,*,,,+,-,%)
|
- 2Sided Tool - modified the UI such that some of the fields will allow only numbers and some special characters ([,],(,),/,*,,,+,-,%)
|
||||||
- Cutout Tool - working on adding mouse bites for the Freeform cutout
|
- Cutout Tool - working on adding mouse bites for the Freeform cutout
|
||||||
- updated the translation files to the current state of the app
|
- updated the translation files to the current state of the app
|
||||||
|
- Cutout Tool - rectangular and freeform cutouts are done in a threaded way
|
||||||
|
- Cutout Tool - added the Mouse Bites feature for the Rectangular and Freeform cutouts and right now it fails in case of using a Geometry object and Freeform cutout (weird result)
|
||||||
|
- some changes in camlib due of warnigns for future changes in Shapely 2.0
|
||||||
|
|
||||||
28.08.2020
|
28.08.2020
|
||||||
|
|
||||||
|
|||||||
@@ -526,9 +526,6 @@ class CutOut(AppTool):
|
|||||||
def on_freeform_cutout(self):
|
def on_freeform_cutout(self):
|
||||||
log.debug("Cutout.on_freeform_cutout() was launched ...")
|
log.debug("Cutout.on_freeform_cutout() was launched ...")
|
||||||
|
|
||||||
# def subtract_rectangle(obj_, x0, y0, x1, y1):
|
|
||||||
# pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
|
|
||||||
# obj_.subtract_polygon(pts)
|
|
||||||
name = self.ui.obj_combo.currentText()
|
name = self.ui.obj_combo.currentText()
|
||||||
|
|
||||||
# Get source object.
|
# Get source object.
|
||||||
@@ -544,7 +541,7 @@ class CutOut(AppTool):
|
|||||||
_("There is no object selected for Cutout.\nSelect one and try again."))
|
_("There is no object selected for Cutout.\nSelect one and try again."))
|
||||||
return
|
return
|
||||||
|
|
||||||
dia = float(self.ui.dia.get_value())
|
dia = self.ui.dia.get_value()
|
||||||
if 0 in {dia}:
|
if 0 in {dia}:
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||||
_("Tool Diameter is zero value. Change it to a positive real number."))
|
_("Tool Diameter is zero value. Change it to a positive real number."))
|
||||||
@@ -555,8 +552,7 @@ class CutOut(AppTool):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return
|
return
|
||||||
|
|
||||||
margin = float(self.ui.margin.get_value())
|
margin = self.ui.margin.get_value()
|
||||||
gapsize = float(self.ui.gapsize.get_value())
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
gaps = self.ui.gaps.get_value()
|
gaps = self.ui.gaps.get_value()
|
||||||
@@ -570,37 +566,14 @@ class CutOut(AppTool):
|
|||||||
"Fill in a correct value and retry. "))
|
"Fill in a correct value and retry. "))
|
||||||
return
|
return
|
||||||
|
|
||||||
if cutout_obj.multigeo is True:
|
# if cutout_obj.multigeo is True:
|
||||||
self.app.inform.emit('[ERROR] %s' % _("Cutout operation cannot be done on a multi-geo Geometry.\n"
|
# self.app.inform.emit('[ERROR] %s' % _("Cutout operation cannot be done on a multi-geo Geometry.\n"
|
||||||
"Optionally, this Multi-geo Geometry can be converted to "
|
# "Optionally, this Multi-geo Geometry can be converted to "
|
||||||
"Single-geo Geometry,\n"
|
# "Single-geo Geometry,\n"
|
||||||
"and after that perform Cutout."))
|
# "and after that perform Cutout."))
|
||||||
return
|
# return
|
||||||
|
|
||||||
convex_box = self.ui.convex_box_cb.get_value()
|
def cutout_handler(geom, gapsize):
|
||||||
|
|
||||||
gapsize = gapsize / 2 + (dia / 2)
|
|
||||||
|
|
||||||
def geo_init(geo_obj, app_obj):
|
|
||||||
solid_geo = []
|
|
||||||
gaps_solid_geo = None
|
|
||||||
|
|
||||||
if cutout_obj.kind == 'gerber':
|
|
||||||
if isinstance(cutout_obj.solid_geometry, list):
|
|
||||||
cutout_obj.solid_geometry = MultiPolygon(cutout_obj.solid_geometry)
|
|
||||||
|
|
||||||
try:
|
|
||||||
if convex_box:
|
|
||||||
object_geo = cutout_obj.solid_geometry.convex_hull
|
|
||||||
else:
|
|
||||||
object_geo = cutout_obj.solid_geometry
|
|
||||||
except Exception as err:
|
|
||||||
log.debug("CutOut.on_freeform_cutout().geo_init() --> %s" % str(err))
|
|
||||||
object_geo = cutout_obj.solid_geometry
|
|
||||||
else:
|
|
||||||
object_geo = cutout_obj.solid_geometry
|
|
||||||
|
|
||||||
def cutout_handler(geom):
|
|
||||||
proc_geometry = []
|
proc_geometry = []
|
||||||
rest_geometry = []
|
rest_geometry = []
|
||||||
r_temp_geo = []
|
r_temp_geo = []
|
||||||
@@ -702,6 +675,49 @@ class CutOut(AppTool):
|
|||||||
|
|
||||||
return proc_geometry, rest_geometry
|
return proc_geometry, rest_geometry
|
||||||
|
|
||||||
|
with self.app.proc_container.new("Generating Cutout ..."):
|
||||||
|
outname = cutout_obj.options["name"] + "_cutout"
|
||||||
|
self.app.collection.promise(outname)
|
||||||
|
|
||||||
|
has_mouse_bites = True if self.ui.gaptype_radio.get_value() == 'mb' else False
|
||||||
|
|
||||||
|
outname_exc = cutout_obj.options["name"] + "_mouse_bites"
|
||||||
|
if has_mouse_bites is True:
|
||||||
|
self.app.collection.promise(outname_exc)
|
||||||
|
|
||||||
|
def job_thread(app_obj):
|
||||||
|
solid_geo = []
|
||||||
|
gaps_solid_geo = []
|
||||||
|
mouse_bites_geo = []
|
||||||
|
|
||||||
|
convex_box = self.ui.convex_box_cb.get_value()
|
||||||
|
gapsize = self.ui.gapsize.get_value()
|
||||||
|
gapsize = gapsize / 2 + (dia / 2)
|
||||||
|
mb_dia = self.ui.mb_dia_entry.get_value()
|
||||||
|
mb_buff_val = mb_dia / 2.0
|
||||||
|
mb_spacing = self.ui.mb_spacing_entry.get_value()
|
||||||
|
gap_type = self.ui.gaptype_radio.get_value()
|
||||||
|
thin_entry = self.ui.thin_depth_entry.get_value()
|
||||||
|
|
||||||
|
if cutout_obj.kind == 'gerber':
|
||||||
|
if isinstance(cutout_obj.solid_geometry, list):
|
||||||
|
cutout_obj.solid_geometry = MultiPolygon(cutout_obj.solid_geometry)
|
||||||
|
try:
|
||||||
|
if convex_box:
|
||||||
|
object_geo = cutout_obj.solid_geometry.convex_hull
|
||||||
|
else:
|
||||||
|
object_geo = cutout_obj.solid_geometry
|
||||||
|
except Exception as err:
|
||||||
|
log.debug("CutOut.on_freeform_cutout().geo_init() --> %s" % str(err))
|
||||||
|
object_geo = cutout_obj.solid_geometry
|
||||||
|
else:
|
||||||
|
if cutout_obj.multigeo is False:
|
||||||
|
object_geo = cutout_obj.solid_geometry
|
||||||
|
else:
|
||||||
|
# first tool in the tools dict
|
||||||
|
t_first = list(cutout_obj.tools.keys())[0]
|
||||||
|
object_geo = cutout_obj.tools[t_first]['solid_geometry']
|
||||||
|
|
||||||
if kind == 'single':
|
if kind == 'single':
|
||||||
object_geo = unary_union(object_geo)
|
object_geo = unary_union(object_geo)
|
||||||
|
|
||||||
@@ -714,13 +730,12 @@ class CutOut(AppTool):
|
|||||||
geo_buf = object_geo.buffer(margin + abs(dia / 2))
|
geo_buf = object_geo.buffer(margin + abs(dia / 2))
|
||||||
else:
|
else:
|
||||||
geo_buf = object_geo.buffer(margin - abs(dia / 2))
|
geo_buf = object_geo.buffer(margin - abs(dia / 2))
|
||||||
|
|
||||||
geo = geo_buf.exterior
|
geo = geo_buf.exterior
|
||||||
else:
|
else:
|
||||||
geo = object_geo
|
geo = object_geo
|
||||||
|
|
||||||
solid_geo, rest_geo = cutout_handler(geom=geo)
|
solid_geo, rest_geo = cutout_handler(geom=geo, gapsize=gapsize)
|
||||||
if self.ui.gaptype_radio.get_value() == 'bt' and self.ui.thin_depth_entry.get_value() > 0:
|
if gap_type == 'bt' and thin_entry != 0:
|
||||||
gaps_solid_geo = rest_geo
|
gaps_solid_geo = rest_geo
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
@@ -736,16 +751,66 @@ class CutOut(AppTool):
|
|||||||
geom_struct_buff = geom_struct.buffer(-margin + abs(dia / 2))
|
geom_struct_buff = geom_struct.buffer(-margin + abs(dia / 2))
|
||||||
geom_struct = geom_struct_buff.interiors
|
geom_struct = geom_struct_buff.interiors
|
||||||
|
|
||||||
c_geo, r_geo = cutout_handler(geom=geom_struct)
|
c_geo, r_geo = cutout_handler(geom=geom_struct, gapsize=gapsize)
|
||||||
solid_geo += c_geo
|
solid_geo += c_geo
|
||||||
if self.ui.gaptype_radio.get_value() == 'bt' and self.ui.thin_depth_entry.get_value() > 0:
|
if gap_type == 'bt' and thin_entry != 0:
|
||||||
gaps_solid_geo += r_geo
|
gaps_solid_geo += r_geo
|
||||||
|
|
||||||
if not solid_geo:
|
if not solid_geo:
|
||||||
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
||||||
return "fail"
|
return "fail"
|
||||||
|
|
||||||
solid_geo = linemerge(solid_geo)
|
solid_geo = linemerge(solid_geo)
|
||||||
|
|
||||||
|
if has_mouse_bites is True:
|
||||||
|
gapsize -= dia / 2
|
||||||
|
mb_object_geo = deepcopy(object_geo)
|
||||||
|
if kind == 'single':
|
||||||
|
mb_object_geo = unary_union(mb_object_geo)
|
||||||
|
|
||||||
|
# for geo in object_geo:
|
||||||
|
if cutout_obj.kind == 'gerber':
|
||||||
|
if isinstance(mb_object_geo, MultiPolygon):
|
||||||
|
x0, y0, x1, y1 = mb_object_geo.bounds
|
||||||
|
mb_object_geo = box(x0, y0, x1, y1)
|
||||||
|
if margin >= 0:
|
||||||
|
geo_buf = mb_object_geo.buffer(margin + mb_buff_val)
|
||||||
|
else:
|
||||||
|
geo_buf = mb_object_geo.buffer(margin - mb_buff_val)
|
||||||
|
mb_geo = geo_buf.exterior
|
||||||
|
else:
|
||||||
|
mb_geo = mb_object_geo
|
||||||
|
|
||||||
|
__, rest_geo = cutout_handler(geom=mb_geo, gapsize=gapsize)
|
||||||
|
mouse_bites_geo = rest_geo
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
__ = iter(mb_object_geo)
|
||||||
|
except TypeError:
|
||||||
|
mb_object_geo = [mb_object_geo]
|
||||||
|
|
||||||
|
for mb_geom_struct in mb_object_geo:
|
||||||
|
if cutout_obj.kind == 'gerber':
|
||||||
|
if margin >= 0:
|
||||||
|
mb_geom_struct = mb_geom_struct.buffer(margin + mb_buff_val)
|
||||||
|
mb_geom_struct = mb_geom_struct.exterior
|
||||||
|
else:
|
||||||
|
mb_geom_struct = mb_geom_struct.buffer(-margin + mb_buff_val)
|
||||||
|
mb_geom_struct = mb_geom_struct.interiors
|
||||||
|
|
||||||
|
__, mb_r_geo = cutout_handler(geom=mb_geom_struct, gapsize=gapsize)
|
||||||
|
mouse_bites_geo += mb_r_geo
|
||||||
|
|
||||||
|
# list of Shapely Points to mark the drill points centers
|
||||||
|
holes = []
|
||||||
|
for line in mouse_bites_geo:
|
||||||
|
calc_len = 0
|
||||||
|
while calc_len < line.length:
|
||||||
|
holes.append(line.interpolate(calc_len))
|
||||||
|
calc_len += mb_dia + mb_spacing
|
||||||
|
|
||||||
|
def geo_init(geo_obj, app_object):
|
||||||
|
geo_obj.multigeo = True
|
||||||
geo_obj.solid_geometry = deepcopy(solid_geo)
|
geo_obj.solid_geometry = deepcopy(solid_geo)
|
||||||
|
|
||||||
xmin, ymin, xmax, ymax = CutOut.recursive_bounds(geo_obj.solid_geometry)
|
xmin, ymin, xmax, ymax = CutOut.recursive_bounds(geo_obj.solid_geometry)
|
||||||
@@ -753,16 +818,13 @@ class CutOut(AppTool):
|
|||||||
geo_obj.options['ymin'] = ymin
|
geo_obj.options['ymin'] = ymin
|
||||||
geo_obj.options['xmax'] = xmax
|
geo_obj.options['xmax'] = xmax
|
||||||
geo_obj.options['ymax'] = ymax
|
geo_obj.options['ymax'] = ymax
|
||||||
|
|
||||||
geo_obj.options['cnctooldia'] = str(dia)
|
geo_obj.options['cnctooldia'] = str(dia)
|
||||||
geo_obj.options['cutz'] = self.ui.cutz_entry.get_value()
|
geo_obj.options['cutz'] = self.ui.cutz_entry.get_value()
|
||||||
geo_obj.options['multidepth'] = self.ui.mpass_cb.get_value()
|
geo_obj.options['multidepth'] = self.ui.mpass_cb.get_value()
|
||||||
geo_obj.options['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
geo_obj.options['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
||||||
|
|
||||||
geo_obj.multigeo = True
|
geo_obj.tools[1] = deepcopy(self.cut_tool_dict)
|
||||||
|
|
||||||
geo_obj.tools.update({
|
|
||||||
1: self.cut_tool_dict
|
|
||||||
})
|
|
||||||
geo_obj.tools[1]['tooldia'] = str(dia)
|
geo_obj.tools[1]['tooldia'] = str(dia)
|
||||||
geo_obj.tools[1]['solid_geometry'] = geo_obj.solid_geometry
|
geo_obj.tools[1]['solid_geometry'] = geo_obj.solid_geometry
|
||||||
|
|
||||||
@@ -771,10 +833,10 @@ class CutOut(AppTool):
|
|||||||
geo_obj.tools[1]['data']['multidepth'] = self.ui.mpass_cb.get_value()
|
geo_obj.tools[1]['data']['multidepth'] = self.ui.mpass_cb.get_value()
|
||||||
geo_obj.tools[1]['data']['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
geo_obj.tools[1]['data']['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
||||||
|
|
||||||
if gaps_solid_geo is not None:
|
if not gaps_solid_geo:
|
||||||
geo_obj.tools.update({
|
pass
|
||||||
9999: self.cut_tool_dict
|
else:
|
||||||
})
|
geo_obj.tools[9999] = deepcopy(self.cut_tool_dict)
|
||||||
geo_obj.tools[9999]['tooldia'] = str(dia)
|
geo_obj.tools[9999]['tooldia'] = str(dia)
|
||||||
geo_obj.tools[9999]['solid_geometry'] = gaps_solid_geo
|
geo_obj.tools[9999]['solid_geometry'] = gaps_solid_geo
|
||||||
|
|
||||||
@@ -785,25 +847,50 @@ class CutOut(AppTool):
|
|||||||
# plot this tool in a different color
|
# plot this tool in a different color
|
||||||
geo_obj.tools[9999]['data']['override_color'] = "#29a3a3fa"
|
geo_obj.tools[9999]['data']['override_color'] = "#29a3a3fa"
|
||||||
|
|
||||||
outname = cutout_obj.options["name"] + "_cutout"
|
def excellon_init(exc_obj, app_o):
|
||||||
ret = self.app.app_obj.new_object('geometry', outname, geo_init)
|
if not holes:
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
|
tools = {}
|
||||||
|
tools[1] = {}
|
||||||
|
tools[1]["tooldia"] = mb_dia
|
||||||
|
tools[1]['drills'] = holes
|
||||||
|
tools[1]['solid_geometry'] = []
|
||||||
|
|
||||||
|
exc_obj.tools = tools
|
||||||
|
exc_obj.create_geometry()
|
||||||
|
exc_obj.source_file = app_o.export_excellon(obj_name=exc_obj.options['name'], local_use=exc_obj,
|
||||||
|
filename=None, use_thread=False)
|
||||||
|
# calculate the bounds
|
||||||
|
xmin, ymin, xmax, ymax = CutOut.recursive_bounds(exc_obj.solid_geometry)
|
||||||
|
exc_obj.options['xmin'] = xmin
|
||||||
|
exc_obj.options['ymin'] = ymin
|
||||||
|
exc_obj.options['xmax'] = xmax
|
||||||
|
exc_obj.options['ymax'] = ymax
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.ui.gaptype_radio.get_value() == 'mb':
|
||||||
|
ret = app_obj.app_obj.new_object('excellon', outname_exc, excellon_init)
|
||||||
if ret == 'fail':
|
if ret == 'fail':
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Mouse bites failed."))
|
||||||
|
|
||||||
|
ret = app_obj.app_obj.new_object('geometry', outname, geo_init)
|
||||||
|
if ret == 'fail':
|
||||||
|
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
||||||
return
|
return
|
||||||
|
|
||||||
# cutout_obj.plot(plot_tool=1)
|
# cutout_obj.plot(plot_tool=1)
|
||||||
self.app.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
|
app_obj.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
|
||||||
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||||
self.app.should_we_save = True
|
app_obj.should_we_save = True
|
||||||
|
except Exception as ee:
|
||||||
|
log.debug(str(ee))
|
||||||
|
|
||||||
|
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
||||||
|
|
||||||
def on_rectangular_cutout(self):
|
def on_rectangular_cutout(self):
|
||||||
log.debug("Cutout.on_rectangular_cutout() was launched ...")
|
log.debug("Cutout.on_rectangular_cutout() was launched ...")
|
||||||
|
|
||||||
# def subtract_rectangle(obj_, x0, y0, x1, y1):
|
|
||||||
# pts = [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
|
|
||||||
# obj_.subtract_polygon(pts)
|
|
||||||
|
|
||||||
name = self.ui.obj_combo.currentText()
|
name = self.ui.obj_combo.currentText()
|
||||||
|
|
||||||
# Get source object.
|
# Get source object.
|
||||||
@@ -828,8 +915,7 @@ class CutOut(AppTool):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
return
|
return
|
||||||
|
|
||||||
margin = float(self.ui.margin.get_value())
|
margin = self.ui.margin.get_value()
|
||||||
gapsize = float(self.ui.gapsize.get_value())
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
gaps = self.ui.gaps.get_value()
|
gaps = self.ui.gaps.get_value()
|
||||||
@@ -844,24 +930,14 @@ class CutOut(AppTool):
|
|||||||
"Fill in a correct value and retry. "))
|
"Fill in a correct value and retry. "))
|
||||||
return
|
return
|
||||||
|
|
||||||
if cutout_obj.multigeo is True:
|
# if cutout_obj.multigeo is True:
|
||||||
self.app.inform.emit('[ERROR] %s' % _("Cutout operation cannot be done on a multi-geo Geometry.\n"
|
# self.app.inform.emit('[ERROR] %s' % _("Cutout operation cannot be done on a multi-geo Geometry.\n"
|
||||||
"Optionally, this Multi-geo Geometry can be converted to "
|
# "Optionally, this Multi-geo Geometry can be converted to "
|
||||||
"Single-geo Geometry,\n"
|
# "Single-geo Geometry,\n"
|
||||||
"and after that perform Cutout."))
|
# "and after that perform Cutout."))
|
||||||
return
|
# return
|
||||||
|
|
||||||
# Get min and max data for each object as we just cut rectangles across X or Y
|
def cutout_rect_handler(geom, gapsize, xmin, ymin, xmax, ymax):
|
||||||
|
|
||||||
gapsize = gapsize / 2 + (dia / 2)
|
|
||||||
|
|
||||||
def geo_init(geo_obj, app_obj):
|
|
||||||
solid_geo = []
|
|
||||||
gaps_solid_geo = None
|
|
||||||
|
|
||||||
object_geo = cutout_obj.solid_geometry
|
|
||||||
|
|
||||||
def cutout_rect_handler(geom):
|
|
||||||
proc_geometry = []
|
proc_geometry = []
|
||||||
|
|
||||||
px = 0.5 * (xmin + xmax) + margin
|
px = 0.5 * (xmin + xmax) + margin
|
||||||
@@ -929,6 +1005,36 @@ class CutOut(AppTool):
|
|||||||
proc_geometry.append(geom)
|
proc_geometry.append(geom)
|
||||||
return proc_geometry
|
return proc_geometry
|
||||||
|
|
||||||
|
with self.app.proc_container.new("Generating Cutout ..."):
|
||||||
|
outname = cutout_obj.options["name"] + "_cutout"
|
||||||
|
self.app.collection.promise(outname)
|
||||||
|
|
||||||
|
has_mouse_bites = True if self.ui.gaptype_radio.get_value() == 'mb' else False
|
||||||
|
|
||||||
|
outname_exc = cutout_obj.options["name"] + "_mouse_bites"
|
||||||
|
if has_mouse_bites is True:
|
||||||
|
self.app.collection.promise(outname_exc)
|
||||||
|
|
||||||
|
def job_thread(app_obj):
|
||||||
|
solid_geo = []
|
||||||
|
gaps_solid_geo = []
|
||||||
|
mouse_bites_geo = []
|
||||||
|
|
||||||
|
gapsize = self.ui.gapsize.get_value()
|
||||||
|
gapsize = gapsize / 2 + (dia / 2)
|
||||||
|
mb_dia = self.ui.mb_dia_entry.get_value()
|
||||||
|
mb_buff_val = mb_dia / 2.0
|
||||||
|
mb_spacing = self.ui.mb_spacing_entry.get_value()
|
||||||
|
gap_type = self.ui.gaptype_radio.get_value()
|
||||||
|
thin_entry = self.ui.thin_depth_entry.get_value()
|
||||||
|
|
||||||
|
if cutout_obj.multigeo is False:
|
||||||
|
object_geo = cutout_obj.solid_geometry
|
||||||
|
else:
|
||||||
|
# first tool in the tools dict
|
||||||
|
t_first = list(cutout_obj.tools.keys())[0]
|
||||||
|
object_geo = cutout_obj.tools[t_first]['solid_geometry']
|
||||||
|
|
||||||
if kind == 'single':
|
if kind == 'single':
|
||||||
# fuse the lines
|
# fuse the lines
|
||||||
object_geo = unary_union(object_geo)
|
object_geo = unary_union(object_geo)
|
||||||
@@ -944,10 +1050,10 @@ class CutOut(AppTool):
|
|||||||
else:
|
else:
|
||||||
geo = geo.buffer(margin - abs(dia / 2))
|
geo = geo.buffer(margin - abs(dia / 2))
|
||||||
|
|
||||||
solid_geo = cutout_rect_handler(geom=geo)
|
solid_geo = cutout_rect_handler(geo, gapsize, xmin, ymin, xmax, ymax)
|
||||||
|
|
||||||
if self.ui.gaptype_radio.get_value() == 'bt' and self.ui.thin_depth_entry.get_value() > 0:
|
if gap_type == 'bt' and thin_entry != 0:
|
||||||
gaps_solid_geo = self.subtract_geo(geo, solid_geo)
|
gaps_solid_geo = self.subtract_geo(geo, deepcopy(solid_geo))
|
||||||
else:
|
else:
|
||||||
if cutout_obj.kind == 'geometry':
|
if cutout_obj.kind == 'geometry':
|
||||||
try:
|
try:
|
||||||
@@ -960,9 +1066,9 @@ class CutOut(AppTool):
|
|||||||
xmin, ymin, xmax, ymax = geom_struct.bounds
|
xmin, ymin, xmax, ymax = geom_struct.bounds
|
||||||
geom_struct = box(xmin, ymin, xmax, ymax)
|
geom_struct = box(xmin, ymin, xmax, ymax)
|
||||||
|
|
||||||
c_geo = cutout_rect_handler(geom=geom_struct)
|
c_geo = cutout_rect_handler(geom_struct, gapsize, xmin, ymin, xmax, ymax)
|
||||||
solid_geo += c_geo
|
solid_geo += c_geo
|
||||||
if self.ui.gaptype_radio.get_value() == 'bt' and self.ui.thin_depth_entry.get_value() > 0:
|
if gap_type == 'bt' and thin_entry != 0:
|
||||||
try:
|
try:
|
||||||
gaps_solid_geo += self.subtract_geo(geom_struct, c_geo)
|
gaps_solid_geo += self.subtract_geo(geom_struct, c_geo)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
@@ -980,9 +1086,9 @@ class CutOut(AppTool):
|
|||||||
|
|
||||||
geom_struct = geom_struct.buffer(margin + abs(dia / 2))
|
geom_struct = geom_struct.buffer(margin + abs(dia / 2))
|
||||||
|
|
||||||
c_geo = cutout_rect_handler(geom=geom_struct)
|
c_geo = cutout_rect_handler(geom_struct, gapsize, xmin, ymin, xmax, ymax)
|
||||||
solid_geo += c_geo
|
solid_geo += c_geo
|
||||||
if self.ui.gaptype_radio.get_value() == 'bt' and self.ui.thin_depth_entry.get_value() > 0:
|
if gap_type == 'bt' and thin_entry != 0:
|
||||||
try:
|
try:
|
||||||
gaps_solid_geo += self.subtract_geo(geom_struct, c_geo)
|
gaps_solid_geo += self.subtract_geo(geom_struct, c_geo)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
@@ -992,23 +1098,101 @@ class CutOut(AppTool):
|
|||||||
'[WARNING_NOTCL] %s' % _("Rectangular cutout with negative margin is not possible."))
|
'[WARNING_NOTCL] %s' % _("Rectangular cutout with negative margin is not possible."))
|
||||||
return "fail"
|
return "fail"
|
||||||
|
|
||||||
geo_obj.options['cnctooldia'] = str(dia)
|
|
||||||
geo_obj.options['cutz'] = self.ui.cutz_entry.get_value()
|
|
||||||
geo_obj.options['multidepth'] = self.ui.mpass_cb.get_value()
|
|
||||||
geo_obj.options['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
|
||||||
|
|
||||||
if not solid_geo:
|
if not solid_geo:
|
||||||
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
||||||
return "fail"
|
return "fail"
|
||||||
|
|
||||||
solid_geo = linemerge(solid_geo)
|
solid_geo = linemerge(solid_geo)
|
||||||
|
|
||||||
|
if has_mouse_bites is True:
|
||||||
|
gapsize -= dia / 2
|
||||||
|
mb_object_geo = deepcopy(object_geo)
|
||||||
|
|
||||||
|
if kind == 'single':
|
||||||
|
# fuse the lines
|
||||||
|
mb_object_geo = unary_union(mb_object_geo)
|
||||||
|
|
||||||
|
xmin, ymin, xmax, ymax = mb_object_geo.bounds
|
||||||
|
mb_geo = box(xmin, ymin, xmax, ymax)
|
||||||
|
|
||||||
|
# if Gerber create a buffer at a distance
|
||||||
|
# if Geometry then cut through the geometry
|
||||||
|
if cutout_obj.kind == 'gerber':
|
||||||
|
if margin >= 0:
|
||||||
|
mb_geo = mb_geo.buffer(margin + mb_buff_val)
|
||||||
|
else:
|
||||||
|
mb_geo = mb_geo.buffer(margin - mb_buff_val)
|
||||||
|
|
||||||
|
mb_solid_geo = cutout_rect_handler(mb_geo, gapsize, xmin, ymin, xmax, ymax)
|
||||||
|
|
||||||
|
mouse_bites_geo = self.subtract_geo(mb_geo, mb_solid_geo)
|
||||||
|
else:
|
||||||
|
if cutout_obj.kind == 'geometry':
|
||||||
|
try:
|
||||||
|
__ = iter(mb_object_geo)
|
||||||
|
except TypeError:
|
||||||
|
mb_object_geo = [mb_object_geo]
|
||||||
|
|
||||||
|
for mb_geom_struct in mb_object_geo:
|
||||||
|
mb_geom_struct = unary_union(mb_geom_struct)
|
||||||
|
xmin, ymin, xmax, ymax = mb_geom_struct.bounds
|
||||||
|
mb_geom_struct = box(xmin, ymin, xmax, ymax)
|
||||||
|
|
||||||
|
c_geo = cutout_rect_handler(mb_geom_struct, gapsize, xmin, ymin, xmax, ymax)
|
||||||
|
solid_geo += c_geo
|
||||||
|
|
||||||
|
try:
|
||||||
|
mouse_bites_geo += self.subtract_geo(mb_geom_struct, c_geo)
|
||||||
|
except TypeError:
|
||||||
|
mouse_bites_geo.append(self.subtract_geo(mb_geom_struct, c_geo))
|
||||||
|
elif cutout_obj.kind == 'gerber' and margin >= 0:
|
||||||
|
try:
|
||||||
|
__ = iter(mb_object_geo)
|
||||||
|
except TypeError:
|
||||||
|
mb_object_geo = [mb_object_geo]
|
||||||
|
|
||||||
|
for mb_geom_struct in mb_object_geo:
|
||||||
|
mb_geom_struct = unary_union(mb_geom_struct)
|
||||||
|
xmin, ymin, xmax, ymax = mb_geom_struct.bounds
|
||||||
|
mb_geom_struct = box(xmin, ymin, xmax, ymax)
|
||||||
|
mb_geom_struct = mb_geom_struct.buffer(margin + mb_buff_val)
|
||||||
|
|
||||||
|
c_geo = cutout_rect_handler(mb_geom_struct, gapsize, xmin, ymin, xmax, ymax)
|
||||||
|
solid_geo += c_geo
|
||||||
|
|
||||||
|
try:
|
||||||
|
mouse_bites_geo += self.subtract_geo(mb_geom_struct, c_geo)
|
||||||
|
except TypeError:
|
||||||
|
mouse_bites_geo.append(self.subtract_geo(mb_geom_struct, c_geo))
|
||||||
|
elif cutout_obj.kind == 'gerber' and margin < 0:
|
||||||
|
msg = '[WARNING_NOTCL] %s' % \
|
||||||
|
_("Rectangular cutout with negative margin is not possible.")
|
||||||
|
app_obj.inform.emit(msg)
|
||||||
|
return "fail"
|
||||||
|
|
||||||
|
# list of Shapely Points to mark the drill points centers
|
||||||
|
holes = []
|
||||||
|
for line in mouse_bites_geo:
|
||||||
|
calc_len = 0
|
||||||
|
while calc_len < line.length:
|
||||||
|
holes.append(line.interpolate(calc_len))
|
||||||
|
calc_len += mb_dia + mb_spacing
|
||||||
|
|
||||||
|
def geo_init(geo_obj, app_obj):
|
||||||
|
geo_obj.multigeo = True
|
||||||
geo_obj.solid_geometry = deepcopy(solid_geo)
|
geo_obj.solid_geometry = deepcopy(solid_geo)
|
||||||
|
|
||||||
geo_obj.multigeo = True
|
geo_obj.options['xmin'] = xmin
|
||||||
|
geo_obj.options['ymin'] = ymin
|
||||||
|
geo_obj.options['xmax'] = xmax
|
||||||
|
geo_obj.options['ymax'] = ymax
|
||||||
|
|
||||||
geo_obj.tools.update({
|
geo_obj.options['cnctooldia'] = str(dia)
|
||||||
1: self.cut_tool_dict
|
geo_obj.options['cutz'] = self.ui.cutz_entry.get_value()
|
||||||
})
|
geo_obj.options['multidepth'] = self.ui.mpass_cb.get_value()
|
||||||
|
geo_obj.options['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
||||||
|
|
||||||
|
geo_obj.tools[1] = deepcopy(self.cut_tool_dict)
|
||||||
geo_obj.tools[1]['tooldia'] = str(dia)
|
geo_obj.tools[1]['tooldia'] = str(dia)
|
||||||
geo_obj.tools[1]['solid_geometry'] = geo_obj.solid_geometry
|
geo_obj.tools[1]['solid_geometry'] = geo_obj.solid_geometry
|
||||||
|
|
||||||
@@ -1017,10 +1201,10 @@ class CutOut(AppTool):
|
|||||||
geo_obj.tools[1]['data']['multidepth'] = self.ui.mpass_cb.get_value()
|
geo_obj.tools[1]['data']['multidepth'] = self.ui.mpass_cb.get_value()
|
||||||
geo_obj.tools[1]['data']['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
geo_obj.tools[1]['data']['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
||||||
|
|
||||||
if gaps_solid_geo is not None:
|
if not gaps_solid_geo:
|
||||||
geo_obj.tools.update({
|
pass
|
||||||
9999: self.cut_tool_dict
|
else:
|
||||||
})
|
geo_obj.tools[9999] = deepcopy(self.cut_tool_dict)
|
||||||
geo_obj.tools[9999]['tooldia'] = str(dia)
|
geo_obj.tools[9999]['tooldia'] = str(dia)
|
||||||
geo_obj.tools[9999]['solid_geometry'] = gaps_solid_geo
|
geo_obj.tools[9999]['solid_geometry'] = gaps_solid_geo
|
||||||
|
|
||||||
@@ -1030,18 +1214,46 @@ class CutOut(AppTool):
|
|||||||
geo_obj.tools[9999]['data']['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
geo_obj.tools[9999]['data']['depthperpass'] = self.ui.maxdepth_entry.get_value()
|
||||||
geo_obj.tools[9999]['data']['override_color'] = "#29a3a3fa"
|
geo_obj.tools[9999]['data']['override_color'] = "#29a3a3fa"
|
||||||
|
|
||||||
outname = cutout_obj.options["name"] + "_cutout"
|
def excellon_init(exc_obj, app_o):
|
||||||
ret = self.app.app_obj.new_object('geometry', outname, geo_init)
|
if not holes:
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
if ret != 'fail':
|
tools = {}
|
||||||
# cutout_obj.plot()
|
tools[1] = {}
|
||||||
self.app.inform.emit('[success] %s' % _("Any form CutOut operation finished."))
|
tools[1]["tooldia"] = mb_dia
|
||||||
else:
|
tools[1]['drills'] = holes
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
tools[1]['solid_geometry'] = []
|
||||||
|
|
||||||
|
exc_obj.tools = tools
|
||||||
|
exc_obj.create_geometry()
|
||||||
|
exc_obj.source_file = app_o.export_excellon(obj_name=exc_obj.options['name'], local_use=exc_obj,
|
||||||
|
filename=None, use_thread=False)
|
||||||
|
# calculate the bounds
|
||||||
|
xmin, ymin, xmax, ymax = CutOut.recursive_bounds(exc_obj.solid_geometry)
|
||||||
|
exc_obj.options['xmin'] = xmin
|
||||||
|
exc_obj.options['ymin'] = ymin
|
||||||
|
exc_obj.options['xmax'] = xmax
|
||||||
|
exc_obj.options['ymax'] = ymax
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.ui.gaptype_radio.get_value() == 'mb':
|
||||||
|
ret = app_obj.app_obj.new_object('excellon', outname_exc, excellon_init)
|
||||||
|
if ret == 'fail':
|
||||||
|
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Mouse bites failed."))
|
||||||
|
|
||||||
|
ret = app_obj.app_obj.new_object('geometry', outname, geo_init)
|
||||||
|
if ret == 'fail':
|
||||||
|
app_obj.inform.emit('[ERROR_NOTCL] %s' % _("Failed."))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# cutout_obj.plot(plot_tool=1)
|
||||||
|
app_obj.inform.emit('[success] %s' % _("Rectangular CutOut operation finished."))
|
||||||
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
# self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||||
self.app.should_we_save = True
|
app_obj.should_we_save = True
|
||||||
|
except Exception as ee:
|
||||||
|
log.debug(str(ee))
|
||||||
|
|
||||||
|
self.app.worker_task.emit({'fcn': job_thread, 'params': [self.app]})
|
||||||
|
|
||||||
def on_manual_gap_click(self):
|
def on_manual_gap_click(self):
|
||||||
name = self.ui.man_object_combo.currentText()
|
name = self.ui.man_object_combo.currentText()
|
||||||
|
|||||||
50
camlib.py
50
camlib.py
@@ -2068,22 +2068,26 @@ class Geometry(object):
|
|||||||
if type(left) == LineString:
|
if type(left) == LineString:
|
||||||
if left.coords[0] == geo.coords[0]:
|
if left.coords[0] == geo.coords[0]:
|
||||||
storage.remove(left)
|
storage.remove(left)
|
||||||
geo.coords = list(geo.coords)[::-1] + list(left.coords)
|
# geo.coords = list(geo.coords)[::-1] + list(left.coords) # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords)[::-1] + list(left.coords))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if left.coords[-1] == geo.coords[0]:
|
if left.coords[-1] == geo.coords[0]:
|
||||||
storage.remove(left)
|
storage.remove(left)
|
||||||
geo.coords = list(left.coords) + list(geo.coords)
|
# geo.coords = list(left.coords) + list(geo.coords) # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords)[::-1] + list(left.coords))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if left.coords[0] == geo.coords[-1]:
|
if left.coords[0] == geo.coords[-1]:
|
||||||
storage.remove(left)
|
storage.remove(left)
|
||||||
geo.coords = list(geo.coords) + list(left.coords)
|
# geo.coords = list(geo.coords) + list(left.coords) # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords) + list(left.coords))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if left.coords[-1] == geo.coords[-1]:
|
if left.coords[-1] == geo.coords[-1]:
|
||||||
storage.remove(left)
|
storage.remove(left)
|
||||||
geo.coords = list(geo.coords) + list(left.coords)[::-1]
|
# geo.coords = list(geo.coords) + list(left.coords)[::-1] # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords) + list(left.coords)[::-1])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
_, right = storage.nearest(geo.coords[-1])
|
_, right = storage.nearest(geo.coords[-1])
|
||||||
@@ -2093,22 +2097,26 @@ class Geometry(object):
|
|||||||
if type(right) == LineString:
|
if type(right) == LineString:
|
||||||
if right.coords[0] == geo.coords[-1]:
|
if right.coords[0] == geo.coords[-1]:
|
||||||
storage.remove(right)
|
storage.remove(right)
|
||||||
geo.coords = list(geo.coords) + list(right.coords)
|
# geo.coords = list(geo.coords) + list(right.coords) # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords) + list(right.coords))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if right.coords[-1] == geo.coords[-1]:
|
if right.coords[-1] == geo.coords[-1]:
|
||||||
storage.remove(right)
|
storage.remove(right)
|
||||||
geo.coords = list(geo.coords) + list(right.coords)[::-1]
|
# geo.coords = list(geo.coords) + list(right.coords)[::-1] # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords) + list(right.coords)[::-1])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if right.coords[0] == geo.coords[0]:
|
if right.coords[0] == geo.coords[0]:
|
||||||
storage.remove(right)
|
storage.remove(right)
|
||||||
geo.coords = list(geo.coords)[::-1] + list(right.coords)
|
# geo.coords = list(geo.coords)[::-1] + list(right.coords) # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords)[::-1] + list(right.coords))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if right.coords[-1] == geo.coords[0]:
|
if right.coords[-1] == geo.coords[0]:
|
||||||
storage.remove(right)
|
storage.remove(right)
|
||||||
geo.coords = list(left.coords) + list(geo.coords)
|
# geo.coords = list(left.coords) + list(geo.coords) # Shapely 2.0
|
||||||
|
geo = LineString(list(left.coords) + list(geo.coords))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# right is either a LinearRing or it does not connect
|
# right is either a LinearRing or it does not connect
|
||||||
@@ -5032,7 +5040,8 @@ class CNCjob(Geometry):
|
|||||||
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
||||||
# then reverse coordinates.
|
# then reverse coordinates.
|
||||||
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
||||||
geo.coords = list(geo.coords)[::-1]
|
# geo.coords = list(geo.coords)[::-1] # Shapley 2.0
|
||||||
|
geo = LineString(list(geo.coords)[::-1])
|
||||||
|
|
||||||
# ---------- Single depth/pass --------
|
# ---------- Single depth/pass --------
|
||||||
if not multidepth:
|
if not multidepth:
|
||||||
@@ -5054,9 +5063,10 @@ class CNCjob(Geometry):
|
|||||||
|
|
||||||
total_cut += (geo.length * nr_cuts)
|
total_cut += (geo.length * nr_cuts)
|
||||||
|
|
||||||
self.gcode += self.create_gcode_multi_pass(geo, current_tooldia, extracut, extracut_length,
|
gc, geo = self.create_gcode_multi_pass(geo, current_tooldia, extracut, extracut_length,
|
||||||
tolerance, z_move=z_move, postproc=p,
|
tolerance, z_move=z_move, postproc=p,
|
||||||
old_point=current_pt)
|
old_point=current_pt)
|
||||||
|
self.gcode += gc
|
||||||
|
|
||||||
# calculate the total distance
|
# calculate the total distance
|
||||||
total_travel = total_travel + abs(distance(pt1=current_pt, pt2=pt))
|
total_travel = total_travel + abs(distance(pt1=current_pt, pt2=pt))
|
||||||
@@ -5395,7 +5405,7 @@ class CNCjob(Geometry):
|
|||||||
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
||||||
# then reverse coordinates.
|
# then reverse coordinates.
|
||||||
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
||||||
geo.coords = list(geo.coords)[::-1]
|
geo = LineString(list(geo.coords)[::-1])
|
||||||
|
|
||||||
# ---------- Single depth/pass --------
|
# ---------- Single depth/pass --------
|
||||||
if not self.multidepth:
|
if not self.multidepth:
|
||||||
@@ -5418,9 +5428,10 @@ class CNCjob(Geometry):
|
|||||||
|
|
||||||
total_cut += (geo.length * nr_cuts)
|
total_cut += (geo.length * nr_cuts)
|
||||||
|
|
||||||
t_gcode += self.create_gcode_multi_pass(geo, current_tooldia, self.extracut,
|
gc, geo = self.create_gcode_multi_pass(geo, current_tooldia, self.extracut,
|
||||||
self.extracut_length, self.tolerance,
|
self.extracut_length, self.tolerance,
|
||||||
z_move=self.z_move, postproc=p, old_point=current_pt)
|
z_move=self.z_move, postproc=p, old_point=current_pt)
|
||||||
|
t_gcode += gc
|
||||||
|
|
||||||
# calculate the total distance
|
# calculate the total distance
|
||||||
total_travel = total_travel + abs(distance(pt1=current_pt, pt2=pt))
|
total_travel = total_travel + abs(distance(pt1=current_pt, pt2=pt))
|
||||||
@@ -5798,7 +5809,8 @@ class CNCjob(Geometry):
|
|||||||
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
||||||
# then reverse coordinates.
|
# then reverse coordinates.
|
||||||
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
||||||
geo.coords = list(geo.coords)[::-1]
|
# geo.coords = list(geo.coords)[::-1] # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords)[::-1])
|
||||||
|
|
||||||
# ---------- Single depth/pass --------
|
# ---------- Single depth/pass --------
|
||||||
if not multidepth:
|
if not multidepth:
|
||||||
@@ -5819,9 +5831,10 @@ class CNCjob(Geometry):
|
|||||||
|
|
||||||
total_cut += (geo.length * nr_cuts)
|
total_cut += (geo.length * nr_cuts)
|
||||||
|
|
||||||
self.gcode += self.create_gcode_multi_pass(geo, current_tooldia, extracut, self.extracut_length,
|
gc, geo = self.create_gcode_multi_pass(geo, current_tooldia, extracut, self.extracut_length,
|
||||||
tolerance, z_move=z_move, postproc=p,
|
tolerance, z_move=z_move, postproc=p,
|
||||||
old_point=current_pt)
|
old_point=current_pt)
|
||||||
|
self.gcode += gc
|
||||||
|
|
||||||
# calculate the travel distance
|
# calculate the travel distance
|
||||||
total_travel += abs(distance(pt1=current_pt, pt2=pt))
|
total_travel += abs(distance(pt1=current_pt, pt2=pt))
|
||||||
@@ -5951,7 +5964,8 @@ class CNCjob(Geometry):
|
|||||||
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
# If last point in geometry is the nearest but prefer the first one if last point == first point
|
||||||
# then reverse coordinates.
|
# then reverse coordinates.
|
||||||
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
if pt != geo.coords[0] and pt == geo.coords[-1]:
|
||||||
geo.coords = list(geo.coords)[::-1]
|
# geo.coords = list(geo.coords)[::-1] # Shapely 2.0
|
||||||
|
geo = LineString(list(geo.coords)[::-1])
|
||||||
|
|
||||||
self.gcode += self.create_soldepaste_gcode(geo, p=p, old_point=current_pt)
|
self.gcode += self.create_soldepaste_gcode(geo, p=p, old_point=current_pt)
|
||||||
current_pt = geo.coords[-1]
|
current_pt = geo.coords[-1]
|
||||||
@@ -6151,17 +6165,17 @@ class CNCjob(Geometry):
|
|||||||
|
|
||||||
# Reverse coordinates if not a loop so we can continue cutting without returning to the beginning.
|
# Reverse coordinates if not a loop so we can continue cutting without returning to the beginning.
|
||||||
if type(geometry) == LineString:
|
if type(geometry) == LineString:
|
||||||
geometry.coords = list(geometry.coords)[::-1]
|
geometry = LineString(list(geometry.coords)[::-1])
|
||||||
reverse = True
|
reverse = True
|
||||||
|
|
||||||
# If geometry is reversed, revert.
|
# If geometry is reversed, revert.
|
||||||
if reverse:
|
if reverse:
|
||||||
if type(geometry) == LineString:
|
if type(geometry) == LineString:
|
||||||
geometry.coords = list(geometry.coords)[::-1]
|
geometry = LineString(list(geometry.coords)[::-1])
|
||||||
|
|
||||||
# Lift the tool
|
# Lift the tool
|
||||||
gcode_multi_pass += self.doformat(p.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
|
return gcode_multi_pass, geometry
|
||||||
|
|
||||||
def codes_split(self, gline):
|
def codes_split(self, gline):
|
||||||
"""
|
"""
|
||||||
|
|||||||
Reference in New Issue
Block a user