From f1107fbd3be9cc8a0ef57e4bce9e66909a792616 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Fri, 6 Nov 2020 05:17:12 +0200 Subject: [PATCH] - in Gerber Editor made the selection multithreaded in a bid to get more performance but until Shapely will start working on vectorized geometry this don't yield too much improvement --- CHANGELOG.md | 4 ++ appEditors/AppGerberEditor.py | 127 ++++++++++++++++++++-------------- make_freezed.py | 120 ++++++++++++++++++++++++++++++++ 3 files changed, 199 insertions(+), 52 deletions(-) create mode 100644 make_freezed.py diff --git a/CHANGELOG.md b/CHANGELOG.md index d51d50aa..99214fa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ CHANGELOG for FlatCAM beta ================================================= +6.11.2020 + +- in Gerber Editor made the selection multithreaded in a bid to get more performance but until Shapely will start working on vectorized geometry this don't yield too much improvement + 5.11.2020 - fixed the annotation plotting in the CNCJob object diff --git a/appEditors/AppGerberEditor.py b/appEditors/AppGerberEditor.py index c6181a8e..9cadfafb 100644 --- a/appEditors/AppGerberEditor.py +++ b/appEditors/AppGerberEditor.py @@ -2397,9 +2397,12 @@ class EraserEditorGrb(ShapeToolEditorGrb): return DrawToolUtilityShape(geo_list) -class SelectEditorGrb(DrawTool): +class SelectEditorGrb(QtCore.QObject, DrawTool): + selection_triggered = QtCore.pyqtSignal(object) + def __init__(self, draw_app): - DrawTool.__init__(self, draw_app) + super().__init__(draw_app=draw_app) + # DrawTool.__init__(self, draw_app) self.name = 'select' self.origin = None @@ -2417,6 +2420,9 @@ class SelectEditorGrb(DrawTool): # here store the selected apertures self.sel_aperture = [] + # multiprocessing results + self.results = [] + try: self.draw_app.ui.apertures_table.clearSelection() except Exception as e: @@ -2432,16 +2438,16 @@ class SelectEditorGrb(DrawTool): log.debug("AppGerberEditor.SelectEditorGrb --> %s" % str(e)) try: - self.draw_app.selection_triggered.disconnect() + self.selection_triggered.disconnect() except (TypeError, AttributeError): pass - self.draw_app.selection_triggered.connect(self.selection_worker) + self.selection_triggered.connect(self.selection_worker) try: self.draw_app.plot_object.disconnect() except (TypeError, AttributeError): pass - self.draw_app.plot_object.connect(self.clean_up) + self.draw_app.plot_object.connect(self.after_selection) def set_origin(self, origin): self.origin = origin @@ -2476,64 +2482,82 @@ class SelectEditorGrb(DrawTool): self.draw_app.selected.clear() self.sel_aperture.clear() - self.draw_app.selection_triggered.emit(point) + self.selection_triggered.emit(point) def selection_worker(self, point): def job_thread(editor_obj): + self.results = [] with editor_obj.app.proc_container.new('%s' % _("Working ...")): - brake_flag = False - for storage_key, storage_val in editor_obj.storage_dict.items(): - for shape_stored in storage_val['geometry']: - if 'solid' in shape_stored.geo: - geometric_data = shape_stored.geo['solid'] - if Point(point).intersects(geometric_data): - if shape_stored in editor_obj.selected: - editor_obj.selected.remove(shape_stored) - else: - # add the object to the selected shapes - editor_obj.selected.append(shape_stored) - brake_flag = True - break - if brake_flag is True: - break + for ap_key, storage_val in editor_obj.storage_dict.items(): + self.results.append( + editor_obj.pool.apply_async(self.check_intersection, args=(ap_key, storage_val, point)) + ) - # ###################################################################################################### - # select the aperture in the Apertures Table that is associated with the selected shape - # ###################################################################################################### - self.sel_aperture.clear() - editor_obj.ui.apertures_table.clearSelection() + output = [] + for p in self.results: + output.append(p.get()) - # disconnect signal when clicking in the table - try: - editor_obj.ui.apertures_table.cellPressed.disconnect() - except Exception as e: - log.debug("AppGerberEditor.SelectEditorGrb.click_release() --> %s" % str(e)) + for ret_val in output: + if ret_val: + k = ret_val[0] + idx = ret_val[1] + shape_stored = editor_obj.storage_dict[k]['geometry'][idx] - brake_flag = False - for shape_s in editor_obj.selected: - for storage in editor_obj.storage_dict: - if shape_s in editor_obj.storage_dict[storage]['geometry']: - self.sel_aperture.append(storage) - brake_flag = True - break - if brake_flag is True: - break - - # actual row selection is done here - for aper in self.sel_aperture: - for row in range(editor_obj.ui.apertures_table.rowCount()): - if str(aper) == editor_obj.ui.apertures_table.item(row, 1).text(): - if not editor_obj.ui.apertures_table.item(row, 0).isSelected(): - editor_obj.ui.apertures_table.selectRow(row) - editor_obj.last_aperture_selected = aper - - # reconnect signal when clicking in the table - editor_obj.ui.apertures_table.cellPressed.connect(editor_obj.on_row_selected) + if shape_stored in editor_obj.selected: + editor_obj.selected.remove(shape_stored) + else: + # add the object to the selected shapes + editor_obj.selected.append(shape_stored) editor_obj.plot_object.emit(None) self.draw_app.app.worker_task.emit({'fcn': job_thread, 'params': [self.draw_app]}) + @staticmethod + def check_intersection(ap_key, ap_storage, point): + for idx, shape_stored in enumerate(ap_storage['geometry']): + if 'solid' in shape_stored.geo: + geometric_data = shape_stored.geo['solid'] + if Point(point).intersects(geometric_data): + return ap_key, idx + + def after_selection(self): + # ###################################################################################################### + # select the aperture in the Apertures Table that is associated with the selected shape + # ###################################################################################################### + self.sel_aperture.clear() + self.draw_app.ui.apertures_table.clearSelection() + + # disconnect signal when clicking in the table + try: + self.draw_app.ui.apertures_table.cellPressed.disconnect() + except Exception as e: + log.debug("AppGerberEditor.SelectEditorGrb.click_release() --> %s" % str(e)) + + brake_flag = False + for shape_s in self.draw_app.selected: + for storage in self.draw_app.storage_dict: + if shape_s in self.draw_app.storage_dict[storage]['geometry']: + self.sel_aperture.append(storage) + brake_flag = True + break + if brake_flag is True: + break + + # actual row selection is done here + for aper in self.sel_aperture: + for row in range(self.draw_app.ui.apertures_table.rowCount()): + if str(aper) == self.draw_app.ui.apertures_table.item(row, 1).text(): + if not self.draw_app.ui.apertures_table.item(row, 0).isSelected(): + self.draw_app.ui.apertures_table.selectRow(row) + self.draw_app.last_aperture_selected = aper + + # reconnect signal when clicking in the table + self.draw_app.ui.apertures_table.cellPressed.connect(self.draw_app.on_row_selected) + + # and plot all + self.draw_app.plot_all() + def clean_up(self): self.draw_app.plot_all() @@ -2563,7 +2587,6 @@ class AppGerberEditor(QtCore.QObject): # plot_finished = QtCore.pyqtSignal() mp_finished = QtCore.pyqtSignal(list) - selection_triggered = QtCore.pyqtSignal(object) plot_object = QtCore.pyqtSignal(object) def __init__(self, app): diff --git a/make_freezed.py b/make_freezed.py new file mode 100644 index 00000000..f2686fde --- /dev/null +++ b/make_freezed.py @@ -0,0 +1,120 @@ +# ########################################################## +# FlatCAM: 2D Post-processing for Manufacturing # +# http://flatcam.org # +# Author: Juan Pablo Caram (c) # +# Date: 12/20/2018 # +# MIT Licence # +# # +# Creates a portable copy of FlatCAM, including Python # +# itself and all dependencies. # +# # +# This is not an aid to install FlatCAM from source on # +# Windows platforms. It is only useful when FlatCAM is up # +# and running and ready to be packaged. # +# ########################################################## + +# ########################################################## +# File Modified: Marius Adrian Stanciu # +# Date: 3/10/2019 # +# ########################################################## + + +# Files not needed: Qt, tk.dll, tcl.dll, tk/, tcl/, vtk/, +# scipy.lib.lapack.flapack.pyd, scipy.lib.blas.fblas.pyd, +# numpy.core._dotblas.pyd, scipy.sparse.sparsetools._bsr.pyd, +# scipy.sparse.sparsetools._csr.pyd, scipy.sparse.sparsetools._csc.pyd, +# scipy.sparse.sparsetools._coo.pyd + +import os +import site +import sys +import platform +from cx_Freeze import setup, Executable + +# this is done to solve the tkinter not being found +PYTHON_INSTALL_DIR = os.path.dirname(os.path.dirname(os.__file__)) +os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6') +os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6') + +# Get the site-package folder, not everybody will install +# Python into C:\PythonXX +site_dir = site.getsitepackages()[1] + +include_files = [] + +include_files.append((os.path.join(site_dir, "shapely"), "shapely")) +include_files.append((os.path.join(site_dir, "svg"), "svg")) +include_files.append((os.path.join(site_dir, "svg/path"), "svg")) +include_files.append((os.path.join(site_dir, "vispy"), "vispy")) +include_files.append((os.path.join(site_dir, "vispy/app"), "vispy/app")) +include_files.append((os.path.join(site_dir, "vispy/app/backends"), "vispy/app/backends")) +# include_files.append((os.path.join(site_dir, "matplotlib"), "matplotlib")) +include_files.append((os.path.join(site_dir, "rtree"), "rtree")) + +if platform.architecture()[0] == '64bit': + include_files.append((os.path.join(site_dir, "google"), "google")) + include_files.append((os.path.join(site_dir, "google/protobuf"), "google/protobuf")) + include_files.append((os.path.join(site_dir, "ortools"), "ortools")) + +include_files.append(("locale", "lib/locale")) +include_files.append(("preprocessors", "lib/preprocessors")) +# include_files.append(("assets", "lib/assets")) +include_files.append(("assets/examples", "lib/assets/examples")) +include_files.append(("assets/linux", "lib/assets/linux")) +include_files.append(("assets/resources", "lib/assets/resources")) +# include_files.append(("share", "lib/share")) +include_files.append(("appGUI/VisPyData", "lib/vispy")) +include_files.append(("config", "lib/config")) + +include_files.append(("README.md", "README.md")) +include_files.append(("LICENSE", "LICENSE")) +include_files.append(("CHANGELOG.md", "CHANGELOG.md")) +base = None + +# Lets not open the console while running the app +if sys.platform == "win32": + base = "Win32GUI" + +if platform.architecture()[0] == '64bit': + buildOptions = dict( + include_files=include_files, + excludes=['scipy', 'pytz', "matplotlib.tests", "numpy.random._examples"], + # packages=['OpenGL','numpy','vispy','ortools','google'] + # packages=['numpy','google', 'rasterio'] # works for Python 3.7 + packages=['opengl', 'numpy', 'google', 'rasterio'], # works for Python 3.6.5 and Python 3.7.1 + ) +else: + buildOptions = dict( + include_files=include_files, + excludes=['scipy', 'pytz'], + # packages=['OpenGL','numpy','vispy','ortools','google'] + # packages=['numpy', 'rasterio'] # works for Python 3.7 + packages=['opengl', 'numpy', 'rasterio'], # works for Python 3.6.5 and Python 3.7.1 + ) + +if sys.platform == "win32": + buildOptions["include_msvcr"] = True + +print("INCLUDE_FILES", include_files) + + +def getTargetName(): + my_OS = platform.system() + if my_OS == 'Linux': + return "FlatCAM" + elif my_OS == 'Windows': + return "FlatCAM.exe" + else: + return "FlatCAM.dmg" + + +exe = Executable("FlatCAM.py", icon='assets/resources/flatcam_icon48.ico', base=base, targetName=getTargetName()) + +setup( + name="FlatCAM", + author="Community effort", + version="8.9", + description="FlatCAM Evo: 2D Computer Aided PCB Manufacturing", + options=dict(build_exe=buildOptions), + executables=[exe] +)