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
- 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.
- 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
@ -282,7 +299,7 @@ CHANGELOG for FlatCAM beta
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: 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
- 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
- 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)
- updated the preprocessor files
- 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
- some small changes in the Scale button handler in FlatCAMObj() class
- 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
- 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
- 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 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
- updated the POT file
- fixed an error in the German PO file
@ -801,7 +818,7 @@ CHANGELOG for FlatCAM beta
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
@ -819,7 +836,7 @@ CHANGELOG for FlatCAM beta
- In Gerber isolation changed the UI
- 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
- 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
@ -830,7 +847,7 @@ CHANGELOG for FlatCAM beta
- in Tool Fiducials added a new fiducial type: chess pattern
- 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
- 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
@ -842,7 +859,7 @@ CHANGELOG for FlatCAM beta
- Tool Fiducials - updated the source_file object for the modified Gerber files
- working on adding line numbers to the TextPlainEdit
- 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
@ -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
- 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)
- 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
@ -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
- 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
- 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
- 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
- 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
6.10.2019
@ -1193,20 +1210,20 @@ CHANGELOG for FlatCAM beta
3.10.2019
- previously I've added the initial layout for the FlatCAMDocument object
- added more editing features in the Selected Tab 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 DocumentObject object
2.10.2019
- 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
- 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 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 name of the new object FlatCAMNotes to a more general one DocumentObject
- 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
- adapted the Project context menu for the new types of 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 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
- 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 two new FlatCAM objects: FlatCAMScript and FlatCAMNotes
- added two new FlatCAM objects: ScriptObject and FlatCAMNotes
30.09.2019
@ -1443,7 +1460,7 @@ CHANGELOG for FlatCAM beta
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
- 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)
@ -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)
- 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
- 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
- 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
@ -1914,7 +1931,7 @@ CHANGELOG for FlatCAM beta
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 PEP8 cleanup in FlatCAMObj.py
- 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 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
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
- 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
- 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
- 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
- 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
- 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
- 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 '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.
- 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
- 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
@ -2863,7 +2880,7 @@ CHANGELOG for FlatCAM beta
- finished Gerber aperture table display
- 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'
- added (and commented) an experimental FlatCAMObj.FlatCAMGerber.plot_aperture()
- added (and commented) an experimental FlatCAMObj.GerberObject.plot_aperture()
12.02.2019
@ -3052,7 +3069,7 @@ CHANGELOG for FlatCAM beta
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
- 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
@ -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)
- fixed GRBL_laser preprocessor file
- 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
- 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.
- 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
- fixed TclCommand Cutout
- added a new TclCommand named CutoutAny. Keyword: cutout_any
@ -3164,7 +3181,7 @@ CHANGELOG for FlatCAM beta
- 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)
- 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
@ -3246,8 +3263,8 @@ CHANGELOG for FlatCAM beta
18.12.2018
- small changes in FlatCAMGeometry.plot()
- updated the FlatCAMGeometry.merge() function and the Join Geometry feature to accommodate the different types of geometries: singlegeo and multigeo type
- small changes in GeometryObject.plot()
- 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 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

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
# module-root dictionary of preprocessors
import FlatCAMApp
import logging
log = logging.getLogger('base')
preprocessors = {}
@ -23,7 +25,7 @@ class ABCPostProcRegister(ABCMeta):
newclass = super(ABCPostProcRegister, cls).__new__(cls, clsname, bases, attrs)
if object not in bases:
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
return newclass

View File

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

View File

@ -16,10 +16,15 @@ from PyQt5.QtCore import Qt, QSettings
from PyQt5.QtGui import QColor
# from PyQt5.QtCore import QModelIndex
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon, FlatCAMCNCjob, FlatCAMDocument, FlatCAMScript, \
FlatCAMObj
from flatcamObjects.FlatCAMObj import 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 FlatCAMApp
import re
import logging
@ -234,12 +239,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
]
classdict = {
"gerber": FlatCAMGerber,
"excellon": FlatCAMExcellon,
"cncjob": FlatCAMCNCjob,
"geometry": FlatCAMGeometry,
"script": FlatCAMScript,
"document": FlatCAMDocument
"gerber": GerberObject,
"excellon": ExcellonObject,
"cncjob": CNCJobObject,
"geometry": GeometryObject,
"script": ScriptObject,
"document": DocumentObject
}
icon_files = {
@ -332,7 +337,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.update_list_signal.connect(self.on_update_list_signal)
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)
def has_promises(self):
@ -349,7 +354,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
return len(self.plot_promises) > 0
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):
@ -373,17 +378,17 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.ui.menuprojectcolor.setEnabled(False)
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)
if type(obj) != FlatCAMGeometry:
if type(obj) != GeometryObject:
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)
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)
if type(obj) != FlatCAMGerber and type(obj) != FlatCAMGeometry and type(obj) != FlatCAMExcellon and \
type(obj) != FlatCAMCNCjob:
if type(obj) != GerberObject and type(obj) != GeometryObject and type(obj) != ExcellonObject and \
type(obj) != CNCJobObject:
# meaning for Scripts and for Document type of FlatCAM object
self.app.ui.menuprojectenable.setVisible(False)
self.app.ui.menuprojectdisable.setVisible(False)
@ -532,21 +537,21 @@ class ObjectCollection(QtCore.QAbstractItemModel):
# return QtWidgets.QAbstractItemModel.flags(self, index)
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"]
# Check promises and clear if exists
if name in self.promises:
self.promises.remove(name)
# FlatCAMApp.App.log.debug("Promised object %s became available." % name)
# FlatCAMApp.App.log.debug("%d promised objects remaining." % len(self.promises))
# log.debug("Promised object %s became available." % name)
# log.debug("%d promised objects remaining." % len(self.promises))
# Prevent same name
while name in self.get_names():
# ## Create a new name
# 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)
if match: # Yes: Increment the number!
base = match.group(1) or ''
@ -596,7 +601,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
: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()]
def get_bounds(self):
@ -606,7 +611,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
:return: [xmin, ymin, xmax, ymax]
: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.
@ -624,7 +629,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
xmax = max([xmax, gxmax])
ymax = max([ymax, gymax])
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]
@ -638,7 +643,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
:return: The requested object or None if no such object.
: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:
for obj in self.get_list():
@ -760,7 +765,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.all_objects_list = self.get_list()
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', '')
@ -897,8 +902,15 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.set_inactive(name)
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:
obj = current.indexes()[0].internalPointer().obj
@ -942,12 +954,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
)
except IndexError:
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('')
try:
self.app.ui.selected_scroll_area.takeWidget()
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()
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 flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
from flatcamParsers.ParseExcellon import Excellon
import FlatCAMApp
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point
import shapely.affinity as affinity
@ -179,7 +178,7 @@ class FCDrillArray(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception as e:
except Exception:
pass
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
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__()
@ -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
self.editor_active = False
def entry2option(option, entry):
self.options[option] = float(entry.text())
# def entry2option(option, entry):
# self.options[option] = float(entry.text())
# Event signals disconnect id holders
self.mp = None
@ -2388,7 +2387,7 @@ class FlatCAMExcEditor(QtCore.QObject):
try:
# 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:
slot_cnt += 1
@ -2661,15 +2660,13 @@ class FlatCAMExcEditor(QtCore.QObject):
# self.tools_table_exc.selectionModel().currentChanged.disconnect()
self.is_modified = True
new_dia = None
# new_dia = None
if self.tools_table_exc.currentItem() is not None:
try:
new_dia = float(self.tools_table_exc.currentItem().text())
except ValueError as e:
log.debug("FlatCAMExcEditor.on_tool_edit() --> %s" % str(e))
self.tools_table_exc.setCurrentItem(None)
return
try:
new_dia = float(self.tools_table_exc.currentItem().text())
except ValueError as e:
log.debug("FlatCAMExcEditor.on_tool_edit() --> %s" % str(e))
return
row_of_item_changed = self.tools_table_exc.currentRow()
# 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
into the editor.
:param exc_obj: FlatCAMExcellon object
:param exc_obj: ExcellonObject object
: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
:param exc_obj: FlatCAMExcellon
:param exc_obj: ExcellonObject
:return: None
"""
@ -3297,7 +3294,8 @@ class FlatCAMExcEditor(QtCore.QObject):
return self.edited_obj_name
def update_options(self, obj):
@staticmethod
def update_options(obj):
try:
if not obj.options:
obj.options = {}
@ -3316,10 +3314,14 @@ class FlatCAMExcEditor(QtCore.QObject):
"""
Creates a new Excellon object for the edited Excellon. Thread-safe.
:param outname: Name of the resulting object. None causes the
name to be that of the file.
:type outname: str
:return: None
:param outname: Name of the resulting object. None causes the
name to be that of the file.
:type outname: str
: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" %
@ -3429,12 +3431,12 @@ class FlatCAMExcEditor(QtCore.QObject):
self.replot()
def toolbar_tool_toggle(self, key):
self.options[key] = self.sender().isChecked()
if self.options[key] is True:
return 1
else:
return 0
# def toolbar_tool_toggle(self, key):
# self.options[key] = self.sender().isChecked()
# if self.options[key] is True:
# return 1
# else:
# return 0
def on_canvas_click(self, event):
"""
@ -3446,12 +3448,12 @@ class FlatCAMExcEditor(QtCore.QObject):
"""
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
right_button = 2
# event_is_dragging = event.is_dragging
# right_button = 2
else:
event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3
# event_is_dragging = self.app.plotcanvas.is_dragging
# right_button = 3
self.pos = self.canvas.translate_coords(event_pos)
@ -3575,8 +3577,8 @@ class FlatCAMExcEditor(QtCore.QObject):
if isinstance(shape, DrawToolUtilityShape):
self.utility.append(shape)
else:
self.storage.insert(shape) # TODO: Check performance
# else:
# self.storage.insert(shape)
def on_exc_click_release(self, event):
"""
@ -3591,11 +3593,11 @@ class FlatCAMExcEditor(QtCore.QObject):
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
# event_is_dragging = event.is_dragging
right_button = 2
else:
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
pos_canvas = self.canvas.translate_coords(event_pos)
@ -4027,7 +4029,7 @@ class FlatCAMExcEditor(QtCore.QObject):
del self.slot_points_edit[storage][0]
if del_shape in self.selected:
self.selected.remove(del_shape) # TODO: Check performance
self.selected.remove(del_shape)
def delete_utility_geometry(self):
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, \
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog, FCTree
from flatcamParsers.ParseFont import *
import FlatCAMApp
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
from shapely.ops import cascaded_union, unary_union, linemerge
@ -88,8 +87,8 @@ class BufferSelectionTool(FlatCAMTool):
self.buffer_corner_lbl.setToolTip(
_("There are 3 types of corners:\n"
" - 'Round': the corner is rounded 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")
" - '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")
)
self.buffer_corner_cb = FCComboBox()
self.buffer_corner_cb.addItem(_("Round"))
@ -3299,8 +3298,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
draw_shape_idx = -1
def __init__(self, app, disabled=False):
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(FlatCAMGeoEditor, self).__init__()
@ -4011,6 +4010,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
:return: Boolean. Status of the checkbox that toggled the Editor Tool
"""
cb_widget = self.sender()
assert isinstance(cb_widget, QtWidgets.QAction), "Expected a QAction got %s" % type(cb_widget)
self.options[key] = cb_widget.isChecked()
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
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'
:return: None
"""
@ -4750,7 +4750,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
Transfers the geometry tool shape buffer to the selected geometry
object. The geometry already in the object are removed.
:param fcgeometry: FlatCAMGeometry
:param fcgeometry: GeometryObject
:return: None
"""
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, \
EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
from FlatCAMTool import FlatCAMTool
import FlatCAMApp
import numpy as np
from numpy.linalg import norm as numpy_norm
@ -182,6 +181,7 @@ class FCShapeTool(DrawTool):
def __init__(self, draw_app):
DrawTool.__init__(self, draw_app)
self.name = None
def make(self):
pass
@ -199,7 +199,7 @@ class FCPad(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception as e:
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_circle.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
@ -1415,7 +1415,7 @@ class FCDisc(FCShapeTool):
try:
QtGui.QGuiApplication.restoreOverrideCursor()
except Exception as e:
except Exception:
pass
self.cursor = QtGui.QCursor(QtGui.QPixmap(self.draw_app.app.resource_location + '/aero_disc.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
@ -2422,8 +2422,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
mp_finished = QtCore.pyqtSignal(list)
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(FlatCAMGrbEditor, self).__init__()
@ -2621,8 +2621,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.buffer_corner_lbl.setToolTip(
_("There are 3 types of corners:\n"
" - 'Round': the corner is rounded.\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")
" - '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")
)
self.buffer_corner_cb = FCComboBox()
self.buffer_corner_cb.addItem(_("Round"))
@ -3479,7 +3479,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
current_table_dia_edited = float(self.apertures_table.currentItem().text())
except ValueError as e:
log.debug("FlatCAMExcEditor.on_tool_edit() --> %s" % str(e))
self.apertures_table.setCurrentItem(None)
# self.apertures_table.setCurrentItem(None)
return
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
into the editor.
:param orig_grb_obj: FlatCAMExcellon
:param orig_grb_obj: ExcellonObject
:return: None
"""
@ -3956,10 +3956,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
global_clear_geo = []
# 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
if 'geometry' in app_obj.gerber_obj.apertures[apid]:
for elem in app_obj.gerber_obj.apertures[apid]['geometry']:
if 'geometry' in app_obj.gerber_obj.apertures[aper_id]:
for elem in app_obj.gerber_obj.apertures[aper_id]['geometry']:
if 'clear' in elem:
global_clear_geo.append(elem['clear'])
log.warning("Found %d clear polygons." % len(global_clear_geo))
@ -3967,7 +3967,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
if global_clear_geo:
global_clear_geo = MultiPolygon(global_clear_geo)
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
# 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']
# for clear_geo in global_clear_geo:
# # 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
# # delete it
# # the solid_geometry. We want for clear_geometry just to cut
# # into solid_geometry not to delete it
# if clear_geo.within(solid_geo):
# solid_geo = solid_geo.difference(clear_geo)
# try:
@ -4307,14 +4307,14 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.plot_all()
def toolbar_tool_toggle(self, key):
"""
:param key: key to update in self.options dictionary
:return:
"""
self.options[key] = self.sender().isChecked()
return self.options[key]
# def toolbar_tool_toggle(self, key):
# """
#
# :param key: key to update in self.options dictionary
# :return:
# """
# self.options[key] = self.sender().isChecked()
# return self.options[key]
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:
event_pos = event.pos
event_is_dragging = event.is_dragging
right_button = 2
# event_is_dragging = event.is_dragging
# right_button = 2
else:
event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3
# event_is_dragging = self.app.plotcanvas.is_dragging
# right_button = 3
self.pos = self.canvas.translate_coords(event_pos)
@ -4457,11 +4457,11 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.modifiers = QtWidgets.QApplication.keyboardModifiers()
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
# event_is_dragging = event.is_dragging
right_button = 2
else:
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
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
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 color: Shape color
:param linewidth: Width of lines in # of pixels.
:return: List of plotted elements.
:param geometry: Geometry to be plotted (Any Shapely.geom kind or list of such)
:param color: Shape color
:param linewidth: Width of lines in # of pixels.
:return: List of plotted elements.
"""
if geometry is None:
@ -5597,7 +5597,7 @@ class TransformEditorTool(FlatCAMTool):
self.flip_ref_entry.set_value((0, 0))
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."))
return

View File

@ -2876,7 +2876,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Open Excellon file
if key == QtCore.Qt.Key_E:
self.app.on_fileopenexcellon()
self.app.on_fileopenexcellon(signal=None)
# Open Gerber file
if key == QtCore.Qt.Key_G:
@ -2884,7 +2884,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if 'editor' in widget_name.lower():
self.app.goto_text_line()
else:
self.app.on_fileopengerber()
self.app.on_fileopengerber(signal=None)
# Distance Tool
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_range(-9999.9999, 9999.9999)
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_entry, 13, 1)
@ -1258,7 +1259,7 @@ class ExcellonObjectUI(ObjectUI):
self.feedrate_probe_entry.set_precision(self.decimals)
self.feedrate_probe_entry.set_range(0.0, 9999.9999)
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_entry, 14, 1)

View File

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

View File

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

View File

@ -1,6 +1,5 @@
from PyQt5 import QtWidgets
from camlib import Geometry, arc, arc_angle, ApertureMacro
import FlatCAMApp
import numpy as np
import re
@ -9,15 +8,16 @@ import traceback
from copy import deepcopy
import sys
from shapely.ops import cascaded_union, unary_union
from shapely.geometry import Polygon, MultiPolygon, LineString, Point
from shapely.ops import cascaded_union
from shapely.affinity import scale, translate
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 flatcamParsers.ParseSVG import *
from flatcamParsers.ParseSVG import svgparselength, getsvggeo
from FlatCAMCommon import GracefulException as grace
import FlatCAMTranslation as fcTranslate
import gettext
import builtins
@ -255,7 +255,7 @@ class Gerber(Geometry):
"""
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# 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.
@ -403,7 +403,7 @@ class Gerber(Geometry):
# Absolute or Relative/Incremental coordinates
# Not implemented
absolute = True
# absolute = True
# How to interpret circular interpolation: SINGLE or MULTI
quadrant_mode = None
@ -428,7 +428,7 @@ class Gerber(Geometry):
for gline in glines:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
line_num += 1
self.source_file += gline + '\n'
@ -986,7 +986,7 @@ class Gerber(Geometry):
if 'geometry' not in self.apertures[current_aperture]:
self.apertures[current_aperture]['geometry'] = []
self.apertures[current_aperture]['geometry'].append(deepcopy(geo_dict))
except Exception as e:
except Exception:
pass
last_path_aperture = current_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:
circular_x = parse_gerber_number(circular_x,
self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e:
except Exception:
circular_x = current_x
try:
circular_y = parse_gerber_number(circular_y,
self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e:
except Exception:
circular_y = current_y
# 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
try:
i = parse_gerber_number(i, self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e:
except Exception:
i = 0
try:
j = parse_gerber_number(j, self.int_digits, self.frac_digits, self.gerber_zeros)
except Exception as e:
except Exception:
j = 0
if quadrant_mode is None:
@ -1668,13 +1668,14 @@ class Gerber(Geometry):
bbox = bbox.envelope
return bbox
def bounds(self):
def bounds(self, flatten=None):
"""
Returns coordinates of rectangular bounds
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()")
@ -1999,8 +2000,7 @@ class Gerber(Geometry):
# variables to display the percentage of work done
self.geo_len = 0
try:
for __ in self.solid_geometry:
self.geo_len += 1
self.geo_len = len(self.solid_geometry)
except TypeError:
self.geo_len = 1
@ -2078,8 +2078,7 @@ class Gerber(Geometry):
# variables to display the percentage of work done
self.geo_len = 0
try:
for __ in self.solid_geometry:
self.geo_len += 1
self.geo_len = len(self.solid_geometry)
except TypeError:
self.geo_len = 1
@ -2217,8 +2216,7 @@ class Gerber(Geometry):
# variables to display the percentage of work done
self.geo_len = 0
try:
for __ in self.solid_geometry:
self.geo_len += 1
self.geo_len = len(self.solid_geometry)
except TypeError:
self.geo_len = 1
@ -2266,8 +2264,9 @@ class Gerber(Geometry):
def buffer(self, distance, join, factor=None):
"""
:param distance: if 'factor' is True then distance is the factor
:param factor: True or False (None)
:param distance: If 'factor' is True then distance is the factor
: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:
"""
log.debug("parseGerber.Gerber.buffer()")

View File

@ -7,7 +7,6 @@
# ############################################################
from camlib import arc, three_point_circle
import FlatCAMApp
import numpy as np
import re
@ -19,6 +18,7 @@ import sys
from shapely.ops import unary_union
from shapely.geometry import LineString, Point
from FlatCAMCommon import GracefulException as grace
import FlatCAMTranslation as fcTranslate
import gettext
import builtins
@ -180,7 +180,7 @@ class HPGL2:
for gline in glines:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
line_num += 1
self.source_file += gline + '\n'
@ -304,7 +304,7 @@ class HPGL2:
(_("Coordinates missing, line ignored"), str(gline)))
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_line = geo.exterior
self.tools[current_tool]['solid_geometry'].append(geo_line)

View File

@ -382,7 +382,7 @@ class AlignObjects(FlatCAMTool):
def check_points(self):
if len(self.clicked_points) == 1:
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.reset_color()
self.set_color()
@ -397,14 +397,14 @@ class AlignObjects(FlatCAMTool):
return
else:
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.reset_color()
self.set_color()
if len(self.clicked_points) == 3:
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.reset_color()
self.set_color()

View File

@ -7,10 +7,9 @@
from PyQt5 import QtWidgets, QtCore
import FlatCAMApp
from FlatCAMCommon import GracefulException as grace
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCDoubleSpinner, RadioSet, FCEntry, FCComboBox
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon
import shapely.geometry.base as base
from shapely.ops import cascaded_union, unary_union
@ -994,7 +993,7 @@ class ToolCopperThieving(FlatCAMTool):
for pol in app_obj.grb_object.solid_geometry:
if app_obj.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
clearance_geometry.append(
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:
if app_obj.app.abort_flag:
# 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))
except TypeError:
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'
geo_n = working_obj.solid_geometry
if isinstance(working_obj, FlatCAMGeometry):
if working_obj.kind == 'geometry':
try:
__ = iter(geo_n)
except Exception as e:
@ -1093,11 +1092,11 @@ class ToolCopperThieving(FlatCAMTool):
for poly in geo_n:
if app_obj.app.abort_flag:
# 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))
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
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)
@ -1192,7 +1191,7 @@ class ToolCopperThieving(FlatCAMTool):
for pol in app_obj.grb_object.solid_geometry:
if app_obj.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
outline_geometry.append(
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 FlatCAMTool import FlatCAMTool
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.ops import cascaded_union, unary_union
@ -270,7 +269,7 @@ class CutOut(FlatCAMTool):
form_layout_2.addRow(gaps_label, self.gaps)
# 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(
_("Cutout the selected object.\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)
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(
_("Cutout the selected object.\n"
"The resulting cutout shape is\n"
@ -335,7 +334,7 @@ class CutOut(FlatCAMTool):
# 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(
_("If the object to be cutout is a Gerber\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)
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(
_("Use the left mouse button (LMB) click\n"
"to create a bridge gap to separate the PCB from\n"
@ -369,7 +368,7 @@ class CutOut(FlatCAMTool):
self.layout.addStretch()
# ## Reset Tool
self.reset_button = QtWidgets.QPushButton(_("Reset Tool"))
self.reset_button = FCButton(_("Reset Tool"))
self.reset_button.setToolTip(
_("Will reset the tool parameters.")
)
@ -525,7 +524,7 @@ class CutOut(FlatCAMTool):
def geo_init(geo_obj, app_obj):
solid_geo = []
if isinstance(cutout_obj, FlatCAMGerber):
if cutout_obj.kind == 'gerber':
if isinstance(cutout_obj.solid_geometry, list):
cutout_obj.solid_geometry = MultiPolygon(cutout_obj.solid_geometry)
@ -542,12 +541,12 @@ class CutOut(FlatCAMTool):
def cutout_handler(geom):
# 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
py = 0.5 * (ymin + ymax) + margin
lenx = (xmax - xmin) + (margin * 2)
leny = (ymax - ymin) + (margin * 2)
px = 0.5 * (xxmin + xxmax) + margin
py = 0.5 * (yymin + yymax) + margin
lenx = (xxmax - xxmin) + (margin * 2)
leny = (yymax - yymin) + (margin * 2)
proc_geometry = []
if gaps == 'None':
@ -555,41 +554,41 @@ class CutOut(FlatCAMTool):
else:
if gaps == '8' or gaps == '2LR':
geom = self.subtract_poly_from_geo(geom,
xmin - gapsize, # botleft_x
xxmin - gapsize, # botleft_x
py - gapsize + leny / 4, # botleft_y
xmax + gapsize, # topright_x
xxmax + gapsize, # topright_x
py + gapsize + leny / 4) # topright_y
geom = self.subtract_poly_from_geo(geom,
xmin - gapsize,
xxmin - gapsize,
py - gapsize - leny / 4,
xmax + gapsize,
xxmax + gapsize,
py + gapsize - leny / 4)
if gaps == '8' or gaps == '2TB':
geom = self.subtract_poly_from_geo(geom,
px - gapsize + lenx / 4,
ymin - gapsize,
yymin - gapsize,
px + gapsize + lenx / 4,
ymax + gapsize)
yymax + gapsize)
geom = self.subtract_poly_from_geo(geom,
px - gapsize - lenx / 4,
ymin - gapsize,
yymin - gapsize,
px + gapsize - lenx / 4,
ymax + gapsize)
yymax + gapsize)
if gaps == '4' or gaps == 'LR':
geom = self.subtract_poly_from_geo(geom,
xmin - gapsize,
xxmin - gapsize,
py - gapsize,
xmax + gapsize,
xxmax + gapsize,
py + gapsize)
if gaps == '4' or gaps == 'TB':
geom = self.subtract_poly_from_geo(geom,
px - gapsize,
ymin - gapsize,
yymin - gapsize,
px + gapsize,
ymax + gapsize)
yymax + gapsize)
try:
for g in geom:
@ -603,7 +602,7 @@ class CutOut(FlatCAMTool):
object_geo = unary_union(object_geo)
# for geo in object_geo:
if isinstance(cutout_obj, FlatCAMGerber):
if cutout_obj.kind == 'gerber':
if isinstance(object_geo, MultiPolygon):
x0, y0, x1, y1 = object_geo.bounds
object_geo = box(x0, y0, x1, y1)
@ -623,7 +622,7 @@ class CutOut(FlatCAMTool):
object_geo = [object_geo]
for geom_struct in object_geo:
if isinstance(cutout_obj, FlatCAMGerber):
if cutout_obj.kind == 'gerber':
if margin >= 0:
geom_struct = (geom_struct.buffer(margin + abs(dia / 2))).exterior
else:
@ -775,7 +774,7 @@ class CutOut(FlatCAMTool):
# if Gerber create a buffer at a distance
# if Geometry then cut through the geometry
if isinstance(cutout_obj, FlatCAMGerber):
if cutout_obj.kind == 'gerber':
if margin >= 0:
geo = geo.buffer(margin + abs(dia / 2))
else:
@ -909,7 +908,7 @@ class CutOut(FlatCAMTool):
"Select one and try again."))
return
if not isinstance(cutout_obj, FlatCAMGerber):
if cutout_obj.kind != 'gerber':
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("The selected object has to be of Gerber type.\n"
"Select a Gerber file and try again."))
@ -988,11 +987,11 @@ class CutOut(FlatCAMTool):
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
# event_is_dragging = event.is_dragging
right_button = 2
else:
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
try:
@ -1038,11 +1037,11 @@ class CutOut(FlatCAMTool):
if self.app.is_legacy is False:
event_pos = event.pos
event_is_dragging = event.is_dragging
right_button = 2
# right_button = 2
else:
event_pos = (event.xdata, event.ydata)
event_is_dragging = self.app.plotcanvas.is_dragging
right_button = 3
# right_button = 3
try:
x = float(event_pos[0])
@ -1159,13 +1158,17 @@ class CutOut(FlatCAMTool):
if '+' in key_string:
mod, __, key_text = key_string.rpartition('+')
if mod.lower() == 'ctrl':
modifiers = QtCore.Qt.ControlModifier
# modifiers = QtCore.Qt.ControlModifier
pass
elif mod.lower() == 'alt':
modifiers = QtCore.Qt.AltModifier
# modifiers = QtCore.Qt.AltModifier
pass
elif mod.lower() == 'shift':
modifiers = QtCore.Qt.ShiftModifier
# modifiers = QtCore.Qt.ShiftModifier
pass
else:
modifiers = QtCore.Qt.NoModifier
# modifiers = QtCore.Qt.NoModifier
pass
key = QtGui.QKeySequence(key_text)
# events from Vispy are of type KeyEvent
else:
@ -1203,7 +1206,8 @@ class CutOut(FlatCAMTool):
geo = self.cutting_geo(pos=(l_x, l_y))
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.
This only operates on the paths in the original geometry,
@ -1270,8 +1274,9 @@ def flatten(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

View File

@ -3,7 +3,6 @@ from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry, FCEntry, FCButton, FCComboBox
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
from numpy import Inf
@ -192,7 +191,7 @@ class DblSidedTool(FlatCAMTool):
# Add a reference
self.add_point_button = QtWidgets.QPushButton(_("Add"))
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"
"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.")
@ -658,7 +657,7 @@ class DblSidedTool(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Gerber object loaded ..."))
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."))
return
@ -701,7 +700,7 @@ class DblSidedTool(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Excellon object loaded ..."))
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."))
return
@ -745,7 +744,7 @@ class DblSidedTool(FlatCAMTool):
self.app.inform.emit('[WARNING_NOTCL] %s' % _("There is no Geometry object loaded ..."))
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."))
return

View File

@ -8,7 +8,6 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
from flatcamGUI.VisPyVisuals import *
from FlatCAMObj import FlatCAMGerber
from copy import copy
import logging
@ -128,7 +127,7 @@ class ToolMove(FlatCAMTool):
pos_canvas = self.app.plotcanvas.translate_coords(event_pos)
# 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])
else:
pos = pos_canvas
@ -148,7 +147,7 @@ class ToolMove(FlatCAMTool):
self.delete_shape()
# 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])
else:
pos = pos_canvas
@ -171,7 +170,7 @@ class ToolMove(FlatCAMTool):
# remove any mark aperture shape that may be displayed
for sel_obj in obj_list:
# 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)
try:
@ -198,8 +197,8 @@ class ToolMove(FlatCAMTool):
elif sel_obj.kind == 'excellon':
sel_obj.source_file = self.app.export_excellon(
obj_name=out_name, filename=None, local_use=sel_obj, use_thread=False)
except Exception as e:
log.debug('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(e)))
except Exception as err:
log.debug('[ERROR_NOTCL] %s --> %s' % ('ToolMove.on_left_click()', str(err)))
return "fail"
# time to plot the moved objects
@ -249,7 +248,7 @@ class ToolMove(FlatCAMTool):
pos_canvas = self.app.plotcanvas.translate_coords((x, y))
# 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])
else:
pos = pos_canvas

View File

@ -12,7 +12,7 @@ from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTabl
FCComboBox, OptionalInputSection
from flatcamParsers.ParseGerber import Gerber
import FlatCAMApp
from FlatCAMCommon import GracefulException as grace
from copy import deepcopy
@ -1987,7 +1987,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in env_obj:
if self.app.abort_flag:
# 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))
bounding_box = cascaded_union(geo_buff_list)
elif ncc_select == _("Reference Object"):
@ -1996,7 +1996,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in env_obj:
if self.app.abort_flag:
# 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))
bounding_box = cascaded_union(geo_buff_list)
@ -2090,7 +2090,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
if isinstance(geo_elem, Polygon):
for ring in self.poly2rings(geo_elem):
@ -2263,7 +2263,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ##########################################################################################
def gen_clear_area(geo_obj, app_obj):
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
if not run_threaded:
@ -2312,7 +2312,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
log.debug("Starting geometry processing for tool: %s" % str(tool))
if self.app.abort_flag:
# 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
QtWidgets.QApplication.processEvents()
@ -2377,7 +2377,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# clean the polygon
p = p.buffer(0)
@ -2551,7 +2551,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ###########################################################################################
def gen_clear_area_rest(geo_obj, app_obj):
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.")
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))
if self.app.abort_flag:
# 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
QtWidgets.QApplication.processEvents()
@ -2644,7 +2644,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
try:
area = area.difference(poly)
except Exception:
@ -2674,7 +2674,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in area.geoms:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# clean the polygon
p = p.buffer(0)
@ -2753,7 +2753,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# check if there is a geometry at all in the cleared geometry
if cleared_geo:
@ -2771,7 +2771,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in cleared_area:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
poly = p.buffer(buffer_value)
cleared_by_last_tool.append(poly)
@ -2836,7 +2836,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
app_obj.new_object("geometry", name, gen_clear_area_rest)
else:
app_obj.new_object("geometry", name, gen_clear_area)
except FlatCAMApp.GracefulException:
except grace:
if run_threaded:
proc.done()
return
@ -2999,7 +2999,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in geo_n:
if self.app.abort_flag:
# 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))
bounding_box = cascaded_union(geo_buff_list)
@ -3017,7 +3017,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for poly in geo_n:
if self.app.abort_flag:
# 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))
bounding_box = cascaded_union(geo_buff_list)
@ -3045,7 +3045,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ##########################################################################################
def gen_clear_area(geo_obj, app_obj):
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
if not run_threaded:
@ -3141,7 +3141,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
if isinstance(geo_elem, Polygon):
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))
if self.app.abort_flag:
# 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
QtWidgets.QApplication.processEvents()
@ -3283,7 +3283,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# clean the polygon
p = p.buffer(0)
@ -3446,7 +3446,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
# ###########################################################################################
def gen_clear_area_rest(geo_obj, app_obj):
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.")
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:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
if isinstance(geo_elem, Polygon):
for ring in self.poly2rings(geo_elem):
@ -3614,7 +3614,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
if type(empty) is Polygon:
empty = MultiPolygon([empty])
@ -3628,7 +3628,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
while sorted_tools:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
tool = sorted_tools.pop(0)
log.debug("Starting geometry processing for tool: %s" % str(tool))
@ -3648,7 +3648,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
try:
area = area.difference(poly_r)
except Exception:
@ -3678,7 +3678,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in area.geoms:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# clean the polygon
p = p.buffer(0)
@ -3754,7 +3754,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# check if there is a geometry at all in the cleared geometry
if cleared_geo:
@ -3772,7 +3772,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
for p in cleared_area:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
r_poly = p.buffer(buffer_value)
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)
else:
app_obj.new_object("geometry", name, gen_clear_area, plot=plot)
except FlatCAMApp.GracefulException:
except grace:
if run_threaded:
proc.done()
return
@ -3887,7 +3887,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
boundary = boundary.difference(el)
pol_nr += 1
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 flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox, FCComboBox
from FlatCAMObj import FlatCAMGerber
import FlatCAMApp
from FlatCAMCommon import GracefulException as grace
from shapely.geometry import MultiPolygon
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 ..."))
return
if not isinstance(fcobj, FlatCAMGerber):
if fcobj.kind != 'gerber':
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Only Gerber objects can be evaluated."))
return
@ -365,7 +364,7 @@ class ToolOptimal(FlatCAMTool):
for geo_el in fcobj.apertures[ap]['geometry']:
if self.app.abort_flag:
# 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:
total_geo.append(geo_el['solid'])
@ -395,7 +394,7 @@ class ToolOptimal(FlatCAMTool):
for s_geo in total_geo[idx:]:
if self.app.abort_flag:
# 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
dist = geo.distance(s_geo)
@ -459,7 +458,7 @@ class ToolOptimal(FlatCAMTool):
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 "
"((x0, y0), (x1, y1)).")
return 'fail'
return
try:
loc_1 = loc[0]
@ -471,7 +470,7 @@ class ToolOptimal(FlatCAMTool):
self.app.on_jump_to(custom_location=loc)
except Exception as e:
log.debug("ToolOptimal.on_locate_position() --> sec try %s" % str(e))
return 'fail'
return
def on_update_text(self, data):
txt = ''
@ -567,12 +566,12 @@ class ToolOptimal(FlatCAMTool):
if self.selected_locations_text != '':
loc = eval(self.selected_locations_text)
else:
return 'fail'
return
except Exception as 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 "
"((x0, y0), (x1, y1)).")
return 'fail'
return
try:
loc_1 = loc[0]
@ -584,7 +583,7 @@ class ToolOptimal(FlatCAMTool):
self.app.on_jump_to(custom_location=loc)
except Exception as e:
log.debug("ToolOptimal.on_locate_sec_position() --> sec try %s" % str(e))
return 'fail'
return
def reset_fields(self):
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 FlatCAMTool import FlatCAMTool
import FlatCAMApp
from FlatCAMCommon import GracefulException as grace
from shapely.geometry import Point, Polygon, LineString, MultiPolygon
from shapely.ops import unary_union
@ -190,7 +190,7 @@ class ToolPDF(FlatCAMTool):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
with self.app.proc_container.new(_("Parsing PDF file ...")):
with open(filename, "rb") as f:
@ -200,7 +200,7 @@ class ToolPDF(FlatCAMTool):
for s in re.findall(self.stream_re, pdf):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
stream_nr += 1
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):
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
@ -404,7 +404,7 @@ class ToolPDF(FlatCAMTool):
for object_name in self.pdf_parsed:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
filename = deepcopy(self.pdf_parsed[object_name]['filename'])
pdf_content = deepcopy(self.pdf_parsed[object_name]['pdf'])
@ -412,7 +412,7 @@ class ToolPDF(FlatCAMTool):
for k in pdf_content:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
ap_dict = pdf_content[k]
if ap_dict:
@ -493,7 +493,7 @@ class ToolPDF(FlatCAMTool):
for pline in lines:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
line_nr += 1
log.debug("line %d: %s" % (line_nr, pline))
@ -868,7 +868,6 @@ class ToolPDF(FlatCAMTool):
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
found_aperture = None
else:
if str(aperture) in apertures_dict.keys():
aperture += 1
@ -1231,7 +1230,6 @@ class ToolPDF(FlatCAMTool):
new_el['solid'] = pdf_geo
new_el['follow'] = pdf_geo.exterior
apertures_dict[copy(found_aperture)]['geometry'].append(deepcopy(new_el))
found_aperture = None
else:
if str(aperture) in apertures_dict.keys():
aperture += 1
@ -1355,7 +1353,7 @@ class ToolPDF(FlatCAMTool):
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
return object_dict

View File

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

View File

@ -9,10 +9,8 @@ from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection, FCComboBox
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber, FlatCAMExcellon
import FlatCAMApp
from FlatCAMCommon import GracefulException as grace
from copy import deepcopy
# from ObjectCollection import *
import numpy as np
import shapely.affinity as affinity
@ -480,13 +478,13 @@ class Panelize(FlatCAMTool):
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
copied_tools = {}
for tt, tt_val in list(panel_obj.tools.items()):
copied_tools[tt] = deepcopy(tt_val)
if isinstance(panel_obj, FlatCAMGerber):
if panel_obj.kind == 'gerber':
# make a copy of the panelized Gerber apertures
copied_apertures = {}
for tt, tt_val in list(panel_obj.apertures.items()):
@ -525,7 +523,7 @@ class Panelize(FlatCAMTool):
for tool_dict in panel_obj.drills:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
point_offseted = affinity.translate(tool_dict['point'], currentx, currenty)
obj_fin.drills.append(
@ -550,7 +548,7 @@ class Panelize(FlatCAMTool):
for tool_dict in panel_obj.slots:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
start_offseted = affinity.translate(tool_dict['start'], currentx, currenty)
stop_offseted = affinity.translate(tool_dict['stop'], currentx, currenty)
@ -600,20 +598,20 @@ class Panelize(FlatCAMTool):
obj_fin.solid_geometry = []
# 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.tools = copied_tools
if panel_obj.multigeo is True:
for tool in panel_obj.tools:
obj_fin.tools[tool]['solid_geometry'][:] = []
elif isinstance(panel_obj, FlatCAMGerber):
elif panel_obj.kind == 'gerber':
obj_fin.apertures = copied_apertures
for ap in obj_fin.apertures:
obj_fin.apertures[ap]['geometry'] = []
# find the number of polygons in the source solid_geometry
geo_len = 0
if isinstance(panel_obj, FlatCAMGeometry):
if panel_obj.kind == 'geometry':
if panel_obj.multigeo is True:
for tool in panel_obj.tools:
try:
@ -625,7 +623,7 @@ class Panelize(FlatCAMTool):
geo_len = len(panel_obj.solid_geometry)
except TypeError:
geo_len = 1
elif isinstance(panel_obj, FlatCAMGerber):
elif panel_obj.kind == 'gerber':
for ap in panel_obj.apertures:
if 'geometry' in panel_obj.apertures[ap]:
try:
@ -641,12 +639,12 @@ class Panelize(FlatCAMTool):
element += 1
old_disp_number = 0
if isinstance(panel_obj, FlatCAMGeometry):
if panel_obj.kind == 'geometry':
if panel_obj.multigeo is True:
for tool in panel_obj.tools:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
# geo = translate_recursion(panel_obj.tools[tool]['solid_geometry'])
# if isinstance(geo, list):
@ -678,7 +676,7 @@ class Panelize(FlatCAMTool):
# obj_fin.solid_geometry.append(geo)
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
try:
# calculate the number of polygons
@ -690,7 +688,7 @@ class Panelize(FlatCAMTool):
for geo_el in panel_obj.solid_geometry:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
trans_geo = translate_recursion(geo_el)
obj_fin.solid_geometry.append(trans_geo)
@ -715,13 +713,13 @@ class Panelize(FlatCAMTool):
# obj_fin.solid_geometry.append(geo)
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
try:
for geo_el in panel_obj.solid_geometry:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
trans_geo = translate_recursion(geo_el)
obj_fin.solid_geometry.append(trans_geo)
@ -732,7 +730,7 @@ class Panelize(FlatCAMTool):
for apid in panel_obj.apertures:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
if 'geometry' in panel_obj.apertures[apid]:
try:
# calculate the number of polygons
@ -743,7 +741,7 @@ class Panelize(FlatCAMTool):
for el in panel_obj.apertures[apid]['geometry']:
if self.app.abort_flag:
# graceful abort requested by the user
raise FlatCAMApp.GracefulException
raise grace
new_el = {}
if 'solid' in el:
@ -786,7 +784,7 @@ class Panelize(FlatCAMTool):
self.app.proc_container.update_view_text('')
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)
else:
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"
"- 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"
"- 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(
[
@ -604,8 +604,8 @@ class ToolPunchGerber(FlatCAMTool):
if grb_obj.apertures[apid]['type'] == 'C' and self.circular_cb.get_value():
if punch_size >= float(grb_obj.apertures[apid]['size']):
self.app.inform.emit('[ERROR_NOTCL] %s' %
_(" Could not generate punched hole Gerber because the punch hole size"
"is bigger than some of the apertures in the Gerber object."))
_("Could not generate punched hole Gerber because the punch hole size"
" is bigger than some of the apertures in the Gerber object."))
return 'fail'
else:
for elem in grb_obj.apertures[apid]['geometry']:
@ -617,7 +617,7 @@ class ToolPunchGerber(FlatCAMTool):
punch_size >= float(grb_obj.apertures[apid]['height']):
self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Could not generate punched hole Gerber because the punch hole size"
"is bigger than some of the apertures in the Gerber object."))
" is bigger than some of the apertures in the Gerber object."))
return 'fail'
elif round(float(grb_obj.apertures[apid]['width']), self.decimals) == \
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
import html
import sys
import traceback
import tkinter as tk
import tclCommands
import gettext
import FlatCAMTranslation as fcTranslate
@ -110,7 +112,7 @@ class TermWidget(QWidget):
elif style == 'err':
text = '<span style="font-weight: bold; color: red;">%s</span>'\
'<span style="font-weight: bold;">%s</span>'\
%(mtype, body)
% (mtype, body)
elif style == 'warning':
# text = '<span style="font-weight: bold; color: #f4b642;">%s</span>' % text
text = '<span style="font-weight: bold; color: #f4b642;">%s</span>' \
@ -253,15 +255,90 @@ class TermWidget(QWidget):
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 args: Parameters passed to the TermWidget parent class
"""
TermWidget.__init__(self, version, *args, app=sysShell)
self._sysShell = sysShell
TermWidget.__init__(self, version, *args, app=app)
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 skipQuotes(txt):
@ -293,7 +370,7 @@ class FCShell(TermWidget):
: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)
@ -315,15 +392,15 @@ class FCShell(TermWidget):
if no_echo is False:
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:
self.append_output(result + '\n')
except tk.TclError as e:
# This will display more precise answer if something in TCL shell fails
result = self._sysShell.tcl.eval("set errorInfo")
self._sysShell.log.error("Exec command Exception: %s" % (result + '\n'))
result = self.tcl.eval("set errorInfo")
self.app.log.error("Exec command Exception: %s" % (result + '\n'))
if no_echo is False:
self.append_error('ERROR: ' + result + '\n')
# Show error in console and just return or in test raise exception
@ -335,39 +412,101 @@ class FCShell(TermWidget):
pass
return result
# """
# Code below is unsused. Saved for later.
# """
def raise_tcl_unknown_error(self, unknownException):
"""
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)
# 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")
:param unknownException:
:return:
"""
if not isinstance(unknownException, self.TclErrorException):
self.raise_tcl_error("Unknown error: %s" % str(unknownException))
else:
raise unknownException
def display_tcl_error(self, error, error_info=None):
"""
Escape bracket [ with '\' otherwise there is error
"ERROR: missing close-bracket" instead of real error
:param error: it may be text or exception
:param error_info: Some informations about the error
:return: None
"""
if isinstance(error, Exception):
exc_type, exc_value, exc_traceback = error_info
if not isinstance(error, self.TclErrorException):
show_trace = 1
else:
show_trace = int(self.app.defaults['global_verbose_error_level'])
if show_trace > 0:
trc = traceback.format_list(traceback.extract_tb(exc_traceback))
trc_formated = []
for a in reversed(trc):
trc_formated.append(a.replace(" ", " > ").replace("\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
from FlatCAMApp import log
from camlib import distance
from FlatCAMObj import FlatCAMCNCjob
from flatcamEditors.FlatCAMTextEditor import TextEditor
from PyQt5 import QtGui, QtCore, QtWidgets
@ -506,7 +505,8 @@ class SolderPaste(FlatCAMTool):
self.flat_geometry = []
# 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
self.combo_context_del_action.triggered.connect(self.on_delete_object)
@ -966,6 +966,7 @@ class SolderPaste(FlatCAMTool):
self.build_ui()
return
else:
old_tool_dia = ''
# identify the old tool_dia and restore the text in tool table
for k, v in self.tooltable_tools.items():
if k == tooluid:
@ -1332,9 +1333,9 @@ class SolderPaste(FlatCAMTool):
# Object initialization function for app.new_object()
# RUNNING ON SEPARATE THREAD!
def job_init(job_obj, app_obj):
assert isinstance(job_obj, FlatCAMCNCjob), \
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
def job_init(job_obj):
assert job_obj.kind == 'cncjob', \
"Initializer expected a CNCJobObject, got %s" % type(job_obj)
# this turn on the FlatCAMCNCJob plot for multiple tools
job_obj.multitool = True
@ -1364,7 +1365,7 @@ class SolderPaste(FlatCAMTool):
res = job_obj.generate_gcode_from_solderpaste_geo(**tooluid_value)
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'
else:
tool_cnc_dict['gcode'] = res

View File

@ -8,7 +8,6 @@
from PyQt5 import QtWidgets
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, EvalEntry2
from FlatCAMObj import FlatCAMCNCjob
import gettext
import FlatCAMTranslation as fcTranslate
@ -681,7 +680,7 @@ class ToolTransform(FlatCAMTool):
try:
# first get a bounding box to fit all
for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob):
if obj.kind == 'cncjob':
pass
else:
xmin, ymin, xmax, ymax = obj.bounds()
@ -699,7 +698,7 @@ class ToolTransform(FlatCAMTool):
px = 0.5 * (xminimal + xmaximal)
py = 0.5 * (yminimal + ymaximal)
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."))
else:
sel_obj.rotate(-num, point=(px, py))
@ -735,7 +734,7 @@ class ToolTransform(FlatCAMTool):
else:
# first get a bounding box to fit all
for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob):
if obj.kind == 'cncjob':
pass
else:
xmin, ymin, xmax, ymax = obj.bounds()
@ -755,7 +754,7 @@ class ToolTransform(FlatCAMTool):
# execute mirroring
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."))
else:
if axis == 'X':
@ -803,7 +802,7 @@ class ToolTransform(FlatCAMTool):
try:
# first get a bounding box to fit all
for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob):
if obj.kind == 'cncjob':
pass
else:
xmin, ymin, xmax, ymax = obj.bounds()
@ -815,7 +814,7 @@ class ToolTransform(FlatCAMTool):
yminimal = min(yminlist)
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."))
else:
if axis == 'X':
@ -842,15 +841,14 @@ class ToolTransform(FlatCAMTool):
ymaxlist = []
if not obj_list:
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("No object selected. Please Select an object to scale!"))
self.app.inform.emit('[WARNING_NOTCL] %s' % _("No object selected. Please Select an object to scale!"))
return
else:
with self.app.proc_container.new(_("Applying Scale")):
try:
# first get a bounding box to fit all
for obj in obj_list:
if isinstance(obj, FlatCAMCNCjob):
if obj.kind == 'cncjob':
pass
else:
xmin, ymin, xmax, ymax = obj.bounds()
@ -873,7 +871,7 @@ class ToolTransform(FlatCAMTool):
py = 0
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."))
else:
sel_obj.scale(xfactor, yfactor, point=(px, py))
@ -883,8 +881,7 @@ class ToolTransform(FlatCAMTool):
self.app.object_changed.emit(sel_obj)
sel_obj.plot()
self.app.inform.emit('[success] %s %s %s...' %
(_('Scale on the'), str(axis), _('axis done')))
self.app.inform.emit('[success] %s %s %s...' % (_('Scale on the'), str(axis), _('axis done')))
except Exception as e:
self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
(_("Due of"), str(e), _("action was not executed.")))
@ -894,14 +891,13 @@ class ToolTransform(FlatCAMTool):
obj_list = self.app.collection.get_selected()
if not obj_list:
self.app.inform.emit('[WARNING_NOTCL] %s' %
_("No object selected. Please Select an object to offset!"))
self.app.inform.emit('[WARNING_NOTCL] %s' % _("No object selected. Please Select an object to offset!"))
return
else:
with self.app.proc_container.new(_("Applying Offset")):
try:
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."))
else:
if axis == 'X':
@ -915,8 +911,7 @@ class ToolTransform(FlatCAMTool):
self.app.object_changed.emit(sel_obj)
sel_obj.plot()
self.app.inform.emit('[success] %s %s %s...' %
(_('Offset on the'), str(axis), _('axis done')))
self.app.inform.emit('[success] %s %s %s...' % (_('Offset on the'), str(axis), _('axis done')))
except Exception as e:
self.app.inform.emit('[ERROR_NOTCL] %s %s, %s.' %
(_("Due of"), str(e), _("action was not executed.")))
@ -932,7 +927,7 @@ class ToolTransform(FlatCAMTool):
with self.app.proc_container.new(_("Applying Buffer")):
try:
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."))
elif sel_obj.kind.lower() == 'gerber':
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 ""
#: FlatCAMApp.py:5652 FlatCAMApp.py:5688
msgid "Expected a FlatCAMGeometry, got"
msgid "Expected a GeometryObject, got"
msgstr ""
#: FlatCAMApp.py:5665
@ -1125,7 +1125,7 @@ msgid "Open TCL script cancelled."
msgstr ""
#: FlatCAMApp.py:9993
msgid "Executing FlatCAMScript file."
msgid "Executing ScriptObject file."
msgstr ""
#: FlatCAMApp.py:10000 FlatCAMApp.py:10003
@ -14705,7 +14705,7 @@ msgid "Buffer done"
msgstr ""
#: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73
msgid "Expected FlatCAMGerber or FlatCAMGeometry, got"
msgid "Expected GerberObject or GeometryObject, got"
msgstr ""
#: 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."
#: FlatCAMApp.py:5652 FlatCAMApp.py:5688
msgid "Expected a FlatCAMGeometry, got"
msgid "Expected a GeometryObject, got"
msgstr "Geometria FlatCAM esperada, recebido"
#: FlatCAMApp.py:5665
@ -1211,7 +1211,7 @@ msgid "Open TCL script cancelled."
msgstr "Abrir script TCL cancelado."
#: FlatCAMApp.py:9993
msgid "Executing FlatCAMScript file."
msgid "Executing ScriptObject file."
msgstr "Executando arquivo de Script FlatCAM."
#: FlatCAMApp.py:10000 FlatCAMApp.py:10003
@ -16677,8 +16677,8 @@ msgid "Buffer done"
msgstr "Buffer concluído"
#: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73
msgid "Expected FlatCAMGerber or FlatCAMGeometry, got"
msgstr "Esperando FlatCAMGerber ou FlatCAMGeometry, recebido"
msgid "Expected GerberObject or GeometryObject, got"
msgstr "Esperando GerberObject ou GeometryObject, recebido"
#: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68
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>"
#~ msgstr "<span style=\"color:red;\"><b>%s</b></span>"
#~ msgid "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->"
#~ msgstr "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->"
#~ msgid "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgstr "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgid "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 = "
#~ "\"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"
#~ 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 и попробуйте снова."
#: FlatCAMApp.py:5652 FlatCAMApp.py:5688
msgid "Expected a FlatCAMGeometry, got"
msgstr "Ожидается FlatCAMGeometry, получено"
msgid "Expected a GeometryObject, got"
msgstr "Ожидается GeometryObject, получено"
#: FlatCAMApp.py:5665
msgid "A Geometry object was converted to MultiGeo type."
@ -1189,8 +1189,8 @@ msgid "Open TCL script cancelled."
msgstr "Открытие сценария отменено."
#: FlatCAMApp.py:9993
msgid "Executing FlatCAMScript file."
msgstr "Выполнение файла FlatCAMScript."
msgid "Executing ScriptObject file."
msgstr "Выполнение файла ScriptObject."
#: FlatCAMApp.py:10000 FlatCAMApp.py:10003
msgid "Run TCL script"
@ -16746,8 +16746,8 @@ msgid "Buffer done"
msgstr "Буфер готов"
#: tclCommands/TclCommandBbox.py:74 tclCommands/TclCommandNregions.py:73
msgid "Expected FlatCAMGerber or FlatCAMGeometry, got"
msgstr "Ожидался FlatCAMGerber или FlatCAMGeometry, получено"
msgid "Expected GerberObject or GeometryObject, got"
msgstr "Ожидался GerberObject или GeometryObject, получено"
#: tclCommands/TclCommandBounds.py:64 tclCommands/TclCommandBounds.py:68
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>"
#~ msgstr "<span style=\"color:red;\"><b>%s</b></span>"
#~ msgid "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->"
#~ msgstr "FlatCAMObj.FlatCAMGeometry.mtool_gen_cncjob() -->"
#~ msgid "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgstr "FlatCAMObj.GeometryObject.mtool_gen_cncjob() -->"
#~ msgid "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/"
#~ "flatcam/downloads/\">отсюда.</a><BR>"
#~ msgid "Expected a FlatCAMGeometry, got %s"
#~ msgstr "Ожидается FlatCAMGeometry, получено %s"
#~ msgid "Expected a GeometryObject, got %s"
#~ msgstr "Ожидается GeometryObject, получено %s"
#~ msgid "Saved to: %s"
#~ msgstr "Сохранёно в: %s"

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,5 @@
import collections
from tclCommands.TclCommand import TclCommand
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
from shapely.ops import cascaded_union
@ -73,7 +72,7 @@ class TclCommandBbox(TclCommand):
if not isinstance(obj, FlatCAMGerber) and not isinstance(obj, FlatCAMGeometry):
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:
args['margin'] = float(self.app.defaults["gerber_bboxmargin"])
@ -92,7 +91,7 @@ class TclCommandBbox(TclCommand):
try:
def geo_init(geo_obj, app_obj):
assert isinstance(geo_obj, FlatCAMGeometry)
# assert geo_obj.kind == 'geometry'
# Bounding box with rounded corners
geo = cascaded_union(obj.solid_geometry)

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMGeometry
import collections
from copy import deepcopy
@ -119,9 +118,9 @@ class TclCommandCncjob(TclCommandSignaled):
else:
return "fail"
if not isinstance(obj, FlatCAMGeometry):
if obj.kind != 'geometry':
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:
return

View File

@ -1,5 +1,4 @@
from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMExcellon
import collections
import math
@ -125,9 +124,9 @@ class TclCommandDrillcncjob(TclCommandSignaled):
else:
return "fail"
if not isinstance(obj, FlatCAMExcellon):
if obj.kind != 'excellon':
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:
return "fail"

View File

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

View File

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

View File

@ -65,10 +65,11 @@ class TclCommandHelp(TclCommand):
if 'name' in args:
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
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:
if not args:
cmd_enum = '%s\n' % _("Available commands:")
@ -77,19 +78,21 @@ class TclCommandHelp(TclCommand):
try:
# find the maximum length of a command name
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)
if curr_len > max_len:
max_len = curr_len
h_space = "&nbsp;"
cnt = 0
for cmd_name in sorted(self.app.tcl_commands_storage):
cmd_description = "<span>%s</span>" % self.app.tcl_commands_storage[cmd_name]['description']
for cmd_name in sorted(self.app.shell.tcl_commands_storage):
cmd_description = "<span>%s</span>" % \
self.app.shell.tcl_commands_storage[cmd_name]['description']
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
@ -104,11 +107,11 @@ class TclCommandHelp(TclCommand):
else:
cnt += 1
except Exception as err:
self.app.log.debug("App.setup_shell.shelp() when run as 'help' --> %s" % str(err))
displayed_text = ['> %s\n' % cmd for cmd in sorted(self.app.tcl_commands_storage)]
self.app.log.debug("tclCommands.TclCommandHelp() when run as 'help' --> %s" % str(err))
displayed_text = ['> %s' % cmd for cmd in sorted(self.app.shell.tcl_commands_storage)]
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"))
self.app.shell.append_raw(cmd_enum)

View File

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

View File

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

View File

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

View File

@ -6,7 +6,6 @@
# ##########################################################
from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMExcellon
import math
import collections
@ -138,7 +137,7 @@ class TclCommandMillDrills(TclCommandSignaled):
except Exception as 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)))
if self.app.collection.has_promises():

View File

@ -6,7 +6,6 @@
# ##########################################################
from tclCommands.TclCommand import TclCommandSignaled
from FlatCAMObj import FlatCAMExcellon
import collections
import math
@ -139,7 +138,7 @@ class TclCommandMillSlots(TclCommandSignaled):
except Exception as 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)))
if self.app.collection.has_promises():

View File

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

View File

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

View File

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

View File

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