- in Excellon Editor -> remade the Tool edit made by editing the diameter values in the Tools Table to work for slots too

This commit is contained in:
Marius Stanciu 2019-08-16 23:42:51 +03:00
parent aa97a3722b
commit 66a205a6fd
2 changed files with 124 additions and 63 deletions

View File

@ -20,7 +20,8 @@ CAD program, and create G-Code for Isolation routing.
- each CNCJob object has now it's own text_collection for the annotations which allow for the individual enabling and disabling of the annotations - each CNCJob object has now it's own text_collection for the annotations which allow for the individual enabling and disabling of the annotations
- added new menu category in File -> Backup with two menu entries that duplicate the functions of the export/import preferences buttons from the bottom of the Preferences window - added new menu category in File -> Backup with two menu entries that duplicate the functions of the export/import preferences buttons from the bottom of the Preferences window
- in Excellon Editor fixed the display of the number of slots in the Tool Table after the resize done with the Resize tool - in Excellon Editor fixed the display of the number of slots in the Tool Table after the resize done with the Resize tool
- in Excellon editor -> Resize tool, made sure that when the slot is resized, it's length remain the same, because the tool should influence only the 'thickness' of the slot. Since I don't know anything but the geometry and tool diameter, this is only an approximation and computationally intensive - in Excellon Editor -> Resize tool, made sure that when the slot is resized, it's length remain the same, because the tool should influence only the 'thickness' of the slot. Since I don't know anything but the geometry and tool diameters (old and new), this is only an approximation and computationally intensive
- in Excellon Editor -> remade the Tool edit made by editing the diameter values in the Tools Table to work for slots too
15.08.2019 15.08.2019

View File

@ -907,11 +907,11 @@ class FCDrillResize(FCShapeTool):
origin='center'))) origin='center')))
elif isinstance(select_shape.geo, Polygon): elif isinstance(select_shape.geo, Polygon):
# I don't have any info regarding the angle of the slot geometry, nor how thick it is or # I don't have any info regarding the angle of the slot geometry, nor how thick it is or
# how long it is given the angle. SO I will have to make an approximation because # how long it is given the angle. So I will have to make an approximation because
# we need to conserve the slot length, we only resize the diameter for the tool # we need to conserve the slot length, we only resize the diameter for the tool
# Therefore scaling won't work and buffering will not work either. # Therefore scaling won't work and buffering will not work either.
# First we get the Linestring that is one that the original slot is built around with the4 # First we get the Linestring that is one that the original slot is built around with the
# tool having the diameter sel_dia # tool having the diameter sel_dia
poly = select_shape.geo poly = select_shape.geo
xmin, ymin, xmax, ymax = poly.bounds xmin, ymin, xmax, ymax = poly.bounds
@ -940,16 +940,17 @@ class FCDrillResize(FCShapeTool):
# around them # around them
start_pt = Point(cut_line_with_max_length_coords[0]) start_pt = Point(cut_line_with_max_length_coords[0])
stop_pt = Point(cut_line_with_max_length_coords[1]) stop_pt = Point(cut_line_with_max_length_coords[1])
start_cut_geo = start_pt.buffer(new_dia) start_cut_geo = start_pt.buffer(new_dia / 2)
stop_cut_geo = stop_pt.buffer(new_dia) stop_cut_geo = stop_pt.buffer(new_dia / 2)
# and we cut the above circle polygons from our line and get in this way a line around # and we cut the above circle polygons from our line and get in this way a line around
# which we can build the new slot by buffering with the new tool diameter # which we can build the new slot by buffering with the new tool diameter
new_line = cut_line_with_max_length.difference(start_cut_geo) new_line = cut_line_with_max_length.difference(start_cut_geo)
new_line = new_line.difference(stop_cut_geo) new_line = new_line.difference(stop_cut_geo)
# create the geometry for the resized slot by buffering with the new diameter value, new_dia # create the geometry for the resized slot by buffering with half of the
new_poly = new_line.buffer(new_dia) # new diameter value, new_dia
new_poly = new_line.buffer(new_dia / 2)
self.geometry.append(DrawToolShape(new_poly)) self.geometry.append(DrawToolShape(new_poly))
else: else:
@ -985,7 +986,6 @@ class FCDrillResize(FCShapeTool):
sel_shapes_to_be_deleted.append(select_shape) sel_shapes_to_be_deleted.append(select_shape)
self.draw_app.on_exc_shape_complete(self.destination_storage)
# a hack to make the tool_table display more drills/slots per diameter when shape(drill/slot) # a hack to make the tool_table display more drills/slots per diameter when shape(drill/slot)
# is added. # is added.
@ -1009,8 +1009,6 @@ class FCDrillResize(FCShapeTool):
else: else:
self.draw_app.slot_points_edit[new_dia].append((0, 0)) self.draw_app.slot_points_edit[new_dia].append((0, 0))
self.geometry = []
for dia_key in list(self.draw_app.storage_dict.keys()): for dia_key in list(self.draw_app.storage_dict.keys()):
# if following the resize of the drills there will be no more drills for some of the tools then # if following the resize of the drills there will be no more drills for some of the tools then
# delete those tools # delete those tools
@ -1034,9 +1032,15 @@ class FCDrillResize(FCShapeTool):
for shp in sel_shapes_to_be_deleted: for shp in sel_shapes_to_be_deleted:
self.draw_app.selected.remove(shp) self.draw_app.selected.remove(shp)
# add the new geometry to storage
self.draw_app.on_exc_shape_complete(self.destination_storage)
self.draw_app.build_ui() self.draw_app.build_ui()
self.draw_app.replot() self.draw_app.replot()
# empty the self.geometry
self.geometry = []
# we reactivate the signals after the after the tool editing # we reactivate the signals after the after the tool editing
self.draw_app.tools_table_exc.itemChanged.connect(self.draw_app.on_tool_edit) self.draw_app.tools_table_exc.itemChanged.connect(self.draw_app.on_tool_edit)
@ -2467,93 +2471,149 @@ class FlatCAMExcEditor(QtCore.QObject):
self.build_ui() self.build_ui()
def on_tool_edit(self, item_changed): def on_tool_edit(self, item_changed):
# if connected, disconnect the signal from the slot on item_changed as it creates issues # if connected, disconnect the signal from the slot on item_changed as it creates issues
self.tools_table_exc.itemChanged.disconnect() try:
self.tools_table_exc.cellPressed.disconnect() self.tools_table_exc.itemChanged.disconnect()
except TypeError:
pass
try:
self.tools_table_exc.cellPressed.disconnect()
except TypeError:
pass
# self.tools_table_exc.selectionModel().currentChanged.disconnect() # self.tools_table_exc.selectionModel().currentChanged.disconnect()
self.is_modified = True self.is_modified = True
current_table_dia_edited = None new_dia = None
if self.tools_table_exc.currentItem() is not None: if self.tools_table_exc.currentItem() is not None:
try: try:
current_table_dia_edited = float(self.tools_table_exc.currentItem().text()) new_dia = float(self.tools_table_exc.currentItem().text())
except ValueError as e: except ValueError as e:
log.debug("FlatCAMExcEditor.on_tool_edit() --> %s" % str(e)) log.debug("FlatCAMExcEditor.on_tool_edit() --> %s" % str(e))
self.tools_table_exc.setCurrentItem(None) self.tools_table_exc.setCurrentItem(None)
return return
row_of_item_changed = self.tools_table_exc.currentRow() row_of_item_changed = self.tools_table_exc.currentRow()
# rows start with 0, tools start with 1 so we adjust the value by 1 # rows start with 0, tools start with 1 so we adjust the value by 1
key_in_tool2tooldia = row_of_item_changed + 1 key_in_tool2tooldia = row_of_item_changed + 1
old_dia = self.tool2tooldia[key_in_tool2tooldia]
dia_changed = self.tool2tooldia[key_in_tool2tooldia] # SOURCE storage
source_storage = self.storage_dict[old_dia]
# DESTINATION storage
# tool diameter is not used so we create a new tool with the desired diameter # tool diameter is not used so we create a new tool with the desired diameter
if current_table_dia_edited not in self.olddia_newdia.values(): if new_dia not in self.olddia_newdia:
# update the dict that holds as keys our initial diameters and as values the edited diameters destination_storage = FlatCAMGeoEditor.make_storage()
self.olddia_newdia[dia_changed] = current_table_dia_edited self.storage_dict[new_dia] = destination_storage
# update the dict that holds tool_no as key and tool_dia as value
self.tool2tooldia[key_in_tool2tooldia] = current_table_dia_edited
# update the tool offset # self.olddia_newdia dict keeps the evidence on current tools diameters as keys and gets updated on values
modified_offset = self.exc_obj.tool_offset.pop(dia_changed, None) # each time a tool diameter is edited or added
if modified_offset is not None: self.olddia_newdia[new_dia] = new_dia
self.exc_obj.tool_offset[current_table_dia_edited] = modified_offset
self.replot()
else: else:
# tool diameter is already in use so we move the drills from the prior tool to the new tool # tool diameter is already in use so we move the drills from the prior tool to the new tool
factor = current_table_dia_edited / dia_changed destination_storage = self.storage_dict[new_dia]
geometry = []
scaled_geo = [] # since we add a new tool, we update also the intial state of the tool_table through it's dictionary
for shape_exc in self.storage_dict[dia_changed].get_objects(): # we add a new entry in the tool2tooldia dict
geo_list = [] self.tool2tooldia[len(self.olddia_newdia)] = new_dia
if isinstance(shape_exc.geo, MultiLineString) or isinstance(shape_exc.geo, MultiPolygon):
for subgeo in shape_exc.geo:
geo_list.append(affinity.scale(subgeo, xfact=factor, yfact=factor, origin='center'))
scaled_geo = MultiLineString(geo_list)
elif isinstance(shape_exc.geo, Polygon):
scaled_geo = geo_list.append(affinity.scale(shape_exc.geo,
xfact=factor, yfact=factor, origin='center'))
if isinstance(shape_exc.geo, MultiLineString): # CHANGE the elements geometry according to the new diameter
# add bogus drill points (for total count of drills) but only if the shape is a MultiLineString factor = new_dia / old_dia
# because the drills are MultiLineString new_geo = Polygon()
for k, v in self.olddia_newdia.items(): for shape_exc in source_storage.get_objects():
if v == current_table_dia_edited: geo_list = []
self.points_edit[k].append((0, 0)) if isinstance(shape_exc.geo, MultiLineString):
break for subgeo in shape_exc.geo:
geo_list.append(affinity.scale(subgeo, xfact=factor, yfact=factor, origin='center'))
new_geo = MultiLineString(geo_list)
elif isinstance(shape_exc.geo, Polygon):
# I don't have any info regarding the angle of the slot geometry, nor how thick it is or
# how long it is given the angle. So I will have to make an approximation because
# we need to conserve the slot length, we only resize the diameter for the tool
# Therefore scaling won't work and buffering will not work either.
# First we get the Linestring that is one that the original slot is built around with the
# tool having the diameter sel_dia
poly = shape_exc.geo
xmin, ymin, xmax, ymax = poly.bounds
# a line that is certain to be bigger than our slot because it's the diagonal
# of it's bounding box
poly_diagonal = LineString([(xmin, ymin), (xmax, ymax)])
poly_centroid = poly.centroid
# center of the slot geometry
poly_center = (poly_centroid.x, poly_centroid.y)
# make a list of intersections with the rotated line
list_of_cuttings = []
for angle in range(0, 359, 1):
rot_poly_diagonal = affinity.rotate(poly_diagonal, angle=angle, origin=poly_center)
cut_line = rot_poly_diagonal.intersection(poly)
cut_line_len = cut_line.length
list_of_cuttings.append(
(cut_line_len, cut_line)
)
# find the cut_line with the maximum length which is the LineString for which the start
# and stop point are the start and stop point of the slot as in the Gerber file
cut_line_with_max_length = max(list_of_cuttings, key=lambda i: i[0])[1]
# find the coordinates of this line
cut_line_with_max_length_coords = list(cut_line_with_max_length.coords)
# extract the first and last point of the line and build some buffered polygon circles
# around them
start_pt = Point(cut_line_with_max_length_coords[0])
stop_pt = Point(cut_line_with_max_length_coords[1])
start_cut_geo = start_pt.buffer(new_dia / 2)
stop_cut_geo = stop_pt.buffer(new_dia / 2)
# and we cut the above circle polygons from our line and get in this way a line around
# which we can build the new slot by buffering with the new tool diameter
new_line = cut_line_with_max_length.difference(start_cut_geo)
new_line = new_line.difference(stop_cut_geo)
# create the geometry for the resized slot by buffering with half of the
# new diameter value: new_dia
new_geo = new_line.buffer(new_dia / 2)
try:
self.points_edit.pop(old_dia, None)
except KeyError:
pass
try:
self.slot_points_edit.pop(old_dia, None)
except KeyError:
pass
# add bogus drill/slots points (for total count of drills/slots)
# for drills
if isinstance(shape_exc.geo, MultiLineString):
if new_dia not in self.points_edit:
self.points_edit[new_dia] = [(0, 0)]
else: else:
# the shape is a Polygon or MultiPolygon therefore we have to increase the slot numbers self.points_edit[new_dia].append((0, 0))
for k, v in self.olddia_newdia.items():
if v == current_table_dia_edited:
self.slot_points_edit[k].append((0, 0))
break
geometry.append(DrawToolShape(scaled_geo)) # for slots
if isinstance(shape_exc.geo, Polygon):
if new_dia not in self.slot_points_edit:
self.slot_points_edit[new_dia] = [(0, 0)]
else:
self.slot_points_edit[new_dia].append((0, 0))
# search for the old dia that correspond to the new dia and add the drills/slots in it's storage self.add_exc_shape(shape=DrawToolShape(new_geo), storage=destination_storage)
# everything will be sorted out later, when the edited Excellon is updated
for k, v in self.olddia_newdia.items():
if v == current_table_dia_edited:
self.add_exc_shape(geometry, self.storage_dict[k])
break
# delete the old tool from which we moved the drills # update the UI and the CANVAS
self.on_tool_delete(dia=dia_changed) self.build_ui()
self.replot()
# delete the tool offset # delete the old tool
self.exc_obj.tool_offset.pop(dia_changed, None) self.on_tool_delete(dia=old_dia)
# we reactivate the signals after the after the tool editing # we reactivate the signals after the after the tool editing
self.tools_table_exc.itemChanged.connect(self.on_tool_edit) self.tools_table_exc.itemChanged.connect(self.on_tool_edit)
self.tools_table_exc.cellPressed.connect(self.on_row_selected) self.tools_table_exc.cellPressed.connect(self.on_row_selected)
self.app.inform.emit(_("[success] Done. Tool edit completed."))
# self.tools_table_exc.selectionModel().currentChanged.connect(self.on_row_selected) # self.tools_table_exc.selectionModel().currentChanged.connect(self.on_row_selected)
def on_name_activate(self): def on_name_activate(self):