- moved the initialization of the FlatCAM editors after a read of the default values. If I don't do this then only at the first start of the application the Editors are not functional as the Editor objects are most likely destroyed

- fixed bug in FlatCAM editors that caused the shapes to be drawn without resolution when the app units where INCH
- modified the transformation functions in all classes in camlib.py and FlatCAMObj.py to work with empty geometries
This commit is contained in:
Marius Stanciu 2019-08-17 18:47:41 +03:00
parent d8937b82fc
commit b20203eace
8 changed files with 184 additions and 64 deletions

View File

@ -1395,18 +1395,11 @@ class App(QtCore.QObject):
end_plot_time = time.time()
self.log.debug("Finished Canvas initialization in %s seconds." % (str(end_plot_time - start_plot_time)))
# ### EDITOR section
self.geo_editor = FlatCAMGeoEditor(self, disabled=True)
self.exc_editor = FlatCAMExcEditor(self)
self.grb_editor = FlatCAMGrbEditor(self)
# ### Adjust tabs width ## ##
# self.collection.view.setMinimumWidth(self.ui.options_scroll_area.widget().sizeHint().width() +
# self.ui.options_scroll_area.verticalScrollBar().sizeHint().width())
self.collection.view.setMinimumWidth(290)
self.log.debug("Finished adding FlatCAM Editor's.")
# ### Worker ####
if self.defaults["global_worker_number"]:
self.workers = WorkerStack(workers_number=int(self.defaults["global_worker_number"]))
@ -2102,6 +2095,17 @@ class App(QtCore.QObject):
filename_factory = self.data_path + '/factory_defaults.FlatConfig'
os.chmod(filename_factory, S_IREAD | S_IRGRP | S_IROTH)
####################################################
# ### EDITOR section ###############################
####################################################
# watch out for the position of the editors instantiation ... if it is done before a save of the default values
# at the first launch of the App , the editors will not be functional.
self.geo_editor = FlatCAMGeoEditor(self, disabled=True)
self.exc_editor = FlatCAMExcEditor(self)
self.grb_editor = FlatCAMGrbEditor(self)
self.log.debug("Finished adding FlatCAM Editor's.")
# Post-GUI initialization: Experimental attempt
# to perform unit tests on the GUI.
# if post_gui is not None:
@ -2378,9 +2382,6 @@ class App(QtCore.QObject):
# we set the notebook to hidden
self.ui.splitter.setSizes([0, 1])
# set call source to the Editor we go into
self.call_source = 'geo_editor'
if edited_object.multigeo is True:
edited_tools = [int(x.text()) for x in edited_object.ui.geo_tools_table.selectedItems()]
if len(edited_tools) > 1:
@ -2402,30 +2403,33 @@ class App(QtCore.QObject):
else:
self.geo_editor.edit_fcgeometry(edited_object)
# set call source to the Editor we go into
self.call_source = 'geo_editor'
elif isinstance(edited_object, FlatCAMExcellon):
# store the Excellon Editor Toolbar visibility before entering in the Editor
self.exc_editor.toolbar_old_state = True if self.ui.exc_edit_toolbar.isVisible() else False
# set call source to the Editor we go into
self.call_source = 'exc_editor'
if self.ui.splitter.sizes()[0] == 0:
self.ui.splitter.setSizes([1, 1])
self.exc_editor.edit_fcexcellon(edited_object)
# set call source to the Editor we go into
self.call_source = 'exc_editor'
elif isinstance(edited_object, FlatCAMGerber):
# store the Gerber Editor Toolbar visibility before entering in the Editor
self.grb_editor.toolbar_old_state = True if self.ui.grb_edit_toolbar.isVisible() else False
# set call source to the Editor we go into
self.call_source = 'grb_editor'
if self.ui.splitter.sizes()[0] == 0:
self.ui.splitter.setSizes([1, 1])
self.grb_editor.edit_fcgerber(edited_object)
# set call source to the Editor we go into
self.call_source = 'grb_editor'
# make sure that we can't select another object while in Editor Mode:
# self.collection.view.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
self.ui.project_frame.setDisabled(True)

View File

@ -5000,14 +5000,20 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
geoms.append(scale_recursion(local_geom))
return geoms
else:
return affinity.scale(geom, xfactor, yfactor, origin=(px, py))
try:
return affinity.scale(geom, xfactor, yfactor, origin=(px, py))
except AttributeError:
return geom
if self.multigeo is True:
for tool in self.tools:
self.tools[tool]['solid_geometry'] = scale_recursion(self.tools[tool]['solid_geometry'])
else:
self.solid_geometry = scale_recursion(self.solid_geometry)
try:
self.solid_geometry = scale_recursion(self.solid_geometry)
except AttributeError:
self.solid_geometry = []
return
self.app.inform.emit(_(
"[success] Geometry Scale done."
))
@ -5038,7 +5044,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
geoms.append(translate_recursion(local_geom))
return geoms
else:
return affinity.translate(geom, xoff=dx, yoff=dy)
try:
return affinity.translate(geom, xoff=dx, yoff=dy)
except AttributeError:
return geom
if self.multigeo is True:
for tool in self.tools:

View File

@ -18,6 +18,9 @@ CAD program, and create G-Code for Isolation routing.
- updated translations and changed version
- fixed installer issue for the x64 version due of the used CX_FREEZE python package which was in unofficial version (obviously not ready to be used)
- fixed bug in Geometry Editor, in disconnect_canvas_event_handlers() where I left some part of code without adding a try - except block which was required
- moved the initialization of the FlatCAM editors after a read of the default values. If I don't do this then only at the first start of the application the Editors are not functional as the Editor objects are most likely destroyed
- fixed bug in FlatCAM editors that caused the shapes to be drawn without resolution when the app units where INCH
- modified the transformation functions in all classes in camlib.py and FlatCAMObj.py to work with empty geometries
- RELEASE 8.95
17.08.2019

111
camlib.py
View File

@ -1389,7 +1389,10 @@ class Geometry(object):
new_obj.append(mirror_geom(g))
return new_obj
else:
return affinity.scale(obj, xscale, yscale, origin=(px, py))
try:
return affinity.scale(obj, xscale, yscale, origin=(px, py))
except AttributeError:
return obj
try:
if self.multigeo is True:
@ -1427,7 +1430,10 @@ class Geometry(object):
new_obj.append(rotate_geom(g))
return new_obj
else:
return affinity.rotate(obj, angle, origin=(px, py))
try:
return affinity.rotate(obj, angle, origin=(px, py))
except AttributeError:
return obj
try:
if self.multigeo is True:
@ -1463,7 +1469,10 @@ class Geometry(object):
new_obj.append(skew_geom(g))
return new_obj
else:
return affinity.skew(obj, angle_x, angle_y, origin=(px, py))
try:
return affinity.skew(obj, angle_x, angle_y, origin=(px, py))
except AttributeError:
return obj
try:
if self.multigeo is True:
@ -3380,7 +3389,10 @@ class Gerber (Geometry):
new_obj.append(scale_geom(g))
return new_obj
else:
return affinity.scale(obj, xfactor, yfactor, origin=(px, py))
try:
return affinity.scale(obj, xfactor, yfactor, origin=(px, py))
except AttributeError:
return obj
self.solid_geometry = scale_geom(self.solid_geometry)
self.follow_geometry = scale_geom(self.follow_geometry)
@ -3444,7 +3456,10 @@ class Gerber (Geometry):
new_obj.append(offset_geom(g))
return new_obj
else:
return affinity.translate(obj, xoff=dx, yoff=dy)
try:
return affinity.translate(obj, xoff=dx, yoff=dy)
except AttributeError:
return obj
# ## Solid geometry
self.solid_geometry = offset_geom(self.solid_geometry)
@ -3500,7 +3515,10 @@ class Gerber (Geometry):
new_obj.append(mirror_geom(g))
return new_obj
else:
return affinity.scale(obj, xscale, yscale, origin=(px, py))
try:
return affinity.scale(obj, xscale, yscale, origin=(px, py))
except AttributeError:
return obj
self.solid_geometry = mirror_geom(self.solid_geometry)
self.follow_geometry = mirror_geom(self.follow_geometry)
@ -3546,7 +3564,10 @@ class Gerber (Geometry):
new_obj.append(skew_geom(g))
return new_obj
else:
return affinity.skew(obj, angle_x, angle_y, origin=(px, py))
try:
return affinity.skew(obj, angle_x, angle_y, origin=(px, py))
except AttributeError:
return obj
self.solid_geometry = skew_geom(self.solid_geometry)
self.follow_geometry = skew_geom(self.follow_geometry)
@ -3585,7 +3606,10 @@ class Gerber (Geometry):
new_obj.append(rotate_geom(g))
return new_obj
else:
return affinity.rotate(obj, angle, origin=(px, py))
try:
return affinity.rotate(obj, angle, origin=(px, py))
except AttributeError:
return obj
self.solid_geometry = rotate_geom(self.solid_geometry)
self.follow_geometry = rotate_geom(self.follow_geometry)
@ -4703,8 +4727,10 @@ class Excellon(Geometry):
new_obj.append(scale_geom(g))
return new_obj
else:
return affinity.scale(obj, xfactor,
yfactor, origin=(px, py))
try:
return affinity.scale(obj, xfactor, yfactor, origin=(px, py))
except AttributeError:
return obj
# Drills
for drill in self.drills:
@ -4739,7 +4765,10 @@ class Excellon(Geometry):
new_obj.append(offset_geom(g))
return new_obj
else:
return affinity.translate(obj, xoff=dx, yoff=dy)
try:
return affinity.translate(obj, xoff=dx, yoff=dy)
except AttributeError:
return obj
# Drills
for drill in self.drills:
@ -4776,7 +4805,10 @@ class Excellon(Geometry):
new_obj.append(mirror_geom(g))
return new_obj
else:
return affinity.scale(obj, xscale, yscale, origin=(px, py))
try:
return affinity.scale(obj, xscale, yscale, origin=(px, py))
except AttributeError:
return obj
# Modify data
# Drills
@ -4823,7 +4855,10 @@ class Excellon(Geometry):
new_obj.append(skew_geom(g))
return new_obj
else:
return affinity.skew(obj, angle_x, angle_y, origin=(px, py))
try:
return affinity.skew(obj, angle_x, angle_y, origin=(px, py))
except AttributeError:
return obj
if point is None:
px, py = 0, 0
@ -4874,9 +4909,15 @@ class Excellon(Geometry):
return new_obj
else:
if origin:
return affinity.rotate(obj, angle, origin=origin)
try:
return affinity.rotate(obj, angle, origin=origin)
except AttributeError:
return obj
else:
return affinity.rotate(obj, angle, origin=(px, py))
try:
return affinity.rotate(obj, angle, origin=(px, py))
except AttributeError:
return obj
if point is None:
# Drills
@ -7135,7 +7176,10 @@ class CNCjob(Geometry):
self.gcode = scale_g(self.gcode)
# offset geometry
for g in self.gcode_parsed:
g['geom'] = affinity.scale(g['geom'], xfactor, yfactor, origin=(px, py))
try:
g['geom'] = affinity.scale(g['geom'], xfactor, yfactor, origin=(px, py))
except AttributeError:
return g['geom']
self.create_geometry()
else:
for k, v in self.cnc_tools.items():
@ -7143,9 +7187,11 @@ class CNCjob(Geometry):
v['gcode'] = scale_g(v['gcode'])
# scale gcode_parsed
for g in v['gcode_parsed']:
g['geom'] = affinity.scale(g['geom'], xfactor, yfactor, origin=(px, py))
try:
g['geom'] = affinity.scale(g['geom'], xfactor, yfactor, origin=(px, py))
except AttributeError:
return g['geom']
v['solid_geometry'] = cascaded_union([geo['geom'] for geo in v['gcode_parsed']])
self.create_geometry()
def offset(self, vect):
@ -7201,7 +7247,10 @@ class CNCjob(Geometry):
self.gcode = offset_g(self.gcode)
# offset geometry
for g in self.gcode_parsed:
g['geom'] = affinity.translate(g['geom'], xoff=dx, yoff=dy)
try:
g['geom'] = affinity.translate(g['geom'], xoff=dx, yoff=dy)
except AttributeError:
return g['geom']
self.create_geometry()
else:
for k, v in self.cnc_tools.items():
@ -7209,7 +7258,10 @@ class CNCjob(Geometry):
v['gcode'] = offset_g(v['gcode'])
# offset gcode_parsed
for g in v['gcode_parsed']:
g['geom'] = affinity.translate(g['geom'], xoff=dx, yoff=dy)
try:
g['geom'] = affinity.translate(g['geom'], xoff=dx, yoff=dy)
except AttributeError:
return g['geom']
v['solid_geometry'] = cascaded_union([geo['geom'] for geo in v['gcode_parsed']])
def mirror(self, axis, point):
@ -7223,8 +7275,10 @@ class CNCjob(Geometry):
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
for g in self.gcode_parsed:
g['geom'] = affinity.scale(g['geom'], xscale, yscale, origin=(px, py))
try:
g['geom'] = affinity.scale(g['geom'], xscale, yscale, origin=(px, py))
except AttributeError:
return g['geom']
self.create_geometry()
def skew(self, angle_x, angle_y, point):
@ -7245,9 +7299,10 @@ class CNCjob(Geometry):
px, py = point
for g in self.gcode_parsed:
g['geom'] = affinity.skew(g['geom'], angle_x, angle_y,
origin=(px, py))
try:
g['geom'] = affinity.skew(g['geom'], angle_x, angle_y, origin=(px, py))
except AttributeError:
return g['geom']
self.create_geometry()
def rotate(self, angle, point):
@ -7261,8 +7316,10 @@ class CNCjob(Geometry):
px, py = point
for g in self.gcode_parsed:
g['geom'] = affinity.rotate(g['geom'], angle, origin=(px, py))
try:
g['geom'] = affinity.rotate(g['geom'], angle, origin=(px, py))
except AttributeError:
return g['geom']
self.create_geometry()

View File

@ -1,3 +1,11 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 8/17/2019 #
# MIT Licence #
# ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, QSettings
@ -1945,6 +1953,11 @@ class FlatCAMExcEditor(QtCore.QObject):
# this var will store the state of the toolbar before starting the editor
self.toolbar_old_state = False
if self.units == 'MM':
self.tolerance = float(self.app.defaults["global_tolerance"])
else:
self.tolerance = float(self.app.defaults["global_tolerance"]) / 20
self.app.ui.delete_drill_btn.triggered.connect(self.on_delete_btn)
self.name_entry.returnPressed.connect(self.on_name_activate)
self.addtool_btn.clicked.connect(self.on_tool_add)
@ -2048,6 +2061,7 @@ class FlatCAMExcEditor(QtCore.QObject):
# store the status of the editor so the Delete at object level will not work until the edit is finished
self.editor_active = False
log.debug("Initialization of the FlatCAM Excellon Editor is finished ...")
def pool_recreated(self, pool):
self.shapes.pool = pool
@ -3727,7 +3741,7 @@ class FlatCAMExcEditor(QtCore.QObject):
plot_elements += self.plot_shape(geometry=geometry.interiors, color=color, linewidth=linewidth)
if type(geometry) == LineString or type(geometry) == LinearRing:
plot_elements.append(self.shapes.add(shape=geometry, color=color, layer=0))
plot_elements.append(self.shapes.add(shape=geometry, color=color, layer=0, tolerance=self.tolerance))
if type(geometry) == Point:
pass

View File

@ -3118,6 +3118,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# store the status of the editor so the Delete at object level will not work until the edit is finished
self.editor_active = False
log.debug("Initialization of the FlatCAM Geometry Editor is finished ...")
def pool_recreated(self, pool):
self.shapes.pool = pool
@ -3174,6 +3175,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# Tell the App that the editor is active
self.editor_active = True
log.debug("Finished activating the Geometry Editor...")
def deactivate(self):
try:
@ -3253,6 +3255,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
# Show original geometry
if self.fcgeometry:
self.fcgeometry.visible = True
log.debug("Finished deactivating the Geometry Editor...")
def connect_canvas_event_handlers(self):
# Canvas events

View File

@ -1,3 +1,11 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 8/17/2019 #
# MIT Licence #
# ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, QSettings
@ -839,6 +847,8 @@ class FCRegion(FCShapeTool):
self.name = 'region'
self.draw_app = draw_app
self.steps_per_circle = self.draw_app.app.defaults["gerber_circle_steps"]
size_ap = float(self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['size'])
self.buf_val = (size_ap / 2) if size_ap > 0 else 0.0000001
@ -885,7 +895,7 @@ class FCRegion(FCShapeTool):
y = data[1]
if len(self.points) == 0:
new_geo_el['solid'] = Point(data).buffer(self.buf_val)
new_geo_el['solid'] = Point(data).buffer(self.buf_val, resolution=int(self.steps_per_circle / 4))
return DrawToolUtilityShape(new_geo_el)
if len(self.points) == 1:
@ -951,12 +961,15 @@ class FCRegion(FCShapeTool):
if len(self.temp_points) > 1:
try:
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val, join_style=1)
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4),
join_style=1)
return DrawToolUtilityShape(new_geo_el)
except Exception as e:
log.debug("FlatCAMGrbEditor.FCRegion.utility_geometry() --> %s" % str(e))
else:
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val)
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
return DrawToolUtilityShape(new_geo_el)
if len(self.points) > 2:
@ -1012,7 +1025,9 @@ class FCRegion(FCShapeTool):
self.temp_points.append(data)
new_geo_el = dict()
new_geo_el['solid'] = LinearRing(self.temp_points).buffer(self.buf_val, join_style=1)
new_geo_el['solid'] = LinearRing(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4),
join_style=1)
new_geo_el['follow'] = LinearRing(self.temp_points)
return DrawToolUtilityShape(new_geo_el)
@ -1031,7 +1046,9 @@ class FCRegion(FCShapeTool):
new_geo_el = dict()
new_geo_el['solid'] = Polygon(self.points).buffer(self.buf_val, join_style=2)
new_geo_el['solid'] = Polygon(self.points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4),
join_style=2)
new_geo_el['follow'] = Polygon(self.points).exterior
self.geometry = DrawToolShape(new_geo_el)
@ -1128,10 +1145,12 @@ class FCTrack(FCRegion):
def make(self):
new_geo_el = dict()
if len(self.temp_points) == 1:
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val)
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
new_geo_el['follow'] = Point(self.temp_points)
else:
new_geo_el['solid'] = (LineString(self.temp_points).buffer(self.buf_val)).buffer(0)
new_geo_el['solid'] = (LineString(self.temp_points).buffer(
self.buf_val, resolution=int(self.steps_per_circle / 4))).buffer(0)
new_geo_el['follow'] = LineString(self.temp_points)
self.geometry = DrawToolShape(new_geo_el)
@ -1156,10 +1175,12 @@ class FCTrack(FCRegion):
new_geo_el = dict()
if len(self.temp_points) == 1:
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val)
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
new_geo_el['follow'] = Point(self.temp_points)
else:
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val)
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
new_geo_el['follow'] = LineString(self.temp_points)
self.draw_app.add_gerber_shape(DrawToolShape(new_geo_el),
@ -1177,7 +1198,8 @@ class FCTrack(FCRegion):
new_geo_el = dict()
if len(self.points) == 0:
new_geo_el['solid'] = Point(data).buffer(self.buf_val)
new_geo_el['solid'] = Point(data).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
return DrawToolUtilityShape(new_geo_el)
elif len(self.points) > 0:
@ -1235,10 +1257,12 @@ class FCTrack(FCRegion):
self.temp_points.append(data)
if len(self.temp_points) == 1:
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val)
new_geo_el['solid'] = Point(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
return DrawToolUtilityShape(new_geo_el)
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val)
new_geo_el['solid'] = LineString(self.temp_points).buffer(self.buf_val,
resolution=int(self.steps_per_circle / 4))
return DrawToolUtilityShape(new_geo_el)
def on_key(self, key):
@ -2802,6 +2826,11 @@ class FlatCAMGrbEditor(QtCore.QObject):
# this will flag if the Editor "tools" are launched from key shortcuts (True) or from menu toolbar (False)
self.launched_from_shortcuts = False
if self.units == 'MM':
self.tolerance = float(self.app.defaults["global_tolerance"])
else:
self.tolerance = float(self.app.defaults["global_tolerance"]) / 20
def make_callback(the_tool):
def f():
self.on_tool_select(the_tool)
@ -2887,6 +2916,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.conversion_factor = 1
self.set_ui()
log.debug("Initialization of the FlatCAM Gerber Editor is finished ...")
def pool_recreated(self, pool):
self.shapes.pool = pool
@ -4372,11 +4402,11 @@ class FlatCAMGrbEditor(QtCore.QObject):
geometry = self.active_tool.geometry
try:
self.shapes.add(shape=geometry.geo, color=color, face_color=color, layer=0)
self.shapes.add(shape=geometry.geo, color=color, face_color=color, layer=0, tolerance=self.tolerance)
except AttributeError:
if type(geometry) == Point:
return
self.shapes.add(shape=geometry, color=color, face_color=color+'AF', layer=0)
self.shapes.add(shape=geometry, color=color, face_color=color+'AF', layer=0, tolerance=self.tolerance)
def start_delayed_plot(self, check_period):
"""

View File

@ -1,10 +1,10 @@
# ########################################################## ##
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
# ########################################################## ##
# ##########################################################
from shapely.geometry import LineString
import logging