- in Geometry Editor made sure that on final save, for MultiLineString geometry all the connected lines are merged into one LineString to minimize the number of vertical movements in GCode
- more work in Punch Gerber Tool
This commit is contained in:
@@ -9,6 +9,11 @@ CAD program, and create G-Code for Isolation routing.
|
|||||||
|
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
|
27.01.2020
|
||||||
|
|
||||||
|
- in Geometry Editor made sure that on final save, for MultiLineString geometry all the connected lines are merged into one LineString to minimize the number of vertical movements in GCode
|
||||||
|
- more work in Punch Gerber Tool
|
||||||
|
|
||||||
24.02.2020
|
24.02.2020
|
||||||
|
|
||||||
- small changes to the Toolchange manual preprocessor
|
- small changes to the Toolchange manual preprocessor
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ from flatcamParsers.ParseFont import *
|
|||||||
import FlatCAMApp
|
import FlatCAMApp
|
||||||
|
|
||||||
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
|
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
|
||||||
from shapely.ops import cascaded_union, unary_union
|
from shapely.ops import cascaded_union, unary_union, linemerge
|
||||||
import shapely.affinity as affinity
|
import shapely.affinity as affinity
|
||||||
from shapely.geometry.polygon import orient
|
from shapely.geometry.polygon import orient
|
||||||
|
|
||||||
@@ -2498,6 +2498,9 @@ class FCSelect(DrawTool):
|
|||||||
raise
|
raise
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
def clean_up(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
class FCExplode(FCShapeTool):
|
class FCExplode(FCShapeTool):
|
||||||
def __init__(self, draw_app):
|
def __init__(self, draw_app):
|
||||||
@@ -3739,8 +3742,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry,
|
geo_to_edit = self.flatten(geometry=fcgeometry.solid_geometry, orient_val=milling_type)
|
||||||
orient_val=milling_type)
|
|
||||||
|
|
||||||
for shape in geo_to_edit:
|
for shape in geo_to_edit:
|
||||||
if shape is not None: # TODO: Make flatten never create a None
|
if shape is not None: # TODO: Make flatten never create a None
|
||||||
@@ -4396,13 +4398,24 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||||||
fcgeometry.tools[self.multigeo_tool]['solid_geometry'] = []
|
fcgeometry.tools[self.multigeo_tool]['solid_geometry'] = []
|
||||||
# for shape in self.shape_buffer:
|
# for shape in self.shape_buffer:
|
||||||
for shape in self.storage.get_objects():
|
for shape in self.storage.get_objects():
|
||||||
fcgeometry.tools[self.multigeo_tool]['solid_geometry'].append(shape.geo)
|
new_geo = shape.geo
|
||||||
|
|
||||||
|
# simplify the MultiLineString
|
||||||
|
if isinstance(new_geo, MultiLineString):
|
||||||
|
new_geo = linemerge(new_geo)
|
||||||
|
|
||||||
|
fcgeometry.tools[self.multigeo_tool]['solid_geometry'].append(new_geo)
|
||||||
self.multigeo_tool = None
|
self.multigeo_tool = None
|
||||||
|
|
||||||
fcgeometry.solid_geometry = []
|
fcgeometry.solid_geometry = []
|
||||||
# for shape in self.shape_buffer:
|
# for shape in self.shape_buffer:
|
||||||
for shape in self.storage.get_objects():
|
for shape in self.storage.get_objects():
|
||||||
fcgeometry.solid_geometry.append(shape.geo)
|
new_geo = shape.geo
|
||||||
|
|
||||||
|
# simplify the MultiLineString
|
||||||
|
if isinstance(new_geo, MultiLineString):
|
||||||
|
new_geo = linemerge(new_geo)
|
||||||
|
fcgeometry.solid_geometry.append(new_geo)
|
||||||
|
|
||||||
def update_options(self, obj):
|
def update_options(self, obj):
|
||||||
if self.paint_tooldia:
|
if self.paint_tooldia:
|
||||||
|
|||||||
@@ -379,6 +379,7 @@ class ToolPunchGerber(FlatCAMTool):
|
|||||||
# ## Signals
|
# ## Signals
|
||||||
self.method_punch.activated_custom.connect(self.on_method)
|
self.method_punch.activated_custom.connect(self.on_method)
|
||||||
self.reset_button.clicked.connect(self.set_tool_ui)
|
self.reset_button.clicked.connect(self.set_tool_ui)
|
||||||
|
self.punch_object_button.clicked.connect(self.on_generate_object)
|
||||||
|
|
||||||
self.circular_cb.stateChanged.connect(
|
self.circular_cb.stateChanged.connect(
|
||||||
lambda state:
|
lambda state:
|
||||||
@@ -493,6 +494,142 @@ class ToolPunchGerber(FlatCAMTool):
|
|||||||
except (AttributeError, TypeError):
|
except (AttributeError, TypeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def on_generate_object(self):
|
||||||
|
|
||||||
|
# get the Gerber file who is the source of the punched Gerber
|
||||||
|
selection_index = self.gerber_object_combo.currentIndex()
|
||||||
|
model_index = self.app.collection.index(selection_index, 0, self.gerber_object_combo.rootModelIndex())
|
||||||
|
|
||||||
|
try:
|
||||||
|
grb_obj = model_index.internalPointer().obj
|
||||||
|
except Exception:
|
||||||
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
|
||||||
|
return
|
||||||
|
|
||||||
|
name = grb_obj.options['name'].rpartition('.')[0]
|
||||||
|
outname = name + "_punched"
|
||||||
|
|
||||||
|
punch_method = self.method_punch.get_value()
|
||||||
|
|
||||||
|
if punch_method == 'exc':
|
||||||
|
|
||||||
|
# get the Excellon file whose geometry will create the punch holes
|
||||||
|
selection_index = self.exc_combo.currentIndex()
|
||||||
|
model_index = self.app.collection.index(selection_index, 0, self.exc_combo.rootModelIndex())
|
||||||
|
|
||||||
|
try:
|
||||||
|
exc_obj = model_index.internalPointer().obj
|
||||||
|
except Exception:
|
||||||
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
|
||||||
|
return
|
||||||
|
|
||||||
|
# this is the punching geometry
|
||||||
|
exc_solid_geometry = MultiPolygon(exc_obj.solid_geometry)
|
||||||
|
if isinstance(grb_obj.solid_geometry, list):
|
||||||
|
grb_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
|
||||||
|
else:
|
||||||
|
grb_solid_geometry = grb_obj.solid_geometry
|
||||||
|
|
||||||
|
# create the punched Gerber solid_geometry
|
||||||
|
punched_solid_geometry = grb_solid_geometry.difference(exc_solid_geometry)
|
||||||
|
|
||||||
|
new_apertures = dict()
|
||||||
|
new_apertures = deepcopy(grb_obj.apertures)
|
||||||
|
|
||||||
|
holes_apertures = dict()
|
||||||
|
|
||||||
|
for apid, val in new_apertures.items():
|
||||||
|
for elem in val['geometry']:
|
||||||
|
# make it work only for Gerber Flashes who are Points in 'follow'
|
||||||
|
if 'solid' in elem and isinstance(elem['follow'], Point):
|
||||||
|
for drill in exc_obj.drills:
|
||||||
|
clear_apid = exc_obj.tools[drill['tool']]['C']
|
||||||
|
exc_poly = drill['point'].buffer(clear_apid / 2.0)
|
||||||
|
if exc_poly.within(elem['solid']):
|
||||||
|
|
||||||
|
if clear_apid not in holes_apertures or holes_apertures[clear_apid]['type'] != 'C':
|
||||||
|
holes_apertures[clear_apid] = dict()
|
||||||
|
holes_apertures[clear_apid]['type'] = 'C'
|
||||||
|
holes_apertures[clear_apid]['size'] = clear_apid
|
||||||
|
holes_apertures[clear_apid]['geometry'] = list()
|
||||||
|
geo_elem = dict()
|
||||||
|
geo_elem['clear'] = exc_poly
|
||||||
|
geo_elem['follow'] = exc_poly.centroid
|
||||||
|
holes_apertures[clear_apid]['geometry'].append(deepcopy(geo_elem))
|
||||||
|
|
||||||
|
elem['clear'] = exc_poly.centroid
|
||||||
|
|
||||||
|
for apid, val in new_apertures.items():
|
||||||
|
for clear_apid, clear_val in holes_apertures.items():
|
||||||
|
if round(clear_apid, self.decimals) == round(val['size'], self.decimals):
|
||||||
|
geo_elem = dict()
|
||||||
|
|
||||||
|
val['geometry'].append(geo_elem)
|
||||||
|
|
||||||
|
def init_func(new_obj, app_obj):
|
||||||
|
new_obj.options.update(grb_obj.options)
|
||||||
|
new_obj.options['name'] = outname
|
||||||
|
new_obj.fill_color = deepcopy(grb_obj.fill_color)
|
||||||
|
new_obj.outline_color = deepcopy(grb_obj.outline_color)
|
||||||
|
|
||||||
|
new_obj.apertures = deepcopy(new_apertures)
|
||||||
|
|
||||||
|
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
|
||||||
|
new_obj.source_file = self.app.export_gerber(obj_name=outname, filename=None,
|
||||||
|
local_use=new_obj, use_thread=False)
|
||||||
|
|
||||||
|
self.app.new_object('gerber', outname, init_func)
|
||||||
|
elif punch_method == 'fixed':
|
||||||
|
punch_size = float(self.dia_entry.get_value())
|
||||||
|
|
||||||
|
punching_geo = list()
|
||||||
|
for apid in grb_obj.apertures:
|
||||||
|
if grb_obj.apertures[apid]['type'] == 'C':
|
||||||
|
if punch_size >= float(grb_obj.apertures[apid]['size']):
|
||||||
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
|
_(" Could not generate punched hole Gerber because the punch hole size"
|
||||||
|
"is bigger than some of the apertures in the Gerber object."))
|
||||||
|
return 'fail'
|
||||||
|
else:
|
||||||
|
for elem in grb_obj.apertures[apid]['geometry']:
|
||||||
|
if 'follow' in elem:
|
||||||
|
if isinstance(elem['follow'], Point):
|
||||||
|
punching_geo.append(elem['follow'].buffer(punch_size / 2))
|
||||||
|
else:
|
||||||
|
if punch_size >= float(grb_obj.apertures[apid]['width']) or \
|
||||||
|
punch_size >= float(grb_obj.apertures[apid]['height']):
|
||||||
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
|
_("Could not generate punched hole Gerber because the punch hole size"
|
||||||
|
"is bigger than some of the apertures in the Gerber object."))
|
||||||
|
return 'fail'
|
||||||
|
else:
|
||||||
|
for elem in grb_obj.apertures[apid]['geometry']:
|
||||||
|
if 'follow' in elem:
|
||||||
|
if isinstance(elem['follow'], Point):
|
||||||
|
punching_geo.append(elem['follow'].buffer(punch_size / 2))
|
||||||
|
|
||||||
|
punching_geo = MultiPolygon(punching_geo)
|
||||||
|
if isinstance(grb_obj.solid_geometry, list):
|
||||||
|
temp_solid_geometry = MultiPolygon(grb_obj.solid_geometry)
|
||||||
|
else:
|
||||||
|
temp_solid_geometry = grb_obj.solid_geometry
|
||||||
|
punched_solid_geometry = temp_solid_geometry.difference(punching_geo)
|
||||||
|
|
||||||
|
if punched_solid_geometry == temp_solid_geometry:
|
||||||
|
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||||
|
_("Could not generate punched hole Gerber because the newly created object "
|
||||||
|
"geometry is the same as the one in the source object geometry..."))
|
||||||
|
return 'fail'
|
||||||
|
|
||||||
|
def init_func(new_obj, app_obj):
|
||||||
|
new_obj.solid_geometry = deepcopy(punched_solid_geometry)
|
||||||
|
|
||||||
|
self.app.new_object('gerber', outname, init_func)
|
||||||
|
elif punch_method == 'ring':
|
||||||
|
pass
|
||||||
|
elif punch_method == 'prop':
|
||||||
|
pass
|
||||||
|
|
||||||
def reset_fields(self):
|
def reset_fields(self):
|
||||||
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||||
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
self.exc_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
|
||||||
|
|||||||
Reference in New Issue
Block a user