Merge remote-tracking branch 'remotes/jpcgt/flatcam/Beta' into Beta

This commit is contained in:
camellan 2019-06-08 23:16:41 +04:00
commit 70e939ca36
68 changed files with 8057 additions and 7048 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,11 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
class LoudDict(dict):
"""

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
import copy
import inspect # TODO: For debugging only.
@ -36,7 +36,7 @@ class ValidationError(Exception):
self.errors = errors
# ##################################### ##
# # FlatCAMObj ##
# # FlatCAMObj # ##
# ##################################### ##
@ -90,6 +90,8 @@ class FlatCAMObj(QtCore.QObject):
self.isHovering = False
self.notHovering = True
self.units = 'IN'
# assert isinstance(self.ui, ObjectUI)
# self.ui.name_entry.returnPressed.connect(self.on_name_activate)
# self.ui.offset_button.clicked.connect(self.on_offset_button_click)
@ -135,8 +137,7 @@ class FlatCAMObj(QtCore.QObject):
if key == 'plot':
self.visible = self.options['plot']
# self.emit(QtCore.SIGNAL("optionChanged"), key)
self.optionChanged.emit(key)
# self.optionChanged.emit(key)
def set_ui(self, ui):
self.ui = ui
@ -296,8 +297,6 @@ class FlatCAMObj(QtCore.QObject):
return False
self.clear()
return True
def serialize(self):
@ -340,14 +339,19 @@ class FlatCAMObj(QtCore.QObject):
@visible.setter
def visible(self, value):
self.shapes.visible = value
log.debug("FlatCAMObj.visible()")
def worker_task(app_obj):
app_obj.shapes.visible = value
# Not all object types has annotations
try:
self.annotation.visible = value
except AttributeError:
app_obj.annotation.visible = value
except Exception as e:
pass
self.app.worker_task.emit({'fcn': worker_task, 'params': [self]})
@property
def drawing_tolerance(self):
return self._drawing_tolerance if self.units == 'MM' or not self.units else self._drawing_tolerance / 25.4
@ -365,12 +369,6 @@ class FlatCAMObj(QtCore.QObject):
except AttributeError:
pass
# Not all object types have mark_shapes
# try:
# self.mark_shapes.clear(update)
# except AttributeError:
# pass
def delete(self):
# Free resources
del self.ui
@ -1053,7 +1051,6 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
:param kwargs: color and face_color
:return:
"""
FlatCAMApp.App.log.debug(str(inspect.stack()[1][3]) + " --> FlatCAMGerber.plot()")
# Does all the required setup and returns False
@ -1065,6 +1062,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
color = kwargs['color']
else:
color = self.app.defaults['global_plot_line']
if 'face_color' in kwargs:
face_color = kwargs['face_color']
else:
@ -1078,7 +1076,7 @@ class FlatCAMGerber(FlatCAMObj, Gerber):
# Make sure geometry is iterable.
try:
_ = iter(geometry)
__ = iter(geometry)
except TypeError:
geometry = [geometry]
@ -2795,7 +2793,7 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
# this stays for compatibility reasons, in case we try to open old projects
try:
_ = iter(self.solid_geometry)
__ = iter(self.solid_geometry)
except TypeError:
self.solid_geometry = [self.solid_geometry]
@ -2932,18 +2930,18 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
"""
pts = []
## Iterable: descend into each item.
# Iterable: descend into each item.
try:
for subo in o:
pts += FlatCAMGeometry.get_pts(subo)
## Non-iterable
# Non-iterable
except TypeError:
if o is not None:
if type(o) == MultiPolygon:
for poly in o:
pts += FlatCAMGeometry.get_pts(poly)
## Descend into .exerior and .interiors
# ## Descend into .exerior and .interiors
elif type(o) == Polygon:
pts += FlatCAMGeometry.get_pts(o.exterior)
for i in o.interiors:
@ -2951,7 +2949,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
elif type(o) == MultiLineString:
for line in o:
pts += FlatCAMGeometry.get_pts(line)
## Has .coords: list them.
# ## Has .coords: list them.
else:
pts += list(o.coords)
else:
@ -3033,6 +3031,12 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# engine of FlatCAM. Most likely are generated by some of tools and are special cases of geometries.
self. special_group = None
self.old_pp_state = ''
self.old_toolchangeg_state = ''
# store here the default data for Geometry Data
self.default_data = {}
# Attributes to be included in serialization
# Always append to it because it carries contents
# from predecessors.
@ -3391,11 +3395,11 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
try:
# works for CheckBoxes
self.ui.grid3.itemAt(i).widget().stateChanged.connect(self.gui_form_to_storage)
except:
except Exception as e:
# works for ComboBoxes
try:
self.ui.grid3.itemAt(i).widget().currentIndexChanged.connect(self.gui_form_to_storage)
except:
except Exception as e2:
# works for Entry
try:
self.ui.grid3.itemAt(i).widget().editingFinished.connect(self.gui_form_to_storage)
@ -3492,13 +3496,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
def on_tool_add(self, dia=None):
self.ui_disconnect()
last_offset = None
last_offset_value = None
last_type = None
last_tool_type = None
last_data = None
last_solid_geometry = []
# if a Tool diameter entered is a char instead a number the final message of Tool adding is changed
# because the Default value for Tool is used.
change_message = False
@ -3547,7 +3544,7 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
self.tools.update({
self.tooluid: {
'tooldia': tooldia,
'offset': ('Path'),
'offset': 'Path',
'offset_value': 0.0,
'type': _('Rough'),
'tool_type': 'C1',
@ -3556,7 +3553,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
}
})
else:
# print("LAST", self.tools[maxuid])
last_data = self.tools[max_uid]['data']
last_offset = self.tools[max_uid]['offset']
last_offset_value = self.tools[max_uid]['offset_value']
@ -3580,7 +3576,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
'solid_geometry': deepcopy(last_solid_geometry)
}
})
# print("CURRENT", self.tools[-1])
self.ui.tool_offset_entry.hide()
self.ui.tool_offset_lbl.hide()
@ -4277,6 +4272,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# Object initialization function for app.new_object()
# RUNNING ON SEPARATE THREAD!
def job_init_single_geometry(job_obj, app_obj):
log.debug("Creating a CNCJob out of a single-geometry")
assert isinstance(job_obj, FlatCAMCNCjob), \
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
@ -4451,8 +4448,9 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
app_obj.progress.emit(40)
tol = float(self.app.defaults['global_tolerance'])
res = job_obj.generate_from_geometry_2(
self, tooldia=tooldia_val, offset=tool_offset, tolerance=0.0005,
self, tooldia=tooldia_val, offset=tool_offset, tolerance=tol,
z_cut=z_cut, z_move=z_move,
feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid,
spindlespeed=spindlespeed, spindledir=spindledir, dwell=dwell, dwelltime=dwelltime,
@ -4488,6 +4486,8 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
# Object initialization function for app.new_object()
# RUNNING ON SEPARATE THREAD!
def job_init_multi_geometry(job_obj, app_obj):
log.debug("Creating a CNCJob out of a multi-geometry")
assert isinstance(job_obj, FlatCAMCNCjob), \
"Initializer expected a FlatCAMCNCjob, got %s" % type(job_obj)
@ -4682,9 +4682,10 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
spindledir = self.app.defaults['geometry_spindledir']
tool_solid_geometry = self.tools[current_uid]['solid_geometry']
tol = float(self.app.defaults['global_tolerance'])
res = job_obj.generate_from_multitool_geometry(
tool_solid_geometry, tooldia=tooldia_val, offset=tool_offset,
tolerance=0.0005, z_cut=z_cut, z_move=z_move,
tolerance=tol, z_cut=z_cut, z_move=z_move,
feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid,
spindlespeed=spindlespeed, spindledir=spindledir, dwell=dwell, dwelltime=dwelltime,
multidepth=multidepth, depthpercut=depthpercut,
@ -4741,7 +4742,6 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
else:
self.app.new_object("cncjob", outname, job_init_multi_geometry)
def generatecncjob(self, outname=None,
tooldia=None, offset=None,
z_cut=None, z_move=None,
@ -4850,8 +4850,13 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
'or self.options["feedrate_probe"]'
))
# TODO: The tolerance should not be hard coded. Just for testing.
job_obj.generate_from_geometry_2(self, tooldia=tooldia, offset=offset, tolerance=0.0005,
job_obj.options['xmin'] = self.options['xmin']
job_obj.options['ymin'] = self.options['ymin']
job_obj.options['xmax'] = self.options['xmax']
job_obj.options['ymax'] = self.options['ymax']
tol = float(self.app.defaults['global_tolerance'])
job_obj.generate_from_geometry_2(self, tooldia=tooldia, offset=offset, tolerance=tol,
z_cut=z_cut, z_move=z_move,
feedrate=feedrate, feedrate_z=feedrate_z, feedrate_rapid=feedrate_rapid,
spindlespeed=spindlespeed, dwell=dwell, dwelltime=dwelltime,
@ -5464,6 +5469,15 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
# set the kind of geometries are plotted by default with plot2() from camlib.CNCJob
self.ui.cncplot_method_combo.set_value(self.app.defaults["cncjob_plot_kind"])
try:
self.ui.annotation_cb.stateChanged.disconnect(self.on_annotation_change)
except:
pass
self.ui.annotation_cb.stateChanged.connect(self.on_annotation_change)
# set if to display text annotations
self.ui.annotation_cb.set_value(self.app.defaults["cncjob_annotation"])
# Show/Hide Advanced Options
if self.app.defaults["global_app_level"] == 'b':
self.ui.level.setText(_(
@ -5913,6 +5927,14 @@ class FlatCAMCNCjob(FlatCAMObj, CNCjob):
self.shapes.clear(update=True)
self.annotation.clear(update=True)
def on_annotation_change(self):
if self.ui.annotation_cb.get_value():
self.app.plotcanvas.text_collection.enabled = True
else:
self.app.plotcanvas.text_collection.enabled = False
kind = self.ui.cncplot_method_combo.get_value()
self.plot(kind=kind)
def convert_units(self, units):
factor = CNCjob.convert_units(self, units)
FlatCAMApp.App.log.debug("FlatCAMCNCjob.convert_units()")

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
############################################################
# ########################################################## ##
from importlib.machinery import SourceFileLoader
import os

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
from flatcamGUI.FlatCAMGUI import FlatCAMActivityView
from PyQt5 import QtCore

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
from PyQt5 import QtGui, QtCore, QtWidgets, QtWidgets
from PyQt5.QtCore import Qt

View File

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

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
from PyQt5 import QtCore

View File

@ -1,14 +1,14 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
############################################################
# ########################################################## ##
# File modified by: Dennis Hayrullin #
############################################################
# ########################################################## ##
# from PyQt5.QtCore import QModelIndex
from FlatCAMObj import *
@ -20,9 +20,9 @@ from PyQt5.QtCore import Qt
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
import builtins
if '_' not in builtins.__dict__:
_ = gettext.gettext
@ -261,7 +261,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
font.setFamily("Seagoe UI")
self.view.setFont(font)
## GUI Events
# ## GUI Events
self.view.selectionModel().selectionChanged.connect(self.on_list_selection_change)
self.view.activated.connect(self.on_item_activated)
# self.view.keyPressed.connect(self.on_key)
@ -399,11 +399,11 @@ class ObjectCollection(QtCore.QAbstractItemModel):
if index.isValid():
obj = index.internalPointer().obj
if obj:
old_name = str(obj.options['name'])
old_name = obj.options['name']
new_name = str(data)
if old_name != new_name and new_name != '':
# rename the object
obj.options["name"] = str(data)
obj.options["name"] = deepcopy(data)
# update the SHELL auto-completer model data
try:
@ -411,11 +411,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
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:
except Exception as e:
log.debug(
"setData() --> Could not remove the old object name from auto-completer model list")
"setData() --> Could not remove the old object name from auto-completer model list. %s" %
str(e))
obj.build_ui()
# obj.build_ui()
self.app.inform.emit(_("Object renamed from <b>{old}</b> to <b>{new}</b>").format(old=old_name,
new=new_name))
@ -452,7 +453,7 @@ class ObjectCollection(QtCore.QAbstractItemModel):
# Prevent same name
while name in self.get_names():
## Create a new name
# ## Create a new name
# Ends with number?
FlatCAMApp.App.log.debug("new_object(): Object name (%s) exists, changing." % name)
match = re.search(r'(.*[^\d])?(\d+)$', name)
@ -525,8 +526,8 @@ class ObjectCollection(QtCore.QAbstractItemModel):
ymin = min([ymin, gymin])
xmax = max([xmax, gxmax])
ymax = max([ymax, gymax])
except:
FlatCAMApp.App.log.warning("DEV WARNING: Tried to get bounds of empty geometry.")
except Exception as e:
FlatCAMApp.App.log.warning("DEV WARNING: Tried to get bounds of empty geometry. %s" % str(e))
return [xmin, ymin, xmax, ymax]
@ -536,12 +537,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
:param name: The name of the object.
:type name: str
:param isCaseSensitive: whether searching of the object is done by name where the name is case sensitive
: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()")
if isCaseSensitive is None or isCaseSensitive is True:
for obj in self.get_list():
if obj.options['name'] == name:
@ -569,10 +570,9 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.myKeywords.remove(name)
self.app.shell._edit.set_model_data(self.app.myKeywords)
self.app.ui.code_editor.set_model_data(self.app.myKeywords)
except:
except Exception as e:
log.debug(
"delete_active() --> Could not remove the old object name from auto-completer model list")
"delete_active() --> Could not remove the old object name from auto-completer model list. %s" % str(e))
self.beginRemoveRows(self.index(group.row(), 0, QtCore.QModelIndex()), active.row(), active.row())
@ -649,12 +649,12 @@ class ObjectCollection(QtCore.QAbstractItemModel):
:return: List of objects
"""
l = self.get_list()
obj_list = self.get_list()
for sel in self.get_selected():
l.remove(sel)
obj_list.remove(sel)
return l
return obj_list
def set_active(self, name):
"""
@ -731,8 +731,8 @@ class ObjectCollection(QtCore.QAbstractItemModel):
self.app.inform.emit('')
try:
self.app.ui.selected_scroll_area.takeWidget()
except:
FlatCAMApp.App.log.debug("Nothing to remove")
except Exception as e:
FlatCAMApp.App.log.debug("Nothing to remove. %s" % str(e))
self.app.setup_component_editor()
return

View File

@ -9,12 +9,77 @@ CAD program, and create G-Code for Isolation routing.
=================================================
7.06.2019
- 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
- updated translations
- RELEASE 8.918
5.06.2019
- updated translations
- some layout changes in Edit -> Preferences such that the German translation (longer words than English) to fit correctly
- after editing an parameter the focus is lost so the user knows that something happened
4.06.2019
- PEP8 updates in FlatCAMExcEditor.py
- added the Excellon Editor parameters to the Edit -> Preferences -> Excellon GUI
- fixed a small bug in Excellon Editor
- PEP8 cleanup in FlatCAMGui
- finished adding the Excellon Editor parameters into the app logic and added a selection limit within Excellon Editor just like in the other editors
3.06.2019
- TclCommand Geocutout is now creating a new geometry object when working on a geometry, preserving also the origin object
- added a new parameter in Edit -> Preferences -> CNCJob named Annotation Color; it controls the color of the font used for annotations
- added a new parameter in Edit -> Preferences -> CNCJob named Annotation Size; it controls the size of the font used for annotations
- made visibility change threaded in FlatCAMObj()
2.06.2019
- fixed issue with geometry name not being updated immediately after change while doing geocutout TclCommand
- some changes to enable/disable project context menu entry handlers
1.06.2019
- fixed text annotation for CNC job so there are no overlapping numbers when 2 lines meet on the same point
- fixed issue in CNC job plotting where some of the isolation polygons are painted incorrectly
- fixed issue in CNCJob where the set circle steps is not used
31.05.2019
- added the possibility to display text annotation for the CNC travel lines. The setting is both in Preferences and in the CNC object properties
30.05.2019
- editing a multi geometry will no longer pop-up a Tcl window
- solved issue #292 where a new geometry renamed with many underscores failed to store the name in a saved project
- the name for the saved projects are updated to the current time and not to the time of the app startup
- some PEP8 changes related to comments starting with only one '#' symbol
- more PEP8 cleanup
- solved issue where after the opening of an object the file path is not saved for further open operations
24.05.2019
- added a toggle Grid button to the canvas context menu in the Grids submenu
- added a toggle left panel button to the canvas context menu
23.05.2019
- fixed bug in Gerber editor FCDisk and FCSemiDisc that the resulting geometry was not stored into the '0' aperture where all the solids are stored
- fixed minor issue in Gerber Editor where apertures were included in the saved object even if there was no geometric data for that aperture
- some PEP8 cleanup in FlatCAMApp.py
22.05.2019
- Geo Editor - added a new editor tool, Eraser
- some PEP8 cleanup of the Geo Editor
- fixed some selection issues in the new tool Eraser in Geometry Editor
- updated the translation files
- RELEASE 8.917
21.05.2019

218
camlib.py
View File

@ -1,12 +1,11 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
#import traceback
from io import StringIO
@ -58,6 +57,12 @@ if platform.architecture()[0] == '64bit':
from ortools.constraint_solver import pywrapcp
from ortools.constraint_solver import routing_enums_pb2
import gettext
import FlatCAMTranslation as fcTranslate
fcTranslate.apply_language('strings')
import builtins
log = logging.getLogger('base2')
log.setLevel(logging.DEBUG)
@ -66,11 +71,6 @@ handler = logging.StreamHandler()
handler.setFormatter(formatter)
log.addHandler(handler)
import gettext
import FlatCAMTranslation as fcTranslate
fcTranslate.apply_language('strings')
import builtins
if '_' not in builtins.__dict__:
_ = gettext.gettext
@ -132,21 +132,20 @@ class Geometry(object):
:param radius: Radius of the circle.
:return: None
"""
# TODO: Decide what solid_geometry is supposed to be and how we append to it.
if self.solid_geometry is None:
self.solid_geometry = []
if type(self.solid_geometry) is list:
self.solid_geometry.append(Point(origin).buffer(radius, int(int(self.geo_steps_per_circle) / 4)))
self.solid_geometry.append(Point(origin).buffer(
radius, int(int(self.geo_steps_per_circle) / 4)))
return
try:
self.solid_geometry = self.solid_geometry.union(Point(origin).buffer(radius,
int(int(self.geo_steps_per_circle) / 4)))
except:
#print "Failed to run union on polygons."
log.error("Failed to run union on polygons.")
self.solid_geometry = self.solid_geometry.union(Point(origin).buffer(
radius, int(int(self.geo_steps_per_circle) / 4)))
except Exception as e:
log.error("Failed to run union on polygons. %s" % str(e))
return
def add_polygon(self, points):
@ -165,9 +164,8 @@ class Geometry(object):
try:
self.solid_geometry = self.solid_geometry.union(Polygon(points))
except:
#print "Failed to run union on polygons."
log.error("Failed to run union on polygons.")
except Exception as e:
log.error("Failed to run union on polygons. %s" % str(e))
return
def add_polyline(self, points):
@ -186,13 +184,11 @@ class Geometry(object):
try:
self.solid_geometry = self.solid_geometry.union(LineString(points))
except:
#print "Failed to run union on polygons."
log.error("Failed to run union on polylines.")
except Exception as e:
log.error("Failed to run union on polylines. %s" % str(e))
return
def is_empty(self):
if isinstance(self.solid_geometry, BaseGeometry):
return self.solid_geometry.is_empty
@ -336,7 +332,8 @@ class Geometry(object):
poly, which can can be iterable, contain iterable of, or
be itself an implementer of .contains().
:param poly: See description
:param point: See description
:param geoset: a polygon or list of polygons where to find if the param point is contained
:return: Polygon containing point or None.
"""
@ -366,12 +363,12 @@ class Geometry(object):
if geometry is None:
geometry = self.solid_geometry
## If iterable, expand recursively.
# ## If iterable, expand recursively.
try:
for geo in geometry:
interiors.extend(self.get_interiors(geometry=geo))
## Not iterable, get the interiors if polygon.
# ## Not iterable, get the interiors if polygon.
except TypeError:
if type(geometry) == Polygon:
interiors.extend(geometry.interiors)
@ -393,12 +390,12 @@ class Geometry(object):
if geometry is None:
geometry = self.solid_geometry
## If iterable, expand recursively.
# ## If iterable, expand recursively.
try:
for geo in geometry:
exteriors.extend(self.get_exteriors(geometry=geo))
## Not iterable, get the exterior if polygon.
# ## Not iterable, get the exterior if polygon.
except TypeError:
if type(geometry) == Polygon:
exteriors.append(geometry.exterior)
@ -423,7 +420,7 @@ class Geometry(object):
if reset:
self.flat_geometry = []
## If iterable, expand recursively.
# ## If iterable, expand recursively.
try:
for geo in geometry:
if geo is not None:
@ -431,7 +428,7 @@ class Geometry(object):
reset=False,
pathonly=pathonly)
## Not iterable, do the actual indexing and add.
# ## Not iterable, do the actual indexing and add.
except TypeError:
if pathonly and type(geometry) == Polygon:
self.flat_geometry.append(geometry.exterior)
@ -480,18 +477,18 @@ class Geometry(object):
# if reset:
# self.flat_geometry = []
#
# ## If iterable, expand recursively.
# # ## If iterable, expand recursively.
# try:
# for geo in geometry:
# self.flatten_to_paths(geometry=geo, reset=False)
#
# ## Not iterable, do the actual indexing and add.
# # ## Not iterable, do the actual indexing and add.
# except TypeError:
# if type(geometry) == Polygon:
# g = geometry.exterior
# self.flat_geometry.append(g)
#
# ## Add first and last points of the path to the index.
# # ## Add first and last points of the path to the index.
# self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[0])
# self.flat_geometry_rtree.insert(len(self.flat_geometry) - 1, g.coords[-1])
#
@ -694,7 +691,6 @@ class Geometry(object):
else:
scale_factor = 1 / dpi
geos = []
unscaled_geos = []
@ -807,7 +803,7 @@ class Geometry(object):
assert type(polygon) == Polygon or type(polygon) == MultiPolygon, \
"Expected a Polygon or MultiPolygon, got %s" % type(polygon)
## The toolpaths
# ## The toolpaths
# Index first and last points in paths
def get_pts(o):
return [o.coords[0], o.coords[-1]]
@ -893,7 +889,7 @@ class Geometry(object):
# Current buffer radius
radius = tooldia / 2 * (1 - overlap)
## The toolpaths
# ## The toolpaths
# Index first and last points in paths
def get_pts(o):
return [o.coords[0], o.coords[-1]]
@ -973,7 +969,7 @@ class Geometry(object):
# log.debug("camlib.clear_polygon3()")
## The toolpaths
# ## The toolpaths
# Index first and last points in paths
def get_pts(o):
return [o.coords[0], o.coords[-1]]
@ -1071,7 +1067,7 @@ class Geometry(object):
# Assuming geolist is a flat list of flat elements
## Index first and last points in paths
# ## Index first and last points in paths
def get_pts(o):
return [o.coords[0], o.coords[-1]]
@ -1085,7 +1081,7 @@ class Geometry(object):
# storage.insert(LineString(shape))
# #storage.insert(shape)
## Iterate over geometry paths getting the nearest each time.
# ## Iterate over geometry paths getting the nearest each time.
#optimized_paths = []
optimized_paths = FlatCAMRTreeStorage()
optimized_paths.get_points = get_pts
@ -1159,7 +1155,7 @@ class Geometry(object):
log.debug("path_connect()")
## Index first and last points in paths
# ## Index first and last points in paths
def get_pts(o):
return [o.coords[0], o.coords[-1]]
#
@ -1180,11 +1176,7 @@ class Geometry(object):
try:
while True:
path_count += 1
#print "geo is", geo
_, left = storage.nearest(geo.coords[0])
#print "left is", left
# If left touches geo, remove left from original
# storage and append to geo.
@ -1210,7 +1202,6 @@ class Geometry(object):
continue
_, right = storage.nearest(geo.coords[-1])
#print "right is", right
# If right touches geo, remove left from original
# storage and append to geo.
@ -1243,7 +1234,7 @@ class Geometry(object):
if type(right) == LinearRing:
optimized_geometry.insert(right)
else:
# Cannot exteng geo any further. Put it away.
# Cannot extend geo any further. Put it away.
optimized_geometry.insert(geo)
# Continue with right.
@ -1288,7 +1279,7 @@ class Geometry(object):
def to_dict(self):
"""
Returns a respresentation of the object as a dictionary.
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.
@ -1485,7 +1476,7 @@ class ApertureMacro:
<Comment>: 0 <Text>
"""
## Regular expressions
# ## Regular expressions
am1_re = re.compile(r'^%AM([^\*]+)\*(.+)?(%)?$')
am2_re = re.compile(r'(.*)%$')
amcomm_re = re.compile(r'^0(.*)')
@ -1496,8 +1487,8 @@ class ApertureMacro:
self.name = name
self.raw = ""
## These below are recomputed for every aperture
## definition, in other words, are temporary variables.
# ## These below are recomputed for every aperture
# ## definition, in other words, are temporary variables.
self.primitives = []
self.locvars = {}
self.geometry = None
@ -1582,7 +1573,7 @@ class ApertureMacro:
# variables are defined in an aperture definition.
match = ApertureMacro.amprim_re.search(part)
if match:
## Replace all variables
# ## Replace all variables
for v in self.locvars:
# replaced the following line with the next to fix Mentor custom apertures not parsed OK
# part = re.sub(r'\$' + str(v) + r'(?![0-9a-zA-Z])', str(self.locvars[v]), part)
@ -1594,7 +1585,7 @@ class ApertureMacro:
# Change x with *
part = re.sub(r'[xX]', "*", part)
## Store
# ## Store
elements = part.split(",")
self.primitives.append([eval(x) for x in elements])
continue
@ -1754,8 +1745,8 @@ class ApertureMacro:
i = 1 # Number of rings created so far
## If the ring does not have an interior it means that it is
## a disk. Then stop.
# ## If the ring does not have an interior it means that it is
# ## a disk. Then stop.
while len(ring.interiors) > 0 and i < nrings:
r -= thickness + gap
if r <= 0:
@ -1764,7 +1755,7 @@ class ApertureMacro:
result = cascaded_union([result, ring])
i += 1
## Crosshair
# ## Crosshair
hor = LineString([(x - cross_len, y), (x + cross_len, y)]).buffer(cross_th/2.0, cap_style=2)
ver = LineString([(x, y-cross_len), (x, y + cross_len)]).buffer(cross_th/2.0, cap_style=2)
result = cascaded_union([result, hor, ver])
@ -1802,7 +1793,7 @@ class ApertureMacro:
:rtype: shapely.geometry.polygon
"""
## Primitive makers
# ## Primitive makers
makers = {
"1": ApertureMacro.make_circle,
"2": ApertureMacro.make_vectorline,
@ -1815,19 +1806,19 @@ class ApertureMacro:
"7": ApertureMacro.make_thermal
}
## Store modifiers as local variables
# ## Store modifiers as local variables
modifiers = modifiers or []
modifiers = [float(m) for m in modifiers]
self.locvars = {}
for i in range(0, len(modifiers)):
self.locvars[str(i + 1)] = modifiers[i]
## Parse
# ## Parse
self.primitives = [] # Cleanup
self.geometry = Polygon()
self.parse_content()
## Make the geometry
# ## Make the geometry
for primitive in self.primitives:
# Make the primitive
prim_geo = makers[str(int(primitive[0]))](primitive[1:])
@ -1898,9 +1889,7 @@ class Gerber (Geometry):
:rtype: Gerber
"""
# How to discretize a circle.
# if steps_per_circle is None:
# steps_per_circle = int(Gerber.defaults['steps_per_circle'])
# How to approximate a circle with lines.
self.steps_per_circle = int(self.app.defaults["gerber_circle_steps"])
# Initialize parent
@ -1917,7 +1906,7 @@ class Gerber (Geometry):
"""Zeros in Gerber numbers. If 'L' then remove leading zeros, if 'T' remove trailing zeros. Used during parsing.
"""
## Gerber elements ##
# ## Gerber elements # ##
'''
apertures = {
'id':{
@ -2304,7 +2293,7 @@ class Gerber (Geometry):
continue
# ############################################################# ##
# Number format ##################
# Number format ############################################### ##
# Example: %FSLAX24Y24*%
# ############################################################# ##
# TODO: This is ignoring most of the format. Implement the rest.
@ -3084,7 +3073,7 @@ class Gerber (Geometry):
else:
log.warning("Invalid arc in line %d." % line_num)
## EOF
# ## EOF
match = self.eof_re.search(gline)
if match:
continue
@ -3100,7 +3089,7 @@ class Gerber (Geometry):
pass
else:
# EOF, create shapely LineString if something still in path
## --- Buffered ---
# ## --- Buffered ---
geo_dict = dict()
# this treats the case when we are storing geometry as paths
@ -3392,7 +3381,7 @@ class Gerber (Geometry):
self.app.inform.emit(_("[success] Gerber Scale done."))
## solid_geometry ???
# ## solid_geometry ???
# It's a cascaded union of objects.
# self.solid_geometry = affinity.scale(self.solid_geometry, factor,
# factor, origin=(0, 0))
@ -3435,7 +3424,7 @@ class Gerber (Geometry):
else:
return affinity.translate(obj, xoff=dx, yoff=dy)
## Solid geometry
# ## Solid geometry
self.solid_geometry = offset_geom(self.solid_geometry)
self.follow_geometry = offset_geom(self.follow_geometry)
@ -3677,7 +3666,7 @@ class Excellon(Geometry):
self.num_tools = [] # List for keeping the tools sorted
self.index_per_tool = {} # Dictionary to store the indexed points for each tool
## IN|MM -> Units are inherited from Geometry
# ## IN|MM -> Units are inherited from Geometry
#self.units = units
# Trailing "T" or leading "L" (default)
@ -3946,7 +3935,7 @@ class Excellon(Geometry):
log.warning("Found end of the header: %s" % eline)
continue
## Alternative units format M71/M72
# ## Alternative units format M71/M72
# Supposed to be just in the body (yes, the body)
# but some put it in the header (PADS for example).
# Will detect anywhere. Occurrence will change the
@ -3969,7 +3958,7 @@ class Excellon(Geometry):
#### Body ## ##
if not in_header:
## Tool change ##
# ## Tool change # ##
match = self.toolsel_re.search(eline)
if match:
current_tool = str(int(match.group(1)))
@ -4009,7 +3998,7 @@ class Excellon(Geometry):
continue
## Allegro Type Tool change ##
# ## Allegro Type Tool change # ##
if allegro_warning is True:
match = self.absinc_re.search(eline)
match1 = self.stop_re.search(eline)
@ -4019,7 +4008,7 @@ class Excellon(Geometry):
log.debug(" Tool change for Allegro type of Excellon: %s" % current_tool)
continue
## Slots parsing for drilled slots (contain G85)
# ## Slots parsing for drilled slots (contain G85)
# a Excellon drilled slot line may look like this:
# X01125Y0022244G85Y0027756
match = self.slots_re.search(eline)
@ -4032,7 +4021,7 @@ class Excellon(Geometry):
start_coords_match = match.group(1)
stop_coords_match = match.group(2)
# Slot coordinates without period ##
# Slot coordinates without period # ##
# get the coordinates for slot start and for slot stop into variables
start_coords_noperiod = self.coordsnoperiod_re.search(start_coords_match)
stop_coords_noperiod = self.coordsnoperiod_re.search(stop_coords_match)
@ -4101,7 +4090,7 @@ class Excellon(Geometry):
)
continue
# Slot coordinates with period: Use literally. ##
# Slot coordinates with period: Use literally. # ##
# get the coordinates for slot start and for slot stop into variables
start_coords_period = self.coordsperiod_re.search(start_coords_match)
stop_coords_period = self.coordsperiod_re.search(stop_coords_match)
@ -4170,7 +4159,7 @@ class Excellon(Geometry):
)
continue
## Coordinates without period ##
# ## Coordinates without period # ##
match = self.coordsnoperiod_re.search(eline)
if match:
matchr = self.repeat_re.search(eline)
@ -4201,7 +4190,7 @@ class Excellon(Geometry):
log.error("Missing coordinates")
continue
## Excellon Routing parse
# ## Excellon Routing parse
if len(re.findall("G00", eline)) > 0:
self.match_routing_start = 'G00'
@ -4251,7 +4240,7 @@ class Excellon(Geometry):
# log.debug("{:15} {:8} {:8}".format(eline, x, y))
continue
## Coordinates with period: Use literally. ##
# ## Coordinates with period: Use literally. # ##
match = self.coordsperiod_re.search(eline)
if match:
matchr = self.repeat_re.search(eline)
@ -4282,7 +4271,7 @@ class Excellon(Geometry):
log.error("Missing coordinates")
continue
## Excellon Routing parse
# ## Excellon Routing parse
if len(re.findall("G00", eline)) > 0:
self.match_routing_start = 'G00'
@ -4336,7 +4325,7 @@ class Excellon(Geometry):
#### Header ## ##
if in_header:
## Tool definitions ##
# ## Tool definitions # ##
match = self.toolset_re.search(eline)
if match:
@ -4354,7 +4343,7 @@ class Excellon(Geometry):
log.debug(" Tool definition: %s %s" % (name, spec))
continue
## Units and number format ##
# ## Units and number format # ##
match = self.units_re.match(eline)
if match:
self.units_found = match.group(1)
@ -4412,7 +4401,7 @@ class Excellon(Geometry):
log.warning("Type of zeros found: %s" % self.zeros)
continue
## Units and number format outside header##
# ## Units and number format outside header# ##
match = self.units_re.match(eline)
if match:
self.units_found = match.group(1)
@ -4489,7 +4478,7 @@ class Excellon(Geometry):
# You must show all zeros to the right of the number and can omit
# all zeros to the left of the number. The CNC-7 will count the number
# of digits you typed and automatically fill in the missing zeros.
## flatCAM expects 6digits
# ## flatCAM expects 6digits
# flatCAM expects the number of digits entered into the defaults
if self.units.lower() == "in": # Inches is 00.0000
@ -4920,7 +4909,6 @@ class CNCjob(Geometry):
"pp_geometry_name":'default',
"pp_excellon_name":'default',
"excellon_optimization_type": "B",
"steps_per_circle": 64
}
def __init__(self,
@ -4937,11 +4925,9 @@ class CNCjob(Geometry):
steps_per_circle=None):
# Used when parsing G-code arcs
if steps_per_circle is None:
steps_per_circle = int(CNCjob.defaults["steps_per_circle"])
self.steps_per_circle = int(steps_per_circle)
self.steps_per_circle = int(self.app.defaults['cncjob_steps_per_circle'])
Geometry.__init__(self, geo_steps_per_circle=int(steps_per_circle))
Geometry.__init__(self, geo_steps_per_circle=self.steps_per_circle)
self.kind = kind
self.origin_kind = None
@ -4983,7 +4969,6 @@ class CNCjob(Geometry):
self.pp_solderpaste_name = None
# Controls if the move from Z_Toolchange to Z_Move is done fast with G0 or normally with G1
self.f_plunge = None
@ -5588,7 +5573,7 @@ class CNCjob(Geometry):
else:
temp_solid_geometry = geometry
## Flatten the geometry. Only linear elements (no polygons) remain.
# ## Flatten the geometry. Only linear elements (no polygons) remain.
flat_geometry = self.flatten(temp_solid_geometry, pathonly=True)
log.debug("%d paths" % len(flat_geometry))
@ -5665,7 +5650,7 @@ class CNCjob(Geometry):
"This is dangerous, skipping %s file") % self.options['name'])
return 'fail'
## Index first and last points in paths
# ## Index first and last points in paths
# What points to index.
def get_pts(o):
return [o.coords[0], o.coords[-1]]
@ -5719,7 +5704,7 @@ class CNCjob(Geometry):
if self.dwell is True:
self.gcode += self.doformat(p.dwell_code) # Dwell time
## Iterate over geometry paths getting the nearest each time.
# ## Iterate over geometry paths getting the nearest each time.
log.debug("Starting G-Code...")
path_count = 0
current_pt = (0, 0)
@ -5855,7 +5840,7 @@ class CNCjob(Geometry):
else:
temp_solid_geometry = geometry.solid_geometry
## Flatten the geometry. Only linear elements (no polygons) remain.
# ## Flatten the geometry. Only linear elements (no polygons) remain.
flat_geometry = self.flatten(temp_solid_geometry, pathonly=True)
log.debug("%d paths" % len(flat_geometry))
@ -5928,7 +5913,7 @@ class CNCjob(Geometry):
"This is dangerous, skipping %s file") % self.options['name'])
return 'fail'
## Index first and last points in paths
# ## Index first and last points in paths
# What points to index.
def get_pts(o):
return [o.coords[0], o.coords[-1]]
@ -5943,8 +5928,6 @@ class CNCjob(Geometry):
if shape is not None: # TODO: This shouldn't have happened.
storage.insert(shape)
# self.input_geometry_bounds = geometry.bounds()
if not append:
self.gcode = ""
@ -6041,7 +6024,7 @@ class CNCjob(Geometry):
log.debug("Generate_from_solderpaste_geometry()")
## Index first and last points in paths
# ## Index first and last points in paths
# What points to index.
def get_pts(o):
return [o.coords[0], o.coords[-1]]
@ -6077,7 +6060,7 @@ class CNCjob(Geometry):
else self.app.defaults['tools_solderpaste_pp']
p = self.app.postprocessors[self.pp_solderpaste_name]
## Flatten the geometry. Only linear elements (no polygons) remain.
# ## Flatten the geometry. Only linear elements (no polygons) remain.
flat_geometry = self.flatten(kwargs['solid_geometry'], pathonly=True)
log.debug("%d paths" % len(flat_geometry))
@ -6096,7 +6079,7 @@ class CNCjob(Geometry):
self.gcode += self.doformat(p.spindle_off_code)
self.gcode += self.doformat(p.toolchange_code)
## Iterate over geometry paths getting the nearest each time.
# ## Iterate over geometry paths getting the nearest each time.
log.debug("Starting SolderPaste G-Code...")
path_count = 0
current_pt = (0, 0)
@ -6355,12 +6338,12 @@ class CNCjob(Geometry):
gobj = self.codes_split(line)
## Units
# ## Units
if 'G' in gobj and (gobj['G'] == 20.0 or gobj['G'] == 21.0):
self.units = {20.0: "IN", 21.0: "MM"}[gobj['G']]
continue
## Changing height
# ## Changing height
if 'Z' in gobj:
if 'Roland' in self.pp_excellon_name or 'Roland' in self.pp_geometry_name:
pass
@ -6431,9 +6414,7 @@ class CNCjob(Geometry):
radius = sqrt(gobj['I']**2 + gobj['J']**2)
start = arctan2(-gobj['J'], -gobj['I'])
stop = arctan2(-center[1] + y, -center[0] + x)
path += arc(center, radius, start, stop,
arcdir[current['G']],
int(self.steps_per_circle / 4))
path += arc(center, radius, start, stop, arcdir[current['G']], int(self.steps_per_circle / 4))
# Update current instruction
for code in gobj:
@ -6498,6 +6479,7 @@ class CNCjob(Geometry):
:param tool_tolerance: Tolerance when drawing the toolshape.
:return: None
"""
# units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
gcode_parsed = gcode_parsed if gcode_parsed else self.gcode_parsed
path_num = 0
@ -6515,15 +6497,21 @@ class CNCjob(Geometry):
elif kind == 'cut':
if geo['kind'][0] == 'C':
obj.add_shape(shape=geo['geom'], color=color['C'][1], visible=visible)
else:
text = []
pos = []
for geo in gcode_parsed:
if geo['kind'][0] == 'T':
current_position = geo['geom'].coords[0]
if current_position not in pos:
pos.append(current_position)
path_num += 1
text.append(str(path_num))
current_position = geo['geom'].coords[-1]
if current_position not in pos:
pos.append(current_position)
path_num += 1
text.append(str(path_num))
pos.append(geo['geom'].coords[0])
# plot the geometry of Excellon objects
if self.origin_kind == 'excellon':
@ -6531,10 +6519,12 @@ class CNCjob(Geometry):
poly = Polygon(geo['geom'])
except ValueError:
# if the geos are travel lines it will enter into Exception
poly = geo['geom'].buffer(tooldia / 2.0).simplify(tool_tolerance)
poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle)
poly = poly.simplify(tool_tolerance)
else:
# plot the geometry of any objects other than Excellon
poly = geo['geom'].buffer(tooldia / 2.0).simplify(tool_tolerance)
poly = geo['geom'].buffer(distance=(tooldia / 1.99999999), resolution=self.steps_per_circle)
poly = poly.simplify(tool_tolerance)
if kind == 'all':
obj.add_shape(shape=poly, color=color[geo['kind'][0]][1], face_color=color[geo['kind'][0]][0],
@ -6548,7 +6538,9 @@ class CNCjob(Geometry):
obj.add_shape(shape=poly, color=color['C'][1], face_color=color['C'][0],
visible=visible, layer=1)
obj.annotation.set(text=text, pos=pos, visible=obj.options['plot'])
obj.annotation.set(text=text, pos=pos, visible=obj.options['plot'],
font_size=self.app.defaults["cncjob_annotation_fontsize"],
color=self.app.defaults["cncjob_annotation_fontcolor"])
def create_geometry(self):
# TODO: This takes forever. Too much data?
@ -7301,7 +7293,7 @@ def dict2obj(d):
# def plotg(geo, solid_poly=False, color="black"):
# try:
# _ = iter(geo)
# __ = iter(geo)
# except:
# geo = [geo]
#
@ -7334,7 +7326,7 @@ def dict2obj(d):
# continue
#
# try:
# _ = iter(g)
# __ = iter(g)
# plotg(g, color=color)
# except:
# log.error("Cannot plot: " + str(type(g)))
@ -7640,7 +7632,7 @@ def parse_gerber_number(strnumber, int_digits, frac_digits, zeros):
def autolist(obj):
try:
_ = iter(obj)
__ = iter(obj)
return obj
except TypeError:
return [obj]
@ -7699,7 +7691,7 @@ class FlatCAMRTree(object):
# Python RTree Index
self.rti = rtindex.Index()
## Track object-point relationship
# ## Track object-point relationship
# Each is list of points in object.
self.obj2points = []

View File

@ -16,9 +16,9 @@ from copy import copy, deepcopy
import gettext
import FlatCAMTranslation as fcTranslate
import builtins
fcTranslate.apply_language('strings')
import builtins
if '_' not in builtins.__dict__:
_ = gettext.gettext
@ -34,9 +34,9 @@ class FCDrillAdd(FCShapeTool):
self.selected_dia = None
try:
self.draw_app.app.inform.emit(self.start_msg)
# self.selected_dia = self.draw_app.tool2tooldia[self.draw_app.tools_table_exc.currentRow() + 1]
self.draw_app.app.inform.emit(_("Click to place ..."))
self.selected_dia = self.draw_app.tool2tooldia[self.draw_app.last_tool_selected]
# as a visual marker, select again in tooltable the actual tool that we are using
# remember that it was deselected when clicking on canvas
item = self.draw_app.tools_table_exc.item((self.draw_app.last_tool_selected - 1), 1)
@ -140,7 +140,7 @@ class FCDrillArray(FCShapeTool):
self.pt = []
try:
self.draw_app.app.inform.emit(self.start_msg)
self.draw_app.app.inform.emit(_("Click to place ..."))
self.selected_dia = self.draw_app.tool2tooldia[self.draw_app.last_tool_selected]
# as a visual marker, select again in tooltable the actual tool that we are using
# remember that it was deselected when clicking on canvas
@ -204,7 +204,7 @@ class FCDrillArray(FCShapeTool):
_("[ERROR_NOTCL] The value is not Float. Check for comma instead of dot separator."))
return
except Exception as e:
self.draw_app.app.inform.emit(_("[ERROR_NOTCL] The value is mistyped. Check the value."))
self.draw_app.app.inform.emit(_("[ERROR_NOTCL] The value is mistyped. Check the value. %s") % str(e))
return
if self.drill_array == 'Linear':
@ -350,7 +350,9 @@ class FCDrillResize(FCShapeTool):
try:
new_dia = self.draw_app.resdrill_entry.get_value()
except:
self.draw_app.app.inform.emit(_("[ERROR_NOTCL] Resize drill(s) failed. Please enter a diameter for resize."))
self.draw_app.app.inform.emit(
_("[ERROR_NOTCL] Resize drill(s) failed. Please enter a diameter for resize.")
)
return
if new_dia not in self.draw_app.olddia_newdia:
@ -416,7 +418,6 @@ class FCDrillResize(FCShapeTool):
for shp in sel_shapes_to_be_deleted:
self.draw_app.selected.remove(shp)
sel_shapes_to_be_deleted = []
self.draw_app.build_ui()
self.draw_app.replot()
@ -440,6 +441,8 @@ class FCDrillMove(FCShapeTool):
# self.shape_buffer = self.draw_app.shape_buffer
self.origin = None
self.destination = None
self.sel_limit = self.draw_app.app.defaults["excellon_editor_sel_limit"]
self.selection_shape = self.selection_bbox()
self.selected_dia_list = []
if self.draw_app.launched_from_shortcuts is True:
@ -503,6 +506,25 @@ class FCDrillMove(FCShapeTool):
self.draw_app.build_ui()
self.draw_app.app.inform.emit(_("[success] Done. Drill(s) Move completed."))
def selection_bbox(self):
geo_list = []
for select_shape in self.draw_app.get_selected():
geometric_data = select_shape.geo
try:
for g in geometric_data:
geo_list.append(g)
except TypeError:
geo_list.append(geometric_data)
xmin, ymin, xmax, ymax = get_shapely_list_bounds(geo_list)
pt1 = (xmin, ymin)
pt2 = (xmax, ymin)
pt3 = (xmax, ymax)
pt4 = (xmin, ymax)
return Polygon([pt1, pt2, pt3, pt4])
def utility_geometry(self, data=None):
"""
Temporary geometry on screen while using this tool.
@ -520,9 +542,22 @@ class FCDrillMove(FCShapeTool):
dx = data[0] - self.origin[0]
dy = data[1] - self.origin[1]
if len(self.draw_app.get_selected()) <= self.sel_limit:
try:
for geom in self.draw_app.get_selected():
geo_list.append(affinity.translate(geom.geo, xoff=dx, yoff=dy))
except AttributeError:
self.draw_app.select_tool('drill_select')
self.draw_app.selected = []
return
return DrawToolUtilityShape(geo_list)
else:
try:
ss_el = affinity.translate(self.selection_shape, xoff=dx, yoff=dy)
except ValueError:
ss_el = None
return DrawToolUtilityShape(ss_el)
class FCDrillCopy(FCDrillMove):
@ -595,8 +630,8 @@ class FCDrillSelect(DrawTool):
try:
for storage in self.exc_editor_app.storage_dict:
for shape in self.exc_editor_app.storage_dict[storage].get_objects():
self.sel_storage.insert(shape)
for sh in self.exc_editor_app.storage_dict[storage].get_objects():
self.sel_storage.insert(sh)
_, closest_shape = self.sel_storage.nearest(pos)
@ -718,19 +753,18 @@ 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__()
self.app = app
self.canvas = self.app.plotcanvas
## Current application units in Upper Case
# ## Current application units in Upper Case
self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
self.exc_edit_widget = QtWidgets.QWidget()
## Box for custom widgets
# ## Box for custom widgets
# This gets populated in offspring implementations.
layout = QtWidgets.QVBoxLayout()
self.exc_edit_widget.setLayout(layout)
@ -744,22 +778,22 @@ class FlatCAMExcEditor(QtCore.QObject):
self.tools_box.setContentsMargins(0, 0, 0, 0)
self.drills_frame.setLayout(self.tools_box)
## Page Title box (spacing between children)
# ## Page Title box (spacing between children)
self.title_box = QtWidgets.QHBoxLayout()
self.tools_box.addLayout(self.title_box)
## Page Title icon
# ## Page Title icon
pixmap = QtGui.QPixmap('share/flatcam_icon32.png')
self.icon = QtWidgets.QLabel()
self.icon.setPixmap(pixmap)
self.title_box.addWidget(self.icon, stretch=0)
## Title label
# ## Title label
self.title_label = QtWidgets.QLabel("<font size=5><b>%s</b></font>" % _('Excellon Editor'))
self.title_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.title_box.addWidget(self.title_label, stretch=1)
## Object name
# ## Object name
self.name_box = QtWidgets.QHBoxLayout()
self.tools_box.addLayout(self.name_box)
name_label = QtWidgets.QLabel(_("Name:"))
@ -804,7 +838,6 @@ class FlatCAMExcEditor(QtCore.QObject):
addtool_entry_lbl.setToolTip(
_("Diameter for the new tool")
)
grid1.addWidget(addtool_entry_lbl, 0, 0)
hlay = QtWidgets.QHBoxLayout()
self.addtool_entry = FCEntry()
@ -818,6 +851,8 @@ class FlatCAMExcEditor(QtCore.QObject):
)
self.addtool_btn.setFixedWidth(80)
hlay.addWidget(self.addtool_btn)
grid1.addWidget(addtool_entry_lbl, 0, 0)
grid1.addLayout(hlay, 0, 1)
grid2 = QtWidgets.QGridLayout()
@ -905,6 +940,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.array_form = QtWidgets.QFormLayout()
self.array_box.addLayout(self.array_form)
# Set the number of drill holes in the drill array
self.drill_array_size_label = QtWidgets.QLabel(_('Nr of drills:'))
self.drill_array_size_label.setToolTip(
_("Specify how many drills to be in the array.")
@ -924,6 +960,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.linear_form = QtWidgets.QFormLayout()
self.linear_box.addLayout(self.linear_form)
# Linear Drill Array direction
self.drill_axis_label = QtWidgets.QLabel(_('Direction:'))
self.drill_axis_label.setToolTip(
_("Direction on which the linear array is oriented:\n"
@ -936,9 +973,9 @@ class FlatCAMExcEditor(QtCore.QObject):
self.drill_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'},
{'label': 'Angle', 'value': 'A'}])
self.drill_axis_radio.set_value('X')
self.linear_form.addRow(self.drill_axis_label, self.drill_axis_radio)
# Linear Drill Array pitch distance
self.drill_pitch_label = QtWidgets.QLabel(_('Pitch:'))
self.drill_pitch_label.setToolTip(
_("Pitch = Distance between elements of the array.")
@ -948,6 +985,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.drill_pitch_entry = LengthEntry()
self.linear_form.addRow(self.drill_pitch_label, self.drill_pitch_entry)
# Linear Drill Array angle
self.linear_angle_label = QtWidgets.QLabel(_('Angle:'))
self.linear_angle_label.setToolTip(
_( "Angle at which the linear array is placed.\n"
@ -981,7 +1019,6 @@ class FlatCAMExcEditor(QtCore.QObject):
self.drill_direction_radio = RadioSet([{'label': 'CW', 'value': 'CW'},
{'label': 'CCW.', 'value': 'CCW'}])
self.drill_direction_radio.set_value('CW')
self.circular_form.addRow(self.drill_direction_label, self.drill_direction_radio)
self.drill_angle_label = QtWidgets.QLabel(_('Angle:'))
@ -1001,7 +1038,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.array_frame.hide()
self.tools_box.addStretch()
## Toolbar events and properties
# ## Toolbar events and properties
self.tools_exc = {
"drill_select": {"button": self.app.ui.select_drill_btn,
"constructor": FCDrillSelect},
@ -1073,12 +1110,6 @@ class FlatCAMExcEditor(QtCore.QObject):
self.app.ui.exc_move_drill_menuitem.triggered.connect(self.exc_move_drills)
# Init GUI
self.drill_array_size_entry.set_value(5)
self.drill_pitch_entry.set_value(2.54)
self.drill_angle_entry.set_value(12)
self.drill_direction_radio.set_value('CW')
self.drill_axis_radio.set_value('X')
self.exc_obj = None
# VisPy Visuals
@ -1090,7 +1121,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.shapes.enabled = False
self.tool_shape.enabled = False
## List of selected shapes.
# ## List of selected shapes.
self.selected = []
self.move_timer = QtCore.QTimer()
@ -1105,6 +1136,8 @@ class FlatCAMExcEditor(QtCore.QObject):
self.snap_y = None
self.pos = None
self.complete = False
def make_callback(thetool):
def f():
self.on_tool_select(thetool)
@ -1159,15 +1192,13 @@ class FlatCAMExcEditor(QtCore.QObject):
@staticmethod
def make_storage():
## Shape storage.
# ## Shape storage.
storage = FlatCAMRTreeStorage()
storage.get_points = DrawToolShape.get_pts
return storage
def set_ui(self):
# updated units
self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
@ -1186,6 +1217,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.points_edit[tool_dia].append(drill['point'])
except KeyError:
self.points_edit[tool_dia] = [drill['point']]
# update the olddia_newdia dict to make sure we have an updated state of the tool_table
for key in self.points_edit:
self.olddia_newdia[key] = key
@ -1211,6 +1243,15 @@ class FlatCAMExcEditor(QtCore.QObject):
tool_dia = float('%.2f' % v['C'])
self.tool2tooldia[int(k)] = tool_dia
# Init GUI
self.addtool_entry.set_value(float(self.app.defaults['excellon_editor_newdia']))
self.drill_array_size_entry.set_value(int(self.app.defaults['excellon_editor_array_size']))
self.drill_axis_radio.set_value(self.app.defaults['excellon_editor_lin_dir'])
self.drill_pitch_entry.set_value(float(self.app.defaults['excellon_editor_lin_pitch']))
self.linear_angle_spinner.set_value(float(self.app.defaults['excellon_editor_lin_angle']))
self.drill_direction_radio.set_value(self.app.defaults['excellon_editor_circ_dir'])
self.drill_angle_entry.set_value(float(self.app.defaults['excellon_editor_circ_angle']))
def build_ui(self, first_run=None):
try:
@ -1231,11 +1272,6 @@ class FlatCAMExcEditor(QtCore.QObject):
self.edited_obj_name = self.exc_obj.options['name']
self.name_entry.set_value(self.edited_obj_name)
if self.units == "IN":
self.addtool_entry.set_value(0.039)
else:
self.addtool_entry.set_value(1.00)
sort_temp = []
for diam in self.olddia_newdia:
@ -1278,9 +1314,9 @@ class FlatCAMExcEditor(QtCore.QObject):
# slot editing not implemented
pass
id = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.tools_table_exc.setItem(self.tool_row, 0, id) # Tool name/id
idd = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
idd.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
self.tools_table_exc.setItem(self.tool_row, 0, idd) # Tool name/id
# Make sure that the drill diameter when in MM is with no more than 2 decimals
# There are no drill bits in MM with more than 3 decimals diameter
@ -1375,7 +1411,6 @@ class FlatCAMExcEditor(QtCore.QObject):
self.tools_table_exc.item(self.tool_row, kl).setFont(font)
self.tools_table_exc.item(self.tool_row, kl).setForeground(QtGui.QColor(0, 70, 255))
# all the tools are selected by default
self.tools_table_exc.selectColumn(0)
#
@ -1458,7 +1493,8 @@ class FlatCAMExcEditor(QtCore.QObject):
# we add a new entry in the tool2tooldia dict
self.tool2tooldia[len(self.olddia_newdia)] = tool_dia
self.app.inform.emit(_("[success] Added new tool with dia: {dia} {units}").format(dia=str(tool_dia), units=str(self.units)))
self.app.inform.emit(_("[success] Added new tool with dia: {dia} {units}").format(dia=str(tool_dia),
units=str(self.units)))
self.build_ui()
@ -1475,7 +1511,6 @@ class FlatCAMExcEditor(QtCore.QObject):
def on_tool_delete(self, dia=None):
self.is_modified = True
deleted_tool_dia_list = []
deleted_tool_offset_list = []
try:
if dia is None or dia is False:
@ -1516,14 +1551,15 @@ class FlatCAMExcEditor(QtCore.QObject):
# delete the tool
self.tool2tooldia.pop(tool_to_be_deleted, None)
# delete also the drills from points_edit dict just in case we add the tool again, we don't want to show the
# number of drills from before was deleter
# delete also the drills from points_edit dict just in case we add the tool again,
# we don't want to show the number of drills from before was deleter
self.points_edit[deleted_tool_dia] = []
flag_del = []
self.olddia_newdia.pop(deleted_tool_dia, None)
self.app.inform.emit(_("[success] Deleted tool with dia: {del_dia} {units}").format(del_dia=str(deleted_tool_dia), units=str(self.units)))
self.app.inform.emit(_("[success] Deleted tool with dia: {del_dia} {units}").format(
del_dia=str(deleted_tool_dia),
units=str(self.units)))
self.replot()
# self.app.inform.emit("Could not delete selected tool")
@ -1539,7 +1575,6 @@ class FlatCAMExcEditor(QtCore.QObject):
# self.tools_table_exc.selectionModel().currentChanged.disconnect()
self.is_modified = True
geometry = []
current_table_dia_edited = None
if self.tools_table_exc.currentItem() is not None:
@ -1575,10 +1610,11 @@ class FlatCAMExcEditor(QtCore.QObject):
factor = current_table_dia_edited / dia_changed
geometry = []
for shape in self.storage_dict[dia_changed].get_objects():
geometry.append(DrawToolShape(
MultiLineString([affinity.scale(subgeo, xfact=factor, yfact=factor, origin='center')
for subgeo in shape.geo])))
for shape_exc in self.storage_dict[dia_changed].get_objects():
scaled_geo = MultiLineString(
[affinity.scale(subgeo, xfact=factor, yfact=factor, origin='center') for subgeo in shape_exc.geo]
)
geometry.append(DrawToolShape(scaled_geo))
# add bogus drill points (for total count of drills)
for k, v in self.olddia_newdia.items():
@ -1586,8 +1622,8 @@ class FlatCAMExcEditor(QtCore.QObject):
self.points_edit[k].append((0, 0))
break
# search for the oldia that correspond to the newdia and add the drills in it's storage
# everything will be sort out later, when the edited excellon is updated
# search for the old dia that correspond to the new dia and add the drills in it's storage
# everything will be sort out later, when the edited Excellon is updated
for k, v in self.olddia_newdia.items():
if v == current_table_dia_edited:
self.add_exc_shape(geometry, self.storage_dict[k])
@ -1739,7 +1775,7 @@ class FlatCAMExcEditor(QtCore.QObject):
self.drills_frame.hide()
def connect_canvas_event_handlers(self):
## Canvas events
# ## Canvas events
# first connect to new, then disconnect the old handlers
# don't ask why but if there is nothing connected I've seen issues
@ -1833,7 +1869,7 @@ class FlatCAMExcEditor(QtCore.QObject):
Imports the geometry from the given FlatCAM Excellon object
into the editor.
:param fcgeometry: FlatCAMExcellon
:param exc_obj: FlatCAMExcellon object
:return: None
"""
@ -1870,16 +1906,16 @@ class FlatCAMExcEditor(QtCore.QObject):
stop_hor_line = ((point.x + (tool_dia / 2)), point.y)
start_vert_line = (point.x, (point.y - (tool_dia / 2)))
stop_vert_line = (point.x, (point.y + (tool_dia / 2)))
shape = MultiLineString([(start_hor_line, stop_hor_line),(start_vert_line, stop_vert_line)])
if shape is not None:
self.add_exc_shape(DrawToolShape(shape), storage_elem)
shape_geo = MultiLineString([(start_hor_line, stop_hor_line), (start_vert_line, stop_vert_line)])
if shape_geo is not None:
self.add_exc_shape(DrawToolShape(shape_geo), storage_elem)
self.storage_dict[tool_dia] = storage_elem
self.replot()
# add a first tool in the Tool Table but only if the Excellon Object is empty
if not self.tool2tooldia:
self.on_tool_add(tooldia=1.00)
self.on_tool_add(tooldia=float(self.app.defaults['excellon_editor_newdia']))
def update_fcexcellon(self, exc_obj):
"""
@ -1907,7 +1943,7 @@ class FlatCAMExcEditor(QtCore.QObject):
# create a tuple with the coordinates (x, y) and add it to the list that is the value of the
# edited_points dictionary
point = (x_coord, y_coord)
if not storage_tooldia in edited_points:
if storage_tooldia not in edited_points:
edited_points[storage_tooldia] = [point]
else:
edited_points[storage_tooldia].append(point)
@ -1964,8 +2000,8 @@ class FlatCAMExcEditor(QtCore.QObject):
if self.is_modified is True:
if "_edit" in self.edited_obj_name:
try:
id = int(self.edited_obj_name[-1]) + 1
self.edited_obj_name = self.edited_obj_name[:-1] + str(id)
idd = int(self.edited_obj_name[-1]) + 1
self.edited_obj_name = self.edited_obj_name[:-1] + str(idd)
except ValueError:
self.edited_obj_name += "_1"
else:
@ -2116,7 +2152,7 @@ class FlatCAMExcEditor(QtCore.QObject):
def toolbar_tool_toggle(self, key):
self.options[key] = self.sender().isChecked()
if self.options[key] == True:
if self.options[key] is True:
return 1
else:
return 0
@ -2151,7 +2187,7 @@ class FlatCAMExcEditor(QtCore.QObject):
if self.active_tool is not None and event.button is 1:
# Dispatch event to active_tool
# msg = self.active_tool.click(self.app.geo_editor.snap(event.xdata, event.ydata))
msg = self.active_tool.click(self.app.geo_editor.snap(self.pos[0], self.pos[1]))
self.active_tool.click(self.app.geo_editor.snap(self.pos[0], self.pos[1]))
# If it is a shape generating tool
if isinstance(self.active_tool, FCShapeTool) and self.active_tool.complete:
@ -2207,6 +2243,7 @@ class FlatCAMExcEditor(QtCore.QObject):
:param shape: Shape to be added.
:type shape: DrawToolShape
:param storage: object where to store the shapes
:return: None
"""
# List of DrawToolShape?
@ -2221,8 +2258,7 @@ class FlatCAMExcEditor(QtCore.QObject):
assert shape.geo is not None, \
"Shape object has empty geometry (None)"
assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or \
not isinstance(shape.geo, list), \
assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or not isinstance(shape.geo, list), \
"Shape objects has empty geometry ([])"
if isinstance(shape, DrawToolUtilityShape):
@ -2251,8 +2287,7 @@ class FlatCAMExcEditor(QtCore.QObject):
assert shape.geo is not None, \
"Shape object has empty geometry (None)"
assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or \
not isinstance(shape.geo, list), \
assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or not isinstance(shape.geo, list), \
"Shape objects has empty geometry ([])"
if isinstance(shape, DrawToolUtilityShape):
@ -2318,14 +2353,15 @@ class FlatCAMExcEditor(QtCore.QObject):
log.warning("Error: %s" % str(e))
raise
def draw_selection_area_handler(self, start_pos, end_pos, sel_type):
def draw_selection_area_handler(self, start, end, sel_type):
"""
:param start_pos: mouse position when the selection LMB click was done
:param end_pos: mouse position when the left mouse button is released
:param sel_type: if True it's a left to right selection (enclosure), if False it's a 'touch' selection
:type Bool
:return:
"""
start_pos = (start[0], start[1])
end_pos = (end[0], end[1])
poly_selection = Polygon([start_pos, (end_pos[0], start_pos[1]), end_pos, (start_pos[0], end_pos[1])])
self.app.delete_selection_shape()
@ -2488,10 +2524,8 @@ class FlatCAMExcEditor(QtCore.QObject):
self.tool_shape.add(
shape=geo.geo, color=(self.app.defaults["global_draw_color"] + '80'),
update=False, layer=0, tolerance=None)
self.tool_shape.redraw()
def replot(self):
self.plot_all()
@ -2526,10 +2560,8 @@ class FlatCAMExcEditor(QtCore.QObject):
#
# self.plot_shape(geometry=shape.geo, color=self.app.defaults['global_draw_color'])
for shape in self.utility:
self.plot_shape(geometry=shape.geo, linewidth=1)
for shape_form in self.utility:
self.plot_shape(geometry=shape_form.geo, linewidth=1)
continue
self.shapes.redraw()
@ -2553,13 +2585,13 @@ class FlatCAMExcEditor(QtCore.QObject):
for geo in geometry:
plot_elements += self.plot_shape(geometry=geo, color=color, linewidth=linewidth)
## Non-iterable
# ## Non-iterable
except TypeError:
## DrawToolShape
# ## DrawToolShape
if isinstance(geometry, DrawToolShape):
plot_elements += self.plot_shape(geometry=geometry.geo, color=color, linewidth=linewidth)
## Polygon: Descend into exterior and each interior.
# ## Polygon: Descend into exterior and each interior.
if type(geometry) == Polygon:
plot_elements += self.plot_shape(geometry=geometry.exterior, color=color, linewidth=linewidth)
plot_elements += self.plot_shape(geometry=geometry.interiors, color=color, linewidth=linewidth)
@ -2604,11 +2636,11 @@ class FlatCAMExcEditor(QtCore.QObject):
self.build_ui()
self.app.inform.emit(_("[success] Done. Drill(s) deleted."))
def delete_shape(self, shape):
def delete_shape(self, del_shape):
self.is_modified = True
if shape in self.utility:
self.utility.remove(shape)
if del_shape in self.utility:
self.utility.remove(del_shape)
return
for storage in self.storage_dict:
@ -2616,8 +2648,8 @@ class FlatCAMExcEditor(QtCore.QObject):
# self.storage_dict[storage].remove(shape)
# except:
# pass
if shape in self.storage_dict[storage].get_objects():
self.storage_dict[storage].remove(shape)
if del_shape in self.storage_dict[storage].get_objects():
self.storage_dict[storage].remove(del_shape)
# a hack to make the tool_table display less drills per diameter
# self.points_edit it's only useful first time when we load the data into the storage
# but is still used as referecen when building tool_table in self.build_ui()
@ -2625,15 +2657,13 @@ class FlatCAMExcEditor(QtCore.QObject):
# deleting self.points_edit elements (doesn't matter who but just the number) solved the display issue.
del self.points_edit[storage][0]
if shape in self.selected:
self.selected.remove(shape) # TODO: Check performance
if del_shape in self.selected:
self.selected.remove(del_shape) # TODO: Check performance
def delete_utility_geometry(self):
# for_deletion = [shape for shape in self.shape_buffer if shape.utility]
# for_deletion = [shape for shape in self.storage.get_objects() if shape.utility]
for_deletion = [shape for shape in self.utility]
for shape in for_deletion:
self.delete_shape(shape)
for_deletion = [util_shape for util_shape in self.utility]
for util_shape in for_deletion:
self.delete_shape(util_shape)
self.tool_shape.clear(update=True)
self.tool_shape.redraw()
@ -2652,17 +2682,17 @@ class FlatCAMExcEditor(QtCore.QObject):
self.tools_exc[toolname]["button"].setChecked(True)
self.on_tool_select(toolname)
def set_selected(self, shape):
def set_selected(self, sel_shape):
# Remove and add to the end.
if shape in self.selected:
self.selected.remove(shape)
if sel_shape in self.selected:
self.selected.remove(sel_shape)
self.selected.append(shape)
self.selected.append(sel_shape)
def set_unselected(self, shape):
if shape in self.selected:
self.selected.remove(shape)
def set_unselected(self, unsel_shape):
if unsel_shape in self.selected:
self.selected.remove(unsel_shape)
def on_array_type_combo(self):
if self.array_type_combo.currentIndex() == 0:
@ -2702,3 +2732,24 @@ class FlatCAMExcEditor(QtCore.QObject):
def exc_move_drills(self):
self.select_tool('drill_move')
return
def get_shapely_list_bounds(geometry_list):
xmin = Inf
ymin = Inf
xmax = -Inf
ymax = -Inf
for gs in geometry_list:
try:
gxmin, gymin, gxmax, gymax = gs.bounds
xmin = min([xmin, gxmin])
ymin = min([ymin, gymin])
xmax = max([xmax, gxmax])
ymax = max([ymax, gymax])
except Exception as e:
log.warning("DEVELOPMENT: Tried to get bounds of empty geometry. --> %s" % str(e))
return [xmin, ymin, xmax, ymax]
# EOF

View File

@ -629,7 +629,7 @@ class TransformEditorTool(FlatCAMTool):
self.transform_lay = QtWidgets.QVBoxLayout()
self.layout.addLayout(self.transform_lay)
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % (_('Editor %s') % self.toolName))
title_label.setStyleSheet("""
QLabel
@ -2918,7 +2918,7 @@ class FCTransform(FCShapeTool):
# ##################### ##
# ## Main Application ###
# # ## Main Application # ##
# ##################### ##
class FlatCAMGeoEditor(QtCore.QObject):
@ -2935,7 +2935,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
self.app = app
self.canvas = app.plotcanvas
## Toolbar events and properties
# ## Toolbar events and properties
self.tools = {
"select": {"button": self.app.ui.geo_select_btn,
"constructor": FCSelect},
@ -2965,7 +2965,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
"constructor": FCCopy}
}
# ## Data
# # ## Data
self.active_tool = None
self.storage = FlatCAMGeoEditor.make_storage()
@ -3373,10 +3373,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
def toolbar_tool_toggle(self, key):
self.options[key] = self.sender().isChecked()
if self.options[key] == True:
return 1
else:
return 0
return 1 if self.options[key] == True else 0
def clear(self):
self.active_tool = None
@ -3416,7 +3413,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
if multigeo_tool:
self.multigeo_tool = multigeo_tool
geo_to_edit = fcgeometry.flatten(geometry=fcgeometry.tools[self.multigeo_tool]['solid_geometry'])
self.app.inform.emit(_("[WARNING] Editing MultiGeo Geometry, tool: {tool} with diameter: {dia}").
self.app.inform.emit(_("[WARNING_NOTCL] Editing MultiGeo Geometry, tool: {tool} with diameter: {dia}").
format(tool=self.multigeo_tool, dia=fcgeometry.tools[self.multigeo_tool]['tooldia']))
else:
geo_to_edit = fcgeometry.flatten()
@ -3572,7 +3569,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
if self.active_tool is None:
return
# ## Snap coordinates
# # ## Snap coordinates
if self.app.grid_status():
x, y = self.snap(x, y)
self.app.app_cursor.enabled = True
@ -3600,14 +3597,14 @@ class FlatCAMGeoEditor(QtCore.QObject):
if event.button == 1 and event.is_dragging == 1 and isinstance(self.active_tool, FCEraser):
pass
else:
# ## Utility geometry (animated)
# # ## Utility geometry (animated)
geo = self.active_tool.utility_geometry(data=(x, y))
if isinstance(geo, DrawToolShape) and geo.geo is not None:
# Remove any previous utility shape
self.tool_shape.clear(update=True)
self.draw_utility_geometry(geo=geo)
# ## Selection area on canvas section ###
# # ## Selection area on canvas section # ##
dx = pos[0] - self.pos[0]
if event.is_dragging == 1 and event.button == 1:
self.app.delete_selection_shape()
@ -3941,9 +3938,9 @@ class FlatCAMGeoEditor(QtCore.QObject):
snap_x, snap_y = (x, y)
snap_distance = Inf
# ## Object (corner?) snap
# ## No need for the objects, just the coordinates
# ## in the index.
# # ## Object (corner?) snap
# # ## No need for the objects, just the coordinates
# # ## in the index.
if self.options["corner_snap"]:
try:
nearest_pt, shape = self.storage.nearest((x, y))
@ -3955,7 +3952,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
except (StopIteration, AssertionError):
pass
# ## Grid snap
# # ## Grid snap
if self.options["grid_snap"]:
if self.options["global_gridx"] != 0:
snap_x_ = round(x / self.options["global_gridx"]) * self.options['global_gridx']

View File

@ -52,7 +52,7 @@ class DrawToolShape(object):
"""
pts = []
## Iterable: descend into each item.
# ## Iterable: descend into each item.
try:
for sub_o in o:
pts += DrawToolShape.get_pts(sub_o)
@ -64,7 +64,7 @@ class DrawToolShape(object):
if isinstance(o, DrawToolShape):
pts += DrawToolShape.get_pts(o.geo)
## Descend into .exerior and .interiors
# ## Descend into .exerior and .interiors
elif type(o) == Polygon:
pts += DrawToolShape.get_pts(o.exterior)
for i in o.interiors:
@ -72,7 +72,7 @@ class DrawToolShape(object):
elif type(o) == MultiLineString:
for line in o:
pts += DrawToolShape.get_pts(line)
## Has .coords: list them.
# ## Has .coords: list them.
else:
if DrawToolShape.tolerance is not None:
pts += list(o.simplify(DrawToolShape.tolerance).coords)
@ -1349,7 +1349,14 @@ class FCDisc(FCShapeTool):
size_ap = float(self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['size'])
self.buf_val = (size_ap / 2) if size_ap > 0 else 0.0000001
self.storage_obj = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['geometry']
if '0' in self.draw_app.storage_dict:
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
else:
self.draw_app.storage_dict['0'] = dict()
self.draw_app.storage_dict['0']['type'] = 'C'
self.draw_app.storage_dict['0']['size'] = 0.0
self.draw_app.storage_dict['0']['geometry'] = list()
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
self.draw_app.app.inform.emit(_("Click on Center point ..."))
@ -1436,7 +1443,14 @@ class FCSemiDisc(FCShapeTool):
size_ap = float(self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['size'])
self.buf_val = (size_ap / 2) if size_ap > 0 else 0.0000001
self.storage_obj = self.draw_app.storage_dict[self.draw_app.last_aperture_selected]['geometry']
if '0' in self.draw_app.storage_dict:
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
else:
self.draw_app.storage_dict['0'] = dict()
self.draw_app.storage_dict['0']['type'] = 'C'
self.draw_app.storage_dict['0']['size'] = 0.0
self.draw_app.storage_dict['0']['geometry'] = list()
self.storage_obj = self.draw_app.storage_dict['0']['geometry']
self.steps_per_circ = self.draw_app.app.defaults["gerber_circle_steps"]
@ -2050,7 +2064,9 @@ class FCEraser(FCShapeTool):
if 'solid' in geo_el.geo:
geometric_data = geo_el.geo['solid']
if eraser_sel_shapes.within(geometric_data) or eraser_sel_shapes.intersects(geometric_data):
geo_el.geo['solid'] = geometric_data.difference(eraser_sel_shapes)
geos = geometric_data.difference(eraser_sel_shapes)
geos = geos.buffer(0)
geo_el.geo['solid'] = deepcopy(geos)
except KeyError:
pass
@ -2374,7 +2390,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
hlay_ad.addWidget(self.addaperture_btn)
hlay_ad.addWidget(self.delaperture_btn)
# ## BUFFER TOOL ###
# # ## BUFFER TOOL # ##
self.buffer_tool_frame = QtWidgets.QFrame()
self.buffer_tool_frame.setContentsMargins(0, 0, 0, 0)
@ -2418,7 +2434,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.buffer_button = QtWidgets.QPushButton(_("Buffer"))
hlay_buf.addWidget(self.buffer_button)
# ## SCALE TOOL ###
# # ## SCALE TOOL # ##
self.scale_tool_frame = QtWidgets.QFrame()
self.scale_tool_frame.setContentsMargins(0, 0, 0, 0)
@ -2617,7 +2633,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
"constructor": FCApertureMove},
}
# ## Data
# # ## Data
self.active_tool = None
self.storage_dict = {}
@ -3621,7 +3637,13 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.gerber_obj.options['name'].upper())
out_name = outname
local_storage_dict = deepcopy(self.storage_dict)
local_storage_dict = dict()
for aperture in self.storage_dict:
if 'geometry' in self.storage_dict[aperture]:
# add aperture only if it has geometry
if len(self.storage_dict[aperture]['geometry']) > 0:
local_storage_dict[aperture] = deepcopy(self.storage_dict[aperture])
# How the object should be initialized
def obj_init(grb_obj, app_obj):
@ -4057,7 +4079,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
if self.active_tool is None:
return
# ## Snap coordinates
# # ## Snap coordinates
if self.app.grid_status():
x, y = self.app.geo_editor.snap(x, y)
self.app.app_cursor.enabled = True
@ -4082,7 +4104,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.app.ui.rel_position_label.setText("<b>Dx</b>: %.4f&nbsp;&nbsp; <b>Dy</b>: "
"%.4f&nbsp;&nbsp;&nbsp;&nbsp;" % (dx, dy))
# ## Utility geometry (animated)
# # ## Utility geometry (animated)
geo = self.active_tool.utility_geometry(data=(x, y))
if isinstance(geo, DrawToolShape) and geo.geo is not None:
@ -4090,7 +4112,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.tool_shape.clear(update=True)
self.draw_utility_geometry(geo=geo)
# ## Selection area on canvas section ###
# # ## Selection area on canvas section # ##
if event.is_dragging == 1 and event.button == 1:
# I make an exception for FCRegion and FCTrack because clicking and dragging while making regions can
# create strange issues like missing a point in a track/region

View File

@ -1,15 +1,15 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
############################################################
# ########################################################## ##
# File Modified (major mod): Marius Adrian Stanciu #
# Date: 3/10/2019 #
############################################################
# ########################################################## ##
from PyQt5.QtCore import QSettings
from flatcamGUI.GUIElements import *
@ -203,6 +203,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menufile.addSeparator()
self.menufile_save = self.menufile.addMenu(QtGui.QIcon('share/save_as.png'), _('Save'))
# Save Project
self.menufilesaveproject = QtWidgets.QAction(QtGui.QIcon('share/floppy16.png'), _('&Save Project ...'), self)
self.menufile_save.addAction(self.menufilesaveproject)
@ -377,7 +378,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
_("Toggle Workspace\tSHIFT+W"))
# ## Tool ###
# self.menutool = self.menu.addMenu('&Tool')
self.menutool = QtWidgets.QMenu(_('&Tool'))
self.menutoolaction = self.menu.addMenu(self.menutool)
self.menutoolshell = self.menutool.addAction(QtGui.QIcon('share/shell16.png'), _('&Command Line\tS'))
@ -393,14 +393,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
)
self.menuhelp_about = self.menuhelp.addAction(QtGui.QIcon('share/about32.png'), _('About'))
# ## FlatCAM Editor menu ###
# self.editor_menu = QtWidgets.QMenu("Editor")
# self.menu.addMenu(self.editor_menu)
self.geo_editor_menu = QtWidgets.QMenu(">Geo Editor<")
self.menu.addMenu(self.geo_editor_menu)
# self.select_menuitem = self.menu.addAction(QtGui.QIcon('share/pointer16.png'), "Select 'Esc'")
self.geo_add_circle_menuitem = self.geo_editor_menu.addAction(
QtGui.QIcon('share/circle32.png'), _('Add Circle\tO')
)
@ -469,7 +465,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
QtGui.QIcon('share/move32.png'),_( 'Move Drill(s)\tM'))
# ## APPLICATION GERBER EDITOR MENU ###
self.grb_editor_menu = QtWidgets.QMenu(_(">Gerber Editor<"))
self.menu.addMenu(self.grb_editor_menu)
@ -516,9 +511,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.exc_editor_menu.menuAction().setVisible(False)
self.exc_editor_menu.setDisabled(True)
################################
### Project Tab Context menu ###
################################
# ################################
# ### Project Tab Context menu ###
# ################################
self.menuproject = QtWidgets.QMenu()
self.menuprojectenable = self.menuproject.addAction(QtGui.QIcon('share/replot32.png'), _('Enable Plot'))
@ -535,9 +530,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.menuprojectproperties = self.menuproject.addAction(QtGui.QIcon('share/properties32.png'), _('Properties'))
################
### Splitter ###
################
# ################
# ### Splitter ###
# ################
# IMPORTANT #
# The order: SPITTER -> NOTEBOOK -> SNAP TOOLBAR is important and without it the GUI will not be initialized as
@ -638,10 +633,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# self.toolbarview.setVisible(False)
### Shell Toolbar ###
# ## Shell Toolbar ##
self.shell_btn = self.toolbarshell.addAction(QtGui.QIcon('share/shell32.png'), _("&Command Line"))
### Tools Toolbar ###
# ## Tools Toolbar ##
self.dblsided_btn = self.toolbartools.addAction(QtGui.QIcon('share/doubleside32.png'), _("2Sided Tool"))
self.cutout_btn = self.toolbartools.addAction(QtGui.QIcon('share/cut16_bis.png'), _("&Cutout Tool"))
self.ncc_btn = self.toolbartools.addAction(QtGui.QIcon('share/ncc16.png'), _("NCC Tool"))
@ -732,7 +727,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.grb_edit_toolbar.addSeparator()
self.aperture_move_btn = self.grb_edit_toolbar.addAction(QtGui.QIcon('share/move32.png'), _("Move"))
### Snap Toolbar ###
# # ## Snap Toolbar # ##
# Snap GRID toolbar is always active to facilitate usage of measurements done on GRID
# self.addToolBar(self.snap_toolbar)
@ -960,9 +955,9 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
"which is the file storing the working default preferences."))
self.pref_tab_bottom_layout_2.addWidget(self.pref_save_button)
########################################
# #################################################
# ## HERE WE BUILD THE SHORTCUTS LIST. TAB AREA ###
########################################
# #################################################
self.shortcuts_tab = QtWidgets.QWidget()
self.sh_tab_layout = QtWidgets.QVBoxLayout()
self.sh_tab_layout.setContentsMargins(2, 2, 2, 2)
@ -1575,11 +1570,13 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# ########################################################### ##
### HERE WE BUILD THE CONTEXT MENU FOR RMB CLICK ON CANVAS ###
# # ## HERE WE BUILD THE CONTEXT MENU FOR RMB CLICK ON CANVAS # ##
# ########################################################### ##
self.popMenu = FCMenu()
self.popmenu_disable = self.popMenu.addAction(QtGui.QIcon('share/clear_plot32.png'), _("Disable"))
self.popmenu_disable = self.popMenu.addAction(QtGui.QIcon('share/disable32.png'), _("Disable Plot"))
self.popmenu_panel_toggle = self.popMenu.addAction(QtGui.QIcon('share/notebook16.png'), _("Toggle Panel"))
self.popMenu.addSeparator()
self.cmenu_newmenu = self.popMenu.addMenu(QtGui.QIcon('share/file32.png'), _("New"))
self.popmenu_new_geo = self.cmenu_newmenu.addAction(QtGui.QIcon('share/new_geo32_bis.png'), _("Geometry"))
@ -1731,6 +1728,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
self.show()
self.filename = ""
self.units = ""
self.setAcceptDrops(True)
# # restore the Toolbar State from file
@ -2036,9 +2034,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
else:
key = event.key
# Propagate to tool
response = None
if self.app.call_source == 'app':
if modifiers == QtCore.Qt.ControlModifier:
if key == QtCore.Qt.Key_A:
@ -2702,7 +2697,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# we do this so we can reuse the following keys while inside a Tool
# the above keys are general enough so were left outside
if self.app.grb_editor.active_tool is not None and self.grb_select_btn.isChecked() == False:
if self.app.grb_editor.active_tool is not None and self.grb_select_btn.isChecked() is False:
response = self.app.grb_editor.active_tool.on_key(key=key)
if response is not None:
self.app.inform.emit(response)
@ -2811,7 +2806,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Add Track
if key == QtCore.Qt.Key_T or key == 'T':
self.app.grb_editor.launched_from_shortcuts = True
## Current application units in Upper Case
# ## Current application units in Upper Case
self.app.grb_editor.select_tool('track')
return
@ -2988,7 +2983,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
# Add Tool
if key == QtCore.Qt.Key_T or key == 'T':
self.app.exc_editor.launched_from_shortcuts = True
## Current application units in Upper Case
# ## Current application units in Upper Case
self.units = self.general_defaults_form.general_app_group.units_radio.get_value().upper()
tool_add_popup = FCInputDialog(title=_("New Tool ..."),
text=_('Enter a Tool Diameter:'),
@ -2999,7 +2994,8 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
if ok:
self.app.exc_editor.on_tool_add(tooldia=val)
self.app.inform.emit(
_("[success] Added new tool with dia: {dia} {units}").format(dia='%.4f' % float(val), units=str(self.units)))
_("[success] Added new tool with dia: {dia} {units}").format(dia='%.4f' % float(val),
units=str(self.units)))
else:
self.app.inform.emit(
_("[WARNING_NOTCL] Adding Tool cancelled ..."))
@ -3126,7 +3122,7 @@ class GeneralPreferencesUI(QtWidgets.QWidget):
self.setLayout(self.layout)
self.general_app_group = GeneralAppPrefGroupUI()
self.general_app_group.setFixedWidth(250)
self.general_app_group.setFixedWidth(280)
self.general_gui_group = GeneralGUIPrefGroupUI()
self.general_gui_group.setFixedWidth(250)
@ -3159,7 +3155,6 @@ class GerberPreferencesUI(QtWidgets.QWidget):
self.gerber_editor_group = GerberEditorPrefGroupUI()
self.gerber_editor_group.setFixedWidth(200)
self.vlay = QtWidgets.QVBoxLayout()
self.vlay.addWidget(self.gerber_opt_group)
self.vlay.addWidget(self.gerber_exp_group)
@ -3182,11 +3177,13 @@ class ExcellonPreferencesUI(QtWidgets.QWidget):
self.excellon_gen_group = ExcellonGenPrefGroupUI()
self.excellon_gen_group.setFixedWidth(220)
self.excellon_opt_group = ExcellonOptPrefGroupUI()
self.excellon_opt_group.setFixedWidth(250)
self.excellon_opt_group.setFixedWidth(290)
self.excellon_exp_group = ExcellonExpPrefGroupUI()
self.excellon_exp_group.setFixedWidth(250)
self.excellon_adv_opt_group = ExcellonAdvOptPrefGroupUI()
self.excellon_adv_opt_group.setFixedWidth(250)
self.excellon_editor_group = ExcellonEditorPrefGroupUI()
self.excellon_editor_group.setFixedWidth(260)
self.vlay = QtWidgets.QVBoxLayout()
self.vlay.addWidget(self.excellon_opt_group)
@ -3195,6 +3192,7 @@ class ExcellonPreferencesUI(QtWidgets.QWidget):
self.layout.addWidget(self.excellon_gen_group)
self.layout.addLayout(self.vlay)
self.layout.addWidget(self.excellon_adv_opt_group)
self.layout.addWidget(self.excellon_editor_group)
self.layout.addStretch()
@ -3209,9 +3207,9 @@ class GeometryPreferencesUI(QtWidgets.QWidget):
self.geometry_gen_group = GeometryGenPrefGroupUI()
self.geometry_gen_group.setFixedWidth(220)
self.geometry_opt_group = GeometryOptPrefGroupUI()
self.geometry_opt_group.setFixedWidth(250)
self.geometry_opt_group.setFixedWidth(300)
self.geometry_adv_opt_group = GeometryAdvOptPrefGroupUI()
self.geometry_adv_opt_group.setFixedWidth(250)
self.geometry_adv_opt_group.setFixedWidth(270)
self.geometry_editor_group = GeometryEditorPrefGroupUI()
self.geometry_editor_group.setFixedWidth(250)
@ -3289,7 +3287,7 @@ class CNCJobPreferencesUI(QtWidgets.QWidget):
self.setLayout(self.layout)
self.cncjob_gen_group = CNCJobGenPrefGroupUI()
self.cncjob_gen_group.setFixedWidth(270)
self.cncjob_gen_group.setFixedWidth(320)
self.cncjob_opt_group = CNCJobOptPrefGroupUI()
self.cncjob_opt_group.setFixedWidth(260)
self.cncjob_adv_opt_group = CNCJobAdvOptPrefGroupUI()
@ -3615,7 +3613,6 @@ class GeneralGUISetGroupUI(OptionsGroupUI):
# Create a form layout for the Application general settings
self.form_box = QtWidgets.QFormLayout()
# Layout selection
self.layout_label = QtWidgets.QLabel(_('Layout:'))
self.layout_label.setToolTip(
@ -3994,7 +3991,7 @@ class GerberGenPrefGroupUI(OptionsGroupUI):
self.setTitle(str("Gerber General"))
## Plot options
# ## Plot options
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
self.layout.addWidget(self.plot_options_label)
@ -4042,8 +4039,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Gerber Options")))
## Isolation Routing
# ## Isolation Routing
self.isolation_routing_label = QtWidgets.QLabel(_("<b>Isolation Routing:</b>"))
self.isolation_routing_label.setToolTip(
_("Create a Geometry object with\n"
@ -4077,8 +4073,13 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
overlabel = QtWidgets.QLabel(_('Pass overlap:'))
overlabel.setToolTip(
_("How much (fraction) of the tool width to overlap each tool pass.\n"
<<<<<<< HEAD
"Example:\n"
"A value here of 0.25 means an overlap of 25% from the tool diameter found above.")
=======
"Example:\n"
"A value here of 0.25 means an overlap of 25%% from the tool diameter found above.")
>>>>>>> remotes/jpcgt/flatcam/Beta
)
grid0.addWidget(overlabel, 2, 0)
self.iso_overlap_entry = FloatEntry()
@ -4102,7 +4103,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
)
grid0.addWidget(self.combine_passes_cb, 4, 0)
## Clear non-copper regions
# ## Clear non-copper regions
self.clearcopper_label = QtWidgets.QLabel(_("<b>Clear non-copper:</b>"))
self.clearcopper_label.setToolTip(
_("Create a Geometry object with\n"
@ -4133,7 +4134,7 @@ class GerberOptPrefGroupUI(OptionsGroupUI):
)
grid1.addWidget(self.noncopper_rounded_cb, 1, 0, 1, 2)
## Bounding box
# ## Bounding box
self.boundingbox_label = QtWidgets.QLabel(_('<b>Bounding Box:</b>'))
self.layout.addWidget(self.boundingbox_label)
@ -4167,8 +4168,7 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Gerber Adv. Options")))
## Advanced Gerber Parameters
# ## Advanced Gerber Parameters
self.adv_param_label = QtWidgets.QLabel(_("<b>Advanced Param.:</b>"))
self.adv_param_label.setToolTip(
_("A list of Gerber advanced parameters.\n"
@ -4186,7 +4186,6 @@ class GerberAdvOptPrefGroupUI(OptionsGroupUI):
_("Generate a 'Follow' geometry.\n"
"This means that it will cut through\n"
"the middle of the trace.")
)
grid0.addWidget(self.follow_cb, 0, 0)
@ -4617,7 +4616,7 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Excellon Options")))
## Create CNC Job
# ## Create CNC Job
self.cncjob_label = QtWidgets.QLabel(_('<b>Create CNC Job</b>'))
self.cncjob_label.setToolTip(
_("Parameters used to create a CNC Job object\n"
@ -4727,7 +4726,6 @@ class ExcellonOptPrefGroupUI(OptionsGroupUI):
self.pp_excellon_name_cb.setFocusPolicy(Qt.StrongFocus)
grid2.addWidget(self.pp_excellon_name_cb, 9, 1)
# ### Choose what to use for Gcode creation: Drills, Slots or Both
excellon_gcode_type_label = QtWidgets.QLabel(_('<b>Gcode: </b>'))
excellon_gcode_type_label.setToolTip(
@ -4791,9 +4789,9 @@ class ExcellonAdvOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Excellon Adv. Options")))
######################
## ADVANCED OPTIONS ##
######################
# #######################
# ## ADVANCED OPTIONS ###
# #######################
self.cncjob_label = QtWidgets.QLabel(_('<b>Advanced Options:</b>'))
self.cncjob_label.setToolTip(
@ -5026,6 +5024,129 @@ class ExcellonExpPrefGroupUI(OptionsGroupUI):
self.zeros_radio.setDisabled(False)
class ExcellonEditorPrefGroupUI(OptionsGroupUI):
def __init__(self, parent=None):
super(ExcellonEditorPrefGroupUI, self).__init__(self)
self.setTitle(str(_("Excellon Editor")))
# Excellon Editor Parameters
self.param_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.param_label.setToolTip(
_("A list of Excellon Editor parameters.")
)
self.layout.addWidget(self.param_label)
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
# Selection Limit
self.sel_limit_label = QtWidgets.QLabel(_("Selection limit:"))
self.sel_limit_label.setToolTip(
_("Set the number of selected Excellon geometry\n"
"items above which the utility geometry\n"
"becomes just a selection rectangle.\n"
"Increases the performance when moving a\n"
"large number of geometric elements.")
)
self.sel_limit_entry = IntEntry()
grid0.addWidget(self.sel_limit_label, 0, 0)
grid0.addWidget(self.sel_limit_entry, 0, 1)
# New tool diameter
self.addtool_entry_lbl = QtWidgets.QLabel(_('New Tool Dia:'))
self.addtool_entry_lbl.setToolTip(
_("Diameter for the new tool")
)
self.addtool_entry = FCEntry()
self.addtool_entry.setValidator(QtGui.QDoubleValidator(0.0001, 99.9999, 4))
grid0.addWidget(self.addtool_entry_lbl, 1, 0)
grid0.addWidget(self.addtool_entry, 1, 1)
# Number of drill holes in a drill array
self.drill_array_size_label = QtWidgets.QLabel(_('Nr of drills:'))
self.drill_array_size_label.setToolTip(
_("Specify how many drills to be in the array.")
)
# self.drill_array_size_label.setFixedWidth(100)
self.drill_array_size_entry = LengthEntry()
grid0.addWidget(self.drill_array_size_label, 2, 0)
grid0.addWidget(self.drill_array_size_entry, 2, 1)
self.drill_array_linear_label = QtWidgets.QLabel(_('<b>Linear Drill Array:</b>'))
grid0.addWidget(self.drill_array_linear_label, 3, 0, 1, 2)
# Linear Drill Array direction
self.drill_axis_label = QtWidgets.QLabel(_('Linear Dir.:'))
self.drill_axis_label.setToolTip(
_("Direction on which the linear array is oriented:\n"
"- 'X' - horizontal axis \n"
"- 'Y' - vertical axis or \n"
"- 'Angle' - a custom angle for the array inclination")
)
# self.drill_axis_label.setFixedWidth(100)
self.drill_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'},
{'label': 'Angle', 'value': 'A'}])
grid0.addWidget(self.drill_axis_label, 4, 0)
grid0.addWidget(self.drill_axis_radio, 4, 1)
# Linear Drill Array pitch distance
self.drill_pitch_label = QtWidgets.QLabel(_('Pitch:'))
self.drill_pitch_label.setToolTip(
_("Pitch = Distance between elements of the array.")
)
# self.drill_pitch_label.setFixedWidth(100)
self.drill_pitch_entry = LengthEntry()
grid0.addWidget(self.drill_pitch_label, 5, 0)
grid0.addWidget(self.drill_pitch_entry, 5, 1)
# Linear Drill Array custom angle
self.drill_angle_label = QtWidgets.QLabel(_('Angle:'))
self.drill_angle_label.setToolTip(
_("Angle at which each element in circular array is placed.")
)
self.drill_angle_entry = LengthEntry()
grid0.addWidget(self.drill_angle_label, 6, 0)
grid0.addWidget(self.drill_angle_entry, 6, 1)
self.drill_array_circ_label = QtWidgets.QLabel(_('<b>Circular Drill Array:</b>'))
grid0.addWidget(self.drill_array_circ_label, 7, 0, 1, 2)
# Circular Drill Array direction
self.drill_circular_direction_label = QtWidgets.QLabel(_('Circular Dir.:'))
self.drill_circular_direction_label.setToolTip(
_("Direction for circular array.\n"
"Can be CW = clockwise or CCW = counter clockwise.")
)
self.drill_circular_dir_radio = RadioSet([{'label': 'CW', 'value': 'CW'},
{'label': 'CCW.', 'value': 'CCW'}])
grid0.addWidget(self.drill_circular_direction_label, 8, 0)
grid0.addWidget(self.drill_circular_dir_radio, 8, 1)
# Circular Drill Array Angle
self.drill_circular_angle_label = QtWidgets.QLabel(_('Circ. Angle:'))
self.drill_circular_angle_label.setToolTip(
_("Angle at which each element in circular array is placed.")
)
self.drill_circular_angle_entry = LengthEntry()
grid0.addWidget(self.drill_circular_angle_label, 9, 0)
grid0.addWidget(self.drill_circular_angle_entry, 9, 1)
self.layout.addStretch()
class GeometryGenPrefGroupUI(OptionsGroupUI):
def __init__(self, parent=None):
# OptionsGroupUI.__init__(self, "Geometry General Preferences", parent=parent)
@ -5033,7 +5154,7 @@ class GeometryGenPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Geometry General")))
## Plot options
# ## Plot options
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
self.layout.addWidget(self.plot_options_label)
@ -5084,7 +5205,7 @@ class GeometryOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Geometry Options")))
# ------------------------------
## Create CNC Job
# ## Create CNC Job
# ------------------------------
self.cncjob_label = QtWidgets.QLabel(_('<b>Create CNC Job:</b>'))
self.cncjob_label.setToolTip(
@ -5243,7 +5364,7 @@ class GeometryAdvOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Geometry Adv. Options")))
# ------------------------------
## Advanced Options
# ## Advanced Options
# ------------------------------
self.cncjob_label = QtWidgets.QLabel(_('<b>Advanced Options:</b>'))
self.cncjob_label.setToolTip(
@ -5405,7 +5526,7 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("CNC Job General")))
## Plot options
# ## Plot options
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
self.layout.addWidget(self.plot_options_label)
@ -5441,15 +5562,62 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.cncplot_method_radio, 1, 1)
grid0.addWidget(QtWidgets.QLabel(''), 1, 2)
# Number of circle steps for circular aperture linear approximation
# Display Annotation
self.annotation_label = QtWidgets.QLabel(_("Display Annotation:"))
self.annotation_label.setToolTip(
_("This selects if to display text annotation on the plot.\n"
"When checked it will display numbers in order for each end\n"
"of a travel line."
)
)
self.annotation_cb = FCCheckBox()
grid0.addWidget(self.annotation_label, 2, 0)
grid0.addWidget(self.annotation_cb, 2, 1)
grid0.addWidget(QtWidgets.QLabel(''), 2, 2)
# Annotation Font Size
self.annotation_fontsize_label = QtWidgets.QLabel(_("Annotation Size:"))
self.annotation_fontsize_label.setToolTip(
_("The font size of the annotation text. In pixels.")
)
grid0.addWidget(self.annotation_fontsize_label, 3, 0)
self.annotation_fontsize_sp = FCSpinner()
grid0.addWidget(self.annotation_fontsize_sp, 3, 1)
grid0.addWidget(QtWidgets.QLabel(''), 3, 2)
# Annotation Font Color
self.annotation_color_label = QtWidgets.QLabel(_('Annotation Color:'))
self.annotation_color_label.setToolTip(
_("Set the font color for the annotation texts.")
)
self.annotation_fontcolor_entry = FCEntry()
self.annotation_fontcolor_button = QtWidgets.QPushButton()
self.annotation_fontcolor_button.setFixedSize(15, 15)
self.form_box_child = QtWidgets.QHBoxLayout()
self.form_box_child.setContentsMargins(0, 0, 0, 0)
self.form_box_child.addWidget(self.annotation_fontcolor_entry)
self.form_box_child.addWidget(self.annotation_fontcolor_button, alignment=Qt.AlignRight)
self.form_box_child.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
color_widget = QtWidgets.QWidget()
color_widget.setLayout(self.form_box_child)
grid0.addWidget(self.annotation_color_label, 4, 0)
grid0.addWidget(color_widget, 4, 1)
grid0.addWidget(QtWidgets.QLabel(''), 4, 2)
# ###################################################################
# Number of circle steps for circular aperture linear approximation #
# ###################################################################
self.steps_per_circle_label = QtWidgets.QLabel(_("Circle Steps:"))
self.steps_per_circle_label.setToolTip(
_("The number of circle steps for <b>GCode</b> \n"
"circle and arc shapes linear approximation.")
)
grid0.addWidget(self.steps_per_circle_label, 2, 0)
grid0.addWidget(self.steps_per_circle_label, 5, 0)
self.steps_per_circle_entry = IntEntry()
grid0.addWidget(self.steps_per_circle_entry, 2, 1)
grid0.addWidget(self.steps_per_circle_entry, 5, 1)
# Tool dia for plot
tdlabel = QtWidgets.QLabel(_('Tool dia:'))
@ -5457,9 +5625,9 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
_("Diameter of the tool to be\n"
"rendered in the plot.")
)
grid0.addWidget(tdlabel, 3, 0)
grid0.addWidget(tdlabel, 6, 0)
self.tooldia_entry = LengthEntry()
grid0.addWidget(self.tooldia_entry, 3, 1)
grid0.addWidget(self.tooldia_entry,6, 1)
# Number of decimals to use in GCODE coordinates
cdeclabel = QtWidgets.QLabel(_('Coords dec.:'))
@ -5467,9 +5635,9 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
_("The number of decimals to be used for \n"
"the X, Y, Z coordinates in CNC code (GCODE, etc.)")
)
grid0.addWidget(cdeclabel, 4, 0)
grid0.addWidget(cdeclabel, 7, 0)
self.coords_dec_entry = IntEntry()
grid0.addWidget(self.coords_dec_entry, 4, 1)
grid0.addWidget(self.coords_dec_entry, 7, 1)
# Number of decimals to use in GCODE feedrate
frdeclabel = QtWidgets.QLabel(_('Feedrate dec.:'))
@ -5477,9 +5645,9 @@ class CNCJobGenPrefGroupUI(OptionsGroupUI):
_("The number of decimals to be used for \n"
"the Feedrate parameter in CNC code (GCODE, etc.)")
)
grid0.addWidget(frdeclabel, 5, 0)
grid0.addWidget(frdeclabel, 8, 0)
self.fr_dec_entry = IntEntry()
grid0.addWidget(self.fr_dec_entry, 5, 1)
grid0.addWidget(self.fr_dec_entry, 8, 1)
self.layout.addStretch()
@ -5491,7 +5659,7 @@ class CNCJobOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("CNC Job Options")))
## Export G-Code
# ## Export G-Code
self.export_gcode_label = QtWidgets.QLabel(_("<b>Export G-Code:</b>"))
self.export_gcode_label.setToolTip(
_("Export and save G-Code to\n"
@ -5532,7 +5700,7 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("CNC Job Adv. Options")))
## Export G-Code
# ## Export G-Code
self.export_gcode_label = QtWidgets.QLabel(_("<b>Export G-Code:</b>"))
self.export_gcode_label.setToolTip(
_("Export and save G-Code to\n"
@ -5592,7 +5760,8 @@ class CNCJobAdvOptPrefGroupUI(OptionsGroupUI):
self.tc_variable_combo.setItemData(8, _("z_move = Z height for travel"), Qt.ToolTipRole)
self.tc_variable_combo.setItemData(9, _("z_depthpercut = the step value for multidepth cut"), Qt.ToolTipRole)
self.tc_variable_combo.setItemData(10, _("spindlesspeed = the value for the spindle speed"), Qt.ToolTipRole)
self.tc_variable_combo.setItemData(11, _("dwelltime = time to dwell to allow the spindle to reach it's set RPM"),
self.tc_variable_combo.setItemData(11,
_("dwelltime = time to dwell to allow the spindle to reach it's set RPM"),
Qt.ToolTipRole)
hlay1.addStretch()
@ -5615,7 +5784,7 @@ class ToolsNCCPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("NCC Tool Options")))
## Clear non-copper regions
# ## Clear non-copper regions
self.clearcopper_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.clearcopper_label.setToolTip(
_("Create a Geometry object with\n"
@ -5716,7 +5885,7 @@ class ToolsCutoutPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Cutout Tool Options")))
## Board cuttout
# ## Board cuttout
self.board_cutout_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.board_cutout_label.setToolTip(
_("Create toolpaths to cut around\n"
@ -5795,7 +5964,7 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("2Sided Tool Options")))
## Board cuttout
# ## Board cuttout
self.dblsided_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.dblsided_label.setToolTip(
_("A tool to help in creating a double sided\n"
@ -5806,7 +5975,7 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
## Drill diameter for alignment holes
# ## Drill diameter for alignment holes
self.drill_dia_entry = LengthEntry()
self.dd_label = QtWidgets.QLabel(_("Drill diam.:"))
self.dd_label.setToolTip(
@ -5816,7 +5985,7 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.dd_label, 0, 0)
grid0.addWidget(self.drill_dia_entry, 0, 1)
## Axis
# ## Axis
self.mirror_axis_radio = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}])
self.mirax_label = QtWidgets.QLabel(_("Mirror Axis:"))
@ -5829,7 +5998,7 @@ class Tools2sidedPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.mirax_label, 2, 0)
grid0.addWidget(self.mirror_axis_radio, 2, 1)
## Axis Location
# ## Axis Location
self.axis_location_radio = RadioSet([{'label': 'Point', 'value': 'point'},
{'label': 'Box', 'value': 'box'}])
self.axloc_label = QtWidgets.QLabel(_("Axis Ref:"))
@ -5853,7 +6022,7 @@ class ToolsPaintPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Paint Tool Options")))
# ------------------------------
## Paint area
# ## Paint area
# ------------------------------
self.paint_label = QtWidgets.QLabel(_('<b>Parameters:</b>'))
self.paint_label.setToolTip(
@ -5957,7 +6126,7 @@ class ToolsFilmPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Film Tool Options")))
## Board cuttout
# ## Board cuttout
self.film_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.film_label.setToolTip(
_("Create a PCB film from a Gerber or Geometry\n"
@ -6018,7 +6187,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Panelize Tool Options")))
## Board cuttout
# ## Board cuttout
self.panelize_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.panelize_label.setToolTip(
_("Create an object that contains an array of (x, y) elements,\n"
@ -6030,7 +6199,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
## Spacing Columns
# ## Spacing Columns
self.pspacing_columns = FCEntry()
self.spacing_columns_label = QtWidgets.QLabel(_("Spacing cols:"))
self.spacing_columns_label.setToolTip(
@ -6040,7 +6209,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.spacing_columns_label, 0, 0)
grid0.addWidget(self.pspacing_columns, 0, 1)
## Spacing Rows
# ## Spacing Rows
self.pspacing_rows = FCEntry()
self.spacing_rows_label = QtWidgets.QLabel(_("Spacing rows:"))
self.spacing_rows_label.setToolTip(
@ -6050,7 +6219,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.spacing_rows_label, 1, 0)
grid0.addWidget(self.pspacing_rows, 1, 1)
## Columns
# ## Columns
self.pcolumns = FCEntry()
self.columns_label = QtWidgets.QLabel(_("Columns:"))
self.columns_label.setToolTip(
@ -6059,7 +6228,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.columns_label, 2, 0)
grid0.addWidget(self.pcolumns, 2, 1)
## Rows
# ## Rows
self.prows = FCEntry()
self.rows_label = QtWidgets.QLabel(_("Rows:"))
self.rows_label.setToolTip(
@ -6068,7 +6237,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.rows_label, 3, 0)
grid0.addWidget(self.prows, 3, 1)
## Type of resulting Panel object
# ## Type of resulting Panel object
self.panel_type_radio = RadioSet([{'label': 'Gerber', 'value': 'gerber'},
{'label': 'Geo', 'value': 'geometry'}])
self.panel_type_label = QtWidgets.QLabel(_("Panel Type:"))
@ -6081,7 +6250,7 @@ class ToolsPanelizePrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.panel_type_label, 4, 0)
grid0.addWidget(self.panel_type_radio, 4, 1)
## Constrains
# ## Constrains
self.pconstrain_cb = FCCheckBox(_("Constrain within:"))
self.pconstrain_cb.setToolTip(
_("Area define by DX and DY within to constrain the panel.\n"
@ -6120,7 +6289,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Calculators Tool Options")))
## V-shape Calculator Tool
# ## V-shape Calculator Tool
self.vshape_tool_label = QtWidgets.QLabel(_("<b>V-Shape Tool Calculator:</b>"))
self.vshape_tool_label.setToolTip(
_("Calculate the tool diameter for a given V-shape tool,\n"
@ -6132,7 +6301,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
## Tip Diameter
# ## Tip Diameter
self.tip_dia_entry = FCEntry()
self.tip_dia_label = QtWidgets.QLabel(_("Tip Diameter:"))
self.tip_dia_label.setToolTip(
@ -6142,7 +6311,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.tip_dia_label, 0, 0)
grid0.addWidget(self.tip_dia_entry, 0, 1)
## Tip angle
# ## Tip angle
self.tip_angle_entry = FCEntry()
self.tip_angle_label = QtWidgets.QLabel(_("Tip angle:"))
self.tip_angle_label.setToolTip(
@ -6152,7 +6321,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.tip_angle_label, 1, 0)
grid0.addWidget(self.tip_angle_entry, 1, 1)
## Depth-of-cut Cut Z
# ## Depth-of-cut Cut Z
self.cut_z_entry = FCEntry()
self.cut_z_label = QtWidgets.QLabel(_("Cut Z:"))
self.cut_z_label.setToolTip(
@ -6162,7 +6331,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.cut_z_label, 2, 0)
grid0.addWidget(self.cut_z_entry, 2, 1)
## Electroplating Calculator Tool
# ## Electroplating Calculator Tool
self.plate_title_label = QtWidgets.QLabel(_("<b>ElectroPlating Calculator:</b>"))
self.plate_title_label.setToolTip(
_("This calculator is useful for those who plate the via/pad/drill holes,\n"
@ -6173,7 +6342,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid1 = QtWidgets.QGridLayout()
self.layout.addLayout(grid1)
## PCB Length
# ## PCB Length
self.pcblength_entry = FCEntry()
self.pcblengthlabel = QtWidgets.QLabel(_("Board Length:"))
@ -6181,7 +6350,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid1.addWidget(self.pcblengthlabel, 0, 0)
grid1.addWidget(self.pcblength_entry, 0, 1)
## PCB Width
# ## PCB Width
self.pcbwidth_entry = FCEntry()
self.pcbwidthlabel = QtWidgets.QLabel(_("Board Width:"))
@ -6189,7 +6358,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid1.addWidget(self.pcbwidthlabel, 1, 0)
grid1.addWidget(self.pcbwidth_entry, 1, 1)
## Current Density
# ## Current Density
self.cdensity_label = QtWidgets.QLabel(_("Current Density:"))
self.cdensity_entry = FCEntry()
@ -6198,7 +6367,7 @@ class ToolsCalculatorsPrefGroupUI(OptionsGroupUI):
grid1.addWidget(self.cdensity_label, 2, 0)
grid1.addWidget(self.cdensity_entry, 2, 1)
## PCB Copper Growth
# ## PCB Copper Growth
self.growth_label = QtWidgets.QLabel(_("Copper Growth:"))
self.growth_entry = FCEntry()
@ -6217,7 +6386,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("Transform Tool Options")))
## Transformations
# ## Transformations
self.transform_label = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.transform_label.setToolTip(
_("Various transformations that can be applied\n"
@ -6228,7 +6397,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0)
## Rotate Angle
# ## Rotate Angle
self.rotate_entry = FCEntry()
self.rotate_label = QtWidgets.QLabel(_("Rotate Angle:"))
self.rotate_label.setToolTip(
@ -6237,7 +6406,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.rotate_label, 0, 0)
grid0.addWidget(self.rotate_entry, 0, 1)
## Skew/Shear Angle on X axis
# ## Skew/Shear Angle on X axis
self.skewx_entry = FCEntry()
self.skewx_label = QtWidgets.QLabel(_("Skew_X angle:"))
self.skewx_label.setToolTip(
@ -6246,7 +6415,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.skewx_label, 1, 0)
grid0.addWidget(self.skewx_entry, 1, 1)
## Skew/Shear Angle on Y axis
# ## Skew/Shear Angle on Y axis
self.skewy_entry = FCEntry()
self.skewy_label = QtWidgets.QLabel(_("Skew_Y angle:"))
self.skewy_label.setToolTip(
@ -6255,7 +6424,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.skewy_label, 2, 0)
grid0.addWidget(self.skewy_entry, 2, 1)
## Scale factor on X axis
# ## Scale factor on X axis
self.scalex_entry = FCEntry()
self.scalex_label = QtWidgets.QLabel(_("Scale_X factor:"))
self.scalex_label.setToolTip(
@ -6264,7 +6433,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.scalex_label, 3, 0)
grid0.addWidget(self.scalex_entry, 3, 1)
## Scale factor on X axis
# ## Scale factor on X axis
self.scaley_entry = FCEntry()
self.scaley_label = QtWidgets.QLabel(_("Scale_Y factor:"))
self.scaley_label.setToolTip(
@ -6273,7 +6442,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.scaley_label, 4, 0)
grid0.addWidget(self.scaley_entry, 4, 1)
## Link Scale factors
# ## Link Scale factors
self.link_cb = FCCheckBox(_("Link"))
self.link_cb.setToolTip(
_("Scale the selected object(s)\n"
@ -6281,7 +6450,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
)
grid0.addWidget(self.link_cb, 5, 0)
## Scale Reference
# ## Scale Reference
self.reference_cb = FCCheckBox(_("Scale Reference"))
self.reference_cb.setToolTip(
_("Scale the selected object(s)\n"
@ -6291,7 +6460,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
)
grid0.addWidget(self.reference_cb, 5, 1)
## Offset distance on X axis
# ## Offset distance on X axis
self.offx_entry = FCEntry()
self.offx_label = QtWidgets.QLabel(_("Offset_X val:"))
self.offx_label.setToolTip(
@ -6300,7 +6469,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.offx_label, 6, 0)
grid0.addWidget(self.offx_entry, 6, 1)
## Offset distance on Y axis
# ## Offset distance on Y axis
self.offy_entry = FCEntry()
self.offy_label = QtWidgets.QLabel(_("Offset_Y val:"))
self.offy_label.setToolTip(
@ -6309,7 +6478,7 @@ class ToolsTransformPrefGroupUI(OptionsGroupUI):
grid0.addWidget(self.offy_label, 7, 0)
grid0.addWidget(self.offy_entry, 7, 1)
## Mirror (Flip) Reference Point
# ## Mirror (Flip) Reference Point
self.mirror_reference_cb = FCCheckBox(_("Mirror Reference"))
self.mirror_reference_cb.setToolTip(
_("Flip the selected object(s)\n"
@ -6344,7 +6513,7 @@ class ToolsSolderpastePrefGroupUI(OptionsGroupUI):
self.setTitle(str(_("SolderPaste Tool Options")))
## Solder Paste Dispensing
# ## Solder Paste Dispensing
self.solderpastelabel = QtWidgets.QLabel(_("<b>Parameters:</b>"))
self.solderpastelabel.setToolTip(
_("A tool to create GCode for dispensing\n"

View File

@ -1,15 +1,15 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
############################################################
# ########################################################## ##
# File Modified (major mod): Marius Adrian Stanciu #
# Date: 3/10/2019 #
############################################################
# ########################################################## ##
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
@ -159,6 +159,10 @@ class LengthEntry(QtWidgets.QLineEdit):
'MM': 1.0}
}
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, Parent=None):
super(LengthEntry, self).mousePressEvent(e) # required to deselect on 2e click
@ -209,6 +213,10 @@ class FloatEntry(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super(FloatEntry, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, Parent=None):
super(FloatEntry, self).mousePressEvent(e) # required to deselect on 2e click
@ -256,6 +264,10 @@ class FloatEntry2(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super(FloatEntry2, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, Parent=None):
super(FloatEntry2, self).mousePressEvent(e) # required to deselect on 2e click
@ -295,6 +307,10 @@ class IntEntry(QtWidgets.QLineEdit):
self.allow_empty = allow_empty
self.empty_val = empty_val
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, Parent=None):
super(IntEntry, self).mousePressEvent(e) # required to deselect on 2e click
@ -335,6 +351,10 @@ class FCEntry(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super(FCEntry, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, Parent=None):
super(FCEntry, self).mousePressEvent(e) # required to deselect on 2e click
@ -365,6 +385,10 @@ class FCEntry2(FCEntry):
def __init__(self, parent=None):
super(FCEntry2, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def set_value(self, val):
try:
@ -378,6 +402,10 @@ class EvalEntry(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super(EvalEntry, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, Parent=None):
super(EvalEntry, self).mousePressEvent(e) # required to deselect on 2e click
@ -420,6 +448,10 @@ class EvalEntry2(QtWidgets.QLineEdit):
def __init__(self, parent=None):
super(EvalEntry2, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, Parent=None):
super(EvalEntry2, self).mousePressEvent(e) # required to deselect on 2e click
@ -1462,6 +1494,10 @@ class FCSpinner(QtWidgets.QSpinBox):
def __init__(self, parent=None):
super(FCSpinner, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, parent=None):
super(FCSpinner, self).mousePressEvent(e) # required to deselect on 2e click
@ -1497,6 +1533,10 @@ class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
def __init__(self, parent=None):
super(FCDoubleSpinner, self).__init__(parent)
self.readyToEdit = True
self.editingFinished.connect(self.on_edit_finished)
def on_edit_finished(self):
self.clearFocus()
def mousePressEvent(self, e, parent=None):
super(FCDoubleSpinner, self).mousePressEvent(e) # required to deselect on 2e click

View File

@ -1,15 +1,15 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
############################################################
# ########################################################## ##
# File Modified (major mod): Marius Adrian Stanciu #
# Date: 3/10/2019 #
############################################################
# ########################################################## ##
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt
@ -36,22 +36,22 @@ class ObjectUI(QtWidgets.QWidget):
layout = QtWidgets.QVBoxLayout()
self.setLayout(layout)
## Page Title box (spacing between children)
# ## Page Title box (spacing between children)
self.title_box = QtWidgets.QHBoxLayout()
layout.addLayout(self.title_box)
## Page Title icon
# ## Page Title icon
pixmap = QtGui.QPixmap(icon_file)
self.icon = QtWidgets.QLabel()
self.icon.setPixmap(pixmap)
self.title_box.addWidget(self.icon, stretch=0)
## Title label
# ## Title label
self.title_label = QtWidgets.QLabel("<font size=5><b>%s</b></font>" % title)
self.title_label.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
self.title_box.addWidget(self.title_label, stretch=1)
## App Level label
# ## App Level label
self.level = QtWidgets.QLabel("")
self.level.setToolTip(
_(
@ -66,13 +66,13 @@ class ObjectUI(QtWidgets.QWidget):
self.level.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
self.title_box.addWidget(self.level)
## Box box for custom widgets
# ## Box box for custom widgets
# This gets populated in offspring implementations.
self.custom_box = QtWidgets.QVBoxLayout()
layout.addLayout(self.custom_box)
######################### ##
## Common to all objects ##
# ## Common to all objects # ##
######################### ##
#### Scale ## ##
@ -176,7 +176,7 @@ class GerberObjectUI(ObjectUI):
self.plot_cb.setFixedWidth(59)
grid0.addWidget(self.plot_cb, 0, 3)
## Object name
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
@ -380,7 +380,7 @@ class GerberObjectUI(ObjectUI):
grid2 = QtWidgets.QGridLayout()
self.custom_box.addLayout(grid2)
## Clear non-copper regions
# ## Clear non-copper regions
self.clearcopper_label = QtWidgets.QLabel(_("<b>Clear N-copper:</b>"))
self.clearcopper_label.setToolTip(
_("Create a Geometry object with\n"
@ -396,7 +396,7 @@ class GerberObjectUI(ObjectUI):
)
grid2.addWidget(self.generate_ncc_button, 0, 1)
## Board cutout
# ## Board cutout
self.board_cutout_label = QtWidgets.QLabel(_("<b>Board cutout:</b>"))
self.board_cutout_label.setToolTip(
_("Create toolpaths to cut around\n"
@ -412,7 +412,7 @@ class GerberObjectUI(ObjectUI):
)
grid2.addWidget(self.generate_cutout_button, 1, 1)
## Non-copper regions
# ## Non-copper regions
self.noncopper_label = QtWidgets.QLabel(_("<b>Non-copper regions:</b>"))
self.noncopper_label.setToolTip(
_("Create polygons covering the\n"
@ -450,7 +450,7 @@ class GerberObjectUI(ObjectUI):
self.generate_noncopper_button = QtWidgets.QPushButton(_('Generate Geo'))
grid4.addWidget(self.generate_noncopper_button, 1, 1)
## Bounding box
# ## Bounding box
self.boundingbox_label = QtWidgets.QLabel(_('<b>Bounding Box:</b>'))
self.boundingbox_label.setToolTip(
_("Create a geometry surrounding the Gerber object.\n"
@ -511,7 +511,7 @@ class ExcellonObjectUI(ObjectUI):
hlay_plot.addStretch()
hlay_plot.addWidget(self.solid_cb)
## Object name
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
@ -833,7 +833,7 @@ class GeometryObjectUI(ObjectUI):
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
self.custom_box.addWidget(self.plot_options_label)
## Object name
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
@ -1346,7 +1346,7 @@ class CNCObjectUI(ObjectUI):
self.offset_label.hide()
self.offset_button.hide()
## Plot options
# ## Plot options
self.plot_options_label = QtWidgets.QLabel(_("<b>Plot Options:</b>"))
self.custom_box.addWidget(self.plot_options_label)
@ -1366,7 +1366,17 @@ class CNCObjectUI(ObjectUI):
{"label": "Cut", "value": "cut"}
], stretch=False)
## Object name
self.annotation_label = QtWidgets.QLabel(_("<b>Display Annotation:</b>"))
self.annotation_label.setToolTip(
_(
"This selects if to display text annotation on the plot.\n"
"When checked it will display numbers in order for each end\n"
"of a travel line."
)
)
self.annotation_cb = FCCheckBox()
# ## Object name
self.name_hlay = QtWidgets.QHBoxLayout()
self.custom_box.addLayout(self.name_hlay)
name_label = QtWidgets.QLabel(_("<b>Name:</b>"))
@ -1399,9 +1409,12 @@ class CNCObjectUI(ObjectUI):
f_lay.addWidget(self.cncplot_method_label, 0, 0)
f_lay.addWidget(self.cncplot_method_combo, 0, 1)
f_lay.addWidget(QtWidgets.QLabel(''), 0, 2)
f_lay.addWidget(self.t_distance_label, 1, 0)
f_lay.addWidget(self.t_distance_entry, 1, 1)
f_lay.addWidget(self.units_label, 1, 2)
f_lay.addWidget(self.annotation_label, 1, 0)
f_lay.addWidget(self.annotation_cb, 1, 1)
f_lay.addWidget(QtWidgets.QLabel(''), 1, 2)
f_lay.addWidget(self.t_distance_label, 2, 0)
f_lay.addWidget(self.t_distance_entry, 2, 1)
f_lay.addWidget(self.units_label, 2, 2)
self.t_distance_label.hide()
self.t_distance_entry.setVisible(False)
@ -1463,7 +1476,7 @@ class CNCObjectUI(ObjectUI):
self.custom_box.addWidget(self.updateplot_button)
################ ##
## Export G-Code
# ## Export G-Code
################ ##
self.export_gcode_label = QtWidgets.QLabel(_("<b>Export CNC Code:</b>"))
self.export_gcode_label.setToolTip(

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://caram.cl/software/flatcam #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
from PyQt5 import QtCore
@ -74,7 +74,7 @@ class PlotCanvas(QtCore.QObject):
self.text_collection = self.new_text_collection()
# TODO: Should be setting to show/hide CNC job annotations (global or per object)
self.text_collection.enabled = False
self.text_collection.enabled = True
# draw a rectangle made out of 4 lines on the canvas to serve as a hint for the work area
# all CNC have a limited workspace

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Dennis Hayrullin #
# Date: 2/5/2016 #
# MIT Licence #
############################################################
# ########################################################## ##
import numpy as np
from PyQt5.QtGui import QPalette

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Dennis Hayrullin #
# Date: 2/5/2016 #
# MIT Licence #
############################################################
# ########################################################## ##
from vispy.visuals import markers, LineVisual, InfiniteLineVisual
from vispy.visuals.axis import Ticker, _get_ticks_talbot

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Dennis Hayrullin #
# Date: 2/5/2016 #
# MIT Licence #
############################################################
# ########################################################## ##
from OpenGL import GLU

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Dennis Hayrullin #
# Date: 2/5/2016 #
# MIT Licence #
############################################################
# ########################################################## ##
from vispy.visuals import CompoundVisual, LineVisual, MeshVisual, TextVisual, MarkersVisual
from vispy.scene.visuals import VisualNode, generate_docstring, visuals
@ -456,20 +456,26 @@ class TextCollectionVisual(TextVisual):
self.data = {}
self.last_key = -1
self.lock = threading.Lock()
self.method = 'gpu'
super(TextCollectionVisual, self).__init__(**kwargs)
self.freeze()
def add(self, text, pos, visible=True, update=True):
def add(self, text, pos, visible=True, update=True, font_size=9, color='black'):
"""
Adds array of text to collection
:param text: list
Array of strings ['str1', 'str2', ... ]
:param pos: list
Array of string positions [(0, 0), (10, 10), ... ]
:param visible: bool
| Set True to make it visible
:param update: bool
Set True to redraw collection
:param font_size: int
Set font size to redraw collection
:param color: string
Set font color to redraw collection
:return: int
Index of array
"""
@ -480,7 +486,7 @@ class TextCollectionVisual(TextVisual):
self.lock.release()
# Prepare data for translation
self.data[key] = {'text': text, 'pos': pos, 'visible': visible}
self.data[key] = {'text': text, 'pos': pos, 'visible': visible,'font_size': font_size, 'color': color}
if update:
self.redraw()
@ -516,6 +522,8 @@ class TextCollectionVisual(TextVisual):
"""
labels = []
pos = []
font_s = 9
color = 'black'
# Merge buffers
for data in list(self.data.values()):
@ -523,6 +531,8 @@ class TextCollectionVisual(TextVisual):
try:
labels += data['text']
pos += data['pos']
font_s = data['font_size']
color = data['color']
except Exception as e:
print("Data error", e)
@ -530,6 +540,8 @@ class TextCollectionVisual(TextVisual):
if len(labels) > 0:
self.text = labels
self.pos = pos
self.font_size = font_s
self.color = color
else:
self.text = None
self.pos = (0, 0)

View File

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

View File

@ -2,12 +2,12 @@
# Vasilis Vlachoudis
# Date: 20-Oct-2015
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File modified: Marius Adrian Stanciu #
# Date: 3/10/2019 #
############################################################
# ########################################################## ##
import math
import sys

View File

@ -1,15 +1,15 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
#########################################################################
# ####################################################################### ##
# ## Borrowed code from 'https://github.com/gddc/ttfquery/blob/master/ # ##
# ## and made it work with Python 3 ########### ##
#########################################################################
# ####################################################################### ##
import re, os, sys, glob
import itertools

View File

@ -1,4 +1,4 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
@ -17,7 +17,7 @@
# * All transformations #
# #
# Reference: www.w3.org/TR/SVG/Overview.html #
############################################################
# ########################################################## ##
# import xml.etree.ElementTree as ET
from svg.path import Line, Arc, CubicBezier, QuadraticBezier, parse_path

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
from FlatCAMObj import *
@ -31,7 +31,7 @@ class ToolCalculator(FlatCAMTool):
self.app = app
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
@ -43,13 +43,13 @@ class ToolCalculator(FlatCAMTool):
self.layout.addWidget(title_label)
#################### ##
## Units Calculator ##
# ## Units Calculator # ##
#################### ##
self.unists_spacer_label = QtWidgets.QLabel(" ")
self.layout.addWidget(self.unists_spacer_label)
## Title of the Units Calculator
# ## Title of the Units Calculator
units_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.unitsName)
self.layout.addWidget(units_label)
@ -77,17 +77,17 @@ class ToolCalculator(FlatCAMTool):
########################## ##
## V-shape Tool Calculator ##
# ## V-shape Tool Calculator # ##
########################## ##
self.v_shape_spacer_label = QtWidgets.QLabel(" ")
self.layout.addWidget(self.v_shape_spacer_label)
## Title of the V-shape Tools Calculator
# ## Title of the V-shape Tools Calculator
v_shape_title_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.v_shapeName)
self.layout.addWidget(v_shape_title_label)
## Form Layout
# ## Form Layout
form_layout = QtWidgets.QFormLayout()
self.layout.addLayout(form_layout)
@ -127,7 +127,7 @@ class ToolCalculator(FlatCAMTool):
form_layout.addRow(self.cutDepth_label, self.cutDepth_entry)
form_layout.addRow(self.effectiveToolDia_label, self.effectiveToolDia_entry)
## Buttons
# ## Buttons
self.calculate_vshape_button = QtWidgets.QPushButton(_("Calculate"))
# self.calculate_button.setFixedWidth(70)
self.calculate_vshape_button.setToolTip(
@ -140,13 +140,13 @@ class ToolCalculator(FlatCAMTool):
################################## ##
## ElectroPlating Tool Calculator ##
# ## ElectroPlating Tool Calculator # ##
################################## ##
self.plate_spacer_label = QtWidgets.QLabel(" ")
self.layout.addWidget(self.plate_spacer_label)
## Title of the ElectroPlating Tools Calculator
# ## Title of the ElectroPlating Tools Calculator
plate_title_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.eplateName)
plate_title_label.setToolTip(
_("This calculator is useful for those who plate the via/pad/drill holes,\n"
@ -154,7 +154,7 @@ class ToolCalculator(FlatCAMTool):
)
self.layout.addWidget(plate_title_label)
## Plate Form Layout
# ## Plate Form Layout
plate_form_layout = QtWidgets.QFormLayout()
self.layout.addLayout(plate_form_layout)
@ -210,7 +210,7 @@ class ToolCalculator(FlatCAMTool):
plate_form_layout.addRow(self.cvaluelabel, self.cvalue_entry)
plate_form_layout.addRow(self.timelabel, self.time_entry)
## Buttons
# ## Buttons
self.calculate_plate_button = QtWidgets.QPushButton(_("Calculate"))
# self.calculate_button.setFixedWidth(70)
self.calculate_plate_button.setToolTip(
@ -223,7 +223,7 @@ class ToolCalculator(FlatCAMTool):
self.layout.addStretch()
## Signals
# ## Signals
self.cutDepth_entry.textChanged.connect(self.on_calculate_tool_dia)
self.cutDepth_entry.editingFinished.connect(self.on_calculate_tool_dia)
self.tipDia_entry.editingFinished.connect(self.on_calculate_tool_dia)
@ -264,7 +264,7 @@ class ToolCalculator(FlatCAMTool):
def set_tool_ui(self):
self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().upper()
## Initialize form
# ## Initialize form
self.mm_entry.set_value('0')
self.inch_entry.set_value('0')

View File

@ -415,7 +415,7 @@ class CutOut(FlatCAMTool):
object_geo = cutout_obj.solid_geometry
try:
_ = iter(object_geo)
__ = iter(object_geo)
except TypeError:
object_geo = [object_geo]
@ -424,7 +424,8 @@ class CutOut(FlatCAMTool):
geo = (geo.buffer(margin + abs(dia / 2))).exterior
# Get min and max data for each object as we just cut rectangles across X or Y
xmin, ymin, xmax, ymax = geo.bounds
xmin, ymin, xmax, ymax = recursive_bounds(geo)
px = 0.5 * (xmin + xmax) + margin
py = 0.5 * (ymin + ymax) + margin
lenx = (xmax - xmin) + (margin * 2)
@ -475,6 +476,11 @@ class CutOut(FlatCAMTool):
solid_geo.append(geo)
geo_obj.solid_geometry = deepcopy(solid_geo)
xmin, ymin, xmax, ymax = recursive_bounds(geo_obj.solid_geometry)
geo_obj.options['xmin'] = xmin
geo_obj.options['ymin'] = ymin
geo_obj.options['xmax'] = xmax
geo_obj.options['ymax'] = ymax
outname = cutout_obj.options["name"] + "_cutout"
self.app.new_object('geometry', outname, geo_init)
@ -565,7 +571,7 @@ class CutOut(FlatCAMTool):
object_geo = cutout_obj.solid_geometry
try:
_ = iter(object_geo)
__ = iter(object_geo)
except TypeError:
object_geo = [object_geo]

View File

@ -20,7 +20,7 @@ class DblSidedTool(FlatCAMTool):
def __init__(self, app):
FlatCAMTool.__init__(self, app)
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
@ -34,11 +34,11 @@ class DblSidedTool(FlatCAMTool):
self.empty_lb = QtWidgets.QLabel("")
self.layout.addWidget(self.empty_lb)
## Grid Layout
# ## Grid Layout
grid_lay = QtWidgets.QGridLayout()
self.layout.addLayout(grid_lay)
## Gerber Object to mirror
# ## Gerber Object to mirror
self.gerber_object_combo = QtWidgets.QComboBox()
self.gerber_object_combo.setModel(self.app.collection)
self.gerber_object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
@ -62,7 +62,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay.addWidget(self.gerber_object_combo, 1, 0)
grid_lay.addWidget(self.mirror_gerber_button, 1, 1)
## Excellon Object to mirror
# ## Excellon Object to mirror
self.exc_object_combo = QtWidgets.QComboBox()
self.exc_object_combo.setModel(self.app.collection)
self.exc_object_combo.setRootModelIndex(self.app.collection.index(1, 0, QtCore.QModelIndex()))
@ -86,7 +86,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay.addWidget(self.exc_object_combo, 3, 0)
grid_lay.addWidget(self.mirror_exc_button, 3, 1)
## Geometry Object to mirror
# ## Geometry Object to mirror
self.geo_object_combo = QtWidgets.QComboBox()
self.geo_object_combo.setModel(self.app.collection)
self.geo_object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
@ -110,11 +110,11 @@ class DblSidedTool(FlatCAMTool):
grid_lay.addWidget(self.geo_object_combo, 5, 0)
grid_lay.addWidget(self.mirror_geo_button, 5, 1)
## Grid Layout
# ## Grid Layout
grid_lay1 = QtWidgets.QGridLayout()
self.layout.addLayout(grid_lay1)
## Axis
# ## Axis
self.mirror_axis = RadioSet([{'label': 'X', 'value': 'X'},
{'label': 'Y', 'value': 'Y'}])
self.mirax_label = QtWidgets.QLabel(_("Mirror Axis:"))
@ -127,7 +127,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay1.addWidget(self.mirax_label, 7, 0)
grid_lay1.addWidget(self.mirror_axis, 7, 1)
## Axis Location
# ## Axis Location
self.axis_location = RadioSet([{'label': 'Point', 'value': 'point'},
{'label': 'Box', 'value': 'box'}])
self.axloc_label = QtWidgets.QLabel(_("Axis Ref:"))
@ -143,11 +143,11 @@ class DblSidedTool(FlatCAMTool):
self.empty_lb2 = QtWidgets.QLabel("")
grid_lay1.addWidget(self.empty_lb2, 9, 0)
## Grid Layout
# ## Grid Layout
grid_lay2 = QtWidgets.QGridLayout()
self.layout.addLayout(grid_lay2)
## Point/Box
# ## Point/Box
self.point_box_container = QtWidgets.QVBoxLayout()
self.pb_label = QtWidgets.QLabel("<b>%s</b>" % _('Point/Box Reference:'))
self.pb_label.setToolTip(
@ -189,7 +189,7 @@ class DblSidedTool(FlatCAMTool):
self.box_combo_type.hide()
## Alignment holes
# ## Alignment holes
self.ah_label = QtWidgets.QLabel("<b>%s</b>" % _('Alignment Drill Coordinates:'))
self.ah_label.setToolTip(
_( "Alignment holes (x1, y1), (x2, y2), ... "
@ -220,7 +220,7 @@ class DblSidedTool(FlatCAMTool):
grid_lay3.addWidget(self.alignment_holes, 0, 0)
grid_lay3.addWidget(self.add_drill_point_button, 0, 1)
## Drill diameter for alignment holes
# ## Drill diameter for alignment holes
self.dt_label = QtWidgets.QLabel("<b>%s</b>:" % _('Alignment Drill Diameter'))
self.dt_label.setToolTip(
_("Diameter of the drill for the "
@ -243,7 +243,7 @@ class DblSidedTool(FlatCAMTool):
hlay2 = QtWidgets.QHBoxLayout()
self.layout.addLayout(hlay2)
## Buttons
# ## Buttons
self.create_alignment_hole_button = QtWidgets.QPushButton(_("Create Excellon Object"))
self.create_alignment_hole_button.setToolTip(
_("Creates an Excellon Object containing the\n"
@ -261,7 +261,7 @@ class DblSidedTool(FlatCAMTool):
self.layout.addStretch()
## Signals
# ## Signals
self.create_alignment_hole_button.clicked.connect(self.on_create_alignment_holes)
self.mirror_gerber_button.clicked.connect(self.on_mirror_gerber)
self.mirror_exc_button.clicked.connect(self.on_mirror_exc)

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
@ -165,7 +165,7 @@ class Film(FlatCAMTool):
self.layout.addStretch()
## Signals
# ## Signals
self.film_object_button.clicked.connect(self.on_film_creation)
self.tf_type_obj_combo.currentIndexChanged.connect(self.on_type_obj_index_changed)
self.tf_type_box_combo.currentIndexChanged.connect(self.on_type_box_index_changed)

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
@ -144,7 +144,7 @@ class ToolImage(FlatCAMTool):
self.layout.addStretch()
## Signals
# ## Signals
self.import_button.clicked.connect(self.on_file_importimage)
def run(self, toggle=True):
@ -173,7 +173,7 @@ class ToolImage(FlatCAMTool):
FlatCAMTool.install(self, icon, separator, **kwargs)
def set_tool_ui(self):
## Initialize form
# ## Initialize form
self.dpi_entry.set_value(96)
self.image_type.set_value('black')
self.mask_bw_entry.set_value(250)

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
from FlatCAMObj import *
@ -32,11 +32,11 @@ class Measurement(FlatCAMTool):
self.canvas = self.app.plotcanvas
self.units = self.app.ui.general_defaults_form.general_app_group.units_radio.get_value().lower()
## Title
# ## Title
title_label = QtWidgets.QLabel("<font size=4><b>%s</b></font><br>" % self.toolName)
self.layout.addWidget(title_label)
## Form Layout
# ## Form Layout
form_layout = QtWidgets.QFormLayout()
self.layout.addLayout(form_layout)

View File

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

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Modified by: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
from copy import copy,deepcopy
@ -38,7 +38,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
self.tools_box.setContentsMargins(0, 0, 0, 0)
self.tools_frame.setLayout(self.tools_box)
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
@ -49,11 +49,11 @@ class NonCopperClear(FlatCAMTool, Gerber):
""")
self.tools_box.addWidget(title_label)
## Form Layout
# ## Form Layout
form_layout = QtWidgets.QFormLayout()
self.tools_box.addLayout(form_layout)
## Object
# ## Object
self.object_combo = QtWidgets.QComboBox()
self.object_combo.setModel(self.app.collection)
self.object_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))

View File

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

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Modified: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
from copy import copy,deepcopy
@ -29,7 +29,7 @@ class ToolPaint(FlatCAMTool, Gerber):
FlatCAMTool.__init__(self, app)
Geometry.__init__(self, geo_steps_per_circle=self.app.defaults["geometry_circle_steps"])
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
@ -47,11 +47,11 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_box.setContentsMargins(0, 0, 0, 0)
self.tools_frame.setLayout(self.tools_box)
## Form Layout
# ## Form Layout
form_layout = QtWidgets.QFormLayout()
self.tools_box.addLayout(form_layout)
## Object
# ## Object
self.object_combo = QtWidgets.QComboBox()
self.object_combo.setModel(self.app.collection)
self.object_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
@ -305,7 +305,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tool_type_item_options = ["C1", "C2", "C3", "C4", "B", "V"]
## Signals
# ## Signals
self.addtool_btn.clicked.connect(self.on_tool_add)
self.addtool_entry.returnPressed.connect(self.on_tool_add)
# self.copytool_btn.clicked.connect(lambda: self.on_tool_copy())
@ -365,7 +365,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.tools_frame.show()
self.reset_fields()
## Init the GUI interface
# ## Init the GUI interface
self.paintmargin_entry.set_value(self.default_data["paintmargin"])
self.paintmethod_combo.set_value(self.default_data["paintmethod"])
self.selectmethod_combo.set_value(self.default_data["selectmethod"])
@ -1035,13 +1035,13 @@ class ToolPaint(FlatCAMTool, Gerber):
if reset:
self.flat_geometry = []
## If iterable, expand recursively.
# ## If iterable, expand recursively.
try:
for geo in geometry:
if geo is not None:
recurse(geometry=geo, reset=False)
## Not iterable, do the actual indexing and add.
# ## Not iterable, do the actual indexing and add.
except TypeError:
self.flat_geometry.append(geometry)

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
from copy import copy, deepcopy
@ -28,7 +28,7 @@ class Panelize(FlatCAMTool):
super(Panelize, self).__init__(self)
self.app = app
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 4/15/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
@ -152,7 +152,7 @@ class PcbWizard(FlatCAMTool):
self.modified_excellon_file = ''
## Signals
# ## Signals
self.excellon_brn.clicked.connect(self.on_load_excellon_click)
self.inf_btn.clicked.connect(self.on_load_inf_click)
self.import_button.clicked.connect(lambda: self.on_import_excellon(
@ -207,7 +207,7 @@ class PcbWizard(FlatCAMTool):
self.exc_file_content = None
self.tools_from_inf = {}
## Initialize form
# ## Initialize form
self.int_entry.set_value(self.integral)
self.frac_entry.set_value(self.fractional)
self.zeros_radio.set_value(self.zeros)

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt
@ -37,7 +37,7 @@ class Properties(FlatCAMTool):
self.properties_box.setContentsMargins(0, 0, 0, 0)
self.properties_frame.setLayout(self.properties_box)
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
# Date: 2/5/2014 #
# MIT Licence #
############################################################
# ########################################################## ##
# from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import Qt

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
from FlatCAMCommon import LoudDict
@ -39,7 +39,7 @@ class SolderPaste(FlatCAMTool):
def __init__(self, app):
FlatCAMTool.__init__(self, app)
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
@ -50,11 +50,11 @@ class SolderPaste(FlatCAMTool):
""")
self.layout.addWidget(title_label)
## Form Layout
# ## Form Layout
obj_form_layout = QtWidgets.QFormLayout()
self.layout.addLayout(obj_form_layout)
## Gerber Object to be used for solderpaste dispensing
# ## Gerber Object to be used for solderpaste dispensing
self.obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.obj_combo.setModel(self.app.collection)
self.obj_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
@ -135,7 +135,7 @@ class SolderPaste(FlatCAMTool):
self.layout.addSpacing(10)
## Buttons
# ## Buttons
grid0_1 = QtWidgets.QGridLayout()
self.layout.addLayout(grid0_1)
@ -157,7 +157,7 @@ class SolderPaste(FlatCAMTool):
self.gcode_box.setContentsMargins(0, 0, 0, 0)
self.gcode_frame.setLayout(self.gcode_box)
## Form Layout
# ## Form Layout
self.gcode_form_layout = QtWidgets.QFormLayout()
self.gcode_box.addLayout(self.gcode_form_layout)
@ -283,7 +283,7 @@ class SolderPaste(FlatCAMTool):
self.pp_combo.setStyleSheet('background-color: rgb(255,255,255)')
self.gcode_form_layout.addRow(pp_label, self.pp_combo)
## Buttons
# ## Buttons
grid1 = QtWidgets.QGridLayout()
self.gcode_box.addLayout(grid1)
@ -301,7 +301,7 @@ class SolderPaste(FlatCAMTool):
self.generation_frame.setLayout(self.generation_box)
## Buttons
# ## Buttons
grid2 = QtWidgets.QGridLayout()
self.generation_box.addLayout(grid2)
@ -313,11 +313,11 @@ class SolderPaste(FlatCAMTool):
grid2.addWidget(step2_lbl, 0, 0)
grid2.addWidget(self.soldergeo_btn, 0, 2)
## Form Layout
# ## Form Layout
geo_form_layout = QtWidgets.QFormLayout()
self.generation_box.addLayout(geo_form_layout)
## Geometry Object to be used for solderpaste dispensing
# ## Geometry Object to be used for solderpaste dispensing
self.geo_obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.geo_obj_combo.setModel(self.app.collection)
self.geo_obj_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
@ -346,11 +346,11 @@ class SolderPaste(FlatCAMTool):
grid3.addWidget(step3_lbl, 0, 0)
grid3.addWidget(self.solder_gcode_btn, 0, 2)
## Form Layout
# ## Form Layout
cnc_form_layout = QtWidgets.QFormLayout()
self.generation_box.addLayout(cnc_form_layout)
## Gerber Object to be used for solderpaste dispensing
# ## Gerber Object to be used for solderpaste dispensing
self.cnc_obj_combo = FCComboBox(callback=self.on_rmb_combo)
self.cnc_obj_combo.setModel(self.app.collection)
self.cnc_obj_combo.setRootModelIndex(self.app.collection.index(3, 0, QtCore.QModelIndex()))
@ -412,7 +412,7 @@ class SolderPaste(FlatCAMTool):
# action to be added in the combobox context menu
self.combo_context_del_action = QtWidgets.QAction(QtGui.QIcon('share/trash16.png'), _("Delete Object"))
## Signals
# ## Signals
self.combo_context_del_action.triggered.connect(self.on_delete_object)
self.addtool_btn.clicked.connect(self.on_tool_add)
self.addtool_entry.returnPressed.connect(self.on_tool_add)
@ -995,7 +995,7 @@ class SolderPaste(FlatCAMTool):
if reset:
self.flat_geometry = []
## If iterable, expand recursively.
# ## If iterable, expand recursively.
try:
for geo in geometry:
if geo is not None:
@ -1003,7 +1003,7 @@ class SolderPaste(FlatCAMTool):
reset=False,
pathonly=pathonly)
## Not iterable, do the actual indexing and add.
# ## Not iterable, do the actual indexing and add.
except TypeError:
if pathonly and type(geometry) == Polygon:
self.flat_geometry.append(geometry.exterior)
@ -1380,7 +1380,7 @@ class SolderPaste(FlatCAMTool):
gcode += obj.cnc_tools[tool]['gcode']
lines = StringIO(gcode)
## Write
# ## Write
if filename is not None:
try:
with open(filename, 'w') as f:

View File

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

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Marius Adrian Stanciu (c) #
# Date: 3/10/2019 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMTool import FlatCAMTool
from FlatCAMObj import *
@ -32,7 +32,7 @@ class ToolTransform(FlatCAMTool):
self.transform_lay = QtWidgets.QVBoxLayout()
self.layout.addLayout(self.transform_lay)
## Title
# ## Title
title_label = QtWidgets.QLabel("%s" % self.toolName)
title_label.setStyleSheet("""
QLabel
@ -56,11 +56,11 @@ class ToolTransform(FlatCAMTool):
self.empty_label4.setFixedWidth(70)
self.transform_lay.addWidget(self.empty_label)
## Rotate Title
# ## Rotate Title
rotate_title_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.rotateName)
self.transform_lay.addWidget(rotate_title_label)
## Layout
# ## Layout
form_layout = QtWidgets.QFormLayout()
self.transform_lay.addLayout(form_layout)
form_child = QtWidgets.QHBoxLayout()
@ -94,11 +94,11 @@ class ToolTransform(FlatCAMTool):
self.transform_lay.addWidget(self.empty_label1)
## Skew Title
# ## Skew Title
skew_title_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.skewName)
self.transform_lay.addWidget(skew_title_label)
## Form Layout
# ## Form Layout
form1_layout = QtWidgets.QFormLayout()
self.transform_lay.addLayout(form1_layout)
form1_child_1 = QtWidgets.QHBoxLayout()
@ -151,11 +151,11 @@ class ToolTransform(FlatCAMTool):
self.transform_lay.addWidget(self.empty_label2)
## Scale Title
# ## Scale Title
scale_title_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.scaleName)
self.transform_lay.addWidget(scale_title_label)
## Form Layout
# ## Form Layout
form2_layout = QtWidgets.QFormLayout()
self.transform_lay.addLayout(form2_layout)
form2_child_1 = QtWidgets.QHBoxLayout()
@ -225,11 +225,11 @@ class ToolTransform(FlatCAMTool):
self.transform_lay.addWidget(self.empty_label3)
## Offset Title
# ## Offset Title
offset_title_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.offsetName)
self.transform_lay.addWidget(offset_title_label)
## Form Layout
# ## Form Layout
form3_layout = QtWidgets.QFormLayout()
self.transform_lay.addLayout(form3_layout)
form3_child_1 = QtWidgets.QHBoxLayout()
@ -280,11 +280,11 @@ class ToolTransform(FlatCAMTool):
self.transform_lay.addWidget(self.empty_label4)
## Flip Title
# ## Flip Title
flip_title_label = QtWidgets.QLabel("<font size=3><b>%s</b></font>" % self.flipName)
self.transform_lay.addWidget(flip_title_label)
## Form Layout
# ## Form Layout
form4_layout = QtWidgets.QFormLayout()
form4_child_hlay = QtWidgets.QHBoxLayout()
self.transform_lay.addLayout(form4_child_hlay)
@ -355,7 +355,7 @@ class ToolTransform(FlatCAMTool):
self.transform_lay.addStretch()
## Signals
# ## Signals
self.rotate_button.clicked.connect(self.on_rotate)
self.skewx_button.clicked.connect(self.on_skewx)
self.skewy_button.clicked.connect(self.on_skewy)
@ -401,7 +401,7 @@ class ToolTransform(FlatCAMTool):
FlatCAMTool.install(self, icon, separator, shortcut='ALT+R', **kwargs)
def set_tool_ui(self):
## Initialize form
# ## Initialize form
if self.app.defaults["tools_transform_rotate"]:
self.rotate_entry.set_value(self.app.defaults["tools_transform_rotate"])
else:

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

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# Author: Juan Pablo Caram (c) #
@ -11,12 +11,12 @@
# This is not an aid to install FlatCAM from source on #
# Windows platforms. It is only useful when FlatCAM is up #
# and running and ready to be packaged. #
############################################################
# ########################################################## ##
############################################################
# ########################################################## ##
# File Modified (major mod): Marius Adrian Stanciu #
# Date: 3/10/2019 #
############################################################
# ########################################################## ##
# Files not needed: Qt, tk.dll, tcl.dll, tk/, tcl/, vtk/,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMPostProc import *

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMPostProc import *

View File

@ -1,10 +1,10 @@
############################################################
# ########################################################## ##
# FlatCAM: 2D Post-processing for Manufacturing #
# http://flatcam.org #
# File Author: Matthieu Berthomé #
# Date: 5/26/2017 #
# MIT Licence #
############################################################
# ########################################################## ##
from FlatCAMPostProc import *

View File

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

View File

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

View File

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

BIN
share/disable16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

BIN
share/disable32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 715 B

BIN
share/notebook16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

View File

@ -120,7 +120,7 @@ class TclCommandCutout(TclCommand):
geo_obj.solid_geometry = cascaded_union([LineString(segment) for segment in cuts])
try:
obj.app.new_object("geometry", name + "_cutout", geo_init_me)
self.app.new_object("geometry", name + "_cutout", geo_init_me)
self.app.inform.emit("[success] Rectangular-form Cutout operation finished.")
except Exception as e:
return "Operation failed: %s" % str(e)

View File

@ -165,6 +165,11 @@ class TclCommandGeoCutout(TclCommandSignaled):
# Get min and max data for each object as we just cut rectangles across X or Y
xmin, ymin, xmax, ymax = cutout_obj.bounds()
cutout_obj.options['xmin'] = xmin
cutout_obj.options['ymin'] = ymin
cutout_obj.options['xmax'] = xmax
cutout_obj.options['ymax'] = ymax
px = 0.5 * (xmin + xmax) + margin
py = 0.5 * (ymin + ymax) + margin
lenghtx = (xmax - xmin) + (margin * 2)
@ -179,48 +184,102 @@ class TclCommandGeoCutout(TclCommandSignaled):
if isinstance(cutout_obj, FlatCAMGeometry):
# rename the obj name so it can be identified as cutout
cutout_obj.options["name"] += "_cutout"
# cutout_obj.options["name"] += "_cutout"
# if gaps_u == 8 or gaps_u == '2lr':
# subtract_rectangle(cutout_obj,
# xmin - gapsize, # botleft_x
# py - gapsize + lenghty / 4, # botleft_y
# xmax + gapsize, # topright_x
# py + gapsize + lenghty / 4) # topright_y
# subtract_rectangle(cutout_obj,
# xmin - gapsize,
# py - gapsize - lenghty / 4,
# xmax + gapsize,
# py + gapsize - lenghty / 4)
#
# if gaps_u == 8 or gaps_u == '2tb':
# subtract_rectangle(cutout_obj,
# px - gapsize + lenghtx / 4,
# ymin - gapsize,
# px + gapsize + lenghtx / 4,
# ymax + gapsize)
# subtract_rectangle(cutout_obj,
# px - gapsize - lenghtx / 4,
# ymin - gapsize,
# px + gapsize - lenghtx / 4,
# ymax + gapsize)
#
# if gaps_u == 4 or gaps_u == 'lr':
# subtract_rectangle(cutout_obj,
# xmin - gapsize,
# py - gapsize,
# xmax + gapsize,
# py + gapsize)
#
# if gaps_u == 4 or gaps_u == 'tb':
# subtract_rectangle(cutout_obj,
# px - gapsize,
# ymin - gapsize,
# px + gapsize,
# ymax + gapsize)
def geo_init(geo_obj, app_obj):
geo = deepcopy(cutout_obj.solid_geometry)
if gaps_u == 8 or gaps_u == '2lr':
subtract_rectangle(cutout_obj,
geo = substract_rectangle_geo(geo,
xmin - gapsize, # botleft_x
py - gapsize + lenghty / 4, # botleft_y
xmax + gapsize, # topright_x
py + gapsize + lenghty / 4) # topright_y
subtract_rectangle(cutout_obj,
geo = substract_rectangle_geo(geo,
xmin - gapsize,
py - gapsize - lenghty / 4,
xmax + gapsize,
py + gapsize - lenghty / 4)
if gaps_u == 8 or gaps_u == '2tb':
subtract_rectangle(cutout_obj,
geo = substract_rectangle_geo(geo,
px - gapsize + lenghtx / 4,
ymin - gapsize,
px + gapsize + lenghtx / 4,
ymax + gapsize)
subtract_rectangle(cutout_obj,
geo = substract_rectangle_geo(geo,
px - gapsize - lenghtx / 4,
ymin - gapsize,
px + gapsize - lenghtx / 4,
ymax + gapsize)
if gaps_u == 4 or gaps_u == 'lr':
subtract_rectangle(cutout_obj,
geo = substract_rectangle_geo(geo,
xmin - gapsize,
py - gapsize,
xmax + gapsize,
py + gapsize)
if gaps_u == 4 or gaps_u == 'tb':
subtract_rectangle(cutout_obj,
geo = substract_rectangle_geo(geo,
px - gapsize,
ymin - gapsize,
px + gapsize,
ymax + gapsize)
geo_obj.solid_geometry = deepcopy(geo)
geo_obj.options['xmin'] = cutout_obj.options['xmin']
geo_obj.options['ymin'] = cutout_obj.options['ymin']
geo_obj.options['xmax'] = cutout_obj.options['xmax']
geo_obj.options['ymax'] = cutout_obj.options['ymax']
cutout_obj.plot()
self.app.inform.emit("[success] Any-form Cutout operation finished.")
app_obj.disable_plots(objects=[cutout_obj])
app_obj.inform.emit("[success] Any-form Cutout operation finished.")
outname = cutout_obj.options["name"] + "_cutout"
self.app.new_object('geometry', outname, geo_init)
# cutout_obj.plot()
# self.app.inform.emit("[success] Any-form Cutout operation finished.")
# self.app.plots_updated.emit()
elif isinstance(cutout_obj, FlatCAMGerber):
def geo_init(geo_obj, app_obj):
@ -267,7 +326,12 @@ class TclCommandGeoCutout(TclCommandSignaled):
ymin - gapsize,
px + gapsize,
ymax + gapsize)
geo_obj.solid_geometry = geo
geo_obj.solid_geometry = deepcopy(geo)
geo_obj.options['xmin'] = cutout_obj.options['xmin']
geo_obj.options['ymin'] = cutout_obj.options['ymin']
geo_obj.options['xmax'] = cutout_obj.options['xmax']
geo_obj.options['ymax'] = cutout_obj.options['ymax']
app_obj.inform.emit("[success] Any-form Cutout operation finished.")
outname = cutout_obj.options["name"] + "_cutout"
self.app.new_object('geometry', outname, geo_init)