Merged in marius_stanciu/flatcam_beta/Beta (pull request #300)

Beta 8.992
This commit is contained in:
Marius Stanciu 2020-04-27 09:40:56 +00:00
commit bea3fbe488
76 changed files with 48494 additions and 25302 deletions

View File

@ -7,11 +7,28 @@ CHANGELOG for FlatCAM beta
================================================= =================================================
27.04.2020
- finished the moving of all Tcl Shell stuff out of the FlatCAAMApp class to flatcamTools.ToolShell class
- updated the requirements.txt file to request that the Shapely package needs to be at least version 1.7.0 as it is needed in the latest versions of FlatCAM beta
- some TOOD cleanups
- minor changes
- replaced the testing if instance of FlatCAMObj with testing the obj.kind attribute
- removed the import of the whole FlatCAMApp file only for the usage of GracefulException
- remove the import of FlatCAMApp and used alternate ways
- optimized the imports in some files
- moved the Bookmarksmanager and ToolDB classes into their own files
- solved some bugs that were not so visible in the Editors and HPGL parser
- split the FlatCAMObj file into multiple files located in the flatcamObjects folder and renamed the contained classes with names more suggestive
- updated the Google Translation for the German language
- added support for Hungarian language - no translation for now
25.04.2020 25.04.2020
- ensured that on Graceful Exit (CTRL+ALT+X key combo) if using Progressive Plotting, the eventual residual plotted lines are deleted. This apply for Tool NCC and Tool Paint - ensured that on Graceful Exit (CTRL+ALT+X key combo) if using Progressive Plotting, the eventual residual plotted lines are deleted. This apply for Tool NCC and Tool Paint
- fixed links in Attributions tab in Help -> About FlatCAM to be able to open external links. - fixed links in Attributions tab in Help -> About FlatCAM to be able to open external links.
- updated Google Translations for French and Spanish languages - updated Google Translations for French and Spanish languages
- added some '\n' chars in the Help Tcl command to make the help more readable
24.04.2020 24.04.2020
@ -282,7 +299,7 @@ CHANGELOG for FlatCAM beta
12.02.2020 12.02.2020
- working on fixing a bug in FlatCAMGeometry.merge() - FIXED issue #380 - working on fixing a bug in GeometryObject.merge() - FIXED issue #380
- fixed bug: when deleting a FlatCAMCNCJob with annotations enabled, the annotations are not deleted from canvas; fixed issue #379 - fixed bug: when deleting a FlatCAMCNCJob with annotations enabled, the annotations are not deleted from canvas; fixed issue #379
- fixed bug: creating a new project while a project is open and it contain CNCJob annotations and/or Gerber mark shapes, did not delete them from canvas - fixed bug: creating a new project while a project is open and it contain CNCJob annotations and/or Gerber mark shapes, did not delete them from canvas
@ -637,7 +654,7 @@ CHANGELOG for FlatCAM beta
- modified the Jump To method such that now allows relative jump from the current mouse location - modified the Jump To method such that now allows relative jump from the current mouse location
- fixed the Defaults upgrade overwriting the new version number with the old one - fixed the Defaults upgrade overwriting the new version number with the old one
- fixed issue with clear_polygon3() - the one who makes 'lines' and fixed the NCC Tool - fixed issue with clear_polygon3() - the one who makes 'lines' and fixed the NCC Tool
- some small changes in the FlatCAMGeometry.on_tool_add() method - some small changes in the GeometryObject.on_tool_add() method
- made sure that in Geometry Editor the self.app.mouse attribute is updated with the current mouse position (x, y) - made sure that in Geometry Editor the self.app.mouse attribute is updated with the current mouse position (x, y)
- updated the preprocessor files - updated the preprocessor files
- fixed the HPGL preprocessor - fixed the HPGL preprocessor
@ -680,7 +697,7 @@ CHANGELOG for FlatCAM beta
- changed the Scale Entry in Object UI to FCEntry() GUI element in order to allow expressions to be entered. E.g: 1/25.4 - changed the Scale Entry in Object UI to FCEntry() GUI element in order to allow expressions to be entered. E.g: 1/25.4
- some small changes in the Scale button handler in FlatCAMObj() class - some small changes in the Scale button handler in FlatCAMObj() class
- added option to save objects as PDF files in File -> Save menu - added option to save objects as PDF files in File -> Save menu
- optimized the FlatCAMGerber.clear_plot_apertures() method - optimized the GerberObject.clear_plot_apertures() method
- some changes in the ObjectUI and for the Geometry UI - some changes in the ObjectUI and for the Geometry UI
- finished a very rough and limited HPGL2 file import - finished a very rough and limited HPGL2 file import
@ -710,7 +727,7 @@ CHANGELOG for FlatCAM beta
- reverted this change: "selected object in Project used to ask twice for UI build" because it will not build the UI when a tab is closed for Document object and the object is selected - reverted this change: "selected object in Project used to ask twice for UI build" because it will not build the UI when a tab is closed for Document object and the object is selected
- fixed issue after Geometry object edit; the GCode made from an edited object did not reflect the changes in the object - fixed issue after Geometry object edit; the GCode made from an edited object did not reflect the changes in the object
- in Object UI, the Scale FCDoubleSpinner will no longer work for Return key press due of issues of unwanted scaling on focusOut event - in Object UI, the Scale FCDoubleSpinner will no longer work for Return key press due of issues of unwanted scaling on focusOut event
- in FlatCAMGeometry fixed the scale and offset methods to always process the self.solid_geometry - in GeometryObject fixed the scale and offset methods to always process the self.solid_geometry
- Calibration Tool - finished the calibrated object creation method - Calibration Tool - finished the calibrated object creation method
- updated the POT file - updated the POT file
- fixed an error in the German PO file - fixed an error in the German PO file
@ -801,7 +818,7 @@ CHANGELOG for FlatCAM beta
28.11.2019 28.11.2019
- small fixes in NCC Tool and in the FlatCAMGeometry class - small fixes in NCC Tool and in the GeometryObject class
27.11.2019 27.11.2019
@ -819,7 +836,7 @@ CHANGELOG for FlatCAM beta
- In Gerber isolation changed the UI - In Gerber isolation changed the UI
- in Gerber isolation added the option to selectively isolate only certain polygons - in Gerber isolation added the option to selectively isolate only certain polygons
- made some optimizations in FlatCAMGerber.isolate() method - made some optimizations in GerberObject.isolate() method
- updated the 'single' isolation of Gerber polygons to remove the polygon if clicked on it and it is already in the list of single polygons to be isolated - updated the 'single' isolation of Gerber polygons to remove the polygon if clicked on it and it is already in the list of single polygons to be isolated
- clicking to add a polygon when doing Single type isolation will add a blue shape marking the selected polygon, second click will remove that shape - clicking to add a polygon when doing Single type isolation will add a blue shape marking the selected polygon, second click will remove that shape
- fixed bugs in Paint Tool when painting single polygon - fixed bugs in Paint Tool when painting single polygon
@ -830,7 +847,7 @@ CHANGELOG for FlatCAM beta
- in Tool Fiducials added a new fiducial type: chess pattern - in Tool Fiducials added a new fiducial type: chess pattern
- work in Calibrate Excellon Tool - work in Calibrate Excellon Tool
- fixed the line numbers in the TextPlainEdit to fit all digits of the line number; activated the line numbers for FlatCAMScript objects too - fixed the line numbers in the TextPlainEdit to fit all digits of the line number; activated the line numbers for ScriptObject objects too
- line numbers in the TextPlainEdit for the selected line are bold - line numbers in the TextPlainEdit for the selected line are bold
- made sure that the self.defaults dictionary is deepcopy-ed in the self.options dictionary - made sure that the self.defaults dictionary is deepcopy-ed in the self.options dictionary
- made sure that the units are read from the self.defaults and not from the GUI - made sure that the units are read from the self.defaults and not from the GUI
@ -842,7 +859,7 @@ CHANGELOG for FlatCAM beta
- Tool Fiducials - updated the source_file object for the modified Gerber files - Tool Fiducials - updated the source_file object for the modified Gerber files
- working on adding line numbers to the TextPlainEdit - working on adding line numbers to the TextPlainEdit
- GCode view now has line numbers - GCode view now has line numbers
- solved a bug that made selection of objects on canvas impossible if there is an object of type FlatCAMScript or FlatCAMDocument opened - solved a bug that made selection of objects on canvas impossible if there is an object of type ScriptObject or DocumentObject opened
21.11.2019 21.11.2019
@ -899,7 +916,7 @@ CHANGELOG for FlatCAM beta
- trying to improve the performance of View CNC Code command by using QPlainTextEdit; made the mods for it - trying to improve the performance of View CNC Code command by using QPlainTextEdit; made the mods for it
- when using the Find function in the TextEditor and the result reach the bottom of the document, the next find will be the first in the document (before it defaulted to the beginning of the document) - when using the Find function in the TextEditor and the result reach the bottom of the document, the next find will be the first in the document (before it defaulted to the beginning of the document)
- finished improving the show of text files in FlatCAM (CNC Code, Source files) - finished improving the show of text files in FlatCAM (CNC Code, Source files)
- fixed an issue in the FlatCAMObj.FlatCAMGerber.convert_units() which needed to be updated after changes elsewhere - fixed an issue in the FlatCAMObj.GerberObject.convert_units() which needed to be updated after changes elsewhere
12.11.2019 12.11.2019
@ -937,7 +954,7 @@ CHANGELOG for FlatCAM beta
- the "CRTL+S" key combo when the Preferences Tab is in focus will save the Preferences instead of saving the Project - the "CRTL+S" key combo when the Preferences Tab is in focus will save the Preferences instead of saving the Project
- fixed bug in the Paint Tool that did not allow choosing a Paint Method that was not Standard - fixed bug in the Paint Tool that did not allow choosing a Paint Method that was not Standard
- made sure that in the FlatCAMGeometry.merge() all the source data is deepcopy-ed in the final object - made sure that in the GeometryObject.merge() all the source data is deepcopy-ed in the final object
- the font color of the Preferences tab will change to red if settings are not saved and it will revert to default when saved - the font color of the Preferences tab will change to red if settings are not saved and it will revert to default when saved
- fixed issue #333. The Geometry Editor Paint tool was not working and using it resulted in an error - fixed issue #333. The Geometry Editor Paint tool was not working and using it resulted in an error
@ -1149,7 +1166,7 @@ CHANGELOG for FlatCAM beta
- added a dark theme to FlatCAM (only for canvas). The selection is done in Edit -> Preferences -> General -> GUI Settings - added a dark theme to FlatCAM (only for canvas). The selection is done in Edit -> Preferences -> General -> GUI Settings
- updated the .POT file and worked a bit in the romanian translation - updated the .POT file and worked a bit in the romanian translation
- small changes: reduced the thickness of the axis in 3D mode from 3 pixels to 1 pixel - small changes: reduced the thickness of the axis in 3D mode from 3 pixels to 1 pixel
- made sure that is the text in the source file of a FlatCAMDocument is HTML is loaded as such - made sure that is the text in the source file of a DocumentObject is HTML is loaded as such
- added inverted icons - added inverted icons
6.10.2019 6.10.2019
@ -1193,20 +1210,20 @@ CHANGELOG for FlatCAM beta
3.10.2019 3.10.2019
- previously I've added the initial layout for the FlatCAMDocument object - previously I've added the initial layout for the DocumentObject object
- added more editing features in the Selected Tab for the FlatCAMDocument object - added more editing features in the Selected Tab for the DocumentObject object
2.10.2019 2.10.2019
- fixed bug in Geometry Editor that did not allow the copy of geometric elements - fixed bug in Geometry Editor that did not allow the copy of geometric elements
- created a new class that holds all the Code Editor functionality and integrated as a Editor in FlatCAM, the location is in flatcamEditors folder - created a new class that holds all the Code Editor functionality and integrated as a Editor in FlatCAM, the location is in flatcamEditors folder
- remade all the functions for view_source, scripts and view_code to use the new TextEditor class; now all the Code Editor tabs are being kept alive, before only one could be in an open state - remade all the functions for view_source, scripts and view_code to use the new TextEditor class; now all the Code Editor tabs are being kept alive, before only one could be in an open state
- changed the name of the new object FlatCAMNotes to a more general one FlatCAMDocument - changed the name of the new object FlatCAMNotes to a more general one DocumentObject
- changed the way a new FlatCAMScript object is made, the method that is processing the Tcl commands when the Run button is clicked is moved to the FlatCAMObj.FlatCAMScript() class - changed the way a new ScriptObject object is made, the method that is processing the Tcl commands when the Run button is clicked is moved to the FlatCAMObj.ScriptObject() class
- reused the Multiprocessing Pool declared in the App for the ToolRulesCheck() class - reused the Multiprocessing Pool declared in the App for the ToolRulesCheck() class
- adapted the Project context menu for the new types of FLatCAM objects - adapted the Project context menu for the new types of FLatCAM objects
- modified the setup_recent_files to accommodate the new FlatCAM objects - modified the setup_recent_files to accommodate the new FlatCAM objects
- made sure that when an FlatCAMScript object is deleted, it's associated Tab is closed - made sure that when an ScriptObject object is deleted, it's associated Tab is closed
- fixed the FlatCMAScript object saving when project is saved (loading a project with this script object is not working yet) - fixed the FlatCMAScript object saving when project is saved (loading a project with this script object is not working yet)
- fixed the FlatCMAScript object when loading it from a project - fixed the FlatCMAScript object when loading it from a project
@ -1220,7 +1237,7 @@ CHANGELOG for FlatCAM beta
- added new settings for the Gerber newly introduced feature to isolate with the V-Shape tools (tip dia, tip angle, tool_type and cut Z) in Edit -> Preferences -> Gerber Advanced - added new settings for the Gerber newly introduced feature to isolate with the V-Shape tools (tip dia, tip angle, tool_type and cut Z) in Edit -> Preferences -> Gerber Advanced
- made those settings just added for Gerber, to be updated on object creation - made those settings just added for Gerber, to be updated on object creation
- added the Geo Tolerance parameter to those that are converted from MM to INCH - added the Geo Tolerance parameter to those that are converted from MM to INCH
- added two new FlatCAM objects: FlatCAMScript and FlatCAMNotes - added two new FlatCAM objects: ScriptObject and FlatCAMNotes
30.09.2019 30.09.2019
@ -1443,7 +1460,7 @@ CHANGELOG for FlatCAM beta
15.09.2019 15.09.2019
- refactored FlatCAMGeometry.mtool_gen_cncjob() method - refactored GeometryObject.mtool_gen_cncjob() method
- fixed the TclCommandCncjob to work for multigeometry Geometry objects; still I had to fix the list of tools parameter, right now I am setting it to an empty list - fixed the TclCommandCncjob to work for multigeometry Geometry objects; still I had to fix the list of tools parameter, right now I am setting it to an empty list
- update the Tcl Command isolate to be able to isolate exteriors, interiors besides the full isolation, using the iso_type parameter - update the Tcl Command isolate to be able to isolate exteriors, interiors besides the full isolation, using the iso_type parameter
- fixed issue in ToolPaint that could not allow area painting of a geometry that was a list and not a Geometric element (polygon or MultiPolygon) - fixed issue in ToolPaint that could not allow area painting of a geometry that was a list and not a Geometric element (polygon or MultiPolygon)
@ -1819,7 +1836,7 @@ CHANGELOG for FlatCAM beta
- done regression to solve the bug with multiple passes cutting from the copper features (I should remember not to make mods here) - done regression to solve the bug with multiple passes cutting from the copper features (I should remember not to make mods here)
- if 'combine' is checked in Gerber isolation but there is only one pass, the resulting geometry will still be single geo - if 'combine' is checked in Gerber isolation but there is only one pass, the resulting geometry will still be single geo
- the 'passes' entry was changed to a IntSpinner so it will allow passes to be entered only in range (1, 999) - it will not allow entry of 0 which may create some issues - the 'passes' entry was changed to a IntSpinner so it will allow passes to be entered only in range (1, 999) - it will not allow entry of 0 which may create some issues
- improved the FlatCAMGerber.isolate() function to work for geometry in the form of list and also in case that the elements of the list are LinearRings (like when doing the Exterior Isolation) - improved the GerberObject.isolate() function to work for geometry in the form of list and also in case that the elements of the list are LinearRings (like when doing the Exterior Isolation)
- in NCC Tool made sure that at each run the old objects are deleted - in NCC Tool made sure that at each run the old objects are deleted
- fixed bug in camlib.Gerber.parse_lines() Gerber parser where for Allegro Gerber files the Gerber units were incorrectly detected - fixed bug in camlib.Gerber.parse_lines() Gerber parser where for Allegro Gerber files the Gerber units were incorrectly detected
- improved Mark Area Tool in Gerber Editor such that at each launch the previous markings are deleted - improved Mark Area Tool in Gerber Editor such that at each launch the previous markings are deleted
@ -1914,7 +1931,7 @@ CHANGELOG for FlatCAM beta
19.07.2019 19.07.2019
- fixed bug in FlatCAMObj.FlatCAMGeometry.ui_disconnect(); the widgets signals were not disconnected from handlers when required therefore the signals were connected in an exponential way - fixed bug in FlatCAMObj.GeometryObject.ui_disconnect(); the widgets signals were not disconnected from handlers when required therefore the signals were connected in an exponential way
- some changes in the widgets used in the Selected tab for Geometry object - some changes in the widgets used in the Selected tab for Geometry object
- some PEP8 cleanup in FlatCAMObj.py - some PEP8 cleanup in FlatCAMObj.py
- updated languages - updated languages
@ -2045,7 +2062,7 @@ CHANGELOG for FlatCAM beta
- fixed bug in ToolCutout where creating a cutout object geometry from another external isolation geometry failed - fixed bug in ToolCutout where creating a cutout object geometry from another external isolation geometry failed
- fixed bug in cncjob TclCommand where the gcode could not be correctly generated due of missing bounds params in obj.options dict - fixed bug in cncjob TclCommand where the gcode could not be correctly generated due of missing bounds params in obj.options dict
- fixed a hardcoded tolerance in FlatCAMGeometry.generatecncjob() and in FlatCAMGeometry.mtool_gen_cncjob() to use the parameter from Preferences - fixed a hardcoded tolerance in GeometryObject.generatecncjob() and in GeometryObject.mtool_gen_cncjob() to use the parameter from Preferences
- updated translations - updated translations
5.06.2019 5.06.2019
@ -2219,7 +2236,7 @@ CHANGELOG for FlatCAM beta
- fixed some bugs related to moving an Gerber object with the aperture table in view - fixed some bugs related to moving an Gerber object with the aperture table in view
- added a new parameter in the Edit -> Preferences -> App Preferences named Geo Tolerance. This parameter control the level of geometric detail throughout FlatCAM. It directly influence the effect of Circle Steps parameter. - added a new parameter in the Edit -> Preferences -> App Preferences named Geo Tolerance. This parameter control the level of geometric detail throughout FlatCAM. It directly influence the effect of Circle Steps parameter.
- solved a bug in Excellon Editor that caused app crash when trying to edit a tool in Tool Table due of missing a tool offset - solved a bug in Excellon Editor that caused app crash when trying to edit a tool in Tool Table due of missing a tool offset
- updated the ToolPanelize tool so the Gerber panel of type FlatCAMGerber can be isolated like any other FlatCAMGerber object - updated the ToolPanelize tool so the Gerber panel of type GerberObject can be isolated like any other GerberObject object
- updated the ToolPanelize tool so it can be edited - updated the ToolPanelize tool so it can be edited
- modified the default values for toolchangez and endz parameters so they are now safe in all cases - modified the default values for toolchangez and endz parameters so they are now safe in all cases
@ -2703,7 +2720,7 @@ CHANGELOG for FlatCAM beta
- added ability to mark individual apertures in Gerber file using the Gerber Aperture Table - added ability to mark individual apertures in Gerber file using the Gerber Aperture Table
- more modifications for the Gerber UI layout; made 'follow' an advanced Gerber option - more modifications for the Gerber UI layout; made 'follow' an advanced Gerber option
- added in Preferences a new Category: Gerber Advanced Options. For now it controls the display of Gerber Aperture Table and the "follow" attribute4 - added in Preferences a new Category: Gerber Advanced Options. For now it controls the display of Gerber Aperture Table and the "follow" attribute4
- fixed FlatCAMGerber.merge() to merge the self.apertures[ap]['solid_geometry'] too - fixed GerberObject.merge() to merge the self.apertures[ap]['solid_geometry'] too
- started to work on a new feature that allow adding a ToolChange GCode macro - GUI added both in CNCJob Selected tab and in CNCJob Preferences - started to work on a new feature that allow adding a ToolChange GCode macro - GUI added both in CNCJob Selected tab and in CNCJob Preferences
- added a limited 'sort-of' Gerber Editor: it allows buffering and scaling of apertures - added a limited 'sort-of' Gerber Editor: it allows buffering and scaling of apertures
@ -2846,7 +2863,7 @@ CHANGELOG for FlatCAM beta
- added total travel distance for CNCJob object created from Excellon Object in the CNCJob Selected tab - added total travel distance for CNCJob object created from Excellon Object in the CNCJob Selected tab
- added 'FlatCAM ' prefix to any detached tab, for easy identification - added 'FlatCAM ' prefix to any detached tab, for easy identification
- remade the Grids context menu (right mouse button click on canvas). Now it has values linked to the units type (inch or mm). Added ability to add or delete grid values and they are persistent. - remade the Grids context menu (right mouse button click on canvas). Now it has values linked to the units type (inch or mm). Added ability to add or delete grid values and they are persistent.
- updated the function for the project context menu 'Generate CNC' menu entry (Action) to use the modernized function FlatCAMObj.FlatCAMGeometry.on_generatecnc_button_click() - updated the function for the project context menu 'Generate CNC' menu entry (Action) to use the modernized function FlatCAMObj.GeometryObject.on_generatecnc_button_click()
- when linked, the grid snap on Y will copy the value in grid snap on X in real time - when linked, the grid snap on Y will copy the value in grid snap on X in real time
- in Gerber aperture table now the values are displayed in the current units set in FlatCAM - in Gerber aperture table now the values are displayed in the current units set in FlatCAM
- added shortcut key 'J' (jump to location) in Editors and added an icon to the dialog popup window - added shortcut key 'J' (jump to location) in Editors and added an icon to the dialog popup window
@ -2863,7 +2880,7 @@ CHANGELOG for FlatCAM beta
- finished Gerber aperture table display - finished Gerber aperture table display
- made the Gerber aperture table not visible as default and added a checkbox that can toggle the visibility - made the Gerber aperture table not visible as default and added a checkbox that can toggle the visibility
- fixed issue with plotting in CNCJob; with Plot kind set to something else than 'all' when toggling Plot, it was defaulting to kind = 'all' - fixed issue with plotting in CNCJob; with Plot kind set to something else than 'all' when toggling Plot, it was defaulting to kind = 'all'
- added (and commented) an experimental FlatCAMObj.FlatCAMGerber.plot_aperture() - added (and commented) an experimental FlatCAMObj.GerberObject.plot_aperture()
12.02.2019 12.02.2019
@ -3052,7 +3069,7 @@ CHANGELOG for FlatCAM beta
28.01.2018 28.01.2018
- fixed the FlatCAMGerber.merge() function - fixed the GerberObject.merge() function
- added a new menu entry for the Gerber Join function: Edit -> Conversions -> "Join Gerber(s) to Gerber" allowing joining Gerber objects into a final Gerber object - added a new menu entry for the Gerber Join function: Edit -> Conversions -> "Join Gerber(s) to Gerber" allowing joining Gerber objects into a final Gerber object
- moved Paint Tool defaults from Geometry section to the Tools section in Edit -> Preferences - moved Paint Tool defaults from Geometry section to the Tools section in Edit -> Preferences
- added key shortcuts for Open Manual = F1 and for Open Online VideoHelp = F2 - added key shortcuts for Open Manual = F1 and for Open Online VideoHelp = F2
@ -3075,13 +3092,13 @@ CHANGELOG for FlatCAM beta
- added new entries to the Canvas context menu (Copy, Delete, Edit/Save, Move, New Excellon, New Geometry, New Project) - added new entries to the Canvas context menu (Copy, Delete, Edit/Save, Move, New Excellon, New Geometry, New Project)
- fixed GRBL_laser preprocessor file - fixed GRBL_laser preprocessor file
- updated function for copy of an Excellon object for the case when the object has slots - updated function for copy of an Excellon object for the case when the object has slots
- updated FlatCAMExcellon.merge() function to work in case some (or all) of the merged objects have slots - updated ExcellonObject.merge() function to work in case some (or all) of the merged objects have slots
25.01.2019 25.01.2019
- deleted junk folders - deleted junk folders
- remade the Panelize Tool: now it is much faster, it is multi-threaded, it works with multitool geometries and it works with multigeo geometries too. - remade the Panelize Tool: now it is much faster, it is multi-threaded, it works with multitool geometries and it works with multigeo geometries too.
- made sure to copy the options attribute to the final object in the case of: FlatCAMGeometry.merge(), FlatCAMGerber.merge() and for the Panelize Tool - made sure to copy the options attribute to the final object in the case of: GeometryObject.merge(), GerberObject.merge() and for the Panelize Tool
- modified the panelize TclCommand to take advantage of the new panelize() function; added a 'threaded' parameter (default value is 1) which controls the execution of the panelize TclCommand: threaded or non-threaded - modified the panelize TclCommand to take advantage of the new panelize() function; added a 'threaded' parameter (default value is 1) which controls the execution of the panelize TclCommand: threaded or non-threaded
- fixed TclCommand Cutout - fixed TclCommand Cutout
- added a new TclCommand named CutoutAny. Keyword: cutout_any - added a new TclCommand named CutoutAny. Keyword: cutout_any
@ -3164,7 +3181,7 @@ CHANGELOG for FlatCAM beta
- fixed the initial text in the ToolShell - fixed the initial text in the ToolShell
- reactivated the version check in case the release is not BETA; FlatCAMApp.App has now a beta object that when set True the application will show in the Title and help-> About that is Beta (and it disable version checking) - reactivated the version check in case the release is not BETA; FlatCAMApp.App has now a beta object that when set True the application will show in the Title and help-> About that is Beta (and it disable version checking)
- added a new name (mine: for good and/or bad) to the contributors list - added a new name (mine: for good and/or bad) to the contributors list
- fixed the Join function to work on Gerber and Excellon, Gerber and Gerber, Excellon and Excelon combination of objects. The merged property is the solid_geometry and the result is a FlatCAMGeometry object. - fixed the Join function to work on Gerber and Excellon, Gerber and Gerber, Excellon and Excelon combination of objects. The merged property is the solid_geometry and the result is a GeometryObject object.
3.01.2019 3.01.2019
@ -3246,8 +3263,8 @@ CHANGELOG for FlatCAM beta
18.12.2018 18.12.2018
- small changes in FlatCAMGeometry.plot() - small changes in GeometryObject.plot()
- updated the FlatCAMGeometry.merge() function and the Join Geometry feature to accommodate the different types of geometries: singlegeo and multigeo type - updated the GeometryObject.merge() function and the Join Geometry feature to accommodate the different types of geometries: singlegeo and multigeo type
- added Conversion submenu in Edit where I moved the Join features and added the Convert from MultiGeo to SingleGeo type and the reverse - added Conversion submenu in Edit where I moved the Join features and added the Convert from MultiGeo to SingleGeo type and the reverse
- added Copy Tool (on a selection of tools) feature in Geometry Object UI - added Copy Tool (on a selection of tools) feature in Geometry Object UI
- fixed the bounds() method for the MultiGeo geometry object so the canvas selection is working and also the Properties Tool - fixed the bounds() method for the MultiGeo geometry object so the canvas selection is working and also the Properties Tool

File diff suppressed because it is too large Load Diff

381
FlatCAMBookmark.py Normal file
View File

@ -0,0 +1,381 @@
from PyQt5 import QtGui, QtCore, QtWidgets
from flatcamGUI.GUIElements import FCTable, FCEntry, FCButton, FCFileSaveDialog
import sys
import webbrowser
from copy import deepcopy
from datetime import datetime
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
class BookmarkManager(QtWidgets.QWidget):
mark_rows = QtCore.pyqtSignal()
def __init__(self, app, storage, parent=None):
super(BookmarkManager, self).__init__(parent)
self.app = app
assert isinstance(storage, dict), "Storage argument is not a dictionary"
self.bm_dict = deepcopy(storage)
# Icon and title
# self.setWindowIcon(parent.app_icon)
# self.setWindowTitle(_("Bookmark Manager"))
# self.resize(600, 400)
# title = QtWidgets.QLabel(
# "<font size=8><B>FlatCAM</B></font><BR>"
# )
# title.setOpenExternalLinks(True)
# layouts
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
table_hlay = QtWidgets.QHBoxLayout()
layout.addLayout(table_hlay)
self.table_widget = FCTable(drag_drop=True, protected_rows=[0, 1])
self.table_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
table_hlay.addWidget(self.table_widget)
self.table_widget.setColumnCount(3)
self.table_widget.setColumnWidth(0, 20)
self.table_widget.setHorizontalHeaderLabels(
[
'#',
_('Title'),
_('Web Link')
]
)
self.table_widget.horizontalHeaderItem(0).setToolTip(
_("Index.\n"
"The rows in gray color will populate the Bookmarks menu.\n"
"The number of gray colored rows is set in Preferences."))
self.table_widget.horizontalHeaderItem(1).setToolTip(
_("Description of the link that is set as an menu action.\n"
"Try to keep it short because it is installed as a menu item."))
self.table_widget.horizontalHeaderItem(2).setToolTip(
_("Web Link. E.g: https://your_website.org "))
# pal = QtGui.QPalette()
# pal.setColor(QtGui.QPalette.Background, Qt.white)
# New Bookmark
new_vlay = QtWidgets.QVBoxLayout()
layout.addLayout(new_vlay)
new_title_lbl = QtWidgets.QLabel('<b>%s</b>' % _("New Bookmark"))
new_vlay.addWidget(new_title_lbl)
form0 = QtWidgets.QFormLayout()
new_vlay.addLayout(form0)
title_lbl = QtWidgets.QLabel('%s:' % _("Title"))
self.title_entry = FCEntry()
form0.addRow(title_lbl, self.title_entry)
link_lbl = QtWidgets.QLabel('%s:' % _("Web Link"))
self.link_entry = FCEntry()
self.link_entry.set_value('http://')
form0.addRow(link_lbl, self.link_entry)
# Buttons Layout
button_hlay = QtWidgets.QHBoxLayout()
layout.addLayout(button_hlay)
add_entry_btn = FCButton(_("Add Entry"))
remove_entry_btn = FCButton(_("Remove Entry"))
export_list_btn = FCButton(_("Export List"))
import_list_btn = FCButton(_("Import List"))
# closebtn = QtWidgets.QPushButton(_("Close"))
# button_hlay.addStretch()
button_hlay.addWidget(add_entry_btn)
button_hlay.addWidget(remove_entry_btn)
button_hlay.addWidget(export_list_btn)
button_hlay.addWidget(import_list_btn)
# button_hlay.addWidget(closebtn)
# ##############################################################################
# ######################## SIGNALS #############################################
# ##############################################################################
add_entry_btn.clicked.connect(self.on_add_entry)
remove_entry_btn.clicked.connect(self.on_remove_entry)
export_list_btn.clicked.connect(self.on_export_bookmarks)
import_list_btn.clicked.connect(self.on_import_bookmarks)
self.title_entry.returnPressed.connect(self.on_add_entry)
self.link_entry.returnPressed.connect(self.on_add_entry)
# closebtn.clicked.connect(self.accept)
self.table_widget.drag_drop_sig.connect(self.mark_table_rows_for_actions)
self.build_bm_ui()
def build_bm_ui(self):
self.table_widget.setRowCount(len(self.bm_dict))
nr_crt = 0
sorted_bookmarks = sorted(list(self.bm_dict.items()), key=lambda x: int(x[0]))
for entry, bookmark in sorted_bookmarks:
row = nr_crt
nr_crt += 1
title = bookmark[0]
weblink = bookmark[1]
id_item = QtWidgets.QTableWidgetItem('%d' % int(nr_crt))
# id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.table_widget.setItem(row, 0, id_item) # Tool name/id
title_item = QtWidgets.QTableWidgetItem(title)
self.table_widget.setItem(row, 1, title_item)
weblink_txt = QtWidgets.QTextBrowser()
weblink_txt.setOpenExternalLinks(True)
weblink_txt.setFrameStyle(QtWidgets.QFrame.NoFrame)
weblink_txt.document().setDefaultStyleSheet("a{ text-decoration: none; }")
weblink_txt.setHtml('<a href=%s>%s</a>' % (weblink, weblink))
self.table_widget.setCellWidget(row, 2, weblink_txt)
vertical_header = self.table_widget.verticalHeader()
vertical_header.hide()
horizontal_header = self.table_widget.horizontalHeader()
horizontal_header.setMinimumSectionSize(10)
horizontal_header.setDefaultSectionSize(70)
horizontal_header.setSectionResizeMode(0, QtWidgets.QHeaderView.Fixed)
horizontal_header.resizeSection(0, 20)
horizontal_header.setSectionResizeMode(1, QtWidgets.QHeaderView.ResizeToContents)
horizontal_header.setSectionResizeMode(2, QtWidgets.QHeaderView.Stretch)
self.mark_table_rows_for_actions()
self.app.defaults["global_bookmarks"].clear()
for key, val in self.bm_dict.items():
self.app.defaults["global_bookmarks"][key] = deepcopy(val)
def on_add_entry(self, **kwargs):
"""
Add a entry in the Bookmark Table and in the menu actions
:return: None
"""
if 'title' in kwargs:
title = kwargs['title']
else:
title = self.title_entry.get_value()
if title == '':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Title entry is empty."))
return 'fail'
if 'link' in kwargs:
link = kwargs['link']
else:
link = self.link_entry.get_value()
if link == 'http://':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Web link entry is empty."))
return 'fail'
# if 'http' not in link or 'https' not in link:
# link = 'http://' + link
for bookmark in self.bm_dict.values():
if title == bookmark[0] or link == bookmark[1]:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Either the Title or the Weblink already in the table."))
return 'fail'
# for some reason if the last char in the weblink is a slash it does not make the link clickable
# so I remove it
if link[-1] == '/':
link = link[:-1]
# add the new entry to storage
new_entry = len(self.bm_dict) + 1
self.bm_dict[str(new_entry)] = [title, link]
# add the link to the menu but only if it is within the set limit
bm_limit = int(self.app.defaults["global_bookmarks_limit"])
if len(self.bm_dict) < bm_limit:
act = QtWidgets.QAction(parent=self.app.ui.menuhelp_bookmarks)
act.setText(title)
act.setIcon(QtGui.QIcon(self.app.resource_location + '/link16.png'))
act.triggered.connect(lambda: webbrowser.open(link))
self.app.ui.menuhelp_bookmarks.insertAction(self.app.ui.menuhelp_bookmarks_manager, act)
self.app.inform.emit('[success] %s' % _("Bookmark added."))
# add the new entry to the bookmark manager table
self.build_bm_ui()
def on_remove_entry(self):
"""
Remove an Entry in the Bookmark table and from the menu actions
:return:
"""
index_list = []
for model_index in self.table_widget.selectionModel().selectedRows():
index = QtCore.QPersistentModelIndex(model_index)
index_list.append(index)
title_to_remove = self.table_widget.item(model_index.row(), 1).text()
if title_to_remove == 'FlatCAM' or title_to_remove == 'Backup Site':
self.app.inform.emit('[WARNING_NOTCL] %s.' % _("This bookmark can not be removed"))
self.build_bm_ui()
return
else:
for k, bookmark in list(self.bm_dict.items()):
if title_to_remove == bookmark[0]:
# remove from the storage
self.bm_dict.pop(k, None)
for act in self.app.ui.menuhelp_bookmarks.actions():
if act.text() == title_to_remove:
# disconnect the signal
try:
act.triggered.disconnect()
except TypeError:
pass
# remove the action from the menu
self.app.ui.menuhelp_bookmarks.removeAction(act)
# house keeping: it pays to have keys increased by one
new_key = 0
new_dict = {}
for k, v in self.bm_dict.items():
# we start with key 1 so we can use the len(self.bm_dict)
# when adding bookmarks (keys in bm_dict)
new_key += 1
new_dict[str(new_key)] = v
self.bm_dict = deepcopy(new_dict)
new_dict.clear()
self.app.inform.emit('[success] %s' % _("Bookmark removed."))
# for index in index_list:
# self.table_widget.model().removeRow(index.row())
self.build_bm_ui()
def on_export_bookmarks(self):
self.app.report_usage("on_export_bookmarks")
self.app.log.debug("on_export_bookmarks()")
date = str(datetime.today()).rpartition('.')[0]
date = ''.join(c for c in date if c not in ':-')
date = date.replace(' ', '_')
filter__ = "Text File (*.TXT);;All Files (*.*)"
filename, _f = FCFileSaveDialog.get_saved_filename( caption=_("Export FlatCAM Bookmarks"),
directory='{l_save}/FlatCAM_{n}_{date}'.format(
l_save=str(self.app.get_last_save_folder()),
n=_("Bookmarks"),
date=date),
filter=filter__)
filename = str(filename)
if filename == "":
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
return
else:
try:
f = open(filename, 'w')
f.close()
except PermissionError:
self.app.inform.emit('[WARNING] %s' %
_("Permission denied, saving not possible.\n"
"Most likely another app is holding the file open and not accessible."))
return
except IOError:
self.app.log.debug('Creating a new bookmarks file ...')
f = open(filename, 'w')
f.close()
except Exception:
e = sys.exc_info()[0]
self.app.log.error("Could not load defaults file.")
self.app.log.error(str(e))
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Could not load bookmarks file."))
return
# Save Bookmarks to a file
try:
with open(filename, "w") as f:
for title, link in self.bm_dict.items():
line2write = str(title) + ':' + str(link) + '\n'
f.write(line2write)
except Exception:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Failed to write bookmarks to file."))
return
self.app.inform.emit('[success] %s: %s' % (_("Exported bookmarks to"), filename))
def on_import_bookmarks(self):
self.app.log.debug("on_import_bookmarks()")
filter_ = "Text File (*.txt);;All Files (*.*)"
filename, _f = QtWidgets.QFileDialog.getOpenFileName(caption=_("Import FlatCAM Bookmarks"), filter=filter_)
filename = str(filename)
if filename == "":
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled."))
else:
try:
with open(filename) as f:
bookmarks = f.readlines()
except IOError:
self.app.log.error("Could not load bookmarks file.")
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Could not load bookmarks file."))
return
for line in bookmarks:
proc_line = line.replace(' ', '').partition(':')
self.on_add_entry(title=proc_line[0], link=proc_line[2])
self.app.inform.emit('[success] %s: %s' % (_("Imported Bookmarks from"), filename))
def mark_table_rows_for_actions(self):
for row in range(self.table_widget.rowCount()):
item_to_paint = self.table_widget.item(row, 0)
if row < self.app.defaults["global_bookmarks_limit"]:
item_to_paint.setBackground(QtGui.QColor('gray'))
# item_to_paint.setForeground(QtGui.QColor('black'))
else:
item_to_paint.setBackground(QtGui.QColor('white'))
# item_to_paint.setForeground(QtGui.QColor('black'))
def rebuild_actions(self):
# rebuild the storage to reflect the order of the lines
self.bm_dict.clear()
for row in range(self.table_widget.rowCount()):
title = self.table_widget.item(row, 1).text()
wlink = self.table_widget.cellWidget(row, 2).toPlainText()
entry = int(row) + 1
self.bm_dict.update(
{
str(entry): [title, wlink]
}
)
self.app.install_bookmarks(book_dict=self.bm_dict)
# def accept(self):
# self.rebuild_actions()
# super().accept()
def closeEvent(self, QCloseEvent):
self.rebuild_actions()
super().closeEvent(QCloseEvent)

File diff suppressed because it is too large Load Diff

2399
FlatCAMDB.py Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,10 @@ from abc import ABCMeta, abstractmethod
import math import math
# module-root dictionary of preprocessors # module-root dictionary of preprocessors
import FlatCAMApp
import logging
log = logging.getLogger('base')
preprocessors = {} preprocessors = {}
@ -23,7 +25,7 @@ class ABCPostProcRegister(ABCMeta):
newclass = super(ABCPostProcRegister, cls).__new__(cls, clsname, bases, attrs) newclass = super(ABCPostProcRegister, cls).__new__(cls, clsname, bases, attrs)
if object not in bases: if object not in bases:
if newclass.__name__ in preprocessors: if newclass.__name__ in preprocessors:
FlatCAMApp.App.log.warning('Preprocessor %s has been overriden' % newclass.__name__) log.warning('Preprocessor %s has been overriden' % newclass.__name__)
preprocessors[newclass.__name__] = newclass() # here is your register function preprocessors[newclass.__name__] = newclass() # here is your register function
return newclass return newclass

View File

@ -29,6 +29,7 @@ languages_dict = {
'en': 'English', 'en': 'English',
'es': 'Spanish', 'es': 'Spanish',
'fr': 'French', 'fr': 'French',
'hu': 'Hungarian',
'it': 'Italian', 'it': 'Italian',
'ro': 'Romanian', 'ro': 'Romanian',
'ru': 'Russian', 'ru': 'Russian',

View File

@ -16,10 +16,15 @@ from PyQt5.QtCore import Qt, QSettings
from PyQt5.QtGui import QColor from PyQt5.QtGui import QColor
# from PyQt5.QtCore import QModelIndex # from PyQt5.QtCore import QModelIndex
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon, FlatCAMCNCjob, FlatCAMDocument, FlatCAMScript, \ from flatcamObjects.FlatCAMObj import FlatCAMObj
FlatCAMObj from flatcamObjects.FlatCAMCNCJob import CNCJobObject
from flatcamObjects.FlatCAMDocument import DocumentObject
from flatcamObjects.FlatCAMExcellon import ExcellonObject
from flatcamObjects.FlatCAMGeometry import GeometryObject
from flatcamObjects.FlatCAMGerber import GerberObject
from flatcamObjects.FlatCAMScript import ScriptObject
import inspect # TODO: Remove import inspect # TODO: Remove
import FlatCAMApp
import re import re
import logging import logging
@ -234,12 +239,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
] ]
classdict = { classdict = {
"gerber": FlatCAMGerber, "gerber": GerberObject,
"excellon": FlatCAMExcellon, "excellon": ExcellonObject,
"cncjob": FlatCAMCNCjob, "cncjob": CNCJobObject,
"geometry": FlatCAMGeometry, "geometry": GeometryObject,
"script": FlatCAMScript, "script": ScriptObject,
"document": FlatCAMDocument "document": DocumentObject
} }
icon_files = { icon_files = {
@ -332,7 +337,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.update_list_signal.connect(self.on_update_list_signal) self.update_list_signal.connect(self.on_update_list_signal)
def promise(self, obj_name): def promise(self, obj_name):
FlatCAMApp.App.log.debug("Object %s has been promised." % obj_name) log.debug("Object %s has been promised." % obj_name)
self.promises.add(obj_name) self.promises.add(obj_name)
def has_promises(self): def has_promises(self):
@ -349,7 +354,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
return len(self.plot_promises) > 0 return len(self.plot_promises) > 0
def on_mouse_down(self, event): def on_mouse_down(self, event):
FlatCAMApp.App.log.debug("Mouse button pressed on list") log.debug("Mouse button pressed on list")
def on_menu_request(self, pos): def on_menu_request(self, pos):
@ -373,17 +378,17 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.ui.menuprojectcolor.setEnabled(False) self.app.ui.menuprojectcolor.setEnabled(False)
for obj in self.get_selected(): for obj in self.get_selected():
if type(obj) == FlatCAMGerber or type(obj) == FlatCAMExcellon: if type(obj) == GerberObject or type(obj) == ExcellonObject:
self.app.ui.menuprojectcolor.setEnabled(True) self.app.ui.menuprojectcolor.setEnabled(True)
if type(obj) != FlatCAMGeometry: if type(obj) != GeometryObject:
self.app.ui.menuprojectgeneratecnc.setVisible(False) self.app.ui.menuprojectgeneratecnc.setVisible(False)
if type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMGerber: if type(obj) != GeometryObject and type(obj) != ExcellonObject and type(obj) != GerberObject:
self.app.ui.menuprojectedit.setVisible(False) self.app.ui.menuprojectedit.setVisible(False)
if type(obj) != FlatCAMGerber and type(obj) != FlatCAMExcellon and type(obj) != FlatCAMCNCjob: if type(obj) != GerberObject and type(obj) != ExcellonObject and type(obj) != CNCJobObject:
self.app.ui.menuprojectviewsource.setVisible(False) self.app.ui.menuprojectviewsource.setVisible(False)
if type(obj) != FlatCAMGerber and type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and \ if type(obj) != GerberObject and type(obj) != GeometryObject and type(obj) != ExcellonObject and \
type(obj) != FlatCAMCNCjob: type(obj) != CNCJobObject:
# meaning for Scripts and for Document type of FlatCAM object # meaning for Scripts and for Document type of FlatCAM object
self.app.ui.menuprojectenable.setVisible(False) self.app.ui.menuprojectenable.setVisible(False)
self.app.ui.menuprojectdisable.setVisible(False) self.app.ui.menuprojectdisable.setVisible(False)
@ -532,21 +537,21 @@ class ObjectCollection(QtCore.QAbstractItemModel):
# return QtWidgets.QAbstractItemModel.flags(self, index) # return QtWidgets.QAbstractItemModel.flags(self, index)
def append(self, obj, active=False, to_index=None): def append(self, obj, active=False, to_index=None):
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> OC.append()") log.debug(str(inspect.stack()[1][3]) + " --> OC.append()")
name = obj.options["name"] name = obj.options["name"]
# Check promises and clear if exists # Check promises and clear if exists
if name in self.promises: if name in self.promises:
self.promises.remove(name) self.promises.remove(name)
# FlatCAMApp.App.log.debug("Promised object %s became available." % name) # log.debug("Promised object %s became available." % name)
# FlatCAMApp.App.log.debug("%d promised objects remaining." % len(self.promises)) # log.debug("%d promised objects remaining." % len(self.promises))
# Prevent same name # Prevent same name
while name in self.get_names(): while name in self.get_names():
# ## Create a new name # ## Create a new name
# Ends with number? # Ends with number?
FlatCAMApp.App.log.debug("new_object(): Object name (%s) exists, changing." % name) log.debug("new_object(): Object name (%s) exists, changing." % name)
match = re.search(r'(.*[^\d])?(\d+)$', name) match = re.search(r'(.*[^\d])?(\d+)$', name)
if match: # Yes: Increment the number! if match: # Yes: Increment the number!
base = match.group(1) or '' base = match.group(1) or ''
@ -596,7 +601,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
:rtype: list :rtype: list
""" """
# FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> OC.get_names()") # log.debug(str(inspect.stack()[1][3]) + " --> OC.get_names()")
return [x.options['name'] for x in self.get_list()] return [x.options['name'] for x in self.get_list()]
def get_bounds(self): def get_bounds(self):
@ -606,7 +611,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
:return: [xmin, ymin, xmax, ymax] :return: [xmin, ymin, xmax, ymax]
:rtype: list :rtype: list
""" """
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_bounds()") log.debug(str(inspect.stack()[1][3]) + "--> OC.get_bounds()")
# TODO: Move the operation out of here. # TODO: Move the operation out of here.
@ -624,7 +629,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
xmax = max([xmax, gxmax]) xmax = max([xmax, gxmax])
ymax = max([ymax, gymax]) ymax = max([ymax, gymax])
except Exception as e: except Exception as e:
FlatCAMApp.App.log.warning("DEV WARNING: Tried to get bounds of empty geometry. %s" % str(e)) log.warning("DEV WARNING: Tried to get bounds of empty geometry. %s" % str(e))
return [xmin, ymin, xmax, ymax] return [xmin, ymin, xmax, ymax]
@ -638,7 +643,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
:return: The requested object or None if no such object. :return: The requested object or None if no such object.
:rtype: FlatCAMObj or None :rtype: FlatCAMObj or None
""" """
# FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.get_by_name()") # log.debug(str(inspect.stack()[1][3]) + "--> OC.get_by_name()")
if isCaseSensitive is None or isCaseSensitive is True: if isCaseSensitive is None or isCaseSensitive is True:
for obj in self.get_list(): for obj in self.get_list():
@ -760,7 +765,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.all_objects_list = self.get_list() self.app.all_objects_list = self.get_list()
def delete_all(self): def delete_all(self):
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_all()") log.debug(str(inspect.stack()[1][3]) + "--> OC.delete_all()")
self.app.object_status_changed.emit(None, 'delete_all', '') self.app.object_status_changed.emit(None, 'delete_all', '')
@ -897,8 +902,15 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.set_inactive(name) self.set_inactive(name)
def on_list_selection_change(self, current, previous): def on_list_selection_change(self, current, previous):
# FlatCAMApp.App.log.debug("on_list_selection_change()") """
# FlatCAMApp.App.log.debug("Current: %s, Previous %s" % (str(current), str(previous)))
:param current: Current selected item
:param previous: Previously selected item
:return:
"""
# log.debug("on_list_selection_change()")
# log.debug("Current: %s, Previous %s" % (str(current), str(previous)))
try: try:
obj = current.indexes()[0].internalPointer().obj obj = current.indexes()[0].internalPointer().obj
@ -942,12 +954,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
) )
except IndexError: except IndexError:
self.item_selected.emit('none') self.item_selected.emit('none')
# FlatCAMApp.App.log.debug("on_list_selection_change(): Index Error (Nothing selected?)") # log.debug("on_list_selection_change(): Index Error (Nothing selected?)")
self.app.inform.emit('') self.app.inform.emit('')
try: try:
self.app.ui.selected_scroll_area.takeWidget() self.app.ui.selected_scroll_area.takeWidget()
except Exception as e: except Exception as e:
FlatCAMApp.App.log.debug("Nothing to remove. %s" % str(e)) log.debug("Nothing to remove. %s" % str(e))
self.app.setup_component_editor() self.app.setup_component_editor()
return return

529
camlib.py

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,6 @@ from camlib import distance, arc, FlatCAMRTreeStorage
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, RadioSet, FCSpinner from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, RadioSet, FCSpinner
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
from flatcamParsers.ParseExcellon import Excellon from flatcamParsers.ParseExcellon import Excellon
import FlatCAMApp
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point
import shapely.affinity as affinity import shapely.affinity as affinity
@ -179,7 +178,7 @@ class FCDrillArray(FCShapeTool):
try: try:
QtGui.QGuiApplication.restoreOverrideCursor() QtGui.QGuiApplication.restoreOverrideCursor()
except Exception as e: except Exception:
pass pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_drill_array.png')) self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_drill_array.png'))
@ -1516,7 +1515,7 @@ class FlatCAMExcEditor(QtCore.QObject):
draw_shape_idx = -1 draw_shape_idx = -1
def __init__(self, app): def __init__(self, app):
assert isinstance(app, FlatCAMApp.App), "Expected the app to be a FlatCAMApp.App, got %s" % type(app) # assert isinstance(app, FlatCAMApp.App), "Expected the app to be a FlatCAMApp.App, got %s" % type(app)
super(FlatCAMExcEditor, self).__init__() super(FlatCAMExcEditor, self).__init__()
@ -2230,8 +2229,8 @@ class FlatCAMExcEditor(QtCore.QObject):
# store the status of the editor so the Delete at object level will not work until the edit is finished # store the status of the editor so the Delete at object level will not work until the edit is finished
self.editor_active = False self.editor_active = False
def entry2option(option, entry): # def entry2option(option, entry):
self.options[option] = float(entry.text()) # self.options[option] = float(entry.text())
# Event signals disconnect id holders # Event signals disconnect id holders
self.mp = None self.mp = None
@ -2388,7 +2387,7 @@ class FlatCAMExcEditor(QtCore.QObject):
try: try:
# Find no of slots for the current tool # Find no of slots for the current tool
for slot in self.slots: for slot in self.slot_points_edit:
if slot['tool'] == tool_no: if slot['tool'] == tool_no:
slot_cnt += 1 slot_cnt += 1
@ -2661,15 +2660,13 @@ class FlatCAMExcEditor(QtCore.QObject):
# self.tools_table_exc.selectionModel().currentChanged.disconnect() # self.tools_table_exc.selectionModel().currentChanged.disconnect()
self.is_modified = True self.is_modified = True
new_dia = None # new_dia = None
if self.tools_table_exc.currentItem() is not None: try:
try: new_dia = 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)) return
self.tools_table_exc.setCurrentItem(None)
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
@ -3042,7 +3039,7 @@ class FlatCAMExcEditor(QtCore.QObject):
Imports the geometry from the given FlatCAM Excellon object Imports the geometry from the given FlatCAM Excellon object
into the editor. into the editor.
:param exc_obj: FlatCAMExcellon object :param exc_obj: ExcellonObject object
:return: None :return: None
""" """
@ -3118,7 +3115,7 @@ class FlatCAMExcEditor(QtCore.QObject):
""" """
Create a new Excellon object that contain the edited content of the source Excellon object Create a new Excellon object that contain the edited content of the source Excellon object
:param exc_obj: FlatCAMExcellon :param exc_obj: ExcellonObject
:return: None :return: None
""" """
@ -3297,7 +3294,8 @@ class FlatCAMExcEditor(QtCore.QObject):
return self.edited_obj_name return self.edited_obj_name
def update_options(self, obj): @staticmethod
def update_options(obj):
try: try:
if not obj.options: if not obj.options:
obj.options = {} obj.options = {}
@ -3316,10 +3314,14 @@ class FlatCAMExcEditor(QtCore.QObject):
""" """
Creates a new Excellon object for the edited Excellon. Thread-safe. Creates a new Excellon object for the edited Excellon. Thread-safe.
:param outname: Name of the resulting object. None causes the :param outname: Name of the resulting object. None causes the
name to be that of the file. name to be that of the file.
:type outname: str :type outname: str
:return: None
:param n_drills: The new Drills storage
:param n_slots: The new Slots storage
:param n_tools: The new Tools storage
:return: None
""" """
self.app.log.debug("Update the Excellon object with edited content. Source is %s" % self.app.log.debug("Update the Excellon object with edited content. Source is %s" %
@ -3429,12 +3431,12 @@ class FlatCAMExcEditor(QtCore.QObject):
self.replot() self.replot()
def toolbar_tool_toggle(self, key): # def toolbar_tool_toggle(self, key):
self.options[key] = self.sender().isChecked() # self.options[key] = self.sender().isChecked()
if self.options[key] is True: # if self.options[key] is True:
return 1 # return 1
else: # else:
return 0 # return 0
def on_canvas_click(self, event): def on_canvas_click(self, event):
""" """
@ -3446,12 +3448,12 @@ class FlatCAMExcEditor(QtCore.QObject):
""" """
if self.app.is_legacy is False: if self.app.is_legacy is False:
event_pos = event.pos event_pos = event.pos
event_is_dragging = event.is_dragging # event_is_dragging = event.is_dragging
right_button = 2 # right_button = 2
else: else:
event_pos = (event.xdata, event.ydata) event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging # event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3 # right_button = 3
self.pos = self.canvas.translate_coords(event_pos) self.pos = self.canvas.translate_coords(event_pos)
@ -3575,8 +3577,8 @@ class FlatCAMExcEditor(QtCore.QObject):
if isinstance(shape, DrawToolUtilityShape): if isinstance(shape, DrawToolUtilityShape):
self.utility.append(shape) self.utility.append(shape)
else: # else:
self.storage.insert(shape) # TODO: Check performance # self.storage.insert(shape)
def on_exc_click_release(self, event): def on_exc_click_release(self, event):
""" """
@ -3591,11 +3593,11 @@ class FlatCAMExcEditor(QtCore.QObject):
if self.app.is_legacy is False: if self.app.is_legacy is False:
event_pos = event.pos event_pos = event.pos
event_is_dragging = event.is_dragging # event_is_dragging = event.is_dragging
right_button = 2 right_button = 2
else: else:
event_pos = (event.xdata, event.ydata) event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging # event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3 right_button = 3
pos_canvas = self.canvas.translate_coords(event_pos) pos_canvas = self.canvas.translate_coords(event_pos)
@ -4027,7 +4029,7 @@ class FlatCAMExcEditor(QtCore.QObject):
del self.slot_points_edit[storage][0] del self.slot_points_edit[storage][0]
if del_shape in self.selected: if del_shape in self.selected:
self.selected.remove(del_shape) # TODO: Check performance self.selected.remove(del_shape)
def delete_utility_geometry(self): def delete_utility_geometry(self):
for_deletion = [util_shape for util_shape in self.utility] for_deletion = [util_shape for util_shape in self.utility]

View File

@ -20,7 +20,6 @@ from flatcamGUI.ObjectUI import RadioSet
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \ from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog, FCTree FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog, FCTree
from flatcamParsers.ParseFont import * from flatcamParsers.ParseFont import *
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, linemerge from shapely.ops import cascaded_union, unary_union, linemerge
@ -88,8 +87,8 @@ class BufferSelectionTool(FlatCAMTool):
self.buffer_corner_lbl.setToolTip( self.buffer_corner_lbl.setToolTip(
_("There are 3 types of corners:\n" _("There are 3 types of corners:\n"
" - 'Round': the corner is rounded for exterior buffer.\n" " - 'Round': the corner is rounded for exterior buffer.\n"
" - 'Square:' the corner is met in a sharp angle for exterior buffer.\n" " - 'Square': the corner is met in a sharp angle for exterior buffer.\n"
" - 'Beveled:' the corner is a line that directly connects the features meeting in the corner") " - 'Beveled': the corner is a line that directly connects the features meeting in the corner")
) )
self.buffer_corner_cb = FCComboBox() self.buffer_corner_cb = FCComboBox()
self.buffer_corner_cb.addItem(_("Round")) self.buffer_corner_cb.addItem(_("Round"))
@ -3299,8 +3298,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
draw_shape_idx = -1 draw_shape_idx = -1
def __init__(self, app, disabled=False): def __init__(self, app, disabled=False):
assert isinstance(app, FlatCAMApp.App), \ # assert isinstance(app, FlatCAMApp.App), \
"Expected the app to be a FlatCAMApp.App, got %s" % type(app) # "Expected the app to be a FlatCAMApp.App, got %s" % type(app)
super(FlatCAMGeoEditor, self).__init__() super(FlatCAMGeoEditor, self).__init__()
@ -4011,6 +4010,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
:return: Boolean. Status of the checkbox that toggled the Editor Tool :return: Boolean. Status of the checkbox that toggled the Editor Tool
""" """
cb_widget = self.sender() cb_widget = self.sender()
assert isinstance(cb_widget, QtWidgets.QAction), "Expected a QAction got %s" % type(cb_widget)
self.options[key] = cb_widget.isChecked() self.options[key] = cb_widget.isChecked()
return 1 if self.options[key] is True else 0 return 1 if self.options[key] is True else 0
@ -4035,7 +4035,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
Imports the geometry from the given FlatCAM Geometry object Imports the geometry from the given FlatCAM Geometry object
into the editor. into the editor.
:param fcgeometry: FlatCAMGeometry :param fcgeometry: GeometryObject
:param multigeo_tool: A tool for the case of the edited geometry being of type 'multigeo' :param multigeo_tool: A tool for the case of the edited geometry being of type 'multigeo'
:return: None :return: None
""" """
@ -4750,7 +4750,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
Transfers the geometry tool shape buffer to the selected geometry Transfers the geometry tool shape buffer to the selected geometry
object. The geometry already in the object are removed. object. The geometry already in the object are removed.
:param fcgeometry: FlatCAMGeometry :param fcgeometry: GeometryObject
:return: None :return: None
""" """
if self.multigeo_tool: if self.multigeo_tool:

View File

@ -21,7 +21,6 @@ from camlib import distance, arc, three_point_circle
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, FCSpinner, RadioSet, \ from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, FCSpinner, RadioSet, \
EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
import FlatCAMApp
import numpy as np import numpy as np
from numpy.linalg import norm as numpy_norm from numpy.linalg import norm as numpy_norm
@ -182,6 +181,7 @@ class FCShapeTool(DrawTool):
def __init__(self, draw_app): def __init__(self, draw_app):
DrawTool.__init__(self, draw_app) DrawTool.__init__(self, draw_app)
self.name = None
def make(self): def make(self):
pass pass
@ -199,7 +199,7 @@ class FCPad(FCShapeTool):
try: try:
QtGui.QGuiApplication.restoreOverrideCursor() QtGui.QGuiApplication.restoreOverrideCursor()
except Exception as e: except Exception:
pass pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_circle.png')) self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_circle.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor) QtGui.QGuiApplication.setOverrideCursor(self.cursor)
@ -1415,7 +1415,7 @@ class FCDisc(FCShapeTool):
try: try:
QtGui.QGuiApplication.restoreOverrideCursor() QtGui.QGuiApplication.restoreOverrideCursor()
except Exception as e: except Exception:
pass pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_disc.png')) self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_disc.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor) QtGui.QGuiApplication.setOverrideCursor(self.cursor)
@ -2422,8 +2422,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
mp_finished = QtCore.pyqtSignal(list) mp_finished = QtCore.pyqtSignal(list)
def __init__(self, app): def __init__(self, app):
assert isinstance(app, FlatCAMApp.App), \ # assert isinstance(app, FlatCAMApp.App), \
"Expected the app to be a FlatCAMApp.App, got %s" % type(app) # "Expected the app to be a FlatCAMApp.App, got %s" % type(app)
super(FlatCAMGrbEditor, self).__init__() super(FlatCAMGrbEditor, self).__init__()
@ -2621,8 +2621,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.buffer_corner_lbl.setToolTip( self.buffer_corner_lbl.setToolTip(
_("There are 3 types of corners:\n" _("There are 3 types of corners:\n"
" - 'Round': the corner is rounded.\n" " - 'Round': the corner is rounded.\n"
" - 'Square:' the corner is met in a sharp angle.\n" " - 'Square': the corner is met in a sharp angle.\n"
" - 'Beveled:' the corner is a line that directly connects the features meeting in the corner") " - 'Beveled': the corner is a line that directly connects the features meeting in the corner")
) )
self.buffer_corner_cb = FCComboBox() self.buffer_corner_cb = FCComboBox()
self.buffer_corner_cb.addItem(_("Round")) self.buffer_corner_cb.addItem(_("Round"))
@ -3479,7 +3479,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
current_table_dia_edited = float(self.apertures_table.currentItem().text()) current_table_dia_edited = float(self.apertures_table.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.apertures_table.setCurrentItem(None) # self.apertures_table.setCurrentItem(None)
return return
row_of_item_changed = self.apertures_table.currentRow() row_of_item_changed = self.apertures_table.currentRow()
@ -3833,7 +3833,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
Imports the geometry found in self.apertures from the given FlatCAM Gerber object Imports the geometry found in self.apertures from the given FlatCAM Gerber object
into the editor. into the editor.
:param orig_grb_obj: FlatCAMExcellon :param orig_grb_obj: ExcellonObject
:return: None :return: None
""" """
@ -3956,10 +3956,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
global_clear_geo = [] global_clear_geo = []
# create one big geometry made out of all 'negative' (clear) polygons # create one big geometry made out of all 'negative' (clear) polygons
for apid in app_obj.gerber_obj.apertures: for aper_id in app_obj.gerber_obj.apertures:
# first check if we have any clear_geometry (LPC) and if yes added it to the global_clear_geo # first check if we have any clear_geometry (LPC) and if yes added it to the global_clear_geo
if 'geometry' in app_obj.gerber_obj.apertures[apid]: if 'geometry' in app_obj.gerber_obj.apertures[aper_id]:
for elem in app_obj.gerber_obj.apertures[apid]['geometry']: for elem in app_obj.gerber_obj.apertures[aper_id]['geometry']:
if 'clear' in elem: if 'clear' in elem:
global_clear_geo.append(elem['clear']) global_clear_geo.append(elem['clear'])
log.warning("Found %d clear polygons." % len(global_clear_geo)) log.warning("Found %d clear polygons." % len(global_clear_geo))
@ -3967,7 +3967,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
if global_clear_geo: if global_clear_geo:
global_clear_geo = MultiPolygon(global_clear_geo) global_clear_geo = MultiPolygon(global_clear_geo)
if isinstance(global_clear_geo, Polygon): if isinstance(global_clear_geo, Polygon):
global_clear_geo = list(global_clear_geo) global_clear_geo = [global_clear_geo]
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of # we subtract the big "negative" (clear) geometry from each solid polygon but only the part of
# clear geometry that fits inside the solid. otherwise we may loose the solid # clear geometry that fits inside the solid. otherwise we may loose the solid
@ -3979,8 +3979,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
# solid_geo = elem['solid'] # solid_geo = elem['solid']
# for clear_geo in global_clear_geo: # for clear_geo in global_clear_geo:
# # Make sure that the clear_geo is within the solid_geo otherwise we loose # # Make sure that the clear_geo is within the solid_geo otherwise we loose
# # the solid_geometry. We want for clear_geometry just to cut into solid_geometry not to # # the solid_geometry. We want for clear_geometry just to cut
# # delete it # # into solid_geometry not to delete it
# if clear_geo.within(solid_geo): # if clear_geo.within(solid_geo):
# solid_geo = solid_geo.difference(clear_geo) # solid_geo = solid_geo.difference(clear_geo)
# try: # try:
@ -4307,14 +4307,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.plot_all() self.plot_all()
def toolbar_tool_toggle(self, key): # def toolbar_tool_toggle(self, key):
""" # """
#
:param key: key to update in self.options dictionary # :param key: key to update in self.options dictionary
:return: # :return:
""" # """
self.options[key] = self.sender().isChecked() # self.options[key] = self.sender().isChecked()
return self.options[key] # return self.options[key]
def on_grb_shape_complete(self, storage=None, specific_shape=None, no_plot=False): def on_grb_shape_complete(self, storage=None, specific_shape=None, no_plot=False):
""" """
@ -4389,12 +4389,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
""" """
if self.app.is_legacy is False: if self.app.is_legacy is False:
event_pos = event.pos event_pos = event.pos
event_is_dragging = event.is_dragging # event_is_dragging = event.is_dragging
right_button = 2 # right_button = 2
else: else:
event_pos = (event.xdata, event.ydata) event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging # event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3 # right_button = 3
self.pos = self.canvas.translate_coords(event_pos) self.pos = self.canvas.translate_coords(event_pos)
@ -4457,11 +4457,11 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.modifiers = QtWidgets.QApplication.keyboardModifiers() self.modifiers = QtWidgets.QApplication.keyboardModifiers()
if self.app.is_legacy is False: if self.app.is_legacy is False:
event_pos = event.pos event_pos = event.pos
event_is_dragging = event.is_dragging # event_is_dragging = event.is_dragging
right_button = 2 right_button = 2
else: else:
event_pos = (event.xdata, event.ydata) event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging # event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3 right_button = 3
pos_canvas = self.canvas.translate_coords(event_pos) pos_canvas = self.canvas.translate_coords(event_pos)
@ -4747,10 +4747,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
Plots a geometric object or list of objects without rendering. Plotted objects Plots a geometric object or list of objects without rendering. Plotted objects
are returned as a list. This allows for efficient/animated rendering. are returned as a list. This allows for efficient/animated rendering.
:param geometry: Geometry to be plotted (Any Shapely.geom kind or list of such) :param geometry: Geometry to be plotted (Any Shapely.geom kind or list of such)
:param color: Shape color :param color: Shape color
:param linewidth: Width of lines in # of pixels. :param linewidth: Width of lines in # of pixels.
:return: List of plotted elements. :return: List of plotted elements.
""" """
if geometry is None: if geometry is None:
@ -5597,7 +5597,7 @@ class TransformEditorTool(FlatCAMTool):
self.flip_ref_entry.set_value((0, 0)) self.flip_ref_entry.set_value((0, 0))
def template(self): def template(self):
if not self.fcdraw.selected: if not self.draw_app.selected:
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. No shape selected.")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("Cancelled. No shape selected."))
return return

View File

@ -2876,7 +2876,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Open Excellon file # Open Excellon file
if key == QtCore.Qt.Key_E: if key == QtCore.Qt.Key_E:
self.app.on_fileopenexcellon() self.app.on_fileopenexcellon(signal=None)
# Open Gerber file # Open Gerber file
if key == QtCore.Qt.Key_G: if key == QtCore.Qt.Key_G:
@ -2884,7 +2884,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if 'editor' in widget_name.lower(): if 'editor' in widget_name.lower():
self.app.goto_text_line() self.app.goto_text_line()
else: else:
self.app.on_fileopengerber() self.app.on_fileopengerber(signal=None)
# Distance Tool # Distance Tool
if key == QtCore.Qt.Key_M: if key == QtCore.Qt.Key_M:

View File

@ -1241,6 +1241,7 @@ class ExcellonObjectUI(ObjectUI):
self.pdepth_entry.set_precision(self.decimals) self.pdepth_entry.set_precision(self.decimals)
self.pdepth_entry.set_range(-9999.9999, 9999.9999) self.pdepth_entry.set_range(-9999.9999, 9999.9999)
self.pdepth_entry.setSingleStep(0.1) self.pdepth_entry.setSingleStep(0.1)
self.pdepth_entry.setObjectName("e_depth_probe")
self.grid5.addWidget(self.pdepth_label, 13, 0) self.grid5.addWidget(self.pdepth_label, 13, 0)
self.grid5.addWidget(self.pdepth_entry, 13, 1) self.grid5.addWidget(self.pdepth_entry, 13, 1)
@ -1258,7 +1259,7 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_probe_entry.set_precision(self.decimals) self.feedrate_probe_entry.set_precision(self.decimals)
self.feedrate_probe_entry.set_range(0.0, 9999.9999) self.feedrate_probe_entry.set_range(0.0, 9999.9999)
self.feedrate_probe_entry.setSingleStep(0.1) self.feedrate_probe_entry.setSingleStep(0.1)
self.feedrate_probe_entry.setObjectName(_("e_fr_probe")) self.feedrate_probe_entry.setObjectName("e_fr_probe")
self.grid5.addWidget(self.feedrate_probe_label, 14, 0) self.grid5.addWidget(self.feedrate_probe_label, 14, 0)
self.grid5.addWidget(self.feedrate_probe_entry, 14, 1) self.grid5.addWidget(self.feedrate_probe_entry, 14, 1)

View File

@ -16,8 +16,6 @@ from descartes.patch import PolygonPatch
from shapely.geometry import Polygon, LineString, LinearRing from shapely.geometry import Polygon, LineString, LinearRing
import FlatCAMApp
from copy import deepcopy from copy import deepcopy
import logging import logging
@ -496,7 +494,7 @@ class PlotCanvasLegacy(QtCore.QObject):
:param event: :param event:
:return: :return:
""" """
FlatCAMApp.App.log.debug('on_key_down(): ' + str(event.key)) log.debug('on_key_down(): ' + str(event.key))
self.key = event.key self.key = event.key
def on_key_up(self, event): def on_key_up(self, event):
@ -531,7 +529,7 @@ class PlotCanvasLegacy(QtCore.QObject):
try: try:
self.figure.clf() self.figure.clf()
except KeyError: except KeyError:
FlatCAMApp.App.log.warning("KeyError in MPL figure.clf()") log.warning("KeyError in MPL figure.clf()")
# Re-build # Re-build
self.figure.add_axes(self.axes) self.figure.add_axes(self.axes)
@ -582,7 +580,7 @@ class PlotCanvasLegacy(QtCore.QObject):
try: try:
r = width / height r = width / height
except ZeroDivisionError: except ZeroDivisionError:
FlatCAMApp.App.log.error("Height is %f" % height) log.error("Height is %f" % height)
return return
canvas_w, canvas_h = self.canvas.get_width_height() canvas_w, canvas_h = self.canvas.get_width_height()
canvas_r = float(canvas_w) / canvas_h canvas_r = float(canvas_w) / canvas_h
@ -1190,10 +1188,10 @@ class ShapeCollectionLegacy:
linewidth=local_shapes[element]['linewidth']) linewidth=local_shapes[element]['linewidth'])
self.axes.add_patch(patch) self.axes.add_patch(patch)
except AssertionError: except AssertionError:
FlatCAMApp.App.log.warning("A geometry component was not a polygon:") log.warning("A geometry component was not a polygon:")
FlatCAMApp.App.log.warning(str(element)) log.warning(str(element))
except Exception as e: except Exception as e:
FlatCAMApp.App.log.debug( log.debug(
"PlotCanvasLegacy.ShepeCollectionLegacy.redraw() gerber 'solid' --> %s" % str(e)) "PlotCanvasLegacy.ShepeCollectionLegacy.redraw() gerber 'solid' --> %s" % str(e))
else: else:
try: try:

View File

@ -8420,7 +8420,7 @@ class Tools2PunchGerberPrefGroupUI(OptionsGroupUI):
"- Excellon Object-> the Excellon object drills center will serve as reference.\n" "- Excellon Object-> the Excellon object drills center will serve as reference.\n"
"- Fixed Diameter -> will try to use the pads center as reference adding fixed diameter holes.\n" "- Fixed Diameter -> will try to use the pads center as reference adding fixed diameter holes.\n"
"- Fixed Annular Ring -> will try to keep a set annular ring.\n" "- Fixed Annular Ring -> will try to keep a set annular ring.\n"
"- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.\n") "- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.")
) )
grid_lay.addWidget(self.hole_size_label, 9, 0) grid_lay.addWidget(self.hole_size_label, 9, 0)
grid_lay.addWidget(self.hole_size_radio, 9, 1) grid_lay.addWidget(self.hole_size_radio, 9, 1)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,314 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
# ##########################################################
# ##########################################################
# File modified by: Marius Stanciu #
# ##########################################################
from flatcamEditors.FlatCAMTextEditor import TextEditor
from flatcamObjects.FlatCAMObj import *
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
class DocumentObject(FlatCAMObj):
"""
Represents a Document object.
"""
optionChanged = QtCore.pyqtSignal(str)
ui_type = DocumentObjectUI
def __init__(self, name):
self.decimals = self.app.decimals
log.debug("Creating a Document object...")
FlatCAMObj.__init__(self, name)
self.kind = "document"
self.units = ''
self.ser_attrs = ['options', 'kind', 'source_file']
self.source_file = ''
self.doc_code = ''
self.font_name = None
self.font_italic = None
self.font_bold = None
self.font_underline = None
self.document_editor_tab = None
self._read_only = False
self.units_found = self.app.defaults['units']
def set_ui(self, ui):
FlatCAMObj.set_ui(self, ui)
log.debug("DocumentObject.set_ui()")
assert isinstance(self.ui, DocumentObjectUI), \
"Expected a DocumentObjectUI, got %s" % type(self.ui)
self.units = self.app.defaults['units'].upper()
self.units_found = self.app.defaults['units']
# Fill form fields only on object create
self.to_form()
# Show/Hide Advanced Options
if self.app.defaults["global_app_level"] == 'b':
self.ui.level.setText(_(
'<span style="color:green;"><b>Basic</b></span>'
))
else:
self.ui.level.setText(_(
'<span style="color:red;"><b>Advanced</b></span>'
))
self.document_editor_tab = TextEditor(app=self.app)
stylesheet = """
QTextEdit {selection-background-color:%s;
selection-color:white;
}
""" % self.app.defaults["document_sel_color"]
self.document_editor_tab.code_editor.setStyleSheet(stylesheet)
# first clear previous text in text editor (if any)
self.document_editor_tab.code_editor.clear()
self.document_editor_tab.code_editor.setReadOnly(self._read_only)
self.document_editor_tab.buttonRun.hide()
self.ui.autocomplete_cb.set_value(self.app.defaults['document_autocompleter'])
self.on_autocomplete_changed(state=self.app.defaults['document_autocompleter'])
self.on_tab_size_change(val=self.app.defaults['document_tab_size'])
flt = "FlatCAM Docs (*.FlatDoc);;All Files (*.*)"
# ######################################################################
# ######################## SIGNALS #####################################
# ######################################################################
self.document_editor_tab.buttonOpen.clicked.disconnect()
self.document_editor_tab.buttonOpen.clicked.connect(lambda: self.document_editor_tab.handleOpen(filt=flt))
self.document_editor_tab.buttonSave.clicked.disconnect()
self.document_editor_tab.buttonSave.clicked.connect(lambda: self.document_editor_tab.handleSaveGCode(filt=flt))
self.document_editor_tab.code_editor.textChanged.connect(self.on_text_changed)
self.ui.font_type_cb.currentFontChanged.connect(self.font_family)
self.ui.font_size_cb.activated.connect(self.font_size)
self.ui.font_bold_tb.clicked.connect(self.on_bold_button)
self.ui.font_italic_tb.clicked.connect(self.on_italic_button)
self.ui.font_under_tb.clicked.connect(self.on_underline_button)
self.ui.font_color_entry.editingFinished.connect(self.on_font_color_entry)
self.ui.font_color_button.clicked.connect(self.on_font_color_button)
self.ui.sel_color_entry.editingFinished.connect(self.on_selection_color_entry)
self.ui.sel_color_button.clicked.connect(self.on_selection_color_button)
self.ui.al_left_tb.clicked.connect(lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignLeft))
self.ui.al_center_tb.clicked.connect(lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignCenter))
self.ui.al_right_tb.clicked.connect(lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignRight))
self.ui.al_justify_tb.clicked.connect(
lambda: self.document_editor_tab.code_editor.setAlignment(Qt.AlignJustify)
)
self.ui.autocomplete_cb.stateChanged.connect(self.on_autocomplete_changed)
self.ui.tab_size_spinner.returnPressed.connect(self.on_tab_size_change)
# #######################################################################
self.ui.font_color_entry.set_value(self.app.defaults['document_font_color'])
self.ui.font_color_button.setStyleSheet(
"background-color:%s" % str(self.app.defaults['document_font_color']))
self.ui.sel_color_entry.set_value(self.app.defaults['document_sel_color'])
self.ui.sel_color_button.setStyleSheet(
"background-color:%s" % self.app.defaults['document_sel_color'])
self.ui.font_size_cb.setCurrentIndex(int(self.app.defaults['document_font_size']))
self.document_editor_tab.handleTextChanged()
self.ser_attrs = ['options', 'kind', 'source_file']
if Qt.mightBeRichText(self.source_file):
self.document_editor_tab.code_editor.setHtml(self.source_file)
else:
for line in self.source_file.splitlines():
self.document_editor_tab.code_editor.append(line)
self.build_ui()
@property
def read_only(self):
return self._read_only
@read_only.setter
def read_only(self, val):
if val:
self._read_only = True
else:
self._read_only = False
def build_ui(self):
FlatCAMObj.build_ui(self)
tab_here = False
# try to not add too many times a tab that it is already installed
for idx in range(self.app.ui.plot_tab_area.count()):
if self.app.ui.plot_tab_area.widget(idx).objectName() == self.options['name']:
tab_here = True
break
# add the tab if it is not already added
if tab_here is False:
self.app.ui.plot_tab_area.addTab(self.document_editor_tab, '%s' % _("Document Editor"))
self.document_editor_tab.setObjectName(self.options['name'])
# Switch plot_area to CNCJob tab
self.app.ui.plot_tab_area.setCurrentWidget(self.document_editor_tab)
def on_autocomplete_changed(self, state):
if state:
self.document_editor_tab.code_editor.completer_enable = True
else:
self.document_editor_tab.code_editor.completer_enable = False
def on_tab_size_change(self, val=None):
try:
self.ui.tab_size_spinner.returnPressed.disconnect(self.on_tab_size_change)
except TypeError:
pass
if val:
self.ui.tab_size_spinner.set_value(val)
tab_balue = int(self.ui.tab_size_spinner.get_value())
self.document_editor_tab.code_editor.setTabStopWidth(tab_balue)
self.app.defaults['document_tab_size'] = tab_balue
self.ui.tab_size_spinner.returnPressed.connect(self.on_tab_size_change)
def on_text_changed(self):
self.source_file = self.document_editor_tab.code_editor.toHtml()
# print(self.source_file)
def font_family(self, font):
# self.document_editor_tab.code_editor.selectAll()
font.setPointSize(float(self.ui.font_size_cb.get_value()))
self.document_editor_tab.code_editor.setCurrentFont(font)
self.font_name = self.ui.font_type_cb.currentFont().family()
def font_size(self):
# self.document_editor_tab.code_editor.selectAll()
self.document_editor_tab.code_editor.setFontPointSize(float(self.ui.font_size_cb.get_value()))
def on_bold_button(self):
if self.ui.font_bold_tb.isChecked():
self.document_editor_tab.code_editor.setFontWeight(QtGui.QFont.Bold)
self.font_bold = True
else:
self.document_editor_tab.code_editor.setFontWeight(QtGui.QFont.Normal)
self.font_bold = False
def on_italic_button(self):
if self.ui.font_italic_tb.isChecked():
self.document_editor_tab.code_editor.setFontItalic(True)
self.font_italic = True
else:
self.document_editor_tab.code_editor.setFontItalic(False)
self.font_italic = False
def on_underline_button(self):
if self.ui.font_under_tb.isChecked():
self.document_editor_tab.code_editor.setFontUnderline(True)
self.font_underline = True
else:
self.document_editor_tab.code_editor.setFontUnderline(False)
self.font_underline = False
# Setting font colors handlers
def on_font_color_entry(self):
self.app.defaults['document_font_color'] = self.ui.font_color_entry.get_value()
self.ui.font_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['document_font_color']))
def on_font_color_button(self):
current_color = QtGui.QColor(self.app.defaults['document_font_color'])
c_dialog = QtWidgets.QColorDialog()
font_color = c_dialog.getColor(initial=current_color)
if font_color.isValid() is False:
return
self.document_editor_tab.code_editor.setTextColor(font_color)
self.ui.font_color_button.setStyleSheet("background-color:%s" % str(font_color.name()))
new_val = str(font_color.name())
self.ui.font_color_entry.set_value(new_val)
self.app.defaults['document_font_color'] = new_val
# Setting selection colors handlers
def on_selection_color_entry(self):
self.app.defaults['document_sel_color'] = self.ui.sel_color_entry.get_value()
self.ui.sel_color_button.setStyleSheet("background-color:%s" % str(self.app.defaults['document_sel_color']))
def on_selection_color_button(self):
current_color = QtGui.QColor(self.app.defaults['document_sel_color'])
c_dialog = QtWidgets.QColorDialog()
sel_color = c_dialog.getColor(initial=current_color)
if sel_color.isValid() is False:
return
p = QtGui.QPalette()
p.setColor(QtGui.QPalette.Highlight, sel_color)
p.setColor(QtGui.QPalette.HighlightedText, QtGui.QColor('white'))
self.document_editor_tab.code_editor.setPalette(p)
self.ui.sel_color_button.setStyleSheet("background-color:%s" % str(sel_color.name()))
new_val = str(sel_color.name())
self.ui.sel_color_entry.set_value(new_val)
self.app.defaults['document_sel_color'] = new_val
def to_dict(self):
"""
Returns a representation of the object as a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
:return: A dictionary-encoded copy of the object.
:rtype: dict
"""
d = {}
for attr in self.ser_attrs:
d[attr] = getattr(self, attr)
return d
def from_dict(self, d):
"""
Sets object's attributes from a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
This method will look only for only and all the
attributes in ``self.ser_attrs``. They must all
be present. Use only for deserializing saved
objects.
:param d: Dictionary of attributes to set in the object.
:type d: dict
:return: None
"""
for attr in self.ser_attrs:
setattr(self, attr, d[attr])

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,505 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
# ##########################################################
# ##########################################################
# File modified by: Marius Stanciu #
# ##########################################################
import inspect # TODO: For debugging only.
from flatcamGUI.ObjectUI import *
from FlatCAMCommon import LoudDict
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
import sys
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
# Interrupts plotting process if FlatCAMObj has been deleted
class ObjectDeleted(Exception):
pass
class ValidationError(Exception):
def __init__(self, message, errors):
super().__init__(message)
self.errors = errors
class FlatCAMObj(QtCore.QObject):
"""
Base type of objects handled in FlatCAM. These become interactive
in the GUI, can be plotted, and their options can be modified
by the user in their respective forms.
"""
# Instance of the application to which these are related.
# The app should set this value.
app = None
# signal to plot a single object
plot_single_object = QtCore.pyqtSignal()
def __init__(self, name):
"""
Constructor.
:param name: Name of the object given by the user.
:return: FlatCAMObj
"""
QtCore.QObject.__init__(self)
# View
self.ui = None
self.options = LoudDict(name=name)
self.options.set_change_callback(self.on_options_change)
self.form_fields = {}
# store here the default data for Geometry Data
self.default_data = {}
# 2D mode
# Axes must exist and be attached to canvas.
self.axes = None
self.kind = None # Override with proper name
if self.app.is_legacy is False:
self.shapes = self.app.plotcanvas.new_shape_group()
# self.shapes = ShapeCollection(parent=self.app.plotcanvas.view.scene, pool=self.app.pool, layers=2)
else:
self.shapes = ShapeCollectionLegacy(obj=self, app=self.app, name=name)
self.mark_shapes = {}
self.item = None # Link with project view item
self.muted_ui = False
self.deleted = False
try:
self._drawing_tolerance = float(self.app.defaults["global_tolerance"]) if \
self.app.defaults["global_tolerance"] else 0.01
except ValueError:
self._drawing_tolerance = 0.01
self.isHovering = False
self.notHovering = True
# Flag to show if a selection shape is drawn
self.selection_shape_drawn = False
# self.units = 'IN'
self.units = self.app.defaults['units']
self.plot_single_object.connect(self.single_object_plot)
def __del__(self):
pass
def __str__(self):
return "<FlatCAMObj({:12s}): {:20s}>".format(self.kind, self.options["name"])
def from_dict(self, d):
"""
This supersedes ``from_dict`` in derived classes. Derived classes
must inherit from FlatCAMObj first, then from derivatives of Geometry.
``self.options`` is only updated, not overwritten. This ensures that
options set by the app do not vanish when reading the objects
from a project file.
:param d: Dictionary with attributes to set.
:return: None
"""
for attr in self.ser_attrs:
if attr == 'options':
self.options.update(d[attr])
else:
try:
setattr(self, attr, d[attr])
except KeyError:
log.debug("FlatCAMObj.from_dict() --> KeyError: %s. "
"Means that we are loading an old project that don't"
"have all attributes in the latest FlatCAM." % str(attr))
pass
def on_options_change(self, key):
# Update form on programmatically options change
self.set_form_item(key)
# Set object visibility
if key == 'plot':
self.visible = self.options['plot']
self.optionChanged.emit(key)
def set_ui(self, ui):
self.ui = ui
self.form_fields = {"name": self.ui.name_entry}
assert isinstance(self.ui, ObjectUI)
self.ui.name_entry.returnPressed.connect(self.on_name_activate)
try:
# it will raise an exception for those FlatCAM objects that do not build UI with the common elements
self.ui.offset_button.clicked.connect(self.on_offset_button_click)
except (TypeError, AttributeError):
pass
try:
self.ui.scale_button.clicked.connect(self.on_scale_button_click)
except (TypeError, AttributeError):
pass
try:
self.ui.offsetvector_entry.returnPressed.connect(self.on_offset_button_click)
except (TypeError, AttributeError):
pass
# Creates problems on focusOut
try:
self.ui.scale_entry.returnPressed.connect(self.on_scale_button_click)
except (TypeError, AttributeError):
pass
# self.ui.skew_button.clicked.connect(self.on_skew_button_click)
def build_ui(self):
"""
Sets up the UI/form for this object. Show the UI
in the App.
:return: None
:rtype: None
"""
self.muted_ui = True
log.debug(str(inspect.stack()[1][3]) + "--> FlatCAMObj.build_ui()")
try:
# HACK: disconnect the scale entry signal since on focus out event will trigger an undesired scale()
# it seems that the takewidget() does generate a focus out event for the QDoubleSpinbox ...
# and reconnect after the takeWidget() is done
# self.ui.scale_entry.returnPressed.disconnect(self.on_scale_button_click)
self.app.ui.selected_scroll_area.takeWidget()
# self.ui.scale_entry.returnPressed.connect(self.on_scale_button_click)
except Exception as e:
self.app.log.debug("FlatCAMObj.build_ui() --> Nothing to remove: %s" % str(e))
self.app.ui.selected_scroll_area.setWidget(self.ui)
# self.ui.setMinimumWidth(100)
# self.ui.setMaximumWidth(self.app.ui.selected_tab.sizeHint().width())
self.muted_ui = False
def on_name_activate(self, silent=None):
old_name = copy(self.options["name"])
new_name = self.ui.name_entry.get_value()
if new_name != old_name:
# update the SHELL auto-completer model data
try:
self.app.myKeywords.remove(old_name)
self.app.myKeywords.append(new_name)
self.app.shell._edit.set_model_data(self.app.myKeywords)
self.app.ui.code_editor.set_model_data(self.app.myKeywords)
except Exception:
log.debug("on_name_activate() --> Could not remove the old object name from auto-completer model list")
self.options["name"] = self.ui.name_entry.get_value()
self.default_data["name"] = self.ui.name_entry.get_value()
self.app.collection.update_view()
if silent:
self.app.inform.emit('[success] %s: %s %s: %s' % (
_("Name changed from"), str(old_name), _("to"), str(new_name)
)
)
def on_offset_button_click(self):
self.app.report_usage("obj_on_offset_button")
self.read_form()
vector_val = self.ui.offsetvector_entry.get_value()
def worker_task():
with self.app.proc_container.new(_("Offsetting...")):
self.offset(vector_val)
self.app.proc_container.update_view_text('')
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
def on_scale_button_click(self):
self.read_form()
try:
factor = float(eval(self.ui.scale_entry.get_value()))
except Exception as e:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Scaling could not be executed."))
log.debug("FlatCAMObj.on_scale_button_click() -- %s" % str(e))
return
if type(factor) != float:
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Scaling could not be executed."))
# if factor is 1.0 do nothing, there is no point in scaling with a factor of 1.0
if factor == 1.0:
self.app.inform.emit('[success] %s' % _("Scale done."))
return
log.debug("FlatCAMObj.on_scale_button_click()")
def worker_task():
with self.app.proc_container.new(_("Scaling...")):
self.scale(factor)
self.app.inform.emit('[success] %s' % _("Scale done."))
self.app.proc_container.update_view_text('')
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
def on_skew_button_click(self):
self.app.report_usage("obj_on_skew_button")
self.read_form()
x_angle = self.ui.xangle_entry.get_value()
y_angle = self.ui.yangle_entry.get_value()
def worker_task():
with self.app.proc_container.new(_("Skewing...")):
self.skew(x_angle, y_angle)
self.app.proc_container.update_view_text('')
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': worker_task, 'params': []})
def to_form(self):
"""
Copies options to the UI form.
:return: None
"""
log.debug(str(inspect.stack()[1][3]) + " --> FlatCAMObj.to_form()")
for option in self.options:
try:
self.set_form_item(option)
except Exception:
self.app.log.warning("Unexpected error:", sys.exc_info())
def read_form(self):
"""
Reads form into ``self.options``.
:return: None
:rtype: None
"""
log.debug(str(inspect.stack()[1][3]) + "--> FlatCAMObj.read_form()")
for option in self.options:
try:
self.read_form_item(option)
except Exception:
self.app.log.warning("Unexpected error:", sys.exc_info())
def set_form_item(self, option):
"""
Copies the specified option to the UI form.
:param option: Name of the option (Key in ``self.options``).
:type option: str
:return: None
"""
try:
self.form_fields[option].set_value(self.options[option])
except KeyError:
# self.app.log.warn("Tried to set an option or field that does not exist: %s" % option)
pass
def read_form_item(self, option):
"""
Reads the specified option from the UI form into ``self.options``.
:param option: Name of the option.
:type option: str
:return: None
"""
try:
self.options[option] = self.form_fields[option].get_value()
except KeyError:
pass
# self.app.log.warning("Failed to read option from field: %s" % option)
def plot(self, kind=None):
"""
Plot this object (Extend this method to implement the actual plotting).
Call this in descendants before doing the plotting.
:param kind: Used by only some of the FlatCAM objects
:return: Whether to continue plotting or not depending on the "plot" option. Boolean
"""
log.debug(str(inspect.stack()[1][3]) + " --> FlatCAMObj.plot()")
if self.deleted:
return False
self.clear()
return True
def single_object_plot(self):
def plot_task():
with self.app.proc_container.new('%s...' % _("Plotting")):
self.plot()
self.app.object_changed.emit(self)
self.app.worker_task.emit({'fcn': plot_task, 'params': []})
def serialize(self):
"""
Returns a representation of the object as a dictionary so
it can be later exported as JSON. Override this method.
:return: Dictionary representing the object
:rtype: dict
"""
return
def deserialize(self, obj_dict):
"""
Re-builds an object from its serialized version.
:param obj_dict: Dictionary representing a FlatCAMObj
:type obj_dict: dict
:return: None
"""
return
def add_shape(self, **kwargs):
if self.deleted:
raise ObjectDeleted()
else:
key = self.shapes.add(tolerance=self.drawing_tolerance, **kwargs)
return key
def add_mark_shape(self, apid, **kwargs):
if self.deleted:
raise ObjectDeleted()
else:
key = self.mark_shapes[apid].add(tolerance=self.drawing_tolerance, layer=0, **kwargs)
return key
def update_filters(self, last_ext, filter_string):
"""
Will modify the filter string that is used when saving a file (a list of file extensions) to have the last
used file extension as the first one in the special string
:param last_ext: The file extension that was last used to save a file
:param filter_string: A key in self.app.defaults that holds a string with the filter from QFileDialog
used when saving a file
:return: None
"""
filters = copy(self.app.defaults[filter_string])
filter_list = filters.split(';;')
filter_list_enum_1 = enumerate(filter_list)
# search for the last element in the filters which should always be "All Files (*.*)"
last_elem = ''
for elem in list(filter_list_enum_1):
if '(*.*)' in elem[1]:
last_elem = filter_list.pop(elem[0])
filter_list_enum = enumerate(filter_list)
for elem in list(filter_list_enum):
if '.' + last_ext in elem[1]:
used_ext = filter_list.pop(elem[0])
# sort the extensions back
filter_list.sort(key=lambda x: x.rpartition('.')[2])
# add as a first element the last used extension
filter_list.insert(0, used_ext)
# add back the element that should always be the last (All Files)
filter_list.append(last_elem)
self.app.defaults[filter_string] = ';;'.join(filter_list)
return
@staticmethod
def poly2rings(poly):
return [poly.exterior] + [interior for interior in poly.interiors]
@property
def visible(self):
return self.shapes.visible
@visible.setter
def visible(self, value, threaded=True):
log.debug("FlatCAMObj.visible()")
def worker_task(app_obj):
self.shapes.visible = value
if self.app.is_legacy is False:
# Not all object types has annotations
try:
self.annotation.visible = value
except Exception:
pass
if threaded is False:
worker_task(app_obj=self.app)
else:
self.app.worker_task.emit({'fcn': worker_task, 'params': [self]})
@property
def drawing_tolerance(self):
self.units = self.app.defaults['units'].upper()
tol = self._drawing_tolerance if self.units == 'MM' or not self.units else self._drawing_tolerance / 25.4
return tol
@drawing_tolerance.setter
def drawing_tolerance(self, value):
self.units = self.app.defaults['units'].upper()
self._drawing_tolerance = value if self.units == 'MM' or not self.units else value / 25.4
def clear(self, update=False):
self.shapes.clear(update)
# Not all object types has annotations
try:
self.annotation.clear(update)
except AttributeError:
pass
def delete(self):
# Free resources
del self.ui
del self.options
# Set flag
self.deleted = True

View File

@ -0,0 +1,231 @@
# ##########################################################
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
# ##########################################################
# ##########################################################
# File modified by: Marius Stanciu #
# ##########################################################
from flatcamEditors.FlatCAMTextEditor import TextEditor
from flatcamObjects.FlatCAMObj import *
from flatcamGUI.ObjectUI import *
import tkinter as tk
import sys
from copy import deepcopy
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__:
_ = gettext.gettext
class ScriptObject(FlatCAMObj):
"""
Represents a TCL script object.
"""
optionChanged = QtCore.pyqtSignal(str)
ui_type = ScriptObjectUI
def __init__(self, name):
self.decimals = self.app.decimals
log.debug("Creating a ScriptObject object...")
FlatCAMObj.__init__(self, name)
self.kind = "script"
self.options.update({
"plot": True,
"type": 'Script',
"source_file": '',
})
self.units = ''
self.ser_attrs = ['options', 'kind', 'source_file']
self.source_file = ''
self.script_code = ''
self.units_found = self.app.defaults['units']
# self.script_editor_tab = TextEditor(app=self.app, plain_text=True)
self.script_editor_tab = TextEditor(app=self.app, plain_text=True)
def set_ui(self, ui):
"""
Sets the Object UI in Selected Tab for the FlatCAM Script type of object.
:param ui:
:return:
"""
FlatCAMObj.set_ui(self, ui)
log.debug("ScriptObject.set_ui()")
assert isinstance(self.ui, ScriptObjectUI), \
"Expected a ScriptObjectUI, got %s" % type(self.ui)
self.units = self.app.defaults['units'].upper()
self.units_found = self.app.defaults['units']
# Fill form fields only on object create
self.to_form()
# Show/Hide Advanced Options
if self.app.defaults["global_app_level"] == 'b':
self.ui.level.setText(_(
'<span style="color:green;"><b>Basic</b></span>'
))
else:
self.ui.level.setText(_(
'<span style="color:red;"><b>Advanced</b></span>'
))
# tab_here = False
# # try to not add too many times a tab that it is already installed
# for idx in range(self.app.ui.plot_tab_area.count()):
# if self.app.ui.plot_tab_area.widget(idx).objectName() == self.options['name']:
# tab_here = True
# break
#
# # add the tab if it is not already added
# if tab_here is False:
# self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
# self.script_editor_tab.setObjectName(self.options['name'])
self.app.ui.plot_tab_area.addTab(self.script_editor_tab, '%s' % _("Script Editor"))
self.script_editor_tab.setObjectName(self.options['name'])
# first clear previous text in text editor (if any)
# self.script_editor_tab.code_editor.clear()
# self.script_editor_tab.code_editor.setReadOnly(False)
self.ui.autocomplete_cb.set_value(self.app.defaults['script_autocompleter'])
self.on_autocomplete_changed(state=self.app.defaults['script_autocompleter'])
self.script_editor_tab.buttonRun.show()
# Switch plot_area to CNCJob tab
self.app.ui.plot_tab_area.setCurrentWidget(self.script_editor_tab)
flt = "FlatCAM Scripts (*.FlatScript);;All Files (*.*)"
self.script_editor_tab.buttonOpen.clicked.disconnect()
self.script_editor_tab.buttonOpen.clicked.connect(lambda: self.script_editor_tab.handleOpen(filt=flt))
self.script_editor_tab.buttonSave.clicked.disconnect()
self.script_editor_tab.buttonSave.clicked.connect(lambda: self.script_editor_tab.handleSaveGCode(filt=flt))
self.script_editor_tab.buttonRun.clicked.connect(self.handle_run_code)
self.script_editor_tab.handleTextChanged()
self.ui.autocomplete_cb.stateChanged.connect(self.on_autocomplete_changed)
self.ser_attrs = ['options', 'kind', 'source_file']
# ---------------------------------------------------- #
# ----------- LOAD THE TEXT SOURCE FILE -------------- #
# ---------------------------------------------------- #
self.app.proc_container.view.set_busy(_("Loading..."))
self.script_editor_tab.t_frame.hide()
try:
self.script_editor_tab.code_editor.setPlainText(self.source_file)
# for line in self.source_file.splitlines():
# QtWidgets.QApplication.processEvents()
# self.script_editor_tab.code_editor.append(line)
except Exception as e:
log.debug("ScriptObject.set_ui() --> %s" % str(e))
self.script_editor_tab.code_editor.moveCursor(QtGui.QTextCursor.End)
self.script_editor_tab.t_frame.show()
self.app.proc_container.view.set_idle()
self.build_ui()
def build_ui(self):
FlatCAMObj.build_ui(self)
def handle_run_code(self):
# trying to run a Tcl command without having the Shell open will create some warnings because the Tcl Shell
# tries to print on a hidden widget, therefore show the dock if hidden
if self.app.ui.shell_dock.isHidden():
self.app.ui.shell_dock.show()
self.script_code = deepcopy(self.script_editor_tab.code_editor.toPlainText())
old_line = ''
for tcl_command_line in self.script_code.splitlines():
# do not process lines starting with '#' = comment and empty lines
if not tcl_command_line.startswith('#') and tcl_command_line != '':
# id FlatCAM is run in Windows then replace all the slashes with
# the UNIX style slash that TCL understands
if sys.platform == 'win32':
if "open" in tcl_command_line:
tcl_command_line = tcl_command_line.replace('\\', '/')
if old_line != '':
new_command = old_line + tcl_command_line + '\n'
else:
new_command = tcl_command_line
# execute the actual Tcl command
try:
self.app.shell.open_processing() # Disables input box.
result = self.app.tcl.eval(str(new_command))
if result != 'None':
self.app.shell.append_output(result + '\n')
old_line = ''
except tk.TclError:
old_line = old_line + tcl_command_line + '\n'
except Exception as e:
log.debug("ScriptObject.handleRunCode() --> %s" % str(e))
if old_line != '':
# it means that the script finished with an error
result = self.app.tcl.eval("set errorInfo")
log.error("Exec command Exception: %s" % (result + '\n'))
self.app.shell.append_error('ERROR: ' + result + '\n')
self.app.shell.close_processing()
def on_autocomplete_changed(self, state):
if state:
self.script_editor_tab.code_editor.completer_enable = True
else:
self.script_editor_tab.code_editor.completer_enable = False
def to_dict(self):
"""
Returns a representation of the object as a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
:return: A dictionary-encoded copy of the object.
:rtype: dict
"""
d = {}
for attr in self.ser_attrs:
d[attr] = getattr(self, attr)
return d
def from_dict(self, d):
"""
Sets object's attributes from a dictionary.
Attributes to include are listed in ``self.ser_attrs``.
This method will look only for only and all the
attributes in ``self.ser_attrs``. They must all
be present. Use only for deserializing saved
objects.
:param d: Dictionary of attributes to set in the object.
:type d: dict
:return: None
"""
for attr in self.ser_attrs:
setattr(self, attr, d[attr])

View File

View File

@ -7,7 +7,6 @@
# ########################################################## ## # ########################################################## ##
from camlib import Geometry from camlib import Geometry
import FlatCAMApp
import shapely.affinity as affinity import shapely.affinity as affinity
from shapely.geometry import Point, LineString from shapely.geometry import Point, LineString
@ -19,6 +18,7 @@ import traceback
from copy import deepcopy from copy import deepcopy
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
from FlatCAMCommon import GracefulException as grace
import gettext import gettext
import builtins import builtins
@ -86,6 +86,7 @@ class Excellon(Geometry):
:return: Excellon object. :return: Excellon object.
:rtype: Excellon :rtype: Excellon
""" """
self.decimals = self.app.decimals self.decimals = self.app.decimals
if geo_steps_per_circle is None: if geo_steps_per_circle is None:
@ -241,12 +242,12 @@ class Excellon(Geometry):
def parse_file(self, filename=None, file_obj=None): def parse_file(self, filename=None, file_obj=None):
""" """
Reads the specified file as array of lines as Reads the specified file as array of lines as passes it to ``parse_lines()``.
passes it to ``parse_lines()``.
:param filename: The file to be read and parsed. :param filename: The file to be read and parsed.
:type filename: str :param file_obj:
:return: None :type filename: str
:return: None
""" """
if file_obj: if file_obj:
estr = file_obj estr = file_obj
@ -298,7 +299,7 @@ class Excellon(Geometry):
for eline in elines: for eline in elines:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
line_num += 1 line_num += 1
# log.debug("%3d %s" % (line_num, str(eline))) # log.debug("%3d %s" % (line_num, str(eline)))
@ -526,7 +527,7 @@ class Excellon(Geometry):
slot_dia = 0.05 slot_dia = 0.05
try: try:
slot_dia = float(self.tools[current_tool]['C']) slot_dia = float(self.tools[current_tool]['C'])
except Exception as e: except Exception:
pass pass
log.debug( log.debug(
'Milling/Drilling slot with tool %s, diam=%f' % ( 'Milling/Drilling slot with tool %s, diam=%f' % (
@ -596,7 +597,7 @@ class Excellon(Geometry):
slot_dia = 0.05 slot_dia = 0.05
try: try:
slot_dia = float(self.tools[current_tool]['C']) slot_dia = float(self.tools[current_tool]['C'])
except Exception as e: except Exception:
pass pass
log.debug( log.debug(
'Milling/Drilling slot with tool %s, diam=%f' % ( 'Milling/Drilling slot with tool %s, diam=%f' % (
@ -893,9 +894,8 @@ class Excellon(Geometry):
log.info("Zeros: %s, Units %s." % (self.zeros, self.units)) log.info("Zeros: %s, Units %s." % (self.zeros, self.units))
except Exception: except Exception:
log.error("Excellon PARSING FAILED. Line %d: %s" % (line_num, eline)) log.error("Excellon PARSING FAILED. Line %d: %s" % (line_num, eline))
msg = '[ERROR_NOTCL] %s' % \ msg = '[ERROR_NOTCL] %s' % _("An internal error has occurred. See shell.\n")
_("An internal error has ocurred. See shell.\n") msg += '{e_code} {tx} {l_nr}: {line}\n'.format(
msg += ('{e_code} {tx} {l_nr}: {line}\n').format(
e_code='[ERROR]', e_code='[ERROR]',
tx=_("Excellon Parser error.\nParsing Failed. Line"), tx=_("Excellon Parser error.\nParsing Failed. Line"),
l_nr=line_num, l_nr=line_num,
@ -1010,13 +1010,13 @@ class Excellon(Geometry):
"Excellon geometry creation failed due of ERROR: %s" % str(e)) "Excellon geometry creation failed due of ERROR: %s" % str(e))
return "fail" return "fail"
def bounds(self): def bounds(self, flatten=None):
""" """
Returns coordinates of rectangular bounds Returns coordinates of rectangular bounds
of Excellon geometry: (xmin, ymin, xmax, ymax). of Excellon geometry: (xmin, ymin, xmax, ymax).
:param flatten: No used
""" """
# fixed issue of getting bounds only for one level lists of objects
# now it can get bounds for nested lists of objects
log.debug("flatcamParsers.ParseExcellon.Excellon.bounds()") log.debug("flatcamParsers.ParseExcellon.Excellon.bounds()")
@ -1056,11 +1056,11 @@ class Excellon(Geometry):
maxy_list = [] maxy_list = []
for tool in self.tools: for tool in self.tools:
minx, miny, maxx, maxy = bounds_rec(self.tools[tool]['solid_geometry']) eminx, eminy, emaxx, emaxy = bounds_rec(self.tools[tool]['solid_geometry'])
minx_list.append(minx) minx_list.append(eminx)
miny_list.append(miny) miny_list.append(eminy)
maxx_list.append(maxx) maxx_list.append(emaxx)
maxy_list.append(maxy) maxy_list.append(emaxy)
return min(minx_list), min(miny_list), max(maxx_list), max(maxy_list) return min(minx_list), min(miny_list), max(maxx_list), max(maxy_list)
@ -1075,8 +1075,9 @@ class Excellon(Geometry):
Kind of convolute way to make the conversion and it is based on the assumption that the Excellon file Kind of convolute way to make the conversion and it is based on the assumption that the Excellon file
will have detected the units before the tools are parsed and stored in self.tools will have detected the units before the tools are parsed and stored in self.tools
:param units:
:type str: IN or MM :param units: 'IN' or 'MM'. String
:return: :return:
""" """
@ -1109,12 +1110,13 @@ class Excellon(Geometry):
Scales geometry on the XY plane in the object by a given factor. Scales geometry on the XY plane in the object by a given factor.
Tool sizes, feedrates an Z-plane dimensions are untouched. Tool sizes, feedrates an Z-plane dimensions are untouched.
:param xfactor: Number by which to scale the object. :param xfactor: Number by which to scale the object.
:type xfactor: float :type xfactor: float
:param yfactor: Number by which to scale the object. :param yfactor: Number by which to scale the object.
:type yfactor: float :type yfactor: float
:return: None :param point: Origin point for scale
:rtype: NOne :return: None
:rtype: None
""" """
log.debug("flatcamParsers.ParseExcellon.Excellon.scale()") log.debug("flatcamParsers.ParseExcellon.Excellon.scale()")
@ -1145,8 +1147,7 @@ class Excellon(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for g in self.drills: self.geo_len = len(self.drills)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
self.old_disp_number = 0 self.old_disp_number = 0
@ -1190,12 +1191,12 @@ class Excellon(Geometry):
return return
def offset_geom(obj): def offset_geom(obj):
if type(obj) is list: try:
new_obj = [] new_obj = []
for g in obj: for geo in obj:
new_obj.append(offset_geom(g)) new_obj.append(offset_geom(geo))
return new_obj return new_obj
else: except TypeError:
try: try:
return affinity.translate(obj, xoff=dx, yoff=dy) return affinity.translate(obj, xoff=dx, yoff=dy)
except AttributeError: except AttributeError:
@ -1204,8 +1205,7 @@ class Excellon(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for g in self.drills: self.geo_len = len(self.drills)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
self.old_disp_number = 0 self.old_disp_number = 0
@ -1237,11 +1237,11 @@ class Excellon(Geometry):
def mirror(self, axis, point): def mirror(self, axis, point):
""" """
:param axis: "X" or "Y" indicates around which axis to mirror. :param axis: "X" or "Y" indicates around which axis to mirror.
:type axis: str :type axis: str
:param point: [x, y] point belonging to the mirror axis. :param point: [x, y] point belonging to the mirror axis.
:type point: list :type point: list
:return: None :return: None
""" """
log.debug("flatcamParsers.ParseExcellon.Excellon.mirror()") log.debug("flatcamParsers.ParseExcellon.Excellon.mirror()")
@ -1249,12 +1249,12 @@ class Excellon(Geometry):
xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis] xscale, yscale = {"X": (1.0, -1.0), "Y": (-1.0, 1.0)}[axis]
def mirror_geom(obj): def mirror_geom(obj):
if type(obj) is list: try:
new_obj = [] new_obj = []
for g in obj: for geo in obj:
new_obj.append(mirror_geom(g)) new_obj.append(mirror_geom(geo))
return new_obj return new_obj
else: except TypeError:
try: try:
return affinity.scale(obj, xscale, yscale, origin=(px, py)) return affinity.scale(obj, xscale, yscale, origin=(px, py))
except AttributeError: except AttributeError:
@ -1265,8 +1265,7 @@ class Excellon(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for g in self.drills: self.geo_len = len(self.drills)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
self.old_disp_number = 0 self.old_disp_number = 0
@ -1300,12 +1299,12 @@ class Excellon(Geometry):
Shear/Skew the geometries of an object by angles along x and y dimensions. Shear/Skew the geometries of an object by angles along x and y dimensions.
Tool sizes, feedrates an Z-plane dimensions are untouched. Tool sizes, feedrates an Z-plane dimensions are untouched.
Parameters :param angle_x:
---------- :param angle_y:
xs, ys : float, float
The shear angle(s) for the x and y axes respectively. These can be The shear angle(s) for the x and y axes respectively. These can be
specified in either degrees (default) or radians by setting specified in either degrees (default) or radians by setting
use_radians=True. use_radians=True.
:param point: Origin point for Skew
See shapely manual for more information: See shapely manual for more information:
http://toblerity.org/shapely/manual.html#affine-transformations http://toblerity.org/shapely/manual.html#affine-transformations
@ -1322,12 +1321,12 @@ class Excellon(Geometry):
return return
def skew_geom(obj): def skew_geom(obj):
if type(obj) is list: try:
new_obj = [] new_obj = []
for g in obj: for g in obj:
new_obj.append(skew_geom(g)) new_obj.append(skew_geom(g))
return new_obj return new_obj
else: except TypeError:
try: try:
return affinity.skew(obj, angle_x, angle_y, origin=(px, py)) return affinity.skew(obj, angle_x, angle_y, origin=(px, py))
except AttributeError: except AttributeError:
@ -1336,8 +1335,7 @@ class Excellon(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for g in self.drills: self.geo_len = len(self.drills)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
self.old_disp_number = 0 self.old_disp_number = 0
@ -1393,9 +1391,10 @@ class Excellon(Geometry):
def rotate(self, angle, point=None): def rotate(self, angle, point=None):
""" """
Rotate the geometry of an object by an angle around the 'point' coordinates Rotate the geometry of an object by an angle around the 'point' coordinates
:param angle: :param angle:
:param point: tuple of coordinates (x, y) :param point: tuple of coordinates (x, y)
:return: :return: None
""" """
log.debug("flatcamParsers.ParseExcellon.Excellon.rotate()") log.debug("flatcamParsers.ParseExcellon.Excellon.rotate()")
@ -1423,8 +1422,7 @@ class Excellon(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for g in self.drills: self.geo_len = len(self.drills)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
self.old_disp_number = 0 self.old_disp_number = 0
@ -1476,9 +1474,10 @@ class Excellon(Geometry):
def buffer(self, distance, join, factor): def buffer(self, distance, join, factor):
""" """
:param distance: if 'factor' is True then distance is the factor :param distance: if 'factor' is True then distance is the factor
:param factor: True or False (None) :param factor: True or False (None)
:return: :param join: The type of line joint used by the shapely buffer method: round, square, bevel
:return: None
""" """
log.debug("flatcamParsers.ParseExcellon.Excellon.buffer()") log.debug("flatcamParsers.ParseExcellon.Excellon.buffer()")
@ -1486,12 +1485,12 @@ class Excellon(Geometry):
return return
def buffer_geom(obj): def buffer_geom(obj):
if type(obj) is list: try:
new_obj = [] new_obj = []
for g in obj: for g in obj:
new_obj.append(buffer_geom(g)) new_obj.append(buffer_geom(g))
return new_obj return new_obj
else: except TypeError:
try: try:
if factor is None: if factor is None:
return obj.buffer(distance, resolution=self.geo_steps_per_circle) return obj.buffer(distance, resolution=self.geo_steps_per_circle)

View File

@ -1,6 +1,5 @@
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from camlib import Geometry, arc, arc_angle, ApertureMacro from camlib import Geometry, arc, arc_angle, ApertureMacro
import FlatCAMApp
import numpy as np import numpy as np
import re import re
@ -9,15 +8,16 @@ import traceback
from copy import deepcopy from copy import deepcopy
import sys import sys
from shapely.ops import cascaded_union, unary_union from shapely.ops import cascaded_union
from shapely.geometry import Polygon, MultiPolygon, LineString, Point from shapely.affinity import scale, translate
import shapely.affinity as affinity import shapely.affinity as affinity
from shapely.geometry import box as shply_box from shapely.geometry import box as shply_box, Polygon, LineString, Point, MultiPolygon
from lxml import etree as ET from lxml import etree as ET
from flatcamParsers.ParseSVG import * from flatcamParsers.ParseSVG import svgparselength, getsvggeo
from FlatCAMCommon import GracefulException as grace
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import gettext import gettext
import builtins import builtins
@ -255,7 +255,7 @@ class Gerber(Geometry):
""" """
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# Found some Gerber with a leading zero in the aperture id and the # Found some Gerber with a leading zero in the aperture id and the
# referenced it without the zero, so this is a hack to handle that. # referenced it without the zero, so this is a hack to handle that.
@ -403,7 +403,7 @@ class Gerber(Geometry):
# Absolute or Relative/Incremental coordinates # Absolute or Relative/Incremental coordinates
# Not implemented # Not implemented
absolute = True # absolute = True
# How to interpret circular interpolation: SINGLE or MULTI # How to interpret circular interpolation: SINGLE or MULTI
quadrant_mode = None quadrant_mode = None
@ -428,7 +428,7 @@ class Gerber(Geometry):
for gline in glines: for gline in glines:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
line_num += 1 line_num += 1
self.source_file += gline + '\n' self.source_file += gline + '\n'
@ -986,7 +986,7 @@ class Gerber(Geometry):
if 'geometry' not in self.apertures[current_aperture]: if 'geometry' not in self.apertures[current_aperture]:
self.apertures[current_aperture]['geometry'] = [] self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict)) self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
except Exception as e: except Exception:
pass pass
last_path_aperture = current_aperture last_path_aperture = current_aperture
# we do this for the case that a region is done without having defined any aperture # we do this for the case that a region is done without having defined any aperture
@ -1229,25 +1229,25 @@ class Gerber(Geometry):
try: try:
circular_x = parse_gerber_number(circular_x, circular_x = parse_gerber_number(circular_x,
self.int_digits, self.frac_digits, self.gerber_zeros) self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e: except Exception:
circular_x = current_x circular_x = current_x
try: try:
circular_y = parse_gerber_number(circular_y, circular_y = parse_gerber_number(circular_y,
self.int_digits, self.frac_digits, self.gerber_zeros) self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e: except Exception:
circular_y = current_y circular_y = current_y
# According to Gerber specification i and j are not modal, which means that when i or j are missing, # According to Gerber specification i and j are not modal, which means that when i or j are missing,
# they are to be interpreted as being zero # they are to be interpreted as being zero
try: try:
i = parse_gerber_number(i, self.int_digits, self.frac_digits, self.gerber_zeros) i = parse_gerber_number(i, self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e: except Exception:
i = 0 i = 0
try: try:
j = parse_gerber_number(j, self.int_digits, self.frac_digits, self.gerber_zeros) j = parse_gerber_number(j, self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e: except Exception:
j = 0 j = 0
if quadrant_mode is None: if quadrant_mode is None:
@ -1668,13 +1668,14 @@ class Gerber(Geometry):
bbox = bbox.envelope bbox = bbox.envelope
return bbox return bbox
def bounds(self): def bounds(self, flatten=None):
""" """
Returns coordinates of rectangular bounds Returns coordinates of rectangular bounds
of Gerber geometry: (xmin, ymin, xmax, ymax). of Gerber geometry: (xmin, ymin, xmax, ymax).
:param flatten: Not used, it is here for compatibility with base class method
:return: None
""" """
# fixed issue of getting bounds only for one level lists of objects
# now it can get bounds for nested lists of objects
log.debug("parseGerber.Gerber.bounds()") log.debug("parseGerber.Gerber.bounds()")
@ -1999,8 +2000,7 @@ class Gerber(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for __ in self.solid_geometry: self.geo_len = len(self.solid_geometry)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
@ -2078,8 +2078,7 @@ class Gerber(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for __ in self.solid_geometry: self.geo_len = len(self.solid_geometry)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
@ -2217,8 +2216,7 @@ class Gerber(Geometry):
# variables to display the percentage of work done # variables to display the percentage of work done
self.geo_len = 0 self.geo_len = 0
try: try:
for __ in self.solid_geometry: self.geo_len = len(self.solid_geometry)
self.geo_len += 1
except TypeError: except TypeError:
self.geo_len = 1 self.geo_len = 1
@ -2266,8 +2264,9 @@ class Gerber(Geometry):
def buffer(self, distance, join, factor=None): def buffer(self, distance, join, factor=None):
""" """
:param distance: if 'factor' is True then distance is the factor :param distance: If 'factor' is True then distance is the factor
:param factor: True or False (None) :param join: The type of joining used by the Shapely buffer method. Can be: round, square and bevel
:param factor: True or False (None)
:return: :return:
""" """
log.debug("parseGerber.Gerber.buffer()") log.debug("parseGerber.Gerber.buffer()")

View File

@ -7,7 +7,6 @@
# ############################################################ # ############################################################
from camlib import arc, three_point_circle from camlib import arc, three_point_circle
import FlatCAMApp
import numpy as np import numpy as np
import re import re
@ -19,6 +18,7 @@ import sys
from shapely.ops import unary_union from shapely.ops import unary_union
from shapely.geometry import LineString, Point from shapely.geometry import LineString, Point
from FlatCAMCommon import GracefulException as grace
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import gettext import gettext
import builtins import builtins
@ -180,7 +180,7 @@ class HPGL2:
for gline in glines: for gline in glines:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
line_num += 1 line_num += 1
self.source_file += gline + '\n' self.source_file += gline + '\n'
@ -304,7 +304,7 @@ class HPGL2:
(_("Coordinates missing, line ignored"), str(gline))) (_("Coordinates missing, line ignored"), str(gline)))
if current_x is not None and current_y is not None: if current_x is not None and current_y is not None:
radius = match.group(1) radius = float(match.group(1))
geo = Point((current_x, current_y)).buffer(radius, int(self.steps_per_circle)) geo = Point((current_x, current_y)).buffer(radius, int(self.steps_per_circle))
geo_line = geo.exterior geo_line = geo.exterior
self.tools[current_tool]['solid_geometry'].append(geo_line) self.tools[current_tool]['solid_geometry'].append(geo_line)

View File

@ -382,7 +382,7 @@ class AlignObjects(FlatCAMTool):
def check_points(self): def check_points(self):
if len(self.clicked_points) == 1: if len(self.clicked_points) == 1:
self.app.inform.emit('%s: %s. %s' % ( self.app.inform.emit('%s: %s. %s' % (
_("First Point"), _("Click on the DESTINATION point."), _(" Or right click to cancel."))) _("First Point"), _("Click on the DESTINATION point."), _("Or right click to cancel.")))
self.target_obj = self.aligner_obj self.target_obj = self.aligner_obj
self.reset_color() self.reset_color()
self.set_color() self.set_color()
@ -397,14 +397,14 @@ class AlignObjects(FlatCAMTool):
return return
else: else:
self.app.inform.emit('%s: %s. %s' % ( self.app.inform.emit('%s: %s. %s' % (
_("Second Point"), _("Click on the START point."), _(" Or right click to cancel."))) _("Second Point"), _("Click on the START point."), _("Or right click to cancel.")))
self.target_obj = self.aligned_obj self.target_obj = self.aligned_obj
self.reset_color() self.reset_color()
self.set_color() self.set_color()
if len(self.clicked_points) == 3: if len(self.clicked_points) == 3:
self.app.inform.emit('%s: %s. %s' % ( self.app.inform.emit('%s: %s. %s' % (
_("Second Point"), _("Click on the DESTINATION point."), _(" Or right click to cancel."))) _("Second Point"), _("Click on the DESTINATION point."), _("Or right click to cancel.")))
self.target_obj = self.aligner_obj self.target_obj = self.aligner_obj
self.reset_color() self.reset_color()
self.set_color() self.set_color()

View File

@ -7,10 +7,9 @@
from PyQt5 import QtWidgets, QtCore from PyQt5 import QtWidgets, QtCore
import FlatCAMApp from FlatCAMCommon import GracefulException as grace
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, FCEntry, FCComboBox from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, FCEntry, FCComboBox
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon
import shapely.geometry.base as base import shapely.geometry.base as base
from shapely.ops import cascaded_union, unary_union from shapely.ops import cascaded_union, unary_union
@ -994,7 +993,7 @@ class ToolCopperThieving(FlatCAMTool):
for pol in app_obj.grb_object.solid_geometry: for pol in app_obj.grb_object.solid_geometry:
if app_obj.app.abort_flag: if app_obj.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
clearance_geometry.append( clearance_geometry.append(
pol.buffer(c_val, int(int(app_obj.geo_steps_per_circle) / 4)) pol.buffer(c_val, int(int(app_obj.geo_steps_per_circle) / 4))
@ -1073,7 +1072,7 @@ class ToolCopperThieving(FlatCAMTool):
for poly in working_obj: for poly in working_obj:
if app_obj.app.abort_flag: if app_obj.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)) geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
except TypeError: except TypeError:
geo_buff_list.append(working_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)) geo_buff_list.append(working_obj.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
@ -1082,7 +1081,7 @@ class ToolCopperThieving(FlatCAMTool):
else: # ref_selected == 'box' else: # ref_selected == 'box'
geo_n = working_obj.solid_geometry geo_n = working_obj.solid_geometry
if isinstance(working_obj, FlatCAMGeometry): if working_obj.kind == 'geometry':
try: try:
__ = iter(geo_n) __ = iter(geo_n)
except Exception as e: except Exception as e:
@ -1093,11 +1092,11 @@ class ToolCopperThieving(FlatCAMTool):
for poly in geo_n: for poly in geo_n:
if app_obj.app.abort_flag: if app_obj.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)) geo_buff_list.append(poly.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre))
bounding_box = cascaded_union(geo_buff_list) bounding_box = cascaded_union(geo_buff_list)
elif isinstance(working_obj, FlatCAMGerber): elif working_obj.kind == 'gerber':
geo_n = cascaded_union(geo_n).convex_hull geo_n = cascaded_union(geo_n).convex_hull
bounding_box = cascaded_union(thieving_obj.solid_geometry).convex_hull.intersection(geo_n) bounding_box = cascaded_union(thieving_obj.solid_geometry).convex_hull.intersection(geo_n)
bounding_box = bounding_box.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre) bounding_box = bounding_box.buffer(distance=margin, join_style=base.JOIN_STYLE.mitre)
@ -1192,7 +1191,7 @@ class ToolCopperThieving(FlatCAMTool):
for pol in app_obj.grb_object.solid_geometry: for pol in app_obj.grb_object.solid_geometry:
if app_obj.app.abort_flag: if app_obj.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
outline_geometry.append( outline_geometry.append(
pol.buffer(c_val+half_thick_line, int(int(app_obj.geo_steps_per_circle) / 4)) pol.buffer(c_val+half_thick_line, int(int(app_obj.geo_steps_per_circle) / 4))

View File

@ -8,7 +8,6 @@
from PyQt5 import QtWidgets, QtGui, QtCore from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, OptionalInputSection, FCButton from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox, OptionalInputSection, FCButton
from FlatCAMObj import FlatCAMGerber
from shapely.geometry import box, MultiPolygon, Polygon, LineString, LinearRing from shapely.geometry import box, MultiPolygon, Polygon, LineString, LinearRing
from shapely.ops import cascaded_union, unary_union from shapely.ops import cascaded_union, unary_union
@ -270,7 +269,7 @@ class CutOut(FlatCAMTool):
form_layout_2.addRow(gaps_label, self.gaps) form_layout_2.addRow(gaps_label, self.gaps)
# Buttons # Buttons
self.ff_cutout_object_btn = QtWidgets.QPushButton(_("Generate Freeform Geometry")) self.ff_cutout_object_btn = FCButton(_("Generate Freeform Geometry"))
self.ff_cutout_object_btn.setToolTip( self.ff_cutout_object_btn.setToolTip(
_("Cutout the selected object.\n" _("Cutout the selected object.\n"
"The cutout shape can be of any shape.\n" "The cutout shape can be of any shape.\n"
@ -284,7 +283,7 @@ class CutOut(FlatCAMTool):
""") """)
grid0.addWidget(self.ff_cutout_object_btn, 20, 0, 1, 2) grid0.addWidget(self.ff_cutout_object_btn, 20, 0, 1, 2)
self.rect_cutout_object_btn = QtWidgets.QPushButton(_("Generate Rectangular Geometry")) self.rect_cutout_object_btn = FCButton(_("Generate Rectangular Geometry"))
self.rect_cutout_object_btn.setToolTip( self.rect_cutout_object_btn.setToolTip(
_("Cutout the selected object.\n" _("Cutout the selected object.\n"
"The resulting cutout shape is\n" "The resulting cutout shape is\n"
@ -335,7 +334,7 @@ class CutOut(FlatCAMTool):
# form_layout_3.addRow(e_lab_0) # form_layout_3.addRow(e_lab_0)
self.man_geo_creation_btn = QtWidgets.QPushButton(_("Generate Manual Geometry")) self.man_geo_creation_btn = FCButton(_("Generate Manual Geometry"))
self.man_geo_creation_btn.setToolTip( self.man_geo_creation_btn.setToolTip(
_("If the object to be cutout is a Gerber\n" _("If the object to be cutout is a Gerber\n"
"first create a Geometry that surrounds it,\n" "first create a Geometry that surrounds it,\n"
@ -350,7 +349,7 @@ class CutOut(FlatCAMTool):
""") """)
grid0.addWidget(self.man_geo_creation_btn, 24, 0, 1, 2) grid0.addWidget(self.man_geo_creation_btn, 24, 0, 1, 2)
self.man_gaps_creation_btn = QtWidgets.QPushButton(_("Manual Add Bridge Gaps")) self.man_gaps_creation_btn = FCButton(_("Manual Add Bridge Gaps"))
self.man_gaps_creation_btn.setToolTip( self.man_gaps_creation_btn.setToolTip(
_("Use the left mouse button (LMB) click\n" _("Use the left mouse button (LMB) click\n"
"to create a bridge gap to separate the PCB from\n" "to create a bridge gap to separate the PCB from\n"
@ -369,7 +368,7 @@ class CutOut(FlatCAMTool):
self.layout.addStretch() self.layout.addStretch()
# ## Reset Tool # ## Reset Tool
self.reset_button = QtWidgets.QPushButton(_("Reset Tool")) self.reset_button = FCButton(_("Reset Tool"))
self.reset_button.setToolTip( self.reset_button.setToolTip(
_("Will reset the tool parameters.") _("Will reset the tool parameters.")
) )
@ -525,7 +524,7 @@ class CutOut(FlatCAMTool):
def geo_init(geo_obj, app_obj): def geo_init(geo_obj, app_obj):
solid_geo = [] solid_geo = []
if isinstance(cutout_obj, FlatCAMGerber): if cutout_obj.kind == 'gerber':
if isinstance(cutout_obj.solid_geometry, list): if isinstance(cutout_obj.solid_geometry, list):
cutout_obj.solid_geometry = MultiPolygon(cutout_obj.solid_geometry) cutout_obj.solid_geometry = MultiPolygon(cutout_obj.solid_geometry)
@ -542,12 +541,12 @@ class CutOut(FlatCAMTool):
def cutout_handler(geom): def cutout_handler(geom):
# Get min and max data for each object as we just cut rectangles across X or Y # Get min and max data for each object as we just cut rectangles across X or Y
xmin, ymin, xmax, ymax = recursive_bounds(geom) xxmin, yymin, xxmax, yymax = recursive_bounds(geom)
px = 0.5 * (xmin + xmax) + margin px = 0.5 * (xxmin + xxmax) + margin
py = 0.5 * (ymin + ymax) + margin py = 0.5 * (yymin + yymax) + margin
lenx = (xmax - xmin) + (margin * 2) lenx = (xxmax - xxmin) + (margin * 2)
leny = (ymax - ymin) + (margin * 2) leny = (yymax - yymin) + (margin * 2)
proc_geometry = [] proc_geometry = []
if gaps == 'None': if gaps == 'None':
@ -555,41 +554,41 @@ class CutOut(FlatCAMTool):
else: else:
if gaps == '8' or gaps == '2LR': if gaps == '8' or gaps == '2LR':
geom = self.subtract_poly_from_geo(geom, geom = self.subtract_poly_from_geo(geom,
xmin - gapsize, # botleft_x xxmin - gapsize, # botleft_x
py - gapsize + leny / 4, # botleft_y py - gapsize + leny / 4, # botleft_y
xmax + gapsize, # topright_x xxmax + gapsize, # topright_x
py + gapsize + leny / 4) # topright_y py + gapsize + leny / 4) # topright_y
geom = self.subtract_poly_from_geo(geom, geom = self.subtract_poly_from_geo(geom,
xmin - gapsize, xxmin - gapsize,
py - gapsize - leny / 4, py - gapsize - leny / 4,
xmax + gapsize, xxmax + gapsize,
py + gapsize - leny / 4) py + gapsize - leny / 4)
if gaps == '8' or gaps == '2TB': if gaps == '8' or gaps == '2TB':
geom = self.subtract_poly_from_geo(geom, geom = self.subtract_poly_from_geo(geom,
px - gapsize + lenx / 4, px - gapsize + lenx / 4,
ymin - gapsize, yymin - gapsize,
px + gapsize + lenx / 4, px + gapsize + lenx / 4,
ymax + gapsize) yymax + gapsize)
geom = self.subtract_poly_from_geo(geom, geom = self.subtract_poly_from_geo(geom,
px - gapsize - lenx / 4, px - gapsize - lenx / 4,
ymin - gapsize, yymin - gapsize,
px + gapsize - lenx / 4, px + gapsize - lenx / 4,
ymax + gapsize) yymax + gapsize)
if gaps == '4' or gaps == 'LR': if gaps == '4' or gaps == 'LR':
geom = self.subtract_poly_from_geo(geom, geom = self.subtract_poly_from_geo(geom,
xmin - gapsize, xxmin - gapsize,
py - gapsize, py - gapsize,
xmax + gapsize, xxmax + gapsize,
py + gapsize) py + gapsize)
if gaps == '4' or gaps == 'TB': if gaps == '4' or gaps == 'TB':
geom = self.subtract_poly_from_geo(geom, geom = self.subtract_poly_from_geo(geom,
px - gapsize, px - gapsize,
ymin - gapsize, yymin - gapsize,
px + gapsize, px + gapsize,
ymax + gapsize) yymax + gapsize)
try: try:
for g in geom: for g in geom:
@ -603,7 +602,7 @@ class CutOut(FlatCAMTool):
object_geo = unary_union(object_geo) object_geo = unary_union(object_geo)
# for geo in object_geo: # for geo in object_geo:
if isinstance(cutout_obj, FlatCAMGerber): if cutout_obj.kind == 'gerber':
if isinstance(object_geo, MultiPolygon): if isinstance(object_geo, MultiPolygon):
x0, y0, x1, y1 = object_geo.bounds x0, y0, x1, y1 = object_geo.bounds
object_geo = box(x0, y0, x1, y1) object_geo = box(x0, y0, x1, y1)
@ -623,7 +622,7 @@ class CutOut(FlatCAMTool):
object_geo = [object_geo] object_geo = [object_geo]
for geom_struct in object_geo: for geom_struct in object_geo:
if isinstance(cutout_obj, FlatCAMGerber): if cutout_obj.kind == 'gerber':
if margin >= 0: if margin >= 0:
geom_struct = (geom_struct.buffer(margin + abs(dia / 2))).exterior geom_struct = (geom_struct.buffer(margin + abs(dia / 2))).exterior
else: else:
@ -775,7 +774,7 @@ class CutOut(FlatCAMTool):
# if Gerber create a buffer at a distance # if Gerber create a buffer at a distance
# if Geometry then cut through the geometry # if Geometry then cut through the geometry
if isinstance(cutout_obj, FlatCAMGerber): if cutout_obj.kind == 'gerber':
if margin >= 0: if margin >= 0:
geo = geo.buffer(margin + abs(dia / 2)) geo = geo.buffer(margin + abs(dia / 2))
else: else:
@ -909,7 +908,7 @@ class CutOut(FlatCAMTool):
"Select one and try again.")) "Select one and try again."))
return return
if not isinstance(cutout_obj, FlatCAMGerber): if cutout_obj.kind != 'gerber':
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit('[ERROR_NOTCL] %s' %
_("The selected object has to be of Gerber type.\n" _("The selected object has to be of Gerber type.\n"
"Select a Gerber file and try again.")) "Select a Gerber file and try again."))
@ -988,11 +987,11 @@ class CutOut(FlatCAMTool):
if self.app.is_legacy is False: if self.app.is_legacy is False:
event_pos = event.pos event_pos = event.pos
event_is_dragging = event.is_dragging # event_is_dragging = event.is_dragging
right_button = 2 right_button = 2
else: else:
event_pos = (event.xdata, event.ydata) event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging # event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3 right_button = 3
try: try:
@ -1038,11 +1037,11 @@ class CutOut(FlatCAMTool):
if self.app.is_legacy is False: if self.app.is_legacy is False:
event_pos = event.pos event_pos = event.pos
event_is_dragging = event.is_dragging event_is_dragging = event.is_dragging
right_button = 2 # right_button = 2
else: else:
event_pos = (event.xdata, event.ydata) event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3 # right_button = 3
try: try:
x = float(event_pos[0]) x = float(event_pos[0])
@ -1159,13 +1158,17 @@ class CutOut(FlatCAMTool):
if '+' in key_string: if '+' in key_string:
mod, __, key_text = key_string.rpartition('+') mod, __, key_text = key_string.rpartition('+')
if mod.lower() == 'ctrl': if mod.lower() == 'ctrl':
modifiers = QtCore.Qt.ControlModifier # modifiers = QtCore.Qt.ControlModifier
pass
elif mod.lower() == 'alt': elif mod.lower() == 'alt':
modifiers = QtCore.Qt.AltModifier # modifiers = QtCore.Qt.AltModifier
pass
elif mod.lower() == 'shift': elif mod.lower() == 'shift':
modifiers = QtCore.Qt.ShiftModifier # modifiers = QtCore.Qt.ShiftModifier
pass
else: else:
modifiers = QtCore.Qt.NoModifier # modifiers = QtCore.Qt.NoModifier
pass
key = QtGui.QKeySequence(key_text) key = QtGui.QKeySequence(key_text)
# events from Vispy are of type KeyEvent # events from Vispy are of type KeyEvent
else: else:
@ -1203,7 +1206,8 @@ class CutOut(FlatCAMTool):
geo = self.cutting_geo(pos=(l_x, l_y)) geo = self.cutting_geo(pos=(l_x, l_y))
self.draw_utility_geometry(geo=geo) self.draw_utility_geometry(geo=geo)
def subtract_poly_from_geo(self, solid_geo, x0, y0, x1, y1): @staticmethod
def subtract_poly_from_geo(solid_geo, x0, y0, x1, y1):
""" """
Subtract polygon made from points from the given object. Subtract polygon made from points from the given object.
This only operates on the paths in the original geometry, This only operates on the paths in the original geometry,
@ -1270,8 +1274,9 @@ def flatten(geometry):
def recursive_bounds(geometry): def recursive_bounds(geometry):
""" """
Returns coordinates of rectangular bounds
of geometry: (xmin, ymin, xmax, ymax). :param geometry: a iterable object that holds geometry
:return: Returns coordinates of rectangular bounds of geometry: (xmin, ymin, xmax, ymax).
""" """
# now it can get bounds for nested lists of objects # now it can get bounds for nested lists of objects

View File

@ -3,7 +3,6 @@ from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton, FCComboBox from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton, FCComboBox
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
from numpy import Inf from numpy import Inf
@ -192,7 +191,7 @@ class DblSidedTool(FlatCAMTool):
# Add a reference # Add a reference
self.add_point_button = QtWidgets.QPushButton(_("Add")) self.add_point_button = QtWidgets.QPushButton(_("Add"))
self.add_point_button.setToolTip( self.add_point_button.setToolTip(
_("Add the coordinates in format <b>(x, y)</b> through which the mirroring axis \n " _("Add the coordinates in format <b>(x, y)</b> through which the mirroring axis\n "
"selected in 'MIRROR AXIS' pass.\n" "selected in 'MIRROR AXIS' pass.\n"
"The (x, y) coordinates are captured by pressing SHIFT key\n" "The (x, y) coordinates are captured by pressing SHIFT key\n"
"and left mouse button click on canvas or you can enter the coordinates manually.") "and left mouse button click on canvas or you can enter the coordinates manually.")
@ -658,7 +657,7 @@ class DblSidedTool(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ...")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
return return
if not isinstance(fcobj, FlatCAMGerber): if fcobj.kind != 'gerber':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored.")) self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored."))
return return
@ -701,7 +700,7 @@ class DblSidedTool(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ...")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
return return
if not isinstance(fcobj, FlatCAMExcellon): if fcobj.kind != 'excellon':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored.")) self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored."))
return return
@ -745,7 +744,7 @@ class DblSidedTool(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Geometry object loaded ...")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Geometry object loaded ..."))
return return
if not isinstance(fcobj, FlatCAMGeometry): if fcobj.kind != 'geometry':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored.")) self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber, Excellon and Geometry objects can be mirrored."))
return return

View File

@ -8,7 +8,6 @@
from PyQt5 import QtWidgets, QtCore from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.VisPyVisuals import * from flatcamGUI.VisPyVisuals import *
from FlatCAMObj import FlatCAMGerber
from copy import copy from copy import copy
import logging import logging
@ -128,7 +127,7 @@ class ToolMove(FlatCAMTool):
pos_canvas = self.app.plotcanvas.translate_coords(event_pos) pos_canvas = self.app.plotcanvas.translate_coords(event_pos)
# if GRID is active we need to get the snapped positions # if GRID is active we need to get the snapped positions
if self.app.grid_status() == True: if self.app.grid_status():
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
else: else:
pos = pos_canvas pos = pos_canvas
@ -148,7 +147,7 @@ class ToolMove(FlatCAMTool):
self.delete_shape() self.delete_shape()
# if GRID is active we need to get the snapped positions # if GRID is active we need to get the snapped positions
if self.app.grid_status() == True: if self.app.grid_status():
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
else: else:
pos = pos_canvas pos = pos_canvas
@ -171,7 +170,7 @@ class ToolMove(FlatCAMTool):
# remove any mark aperture shape that may be displayed # remove any mark aperture shape that may be displayed
for sel_obj in obj_list: for sel_obj in obj_list:
# if the Gerber mark shapes are enabled they need to be disabled before move # if the Gerber mark shapes are enabled they need to be disabled before move
if isinstance(sel_obj, FlatCAMGerber): if sel_obj.kind == 'gerber':
sel_obj.ui.aperture_table_visibility_cb.setChecked(False) sel_obj.ui.aperture_table_visibility_cb.setChecked(False)
try: try:
@ -198,8 +197,8 @@ class ToolMove(FlatCAMTool):
elif sel_obj.kind == 'excellon': elif sel_obj.kind == 'excellon':
sel_obj.source_file = self.app.export_excellon( sel_obj.source_file = self.app.export_excellon(
obj_name=out_name, filename=None, local_use=sel_obj, use_thread=False) obj_name=out_name, filename=None, local_use=sel_obj, use_thread=False)
except Exception as e: except Exception as err:
log.debug('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(e))) log.debug('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(err)))
return "fail" return "fail"
# time to plot the moved objects # time to plot the moved objects
@ -249,7 +248,7 @@ class ToolMove(FlatCAMTool):
pos_canvas = self.app.plotcanvas.translate_coords((x, y)) pos_canvas = self.app.plotcanvas.translate_coords((x, y))
# if GRID is active we need to get the snapped positions # if GRID is active we need to get the snapped positions
if self.app.grid_status() == True: if self.app.grid_status():
pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1]) pos = self.app.geo_editor.snap(pos_canvas[0], pos_canvas[1])
else: else:
pos = pos_canvas pos = pos_canvas

View File

@ -12,7 +12,7 @@ from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTabl
FCComboBox, OptionalInputSection FCComboBox, OptionalInputSection
from flatcamParsers.ParseGerber import Gerber from flatcamParsers.ParseGerber import Gerber
import FlatCAMApp from FlatCAMCommon import GracefulException as grace
from copy import deepcopy from copy import deepcopy
@ -1987,7 +1987,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in env_obj: for poly in env_obj:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)) geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
bounding_box = cascaded_union(geo_buff_list) bounding_box = cascaded_union(geo_buff_list)
elif ncc_select == _("Reference Object"): elif ncc_select == _("Reference Object"):
@ -1996,7 +1996,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in env_obj: for poly in env_obj:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)) geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
bounding_box = cascaded_union(geo_buff_list) bounding_box = cascaded_union(geo_buff_list)
@ -2090,7 +2090,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if isinstance(geo_elem, Polygon): if isinstance(geo_elem, Polygon):
for ring in self.poly2rings(geo_elem): for ring in self.poly2rings(geo_elem):
@ -2263,7 +2263,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ########################################################################################## # ##########################################################################################
def gen_clear_area(geo_obj, app_obj): def gen_clear_area(geo_obj, app_obj):
assert geo_obj.kind == 'geometry', \ assert geo_obj.kind == 'geometry', \
"Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj) "Initializer expected a GeometryObject, got %s" % type(geo_obj)
# provide the app with a way to process the GUI events when in a blocking loop # provide the app with a way to process the GUI events when in a blocking loop
if not run_threaded: if not run_threaded:
@ -2312,7 +2312,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
log.debug("Starting geometry processing for tool: %s" % str(tool)) log.debug("Starting geometry processing for tool: %s" % str(tool))
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# provide the app with a way to process the GUI events when in a blocking loop # provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
@ -2377,7 +2377,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# clean the polygon # clean the polygon
p = p.buffer(0) p = p.buffer(0)
@ -2551,7 +2551,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ########################################################################################### # ###########################################################################################
def gen_clear_area_rest(geo_obj, app_obj): def gen_clear_area_rest(geo_obj, app_obj):
assert geo_obj.kind == 'geometry', \ assert geo_obj.kind == 'geometry', \
"Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj) "Initializer expected a GeometryObject, got %s" % type(geo_obj)
log.debug("NCC Tool. Rest machining copper clearing task started.") log.debug("NCC Tool. Rest machining copper clearing task started.")
app_obj.inform.emit('_(NCC Tool. Rest machining copper clearing task started.') app_obj.inform.emit('_(NCC Tool. Rest machining copper clearing task started.')
@ -2595,7 +2595,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
log.debug("Starting geometry processing for tool: %s" % str(tool)) log.debug("Starting geometry processing for tool: %s" % str(tool))
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# provide the app with a way to process the GUI events when in a blocking loop # provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
@ -2644,7 +2644,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
try: try:
area = area.difference(poly) area = area.difference(poly)
except Exception: except Exception:
@ -2674,7 +2674,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in area.geoms: for p in area.geoms:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# clean the polygon # clean the polygon
p = p.buffer(0) p = p.buffer(0)
@ -2753,7 +2753,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# check if there is a geometry at all in the cleared geometry # check if there is a geometry at all in the cleared geometry
if cleared_geo: if cleared_geo:
@ -2771,7 +2771,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in cleared_area: for p in cleared_area:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
poly = p.buffer(buffer_value) poly = p.buffer(buffer_value)
cleared_by_last_tool.append(poly) cleared_by_last_tool.append(poly)
@ -2836,7 +2836,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.new_object("geometry", name, gen_clear_area_rest) app_obj.new_object("geometry", name, gen_clear_area_rest)
else: else:
app_obj.new_object("geometry", name, gen_clear_area) app_obj.new_object("geometry", name, gen_clear_area)
except FlatCAMApp.GracefulException: except grace:
if run_threaded: if run_threaded:
proc.done() proc.done()
return return
@ -2999,7 +2999,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in geo_n: for poly in geo_n:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)) geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
bounding_box = cascaded_union(geo_buff_list) bounding_box = cascaded_union(geo_buff_list)
@ -3017,7 +3017,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in geo_n: for poly in geo_n:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre)) geo_buff_list.append(poly.buffer(distance=ncc_margin, join_style=base.JOIN_STYLE.mitre))
bounding_box = cascaded_union(geo_buff_list) bounding_box = cascaded_union(geo_buff_list)
@ -3045,7 +3045,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ########################################################################################## # ##########################################################################################
def gen_clear_area(geo_obj, app_obj): def gen_clear_area(geo_obj, app_obj):
assert geo_obj.kind == 'geometry', \ assert geo_obj.kind == 'geometry', \
"Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj) "Initializer expected a GeometryObject, got %s" % type(geo_obj)
# provide the app with a way to process the GUI events when in a blocking loop # provide the app with a way to process the GUI events when in a blocking loop
if not run_threaded: if not run_threaded:
@ -3141,7 +3141,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if isinstance(geo_elem, Polygon): if isinstance(geo_elem, Polygon):
for ring in self.poly2rings(geo_elem): for ring in self.poly2rings(geo_elem):
@ -3242,7 +3242,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
log.debug("Starting geometry processing for tool: %s" % str(tool)) log.debug("Starting geometry processing for tool: %s" % str(tool))
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# provide the app with a way to process the GUI events when in a blocking loop # provide the app with a way to process the GUI events when in a blocking loop
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
@ -3283,7 +3283,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# clean the polygon # clean the polygon
p = p.buffer(0) p = p.buffer(0)
@ -3446,7 +3446,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ########################################################################################### # ###########################################################################################
def gen_clear_area_rest(geo_obj, app_obj): def gen_clear_area_rest(geo_obj, app_obj):
assert geo_obj.kind == 'geometry', \ assert geo_obj.kind == 'geometry', \
"Initializer expected a FlatCAMGeometry, got %s" % type(geo_obj) "Initializer expected a GeometryObject, got %s" % type(geo_obj)
log.debug("NCC Tool. Rest machining copper clearing task started.") log.debug("NCC Tool. Rest machining copper clearing task started.")
app_obj.inform.emit('_(NCC Tool. Rest machining copper clearing task started.') app_obj.inform.emit('_(NCC Tool. Rest machining copper clearing task started.')
@ -3520,7 +3520,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if isinstance(geo_elem, Polygon): if isinstance(geo_elem, Polygon):
for ring in self.poly2rings(geo_elem): for ring in self.poly2rings(geo_elem):
@ -3614,7 +3614,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if type(empty) is Polygon: if type(empty) is Polygon:
empty = MultiPolygon([empty]) empty = MultiPolygon([empty])
@ -3628,7 +3628,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
while sorted_tools: while sorted_tools:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
tool = sorted_tools.pop(0) tool = sorted_tools.pop(0)
log.debug("Starting geometry processing for tool: %s" % str(tool)) log.debug("Starting geometry processing for tool: %s" % str(tool))
@ -3648,7 +3648,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
try: try:
area = area.difference(poly_r) area = area.difference(poly_r)
except Exception: except Exception:
@ -3678,7 +3678,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in area.geoms: for p in area.geoms:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# clean the polygon # clean the polygon
p = p.buffer(0) p = p.buffer(0)
@ -3754,7 +3754,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# check if there is a geometry at all in the cleared geometry # check if there is a geometry at all in the cleared geometry
if cleared_geo: if cleared_geo:
@ -3772,7 +3772,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in cleared_area: for p in cleared_area:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
r_poly = p.buffer(buffer_value) r_poly = p.buffer(buffer_value)
cleared_by_last_tool.append(r_poly) cleared_by_last_tool.append(r_poly)
@ -3833,7 +3833,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot) app_obj.new_object("geometry", name, gen_clear_area_rest, plot=plot)
else: else:
app_obj.new_object("geometry", name, gen_clear_area, plot=plot) app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
except FlatCAMApp.GracefulException: except grace:
if run_threaded: if run_threaded:
proc.done() proc.done()
return return
@ -3887,7 +3887,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
boundary = boundary.difference(el) boundary = boundary.difference(el)
pol_nr += 1 pol_nr += 1
disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100])) disp_number = int(np.interp(pol_nr, [0, geo_len], [0, 100]))

View File

@ -9,8 +9,7 @@ from PyQt5 import QtWidgets, QtCore, QtGui
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox, FCComboBox from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox, FCComboBox
from FlatCAMObj import FlatCAMGerber from FlatCAMCommon import GracefulException as grace
import FlatCAMApp
from shapely.geometry import MultiPolygon from shapely.geometry import MultiPolygon
from shapely.ops import nearest_points from shapely.ops import nearest_points
@ -343,7 +342,7 @@ class ToolOptimal(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ...")) self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
return return
if not isinstance(fcobj, FlatCAMGerber): if fcobj.kind != 'gerber':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber objects can be evaluated.")) self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber objects can be evaluated."))
return return
@ -365,7 +364,7 @@ class ToolOptimal(FlatCAMTool):
for geo_el in fcobj.apertures[ap]['geometry']: for geo_el in fcobj.apertures[ap]['geometry']:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if 'solid' in geo_el and geo_el['solid'] is not None and geo_el['solid'].is_valid: if 'solid' in geo_el and geo_el['solid'] is not None and geo_el['solid'].is_valid:
total_geo.append(geo_el['solid']) total_geo.append(geo_el['solid'])
@ -395,7 +394,7 @@ class ToolOptimal(FlatCAMTool):
for s_geo in total_geo[idx:]: for s_geo in total_geo[idx:]:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# minimize the number of distances by not taking into considerations those that are too small # minimize the number of distances by not taking into considerations those that are too small
dist = geo.distance(s_geo) dist = geo.distance(s_geo)
@ -459,7 +458,7 @@ class ToolOptimal(FlatCAMTool):
log.debug("ToolOptimal.on_locate_position() --> first try %s" % str(e)) log.debug("ToolOptimal.on_locate_position() --> first try %s" % str(e))
self.app.inform.emit("[ERROR_NOTCL] The selected text is no valid location in the format " self.app.inform.emit("[ERROR_NOTCL] The selected text is no valid location in the format "
"((x0, y0), (x1, y1)).") "((x0, y0), (x1, y1)).")
return 'fail' return
try: try:
loc_1 = loc[0] loc_1 = loc[0]
@ -471,7 +470,7 @@ class ToolOptimal(FlatCAMTool):
self.app.on_jump_to(custom_location=loc) self.app.on_jump_to(custom_location=loc)
except Exception as e: except Exception as e:
log.debug("ToolOptimal.on_locate_position() --> sec try %s" % str(e)) log.debug("ToolOptimal.on_locate_position() --> sec try %s" % str(e))
return 'fail' return
def on_update_text(self, data): def on_update_text(self, data):
txt = '' txt = ''
@ -567,12 +566,12 @@ class ToolOptimal(FlatCAMTool):
if self.selected_locations_text != '': if self.selected_locations_text != '':
loc = eval(self.selected_locations_text) loc = eval(self.selected_locations_text)
else: else:
return 'fail' return
except Exception as e: except Exception as e:
log.debug("ToolOptimal.on_locate_sec_position() --> first try %s" % str(e)) log.debug("ToolOptimal.on_locate_sec_position() --> first try %s" % str(e))
self.app.inform.emit("[ERROR_NOTCL] The selected text is no valid location in the format " self.app.inform.emit("[ERROR_NOTCL] The selected text is no valid location in the format "
"((x0, y0), (x1, y1)).") "((x0, y0), (x1, y1)).")
return 'fail' return
try: try:
loc_1 = loc[0] loc_1 = loc[0]
@ -584,7 +583,7 @@ class ToolOptimal(FlatCAMTool):
self.app.on_jump_to(custom_location=loc) self.app.on_jump_to(custom_location=loc)
except Exception as e: except Exception as e:
log.debug("ToolOptimal.on_locate_sec_position() --> sec try %s" % str(e)) log.debug("ToolOptimal.on_locate_sec_position() --> sec try %s" % str(e))
return 'fail' return
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()))

View File

@ -8,7 +8,7 @@
from PyQt5 import QtWidgets, QtCore from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
import FlatCAMApp from FlatCAMCommon import GracefulException as grace
from shapely.geometry import Point, Polygon, LineString, MultiPolygon from shapely.geometry import Point, Polygon, LineString, MultiPolygon
from shapely.ops import unary_union from shapely.ops import unary_union
@ -190,7 +190,7 @@ class ToolPDF(FlatCAMTool):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
with self.app.proc_container.new(_("Parsing PDF file ...")): with self.app.proc_container.new(_("Parsing PDF file ...")):
with open(filename, "rb") as f: with open(filename, "rb") as f:
@ -200,7 +200,7 @@ class ToolPDF(FlatCAMTool):
for s in re.findall(self.stream_re, pdf): for s in re.findall(self.stream_re, pdf):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
stream_nr += 1 stream_nr += 1
log.debug(" PDF STREAM: %d\n" % stream_nr) log.debug(" PDF STREAM: %d\n" % stream_nr)
@ -291,7 +291,7 @@ class ToolPDF(FlatCAMTool):
def layer_rendering_as_gerber(self, filename, ap_dict, layer_nr): def layer_rendering_as_gerber(self, filename, ap_dict, layer_nr):
outname = filename.split('/')[-1].split('\\')[-1] + "_%s" % str(layer_nr) outname = filename.split('/')[-1].split('\\')[-1] + "_%s" % str(layer_nr)
def obj_init(grb_obj, app_obj): def obj_init(grb_obj):
grb_obj.apertures = ap_dict grb_obj.apertures = ap_dict
@ -404,7 +404,7 @@ class ToolPDF(FlatCAMTool):
for object_name in self.pdf_parsed: for object_name in self.pdf_parsed:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
filename = deepcopy(self.pdf_parsed[object_name]['filename']) filename = deepcopy(self.pdf_parsed[object_name]['filename'])
pdf_content = deepcopy(self.pdf_parsed[object_name]['pdf']) pdf_content = deepcopy(self.pdf_parsed[object_name]['pdf'])
@ -412,7 +412,7 @@ class ToolPDF(FlatCAMTool):
for k in pdf_content: for k in pdf_content:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
ap_dict = pdf_content[k] ap_dict = pdf_content[k]
if ap_dict: if ap_dict:
@ -493,7 +493,7 @@ class ToolPDF(FlatCAMTool):
for pline in lines: for pline in lines:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
line_nr += 1 line_nr += 1
log.debug("line %d: %s" % (line_nr, pline)) log.debug("line %d: %s" % (line_nr, pline))
@ -868,7 +868,6 @@ class ToolPDF(FlatCAMTool):
new_el['solid'] = pdf_geo new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior new_el['follow'] = pdf_geo.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el)) apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
found_aperture = None
else: else:
if str(aperture) in apertures_dict.keys(): if str(aperture) in apertures_dict.keys():
aperture += 1 aperture += 1
@ -1231,7 +1230,6 @@ class ToolPDF(FlatCAMTool):
new_el['solid'] = pdf_geo new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior new_el['follow'] = pdf_geo.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el)) apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
found_aperture = None
else: else:
if str(aperture) in apertures_dict.keys(): if str(aperture) in apertures_dict.keys():
aperture += 1 aperture += 1
@ -1355,7 +1353,7 @@ class ToolPDF(FlatCAMTool):
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
return object_dict return object_dict

View File

@ -14,7 +14,7 @@ from copy import deepcopy
from flatcamParsers.ParseGerber import Gerber from flatcamParsers.ParseGerber import Gerber
from camlib import Geometry, FlatCAMRTreeStorage from camlib import Geometry, FlatCAMRTreeStorage
from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton, FCComboBox from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet, FCButton, FCComboBox
import FlatCAMApp from FlatCAMCommon import GracefulException as grace
from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point from shapely.geometry import base, Polygon, MultiPolygon, LinearRing, Point
from shapely.ops import cascaded_union, unary_union, linemerge from shapely.ops import cascaded_union, unary_union, linemerge
@ -1836,7 +1836,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
except FlatCAMApp.GracefulException: except grace:
return "fail" return "fail"
except Exception as ee: except Exception as ee:
log.debug("ToolPaint.paint_polygon_worker() Standard --> %s" % str(ee)) log.debug("ToolPaint.paint_polygon_worker() Standard --> %s" % str(ee))
@ -1850,7 +1850,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
except FlatCAMApp.GracefulException: except grace:
return "fail" return "fail"
except Exception as ee: except Exception as ee:
log.debug("ToolPaint.paint_polygon_worker() Seed --> %s" % str(ee)) log.debug("ToolPaint.paint_polygon_worker() Seed --> %s" % str(ee))
@ -1864,7 +1864,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
except FlatCAMApp.GracefulException: except grace:
return "fail" return "fail"
except Exception as ee: except Exception as ee:
log.debug("ToolPaint.paint_polygon_worker() Lines --> %s" % str(ee)) log.debug("ToolPaint.paint_polygon_worker() Lines --> %s" % str(ee))
@ -2015,7 +2015,7 @@ class ToolPaint(FlatCAMTool, Gerber):
# contour=cont, # contour=cont,
# connect=conn, # connect=conn,
# prog_plot=prog_plot) # prog_plot=prog_plot)
except FlatCAMApp.GracefulException: except grace:
return "fail" return "fail"
except Exception as ee: except Exception as ee:
log.debug("ToolPaint.paint_polygon_worker() Laser Lines --> %s" % str(ee)) log.debug("ToolPaint.paint_polygon_worker() Laser Lines --> %s" % str(ee))
@ -2052,7 +2052,7 @@ class ToolPaint(FlatCAMTool, Gerber):
contour=cont, contour=cont,
connect=conn, connect=conn,
prog_plot=prog_plot) prog_plot=prog_plot)
except FlatCAMApp.GracefulException: except grace:
return "fail" return "fail"
except Exception as ee: except Exception as ee:
log.debug("ToolPaint.paint_polygon_worker() Combo --> %s" % str(ee)) log.debug("ToolPaint.paint_polygon_worker() Combo --> %s" % str(ee))
@ -2199,7 +2199,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
prog_plot=prog_plot) prog_plot=prog_plot)
@ -2217,7 +2217,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -2230,7 +2230,7 @@ class ToolPaint(FlatCAMTool, Gerber):
for x in cp: for x in cp:
total_geometry += list(x.get_objects()) total_geometry += list(x.get_objects())
final_solid_geometry += total_geometry final_solid_geometry += total_geometry
except FlatCAMApp.GracefulException: except grace:
return "fail" return "fail"
except Exception as e: except Exception as e:
log.debug("Could not Paint the polygons. %s" % str(e)) log.debug("Could not Paint the polygons. %s" % str(e))
@ -2305,7 +2305,7 @@ class ToolPaint(FlatCAMTool, Gerber):
def job_thread(app_obj): def job_thread(app_obj):
try: try:
ret = app_obj.new_object("geometry", name, job_init, plot=plot) ret = app_obj.new_object("geometry", name, job_init, plot=plot)
except FlatCAMApp.GracefulException: except grace:
proc.done() proc.done()
return return
except Exception as er: except Exception as er:
@ -2376,7 +2376,7 @@ class ToolPaint(FlatCAMTool, Gerber):
""" """
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if geometry is None: if geometry is None:
return return
@ -2517,7 +2517,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -2542,7 +2542,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -2705,7 +2705,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
prog_plot=prog_plot) prog_plot=prog_plot)
@ -2723,7 +2723,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -2735,7 +2735,7 @@ class ToolPaint(FlatCAMTool, Gerber):
for x in cp: for x in cp:
cleared_geo += list(x.get_objects()) cleared_geo += list(x.get_objects())
final_solid_geometry += cleared_geo final_solid_geometry += cleared_geo
except FlatCAMApp.GracefulException: except grace:
return "fail" return "fail"
except Exception as e: except Exception as e:
log.debug("Could not Paint the polygons. %s" % str(e)) log.debug("Could not Paint the polygons. %s" % str(e))
@ -2815,7 +2815,7 @@ class ToolPaint(FlatCAMTool, Gerber):
ret = app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot) ret = app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
else: else:
ret = app_obj.new_object("geometry", name, gen_paintarea, plot=plot) ret = app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
except FlatCAMApp.GracefulException: except grace:
proc.done() proc.done()
return return
except Exception as err: except Exception as err:
@ -2873,7 +2873,7 @@ class ToolPaint(FlatCAMTool, Gerber):
""" """
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if geometry is None: if geometry is None:
return return
@ -3015,7 +3015,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -3040,7 +3040,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -3193,7 +3193,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(pp, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -3218,7 +3218,7 @@ class ToolPaint(FlatCAMTool, Gerber):
QtWidgets.QApplication.processEvents() QtWidgets.QApplication.processEvents()
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn, geo_res = self.paint_polygon_worker(poly_buf, tooldiameter=tool_dia, over=over, conn=conn,
cont=cont, paint_method=paint_method, obj=obj, cont=cont, paint_method=paint_method, obj=obj,
@ -3312,7 +3312,7 @@ class ToolPaint(FlatCAMTool, Gerber):
ret = app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot) ret = app_obj.new_object("geometry", name, gen_paintarea_rest_machining, plot=plot)
else: else:
ret = app_obj.new_object("geometry", name, gen_paintarea, plot=plot) ret = app_obj.new_object("geometry", name, gen_paintarea, plot=plot)
except FlatCAMApp.GracefulException: except grace:
proc.done() proc.done()
return return
except Exception as err: except Exception as err:

View File

@ -9,10 +9,8 @@ from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection, FCComboBox from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection, FCComboBox
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber, FlatCAMExcellon from FlatCAMCommon import GracefulException as grace
import FlatCAMApp
from copy import deepcopy from copy import deepcopy
# from ObjectCollection import *
import numpy as np import numpy as np
import shapely.affinity as affinity import shapely.affinity as affinity
@ -480,13 +478,13 @@ class Panelize(FlatCAMTool):
rows -= 1 rows -= 1
panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1)) panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
if isinstance(panel_obj, FlatCAMExcellon) or isinstance(panel_obj, FlatCAMGeometry): if panel_obj.kind == 'excellon' or panel_obj.kind == 'geometry':
# make a copy of the panelized Excellon or Geometry tools # make a copy of the panelized Excellon or Geometry tools
copied_tools = {} copied_tools = {}
for tt, tt_val in list(panel_obj.tools.items()): for tt, tt_val in list(panel_obj.tools.items()):
copied_tools[tt] = deepcopy(tt_val) copied_tools[tt] = deepcopy(tt_val)
if isinstance(panel_obj, FlatCAMGerber): if panel_obj.kind == 'gerber':
# make a copy of the panelized Gerber apertures # make a copy of the panelized Gerber apertures
copied_apertures = {} copied_apertures = {}
for tt, tt_val in list(panel_obj.apertures.items()): for tt, tt_val in list(panel_obj.apertures.items()):
@ -525,7 +523,7 @@ class Panelize(FlatCAMTool):
for tool_dict in panel_obj.drills: for tool_dict in panel_obj.drills:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
point_offseted = affinity.translate(tool_dict['point'], currentx, currenty) point_offseted = affinity.translate(tool_dict['point'], currentx, currenty)
obj_fin.drills.append( obj_fin.drills.append(
@ -550,7 +548,7 @@ class Panelize(FlatCAMTool):
for tool_dict in panel_obj.slots: for tool_dict in panel_obj.slots:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
start_offseted = affinity.translate(tool_dict['start'], currentx, currenty) start_offseted = affinity.translate(tool_dict['start'], currentx, currenty)
stop_offseted = affinity.translate(tool_dict['stop'], currentx, currenty) stop_offseted = affinity.translate(tool_dict['stop'], currentx, currenty)
@ -600,20 +598,20 @@ class Panelize(FlatCAMTool):
obj_fin.solid_geometry = [] obj_fin.solid_geometry = []
# create the initial structure on which to create the panel # create the initial structure on which to create the panel
if isinstance(panel_obj, FlatCAMGeometry): if panel_obj.kind == 'geometry':
obj_fin.multigeo = panel_obj.multigeo obj_fin.multigeo = panel_obj.multigeo
obj_fin.tools = copied_tools obj_fin.tools = copied_tools
if panel_obj.multigeo is True: if panel_obj.multigeo is True:
for tool in panel_obj.tools: for tool in panel_obj.tools:
obj_fin.tools[tool]['solid_geometry'][:] = [] obj_fin.tools[tool]['solid_geometry'][:] = []
elif isinstance(panel_obj, FlatCAMGerber): elif panel_obj.kind == 'gerber':
obj_fin.apertures = copied_apertures obj_fin.apertures = copied_apertures
for ap in obj_fin.apertures: for ap in obj_fin.apertures:
obj_fin.apertures[ap]['geometry'] = [] obj_fin.apertures[ap]['geometry'] = []
# find the number of polygons in the source solid_geometry # find the number of polygons in the source solid_geometry
geo_len = 0 geo_len = 0
if isinstance(panel_obj, FlatCAMGeometry): if panel_obj.kind == 'geometry':
if panel_obj.multigeo is True: if panel_obj.multigeo is True:
for tool in panel_obj.tools: for tool in panel_obj.tools:
try: try:
@ -625,7 +623,7 @@ class Panelize(FlatCAMTool):
geo_len = len(panel_obj.solid_geometry) geo_len = len(panel_obj.solid_geometry)
except TypeError: except TypeError:
geo_len = 1 geo_len = 1
elif isinstance(panel_obj, FlatCAMGerber): elif panel_obj.kind == 'gerber':
for ap in panel_obj.apertures: for ap in panel_obj.apertures:
if 'geometry' in panel_obj.apertures[ap]: if 'geometry' in panel_obj.apertures[ap]:
try: try:
@ -641,12 +639,12 @@ class Panelize(FlatCAMTool):
element += 1 element += 1
old_disp_number = 0 old_disp_number = 0
if isinstance(panel_obj, FlatCAMGeometry): if panel_obj.kind == 'geometry':
if panel_obj.multigeo is True: if panel_obj.multigeo is True:
for tool in panel_obj.tools: for tool in panel_obj.tools:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
# geo = translate_recursion(panel_obj.tools[tool]['solid_geometry']) # geo = translate_recursion(panel_obj.tools[tool]['solid_geometry'])
# if isinstance(geo, list): # if isinstance(geo, list):
@ -678,7 +676,7 @@ class Panelize(FlatCAMTool):
# obj_fin.solid_geometry.append(geo) # obj_fin.solid_geometry.append(geo)
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
try: try:
# calculate the number of polygons # calculate the number of polygons
@ -690,7 +688,7 @@ class Panelize(FlatCAMTool):
for geo_el in panel_obj.solid_geometry: for geo_el in panel_obj.solid_geometry:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
trans_geo = translate_recursion(geo_el) trans_geo = translate_recursion(geo_el)
obj_fin.solid_geometry.append(trans_geo) obj_fin.solid_geometry.append(trans_geo)
@ -715,13 +713,13 @@ class Panelize(FlatCAMTool):
# obj_fin.solid_geometry.append(geo) # obj_fin.solid_geometry.append(geo)
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
try: try:
for geo_el in panel_obj.solid_geometry: for geo_el in panel_obj.solid_geometry:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
trans_geo = translate_recursion(geo_el) trans_geo = translate_recursion(geo_el)
obj_fin.solid_geometry.append(trans_geo) obj_fin.solid_geometry.append(trans_geo)
@ -732,7 +730,7 @@ class Panelize(FlatCAMTool):
for apid in panel_obj.apertures: for apid in panel_obj.apertures:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
if 'geometry' in panel_obj.apertures[apid]: if 'geometry' in panel_obj.apertures[apid]:
try: try:
# calculate the number of polygons # calculate the number of polygons
@ -743,7 +741,7 @@ class Panelize(FlatCAMTool):
for el in panel_obj.apertures[apid]['geometry']: for el in panel_obj.apertures[apid]['geometry']:
if self.app.abort_flag: if self.app.abort_flag:
# graceful abort requested by the user # graceful abort requested by the user
raise FlatCAMApp.GracefulException raise grace
new_el = {} new_el = {}
if 'solid' in el: if 'solid' in el:
@ -786,7 +784,7 @@ class Panelize(FlatCAMTool):
self.app.proc_container.update_view_text('') self.app.proc_container.update_view_text('')
self.app.inform.emit('%s: %d' % (_("Generating panel... Spawning copies"), (int(rows * columns)))) self.app.inform.emit('%s: %d' % (_("Generating panel... Spawning copies"), (int(rows * columns))))
if isinstance(panel_obj, FlatCAMExcellon): if panel_obj.kind == 'excellon':
self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True) self.app.new_object("excellon", self.outname, job_init_excellon, plot=True, autoselected=True)
else: else:
self.app.new_object(panel_type, self.outname, job_init_geometry, plot=True, autoselected=True) self.app.new_object(panel_type, self.outname, job_init_geometry, plot=True, autoselected=True)

View File

@ -142,7 +142,7 @@ class ToolPunchGerber(FlatCAMTool):
"- Excellon Object-> the Excellon object drills center will serve as reference.\n" "- Excellon Object-> the Excellon object drills center will serve as reference.\n"
"- Fixed Diameter -> will try to use the pads center as reference adding fixed diameter holes.\n" "- Fixed Diameter -> will try to use the pads center as reference adding fixed diameter holes.\n"
"- Fixed Annular Ring -> will try to keep a set annular ring.\n" "- Fixed Annular Ring -> will try to keep a set annular ring.\n"
"- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.\n") "- Proportional -> will make a Gerber punch hole having the diameter a percentage of the pad diameter.")
) )
self.method_punch = RadioSet( self.method_punch = RadioSet(
[ [
@ -604,8 +604,8 @@ class ToolPunchGerber(FlatCAMTool):
if grb_obj.apertures[apid]['type'] == 'C' and self.circular_cb.get_value(): if grb_obj.apertures[apid]['type'] == 'C' and self.circular_cb.get_value():
if punch_size >= float(grb_obj.apertures[apid]['size']): if punch_size >= float(grb_obj.apertures[apid]['size']):
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit('[ERROR_NOTCL] %s' %
_(" Could not generate punched hole Gerber because the punch hole size" _("Could not generate punched hole Gerber because the punch hole size"
"is bigger than some of the apertures in the Gerber object.")) " is bigger than some of the apertures in the Gerber object."))
return 'fail' return 'fail'
else: else:
for elem in grb_obj.apertures[apid]['geometry']: for elem in grb_obj.apertures[apid]['geometry']:
@ -617,7 +617,7 @@ class ToolPunchGerber(FlatCAMTool):
punch_size >= float(grb_obj.apertures[apid]['height']): punch_size >= float(grb_obj.apertures[apid]['height']):
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Could not generate punched hole Gerber because the punch hole size" _("Could not generate punched hole Gerber because the punch hole size"
"is bigger than some of the apertures in the Gerber object.")) " is bigger than some of the apertures in the Gerber object."))
return 'fail' return 'fail'
elif round(float(grb_obj.apertures[apid]['width']), self.decimals) == \ elif round(float(grb_obj.apertures[apid]['width']), self.decimals) == \
round(float(grb_obj.apertures[apid]['height']), self.decimals) and \ round(float(grb_obj.apertures[apid]['height']), self.decimals) and \

View File

@ -13,8 +13,10 @@ from PyQt5.QtWidgets import QVBoxLayout, QWidget
from flatcamGUI.GUIElements import _BrowserTextEdit, _ExpandableTextEdit from flatcamGUI.GUIElements import _BrowserTextEdit, _ExpandableTextEdit
import html import html
import sys import sys
import traceback
import tkinter as tk import tkinter as tk
import tclCommands
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -110,7 +112,7 @@ class TermWidget(QWidget):
elif style == 'err': elif style == 'err':
text = '<span style="font-weight: bold; color: red;">%s</span>'\ text = '<span style="font-weight: bold; color: red;">%s</span>'\
'<span style="font-weight: bold;">%s</span>'\ '<span style="font-weight: bold;">%s</span>'\
%(mtype, body) % (mtype, body)
elif style == 'warning': elif style == 'warning':
# text = '<span style="font-weight: bold; color: #f4b642;">%s</span>' % text # text = '<span style="font-weight: bold; color: #f4b642;">%s</span>' % text
text = '<span style="font-weight: bold; color: #f4b642;">%s</span>' \ text = '<span style="font-weight: bold; color: #f4b642;">%s</span>' \
@ -253,15 +255,90 @@ class TermWidget(QWidget):
class FCShell(TermWidget): class FCShell(TermWidget):
def __init__(self, sysShell, version, *args): def __init__(self, app, version, *args):
""" """
Initialize the TCL Shell. A dock widget that holds the GUI interface to the FlatCAM command line.
:param sysShell: When instantiated the sysShell will be actually the FlatCAMApp.App() class :param app: When instantiated the sysShell will be actually the FlatCAMApp.App() class
:param version: FlatCAM version string :param version: FlatCAM version string
:param args: Parameters passed to the TermWidget parent class :param args: Parameters passed to the TermWidget parent class
""" """
TermWidget.__init__(self, version, *args, app=sysShell) TermWidget.__init__(self, version, *args, app=app)
self._sysShell = sysShell self.app = app
self.tcl_commands_storage = {}
if hasattr(self, 'tcl') and self.tcl is not None:
# self.tcl = None
# new object cannot be used here as it will not remember values created for next passes,
# because tcl was executed in old instance of TCL
pass
else:
self.tcl = tk.Tcl()
self.setup_shell()
self._edit.set_model_data(self.app.myKeywords)
self.setWindowIcon(self.app.ui.app_icon)
self.setWindowTitle("FlatCAM Shell")
self.resize(*self.app.defaults["global_shell_shape"])
self._append_to_browser('in', "FlatCAM %s - " % version)
self.append_output('%s\n\n' % _("Type >help< to get started"))
def setup_shell(self):
"""
Creates shell functions. Runs once at startup.
:return: None
"""
'''
How to implement TCL shell commands:
All parameters passed to command should be possible to set as None and test it afterwards.
This is because we need to see error caused in tcl,
if None value as default parameter is not allowed TCL will return empty error.
Use:
def mycommand(name=None,...):
Test it like this:
if name is None:
self.raise_tcl_error('Argument name is missing.')
When error occurred, always use raise_tcl_error, never return "some text" on error,
otherwise we will miss it and processing will silently continue.
Method raise_tcl_error pass error into TCL interpreter, then raise python exception,
which is caught in exec_command and displayed in TCL shell console with red background.
Error in console is displayed with TCL trace.
This behavior works only within main thread,
errors with promissed tasks can be catched and detected only with log.
TODO: this problem have to be addressed somehow, maybe rewrite promissing to be blocking somehow for
TCL shell.
Kamil's comment: I will rewrite existing TCL commands from time to time to follow this rules.
'''
# Import/overwrite tcl commands as objects of TclCommand descendants
# This modifies the variable 'self.tcl_commands_storage'.
tclCommands.register_all_commands(self.app, self.tcl_commands_storage)
# Add commands to the tcl interpreter
for cmd in self.tcl_commands_storage:
self.tcl.createcommand(cmd, self.tcl_commands_storage[cmd]['fcn'])
# Make the tcl puts function return instead of print to stdout
self.tcl.eval('''
rename puts original_puts
proc puts {args} {
if {[llength $args] == 1} {
return "[lindex $args 0]"
} else {
eval original_puts $args
}
}
''')
def is_command_complete(self, text): def is_command_complete(self, text):
def skipQuotes(txt): def skipQuotes(txt):
@ -293,7 +370,7 @@ class FCShell(TermWidget):
:return: output if there was any :return: output if there was any
""" """
self._sysShell.report_usage('exec_command') self.app.report_usage('exec_command')
return self.exec_command_test(text, False, no_echo=no_echo) return self.exec_command_test(text, False, no_echo=no_echo)
@ -315,15 +392,15 @@ class FCShell(TermWidget):
if no_echo is False: if no_echo is False:
self.open_processing() # Disables input box. self.open_processing() # Disables input box.
result = self._sysShell.tcl.eval(str(tcl_command_string)) result = self.tcl.eval(str(tcl_command_string))
if result != 'None' and no_echo is False: if result != 'None' and no_echo is False:
self.append_output(result + '\n') self.append_output(result + '\n')
except tk.TclError as e: except tk.TclError as e:
# This will display more precise answer if something in TCL shell fails # This will display more precise answer if something in TCL shell fails
result = self._sysShell.tcl.eval("set errorInfo") result = self.tcl.eval("set errorInfo")
self._sysShell.log.error("Exec command Exception: %s" % (result + '\n')) self.app.log.error("Exec command Exception: %s" % (result + '\n'))
if no_echo is False: if no_echo is False:
self.append_error('ERROR: ' + result + '\n') self.append_error('ERROR: ' + result + '\n')
# Show error in console and just return or in test raise exception # Show error in console and just return or in test raise exception
@ -335,39 +412,101 @@ class FCShell(TermWidget):
pass pass
return result return result
# """ def raise_tcl_unknown_error(self, unknownException):
# Code below is unsused. Saved for later. """
# """ Raise exception if is different type than TclErrorException
this is here mainly to show unknown errors inside TCL shell console.
# parts = re.findall(r'([\w\\:\.]+|".*?")+', text) :param unknownException:
# parts = [p.replace('\n', '').replace('"', '') for p in parts] :return:
# self.log.debug(parts) """
# try:
# if parts[0] not in commands: if not isinstance(unknownException, self.TclErrorException):
# self.shell.append_error("Unknown command\n") self.raise_tcl_error("Unknown error: %s" % str(unknownException))
# return else:
# raise unknownException
# #import inspect
# #inspect.getargspec(someMethod) def display_tcl_error(self, error, error_info=None):
# if (type(commands[parts[0]]["params"]) is not list and len(parts)-1 != commands[parts[0]]["params"]) or \ """
# (type(commands[parts[0]]["params"]) is list and len(parts)-1 not in commands[parts[0]]["params"]): Escape bracket [ with '\' otherwise there is error
# self.shell.append_error( "ERROR: missing close-bracket" instead of real error
# "Command %s takes %d arguments. %d given.\n" %
# (parts[0], commands[parts[0]]["params"], len(parts)-1) :param error: it may be text or exception
# ) :param error_info: Some informations about the error
# return :return: None
# """
# cmdfcn = commands[parts[0]]["fcn"]
# cmdconv = commands[parts[0]]["converters"] if isinstance(error, Exception):
# if len(parts) - 1 > 0: exc_type, exc_value, exc_traceback = error_info
# retval = cmdfcn(*[cmdconv[i](parts[i + 1]) for i in range(len(parts)-1)]) if not isinstance(error, self.TclErrorException):
# else: show_trace = 1
# retval = cmdfcn() else:
# retfcn = commands[parts[0]]["retfcn"] show_trace = int(self.app.defaults['global_verbose_error_level'])
# if retval and retfcn(retval):
# self.shell.append_output(retfcn(retval) + "\n") if show_trace > 0:
# trc = traceback.format_list(traceback.extract_tb(exc_traceback))
# except Exception as e: trc_formated = []
# #self.shell.append_error(''.join(traceback.format_exc())) for a in reversed(trc):
# #self.shell.append_error("?\n") trc_formated.append(a.replace(" ", " > ").replace("\n", ""))
# self.shell.append_error(str(e) + "\n") text = "%s\nPython traceback: %s\n%s" % (exc_value, exc_type, "\n".join(trc_formated))
else:
text = "%s" % error
else:
text = error
text = text.replace('[', '\\[').replace('"', '\\"')
self.tcl.eval('return -code error "%s"' % text)
def raise_tcl_error(self, text):
"""
This method pass exception from python into TCL as error, so we get stacktrace and reason
:param text: text of error
:return: raise exception
"""
self.display_tcl_error(text)
raise self.TclErrorException(text)
class TclErrorException(Exception):
"""
this exception is defined here, to be able catch it if we successfully handle all errors from shell command
"""
pass
# """
# Code below is unsused. Saved for later.
# """
# parts = re.findall(r'([\w\\:\.]+|".*?")+', text)
# parts = [p.replace('\n', '').replace('"', '') for p in parts]
# self.log.debug(parts)
# try:
# if parts[0] not in commands:
# self.shell.append_error("Unknown command\n")
# return
#
# #import inspect
# #inspect.getargspec(someMethod)
# if (type(commands[parts[0]]["params"]) is not list and len(parts)-1 != commands[parts[0]]["params"]) or \
# (type(commands[parts[0]]["params"]) is list and len(parts)-1 not in commands[parts[0]]["params"]):
# self.shell.append_error(
# "Command %s takes %d arguments. %d given.\n" %
# (parts[0], commands[parts[0]]["params"], len(parts)-1)
# )
# return
#
# cmdfcn = commands[parts[0]]["fcn"]
# cmdconv = commands[parts[0]]["converters"]
# if len(parts) - 1 > 0:
# retval = cmdfcn(*[cmdconv[i](parts[i + 1]) for i in range(len(parts)-1)])
# else:
# retval = cmdfcn()
# retfcn = commands[parts[0]]["retfcn"]
# if retval and retfcn(retval):
# self.shell.append_output(retfcn(retval) + "\n")
#
# except Exception as e:
# #self.shell.append_error(''.join(traceback.format_exc()))
# #self.shell.append_error("?\n")
# self.shell.append_error(str(e) + "\n")

View File

@ -11,7 +11,6 @@ from flatcamGUI.GUIElements import FCComboBox, FCEntry, FCTable, \
FCInputDialog, FCDoubleSpinner, FCSpinner, FCFileSaveDialog FCInputDialog, FCDoubleSpinner, FCSpinner, FCFileSaveDialog
from FlatCAMApp import log from FlatCAMApp import log
from camlib import distance from camlib import distance
from FlatCAMObj import FlatCAMCNCjob
from flatcamEditors.FlatCAMTextEditor import TextEditor from flatcamEditors.FlatCAMTextEditor import TextEditor
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
@ -506,7 +505,8 @@ class SolderPaste(FlatCAMTool):
self.flat_geometry = [] self.flat_geometry = []
# action to be added in the combobox context menu # action to be added in the combobox context menu
self.combo_context_del_action = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/trash16.png'), _("Delete Object")) self.combo_context_del_action = QtWidgets.QAction(QtGui.QIcon(self.app.resource_location + '/trash16.png'),
_("Delete Object"))
# ## Signals # ## Signals
self.combo_context_del_action.triggered.connect(self.on_delete_object) self.combo_context_del_action.triggered.connect(self.on_delete_object)
@ -966,6 +966,7 @@ class SolderPaste(FlatCAMTool):
self.build_ui() self.build_ui()
return return
else: else:
old_tool_dia = ''
# identify the old tool_dia and restore the text in tool table # identify the old tool_dia and restore the text in tool table
for k, v in self.tooltable_tools.items(): for k, v in self.tooltable_tools.items():
if k == tooluid: if k == tooluid:
@ -1332,9 +1333,9 @@ class SolderPaste(FlatCAMTool):
# Object initialization function for app.new_object() # Object initialization function for app.new_object()
# RUNNING ON SEPARATE THREAD! # RUNNING ON SEPARATE THREAD!
def job_init(job_obj, app_obj): def job_init(job_obj):
assert isinstance(job_obj, FlatCAMCNCjob), \ assert job_obj.kind == 'cncjob', \
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj) "Initializer expected a CNCJobObject, got %s" % type(job_obj)
# this turn on the FlatCAMCNCJob plot for multiple tools # this turn on the FlatCAMCNCJob plot for multiple tools
job_obj.multitool = True job_obj.multitool = True
@ -1364,7 +1365,7 @@ class SolderPaste(FlatCAMTool):
res = job_obj.generate_gcode_from_solderpaste_geo(**tooluid_value) res = job_obj.generate_gcode_from_solderpaste_geo(**tooluid_value)
if res == 'fail': if res == 'fail':
log.debug("FlatCAMGeometry.mtool_gen_cncjob() --> generate_from_geometry2() failed") log.debug("GeometryObject.mtool_gen_cncjob() --> generate_from_geometry2() failed")
return 'fail' return 'fail'
else: else:
tool_cnc_dict['gcode'] = res tool_cnc_dict['gcode'] = res

View File

@ -8,7 +8,6 @@
from PyQt5 import QtWidgets from PyQt5 import QtWidgets
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, EvalEntry2 from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, EvalEntry2
from FlatCAMObj import FlatCAMCNCjob
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -681,7 +680,7 @@ class ToolTransform(FlatCAMTool):
try: try:
# first get a bounding box to fit all # first get a bounding box to fit all
for obj in obj_list: for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob): if obj.kind == 'cncjob':
pass pass
else: else:
xmin, ymin, xmax, ymax = obj.bounds() xmin, ymin, xmax, ymax = obj.bounds()
@ -699,7 +698,7 @@ class ToolTransform(FlatCAMTool):
px = 0.5 * (xminimal + xmaximal) px = 0.5 * (xminimal + xmaximal)
py = 0.5 * (yminimal + ymaximal) py = 0.5 * (yminimal + ymaximal)
for sel_obj in obj_list: for sel_obj in obj_list:
if isinstance(sel_obj, FlatCAMCNCjob): if sel_obj.kind == 'cncjob':
self.app.inform.emit(_("CNCJob objects can't be rotated.")) self.app.inform.emit(_("CNCJob objects can't be rotated."))
else: else:
sel_obj.rotate(-num, point=(px, py)) sel_obj.rotate(-num, point=(px, py))
@ -735,7 +734,7 @@ class ToolTransform(FlatCAMTool):
else: else:
# first get a bounding box to fit all # first get a bounding box to fit all
for obj in obj_list: for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob): if obj.kind == 'cncjob':
pass pass
else: else:
xmin, ymin, xmax, ymax = obj.bounds() xmin, ymin, xmax, ymax = obj.bounds()
@ -755,7 +754,7 @@ class ToolTransform(FlatCAMTool):
# execute mirroring # execute mirroring
for sel_obj in obj_list: for sel_obj in obj_list:
if isinstance(sel_obj, FlatCAMCNCjob): if sel_obj.kind == 'cncjob':
self.app.inform.emit(_("CNCJob objects can't be mirrored/flipped.")) self.app.inform.emit(_("CNCJob objects can't be mirrored/flipped."))
else: else:
if axis == 'X': if axis == 'X':
@ -803,7 +802,7 @@ class ToolTransform(FlatCAMTool):
try: try:
# first get a bounding box to fit all # first get a bounding box to fit all
for obj in obj_list: for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob): if obj.kind == 'cncjob':
pass pass
else: else:
xmin, ymin, xmax, ymax = obj.bounds() xmin, ymin, xmax, ymax = obj.bounds()
@ -815,7 +814,7 @@ class ToolTransform(FlatCAMTool):
yminimal = min(yminlist) yminimal = min(yminlist)
for sel_obj in obj_list: for sel_obj in obj_list:
if isinstance(sel_obj, FlatCAMCNCjob): if sel_obj.kind == 'cncjob':
self.app.inform.emit(_("CNCJob objects can't be skewed.")) self.app.inform.emit(_("CNCJob objects can't be skewed."))
else: else:
if axis == 'X': if axis == 'X':
@ -842,15 +841,14 @@ class ToolTransform(FlatCAMTool):
ymaxlist = [] ymaxlist = []
if not obj_list: if not obj_list:
self.app.inform.emit('[WARNING_NOTCL] %s' % self.app.inform.emit('[WARNING_NOTCL] %s' % _("No object selected. Please Select an object to scale!"))
_("No object selected. Please Select an object to scale!"))
return return
else: else:
with self.app.proc_container.new(_("Applying Scale")): with self.app.proc_container.new(_("Applying Scale")):
try: try:
# first get a bounding box to fit all # first get a bounding box to fit all
for obj in obj_list: for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob): if obj.kind == 'cncjob':
pass pass
else: else:
xmin, ymin, xmax, ymax = obj.bounds() xmin, ymin, xmax, ymax = obj.bounds()
@ -873,7 +871,7 @@ class ToolTransform(FlatCAMTool):
py = 0 py = 0
for sel_obj in obj_list: for sel_obj in obj_list:
if isinstance(sel_obj, FlatCAMCNCjob): if sel_obj.kind == 'cncjob':
self.app.inform.emit(_("CNCJob objects can't be scaled.")) self.app.inform.emit(_("CNCJob objects can't be scaled."))
else: else:
sel_obj.scale(xfactor, yfactor, point=(px, py)) sel_obj.scale(xfactor, yfactor, point=(px, py))
@ -883,8 +881,7 @@ class ToolTransform(FlatCAMTool):
self.app.object_changed.emit(sel_obj) self.app.object_changed.emit(sel_obj)
sel_obj.plot() sel_obj.plot()
self.app.inform.emit('[success] %s %s %s...' % self.app.inform.emit('[success] %s %s %s...' % (_('Scale on the'), str(axis), _('axis done')))
(_('Scale on the'), str(axis), _('axis done')))
except Exception as e: except Exception as e:
self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' % self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
(_("Due of"), str(e), _("action was not executed."))) (_("Due of"), str(e), _("action was not executed.")))
@ -894,14 +891,13 @@ class ToolTransform(FlatCAMTool):
obj_list = self.app.collection.get_selected() obj_list = self.app.collection.get_selected()
if not obj_list: if not obj_list:
self.app.inform.emit('[WARNING_NOTCL] %s' % self.app.inform.emit('[WARNING_NOTCL] %s' % _("No object selected. Please Select an object to offset!"))
_("No object selected. Please Select an object to offset!"))
return return
else: else:
with self.app.proc_container.new(_("Applying Offset")): with self.app.proc_container.new(_("Applying Offset")):
try: try:
for sel_obj in obj_list: for sel_obj in obj_list:
if isinstance(sel_obj, FlatCAMCNCjob): if sel_obj.kind == 'cncjob':
self.app.inform.emit(_("CNCJob objects can't be offset.")) self.app.inform.emit(_("CNCJob objects can't be offset."))
else: else:
if axis == 'X': if axis == 'X':
@ -915,8 +911,7 @@ class ToolTransform(FlatCAMTool):
self.app.object_changed.emit(sel_obj) self.app.object_changed.emit(sel_obj)
sel_obj.plot() sel_obj.plot()
self.app.inform.emit('[success] %s %s %s...' % self.app.inform.emit('[success] %s %s %s...' % (_('Offset on the'), str(axis), _('axis done')))
(_('Offset on the'), str(axis), _('axis done')))
except Exception as e: except Exception as e:
self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' % self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
(_("Due of"), str(e), _("action was not executed."))) (_("Due of"), str(e), _("action was not executed.")))
@ -932,7 +927,7 @@ class ToolTransform(FlatCAMTool):
with self.app.proc_container.new(_("Applying Buffer")): with self.app.proc_container.new(_("Applying Buffer")):
try: try:
for sel_obj in obj_list: for sel_obj in obj_list:
if isinstance(sel_obj, FlatCAMCNCjob): if sel_obj.kind == 'cncjob':
self.app.inform.emit(_("CNCJob objects can't be buffered.")) self.app.inform.emit(_("CNCJob objects can't be buffered."))
elif sel_obj.kind.lower() == 'gerber': elif sel_obj.kind.lower() == 'gerber':
sel_obj.buffer(value, join, factor) sel_obj.buffer(value, join, factor)

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -507,7 +507,7 @@ msgid "Failed. Select a Geometry Object and try again."
msgstr "" msgstr ""
#: FlatCAMApp.py:5652 FlatCAMApp.py:5688 #: FlatCAMApp.py:5652 FlatCAMApp.py:5688
msgid "Expected a FlatCAMGeometry, got" msgid "Expected a GeometryObject, got"
msgstr "" msgstr ""
#: FlatCAMApp.py:5665 #: FlatCAMApp.py:5665
@ -1125,7 +1125,7 @@ msgid "Open TCL script cancelled."
msgstr "" msgstr ""
#: FlatCAMApp.py:9993 #: FlatCAMApp.py:9993
msgid "Executing FlatCAMScript file." msgid "Executing ScriptObject file."
msgstr "" msgstr ""
#: FlatCAMApp.py:10000 FlatCAMApp.py:10003 #: FlatCAMApp.py:10000 FlatCAMApp.py:10003
@ -14705,7 +14705,7 @@ msgid "Buffer done"
msgstr "" msgstr ""
#: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73 #: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73
msgid "Expected FlatCAMGerber or FlatCAMGeometry, got" msgid "Expected GerberObject or GeometryObject, got"
msgstr "" msgstr ""
#: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68 #: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68

View File

@ -557,7 +557,7 @@ msgid "Failed. Select a Geometry Object and try again."
msgstr "Falha. Selecione um Objeto de Geometria e tente novamente." msgstr "Falha. Selecione um Objeto de Geometria e tente novamente."
#: FlatCAMApp.py:5652 FlatCAMApp.py:5688 #: FlatCAMApp.py:5652 FlatCAMApp.py:5688
msgid "Expected a FlatCAMGeometry, got" msgid "Expected a GeometryObject, got"
msgstr "Geometria FlatCAM esperada, recebido" msgstr "Geometria FlatCAM esperada, recebido"
#: FlatCAMApp.py:5665 #: FlatCAMApp.py:5665
@ -1211,7 +1211,7 @@ msgid "Open TCL script cancelled."
msgstr "Abrir script TCL cancelado." msgstr "Abrir script TCL cancelado."
#: FlatCAMApp.py:9993 #: FlatCAMApp.py:9993
msgid "Executing FlatCAMScript file." msgid "Executing ScriptObject file."
msgstr "Executando arquivo de Script FlatCAM." msgstr "Executando arquivo de Script FlatCAM."
#: FlatCAMApp.py:10000 FlatCAMApp.py:10003 #: FlatCAMApp.py:10000 FlatCAMApp.py:10003
@ -16677,8 +16677,8 @@ msgid "Buffer done"
msgstr "Buffer concluído" msgstr "Buffer concluído"
#: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73 #: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73
msgid "Expected FlatCAMGerber or FlatCAMGeometry, got" msgid "Expected GerberObject or GeometryObject, got"
msgstr "Esperando FlatCAMGerber ou FlatCAMGeometry, recebido" msgstr "Esperando GerberObject ou GeometryObject, recebido"
#: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68 #: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68
msgid "Expected a list of objects names separated by comma. Got" msgid "Expected a list of objects names separated by comma. Got"
@ -17323,8 +17323,8 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ msgid "<span style=\"color:red;\"><b>%s</b></span>" #~ msgid "<span style=\"color:red;\"><b>%s</b></span>"
#~ msgstr "<span style=\"color:red;\"><b>%s</b></span>" #~ msgstr "<span style=\"color:red;\"><b>%s</b></span>"
#~ msgid "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->" #~ msgid "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgstr "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->" #~ msgstr "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgid "FlatCAMCNNJob.on_edit_code_click() -->" #~ msgid "FlatCAMCNNJob.on_edit_code_click() -->"
#~ msgstr "FlatCAMCNNJob.on_edit_code_click() -->" #~ msgstr "FlatCAMCNNJob.on_edit_code_click() -->"
@ -17580,7 +17580,7 @@ msgstr "Nenhum nome de geometria nos argumentos. Altere e tente novamente."
#~ "flatcam/src/Beta/\">aqui.</a><BR>Área de <B>DOWNLOAD</B> <a href = " #~ "flatcam/src/Beta/\">aqui.</a><BR>Área de <B>DOWNLOAD</B> <a href = "
#~ "\"https://bitbucket.org/jpcgt/flatcam/downloads/\">aqui.</a><BR>" #~ "\"https://bitbucket.org/jpcgt/flatcam/downloads/\">aqui.</a><BR>"
#~ msgid "Expected a FlatCAMGeometry, got %s" #~ msgid "Expected a GeometryObject, got %s"
#~ msgstr "Geometria FlatCAM esperada, recebido %s" #~ msgstr "Geometria FlatCAM esperada, recebido %s"
#~ msgid "Saved to: %s" #~ msgid "Saved to: %s"

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -546,8 +546,8 @@ msgid "Failed. Select a Geometry Object and try again."
msgstr "Неудалось. Выберите объект Geometry и попробуйте снова." msgstr "Неудалось. Выберите объект Geometry и попробуйте снова."
#: FlatCAMApp.py:5652 FlatCAMApp.py:5688 #: FlatCAMApp.py:5652 FlatCAMApp.py:5688
msgid "Expected a FlatCAMGeometry, got" msgid "Expected a GeometryObject, got"
msgstr "Ожидается FlatCAMGeometry, получено" msgstr "Ожидается GeometryObject, получено"
#: FlatCAMApp.py:5665 #: FlatCAMApp.py:5665
msgid "A Geometry object was converted to MultiGeo type." msgid "A Geometry object was converted to MultiGeo type."
@ -1189,8 +1189,8 @@ msgid "Open TCL script cancelled."
msgstr "Открытие сценария отменено." msgstr "Открытие сценария отменено."
#: FlatCAMApp.py:9993 #: FlatCAMApp.py:9993
msgid "Executing FlatCAMScript file." msgid "Executing ScriptObject file."
msgstr "Выполнение файла FlatCAMScript." msgstr "Выполнение файла ScriptObject."
#: FlatCAMApp.py:10000 FlatCAMApp.py:10003 #: FlatCAMApp.py:10000 FlatCAMApp.py:10003
msgid "Run TCL script" msgid "Run TCL script"
@ -16746,8 +16746,8 @@ msgid "Buffer done"
msgstr "Буфер готов" msgstr "Буфер готов"
#: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73 #: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73
msgid "Expected FlatCAMGerber or FlatCAMGeometry, got" msgid "Expected GerberObject or GeometryObject, got"
msgstr "Ожидался FlatCAMGerber или FlatCAMGeometry, получено" msgstr "Ожидался GerberObject или GeometryObject, получено"
#: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68 #: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68
msgid "Expected a list of objects names separated by comma. Got" msgid "Expected a list of objects names separated by comma. Got"
@ -17431,8 +17431,8 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ msgid "<span style=\"color:red;\"><b>%s</b></span>" #~ msgid "<span style=\"color:red;\"><b>%s</b></span>"
#~ msgstr "<span style=\"color:red;\"><b>%s</b></span>" #~ msgstr "<span style=\"color:red;\"><b>%s</b></span>"
#~ msgid "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->" #~ msgid "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgstr "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->" #~ msgstr "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgid "FlatCAMCNNJob.on_edit_code_click() -->" #~ msgid "FlatCAMCNNJob.on_edit_code_click() -->"
#~ msgstr "FlatCAMCNNJob.on_edit_code_click() -->" #~ msgstr "FlatCAMCNNJob.on_edit_code_click() -->"
@ -17603,8 +17603,8 @@ msgstr "Нет имени геометрии в аргументах. Укажи
#~ "a><BR><b>ЗАГРУЗИТЬ</B> можно <a href = \"https://bitbucket.org/jpcgt/" #~ "a><BR><b>ЗАГРУЗИТЬ</B> можно <a href = \"https://bitbucket.org/jpcgt/"
#~ "flatcam/downloads/\">отсюда.</a><BR>" #~ "flatcam/downloads/\">отсюда.</a><BR>"
#~ msgid "Expected a FlatCAMGeometry, got %s" #~ msgid "Expected a GeometryObject, got %s"
#~ msgstr "Ожидается FlatCAMGeometry, получено %s" #~ msgstr "Ожидается GeometryObject, получено %s"
#~ msgid "Saved to: %s" #~ msgid "Saved to: %s"
#~ msgstr "Сохранёно в: %s" #~ msgstr "Сохранёно в: %s"

View File

@ -498,7 +498,7 @@ msgid "Failed. Select a Geometry Object and try again."
msgstr "" msgstr ""
#: FlatCAMApp.py:5765 FlatCAMApp.py:5801 #: FlatCAMApp.py:5765 FlatCAMApp.py:5801
msgid "Expected a FlatCAMGeometry, got" msgid "Expected a GeometryObject, got"
msgstr "" msgstr ""
#: FlatCAMApp.py:5778 #: FlatCAMApp.py:5778
@ -1056,7 +1056,7 @@ msgid "Open TCL script"
msgstr "" msgstr ""
#: FlatCAMApp.py:10373 #: FlatCAMApp.py:10373
msgid "Executing FlatCAMScript file." msgid "Executing ScriptObject file."
msgstr "" msgstr ""
#: FlatCAMApp.py:10381 FlatCAMApp.py:10384 #: FlatCAMApp.py:10381 FlatCAMApp.py:10384
@ -15065,7 +15065,7 @@ msgid "Buffer done"
msgstr "" msgstr ""
#: tclCommands/TclCommandBbox.py:76 tclCommands/TclCommandNregions.py:75 #: tclCommands/TclCommandBbox.py:76 tclCommands/TclCommandNregions.py:75
msgid "Expected FlatCAMGerber or FlatCAMGeometry, got" msgid "Expected GerberObject or GeometryObject, got"
msgstr "" msgstr ""
#: tclCommands/TclCommandBounds.py:67 tclCommands/TclCommandBounds.py:71 #: tclCommands/TclCommandBounds.py:67 tclCommands/TclCommandBounds.py:71

View File

@ -18,7 +18,7 @@ vispy
ortools>=7.0 ortools>=7.0
svg.path svg.path
simplejson simplejson
shapely>=1.3 shapely>=1.7.0
freetype-py freetype-py
fontTools fontTools
rasterio rasterio

View File

@ -71,7 +71,7 @@ class TclCommand(object):
:return: none :return: none
""" """
self.app.raise_tcl_error(text) self.app.shell.raise_tcl_error(text)
def get_current_command(self): def get_current_command(self):
""" """
@ -275,7 +275,7 @@ class TclCommand(object):
# because of signaling we cannot call error to TCL from here but when task # because of signaling we cannot call error to TCL from here but when task
# is finished also non-signaled are handled here to better exception # is finished also non-signaled are handled here to better exception
# handling and displayed after command is finished # handling and displayed after command is finished
raise self.app.TclErrorException(text) raise self.app.shell.TclErrorException(text)
def execute_wrapper(self, *args): def execute_wrapper(self, *args):
""" """
@ -296,7 +296,7 @@ class TclCommand(object):
except Exception as unknown: except Exception as unknown:
error_info = sys.exc_info() error_info = sys.exc_info()
self.log.error("TCL command '%s' failed. Error text: %s" % (str(self), str(unknown))) self.log.error("TCL command '%s' failed. Error text: %s" % (str(self), str(unknown)))
self.app.display_tcl_error(unknown, error_info) self.app.shell.display_tcl_error(unknown, error_info)
self.raise_tcl_unknown_error(unknown) self.raise_tcl_unknown_error(unknown)
@abc.abstractmethod @abc.abstractmethod
@ -400,9 +400,9 @@ class TclCommandSignaled(TclCommand):
raise ex[0] raise ex[0]
if status['timed_out']: if status['timed_out']:
self.app.raise_tcl_unknown_error("Operation timed outed! Consider increasing option " self.app.shell.raise_tcl_unknown_error("Operation timed outed! Consider increasing option "
"'-timeout <miliseconds>' for command or " "'-timeout <miliseconds>' for command or "
"'set_sys global_background_timeout <miliseconds>'.") "'set_sys global_background_timeout <miliseconds>'.")
try: try:
self.log.debug("TCL command '%s' executed." % str(type(self).__name__)) self.log.debug("TCL command '%s' executed." % str(type(self).__name__))
@ -439,5 +439,5 @@ class TclCommandSignaled(TclCommand):
else: else:
error_info = sys.exc_info() error_info = sys.exc_info()
self.log.error("TCL command '%s' failed." % str(self)) self.log.error("TCL command '%s' failed." % str(self))
self.app.display_tcl_error(unknown, error_info) self.app.shell.display_tcl_error(unknown, error_info)
self.raise_tcl_unknown_error(unknown) self.raise_tcl_unknown_error(unknown)

View File

@ -1,6 +1,5 @@
import collections import collections
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber, FlatCAMExcellon
from shapely.geometry import Point from shapely.geometry import Point
import shapely.affinity as affinity import shapely.affinity as affinity
@ -89,9 +88,7 @@ class TclCommandAlignDrill(TclCommandSignaled):
if obj is None: if obj is None:
return "Object not found: %s" % name return "Object not found: %s" % name
if not isinstance(obj, FlatCAMGeometry) and \ if obj.kind != "geometry" and obj.kind != 'gerber' and obj.kind != 'excellon':
not isinstance(obj, FlatCAMGerber) and \
not isinstance(obj, FlatCAMExcellon):
return "ERROR: Only Gerber, Geometry and Excellon objects can be used." return "ERROR: Only Gerber, Geometry and Excellon objects can be used."
# Axis # Axis

View File

@ -1,6 +1,5 @@
import collections import collections
from tclCommands.TclCommand import TclCommand from tclCommands.TclCommand import TclCommand
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
from shapely.ops import cascaded_union from shapely.ops import cascaded_union
@ -73,7 +72,7 @@ class TclCommandBbox(TclCommand):
if not isinstance(obj, FlatCAMGerber) and not isinstance(obj, FlatCAMGeometry): if not isinstance(obj, FlatCAMGerber) and not isinstance(obj, FlatCAMGeometry):
self.raise_tcl_error('%s %s: %s.' % ( self.raise_tcl_error('%s %s: %s.' % (
_("Expected FlatCAMGerber or FlatCAMGeometry, got"), name, type(obj))) _("Expected GerberObject or GeometryObject, got"), name, type(obj)))
if 'margin' not in args: if 'margin' not in args:
args['margin'] = float(self.app.defaults["gerber_bboxmargin"]) args['margin'] = float(self.app.defaults["gerber_bboxmargin"])
@ -92,7 +91,7 @@ class TclCommandBbox(TclCommand):
try: try:
def geo_init(geo_obj, app_obj): def geo_init(geo_obj, app_obj):
assert isinstance(geo_obj, FlatCAMGeometry) # assert geo_obj.kind == 'geometry'
# Bounding box with rounded corners # Bounding box with rounded corners
geo = cascaded_union(obj.solid_geometry) geo = cascaded_union(obj.solid_geometry)

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMGeometry
import collections import collections
from copy import deepcopy from copy import deepcopy
@ -119,9 +118,9 @@ class TclCommandCncjob(TclCommandSignaled):
else: else:
return "fail" return "fail"
if not isinstance(obj, FlatCAMGeometry): if obj.kind != 'geometry':
if muted is False: if muted is False:
self.raise_tcl_error('Expected FlatCAMGeometry, got %s %s.' % (str(name), type(obj))) self.raise_tcl_error('Expected GeometryObject, got %s %s.' % (str(name), type(obj)))
else: else:
return return

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMExcellon
import collections import collections
import math import math
@ -125,9 +124,9 @@ class TclCommandDrillcncjob(TclCommandSignaled):
else: else:
return "fail" return "fail"
if not isinstance(obj, FlatCAMExcellon): if obj.kind != 'excellon':
if muted is False: if muted is False:
self.raise_tcl_error('Expected FlatCAMExcellon, got %s %s.' % (name, type(obj))) self.raise_tcl_error('Expected ExcellonObject, got %s %s.' % (name, type(obj)))
else: else:
return "fail" return "fail"

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMGerber
import collections import collections
@ -56,8 +55,8 @@ class TclCommandFollow(TclCommandSignaled):
if obj is None: if obj is None:
self.raise_tcl_error("Object not found: %s" % name) self.raise_tcl_error("Object not found: %s" % name)
if not isinstance(obj, FlatCAMGerber): if obj.kind != 'gerber':
self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj))) self.raise_tcl_error('Expected GerberObject, got %s %s.' % (name, type(obj)))
del args['name'] del args['name']
try: try:

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
import logging import logging
import collections import collections
@ -209,7 +208,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
except ValueError: except ValueError:
gaps_u = gaps gaps_u = gaps
if isinstance(cutout_obj, FlatCAMGeometry): if cutout_obj.kind == 'geometry':
# rename the obj name so it can be identified as cutout # rename the obj name so it can be identified as cutout
# cutout_obj.options["name"] += "_cutout" # cutout_obj.options["name"] += "_cutout"
@ -306,7 +305,7 @@ class TclCommandGeoCutout(TclCommandSignaled):
# cutout_obj.plot() # cutout_obj.plot()
# self.app.inform.emit("[success] Any-form Cutout operation finished.") # self.app.inform.emit("[success] Any-form Cutout operation finished.")
# self.app.plots_updated.emit() # self.app.plots_updated.emit()
elif isinstance(cutout_obj, FlatCAMGerber): elif cutout_obj.kind == 'gerber':
def geo_init(geo_obj, app_obj): def geo_init(geo_obj, app_obj):
try: try:

View File

@ -65,10 +65,11 @@ class TclCommandHelp(TclCommand):
if 'name' in args: if 'name' in args:
name = args['name'] name = args['name']
if name not in self.app.tcl_commands_storage: if name not in self.app.shell.tcl_commands_storage:
return "Unknown command: %s" % name return "Unknown command: %s" % name
self.app.shell.append_output(self.app.tcl_commands_storage[name]["help"]) help_for_command = self.app.shell.tcl_commands_storage[name]["help"] + '\n\n'
self.app.shell.append_output(help_for_command)
else: else:
if not args: if not args:
cmd_enum = '%s\n' % _("Available commands:") cmd_enum = '%s\n' % _("Available commands:")
@ -77,19 +78,21 @@ class TclCommandHelp(TclCommand):
try: try:
# find the maximum length of a command name # find the maximum length of a command name
max_len = 0 max_len = 0
for cmd_name in self.app.tcl_commands_storage: for cmd_name in self.app.shell.tcl_commands_storage:
curr_len = len(cmd_name) curr_len = len(cmd_name)
if curr_len > max_len: if curr_len > max_len:
max_len = curr_len max_len = curr_len
h_space = "&nbsp;" h_space = "&nbsp;"
cnt = 0 cnt = 0
for cmd_name in sorted(self.app.tcl_commands_storage): for cmd_name in sorted(self.app.shell.tcl_commands_storage):
cmd_description = "<span>%s</span>" % self.app.tcl_commands_storage[cmd_name]['description'] cmd_description = "<span>%s</span>" % \
self.app.shell.tcl_commands_storage[cmd_name]['description']
curr_len = len(cmd_name) curr_len = len(cmd_name)
cmd_name_colored = "<span style=\" font-weight: bold; color: red;\" >%s</span>" % str(cmd_name) cmd_name_colored = "> <span style=\" font-weight: bold; color: red;\" >%s</span>" % \
str(cmd_name)
nr_chars = max_len - curr_len nr_chars = max_len - curr_len
@ -104,11 +107,11 @@ class TclCommandHelp(TclCommand):
else: else:
cnt += 1 cnt += 1
except Exception as err: except Exception as err:
self.app.log.debug("App.setup_shell.shelp() when run as 'help' --> %s" % str(err)) self.app.log.debug("tclCommands.TclCommandHelp() when run as 'help' --> %s" % str(err))
displayed_text = ['> %s\n' % cmd for cmd in sorted(self.app.tcl_commands_storage)] displayed_text = ['> %s' % cmd for cmd in sorted(self.app.shell.tcl_commands_storage)]
cmd_enum += '<br>'.join(displayed_text) cmd_enum += '<br>'.join(displayed_text)
cmd_enum += '<br><br>%s<br>%s<br>' % ( cmd_enum += '<br><br>%s<br>%s<br><br>' % (
_("Type help <command_name> for usage."), _("Example: help open_gerber")) _("Type help <command_name> for usage."), _("Example: help open_gerber"))
self.app.shell.append_raw(cmd_enum) self.app.shell.append_raw(cmd_enum)

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMGerber
import collections import collections
@ -96,8 +95,8 @@ class TclCommandIsolate(TclCommandSignaled):
if obj is None: if obj is None:
self.raise_tcl_error("Object not found: %s" % name) self.raise_tcl_error("Object not found: %s" % name)
if not isinstance(obj, FlatCAMGerber): if obj.kind != 'gerber':
self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (name, type(obj))) self.raise_tcl_error('Expected GerberObject, got %s %s.' % (name, type(obj)))
del args['name'] del args['name']
obj.isolate(plot=False, **args) obj.isolate(plot=False, **args)

View File

@ -1,5 +1,5 @@
from tclCommands.TclCommand import TclCommand from tclCommands.TclCommand import TclCommand
from FlatCAMObj import FlatCAMExcellon from flatcamObjects.FlatCAMExcellon import ExcellonObject
import collections import collections
@ -62,7 +62,7 @@ class TclCommandJoinExcellon(TclCommand):
objs.append(obj) objs.append(obj)
def initialize(obj_, app): def initialize(obj_, app):
FlatCAMExcellon.merge(self, objs, obj_) ExcellonObject.merge(self, objs, obj_)
if objs and len(objs) >= 2: if objs and len(objs) >= 2:
self.app.new_object("excellon", outname, initialize, plot=False) self.app.new_object("excellon", outname, initialize, plot=False)

View File

@ -1,5 +1,5 @@
from tclCommands.TclCommand import TclCommand from tclCommands.TclCommand import TclCommand
from FlatCAMObj import FlatCAMGeometry from flatcamObjects.FlatCAMGeometry import GeometryObject
import collections import collections
@ -62,7 +62,7 @@ class TclCommandJoinGeometry(TclCommand):
objs.append(obj) objs.append(obj)
def initialize(obj_, app): def initialize(obj_, app):
FlatCAMGeometry.merge(self, objs, obj_) GeometryObject.merge(self, objs, obj_)
if objs and len(objs) >= 2: if objs and len(objs) >= 2:
self.app.new_object("geometry", outname, initialize, plot=False) self.app.new_object("geometry", outname, initialize, plot=False)

View File

@ -6,7 +6,6 @@
# ########################################################## # ##########################################################
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMExcellon
import math import math
import collections import collections
@ -138,7 +137,7 @@ class TclCommandMillDrills(TclCommandSignaled):
except Exception as e: except Exception as e:
self.raise_tcl_error("Bad tools: %s" % str(e)) self.raise_tcl_error("Bad tools: %s" % str(e))
if not isinstance(obj, FlatCAMExcellon): if obj.kind != 'excellon':
self.raise_tcl_error('Only Excellon objects can be mill-drilled, got %s %s.' % (name, type(obj))) self.raise_tcl_error('Only Excellon objects can be mill-drilled, got %s %s.' % (name, type(obj)))
if self.app.collection.has_promises(): if self.app.collection.has_promises():

View File

@ -6,7 +6,6 @@
# ########################################################## # ##########################################################
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMExcellon
import collections import collections
import math import math
@ -139,7 +138,7 @@ class TclCommandMillSlots(TclCommandSignaled):
except Exception as e: except Exception as e:
self.raise_tcl_error("Bad tools: %s" % str(e)) self.raise_tcl_error("Bad tools: %s" % str(e))
if not isinstance(obj, FlatCAMExcellon): if obj.kind != 'excellon':
self.raise_tcl_error('Only Excellon objects can have mill-slots, got %s %s.' % (name, type(obj))) self.raise_tcl_error('Only Excellon objects can have mill-slots, got %s %s.' % (name, type(obj)))
if self.app.collection.has_promises(): if self.app.collection.has_promises():

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMExcellon, FlatCAMGeometry, FlatCAMGerber
import collections import collections
@ -68,9 +67,7 @@ class TclCommandMirror(TclCommandSignaled):
if obj is None: if obj is None:
return "Object not found: %s" % name return "Object not found: %s" % name
if not isinstance(obj, FlatCAMGerber) and \ if obj.kind != 'gerber' and obj.kind != 'geometry' and obj.kind != 'excellon':
not isinstance(obj, FlatCAMExcellon) and \
not isinstance(obj, FlatCAMGeometry):
return "ERROR: Only Gerber, Excellon and Geometry objects can be mirrored." return "ERROR: Only Gerber, Excellon and Geometry objects can be mirrored."
# Axis # Axis

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommand from tclCommands.TclCommand import TclCommand
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
from shapely.ops import cascaded_union from shapely.ops import cascaded_union
@ -71,8 +70,8 @@ class TclCommandNregions(TclCommand):
if obj is None: if obj is None:
self.raise_tcl_error("%s: %s" % (_("Object not found"), name)) self.raise_tcl_error("%s: %s" % (_("Object not found"), name))
if not isinstance(obj, FlatCAMGerber) and not isinstance(obj, FlatCAMGeometry): if obj.kind != 'gerber' and obj.kind != 'geometry':
self.raise_tcl_error('%s %s: %s.' % (_("Expected FlatCAMGerber or FlatCAMGeometry, got"), name, type(obj))) self.raise_tcl_error('%s %s: %s.' % (_("Expected GerberObject or GeometryObject, got"), name, type(obj)))
if 'margin' not in args: if 'margin' not in args:
args['margin'] = float(self.app.defaults["gerber_noncoppermargin"]) args['margin'] = float(self.app.defaults["gerber_noncoppermargin"])
@ -91,7 +90,7 @@ class TclCommandNregions(TclCommand):
try: try:
def geo_init(geo_obj, app_obj): def geo_init(geo_obj, app_obj):
assert isinstance(geo_obj, FlatCAMGeometry) assert geo_obj.kind == 'geometry'
geo = cascaded_union(obj.solid_geometry) geo = cascaded_union(obj.solid_geometry)
bounding_box = geo.envelope.buffer(float(margin)) bounding_box = geo.envelope.buffer(float(margin))

View File

@ -1,6 +1,5 @@
from tclCommands.TclCommand import TclCommandSignaled from tclCommands.TclCommand import TclCommandSignaled
from camlib import ParseError from camlib import ParseError
from FlatCAMObj import FlatCAMGerber
import collections import collections
@ -53,8 +52,8 @@ class TclCommandOpenGerber(TclCommandSignaled):
# How the object should be initialized # How the object should be initialized
def obj_init(gerber_obj, app_obj): def obj_init(gerber_obj, app_obj):
if not isinstance(gerber_obj, FlatCAMGerber): if gerber_obj.kind != 'gerber':
self.raise_tcl_error('Expected FlatCAMGerber, got %s %s.' % (outname, type(gerber_obj))) self.raise_tcl_error('Expected GerberObject, got %s %s.' % (outname, type(gerber_obj)))
# Opening the file happens here # Opening the file happens here
try: try:

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommand from tclCommands.TclCommand import TclCommand
from FlatCAMObj import FlatCAMGeometry, FlatCAMExcellon
import shapely.affinity as affinity import shapely.affinity as affinity
@ -153,12 +152,12 @@ class TclCommandPanelize(TclCommand):
# objs.append(obj_init) # objs.append(obj_init)
# #
# def initialize_geometry(obj_init, app): # def initialize_geometry(obj_init, app):
# FlatCAMGeometry.merge(objs, obj_init) # GeometryObject.merge(objs, obj_init)
# #
# def initialize_excellon(obj_init, app): # def initialize_excellon(obj_init, app):
# # merge expects tools to exist in the target object # # merge expects tools to exist in the target object
# obj_init.tools = obj.tools.copy() # obj_init.tools = obj.tools.copy()
# FlatCAMExcellon.merge(objs, obj_init) # ExcellonObject.merge(objs, obj_init)
# #
# objs = [] # objs = []
# if obj is not None: # if obj is not None:
@ -167,7 +166,7 @@ class TclCommandPanelize(TclCommand):
# currentx = 0 # currentx = 0
# for col in range(columns): # for col in range(columns):
# local_outname = outname + ".tmp." + str(col) + "." + str(row) # local_outname = outname + ".tmp." + str(col) + "." + str(row)
# if isinstance(obj, FlatCAMExcellon): # if isinstance(obj, ExcellonObject):
# self.app.new_object("excellon", local_outname, initialize_local_excellon, plot=False, # self.app.new_object("excellon", local_outname, initialize_local_excellon, plot=False,
# autoselected=False) # autoselected=False)
# else: # else:
@ -177,7 +176,7 @@ class TclCommandPanelize(TclCommand):
# currentx += lenghtx # currentx += lenghtx
# currenty += lenghty # currenty += lenghty
# #
# if isinstance(obj, FlatCAMExcellon): # if isinstance(obj, ExcellonObject):
# self.app.new_object("excellon", outname, initialize_excellon) # self.app.new_object("excellon", outname, initialize_excellon)
# else: # else:
# self.app.new_object("geometry", outname, initialize_geometry) # self.app.new_object("geometry", outname, initialize_geometry)
@ -258,7 +257,7 @@ class TclCommandPanelize(TclCommand):
obj_fin.solid_geometry = [] obj_fin.solid_geometry = []
if isinstance(obj, FlatCAMGeometry): if obj.kind == 'geometry':
obj_fin.multigeo = obj.multigeo obj_fin.multigeo = obj.multigeo
obj_fin.tools = deepcopy(obj.tools) obj_fin.tools = deepcopy(obj.tools)
if obj.multigeo is True: if obj.multigeo is True:
@ -269,7 +268,7 @@ class TclCommandPanelize(TclCommand):
currentx = 0.0 currentx = 0.0
for col in range(columns): for col in range(columns):
if isinstance(obj, FlatCAMGeometry): if obj.kind == 'geometry':
if obj.multigeo is True: if obj.multigeo is True:
for tool in obj.tools: for tool in obj.tools:
obj_fin.tools[tool]['solid_geometry'].append(translate_recursion( obj_fin.tools[tool]['solid_geometry'].append(translate_recursion(
@ -287,7 +286,7 @@ class TclCommandPanelize(TclCommand):
currentx += lenghtx currentx += lenghtx
currenty += lenghty currenty += lenghty
if isinstance(obj, FlatCAMExcellon): if obj.kind == 'excellon':
self.app.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True) self.app.new_object("excellon", outname, job_init_excellon, plot=False, autoselected=True)
else: else:
self.app.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True) self.app.new_object("geometry", outname, job_init_geometry, plot=False, autoselected=True)