jpcgt/flatcam/Beta слито с Beta
261
FlatCAMApp.py
|
@ -9,6 +9,8 @@
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import urllib.error
|
import urllib.error
|
||||||
|
import webbrowser
|
||||||
|
|
||||||
import getopt
|
import getopt
|
||||||
import random
|
import random
|
||||||
import simplejson as json
|
import simplejson as json
|
||||||
|
@ -21,7 +23,7 @@ import subprocess
|
||||||
import ctypes
|
import ctypes
|
||||||
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
from PyQt5 import QtPrintSupport, QtNetwork
|
from PyQt5 import QtPrintSupport
|
||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
import gc
|
import gc
|
||||||
|
@ -40,10 +42,12 @@ import vispy.scene as scene
|
||||||
# #######################################
|
# #######################################
|
||||||
from ObjectCollection import *
|
from ObjectCollection import *
|
||||||
from FlatCAMObj import *
|
from FlatCAMObj import *
|
||||||
|
from camlib import to_dict, dict2obj, ET, ParseError
|
||||||
|
|
||||||
from flatcamGUI.PlotCanvas import *
|
from flatcamGUI.PlotCanvas import *
|
||||||
from flatcamGUI.PlotCanvasLegacy import *
|
from flatcamGUI.PlotCanvasLegacy import *
|
||||||
|
|
||||||
from flatcamGUI.FlatCAMGUI import *
|
from flatcamGUI.FlatCAMGUI import *
|
||||||
|
|
||||||
from FlatCAMCommon import LoudDict
|
from FlatCAMCommon import LoudDict
|
||||||
from FlatCAMPostProc import load_postprocessors
|
from FlatCAMPostProc import load_postprocessors
|
||||||
|
|
||||||
|
@ -3061,7 +3065,7 @@ class App(QtCore.QObject):
|
||||||
separator=True)
|
separator=True)
|
||||||
|
|
||||||
self.panelize_tool = Panelize(self)
|
self.panelize_tool = Panelize(self)
|
||||||
self.panelize_tool.install(icon=QtGui.QIcon('share/panel16.png'))
|
self.panelize_tool.install(icon=QtGui.QIcon('share/panelize16.png'))
|
||||||
|
|
||||||
self.film_tool = Film(self)
|
self.film_tool = Film(self)
|
||||||
self.film_tool.install(icon=QtGui.QIcon('share/film16.png'))
|
self.film_tool.install(icon=QtGui.QIcon('share/film16.png'))
|
||||||
|
@ -3192,6 +3196,7 @@ class App(QtCore.QObject):
|
||||||
self.ui.newexc_btn.triggered.connect(self.new_excellon_object)
|
self.ui.newexc_btn.triggered.connect(self.new_excellon_object)
|
||||||
self.ui.editgeo_btn.triggered.connect(self.object2editor)
|
self.ui.editgeo_btn.triggered.connect(self.object2editor)
|
||||||
self.ui.update_obj_btn.triggered.connect(lambda: self.editor2object())
|
self.ui.update_obj_btn.triggered.connect(lambda: self.editor2object())
|
||||||
|
self.ui.copy_btn.triggered.connect(self.on_copy_object)
|
||||||
self.ui.delete_btn.triggered.connect(self.on_delete)
|
self.ui.delete_btn.triggered.connect(self.on_delete)
|
||||||
|
|
||||||
self.ui.distance_btn.triggered.connect(lambda: self.distance_tool.run(toggle=True))
|
self.ui.distance_btn.triggered.connect(lambda: self.distance_tool.run(toggle=True))
|
||||||
|
@ -3228,6 +3233,9 @@ class App(QtCore.QObject):
|
||||||
"""
|
"""
|
||||||
self.report_usage("object2editor()")
|
self.report_usage("object2editor()")
|
||||||
|
|
||||||
|
# disable the objects menu as it may interfere with the Editors
|
||||||
|
self.ui.menuobjects.setDisabled(True)
|
||||||
|
|
||||||
edited_object = self.collection.get_active()
|
edited_object = self.collection.get_active()
|
||||||
|
|
||||||
if isinstance(edited_object, FlatCAMGerber) or isinstance(edited_object, FlatCAMGeometry) or \
|
if isinstance(edited_object, FlatCAMGerber) or isinstance(edited_object, FlatCAMGeometry) or \
|
||||||
|
@ -3316,6 +3324,9 @@ class App(QtCore.QObject):
|
||||||
"""
|
"""
|
||||||
self.report_usage("editor2object()")
|
self.report_usage("editor2object()")
|
||||||
|
|
||||||
|
# re-enable the objects menu that was disabled on entry in Editor mode
|
||||||
|
self.ui.menuobjects.setDisabled(False)
|
||||||
|
|
||||||
# do not update a geometry or excellon object unless it comes out of an editor
|
# do not update a geometry or excellon object unless it comes out of an editor
|
||||||
if self.call_source != 'app':
|
if self.call_source != 'app':
|
||||||
edited_obj = self.collection.get_active()
|
edited_obj = self.collection.get_active()
|
||||||
|
@ -4527,10 +4538,10 @@ class App(QtCore.QObject):
|
||||||
|
|
||||||
attributions_label = QtWidgets.QLabel(
|
attributions_label = QtWidgets.QLabel(
|
||||||
_(
|
_(
|
||||||
'Some of the icons used are from the following sources: <BR>'
|
'Some of the icons used are from the following sources:<br>'
|
||||||
'<div>Icons made by <a href="https://www.flaticon.com/authors/freepik" '
|
'<div>Icons made by <a href="https://www.flaticon.com/authors/freepik" '
|
||||||
'title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" '
|
'title="Freepik">Freepik</a> from <a href="https://www.flaticon.com/" '
|
||||||
'title="Flaticon">www.flaticon.com</a></div><br>'
|
'title="Flaticon">www.flaticon.com</a></div>'
|
||||||
'Icons by <a target="_blank" href="https://icons8.com">Icons8</a>'
|
'Icons by <a target="_blank" href="https://icons8.com">Icons8</a>'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -4650,6 +4661,10 @@ class App(QtCore.QObject):
|
||||||
self.prog_form_lay.addRow(QtWidgets.QLabel('%s' % "@mgix"))
|
self.prog_form_lay.addRow(QtWidgets.QLabel('%s' % "@mgix"))
|
||||||
|
|
||||||
self.translator_grid_lay = QtWidgets.QGridLayout()
|
self.translator_grid_lay = QtWidgets.QGridLayout()
|
||||||
|
self.translator_grid_lay.setColumnStretch(0, 0)
|
||||||
|
self.translator_grid_lay.setColumnStretch(1, 0)
|
||||||
|
self.translator_grid_lay.setColumnStretch(2, 1)
|
||||||
|
self.translator_grid_lay.setColumnStretch(3, 0)
|
||||||
|
|
||||||
# trans_widget = QtWidgets.QWidget()
|
# trans_widget = QtWidgets.QWidget()
|
||||||
# trans_widget.setLayout(self.translator_grid_lay)
|
# trans_widget.setLayout(self.translator_grid_lay)
|
||||||
|
@ -4667,25 +4682,29 @@ class App(QtCore.QObject):
|
||||||
|
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("Language")), 0, 0)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("Language")), 0, 0)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("Translator")), 0, 1)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("Translator")), 0, 1)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("E-mail")), 0, 2)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("Corrections")), 0, 2)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Brasilian - Portuguese"), 1, 0)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("E-mail")), 0, 3)
|
||||||
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "BR - Portuguese"), 1, 0)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Carlos Stein"), 1, 1)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Carlos Stein"), 1, 1)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 1, 2)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "<carlos.stein@gmail.com>"), 1, 3)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "French"), 2, 0)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "French"), 2, 0)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu (Google-Translation)"), 2, 1)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 2, 1)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 2, 2)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "(Google-Translation)"), 2, 2)
|
||||||
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 2, 3)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "German"), 3, 0)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "German"), 3, 0)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu (Google-Translation)"), 3, 1)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 3, 1)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 3, 2)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Jens Karstedt"), 3, 2)
|
||||||
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 3, 3)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Romanian"), 4, 0)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Romanian"), 4, 0)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 4, 1)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 4, 1)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 4, 2)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 4, 3)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Russian"), 5, 0)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Russian"), 5, 0)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Andrey Kultyapov"), 5, 1)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Andrey Kultyapov"), 5, 1)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "<camellan@yandex.ru>"), 5, 2)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "<camellan@yandex.ru>"), 5, 3)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Spanish"), 6, 0)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Spanish"), 6, 0)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu (Google-Translation)"), 6, 1)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 6, 1)
|
||||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 6, 2)
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "(Google-Translation)"), 6, 2)
|
||||||
|
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 6, 3)
|
||||||
self.translator_grid_lay.setColumnStretch(0, 0)
|
self.translator_grid_lay.setColumnStretch(0, 0)
|
||||||
self.translators_tab_layout.addStretch()
|
self.translators_tab_layout.addStretch()
|
||||||
|
|
||||||
|
@ -7922,9 +7941,12 @@ class App(QtCore.QObject):
|
||||||
def add_act(name):
|
def add_act(name):
|
||||||
obj_for_icon = self.collection.get_by_name(name)
|
obj_for_icon = self.collection.get_by_name(name)
|
||||||
add_action = QtWidgets.QAction(parent=self.ui.menuobjects)
|
add_action = QtWidgets.QAction(parent=self.ui.menuobjects)
|
||||||
|
add_action.setCheckable(True)
|
||||||
add_action.setText(name)
|
add_action.setText(name)
|
||||||
add_action.setIcon(QtGui.QIcon(icon_files[obj_for_icon.kind]))
|
add_action.setIcon(QtGui.QIcon(icon_files[obj_for_icon.kind]))
|
||||||
add_action.triggered.connect(lambda: self.collection.set_exclusive_active(name))
|
add_action.triggered.connect(
|
||||||
|
lambda: self.collection.set_active(name) if add_action.isChecked() is True else
|
||||||
|
self.collection.set_inactive(name))
|
||||||
self.ui.menuobjects.addAction(add_action)
|
self.ui.menuobjects.addAction(add_action)
|
||||||
|
|
||||||
for name in gerber_list:
|
for name in gerber_list:
|
||||||
|
@ -7950,6 +7972,17 @@ class App(QtCore.QObject):
|
||||||
for name in doc_list:
|
for name in doc_list:
|
||||||
add_act(name)
|
add_act(name)
|
||||||
|
|
||||||
|
self.ui.menuobjects.addSeparator()
|
||||||
|
self.ui.menuobjects_selall = self.ui.menuobjects.addAction(
|
||||||
|
QtGui.QIcon('share/select_all.png'),
|
||||||
|
_('Select All')
|
||||||
|
)
|
||||||
|
self.ui.menuobjects_unselall = self.ui.menuobjects.addAction(
|
||||||
|
QtGui.QIcon('share/deselect_all32.png'),
|
||||||
|
_('Deselect All')
|
||||||
|
)
|
||||||
|
self.ui.menuobjects_selall.triggered.connect(lambda: self.on_objects_selection(True))
|
||||||
|
self.ui.menuobjects_unselall.triggered.connect(lambda: self.on_objects_selection(False))
|
||||||
|
|
||||||
elif state == 'delete':
|
elif state == 'delete':
|
||||||
for act in self.ui.menuobjects.actions():
|
for act in self.ui.menuobjects.actions():
|
||||||
|
@ -7966,7 +7999,9 @@ class App(QtCore.QObject):
|
||||||
add_action = QtWidgets.QAction(parent=self.ui.menuobjects)
|
add_action = QtWidgets.QAction(parent=self.ui.menuobjects)
|
||||||
add_action.setText(obj.options['name'])
|
add_action.setText(obj.options['name'])
|
||||||
add_action.setIcon(QtGui.QIcon(icon_files[obj.kind]))
|
add_action.setIcon(QtGui.QIcon(icon_files[obj.kind]))
|
||||||
add_action.triggered.connect(lambda: self.collection.set_exclusive_active(obj.options['name']))
|
add_action.triggered.connect(
|
||||||
|
lambda: self.collection.set_active(obj.options['name']) if add_action.isChecked() is True else
|
||||||
|
self.collection.set_inactive(obj.options['name']))
|
||||||
|
|
||||||
self.ui.menuobjects.insertAction(act, add_action)
|
self.ui.menuobjects.insertAction(act, add_action)
|
||||||
|
|
||||||
|
@ -7984,6 +8019,39 @@ class App(QtCore.QObject):
|
||||||
pass
|
pass
|
||||||
self.ui.menuobjects.clear()
|
self.ui.menuobjects.clear()
|
||||||
|
|
||||||
|
self.ui.menuobjects.addSeparator()
|
||||||
|
self.ui.menuobjects_selall = self.ui.menuobjects.addAction(
|
||||||
|
QtGui.QIcon('share/select_all.png'),
|
||||||
|
_('Select All')
|
||||||
|
)
|
||||||
|
self.ui.menuobjects_unselall = self.ui.menuobjects.addAction(
|
||||||
|
QtGui.QIcon('share/deselect_all32.png'),
|
||||||
|
_('Deselect All')
|
||||||
|
)
|
||||||
|
self.ui.menuobjects_selall.triggered.connect(lambda: self.on_objects_selection(True))
|
||||||
|
self.ui.menuobjects_unselall.triggered.connect(lambda: self.on_objects_selection(False))
|
||||||
|
|
||||||
|
def on_objects_selection(self, on_off):
|
||||||
|
obj_list = self.collection.get_names()
|
||||||
|
|
||||||
|
if on_off is True:
|
||||||
|
self.collection.set_all_active()
|
||||||
|
for act in self.ui.menuobjects.actions():
|
||||||
|
try:
|
||||||
|
act.setChecked(True)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
if obj_list:
|
||||||
|
self.inform.emit('[selected] %s' % _("All objects are selected."))
|
||||||
|
else:
|
||||||
|
self.collection.set_all_inactive()
|
||||||
|
for act in self.ui.menuobjects.actions():
|
||||||
|
try:
|
||||||
|
act.setChecked(False)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
self.inform.emit('%s' % _("Objects selection is cleared."))
|
||||||
|
|
||||||
def grid_status(self):
|
def grid_status(self):
|
||||||
if self.ui.grid_snap_btn.isChecked():
|
if self.ui.grid_snap_btn.isChecked():
|
||||||
return True
|
return True
|
||||||
|
@ -8426,93 +8494,40 @@ class App(QtCore.QObject):
|
||||||
objects_under_the_click_list.append(obj.options['name'])
|
objects_under_the_click_list.append(obj.options['name'])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# If there is no element in the overlapped objects list then make everyone inactive
|
if objects_under_the_click_list:
|
||||||
# because we selected "nothing"
|
curr_sel_obj = self.collection.get_active()
|
||||||
self.collection.set_all_inactive()
|
|
||||||
|
|
||||||
# delete the possible selection box around a possible selected object
|
|
||||||
self.delete_selection_shape()
|
|
||||||
|
|
||||||
if not objects_under_the_click_list:
|
|
||||||
|
|
||||||
# and as a convenience move the focus to the Project tab because Selected tab is now empty but
|
|
||||||
# only when working on App
|
|
||||||
if self.call_source == 'app':
|
|
||||||
if self.click_noproject is False:
|
|
||||||
self.ui.notebook.setCurrentWidget(self.ui.project_tab)
|
|
||||||
else:
|
|
||||||
# restore auto open the Project Tab
|
|
||||||
self.click_noproject = False
|
|
||||||
|
|
||||||
# delete any text in the status bar, implicitly the last object name that was selected
|
|
||||||
self.inform.emit("")
|
|
||||||
else:
|
|
||||||
self.call_source = 'app'
|
|
||||||
else:
|
|
||||||
# case when there is only an object under the click and we toggle it
|
# case when there is only an object under the click and we toggle it
|
||||||
if len(objects_under_the_click_list) == 1:
|
if len(objects_under_the_click_list) == 1:
|
||||||
if self.collection.get_active() is None:
|
if curr_sel_obj is None:
|
||||||
self.collection.set_active(objects_under_the_click_list[0])
|
self.collection.set_active(objects_under_the_click_list[0])
|
||||||
# create the selection box around the selected object
|
|
||||||
curr_sel_obj = self.collection.get_active()
|
curr_sel_obj = self.collection.get_active()
|
||||||
|
|
||||||
|
# create the selection box around the selected object
|
||||||
if self.defaults['global_selection_shape'] is True:
|
if self.defaults['global_selection_shape'] is True:
|
||||||
self.draw_selection_shape(curr_sel_obj)
|
self.draw_selection_shape(curr_sel_obj)
|
||||||
|
|
||||||
# self.inform.emit('[selected] %s: %s selected' %
|
|
||||||
# (str(curr_sel_obj.kind).capitalize(), str(curr_sel_obj.options['name'])))
|
|
||||||
if curr_sel_obj.kind == 'gerber':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='green', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'excellon':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='brown', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'cncjob':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='blue', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'geometry':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='red', name=str(curr_sel_obj.options['name'])))
|
|
||||||
|
|
||||||
elif self.collection.get_active().options['name'] not in objects_under_the_click_list:
|
elif self.collection.get_active().options['name'] not in objects_under_the_click_list:
|
||||||
self.collection.set_all_inactive()
|
self.on_objects_selection(False)
|
||||||
self.delete_selection_shape()
|
self.delete_selection_shape()
|
||||||
|
|
||||||
self.collection.set_active(objects_under_the_click_list[0])
|
self.collection.set_active(objects_under_the_click_list[0])
|
||||||
# create the selection box around the selected object
|
|
||||||
curr_sel_obj = self.collection.get_active()
|
curr_sel_obj = self.collection.get_active()
|
||||||
|
|
||||||
|
# create the selection box around the selected object
|
||||||
if self.defaults['global_selection_shape'] is True:
|
if self.defaults['global_selection_shape'] is True:
|
||||||
self.draw_selection_shape(curr_sel_obj)
|
self.draw_selection_shape(curr_sel_obj)
|
||||||
|
|
||||||
# self.inform.emit('[selected] %s: %s selected' %
|
self.selected_message(curr_sel_obj=curr_sel_obj)
|
||||||
# (str(curr_sel_obj.kind).capitalize(), str(curr_sel_obj.options['name'])))
|
|
||||||
if curr_sel_obj.kind == 'gerber':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='green', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'excellon':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='brown', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'cncjob':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='blue', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'geometry':
|
|
||||||
self.inform.emit(
|
|
||||||
_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='red', name=str(curr_sel_obj.options['name'])))
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.collection.set_all_inactive()
|
self.on_objects_selection(False)
|
||||||
self.delete_selection_shape()
|
self.delete_selection_shape()
|
||||||
if self.call_source == 'app':
|
|
||||||
# delete any text in the status bar, implicitly the last object name that was selected
|
if self.call_source != 'app':
|
||||||
self.inform.emit("")
|
|
||||||
else:
|
|
||||||
self.call_source = 'app'
|
self.call_source = 'app'
|
||||||
|
|
||||||
|
self.selected_message(curr_sel_obj=curr_sel_obj)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# If there is no selected object
|
# If there is no selected object
|
||||||
# make active the first element of the overlapped objects list
|
# make active the first element of the overlapped objects list
|
||||||
|
@ -8527,9 +8542,9 @@ class App(QtCore.QObject):
|
||||||
name_sel_obj = objects_under_the_click_list[0]
|
name_sel_obj = objects_under_the_click_list[0]
|
||||||
self.collection.set_active(name_sel_obj)
|
self.collection.set_active(name_sel_obj)
|
||||||
else:
|
else:
|
||||||
name_sel_obj_idx = objects_under_the_click_list.index(name_sel_obj)
|
sel_idx = objects_under_the_click_list.index(name_sel_obj)
|
||||||
self.collection.set_all_inactive()
|
self.collection.set_all_inactive()
|
||||||
self.collection.set_active(objects_under_the_click_list[(name_sel_obj_idx + 1) %
|
self.collection.set_active(objects_under_the_click_list[(sel_idx + 1) %
|
||||||
len(objects_under_the_click_list)])
|
len(objects_under_the_click_list)])
|
||||||
|
|
||||||
curr_sel_obj = self.collection.get_active()
|
curr_sel_obj = self.collection.get_active()
|
||||||
|
@ -8539,30 +8554,44 @@ class App(QtCore.QObject):
|
||||||
if self.defaults['global_selection_shape'] is True:
|
if self.defaults['global_selection_shape'] is True:
|
||||||
self.draw_selection_shape(curr_sel_obj)
|
self.draw_selection_shape(curr_sel_obj)
|
||||||
|
|
||||||
# self.inform.emit('[selected] %s: %s selected' %
|
self.selected_message(curr_sel_obj=curr_sel_obj)
|
||||||
# (str(curr_sel_obj.kind).capitalize(), str(curr_sel_obj.options['name'])))
|
|
||||||
if curr_sel_obj.kind == 'gerber':
|
|
||||||
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='green', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'excellon':
|
|
||||||
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='brown', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'cncjob':
|
|
||||||
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='blue', name=str(curr_sel_obj.options['name'])))
|
|
||||||
elif curr_sel_obj.kind == 'geometry':
|
|
||||||
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
|
||||||
color='red', name=str(curr_sel_obj.options['name'])))
|
|
||||||
|
|
||||||
# for obj in self.collection.get_list():
|
else:
|
||||||
# obj.plot()
|
# deselect everything
|
||||||
# curr_sel_obj.plot(color=self.FC_dark_blue, face_color=self.FC_light_blue)
|
self.on_objects_selection(False)
|
||||||
|
# delete the possible selection box around a possible selected object
|
||||||
|
self.delete_selection_shape()
|
||||||
|
|
||||||
# TODO: on selected objects change the object colors and do not draw the selection box
|
# and as a convenience move the focus to the Project tab because Selected tab is now empty but
|
||||||
# self.plotcanvas.update() # this updates the canvas
|
# only when working on App
|
||||||
|
if self.call_source == 'app':
|
||||||
|
if self.click_noproject is False:
|
||||||
|
self.ui.notebook.setCurrentWidget(self.ui.project_tab)
|
||||||
|
else:
|
||||||
|
# restore auto open the Project Tab
|
||||||
|
self.click_noproject = False
|
||||||
|
|
||||||
|
# delete any text in the status bar, implicitly the last object name that was selected
|
||||||
|
# self.inform.emit("")
|
||||||
|
else:
|
||||||
|
self.call_source = 'app'
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.error("[ERROR] Something went bad. %s" % str(e))
|
log.error("[ERROR] Something went bad in App.select_objects(). %s" % str(e))
|
||||||
return
|
|
||||||
|
def selected_message(self, curr_sel_obj):
|
||||||
|
if curr_sel_obj:
|
||||||
|
if curr_sel_obj.kind == 'gerber':
|
||||||
|
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
||||||
|
color='green', name=str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'excellon':
|
||||||
|
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
||||||
|
color='brown', name=str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'cncjob':
|
||||||
|
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
||||||
|
color='blue', name=str(curr_sel_obj.options['name'])))
|
||||||
|
elif curr_sel_obj.kind == 'geometry':
|
||||||
|
self.inform.emit(_('[selected]<span style="color:{color};">{name}</span> selected').format(
|
||||||
|
color='red', name=str(curr_sel_obj.options['name'])))
|
||||||
|
|
||||||
def delete_hover_shape(self):
|
def delete_hover_shape(self):
|
||||||
self.hover_shapes.clear()
|
self.hover_shapes.clear()
|
||||||
|
@ -8621,6 +8650,9 @@ class App(QtCore.QObject):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if sel_obj is None:
|
||||||
|
return
|
||||||
|
|
||||||
pt1 = (float(sel_obj.options['xmin']), float(sel_obj.options['ymin']))
|
pt1 = (float(sel_obj.options['xmin']), float(sel_obj.options['ymin']))
|
||||||
pt2 = (float(sel_obj.options['xmax']), float(sel_obj.options['ymin']))
|
pt2 = (float(sel_obj.options['xmax']), float(sel_obj.options['ymin']))
|
||||||
pt3 = (float(sel_obj.options['xmax']), float(sel_obj.options['ymax']))
|
pt3 = (float(sel_obj.options['xmax']), float(sel_obj.options['ymax']))
|
||||||
|
@ -8634,13 +8666,6 @@ class App(QtCore.QObject):
|
||||||
sel_rect = sel_rect.buffer(-0.00393)
|
sel_rect = sel_rect.buffer(-0.00393)
|
||||||
sel_rect = sel_rect.buffer(0.00787)
|
sel_rect = sel_rect.buffer(0.00787)
|
||||||
|
|
||||||
# if color:
|
|
||||||
# face = Color(color, alpha=0.2)
|
|
||||||
# outline = Color(color, alpha=0.8)
|
|
||||||
# else:
|
|
||||||
# face = Color(self.defaults['global_sel_fill'], alpha=0.2)
|
|
||||||
# outline = Color(self.defaults['global_sel_line'], alpha=0.8)
|
|
||||||
|
|
||||||
if color:
|
if color:
|
||||||
face = color[:-2] + str(hex(int(0.2 * 255)))[2:]
|
face = color[:-2] + str(hex(int(0.2 * 255)))[2:]
|
||||||
outline = color[:-2] + str(hex(int(0.8 * 255)))[2:]
|
outline = color[:-2] + str(hex(int(0.8 * 255)))[2:]
|
||||||
|
@ -9044,7 +9069,7 @@ class App(QtCore.QObject):
|
||||||
try:
|
try:
|
||||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
|
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
|
||||||
caption=_("Export SVG"),
|
caption=_("Export SVG"),
|
||||||
directory=self.get_last_save_folder() + '/' + str(name),
|
directory=self.get_last_save_folder() + '/' + str(name) + '_svg',
|
||||||
filter=_filter)
|
filter=_filter)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export SVG"), filter=_filter)
|
filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export SVG"), filter=_filter)
|
||||||
|
|
|
@ -10,24 +10,33 @@
|
||||||
# File modified by: Marius Stanciu #
|
# File modified by: Marius Stanciu #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from PyQt5.QtGui import QTextDocument
|
from shapely.geometry import Point, Polygon, MultiPolygon, MultiLineString, LineString, LinearRing
|
||||||
|
from shapely.ops import cascaded_union
|
||||||
|
import shapely.affinity as affinity
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
|
from copy import deepcopy
|
||||||
|
from io import StringIO
|
||||||
|
import traceback
|
||||||
import inspect # TODO: For debugging only.
|
import inspect # TODO: For debugging only.
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from flatcamEditors.FlatCAMTextEditor import TextEditor
|
from flatcamEditors.FlatCAMTextEditor import TextEditor
|
||||||
|
|
||||||
from flatcamGUI.ObjectUI import *
|
from flatcamGUI.ObjectUI import *
|
||||||
from FlatCAMCommon import LoudDict
|
from FlatCAMCommon import LoudDict
|
||||||
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||||
from camlib import *
|
|
||||||
from flatcamParsers.ParseExcellon import Excellon
|
from flatcamParsers.ParseExcellon import Excellon
|
||||||
from flatcamParsers.ParseGerber import Gerber
|
from flatcamParsers.ParseGerber import Gerber
|
||||||
|
from camlib import Geometry, CNCjob
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
import itertools
|
|
||||||
import tkinter as tk
|
import tkinter as tk
|
||||||
import sys
|
import os, sys, itertools
|
||||||
|
import ezdxf
|
||||||
|
|
||||||
|
import math
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -66,7 +75,7 @@ class FlatCAMObj(QtCore.QObject):
|
||||||
app = None
|
app = None
|
||||||
|
|
||||||
# signal to plot a single object
|
# signal to plot a single object
|
||||||
plot_single_object = pyqtSignal()
|
plot_single_object = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
"""
|
"""
|
||||||
|
@ -2804,10 +2813,13 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
|
||||||
|
|
||||||
for tool in tools:
|
for tool in tools:
|
||||||
if tooldia > self.tools[tool]["C"]:
|
if tooldia > self.tools[tool]["C"]:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s %s: %s' % (
|
self.app.inform.emit(
|
||||||
_("Milling tool for DRILLS is larger than hole size. Cancelled.",
|
'[ERROR_NOTCL] %s %s: %s' % (
|
||||||
str(tool))
|
_("Milling tool for DRILLS is larger than hole size. Cancelled."),
|
||||||
))
|
_("Tool"),
|
||||||
|
str(tool)
|
||||||
|
)
|
||||||
|
)
|
||||||
return False, "Error: Milling tool is larger than hole."
|
return False, "Error: Milling tool is larger than hole."
|
||||||
|
|
||||||
def geo_init(geo_obj, app_obj):
|
def geo_init(geo_obj, app_obj):
|
||||||
|
@ -3510,21 +3522,21 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
||||||
offset_item = QtWidgets.QComboBox()
|
offset_item = QtWidgets.QComboBox()
|
||||||
for item in self.offset_item_options:
|
for item in self.offset_item_options:
|
||||||
offset_item.addItem(item)
|
offset_item.addItem(item)
|
||||||
offset_item.setStyleSheet('background-color: rgb(255,255,255)')
|
# offset_item.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
idx = offset_item.findText(tooluid_value['offset'])
|
idx = offset_item.findText(tooluid_value['offset'])
|
||||||
offset_item.setCurrentIndex(idx)
|
offset_item.setCurrentIndex(idx)
|
||||||
|
|
||||||
type_item = QtWidgets.QComboBox()
|
type_item = QtWidgets.QComboBox()
|
||||||
for item in self.type_item_options:
|
for item in self.type_item_options:
|
||||||
type_item.addItem(item)
|
type_item.addItem(item)
|
||||||
type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
# type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
idx = type_item.findText(tooluid_value['type'])
|
idx = type_item.findText(tooluid_value['type'])
|
||||||
type_item.setCurrentIndex(idx)
|
type_item.setCurrentIndex(idx)
|
||||||
|
|
||||||
tool_type_item = QtWidgets.QComboBox()
|
tool_type_item = QtWidgets.QComboBox()
|
||||||
for item in self.tool_type_item_options:
|
for item in self.tool_type_item_options:
|
||||||
tool_type_item.addItem(item)
|
tool_type_item.addItem(item)
|
||||||
tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
# tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
idx = tool_type_item.findText(tooluid_value['tool_type'])
|
idx = tool_type_item.findText(tooluid_value['tool_type'])
|
||||||
tool_type_item.setCurrentIndex(idx)
|
tool_type_item.setCurrentIndex(idx)
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
from importlib.machinery import SourceFileLoader
|
from importlib.machinery import SourceFileLoader
|
||||||
import os
|
import os
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
from datetime import datetime
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
# module-root dictionary of postprocessors
|
# module-root dictionary of postprocessors
|
||||||
|
|
|
@ -11,13 +11,20 @@
|
||||||
# File modified by: Marius Stanciu #
|
# File modified by: Marius Stanciu #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
# from PyQt5.QtCore import QModelIndex
|
|
||||||
from FlatCAMObj import *
|
|
||||||
import inspect # TODO: Remove
|
|
||||||
import FlatCAMApp
|
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import Qt, QSettings
|
from PyQt5.QtCore import Qt, QSettings
|
||||||
# import webbrowser
|
from PyQt5.QtGui import QColor
|
||||||
|
# from PyQt5.QtCore import QModelIndex
|
||||||
|
|
||||||
|
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon, FlatCAMCNCjob, FlatCAMDocument, FlatCAMScript
|
||||||
|
import inspect # TODO: Remove
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
|
import re
|
||||||
|
import logging
|
||||||
|
import collections
|
||||||
|
from copy import deepcopy
|
||||||
|
from numpy import Inf
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -27,6 +34,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class KeySensitiveListView(QtWidgets.QTreeView):
|
class KeySensitiveListView(QtWidgets.QTreeView):
|
||||||
"""
|
"""
|
||||||
|
@ -715,6 +724,16 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
||||||
log.error("[ERROR] Cause: %s" % str(e))
|
log.error("[ERROR] Cause: %s" % str(e))
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
def set_all_active(self):
|
||||||
|
"""
|
||||||
|
Select all objects from the project list. This triggers the
|
||||||
|
list_selection_changed event and call on_list_selection_changed.
|
||||||
|
|
||||||
|
:return: None
|
||||||
|
"""
|
||||||
|
for name in self.get_names():
|
||||||
|
self.set_active(name)
|
||||||
|
|
||||||
def set_exclusive_active(self, name):
|
def set_exclusive_active(self, name):
|
||||||
"""
|
"""
|
||||||
Make the object with the name in parameters the only selected object
|
Make the object with the name in parameters the only selected object
|
||||||
|
|
36
README.md
|
@ -9,6 +9,40 @@ CAD program, and create G-Code for Isolation routing.
|
||||||
|
|
||||||
=================================================
|
=================================================
|
||||||
|
|
||||||
|
18.10.2019
|
||||||
|
|
||||||
|
- finished the update on the Google translated Spanish translation.
|
||||||
|
- updated the new objects icons for Gerber, Geometry and Excellon
|
||||||
|
- small import problem fixed
|
||||||
|
- RELEASE 8.98
|
||||||
|
|
||||||
|
17.10.2019
|
||||||
|
|
||||||
|
- fixed a bug in milling holes due of a message wrongly formatted
|
||||||
|
- added an translator email address
|
||||||
|
- finished the update on German Google translation. Part of it was corrected by Jens Karstedt
|
||||||
|
- finished the update of the Romanian translation.
|
||||||
|
- finished the Objects menu by adding the ability of actions to be checked so they will show the selected status of the objects and by adding to actions to (de)select all objects
|
||||||
|
- fixed and optimized the click selection on canvas
|
||||||
|
- fixed Gerber parsing for very simple Gerber files that have only one Polygon but many LPC zones
|
||||||
|
- fixed SVG export; fix bug #327
|
||||||
|
- finished the update on French Google translation.
|
||||||
|
|
||||||
|
16.10.2019
|
||||||
|
|
||||||
|
- small update to Romanian translation files
|
||||||
|
|
||||||
|
15.10.2019
|
||||||
|
|
||||||
|
- adjusted the layout in NCC Tool
|
||||||
|
- fixed bug in Panelization Tool for which in case of Excellon objects, the panel kept a reference to the source object which created issues when moving or disabling/enabling the plots
|
||||||
|
- cleaned up the module imports throughout the app (the TclCommands are not yet verified)
|
||||||
|
- removed the styling on the comboboxes cellWidget's in the Tool Tables
|
||||||
|
- replaced some of the icons that did not looked Ok on the dark theme
|
||||||
|
- added a new toolbar button for the Copy object functionality
|
||||||
|
- changed the Panelize tool icon
|
||||||
|
- corrected some strings
|
||||||
|
|
||||||
14.10.2019
|
14.10.2019
|
||||||
|
|
||||||
- modified the result highlight color in Check Rules Tool
|
- modified the result highlight color in Check Rules Tool
|
||||||
|
@ -189,7 +223,7 @@ CAD program, and create G-Code for Isolation routing.
|
||||||
- fixed the ToolMeasurement geometry not being displayed
|
- fixed the ToolMeasurement geometry not being displayed
|
||||||
- fixed a bug in Excellon Editor that crashed the app when editing the first tool added automatically into a new black Excellon file
|
- fixed a bug in Excellon Editor that crashed the app when editing the first tool added automatically into a new black Excellon file
|
||||||
- made sure that if the big mouse cursor is selected, the utility geometry in Excellon Editor has a thicker line width (2 pixels now) so it is visible over the geometry of the mouse cursor
|
- made sure that if the big mouse cursor is selected, the utility geometry in Excellon Editor has a thicker line width (2 pixels now) so it is visible over the geometry of the mouse cursor
|
||||||
- fixed issue #319 where generating a CNCJob from a geometry made with NCC Tool made the app crash
|
- fixed issue #319 where generating a CNCJob from a geometry made with NCC Tool made the app crash; also #328 which is the same
|
||||||
- replaced in FlatCAM Tools and in FLatCAMObj.py and in Editors all references to hardcoded decimals in string formats for tools with a variable declared in the __init__()
|
- replaced in FlatCAM Tools and in FLatCAMObj.py and in Editors all references to hardcoded decimals in string formats for tools with a variable declared in the __init__()
|
||||||
- fixed a small bug that made app crash when the splash screen is disabled: it was trying to close it without being open
|
- fixed a small bug that made app crash when the splash screen is disabled: it was trying to close it without being open
|
||||||
|
|
||||||
|
|
106
camlib.py
|
@ -11,12 +11,9 @@ from PyQt5 import QtWidgets
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, dot, float32, \
|
|
||||||
transpose
|
|
||||||
from numpy.linalg import solve, norm
|
from numpy.linalg import solve, norm
|
||||||
|
|
||||||
import re, sys, os, platform
|
import platform
|
||||||
import math
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -26,8 +23,8 @@ from rtree import index as rtindex
|
||||||
from lxml import etree as ET
|
from lxml import etree as ET
|
||||||
|
|
||||||
# See: http://toblerity.org/shapely/manual.html
|
# See: http://toblerity.org/shapely/manual.html
|
||||||
from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString
|
from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString, MultiPoint, MultiPolygon
|
||||||
from shapely.geometry import MultiPoint, MultiPolygon
|
|
||||||
from shapely.geometry import box as shply_box
|
from shapely.geometry import box as shply_box
|
||||||
from shapely.ops import cascaded_union, unary_union, polygonize
|
from shapely.ops import cascaded_union, unary_union, polygonize
|
||||||
import shapely.affinity as affinity
|
import shapely.affinity as affinity
|
||||||
|
@ -64,7 +61,6 @@ import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
|
||||||
|
|
||||||
fcTranslate.apply_language('strings')
|
fcTranslate.apply_language('strings')
|
||||||
|
|
||||||
log = logging.getLogger('base2')
|
log = logging.getLogger('base2')
|
||||||
|
@ -162,9 +158,9 @@ class ApertureMacro:
|
||||||
|
|
||||||
# ## Variables
|
# ## Variables
|
||||||
# These are variables defined locally inside the macro. They can be
|
# These are variables defined locally inside the macro. They can be
|
||||||
# numerical constant or defind in terms of previously define
|
# numerical constant or defined in terms of previously define
|
||||||
# variables, which can be defined locally or in an aperture
|
# variables, which can be defined locally or in an aperture
|
||||||
# definition. All replacements ocurr here.
|
# definition. All replacements occur here.
|
||||||
match = ApertureMacro.amvar_re.search(part)
|
match = ApertureMacro.amvar_re.search(part)
|
||||||
if match:
|
if match:
|
||||||
var = match.group(1)
|
var = match.group(1)
|
||||||
|
@ -336,8 +332,8 @@ class ApertureMacro:
|
||||||
points = [(0, 0)]*nverts
|
points = [(0, 0)]*nverts
|
||||||
|
|
||||||
for i in range(nverts):
|
for i in range(nverts):
|
||||||
points[i] = (x + 0.5 * dia * cos(2*pi * i/nverts),
|
points[i] = (x + 0.5 * dia * np.cos(2*np.pi * i/nverts),
|
||||||
y + 0.5 * dia * sin(2*pi * i/nverts))
|
y + 0.5 * dia * np.sin(2*np.pi * i/nverts))
|
||||||
|
|
||||||
poly = Polygon(points)
|
poly = Polygon(points)
|
||||||
poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
|
poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
|
||||||
|
@ -637,10 +633,10 @@ class Geometry(object):
|
||||||
|
|
||||||
def bounds_rec(obj):
|
def bounds_rec(obj):
|
||||||
if type(obj) is list:
|
if type(obj) is list:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in obj:
|
for k in obj:
|
||||||
if type(k) is dict:
|
if type(k) is dict:
|
||||||
|
@ -1155,7 +1151,7 @@ class Geometry(object):
|
||||||
log.debug("Image import as monochrome.")
|
log.debug("Image import as monochrome.")
|
||||||
else:
|
else:
|
||||||
mask_setting = (red <= mask[1]) + (green <= mask[2]) + (blue <= mask[3])
|
mask_setting = (red <= mask[1]) + (green <= mask[2]) + (blue <= mask[3])
|
||||||
total = np.zeros(red.shape, dtype=float32)
|
total = np.zeros(red.shape, dtype=np.float32)
|
||||||
for band in red, green, blue:
|
for band in red, green, blue:
|
||||||
total += band
|
total += band
|
||||||
total /= 3
|
total /= 3
|
||||||
|
@ -1847,8 +1843,6 @@ class Geometry(object):
|
||||||
:return: SVG Element
|
:return: SVG Element
|
||||||
"""
|
"""
|
||||||
|
|
||||||
geom = None
|
|
||||||
|
|
||||||
# Make sure we see a Shapely Geometry class and not a list
|
# Make sure we see a Shapely Geometry class and not a list
|
||||||
if str(type(self)) == "<class 'FlatCAMObj.FlatCAMGeometry'>":
|
if str(type(self)) == "<class 'FlatCAMObj.FlatCAMGeometry'>":
|
||||||
flat_geo = []
|
flat_geo = []
|
||||||
|
@ -1873,6 +1867,8 @@ class Geometry(object):
|
||||||
elif skew_reference == 'bottomright':
|
elif skew_reference == 'bottomright':
|
||||||
skew_ref = (xmax, ymin)
|
skew_ref = (xmax, ymin)
|
||||||
|
|
||||||
|
geom = geom_svg
|
||||||
|
|
||||||
if scale_factor_x:
|
if scale_factor_x:
|
||||||
geom = affinity.scale(geom_svg, scale_factor_x, 1.0)
|
geom = affinity.scale(geom_svg, scale_factor_x, 1.0)
|
||||||
if scale_factor_y:
|
if scale_factor_y:
|
||||||
|
@ -3298,10 +3294,10 @@ class CNCjob(Geometry):
|
||||||
|
|
||||||
def bounds_rec(obj):
|
def bounds_rec(obj):
|
||||||
if type(obj) is list:
|
if type(obj) is list:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in obj:
|
for k in obj:
|
||||||
if type(k) is dict:
|
if type(k) is dict:
|
||||||
|
@ -4049,9 +4045,9 @@ class CNCjob(Geometry):
|
||||||
arcdir = [None, None, "cw", "ccw"]
|
arcdir = [None, None, "cw", "ccw"]
|
||||||
if current['G'] in [2, 3]: # arc
|
if current['G'] in [2, 3]: # arc
|
||||||
center = [gobj['I'] + current['X'], gobj['J'] + current['Y']]
|
center = [gobj['I'] + current['X'], gobj['J'] + current['Y']]
|
||||||
radius = sqrt(gobj['I']**2 + gobj['J']**2)
|
radius = np.sqrt(gobj['I']**2 + gobj['J']**2)
|
||||||
start = arctan2(-gobj['J'], -gobj['I'])
|
start = np.arctan2(-gobj['J'], -gobj['I'])
|
||||||
stop = arctan2(-center[1] + y, -center[0] + x)
|
stop = np.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
|
# Update current instruction
|
||||||
|
@ -4710,10 +4706,10 @@ class CNCjob(Geometry):
|
||||||
|
|
||||||
def bounds_rec(obj):
|
def bounds_rec(obj):
|
||||||
if type(obj) is list:
|
if type(obj) is list:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in obj:
|
for k in obj:
|
||||||
if type(k) is dict:
|
if type(k) is dict:
|
||||||
|
@ -4742,15 +4738,15 @@ class CNCjob(Geometry):
|
||||||
|
|
||||||
bounds_coords = bounds_rec(self.solid_geometry)
|
bounds_coords = bounds_rec(self.solid_geometry)
|
||||||
else:
|
else:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
for k, v in self.cnc_tools.items():
|
for k, v in self.cnc_tools.items():
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
try:
|
try:
|
||||||
for k in v['solid_geometry']:
|
for k in v['solid_geometry']:
|
||||||
minx_, miny_, maxx_, maxy_ = bounds_rec(k)
|
minx_, miny_, maxx_, maxy_ = bounds_rec(k)
|
||||||
|
@ -5186,10 +5182,10 @@ class CNCjob(Geometry):
|
||||||
|
|
||||||
|
|
||||||
def get_bounds(geometry_list):
|
def get_bounds(geometry_list):
|
||||||
xmin = Inf
|
xmin = np.Inf
|
||||||
ymin = Inf
|
ymin = np.Inf
|
||||||
xmax = -Inf
|
xmax = -np.Inf
|
||||||
ymax = -Inf
|
ymax = -np.Inf
|
||||||
|
|
||||||
for gs in geometry_list:
|
for gs in geometry_list:
|
||||||
try:
|
try:
|
||||||
|
@ -5229,33 +5225,33 @@ def arc(center, radius, start, stop, direction, steps_per_circ):
|
||||||
da_sign = {"cw": -1.0, "ccw": 1.0}
|
da_sign = {"cw": -1.0, "ccw": 1.0}
|
||||||
points = []
|
points = []
|
||||||
if direction == "ccw" and stop <= start:
|
if direction == "ccw" and stop <= start:
|
||||||
stop += 2 * pi
|
stop += 2 * np.pi
|
||||||
if direction == "cw" and stop >= start:
|
if direction == "cw" and stop >= start:
|
||||||
stop -= 2 * pi
|
stop -= 2 * np.pi
|
||||||
|
|
||||||
angle = abs(stop - start)
|
angle = abs(stop - start)
|
||||||
|
|
||||||
# angle = stop-start
|
# angle = stop-start
|
||||||
steps = max([int(ceil(angle / (2 * pi) * steps_per_circ)), 2])
|
steps = max([int(np.ceil(angle / (2 * np.pi) * steps_per_circ)), 2])
|
||||||
delta_angle = da_sign[direction] * angle * 1.0 / steps
|
delta_angle = da_sign[direction] * angle * 1.0 / steps
|
||||||
for i in range(steps + 1):
|
for i in range(steps + 1):
|
||||||
theta = start + delta_angle * i
|
theta = start + delta_angle * i
|
||||||
points.append((center[0] + radius * cos(theta), center[1] + radius * sin(theta)))
|
points.append((center[0] + radius * np.cos(theta), center[1] + radius * np.sin(theta)))
|
||||||
return points
|
return points
|
||||||
|
|
||||||
|
|
||||||
def arc2(p1, p2, center, direction, steps_per_circ):
|
def arc2(p1, p2, center, direction, steps_per_circ):
|
||||||
r = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
r = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
||||||
start = arctan2(p1[1] - center[1], p1[0] - center[0])
|
start = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stop = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stop = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
return arc(center, r, start, stop, direction, steps_per_circ)
|
return arc(center, r, start, stop, direction, steps_per_circ)
|
||||||
|
|
||||||
|
|
||||||
def arc_angle(start, stop, direction):
|
def arc_angle(start, stop, direction):
|
||||||
if direction == "ccw" and stop <= start:
|
if direction == "ccw" and stop <= start:
|
||||||
stop += 2 * pi
|
stop += 2 * np.pi
|
||||||
if direction == "cw" and stop >= start:
|
if direction == "cw" and stop >= start:
|
||||||
stop -= 2 * pi
|
stop -= 2 * np.pi
|
||||||
|
|
||||||
angle = abs(stop - start)
|
angle = abs(stop - start)
|
||||||
return angle
|
return angle
|
||||||
|
@ -5665,12 +5661,12 @@ def three_point_circle(p1, p2, p3):
|
||||||
a2 = (p2 + p3) / 2.0
|
a2 = (p2 + p3) / 2.0
|
||||||
|
|
||||||
# Normals
|
# Normals
|
||||||
b1 = dot((p2 - p1), array([[0, -1], [1, 0]], dtype=float32))
|
b1 = np.dot((p2 - p1), np.array([[0, -1], [1, 0]], dtype=np.float32))
|
||||||
b2 = dot((p3 - p2), array([[0, 1], [-1, 0]], dtype=float32))
|
b2 = np.dot((p3 - p2), np.array([[0, 1], [-1, 0]], dtype=np.float32))
|
||||||
|
|
||||||
# Params
|
# Params
|
||||||
try:
|
try:
|
||||||
T = solve(transpose(array([-b1, b2])), a1 - a2)
|
T = solve(np.transpose(np.array([-b1, b2])), a1 - a2)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug("camlib.three_point_circle() --> %s" % str(e))
|
log.debug("camlib.three_point_circle() --> %s" % str(e))
|
||||||
return
|
return
|
||||||
|
@ -5685,11 +5681,11 @@ def three_point_circle(p1, p2, p3):
|
||||||
|
|
||||||
|
|
||||||
def distance(pt1, pt2):
|
def distance(pt1, pt2):
|
||||||
return sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
|
return np.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
|
||||||
|
|
||||||
|
|
||||||
def distance_euclidian(x1, y1, x2, y2):
|
def distance_euclidian(x1, y1, x2, y2):
|
||||||
return sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
|
return np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
|
||||||
|
|
||||||
|
|
||||||
class FlatCAMRTree(object):
|
class FlatCAMRTree(object):
|
||||||
|
|
|
@ -12,14 +12,17 @@ class Polygon(object):
|
||||||
self.context = context
|
self.context = context
|
||||||
else:
|
else:
|
||||||
self.context = getattr(context, '__geo_interface__', context)
|
self.context = getattr(context, '__geo_interface__', context)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def geom_type(self):
|
def geom_type(self):
|
||||||
return (getattr(self.context, 'geom_type', None)
|
return (getattr(self.context, 'geom_type', None)
|
||||||
or self.context['type'])
|
or self.context['type'])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def exterior(self):
|
def exterior(self):
|
||||||
return (getattr(self.context, 'exterior', None)
|
return (getattr(self.context, 'exterior', None)
|
||||||
or self.context['coordinates'][0])
|
or self.context['coordinates'][0])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def interiors(self):
|
def interiors(self):
|
||||||
value = getattr(self.context, 'interiors', None)
|
value = getattr(self.context, 'interiors', None)
|
||||||
|
|
|
@ -8,19 +8,23 @@
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import Qt, QSettings
|
from PyQt5.QtCore import Qt, QSettings
|
||||||
|
|
||||||
from shapely.geometry import LineString, LinearRing, MultiLineString
|
from camlib import distance, arc, FlatCAMRTreeStorage
|
||||||
from shapely.ops import cascaded_union
|
|
||||||
import shapely.affinity as affinity
|
|
||||||
|
|
||||||
from numpy import arctan2, Inf, array, sqrt, sign, dot
|
|
||||||
from rtree import index as rtindex
|
|
||||||
|
|
||||||
from camlib import *
|
|
||||||
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
|
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
|
||||||
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
|
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
|
||||||
from flatcamParsers.ParseExcellon import Excellon
|
from flatcamParsers.ParseExcellon import Excellon
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
from copy import copy, deepcopy
|
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point
|
||||||
|
import shapely.affinity as affinity
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from rtree import index as rtindex
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import math
|
||||||
|
import logging
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -30,6 +34,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class FCDrillAdd(FCShapeTool):
|
class FCDrillAdd(FCShapeTool):
|
||||||
"""
|
"""
|
||||||
|
@ -556,7 +562,6 @@ class FCSlotArray(FCShapeTool):
|
||||||
_("To add an Slot Array first select a tool in Tool Table"))
|
_("To add an Slot Array first select a tool in Tool Table"))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
QtGui.QGuiApplication.restoreOverrideCursor()
|
QtGui.QGuiApplication.restoreOverrideCursor()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -1006,7 +1011,6 @@ class FCDrillResize(FCShapeTool):
|
||||||
|
|
||||||
sel_shapes_to_be_deleted.append(select_shape)
|
sel_shapes_to_be_deleted.append(select_shape)
|
||||||
|
|
||||||
|
|
||||||
# a hack to make the tool_table display more drills/slots per diameter when shape(drill/slot)
|
# a hack to make the tool_table display more drills/slots per diameter when shape(drill/slot)
|
||||||
# is added.
|
# is added.
|
||||||
# self.points_edit it's only useful first time when we load the data into the storage
|
# self.points_edit it's only useful first time when we load the data into the storage
|
||||||
|
@ -3084,7 +3088,6 @@ class FlatCAMExcEditor(QtCore.QObject):
|
||||||
# element[1] of the tuple is a list of coordinates (a tuple themselves)
|
# element[1] of the tuple is a list of coordinates (a tuple themselves)
|
||||||
ordered_edited_points = sorted(zip(edited_points.keys(), edited_points.values()))
|
ordered_edited_points = sorted(zip(edited_points.keys(), edited_points.values()))
|
||||||
|
|
||||||
|
|
||||||
current_tool = 0
|
current_tool = 0
|
||||||
for tool_dia in ordered_edited_points:
|
for tool_dia in ordered_edited_points:
|
||||||
current_tool += 1
|
current_tool += 1
|
||||||
|
@ -3208,14 +3211,13 @@ class FlatCAMExcEditor(QtCore.QObject):
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
_("There are no Tools definitions in the file. Aborting Excellon creation.")
|
_("There are no Tools definitions in the file. Aborting Excellon creation.")
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
msg = '[ERROR] %s' % \
|
msg = '[ERROR] %s' % \
|
||||||
_("An internal error has ocurred. See Shell.\n")
|
_("An internal error has ocurred. See Shell.\n")
|
||||||
msg += traceback.format_exc()
|
msg += traceback.format_exc()
|
||||||
app_obj.inform.emit(msg)
|
app_obj.inform.emit(msg)
|
||||||
raise
|
return
|
||||||
# raise
|
|
||||||
|
|
||||||
with self.app.proc_container.new(_("Creating Excellon.")):
|
with self.app.proc_container.new(_("Creating Excellon.")):
|
||||||
|
|
||||||
|
@ -3320,7 +3322,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
||||||
self.pos = self.canvas.translate_coords(event_pos)
|
self.pos = self.canvas.translate_coords(event_pos)
|
||||||
|
|
||||||
if self.app.grid_status() == True:
|
if self.app.grid_status() == True:
|
||||||
self.pos = self.app.geo_editor.snap(self.pos[0], self.pos[1])
|
self.pos = self.app.geo_editor.snap(self.pos[0], self.pos[1])
|
||||||
else:
|
else:
|
||||||
self.pos = (self.pos[0], self.pos[1])
|
self.pos = (self.pos[0], self.pos[1])
|
||||||
|
|
||||||
|
@ -3555,14 +3557,14 @@ class FlatCAMExcEditor(QtCore.QObject):
|
||||||
for storage in self.storage_dict:
|
for storage in self.storage_dict:
|
||||||
for obj in self.storage_dict[storage].get_objects():
|
for obj in self.storage_dict[storage].get_objects():
|
||||||
if (sel_type is True and poly_selection.contains(obj.geo)) or \
|
if (sel_type is True and poly_selection.contains(obj.geo)) or \
|
||||||
(sel_type is False and poly_selection.intersects(obj.geo)):
|
(sel_type is False and poly_selection.intersects(obj.geo)):
|
||||||
|
|
||||||
if obj in self.selected:
|
if obj in self.selected:
|
||||||
# remove the shape object from the selected shapes storage
|
# remove the shape object from the selected shapes storage
|
||||||
self.selected.remove(obj)
|
self.selected.remove(obj)
|
||||||
else:
|
else:
|
||||||
# add the shape object to the selected shapes storage
|
# add the shape object to the selected shapes storage
|
||||||
self.selected.append(obj)
|
self.selected.append(obj)
|
||||||
else:
|
else:
|
||||||
# clear the selection shapes storage
|
# clear the selection shapes storage
|
||||||
self.selected = []
|
self.selected = []
|
||||||
|
@ -3878,7 +3880,8 @@ class FlatCAMExcEditor(QtCore.QObject):
|
||||||
# self.points_edit it's only useful first time when we load the data into the storage
|
# 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()
|
# but is still used as referecen when building tool_table in self.build_ui()
|
||||||
# the number of drills displayed in column 2 is just a len(self.points_edit) therefore
|
# the number of drills displayed in column 2 is just a len(self.points_edit) therefore
|
||||||
# deleting self.points_edit elements (doesn't matter who but just the number) solved the display issue.
|
# deleting self.points_edit elements (doesn't matter who but just the number)
|
||||||
|
# solved the display issue.
|
||||||
del self.points_edit[storage][0]
|
del self.points_edit[storage][0]
|
||||||
else:
|
else:
|
||||||
self.storage_dict[storage].remove(del_shape)
|
self.storage_dict[storage].remove(del_shape)
|
||||||
|
@ -3998,10 +4001,10 @@ class FlatCAMExcEditor(QtCore.QObject):
|
||||||
|
|
||||||
|
|
||||||
def get_shapely_list_bounds(geometry_list):
|
def get_shapely_list_bounds(geometry_list):
|
||||||
xmin = Inf
|
xmin = np.Inf
|
||||||
ymin = Inf
|
ymin = np.Inf
|
||||||
xmax = -Inf
|
xmax = -np.Inf
|
||||||
ymax = -Inf
|
ymax = -np.Inf
|
||||||
|
|
||||||
for gs in geometry_list:
|
for gs in geometry_list:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -13,24 +13,26 @@
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import Qt, QSettings
|
from PyQt5.QtCore import Qt, QSettings
|
||||||
from camlib import *
|
|
||||||
|
from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStorage
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from flatcamGUI.ObjectUI import LengthEntry, RadioSet
|
from flatcamGUI.ObjectUI import RadioSet
|
||||||
|
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
|
||||||
|
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog
|
||||||
|
from flatcamParsers.ParseFont import *
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
|
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
|
||||||
# from shapely.geometry import mapping
|
|
||||||
from shapely.ops import cascaded_union, unary_union
|
from shapely.ops import cascaded_union, unary_union
|
||||||
import shapely.affinity as affinity
|
import shapely.affinity as affinity
|
||||||
from shapely.geometry.polygon import orient
|
from shapely.geometry.polygon import orient
|
||||||
|
|
||||||
from numpy import arctan2, Inf, array, sqrt, sign, dot
|
import numpy as np
|
||||||
from numpy.linalg import norm as numpy_norm
|
from numpy.linalg import norm as numpy_norm
|
||||||
|
|
||||||
from rtree import index as rtindex
|
from rtree import index as rtindex
|
||||||
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
|
|
||||||
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog
|
|
||||||
from flatcamParsers.ParseFont import *
|
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
# from vispy.io import read_png
|
# from vispy.io import read_png
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -684,8 +686,8 @@ class TransformEditorTool(FlatCAMTool):
|
||||||
self.rotate_button.set_value(_("Rotate"))
|
self.rotate_button.set_value(_("Rotate"))
|
||||||
self.rotate_button.setToolTip(
|
self.rotate_button.setToolTip(
|
||||||
_("Rotate the selected shape(s).\n"
|
_("Rotate the selected shape(s).\n"
|
||||||
"The point of reference is the middle of\n"
|
"The point of reference is the middle of\n"
|
||||||
"the bounding box for all selected shapes.")
|
"the bounding box for all selected shapes.")
|
||||||
)
|
)
|
||||||
self.rotate_button.setFixedWidth(60)
|
self.rotate_button.setFixedWidth(60)
|
||||||
|
|
||||||
|
@ -802,7 +804,7 @@ class TransformEditorTool(FlatCAMTool):
|
||||||
self.scale_link_cb.setText(_("Link"))
|
self.scale_link_cb.setText(_("Link"))
|
||||||
self.scale_link_cb.setToolTip(
|
self.scale_link_cb.setToolTip(
|
||||||
_("Scale the selected shape(s)\n"
|
_("Scale the selected shape(s)\n"
|
||||||
"using the Scale Factor X for both axis."))
|
"using the Scale Factor X for both axis."))
|
||||||
self.scale_link_cb.setFixedWidth(50)
|
self.scale_link_cb.setFixedWidth(50)
|
||||||
|
|
||||||
self.scale_zero_ref_cb = FCCheckBox()
|
self.scale_zero_ref_cb = FCCheckBox()
|
||||||
|
@ -1060,7 +1062,6 @@ class TransformEditorTool(FlatCAMTool):
|
||||||
_("Transformation cancelled. No shape selected."))
|
_("Transformation cancelled. No shape selected."))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
self.draw_app.select_tool("select")
|
self.draw_app.select_tool("select")
|
||||||
self.app.ui.notebook.setTabText(2, "Tools")
|
self.app.ui.notebook.setTabText(2, "Tools")
|
||||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||||
|
@ -1081,10 +1082,7 @@ class TransformEditorTool(FlatCAMTool):
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
_("Wrong value format entered, use a number."))
|
_("Wrong value format entered, use a number."))
|
||||||
return
|
return
|
||||||
self.app.worker_task.emit({'fcn': self.on_rotate_action,
|
self.app.worker_task.emit({'fcn': self.on_rotate_action, 'params': [value]})
|
||||||
'params': [value]})
|
|
||||||
# self.on_rotate_action(value)
|
|
||||||
return
|
|
||||||
|
|
||||||
def on_flipx(self):
|
def on_flipx(self):
|
||||||
# self.on_flip("Y")
|
# self.on_flip("Y")
|
||||||
|
@ -1205,13 +1203,9 @@ class TransformEditorTool(FlatCAMTool):
|
||||||
axis = 'Y'
|
axis = 'Y'
|
||||||
point = (0, 0)
|
point = (0, 0)
|
||||||
if self.scale_zero_ref_cb.get_value():
|
if self.scale_zero_ref_cb.get_value():
|
||||||
self.app.worker_task.emit({'fcn': self.on_scale,
|
self.app.worker_task.emit({'fcn': self.on_scale, 'params': [axis, xvalue, yvalue, point]})
|
||||||
'params': [axis, xvalue, yvalue, point]})
|
|
||||||
# self.on_scale("Y", xvalue, yvalue, point=(0,0))
|
|
||||||
else:
|
else:
|
||||||
# self.on_scale("Y", xvalue, yvalue)
|
self.app.worker_task.emit({'fcn': self.on_scale, 'params': [axis, xvalue, yvalue]})
|
||||||
self.app.worker_task.emit({'fcn': self.on_scale,
|
|
||||||
'params': [axis, xvalue, yvalue]})
|
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -1304,7 +1298,7 @@ class TransformEditorTool(FlatCAMTool):
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
||||||
(_("Rotation action was not executed"),str(e)))
|
(_("Rotation action was not executed"), str(e)))
|
||||||
return
|
return
|
||||||
|
|
||||||
def on_flip(self, axis):
|
def on_flip(self, axis):
|
||||||
|
@ -1664,10 +1658,10 @@ class DrawToolShape(object):
|
||||||
# now it can get bounds for nested lists of objects
|
# now it can get bounds for nested lists of objects
|
||||||
def bounds_rec(shape_el):
|
def bounds_rec(shape_el):
|
||||||
if type(shape_el) is list:
|
if type(shape_el) is list:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in shape_el:
|
for k in shape_el:
|
||||||
minx_, miny_, maxx_, maxy_ = bounds_rec(k)
|
minx_, miny_, maxx_, maxy_ = bounds_rec(k)
|
||||||
|
@ -1904,10 +1898,10 @@ class DrawTool(object):
|
||||||
def bounds(self, obj):
|
def bounds(self, obj):
|
||||||
def bounds_rec(o):
|
def bounds_rec(o):
|
||||||
if type(o) is list:
|
if type(o) is list:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in o:
|
for k in o:
|
||||||
try:
|
try:
|
||||||
|
@ -1977,7 +1971,7 @@ class FCCircle(FCShapeTool):
|
||||||
if len(self.points) == 1:
|
if len(self.points) == 1:
|
||||||
p1 = self.points[0]
|
p1 = self.points[0]
|
||||||
p2 = data
|
p2 = data
|
||||||
radius = sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
radius = np.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
||||||
return DrawToolUtilityShape(Point(p1).buffer(radius, int(self.steps_per_circ / 4)))
|
return DrawToolUtilityShape(Point(p1).buffer(radius, int(self.steps_per_circ / 4)))
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
@ -2086,36 +2080,36 @@ class FCArc(FCShapeTool):
|
||||||
p1 = self.points[1]
|
p1 = self.points[1]
|
||||||
p2 = data
|
p2 = data
|
||||||
|
|
||||||
radius = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
radius = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
|
|
||||||
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
||||||
self.direction, self.steps_per_circ)),
|
self.direction, self.steps_per_circ)),
|
||||||
Point(center)])
|
Point(center)])
|
||||||
|
|
||||||
elif self.mode == '132':
|
elif self.mode == '132':
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p3 = array(self.points[1])
|
p3 = np.array(self.points[1])
|
||||||
p2 = array(data)
|
p2 = np.array(data)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
center, radius, t = three_point_circle(p1, p2, p3)
|
center, radius, t = three_point_circle(p1, p2, p3)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return
|
return
|
||||||
|
|
||||||
direction = 'cw' if sign(t) > 0 else 'ccw'
|
direction = 'cw' if np.sign(t) > 0 else 'ccw'
|
||||||
|
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||||
|
|
||||||
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
||||||
direction, self.steps_per_circ)),
|
direction, self.steps_per_circ)),
|
||||||
Point(center), Point(p1), Point(p3)])
|
Point(center), Point(p1), Point(p3)])
|
||||||
|
|
||||||
else: # '12c'
|
else: # '12c'
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p2 = array(self.points[1])
|
p2 = np.array(self.points[1])
|
||||||
|
|
||||||
# Midpoint
|
# Midpoint
|
||||||
a = (p1 + p2) / 2.0
|
a = (p1 + p2) / 2.0
|
||||||
|
@ -2124,7 +2118,7 @@ class FCArc(FCShapeTool):
|
||||||
c = p2 - p1
|
c = p2 - p1
|
||||||
|
|
||||||
# Perpendicular vector
|
# Perpendicular vector
|
||||||
b = dot(c, array([[0, -1], [1, 0]], dtype=float32))
|
b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
|
||||||
b /= numpy_norm(b)
|
b /= numpy_norm(b)
|
||||||
|
|
||||||
# Distance
|
# Distance
|
||||||
|
@ -2133,14 +2127,14 @@ class FCArc(FCShapeTool):
|
||||||
# Which side? Cross product with c.
|
# Which side? Cross product with c.
|
||||||
# cross(M-A, B-A), where line is AB and M is test point.
|
# cross(M-A, B-A), where line is AB and M is test point.
|
||||||
side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0]
|
side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0]
|
||||||
t *= sign(side)
|
t *= np.sign(side)
|
||||||
|
|
||||||
# Center = a + bt
|
# Center = a + bt
|
||||||
center = a + b * t
|
center = a + b * t
|
||||||
|
|
||||||
radius = numpy_norm(center - p1)
|
radius = numpy_norm(center - p1)
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
|
|
||||||
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
||||||
self.direction, self.steps_per_circ)),
|
self.direction, self.steps_per_circ)),
|
||||||
|
@ -2156,29 +2150,29 @@ class FCArc(FCShapeTool):
|
||||||
p2 = self.points[2]
|
p2 = self.points[2]
|
||||||
|
|
||||||
radius = distance(center, p1)
|
radius = distance(center, p1)
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
||||||
self.direction, self.steps_per_circ)))
|
self.direction, self.steps_per_circ)))
|
||||||
|
|
||||||
elif self.mode == '132':
|
elif self.mode == '132':
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p3 = array(self.points[1])
|
p3 = np.array(self.points[1])
|
||||||
p2 = array(self.points[2])
|
p2 = np.array(self.points[2])
|
||||||
|
|
||||||
center, radius, t = three_point_circle(p1, p2, p3)
|
center, radius, t = three_point_circle(p1, p2, p3)
|
||||||
direction = 'cw' if sign(t) > 0 else 'ccw'
|
direction = 'cw' if np.sign(t) > 0 else 'ccw'
|
||||||
|
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||||
|
|
||||||
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
||||||
direction, self.steps_per_circ)))
|
direction, self.steps_per_circ)))
|
||||||
|
|
||||||
else: # self.mode == '12c'
|
else: # self.mode == '12c'
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p2 = array(self.points[1])
|
p2 = np.array(self.points[1])
|
||||||
pc = array(self.points[2])
|
pc = np.array(self.points[2])
|
||||||
|
|
||||||
# Midpoint
|
# Midpoint
|
||||||
a = (p1 + p2) / 2.0
|
a = (p1 + p2) / 2.0
|
||||||
|
@ -2187,7 +2181,7 @@ class FCArc(FCShapeTool):
|
||||||
c = p2 - p1
|
c = p2 - p1
|
||||||
|
|
||||||
# Perpendicular vector
|
# Perpendicular vector
|
||||||
b = dot(c, array([[0, -1], [1, 0]], dtype=float32))
|
b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
|
||||||
b /= numpy_norm(b)
|
b /= numpy_norm(b)
|
||||||
|
|
||||||
# Distance
|
# Distance
|
||||||
|
@ -2196,14 +2190,14 @@ class FCArc(FCShapeTool):
|
||||||
# Which side? Cross product with c.
|
# Which side? Cross product with c.
|
||||||
# cross(M-A, B-A), where line is AB and M is test point.
|
# cross(M-A, B-A), where line is AB and M is test point.
|
||||||
side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0]
|
side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0]
|
||||||
t *= sign(side)
|
t *= np.sign(side)
|
||||||
|
|
||||||
# Center = a + bt
|
# Center = a + bt
|
||||||
center = a + b * t
|
center = a + b * t
|
||||||
|
|
||||||
radius = numpy_norm(center - p1)
|
radius = numpy_norm(center - p1)
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
|
|
||||||
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
||||||
self.direction, self.steps_per_circ)))
|
self.direction, self.steps_per_circ)))
|
||||||
|
@ -2228,7 +2222,7 @@ class FCRectangle(FCShapeTool):
|
||||||
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero.png'))
|
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero.png'))
|
||||||
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
|
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
|
||||||
|
|
||||||
self.draw_app.app.inform.emit( _("Click on 1st corner ..."))
|
self.draw_app.app.inform.emit(_("Click on 1st corner ..."))
|
||||||
|
|
||||||
def click(self, point):
|
def click(self, point):
|
||||||
self.points.append(point)
|
self.points.append(point)
|
||||||
|
@ -2705,7 +2699,6 @@ class FCText(FCShapeTool):
|
||||||
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_text.png'))
|
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_text.png'))
|
||||||
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
|
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
|
||||||
|
|
||||||
|
|
||||||
# self.shape_buffer = self.draw_app.shape_buffer
|
# self.shape_buffer = self.draw_app.shape_buffer
|
||||||
self.draw_app = draw_app
|
self.draw_app = draw_app
|
||||||
self.app = draw_app.app
|
self.app = draw_app.app
|
||||||
|
@ -2728,21 +2721,19 @@ class FCText(FCShapeTool):
|
||||||
log.debug("Font geometry is empty or incorrect: %s" % str(e))
|
log.debug("Font geometry is empty or incorrect: %s" % str(e))
|
||||||
self.draw_app.app.inform.emit('[ERROR] %s: %s' %
|
self.draw_app.app.inform.emit('[ERROR] %s: %s' %
|
||||||
(_("Font not supported. Only Regular, Bold, Italic and BoldItalic are "
|
(_("Font not supported. Only Regular, Bold, Italic and BoldItalic are "
|
||||||
"supported. Error"), str(e)))
|
"supported. Error"), str(e)))
|
||||||
self.text_gui.text_path = []
|
self.text_gui.text_path = []
|
||||||
self.text_gui.hide_tool()
|
self.text_gui.hide_tool()
|
||||||
self.draw_app.select_tool('select')
|
self.draw_app.select_tool('select')
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' %
|
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' % _("No text to add."))
|
||||||
_("No text to add."))
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.text_gui.text_path = []
|
self.text_gui.text_path = []
|
||||||
self.text_gui.hide_tool()
|
self.text_gui.hide_tool()
|
||||||
self.complete = True
|
self.complete = True
|
||||||
self.draw_app.app.inform.emit('[success]%s' %
|
self.draw_app.app.inform.emit('[success]%s' % _(" Done. Adding Text completed."))
|
||||||
_(" Done. Adding Text completed."))
|
|
||||||
|
|
||||||
def utility_geometry(self, data=None):
|
def utility_geometry(self, data=None):
|
||||||
"""
|
"""
|
||||||
|
@ -3060,7 +3051,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
"text": {"button": self.app.ui.geo_add_text_btn,
|
"text": {"button": self.app.ui.geo_add_text_btn,
|
||||||
"constructor": FCText},
|
"constructor": FCText},
|
||||||
"buffer": {"button": self.app.ui.geo_add_buffer_btn,
|
"buffer": {"button": self.app.ui.geo_add_buffer_btn,
|
||||||
"constructor": FCBuffer},
|
"constructor": FCBuffer},
|
||||||
"paint": {"button": self.app.ui.geo_add_paint_btn,
|
"paint": {"button": self.app.ui.geo_add_paint_btn,
|
||||||
"constructor": FCPaint},
|
"constructor": FCPaint},
|
||||||
"eraser": {"button": self.app.ui.geo_eraser_btn,
|
"eraser": {"button": self.app.ui.geo_eraser_btn,
|
||||||
|
@ -3068,11 +3059,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
"move": {"button": self.app.ui.geo_move_btn,
|
"move": {"button": self.app.ui.geo_move_btn,
|
||||||
"constructor": FCMove},
|
"constructor": FCMove},
|
||||||
"transform": {"button": self.app.ui.geo_transform_btn,
|
"transform": {"button": self.app.ui.geo_transform_btn,
|
||||||
"constructor": FCTransform},
|
"constructor": FCTransform},
|
||||||
"copy": {"button": self.app.ui.geo_copy_btn,
|
"copy": {"button": self.app.ui.geo_copy_btn,
|
||||||
"constructor": FCCopy},
|
"constructor": FCCopy},
|
||||||
"explode": {"button": self.app.ui.geo_explode_btn,
|
"explode": {"button": self.app.ui.geo_explode_btn,
|
||||||
"constructor": FCExplode}
|
"constructor": FCExplode}
|
||||||
}
|
}
|
||||||
|
|
||||||
# # ## Data
|
# # ## Data
|
||||||
|
@ -3502,7 +3493,6 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.app.ui.draw_text.triggered.disconnect()
|
self.app.ui.draw_text.triggered.disconnect()
|
||||||
except (TypeError, AttributeError):
|
except (TypeError, AttributeError):
|
||||||
|
@ -3561,12 +3551,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
self.add_shape(subshape)
|
self.add_shape(subshape)
|
||||||
return
|
return
|
||||||
|
|
||||||
assert isinstance(shape, DrawToolShape), \
|
assert isinstance(shape, DrawToolShape), "Expected a DrawToolShape, got %s" % type(shape)
|
||||||
"Expected a DrawToolShape, got %s" % type(shape)
|
assert shape.geo is not None, "Shape object has empty geometry (None)"
|
||||||
|
|
||||||
assert shape.geo is not None, \
|
|
||||||
"Shape object has empty geometry (None)"
|
|
||||||
|
|
||||||
assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or \
|
assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or \
|
||||||
not isinstance(shape.geo, list), "Shape objects has empty geometry ([])"
|
not isinstance(shape.geo, list), "Shape objects has empty geometry ([])"
|
||||||
|
|
||||||
|
@ -4122,13 +4108,17 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if shape in self.selected:
|
if shape in self.selected:
|
||||||
self.plot_shape(geometry=shape.geo, color=self.app.defaults['global_sel_draw_color'] + 'FF', linewidth=2)
|
self.plot_shape(geometry=shape.geo,
|
||||||
|
color=self.app.defaults['global_sel_draw_color'] + 'FF',
|
||||||
|
linewidth=2)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.plot_shape(geometry=shape.geo, color=self.app.defaults['global_draw_color'] + "FF")
|
self.plot_shape(geometry=shape.geo,
|
||||||
|
color=self.app.defaults['global_draw_color'] + "FF")
|
||||||
|
|
||||||
for shape in self.utility:
|
for shape in self.utility:
|
||||||
self.plot_shape(geometry=shape.geo, linewidth=1)
|
self.plot_shape(geometry=shape.geo,
|
||||||
|
linewidth=1)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self.shapes.redraw()
|
self.shapes.redraw()
|
||||||
|
@ -4237,7 +4227,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
snap_x, snap_y = (x, y)
|
snap_x, snap_y = (x, y)
|
||||||
snap_distance = Inf
|
snap_distance = np.Inf
|
||||||
|
|
||||||
# # ## Object (corner?) snap
|
# # ## Object (corner?) snap
|
||||||
# # ## No need for the objects, just the coordinates
|
# # ## No need for the objects, just the coordinates
|
||||||
|
@ -4488,7 +4478,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
results = []
|
results = []
|
||||||
for t in selected:
|
for t in selected:
|
||||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
||||||
results.append((t.geo.exterior).buffer(
|
results.append(t.geo.exterior.buffer(
|
||||||
buf_distance - 1e-10,
|
buf_distance - 1e-10,
|
||||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
join_style=join_style)
|
join_style=join_style)
|
||||||
|
@ -4519,22 +4509,18 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
|
|
||||||
if buf_distance < 0:
|
if buf_distance < 0:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Negative buffer value is not accepted."))
|
||||||
_("Negative buffer value is not accepted.")
|
|
||||||
)
|
|
||||||
# deselect everything
|
# deselect everything
|
||||||
self.selected = []
|
self.selected = []
|
||||||
self.replot()
|
self.replot()
|
||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
if len(selected) == 0:
|
if len(selected) == 0:
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Nothing selected for buffering."))
|
||||||
_("Nothing selected for buffering."))
|
|
||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
if not isinstance(buf_distance, float):
|
if not isinstance(buf_distance, float):
|
||||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Invalid distance for buffering."))
|
||||||
_("Invalid distance for buffering."))
|
|
||||||
# deselect everything
|
# deselect everything
|
||||||
self.selected = []
|
self.selected = []
|
||||||
self.replot()
|
self.replot()
|
||||||
|
@ -4546,7 +4532,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
t.geo = Polygon(t.geo)
|
t.geo = Polygon(t.geo)
|
||||||
|
|
||||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
||||||
results.append((t.geo).buffer(
|
results.append(t.geo.buffer(
|
||||||
-buf_distance + 1e-10,
|
-buf_distance + 1e-10,
|
||||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
join_style=join_style)
|
join_style=join_style)
|
||||||
|
@ -4564,8 +4550,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
self.add_shape(DrawToolShape(sha))
|
self.add_shape(DrawToolShape(sha))
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
self.app.inform.emit('[success] %s' %
|
self.app.inform.emit('[success] %s' % _("Interior buffer geometry created."))
|
||||||
_("Interior buffer geometry created."))
|
|
||||||
|
|
||||||
def buffer_ext(self, buf_distance, join_style):
|
def buffer_ext(self, buf_distance, join_style):
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
|
@ -4598,7 +4583,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
t.geo = Polygon(t.geo)
|
t.geo = Polygon(t.geo)
|
||||||
|
|
||||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
||||||
results.append((t.geo).buffer(
|
results.append(t.geo.buffer(
|
||||||
buf_distance,
|
buf_distance,
|
||||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||||
join_style=join_style)
|
join_style=join_style)
|
||||||
|
@ -4616,68 +4601,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
self.add_shape(DrawToolShape(sha))
|
self.add_shape(DrawToolShape(sha))
|
||||||
|
|
||||||
self.replot()
|
self.replot()
|
||||||
self.app.inform.emit('[success] %s' %
|
self.app.inform.emit('[success] %s' % _("Exterior buffer geometry created."))
|
||||||
_("Exterior buffer geometry created."))
|
|
||||||
|
|
||||||
# def paint(self, tooldia, overlap, margin, method):
|
|
||||||
# selected = self.get_selected()
|
|
||||||
#
|
|
||||||
# if len(selected) == 0:
|
|
||||||
# self.app.inform.emit("[WARNING] Nothing selected for painting.")
|
|
||||||
# return
|
|
||||||
#
|
|
||||||
# for param in [tooldia, overlap, margin]:
|
|
||||||
# if not isinstance(param, float):
|
|
||||||
# param_name = [k for k, v in locals().items() if v is param][0]
|
|
||||||
# self.app.inform.emit("[WARNING] Invalid value for {}".format(param))
|
|
||||||
#
|
|
||||||
# # Todo: Check for valid method.
|
|
||||||
#
|
|
||||||
# # Todo: This is the 3rd implementation on painting polys... try to consolidate
|
|
||||||
#
|
|
||||||
# results = []
|
|
||||||
#
|
|
||||||
# def recurse(geo):
|
|
||||||
# try:
|
|
||||||
# for subg in geo:
|
|
||||||
# for subsubg in recurse(subg):
|
|
||||||
# yield subsubg
|
|
||||||
# except TypeError:
|
|
||||||
# if isinstance(geo, LinearRing):
|
|
||||||
# yield geo
|
|
||||||
#
|
|
||||||
# raise StopIteration
|
|
||||||
#
|
|
||||||
# for geo in selected:
|
|
||||||
# print(type(geo.geo))
|
|
||||||
#
|
|
||||||
# local_results = []
|
|
||||||
# for poly in recurse(geo.geo):
|
|
||||||
# if method == "seed":
|
|
||||||
# # Type(cp) == FlatCAMRTreeStorage | None
|
|
||||||
# cp = Geometry.clear_polygon2(poly.buffer(-margin),
|
|
||||||
# tooldia, overlap=overlap)
|
|
||||||
#
|
|
||||||
# else:
|
|
||||||
# # Type(cp) == FlatCAMRTreeStorage | None
|
|
||||||
# cp = Geometry.clear_polygon(poly.buffer(-margin),
|
|
||||||
# tooldia, overlap=overlap)
|
|
||||||
#
|
|
||||||
# if cp is not None:
|
|
||||||
# local_results += list(cp.get_objects())
|
|
||||||
#
|
|
||||||
# results.append(cascaded_union(local_results))
|
|
||||||
#
|
|
||||||
# # This is a dirty patch:
|
|
||||||
# for r in results:
|
|
||||||
# self.add_shape(DrawToolShape(r))
|
|
||||||
#
|
|
||||||
# self.replot()
|
|
||||||
|
|
||||||
def paint(self, tooldia, overlap, margin, connect, contour, method):
|
def paint(self, tooldia, overlap, margin, connect, contour, method):
|
||||||
|
|
||||||
self.paint_tooldia = tooldia
|
self.paint_tooldia = tooldia
|
||||||
|
|
||||||
selected = self.get_selected()
|
selected = self.get_selected()
|
||||||
|
|
||||||
if len(selected) == 0:
|
if len(selected) == 0:
|
||||||
|
@ -4814,11 +4742,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
||||||
|
|
||||||
|
|
||||||
def distance(pt1, pt2):
|
def distance(pt1, pt2):
|
||||||
return sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
|
return np.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
|
||||||
|
|
||||||
|
|
||||||
def mag(vec):
|
def mag(vec):
|
||||||
return sqrt(vec[0] ** 2 + vec[1] ** 2)
|
return np.sqrt(vec[0] ** 2 + vec[1] ** 2)
|
||||||
|
|
||||||
|
|
||||||
def poly2rings(poly):
|
def poly2rings(poly):
|
||||||
|
@ -4826,10 +4754,10 @@ def poly2rings(poly):
|
||||||
|
|
||||||
|
|
||||||
def get_shapely_list_bounds(geometry_list):
|
def get_shapely_list_bounds(geometry_list):
|
||||||
xmin = Inf
|
xmin = np.Inf
|
||||||
ymin = Inf
|
ymin = np.Inf
|
||||||
xmax = -Inf
|
xmax = -np.Inf
|
||||||
ymax = -Inf
|
ymax = -np.Inf
|
||||||
|
|
||||||
for gs in geometry_list:
|
for gs in geometry_list:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -8,29 +8,28 @@
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import Qt, QSettings
|
from PyQt5.QtCore import Qt, QSettings
|
||||||
|
|
||||||
from shapely.geometry import LineString, LinearRing, MultiLineString
|
from shapely.geometry import LineString, LinearRing, MultiLineString, Point, Polygon, MultiPolygon
|
||||||
# from shapely.geometry import mapping
|
from shapely.ops import cascaded_union
|
||||||
from shapely.ops import cascaded_union, unary_union
|
|
||||||
import shapely.affinity as affinity
|
import shapely.affinity as affinity
|
||||||
|
|
||||||
from numpy import arctan2, Inf, array, sqrt, sign, dot
|
|
||||||
from rtree import index as rtindex
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
|
import logging
|
||||||
|
|
||||||
from camlib import *
|
from camlib import distance, arc, three_point_circle
|
||||||
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, \
|
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, \
|
||||||
SpinBoxDelegate, EvalEntry, EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
|
EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
|
||||||
from FlatCAMObj import FlatCAMGerber
|
|
||||||
from flatcamParsers.ParseGerber import Gerber
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
from numpy.linalg import norm as numpy_norm
|
from numpy.linalg import norm as numpy_norm
|
||||||
|
import math
|
||||||
|
|
||||||
# from vispy.io import read_png
|
# from vispy.io import read_png
|
||||||
# import pngcanvas
|
# import pngcanvas
|
||||||
|
import traceback
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -39,6 +38,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class DrawToolShape(object):
|
class DrawToolShape(object):
|
||||||
"""
|
"""
|
||||||
|
@ -147,10 +148,10 @@ class DrawTool(object):
|
||||||
def bounds(obj):
|
def bounds(obj):
|
||||||
def bounds_rec(o):
|
def bounds_rec(o):
|
||||||
if type(o) is list:
|
if type(o) is list:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in o:
|
for k in o:
|
||||||
try:
|
try:
|
||||||
|
@ -311,13 +312,13 @@ class FCPad(FCShapeTool):
|
||||||
p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width)
|
p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width)
|
||||||
|
|
||||||
down_center = [point_x, point_y - self.half_height + self.half_width]
|
down_center = [point_x, point_y - self.half_height + self.half_width]
|
||||||
d_start_angle = math.pi
|
d_start_angle = np.pi
|
||||||
d_stop_angle = 0.0
|
d_stop_angle = 0.0
|
||||||
down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
up_center = [point_x, point_y + self.half_height - self.half_width]
|
up_center = [point_x, point_y + self.half_height - self.half_width]
|
||||||
u_start_angle = 0.0
|
u_start_angle = 0.0
|
||||||
u_stop_angle = math.pi
|
u_stop_angle = np.pi
|
||||||
up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
geo.append(p1)
|
geo.append(p1)
|
||||||
|
@ -340,13 +341,13 @@ class FCPad(FCShapeTool):
|
||||||
p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height)
|
p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height)
|
||||||
|
|
||||||
left_center = [point_x - self.half_width + self.half_height, point_y]
|
left_center = [point_x - self.half_width + self.half_height, point_y]
|
||||||
d_start_angle = math.pi / 2
|
d_start_angle = np.pi / 2
|
||||||
d_stop_angle = 1.5 * math.pi
|
d_stop_angle = 1.5 * np.pi
|
||||||
left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
right_center = [point_x + self.half_width - self.half_height, point_y]
|
right_center = [point_x + self.half_width - self.half_height, point_y]
|
||||||
u_start_angle = 1.5 * math.pi
|
u_start_angle = 1.5 * np.pi
|
||||||
u_stop_angle = math.pi / 2
|
u_stop_angle = np.pi / 2
|
||||||
right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
geo.append(p1)
|
geo.append(p1)
|
||||||
|
@ -618,13 +619,13 @@ class FCPadArray(FCShapeTool):
|
||||||
p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width)
|
p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width)
|
||||||
|
|
||||||
down_center = [point_x, point_y - self.half_height + self.half_width]
|
down_center = [point_x, point_y - self.half_height + self.half_width]
|
||||||
d_start_angle = math.pi
|
d_start_angle = np.pi
|
||||||
d_stop_angle = 0.0
|
d_stop_angle = 0.0
|
||||||
down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
up_center = [point_x, point_y + self.half_height - self.half_width]
|
up_center = [point_x, point_y + self.half_height - self.half_width]
|
||||||
u_start_angle = 0.0
|
u_start_angle = 0.0
|
||||||
u_stop_angle = math.pi
|
u_stop_angle = np.pi
|
||||||
up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
geo.append(p1)
|
geo.append(p1)
|
||||||
|
@ -647,13 +648,13 @@ class FCPadArray(FCShapeTool):
|
||||||
p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height)
|
p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height)
|
||||||
|
|
||||||
left_center = [point_x - self.half_width + self.half_height, point_y]
|
left_center = [point_x - self.half_width + self.half_height, point_y]
|
||||||
d_start_angle = math.pi / 2
|
d_start_angle = np.pi / 2
|
||||||
d_stop_angle = 1.5 * math.pi
|
d_stop_angle = 1.5 * np.pi
|
||||||
left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
right_center = [point_x + self.half_width - self.half_height, point_y]
|
right_center = [point_x + self.half_width - self.half_height, point_y]
|
||||||
u_start_angle = 1.5 * math.pi
|
u_start_angle = 1.5 * np.pi
|
||||||
u_stop_angle = math.pi / 2
|
u_stop_angle = np.pi / 2
|
||||||
right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
|
||||||
|
|
||||||
geo.append(p1)
|
geo.append(p1)
|
||||||
|
@ -1296,7 +1297,7 @@ class FCTrack(FCRegion):
|
||||||
self.draw_app.bend_mode = 2
|
self.draw_app.bend_mode = 2
|
||||||
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path2.png'))
|
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path2.png'))
|
||||||
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
|
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
|
||||||
msg = _('Track Mode 2: Reverse 45 degrees ...')
|
msg = _('Track Mode 2: Reverse 45 degrees ...')
|
||||||
elif self.draw_app.bend_mode == 2:
|
elif self.draw_app.bend_mode == 2:
|
||||||
self.draw_app.bend_mode = 3
|
self.draw_app.bend_mode = 3
|
||||||
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path3.png'))
|
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path3.png'))
|
||||||
|
@ -1415,7 +1416,7 @@ class FCDisc(FCShapeTool):
|
||||||
if len(self.points) == 1:
|
if len(self.points) == 1:
|
||||||
p1 = self.points[0]
|
p1 = self.points[0]
|
||||||
p2 = data
|
p2 = data
|
||||||
radius = sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
radius = math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
|
||||||
new_geo_el['solid'] = Point(p1).buffer((radius + self.buf_val / 2), int(self.steps_per_circ / 4))
|
new_geo_el['solid'] = Point(p1).buffer((radius + self.buf_val / 2), int(self.steps_per_circ / 4))
|
||||||
return DrawToolUtilityShape(new_geo_el)
|
return DrawToolUtilityShape(new_geo_el)
|
||||||
|
|
||||||
|
@ -1557,9 +1558,9 @@ class FCSemiDisc(FCShapeTool):
|
||||||
p1 = self.points[1]
|
p1 = self.points[1]
|
||||||
p2 = data
|
p2 = data
|
||||||
|
|
||||||
radius = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2) + (self.buf_val / 2)
|
radius = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2) + (self.buf_val / 2)
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
|
|
||||||
new_geo_el['solid'] = LineString(
|
new_geo_el['solid'] = LineString(
|
||||||
arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ))
|
arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ))
|
||||||
|
@ -1567,20 +1568,20 @@ class FCSemiDisc(FCShapeTool):
|
||||||
return DrawToolUtilityShape([new_geo_el, new_geo_el_pt1])
|
return DrawToolUtilityShape([new_geo_el, new_geo_el_pt1])
|
||||||
|
|
||||||
elif self.mode == '132':
|
elif self.mode == '132':
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p3 = array(self.points[1])
|
p3 = np.array(self.points[1])
|
||||||
p2 = array(data)
|
p2 = np.array(data)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
center, radius, t = three_point_circle(p1, p2, p3)
|
center, radius, t = three_point_circle(p1, p2, p3)
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return
|
return
|
||||||
|
|
||||||
direction = 'cw' if sign(t) > 0 else 'ccw'
|
direction = 'cw' if np.sign(t) > 0 else 'ccw'
|
||||||
radius += (self.buf_val / 2)
|
radius += (self.buf_val / 2)
|
||||||
|
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||||
|
|
||||||
new_geo_el['solid'] = LineString(
|
new_geo_el['solid'] = LineString(
|
||||||
arc(center, radius, startangle, stopangle, direction, self.steps_per_circ))
|
arc(center, radius, startangle, stopangle, direction, self.steps_per_circ))
|
||||||
|
@ -1591,8 +1592,8 @@ class FCSemiDisc(FCShapeTool):
|
||||||
return DrawToolUtilityShape([new_geo_el, new_geo_el_pt2, new_geo_el_pt1, new_geo_el_pt3])
|
return DrawToolUtilityShape([new_geo_el, new_geo_el_pt2, new_geo_el_pt1, new_geo_el_pt3])
|
||||||
|
|
||||||
else: # '12c'
|
else: # '12c'
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p2 = array(self.points[1])
|
p2 = np.array(self.points[1])
|
||||||
# Midpoint
|
# Midpoint
|
||||||
a = (p1 + p2) / 2.0
|
a = (p1 + p2) / 2.0
|
||||||
|
|
||||||
|
@ -1600,7 +1601,7 @@ class FCSemiDisc(FCShapeTool):
|
||||||
c = p2 - p1
|
c = p2 - p1
|
||||||
|
|
||||||
# Perpendicular vector
|
# Perpendicular vector
|
||||||
b = dot(c, array([[0, -1], [1, 0]], dtype=float32))
|
b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
|
||||||
b /= numpy_norm(b)
|
b /= numpy_norm(b)
|
||||||
|
|
||||||
# Distance
|
# Distance
|
||||||
|
@ -1609,14 +1610,14 @@ class FCSemiDisc(FCShapeTool):
|
||||||
# Which side? Cross product with c.
|
# Which side? Cross product with c.
|
||||||
# cross(M-A, B-A), where line is AB and M is test point.
|
# cross(M-A, B-A), where line is AB and M is test point.
|
||||||
side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0]
|
side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0]
|
||||||
t *= sign(side)
|
t *= np.sign(side)
|
||||||
|
|
||||||
# Center = a + bt
|
# Center = a + bt
|
||||||
center = a + b * t
|
center = a + b * t
|
||||||
|
|
||||||
radius = numpy_norm(center - p1) + (self.buf_val / 2)
|
radius = numpy_norm(center - p1) + (self.buf_val / 2)
|
||||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
|
|
||||||
new_geo_el['solid'] = LineString(
|
new_geo_el['solid'] = LineString(
|
||||||
arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ))
|
arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ))
|
||||||
|
@ -1636,8 +1637,8 @@ class FCSemiDisc(FCShapeTool):
|
||||||
p2 = self.points[2]
|
p2 = self.points[2]
|
||||||
|
|
||||||
radius = distance(center, p1) + (self.buf_val / 2)
|
radius = distance(center, p1) + (self.buf_val / 2)
|
||||||
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stop_angle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stop_angle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
new_geo_el['solid'] = Polygon(
|
new_geo_el['solid'] = Polygon(
|
||||||
arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ))
|
arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ))
|
||||||
new_geo_el['follow'] = Polygon(
|
new_geo_el['follow'] = Polygon(
|
||||||
|
@ -1645,16 +1646,16 @@ class FCSemiDisc(FCShapeTool):
|
||||||
self.geometry = DrawToolShape(new_geo_el)
|
self.geometry = DrawToolShape(new_geo_el)
|
||||||
|
|
||||||
elif self.mode == '132':
|
elif self.mode == '132':
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p3 = array(self.points[1])
|
p3 = np.array(self.points[1])
|
||||||
p2 = array(self.points[2])
|
p2 = np.array(self.points[2])
|
||||||
|
|
||||||
center, radius, t = three_point_circle(p1, p2, p3)
|
center, radius, t = three_point_circle(p1, p2, p3)
|
||||||
direction = 'cw' if sign(t) > 0 else 'ccw'
|
direction = 'cw' if np.sign(t) > 0 else 'ccw'
|
||||||
radius += (self.buf_val / 2)
|
radius += (self.buf_val / 2)
|
||||||
|
|
||||||
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stop_angle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
stop_angle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||||
|
|
||||||
new_geo_el['solid'] = Polygon(arc(center, radius, start_angle, stop_angle, direction, self.steps_per_circ))
|
new_geo_el['solid'] = Polygon(arc(center, radius, start_angle, stop_angle, direction, self.steps_per_circ))
|
||||||
new_geo_el['follow'] = Polygon(
|
new_geo_el['follow'] = Polygon(
|
||||||
|
@ -1662,9 +1663,9 @@ class FCSemiDisc(FCShapeTool):
|
||||||
self.geometry = DrawToolShape(new_geo_el)
|
self.geometry = DrawToolShape(new_geo_el)
|
||||||
|
|
||||||
else: # self.mode == '12c'
|
else: # self.mode == '12c'
|
||||||
p1 = array(self.points[0])
|
p1 = np.array(self.points[0])
|
||||||
p2 = array(self.points[1])
|
p2 = np.array(self.points[1])
|
||||||
pc = array(self.points[2])
|
pc = np.array(self.points[2])
|
||||||
|
|
||||||
# Midpoint
|
# Midpoint
|
||||||
a = (p1 + p2) / 2.0
|
a = (p1 + p2) / 2.0
|
||||||
|
@ -1673,7 +1674,7 @@ class FCSemiDisc(FCShapeTool):
|
||||||
c = p2 - p1
|
c = p2 - p1
|
||||||
|
|
||||||
# Perpendicular vector
|
# Perpendicular vector
|
||||||
b = dot(c, array([[0, -1], [1, 0]], dtype=float32))
|
b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
|
||||||
b /= numpy_norm(b)
|
b /= numpy_norm(b)
|
||||||
|
|
||||||
# Distance
|
# Distance
|
||||||
|
@ -1682,14 +1683,14 @@ class FCSemiDisc(FCShapeTool):
|
||||||
# Which side? Cross product with c.
|
# Which side? Cross product with c.
|
||||||
# cross(M-A, B-A), where line is AB and M is test point.
|
# cross(M-A, B-A), where line is AB and M is test point.
|
||||||
side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0]
|
side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0]
|
||||||
t *= sign(side)
|
t *= np.sign(side)
|
||||||
|
|
||||||
# Center = a + bt
|
# Center = a + bt
|
||||||
center = a + b * t
|
center = a + b * t
|
||||||
|
|
||||||
radius = numpy_norm(center - p1) + (self.buf_val / 2)
|
radius = numpy_norm(center - p1) + (self.buf_val / 2)
|
||||||
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||||
stop_angle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
stop_angle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||||
|
|
||||||
new_geo_el['solid'] = Polygon(
|
new_geo_el['solid'] = Polygon(
|
||||||
arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ))
|
arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ))
|
||||||
|
@ -2437,9 +2438,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
self.apertures_box.addLayout(grid1)
|
self.apertures_box.addLayout(grid1)
|
||||||
|
|
||||||
apcode_lbl = QtWidgets.QLabel('%s:' % _('Aperture Code'))
|
apcode_lbl = QtWidgets.QLabel('%s:' % _('Aperture Code'))
|
||||||
apcode_lbl.setToolTip(
|
apcode_lbl.setToolTip(_("Code for the new aperture"))
|
||||||
_("Code for the new aperture")
|
|
||||||
)
|
|
||||||
grid1.addWidget(apcode_lbl, 1, 0)
|
grid1.addWidget(apcode_lbl, 1, 0)
|
||||||
|
|
||||||
self.apcode_entry = FCEntry()
|
self.apcode_entry = FCEntry()
|
||||||
|
@ -2448,11 +2447,11 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
|
|
||||||
apsize_lbl = QtWidgets.QLabel('%s:' % _('Aperture Size'))
|
apsize_lbl = QtWidgets.QLabel('%s:' % _('Aperture Size'))
|
||||||
apsize_lbl.setToolTip(
|
apsize_lbl.setToolTip(
|
||||||
_("Size for the new aperture.\n"
|
_("Size for the new aperture.\n"
|
||||||
"If aperture type is 'R' or 'O' then\n"
|
"If aperture type is 'R' or 'O' then\n"
|
||||||
"this value is automatically\n"
|
"this value is automatically\n"
|
||||||
"calculated as:\n"
|
"calculated as:\n"
|
||||||
"sqrt(width**2 + height**2)")
|
"sqrt(width**2 + height**2)")
|
||||||
)
|
)
|
||||||
grid1.addWidget(apsize_lbl, 2, 0)
|
grid1.addWidget(apsize_lbl, 2, 0)
|
||||||
|
|
||||||
|
@ -2462,10 +2461,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
|
|
||||||
aptype_lbl = QtWidgets.QLabel('%s:' % _('Aperture Type'))
|
aptype_lbl = QtWidgets.QLabel('%s:' % _('Aperture Type'))
|
||||||
aptype_lbl.setToolTip(
|
aptype_lbl.setToolTip(
|
||||||
_("Select the type of new aperture. Can be:\n"
|
_("Select the type of new aperture. Can be:\n"
|
||||||
"C = circular\n"
|
"C = circular\n"
|
||||||
"R = rectangular\n"
|
"R = rectangular\n"
|
||||||
"O = oblong")
|
"O = oblong")
|
||||||
)
|
)
|
||||||
grid1.addWidget(aptype_lbl, 3, 0)
|
grid1.addWidget(aptype_lbl, 3, 0)
|
||||||
|
|
||||||
|
@ -2475,9 +2474,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
|
|
||||||
self.apdim_lbl = QtWidgets.QLabel('%s:' % _('Aperture Dim'))
|
self.apdim_lbl = QtWidgets.QLabel('%s:' % _('Aperture Dim'))
|
||||||
self.apdim_lbl.setToolTip(
|
self.apdim_lbl.setToolTip(
|
||||||
_("Dimensions for the new aperture.\n"
|
_("Dimensions for the new aperture.\n"
|
||||||
"Active only for rectangular apertures (type R).\n"
|
"Active only for rectangular apertures (type R).\n"
|
||||||
"The format is (width, height)")
|
"The format is (width, height)")
|
||||||
)
|
)
|
||||||
grid1.addWidget(self.apdim_lbl, 4, 0)
|
grid1.addWidget(self.apdim_lbl, 4, 0)
|
||||||
|
|
||||||
|
@ -2495,12 +2494,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
|
|
||||||
self.addaperture_btn = QtWidgets.QPushButton(_('Add'))
|
self.addaperture_btn = QtWidgets.QPushButton(_('Add'))
|
||||||
self.addaperture_btn.setToolTip(
|
self.addaperture_btn.setToolTip(
|
||||||
_( "Add a new aperture to the aperture list.")
|
_("Add a new aperture to the aperture list.")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.delaperture_btn = QtWidgets.QPushButton(_('Delete'))
|
self.delaperture_btn = QtWidgets.QPushButton(_('Delete'))
|
||||||
self.delaperture_btn.setToolTip(
|
self.delaperture_btn.setToolTip(
|
||||||
_( "Delete a aperture in the aperture list")
|
_("Delete a aperture in the aperture list")
|
||||||
)
|
)
|
||||||
hlay_ad.addWidget(self.addaperture_btn)
|
hlay_ad.addWidget(self.addaperture_btn)
|
||||||
hlay_ad.addWidget(self.delaperture_btn)
|
hlay_ad.addWidget(self.delaperture_btn)
|
||||||
|
@ -2677,8 +2676,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
|
|
||||||
self.array_type_combo = FCComboBox()
|
self.array_type_combo = FCComboBox()
|
||||||
self.array_type_combo.setToolTip(
|
self.array_type_combo.setToolTip(
|
||||||
_( "Select the type of pads array to create.\n"
|
_("Select the type of pads array to create.\n"
|
||||||
"It can be Linear X(Y) or Circular")
|
"It can be Linear X(Y) or Circular")
|
||||||
)
|
)
|
||||||
self.array_type_combo.addItem(_("Linear"))
|
self.array_type_combo.addItem(_("Linear"))
|
||||||
self.array_type_combo.addItem(_("Circular"))
|
self.array_type_combo.addItem(_("Circular"))
|
||||||
|
@ -2733,10 +2732,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
|
|
||||||
self.linear_angle_label = QtWidgets.QLabel('%s:' % _('Angle'))
|
self.linear_angle_label = QtWidgets.QLabel('%s:' % _('Angle'))
|
||||||
self.linear_angle_label.setToolTip(
|
self.linear_angle_label.setToolTip(
|
||||||
_( "Angle at which the linear array is placed.\n"
|
_("Angle at which the linear array is placed.\n"
|
||||||
"The precision is of max 2 decimals.\n"
|
"The precision is of max 2 decimals.\n"
|
||||||
"Min value is: -359.99 degrees.\n"
|
"Min value is: -359.99 degrees.\n"
|
||||||
"Max value is: 360.00 degrees.")
|
"Max value is: 360.00 degrees.")
|
||||||
)
|
)
|
||||||
self.linear_angle_label.setMinimumWidth(100)
|
self.linear_angle_label.setMinimumWidth(100)
|
||||||
|
|
||||||
|
@ -2808,9 +2807,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
"scale": {"button": self.app.ui.aperture_scale_btn,
|
"scale": {"button": self.app.ui.aperture_scale_btn,
|
||||||
"constructor": FCScale},
|
"constructor": FCScale},
|
||||||
"markarea": {"button": self.app.ui.aperture_markarea_btn,
|
"markarea": {"button": self.app.ui.aperture_markarea_btn,
|
||||||
"constructor": FCMarkArea},
|
"constructor": FCMarkArea},
|
||||||
"eraser": {"button": self.app.ui.aperture_eraser_btn,
|
"eraser": {"button": self.app.ui.aperture_eraser_btn,
|
||||||
"constructor": FCEraser},
|
"constructor": FCEraser},
|
||||||
"copy": {"button": self.app.ui.aperture_copy_btn,
|
"copy": {"button": self.app.ui.aperture_copy_btn,
|
||||||
"constructor": FCApertureCopy},
|
"constructor": FCApertureCopy},
|
||||||
"transform": {"button": self.app.ui.grb_transform_btn,
|
"transform": {"button": self.app.ui.grb_transform_btn,
|
||||||
|
@ -3245,7 +3244,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
self.storage_dict[ap_id]['width'] = dims[0]
|
self.storage_dict[ap_id]['width'] = dims[0]
|
||||||
self.storage_dict[ap_id]['height'] = dims[1]
|
self.storage_dict[ap_id]['height'] = dims[1]
|
||||||
|
|
||||||
size_val = math.sqrt((dims[0] ** 2) + (dims[1] ** 2))
|
size_val = np.sqrt((dims[0] ** 2) + (dims[1] ** 2))
|
||||||
self.apsize_entry.set_value(size_val)
|
self.apsize_entry.set_value(size_val)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -3613,7 +3612,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
self.app.ui.grb_draw_eraser.triggered.connect(self.on_eraser)
|
self.app.ui.grb_draw_eraser.triggered.connect(self.on_eraser)
|
||||||
self.app.ui.grb_draw_transformations.triggered.connect(self.on_transform)
|
self.app.ui.grb_draw_transformations.triggered.connect(self.on_transform)
|
||||||
|
|
||||||
|
|
||||||
def disconnect_canvas_event_handlers(self):
|
def disconnect_canvas_event_handlers(self):
|
||||||
|
|
||||||
# we restore the key and mouse control to FlatCAMApp method
|
# we restore the key and mouse control to FlatCAMApp method
|
||||||
|
@ -3803,7 +3801,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
||||||
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of clear geometry
|
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of clear geometry
|
||||||
# that fits inside the solid. otherwise we may loose the solid
|
# that fits inside the solid. otherwise we may loose the solid
|
||||||
for apid in self.gerber_obj.apertures:
|
for apid in self.gerber_obj.apertures:
|
||||||
temp_solid_geometry= []
|
temp_solid_geometry = []
|
||||||
if 'geometry' in self.gerber_obj.apertures[apid]:
|
if 'geometry' in self.gerber_obj.apertures[apid]:
|
||||||
# for elem in self.gerber_obj.apertures[apid]['geometry']:
|
# for elem in self.gerber_obj.apertures[apid]['geometry']:
|
||||||
# if 'solid' in elem:
|
# if 'solid' in elem:
|
||||||
|
@ -6032,10 +6030,10 @@ class TransformEditorTool(FlatCAMTool):
|
||||||
|
|
||||||
|
|
||||||
def get_shapely_list_bounds(geometry_list):
|
def get_shapely_list_bounds(geometry_list):
|
||||||
xmin = Inf
|
xmin = np.Inf
|
||||||
ymin = Inf
|
ymin = np.Inf
|
||||||
xmax = -Inf
|
xmax = -np.Inf
|
||||||
ymax = -Inf
|
ymax = -np.Inf
|
||||||
|
|
||||||
for gs in geometry_list:
|
for gs in geometry_list:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -12,8 +12,12 @@
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from flatcamGUI.PreferencesUI import *
|
from flatcamGUI.PreferencesUI import *
|
||||||
|
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool
|
||||||
from matplotlib.backend_bases import KeyEvent as mpl_key_event
|
from matplotlib.backend_bases import KeyEvent as mpl_key_event
|
||||||
|
|
||||||
|
import webbrowser
|
||||||
|
from copy import deepcopy
|
||||||
|
from datetime import datetime
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -70,15 +74,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
self.menufilenew = self.menufile.addMenu(QtGui.QIcon('share/file16.png'), _('&New'))
|
self.menufilenew = self.menufile.addMenu(QtGui.QIcon('share/file16.png'), _('&New'))
|
||||||
self.menufilenew.setToolTipsVisible(True)
|
self.menufilenew.setToolTipsVisible(True)
|
||||||
|
|
||||||
self.menufilenewgeo = self.menufilenew.addAction(QtGui.QIcon('share/geometry16.png'), _('Geometry\tN'))
|
self.menufilenewgeo = self.menufilenew.addAction(QtGui.QIcon('share/new_file_geo16.png'), _('Geometry\tN'))
|
||||||
self.menufilenewgeo.setToolTip(
|
self.menufilenewgeo.setToolTip(
|
||||||
_("Will create a new, empty Geometry Object.")
|
_("Will create a new, empty Geometry Object.")
|
||||||
)
|
)
|
||||||
self.menufilenewgrb = self.menufilenew.addAction(QtGui.QIcon('share/flatcam_icon32.png'), _('Gerber\tB'))
|
self.menufilenewgrb = self.menufilenew.addAction(QtGui.QIcon('share/new_file_grb16.png'), _('Gerber\tB'))
|
||||||
self.menufilenewgrb.setToolTip(
|
self.menufilenewgrb.setToolTip(
|
||||||
_("Will create a new, empty Gerber Object.")
|
_("Will create a new, empty Gerber Object.")
|
||||||
)
|
)
|
||||||
self.menufilenewexc = self.menufilenew.addAction(QtGui.QIcon('share/drill16.png'), _('Excellon\tL'))
|
self.menufilenewexc = self.menufilenew.addAction(QtGui.QIcon('share/new_file_exc16.png'), _('Excellon\tL'))
|
||||||
self.menufilenewexc.setToolTip(
|
self.menufilenewexc.setToolTip(
|
||||||
_("Will create a new, empty Excellon Object.")
|
_("Will create a new, empty Excellon Object.")
|
||||||
)
|
)
|
||||||
|
@ -416,6 +420,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
# ########################## Objects # ###################################
|
# ########################## Objects # ###################################
|
||||||
# ########################################################################
|
# ########################################################################
|
||||||
self.menuobjects = self.menu.addMenu(_('Objects'))
|
self.menuobjects = self.menu.addMenu(_('Objects'))
|
||||||
|
self.menuobjects.addSeparator()
|
||||||
|
self.menuobjects_selall = self.menuobjects.addAction(QtGui.QIcon('share/select_all.png'), _('Select All'))
|
||||||
|
self.menuobjects_unselall = self.menuobjects.addAction(
|
||||||
|
QtGui.QIcon('share/deselect_all32.png'),
|
||||||
|
_('Deselect All')
|
||||||
|
)
|
||||||
|
|
||||||
# ########################################################################
|
# ########################################################################
|
||||||
# ########################## Tool # ######################################
|
# ########################## Tool # ######################################
|
||||||
|
@ -682,22 +692,23 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
self.file_open_excellon_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), _("Open Excellon"))
|
self.file_open_excellon_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), _("Open Excellon"))
|
||||||
self.toolbarfile.addSeparator()
|
self.toolbarfile.addSeparator()
|
||||||
self.file_open_btn = self.toolbarfile.addAction(QtGui.QIcon('share/folder32.png'), _("Open project"))
|
self.file_open_btn = self.toolbarfile.addAction(QtGui.QIcon('share/folder32.png'), _("Open project"))
|
||||||
self.file_save_btn = self.toolbarfile.addAction(QtGui.QIcon('share/floppy32.png'), _("Save project"))
|
self.file_save_btn = self.toolbarfile.addAction(QtGui.QIcon('share/project_save32.png'), _("Save project"))
|
||||||
|
|
||||||
# ########################################################################
|
# ########################################################################
|
||||||
# ########################## Edit Toolbar# ###############################
|
# ########################## Edit Toolbar# ###############################
|
||||||
# ########################################################################
|
# ########################################################################
|
||||||
self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32_bis.png'), _("New Blank Geometry"))
|
self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_file_geo32.png'), _("New Blank Geometry"))
|
||||||
self.newgrb_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32.png'), _("New Blank Gerber"))
|
self.newgrb_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_file_grb32.png'), _("New Blank Gerber"))
|
||||||
self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_exc32.png'), _("New Blank Excellon"))
|
self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_file_exc32.png'), _("New Blank Excellon"))
|
||||||
self.toolbargeo.addSeparator()
|
self.toolbargeo.addSeparator()
|
||||||
self.editgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/edit32.png'), _("Editor"))
|
self.editgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/edit_file32.png'), _("Editor"))
|
||||||
self.update_obj_btn = self.toolbargeo.addAction(
|
self.update_obj_btn = self.toolbargeo.addAction(
|
||||||
QtGui.QIcon('share/edit_ok32_bis.png'), _("Save Object and close the Editor")
|
QtGui.QIcon('share/close_edit_file32.png'), _("Save Object and close the Editor")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.toolbargeo.addSeparator()
|
self.toolbargeo.addSeparator()
|
||||||
self.delete_btn = self.toolbargeo.addAction(QtGui.QIcon('share/cancel_edit32.png'), _("&Delete"))
|
self.copy_btn = self.toolbargeo.addAction(QtGui.QIcon('share/copy_file32.png'), _("Copy"))
|
||||||
|
self.delete_btn = self.toolbargeo.addAction(QtGui.QIcon('share/delete_file32.png'), _("&Delete"))
|
||||||
self.toolbargeo.addSeparator()
|
self.toolbargeo.addSeparator()
|
||||||
self.distance_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance32.png'), _("Distance Tool"))
|
self.distance_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance32.png'), _("Distance Tool"))
|
||||||
self.distance_min_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance_min32.png'),
|
self.distance_min_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance_min32.png'),
|
||||||
|
@ -705,7 +716,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
self.origin_btn = self.toolbargeo.addAction(QtGui.QIcon('share/origin32.png'), _('Set Origin'))
|
self.origin_btn = self.toolbargeo.addAction(QtGui.QIcon('share/origin32.png'), _('Set Origin'))
|
||||||
self.jmp_btn = self.toolbargeo.addAction(QtGui.QIcon('share/jump_to16.png'), _('Jump to Location'))
|
self.jmp_btn = self.toolbargeo.addAction(QtGui.QIcon('share/jump_to16.png'), _('Jump to Location'))
|
||||||
|
|
||||||
|
|
||||||
# ########################################################################
|
# ########################################################################
|
||||||
# ########################## View Toolbar# ###############################
|
# ########################## View Toolbar# ###############################
|
||||||
# ########################################################################
|
# ########################################################################
|
||||||
|
@ -734,10 +744,10 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
self.paint_btn = self.toolbartools.addAction(QtGui.QIcon('share/paint20_1.png'), _("Paint Tool"))
|
self.paint_btn = self.toolbartools.addAction(QtGui.QIcon('share/paint20_1.png'), _("Paint Tool"))
|
||||||
self.toolbartools.addSeparator()
|
self.toolbartools.addSeparator()
|
||||||
|
|
||||||
self.panelize_btn = self.toolbartools.addAction(QtGui.QIcon('share/panel16.png'), _("Panel Tool"))
|
self.panelize_btn = self.toolbartools.addAction(QtGui.QIcon('share/panelize32.png'), _("Panel Tool"))
|
||||||
self.film_btn = self.toolbartools.addAction(QtGui.QIcon('share/film16.png'), _("Film Tool"))
|
self.film_btn = self.toolbartools.addAction(QtGui.QIcon('share/film16.png'), _("Film Tool"))
|
||||||
self.solder_btn = self.toolbartools.addAction(QtGui.QIcon('share/solderpastebis32.png'), _("SolderPaste Tool"))
|
self.solder_btn = self.toolbartools.addAction(QtGui.QIcon('share/solderpastebis32.png'), _("SolderPaste Tool"))
|
||||||
self.sub_btn = self.toolbartools.addAction(QtGui.QIcon('share/sub32.png'), _("Substract Tool"))
|
self.sub_btn = self.toolbartools.addAction(QtGui.QIcon('share/sub32.png'), _("Subtract Tool"))
|
||||||
self.rules_btn = self.toolbartools.addAction(QtGui.QIcon('share/rules32.png'), _("Rules Tool"))
|
self.rules_btn = self.toolbartools.addAction(QtGui.QIcon('share/rules32.png'), _("Rules Tool"))
|
||||||
self.optimal_btn = self.toolbartools.addAction(QtGui.QIcon('share/open_excellon32.png'), _("Optimal Tool"))
|
self.optimal_btn = self.toolbartools.addAction(QtGui.QIcon('share/open_excellon32.png'), _("Optimal Tool"))
|
||||||
|
|
||||||
|
@ -1869,7 +1879,7 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
|
|
||||||
self.draw_union = self.g_editor_cmenu.addAction(QtGui.QIcon('share/union32.png'), _("Union"))
|
self.draw_union = self.g_editor_cmenu.addAction(QtGui.QIcon('share/union32.png'), _("Union"))
|
||||||
self.draw_intersect = self.g_editor_cmenu.addAction(QtGui.QIcon('share/intersection32.png'), _("Intersection"))
|
self.draw_intersect = self.g_editor_cmenu.addAction(QtGui.QIcon('share/intersection32.png'), _("Intersection"))
|
||||||
self.draw_substract = self.g_editor_cmenu.addAction(QtGui.QIcon('share/subtract32.png'), _("Substraction"))
|
self.draw_substract = self.g_editor_cmenu.addAction(QtGui.QIcon('share/subtract32.png'), _("Subtraction"))
|
||||||
self.draw_cut = self.g_editor_cmenu.addAction(QtGui.QIcon('share/cutpath32.png'), _("Cut"))
|
self.draw_cut = self.g_editor_cmenu.addAction(QtGui.QIcon('share/cutpath32.png'), _("Cut"))
|
||||||
self.draw_transform = self.g_editor_cmenu.addAction(QtGui.QIcon('share/transform.png'), _("Transformations"))
|
self.draw_transform = self.g_editor_cmenu.addAction(QtGui.QIcon('share/transform.png'), _("Transformations"))
|
||||||
|
|
||||||
|
@ -2106,19 +2116,21 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
self.file_open_excellon_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), _("Open Excellon"))
|
self.file_open_excellon_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), _("Open Excellon"))
|
||||||
self.toolbarfile.addSeparator()
|
self.toolbarfile.addSeparator()
|
||||||
self.file_open_btn = self.toolbarfile.addAction(QtGui.QIcon('share/folder32.png'), _("Open project"))
|
self.file_open_btn = self.toolbarfile.addAction(QtGui.QIcon('share/folder32.png'), _("Open project"))
|
||||||
self.file_save_btn = self.toolbarfile.addAction(QtGui.QIcon('share/floppy32.png'), _("Save project"))
|
self.file_save_btn = self.toolbarfile.addAction(QtGui.QIcon('share/project_save32.png'), _("Save project"))
|
||||||
|
|
||||||
# ## Edit Toolbar # ##
|
# ## Edit Toolbar # ##
|
||||||
self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32_bis.png'), _("New Blank Geometry"))
|
self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_file_geo32.png'), _("New Blank Geometry"))
|
||||||
self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_exc32.png'), _("New Blank Excellon"))
|
self.newgrb_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_file_grb32.png'), _("New Blank Gerber"))
|
||||||
|
self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_file_exc32.png'), _("New Blank Excellon"))
|
||||||
self.toolbargeo.addSeparator()
|
self.toolbargeo.addSeparator()
|
||||||
self.editgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/edit32.png'), _("Editor"))
|
self.editgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/edit32.png'), _("Editor"))
|
||||||
self.update_obj_btn = self.toolbargeo.addAction(
|
self.update_obj_btn = self.toolbargeo.addAction(
|
||||||
QtGui.QIcon('share/edit_ok32_bis.png'), _("Save Object and close the Editor")
|
QtGui.QIcon('share/close_edit_file32.png'), _("Save Object and close the Editor")
|
||||||
)
|
)
|
||||||
|
|
||||||
self.toolbargeo.addSeparator()
|
self.toolbargeo.addSeparator()
|
||||||
self.delete_btn = self.toolbargeo.addAction(QtGui.QIcon('share/cancel_edit32.png'), _("&Delete"))
|
self.copy_btn = self.toolbargeo.addAction(QtGui.QIcon('share/copy_file32.png'), _("Copy"))
|
||||||
|
self.delete_btn = self.toolbargeo.addAction(QtGui.QIcon('share/delete_file32.png'), _("&Delete"))
|
||||||
self.toolbargeo.addSeparator()
|
self.toolbargeo.addSeparator()
|
||||||
self.distance_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance32.png'), _("Distance Tool"))
|
self.distance_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance32.png'), _("Distance Tool"))
|
||||||
self.distance_min_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance_min32.png'),
|
self.distance_min_btn = self.toolbargeo.addAction(QtGui.QIcon('share/distance_min32.png'),
|
||||||
|
@ -2148,11 +2160,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
||||||
self.paint_btn = self.toolbartools.addAction(QtGui.QIcon('share/paint20_1.png'), _("Paint Tool"))
|
self.paint_btn = self.toolbartools.addAction(QtGui.QIcon('share/paint20_1.png'), _("Paint Tool"))
|
||||||
self.toolbartools.addSeparator()
|
self.toolbartools.addSeparator()
|
||||||
|
|
||||||
self.panelize_btn = self.toolbartools.addAction(QtGui.QIcon('share/panel16.png'), _("Panel Tool"))
|
self.panelize_btn = self.toolbartools.addAction(QtGui.QIcon('share/panelize32.png'), _("Panel Tool"))
|
||||||
self.film_btn = self.toolbartools.addAction(QtGui.QIcon('share/film16.png'), _("Film Tool"))
|
self.film_btn = self.toolbartools.addAction(QtGui.QIcon('share/film16.png'), _("Film Tool"))
|
||||||
self.solder_btn = self.toolbartools.addAction(QtGui.QIcon('share/solderpastebis32.png'),
|
self.solder_btn = self.toolbartools.addAction(QtGui.QIcon('share/solderpastebis32.png'),
|
||||||
_("SolderPaste Tool"))
|
_("SolderPaste Tool"))
|
||||||
self.sub_btn = self.toolbartools.addAction(QtGui.QIcon('share/sub32.png'), _("Substract Tool"))
|
self.sub_btn = self.toolbartools.addAction(QtGui.QIcon('share/sub32.png'), _("Subtract Tool"))
|
||||||
|
|
||||||
self.toolbartools.addSeparator()
|
self.toolbartools.addSeparator()
|
||||||
|
|
||||||
|
@ -3696,7 +3708,7 @@ class FlatCAMSystemTray(QtWidgets.QSystemTrayIcon):
|
||||||
|
|
||||||
class BookmarkManager(QtWidgets.QWidget):
|
class BookmarkManager(QtWidgets.QWidget):
|
||||||
|
|
||||||
mark_rows = pyqtSignal()
|
mark_rows = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, app, storage, parent=None):
|
def __init__(self, app, storage, parent=None):
|
||||||
super(BookmarkManager, self).__init__(parent)
|
super(BookmarkManager, self).__init__(parent)
|
||||||
|
@ -3754,7 +3766,7 @@ class BookmarkManager(QtWidgets.QWidget):
|
||||||
new_vlay = QtWidgets.QVBoxLayout()
|
new_vlay = QtWidgets.QVBoxLayout()
|
||||||
layout.addLayout(new_vlay)
|
layout.addLayout(new_vlay)
|
||||||
|
|
||||||
new_title_lbl = QtWidgets.QLabel(_("<b>New Bookmark</b>"))
|
new_title_lbl = QtWidgets.QLabel('<b>%s</b>' % _("New Bookmark"))
|
||||||
new_vlay.addWidget(new_title_lbl)
|
new_vlay.addWidget(new_title_lbl)
|
||||||
|
|
||||||
form0 = QtWidgets.QFormLayout()
|
form0 = QtWidgets.QFormLayout()
|
||||||
|
@ -3958,8 +3970,9 @@ class BookmarkManager(QtWidgets.QWidget):
|
||||||
|
|
||||||
filter__ = "Text File (*.TXT);;All Files (*.*)"
|
filter__ = "Text File (*.TXT);;All Files (*.*)"
|
||||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export FlatCAM Preferences"),
|
filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export FlatCAM Preferences"),
|
||||||
directory=_('{l_save}/FlatCAM_Bookmarks_{date}').format(
|
directory='{l_save}/FlatCAM_{n}_{date}'.format(
|
||||||
l_save=str(self.app.get_last_save_folder()),
|
l_save=str(self.app.get_last_save_folder()),
|
||||||
|
n=_("Bookmarks"),
|
||||||
date=date),
|
date=date),
|
||||||
filter=filter__)
|
filter=filter__)
|
||||||
|
|
||||||
|
@ -3986,7 +3999,7 @@ class BookmarkManager(QtWidgets.QWidget):
|
||||||
self.app.log.error("Could not load defaults file.")
|
self.app.log.error("Could not load defaults file.")
|
||||||
self.app.log.error(str(e))
|
self.app.log.error(str(e))
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
_("Could not load bookamrks file."))
|
_("Could not load bookmarks file."))
|
||||||
return
|
return
|
||||||
|
|
||||||
# Save update options
|
# Save update options
|
||||||
|
@ -4019,7 +4032,7 @@ class BookmarkManager(QtWidgets.QWidget):
|
||||||
with open(filename) as f:
|
with open(filename) as f:
|
||||||
bookmarks = f.readlines()
|
bookmarks = f.readlines()
|
||||||
except IOError:
|
except IOError:
|
||||||
self.app.log.error("Could not load bookamrks file.")
|
self.app.log.error("Could not load bookmarks file.")
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
_("Could not load bookmarks file."))
|
_("Could not load bookmarks file."))
|
||||||
return
|
return
|
||||||
|
|
|
@ -12,18 +12,14 @@
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
from PyQt5.QtCore import Qt, pyqtSlot
|
||||||
from PyQt5.QtWidgets import QTextEdit, QCompleter, QAction
|
from PyQt5.QtWidgets import QTextEdit, QCompleter, QAction
|
||||||
from PyQt5.QtGui import QColor, QKeySequence, QPalette, QTextCursor
|
from PyQt5.QtGui import QKeySequence, QTextCursor
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
import re
|
import re
|
||||||
import logging
|
import logging
|
||||||
import html
|
import html
|
||||||
import webbrowser
|
|
||||||
from copy import deepcopy
|
|
||||||
import sys
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
log = logging.getLogger('base')
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
@ -513,7 +509,7 @@ class EvalEntry2(QtWidgets.QLineEdit):
|
||||||
|
|
||||||
class FCSpinner(QtWidgets.QSpinBox):
|
class FCSpinner(QtWidgets.QSpinBox):
|
||||||
|
|
||||||
returnPressed = pyqtSignal()
|
returnPressed = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(FCSpinner, self).__init__(parent)
|
super(FCSpinner, self).__init__(parent)
|
||||||
|
@ -580,7 +576,7 @@ class FCSpinner(QtWidgets.QSpinBox):
|
||||||
|
|
||||||
class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
|
class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
|
||||||
|
|
||||||
returnPressed = pyqtSignal()
|
returnPressed = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super(FCDoubleSpinner, self).__init__(parent)
|
super(FCDoubleSpinner, self).__init__(parent)
|
||||||
|
@ -869,16 +865,16 @@ class FCTextAreaExtended(QtWidgets.QTextEdit):
|
||||||
if self.textCursor().block().text().startswith(" "):
|
if self.textCursor().block().text().startswith(" "):
|
||||||
# skip the white space
|
# skip the white space
|
||||||
self.moveCursor(QtGui.QTextCursor.NextWord)
|
self.moveCursor(QtGui.QTextCursor.NextWord)
|
||||||
self.moveCursor(QtGui.QTextCursor.NextCharacter,QtGui.QTextCursor.KeepAnchor)
|
self.moveCursor(QtGui.QTextCursor.NextCharacter, QtGui.QTextCursor.KeepAnchor)
|
||||||
character = self.textCursor().selectedText()
|
character = self.textCursor().selectedText()
|
||||||
if character == "#":
|
if character == "#":
|
||||||
# delete #
|
# delete #
|
||||||
self.textCursor().deletePreviousChar()
|
self.textCursor().deletePreviousChar()
|
||||||
# delete white space
|
# delete white space
|
||||||
self.moveCursor(QtGui.QTextCursor.NextWord,QtGui.QTextCursor.KeepAnchor)
|
self.moveCursor(QtGui.QTextCursor.NextWord, QtGui.QTextCursor.KeepAnchor)
|
||||||
self.textCursor().removeSelectedText()
|
self.textCursor().removeSelectedText()
|
||||||
else:
|
else:
|
||||||
self.moveCursor(QtGui.QTextCursor.PreviousCharacter,QtGui.QTextCursor.KeepAnchor)
|
self.moveCursor(QtGui.QTextCursor.PreviousCharacter, QtGui.QTextCursor.KeepAnchor)
|
||||||
self.textCursor().insertText("# ")
|
self.textCursor().insertText("# ")
|
||||||
cursor = QtGui.QTextCursor(self.textCursor())
|
cursor = QtGui.QTextCursor(self.textCursor())
|
||||||
cursor.setPosition(pos)
|
cursor.setPosition(pos)
|
||||||
|
@ -1261,7 +1257,6 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
||||||
attached = True
|
attached = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
# If the tab is not attached, close it's window and
|
# If the tab is not attached, close it's window and
|
||||||
# remove the reference to it
|
# remove the reference to it
|
||||||
if not attached:
|
if not attached:
|
||||||
|
@ -1342,8 +1337,8 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
||||||
can be re-attached by closing the dialog or by dragging the window into the tab bar
|
can be re-attached by closing the dialog or by dragging the window into the tab bar
|
||||||
"""
|
"""
|
||||||
|
|
||||||
onCloseSignal = pyqtSignal(QtWidgets.QWidget, str, QtGui.QIcon)
|
onCloseSignal = QtCore.pyqtSignal(QtWidgets.QWidget, str, QtGui.QIcon)
|
||||||
onDropSignal = pyqtSignal(str, QtCore.QPoint)
|
onDropSignal = QtCore.pyqtSignal(str, QtCore.QPoint)
|
||||||
|
|
||||||
def __init__(self, name, contentWidget):
|
def __init__(self, name, contentWidget):
|
||||||
QtWidgets.QMainWindow.__init__(self, None)
|
QtWidgets.QMainWindow.__init__(self, None)
|
||||||
|
@ -1384,7 +1379,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
||||||
An event filter class to detect a QMainWindow drop event
|
An event filter class to detect a QMainWindow drop event
|
||||||
"""
|
"""
|
||||||
|
|
||||||
onDropSignal = pyqtSignal(QtCore.QPoint)
|
onDropSignal = QtCore.pyqtSignal(QtCore.QPoint)
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
QtCore.QObject.__init__(self)
|
QtCore.QObject.__init__(self)
|
||||||
|
@ -1416,11 +1411,11 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
class FCTabBar(QtWidgets.QTabBar):
|
class FCTabBar(QtWidgets.QTabBar):
|
||||||
onDetachTabSignal = pyqtSignal(int, QtCore.QPoint)
|
onDetachTabSignal = QtCore.pyqtSignal(int, QtCore.QPoint)
|
||||||
onMoveTabSignal = pyqtSignal(int, int)
|
onMoveTabSignal = QtCore.pyqtSignal(int, int)
|
||||||
detachedTabDropSignal = pyqtSignal(str, int, QtCore.QPoint)
|
detachedTabDropSignal = QtCore.pyqtSignal(str, int, QtCore.QPoint)
|
||||||
|
|
||||||
right_click = pyqtSignal(int)
|
right_click = QtCore.pyqtSignal(int)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QtWidgets.QTabBar.__init__(self, parent)
|
QtWidgets.QTabBar.__init__(self, parent)
|
||||||
|
@ -1498,7 +1493,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
||||||
self.dragInitiated = True
|
self.dragInitiated = True
|
||||||
|
|
||||||
# If the current movement is a drag initiated by the left button
|
# If the current movement is a drag initiated by the left button
|
||||||
if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged):
|
if ((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged:
|
||||||
|
|
||||||
# Stop the move event
|
# Stop the move event
|
||||||
finishMoveEvent = QtGui.QMouseEvent(
|
finishMoveEvent = QtGui.QMouseEvent(
|
||||||
|
@ -1591,7 +1586,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
||||||
|
|
||||||
|
|
||||||
class FCDetachableTab2(FCDetachableTab):
|
class FCDetachableTab2(FCDetachableTab):
|
||||||
tab_closed_signal = pyqtSignal(object)
|
tab_closed_signal = QtCore.pyqtSignal(object)
|
||||||
|
|
||||||
def __init__(self, protect=None, protect_by_name=None, parent=None):
|
def __init__(self, protect=None, protect_by_name=None, parent=None):
|
||||||
super(FCDetachableTab2, self).__init__(protect=protect, protect_by_name=protect_by_name, parent=parent)
|
super(FCDetachableTab2, self).__init__(protect=protect, protect_by_name=protect_by_name, parent=parent)
|
||||||
|
@ -1729,7 +1724,7 @@ class OptionalHideInputSection:
|
||||||
|
|
||||||
class FCTable(QtWidgets.QTableWidget):
|
class FCTable(QtWidgets.QTableWidget):
|
||||||
|
|
||||||
drag_drop_sig = pyqtSignal()
|
drag_drop_sig = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, drag_drop=False, protected_rows=None, parent=None):
|
def __init__(self, drag_drop=False, protected_rows=None, parent=None):
|
||||||
super(FCTable, self).__init__(parent)
|
super(FCTable, self).__init__(parent)
|
||||||
|
@ -2024,8 +2019,8 @@ class _ExpandableTextEdit(QTextEdit):
|
||||||
Class implements edit line, which expands themselves automatically
|
Class implements edit line, which expands themselves automatically
|
||||||
"""
|
"""
|
||||||
|
|
||||||
historyNext = pyqtSignal()
|
historyNext = QtCore.pyqtSignal()
|
||||||
historyPrev = pyqtSignal()
|
historyPrev = QtCore.pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, termwidget, *args):
|
def __init__(self, termwidget, *args):
|
||||||
QTextEdit.__init__(self, *args)
|
QTextEdit.__init__(self, *args)
|
||||||
|
@ -2148,7 +2143,7 @@ class _ExpandableTextEdit(QTextEdit):
|
||||||
|
|
||||||
|
|
||||||
class MyCompleter(QCompleter):
|
class MyCompleter(QCompleter):
|
||||||
insertText = pyqtSignal(str)
|
insertText = QtCore.pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
QCompleter.__init__(self)
|
QCompleter.__init__(self)
|
||||||
|
@ -2166,4 +2161,3 @@ class MyCompleter(QCompleter):
|
||||||
|
|
||||||
def getSelected(self):
|
def getSelected(self):
|
||||||
return self.lastSelected
|
return self.lastSelected
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,6 @@
|
||||||
# Date: 3/10/2019 #
|
# Date: 3/10/2019 #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from flatcamGUI.GUIElements import *
|
from flatcamGUI.GUIElements import *
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
# Modified by Marius Stanciu 09/21/2019 #
|
# Modified by Marius Stanciu 09/21/2019 #
|
||||||
############################################################
|
############################################################
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtCore
|
||||||
from PyQt5.QtCore import pyqtSignal
|
from PyQt5.QtCore import pyqtSignal
|
||||||
|
|
||||||
# needed for legacy mode
|
# needed for legacy mode
|
||||||
|
|
|
@ -8,11 +8,8 @@
|
||||||
from PyQt5.QtCore import QSettings
|
from PyQt5.QtCore import QSettings
|
||||||
from flatcamGUI.GUIElements import *
|
from flatcamGUI.GUIElements import *
|
||||||
import platform
|
import platform
|
||||||
import webbrowser
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool
|
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -5121,7 +5118,7 @@ class Tools2RulesCheckPrefGroupUI(OptionsGroupUI):
|
||||||
|
|
||||||
self.crlabel = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
|
self.crlabel = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
|
||||||
self.crlabel.setToolTip(
|
self.crlabel.setToolTip(
|
||||||
_("A tool to check if Gerber files fir within a set\n"
|
_("A tool to check if Gerber files are within a set\n"
|
||||||
"of Manufacturing Rules.")
|
"of Manufacturing Rules.")
|
||||||
)
|
)
|
||||||
self.layout.addWidget(self.crlabel)
|
self.layout.addWidget(self.crlabel)
|
||||||
|
|
|
@ -6,12 +6,15 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
from PyQt5.QtGui import QPalette
|
from PyQt5.QtGui import QPalette
|
||||||
from PyQt5.QtCore import QSettings
|
from PyQt5.QtCore import QSettings
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
import vispy.scene as scene
|
import vispy.scene as scene
|
||||||
from vispy.scene.cameras.base_camera import BaseCamera
|
from vispy.scene.cameras.base_camera import BaseCamera
|
||||||
from vispy.color import Color
|
from vispy.color import Color
|
||||||
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
white = Color("#ffffff")
|
white = Color("#ffffff")
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from shapely.geometry import LineString
|
from shapely.geometry import LineString
|
||||||
|
from shapely.affinity import rotate
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
log = logging.getLogger('base2')
|
log = logging.getLogger('base2')
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
import math
|
import math
|
||||||
import sys
|
|
||||||
|
|
||||||
|
|
||||||
def norm(v):
|
def norm(v):
|
||||||
|
|
|
@ -1,4 +1,14 @@
|
||||||
from camlib import *
|
|
||||||
|
from camlib import Geometry
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
|
import shapely.affinity as affinity
|
||||||
|
from shapely.geometry import Point, LineString
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import re
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
|
||||||
|
@ -8,6 +18,8 @@ import builtins
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class Excellon(Geometry):
|
class Excellon(Geometry):
|
||||||
"""
|
"""
|
||||||
|
@ -1017,10 +1029,10 @@ class Excellon(Geometry):
|
||||||
|
|
||||||
def bounds_rec(obj):
|
def bounds_rec(obj):
|
||||||
if type(obj) is list:
|
if type(obj) is list:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in obj:
|
for k in obj:
|
||||||
if type(k) is dict:
|
if type(k) is dict:
|
||||||
|
@ -1087,8 +1099,10 @@ class Excellon(Geometry):
|
||||||
Scales geometry on the XY plane in the object by a given factor.
|
Scales geometry on the XY plane in the object by a given factor.
|
||||||
Tool sizes, feedrates an Z-plane dimensions are untouched.
|
Tool sizes, feedrates an Z-plane dimensions are untouched.
|
||||||
|
|
||||||
:param factor: Number by which to scale the object.
|
:param xfactor: Number by which to scale the object.
|
||||||
:type factor: float
|
:type xfactor: float
|
||||||
|
:param yfactor: Number by which to scale the object.
|
||||||
|
:type yfactor: float
|
||||||
:return: None
|
:return: None
|
||||||
:rtype: NOne
|
:rtype: NOne
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -11,12 +11,11 @@
|
||||||
# ######################################################################
|
# ######################################################################
|
||||||
|
|
||||||
import re, os, sys, glob
|
import re, os, sys, glob
|
||||||
import itertools
|
|
||||||
|
|
||||||
from shapely.geometry import Point, Polygon
|
from shapely.geometry import Point, Polygon
|
||||||
from shapely.affinity import translate, scale, rotate
|
from shapely.affinity import translate, scale
|
||||||
from shapely.geometry import MultiPolygon
|
from shapely.geometry import MultiPolygon
|
||||||
from shapely.geometry.base import BaseGeometry
|
|
||||||
|
|
||||||
import freetype as ft
|
import freetype as ft
|
||||||
from fontTools import ttLib
|
from fontTools import ttLib
|
||||||
|
|
|
@ -1,4 +1,19 @@
|
||||||
from camlib import *
|
|
||||||
|
from camlib import Geometry, arc, arc_angle, ApertureMacro
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import re
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
from copy import deepcopy
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from shapely.ops import cascaded_union
|
||||||
|
from shapely.geometry import Polygon, MultiPolygon, LineString, Point
|
||||||
|
import shapely.affinity as affinity
|
||||||
|
from shapely.geometry import box as shply_box
|
||||||
|
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
|
@ -7,6 +22,8 @@ import builtins
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class Gerber(Geometry):
|
class Gerber(Geometry):
|
||||||
"""
|
"""
|
||||||
|
@ -253,14 +270,14 @@ class Gerber(Geometry):
|
||||||
self.apertures[apid] = {"type": "R",
|
self.apertures[apid] = {"type": "R",
|
||||||
"width": float(paramList[0]),
|
"width": float(paramList[0]),
|
||||||
"height": float(paramList[1]),
|
"height": float(paramList[1]),
|
||||||
"size": sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack
|
"size": np.sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack
|
||||||
return apid
|
return apid
|
||||||
|
|
||||||
if apertureType == "O": # Obround
|
if apertureType == "O": # Obround
|
||||||
self.apertures[apid] = {"type": "O",
|
self.apertures[apid] = {"type": "O",
|
||||||
"width": float(paramList[0]),
|
"width": float(paramList[0]),
|
||||||
"height": float(paramList[1]),
|
"height": float(paramList[1]),
|
||||||
"size": sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack
|
"size": np.sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack
|
||||||
return apid
|
return apid
|
||||||
|
|
||||||
if apertureType == "P": # Polygon (regular)
|
if apertureType == "P": # Polygon (regular)
|
||||||
|
@ -1231,15 +1248,15 @@ class Gerber(Geometry):
|
||||||
|
|
||||||
if quadrant_mode == 'MULTI':
|
if quadrant_mode == 'MULTI':
|
||||||
center = [i + current_x, j + current_y]
|
center = [i + current_x, j + current_y]
|
||||||
radius = sqrt(i ** 2 + j ** 2)
|
radius = np.sqrt(i ** 2 + j ** 2)
|
||||||
start = arctan2(-j, -i) # Start angle
|
start = np.arctan2(-j, -i) # Start angle
|
||||||
# Numerical errors might prevent start == stop therefore
|
# Numerical errors might prevent start == stop therefore
|
||||||
# we check ahead of time. This should result in a
|
# we check ahead of time. This should result in a
|
||||||
# 360 degree arc.
|
# 360 degree arc.
|
||||||
if current_x == circular_x and current_y == circular_y:
|
if current_x == circular_x and current_y == circular_y:
|
||||||
stop = start
|
stop = start
|
||||||
else:
|
else:
|
||||||
stop = arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
|
stop = np.arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
|
||||||
|
|
||||||
this_arc = arc(center, radius, start, stop,
|
this_arc = arc(center, radius, start, stop,
|
||||||
arcdir[current_interpolation_mode],
|
arcdir[current_interpolation_mode],
|
||||||
|
@ -1273,10 +1290,10 @@ class Gerber(Geometry):
|
||||||
valid = False
|
valid = False
|
||||||
log.debug("I: %f J: %f" % (i, j))
|
log.debug("I: %f J: %f" % (i, j))
|
||||||
for center in center_candidates:
|
for center in center_candidates:
|
||||||
radius = sqrt(i ** 2 + j ** 2)
|
radius = np.sqrt(i ** 2 + j ** 2)
|
||||||
|
|
||||||
# Make sure radius to start is the same as radius to end.
|
# Make sure radius to start is the same as radius to end.
|
||||||
radius2 = sqrt((center[0] - circular_x) ** 2 + (center[1] - circular_y) ** 2)
|
radius2 = np.sqrt((center[0] - circular_x) ** 2 + (center[1] - circular_y) ** 2)
|
||||||
if radius2 < radius * 0.95 or radius2 > radius * 1.05:
|
if radius2 < radius * 0.95 or radius2 > radius * 1.05:
|
||||||
continue # Not a valid center.
|
continue # Not a valid center.
|
||||||
|
|
||||||
|
@ -1284,16 +1301,16 @@ class Gerber(Geometry):
|
||||||
i = center[0] - current_x
|
i = center[0] - current_x
|
||||||
j = center[1] - current_y
|
j = center[1] - current_y
|
||||||
|
|
||||||
start = arctan2(-j, -i) # Start angle
|
start = np.arctan2(-j, -i) # Start angle
|
||||||
stop = arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
|
stop = np.arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
|
||||||
angle = abs(arc_angle(start, stop, arcdir[current_interpolation_mode]))
|
angle = abs(arc_angle(start, stop, arcdir[current_interpolation_mode]))
|
||||||
log.debug("ARC START: %f, %f CENTER: %f, %f STOP: %f, %f" %
|
log.debug("ARC START: %f, %f CENTER: %f, %f STOP: %f, %f" %
|
||||||
(current_x, current_y, center[0], center[1], circular_x, circular_y))
|
(current_x, current_y, center[0], center[1], circular_x, circular_y))
|
||||||
log.debug("START Ang: %f, STOP Ang: %f, DIR: %s, ABS: %.12f <= %.12f: %s" %
|
log.debug("START Ang: %f, STOP Ang: %f, DIR: %s, ABS: %.12f <= %.12f: %s" %
|
||||||
(start * 180 / pi, stop * 180 / pi, arcdir[current_interpolation_mode],
|
(start * 180 / np.pi, stop * 180 / np.pi, arcdir[current_interpolation_mode],
|
||||||
angle * 180 / pi, pi / 2 * 180 / pi, angle <= (pi + 1e-6) / 2))
|
angle * 180 / np.pi, np.pi / 2 * 180 / np.pi, angle <= (np.pi + 1e-6) / 2))
|
||||||
|
|
||||||
if angle <= (pi + 1e-6) / 2:
|
if angle <= (np.pi + 1e-6) / 2:
|
||||||
log.debug("########## ACCEPTING ARC ############")
|
log.debug("########## ACCEPTING ARC ############")
|
||||||
this_arc = arc(center, radius, start, stop,
|
this_arc = arc(center, radius, start, stop,
|
||||||
arcdir[current_interpolation_mode],
|
arcdir[current_interpolation_mode],
|
||||||
|
@ -1367,7 +1384,7 @@ class Gerber(Geometry):
|
||||||
|
|
||||||
# this treats the case when we are storing geometry as solids
|
# this treats the case when we are storing geometry as solids
|
||||||
|
|
||||||
if len(poly_buffer) == 0:
|
if len(poly_buffer) == 0 and len(self.solid_geometry) == 0:
|
||||||
log.error("Object is not Gerber file or empty. Aborting Object creation.")
|
log.error("Object is not Gerber file or empty. Aborting Object creation.")
|
||||||
return 'fail'
|
return 'fail'
|
||||||
|
|
||||||
|
@ -1478,8 +1495,8 @@ class Gerber(Geometry):
|
||||||
n_vertices = aperture['nVertices']
|
n_vertices = aperture['nVertices']
|
||||||
points = []
|
points = []
|
||||||
for i in range(0, n_vertices):
|
for i in range(0, n_vertices):
|
||||||
x = loc[0] + 0.5 * diam * (cos(2 * pi * i / n_vertices))
|
x = loc[0] + 0.5 * diam * (np.cos(2 * np.pi * i / n_vertices))
|
||||||
y = loc[1] + 0.5 * diam * (sin(2 * pi * i / n_vertices))
|
y = loc[1] + 0.5 * diam * (np.sin(2 * np.pi * i / n_vertices))
|
||||||
points.append((x, y))
|
points.append((x, y))
|
||||||
ply = Polygon(points)
|
ply = Polygon(points)
|
||||||
if 'rotation' in aperture:
|
if 'rotation' in aperture:
|
||||||
|
@ -1553,10 +1570,10 @@ class Gerber(Geometry):
|
||||||
|
|
||||||
def bounds_rec(obj):
|
def bounds_rec(obj):
|
||||||
if type(obj) is list and type(obj) is not MultiPolygon:
|
if type(obj) is list and type(obj) is not MultiPolygon:
|
||||||
minx = Inf
|
minx = np.Inf
|
||||||
miny = Inf
|
miny = np.Inf
|
||||||
maxx = -Inf
|
maxx = -np.Inf
|
||||||
maxy = -Inf
|
maxy = -np.Inf
|
||||||
|
|
||||||
for k in obj:
|
for k in obj:
|
||||||
if type(k) is dict:
|
if type(k) is dict:
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
from svg.path import Line, Arc, CubicBezier, QuadraticBezier, parse_path
|
from svg.path import Line, Arc, CubicBezier, QuadraticBezier, parse_path
|
||||||
from svg.path.path import Move
|
from svg.path.path import Move
|
||||||
from shapely.geometry import LineString
|
from shapely.geometry import LineString
|
||||||
from shapely.affinity import skew, affine_transform
|
from shapely.affinity import skew, affine_transform, rotate
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from flatcamParsers.ParseFont import *
|
from flatcamParsers.ParseFont import *
|
||||||
|
|
|
@ -5,8 +5,9 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from FlatCAMObj import *
|
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, FCEntry
|
||||||
import math
|
import math
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
|
@ -321,11 +322,11 @@ class ToolCalculator(FlatCAMTool):
|
||||||
|
|
||||||
def on_calculate_inch_units(self):
|
def on_calculate_inch_units(self):
|
||||||
mm_val = float(self.mm_entry.get_value())
|
mm_val = float(self.mm_entry.get_value())
|
||||||
self.inch_entry.set_value('%.*f' % (self.decimals,(mm_val / 25.4)))
|
self.inch_entry.set_value('%.*f' % (self.decimals, (mm_val / 25.4)))
|
||||||
|
|
||||||
def on_calculate_mm_units(self):
|
def on_calculate_mm_units(self):
|
||||||
inch_val = float(self.inch_entry.get_value())
|
inch_val = float(self.inch_entry.get_value())
|
||||||
self.mm_entry.set_value('%.*f' % (self.decimals,(inch_val * 25.4)))
|
self.mm_entry.set_value('%.*f' % (self.decimals, (inch_val * 25.4)))
|
||||||
|
|
||||||
def on_calculate_eplate(self):
|
def on_calculate_eplate(self):
|
||||||
length = float(self.pcblength_entry.get_value())
|
length = float(self.pcblength_entry.get_value())
|
||||||
|
|
|
@ -5,12 +5,21 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from ObjectCollection import *
|
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox
|
||||||
from FlatCAMApp import *
|
from FlatCAMObj import FlatCAMGerber
|
||||||
from shapely.geometry import box
|
|
||||||
from shapely.ops import cascaded_union, unary_union
|
|
||||||
|
|
||||||
|
from shapely.geometry import box, MultiPolygon, Polygon, LineString, LinearRing
|
||||||
|
from shapely.ops import cascaded_union, unary_union
|
||||||
|
import shapely.affinity as affinity
|
||||||
|
|
||||||
|
from matplotlib.backend_bases import KeyEvent as mpl_key_event
|
||||||
|
|
||||||
|
from numpy import Inf
|
||||||
|
from copy import deepcopy
|
||||||
|
import math
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -19,6 +28,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class CutOut(FlatCAMTool):
|
class CutOut(FlatCAMTool):
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtCore
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from FlatCAMObj import *
|
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry
|
||||||
|
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
|
||||||
|
|
||||||
from shapely.geometry import Point
|
from shapely.geometry import Point
|
||||||
from shapely import affinity
|
from shapely import affinity
|
||||||
from PyQt5 import QtCore
|
|
||||||
|
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -12,6 +17,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class DblSidedTool(FlatCAMTool):
|
class DblSidedTool(FlatCAMTool):
|
||||||
|
|
||||||
|
|
|
@ -5,12 +5,15 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtCore
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from FlatCAMObj import *
|
|
||||||
from flatcamGUI.VisPyVisuals import *
|
from flatcamGUI.VisPyVisuals import *
|
||||||
|
from flatcamGUI.GUIElements import FCEntry
|
||||||
|
|
||||||
from math import sqrt
|
import copy
|
||||||
|
import math
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -19,6 +22,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class Distance(FlatCAMTool):
|
class Distance(FlatCAMTool):
|
||||||
|
|
||||||
|
@ -335,7 +340,7 @@ class Distance(FlatCAMTool):
|
||||||
elif len(self.points) == 2:
|
elif len(self.points) == 2:
|
||||||
dx = self.points[1][0] - self.points[0][0]
|
dx = self.points[1][0] - self.points[0][0]
|
||||||
dy = self.points[1][1] - self.points[0][1]
|
dy = self.points[1][1] - self.points[0][1]
|
||||||
d = sqrt(dx ** 2 + dy ** 2)
|
d = math.sqrt(dx ** 2 + dy ** 2)
|
||||||
self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
|
self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
|
||||||
|
|
||||||
self.app.inform.emit(_("MEASURING: Result D(x) = {d_x} | D(y) = {d_y} | Distance = {d_z}").format(
|
self.app.inform.emit(_("MEASURING: Result D(x) = {d_x} | D(y) = {d_y} | Distance = {d_z}").format(
|
||||||
|
|
|
@ -5,14 +5,16 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtCore
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from FlatCAMObj import *
|
|
||||||
from flatcamGUI.VisPyVisuals import *
|
from flatcamGUI.VisPyVisuals import *
|
||||||
|
from flatcamGUI.GUIElements import FCEntry
|
||||||
|
|
||||||
from shapely.ops import nearest_points
|
from shapely.ops import nearest_points
|
||||||
|
from shapely.geometry import Point
|
||||||
|
|
||||||
from math import sqrt
|
import math
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -21,6 +23,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class DistanceMin(FlatCAMTool):
|
class DistanceMin(FlatCAMTool):
|
||||||
|
|
||||||
|
@ -260,7 +264,7 @@ class DistanceMin(FlatCAMTool):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
d = sqrt(dx ** 2 + dy ** 2)
|
d = math.sqrt(dx ** 2 + dy ** 2)
|
||||||
self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
|
self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
|
||||||
|
|
||||||
self.h_point = (min(first_pos.x, last_pos.x) + (abs(dx) / 2), min(first_pos.y, last_pos.y) + (abs(dy) / 2))
|
self.h_point = (min(first_pos.x, last_pos.x) + (abs(dx) / 2), min(first_pos.y, last_pos.y) + (abs(dy) / 2))
|
||||||
|
|
|
@ -5,14 +5,15 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
|
||||||
from FlatCAMObj import *
|
|
||||||
|
|
||||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
|
|
||||||
OptionalHideInputSection, OptionalInputSection
|
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
|
|
||||||
|
from FlatCAMTool import FlatCAMTool
|
||||||
|
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
|
||||||
|
OptionalHideInputSection, OptionalInputSection
|
||||||
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
import logging
|
||||||
|
from shapely.geometry import Polygon, MultiPolygon, Point
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -22,6 +23,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class Film(FlatCAMTool):
|
class Film(FlatCAMTool):
|
||||||
|
|
||||||
|
@ -166,7 +169,7 @@ class Film(FlatCAMTool):
|
||||||
self.ois_scale = OptionalInputSection(self.film_scale_cb, [self.film_scalex_label, self.film_scalex_entry,
|
self.ois_scale = OptionalInputSection(self.film_scale_cb, [self.film_scalex_label, self.film_scalex_entry,
|
||||||
self.film_scaley_label, self.film_scaley_entry])
|
self.film_scaley_label, self.film_scaley_entry])
|
||||||
# Skew Geometry
|
# Skew Geometry
|
||||||
self.film_skew_cb =FCCheckBox('%s' % _("Skew Film geometry"))
|
self.film_skew_cb = FCCheckBox('%s' % _("Skew Film geometry"))
|
||||||
self.film_skew_cb.setToolTip(
|
self.film_skew_cb.setToolTip(
|
||||||
_("Positive values will skew to the right\n"
|
_("Positive values will skew to the right\n"
|
||||||
"while negative values will skew to the left.")
|
"while negative values will skew to the left.")
|
||||||
|
@ -202,9 +205,9 @@ class Film(FlatCAMTool):
|
||||||
"It can be one of the four points of the geometry bounding box.")
|
"It can be one of the four points of the geometry bounding box.")
|
||||||
)
|
)
|
||||||
self.film_skew_reference = RadioSet([{'label': _('Bottom Left'), 'value': 'bottomleft'},
|
self.film_skew_reference = RadioSet([{'label': _('Bottom Left'), 'value': 'bottomleft'},
|
||||||
{'label': _('Top Left'), 'value': 'topleft'},
|
{'label': _('Top Left'), 'value': 'topleft'},
|
||||||
{'label': _('Bottom Right'), 'value': 'bottomright'},
|
{'label': _('Bottom Right'), 'value': 'bottomright'},
|
||||||
{'label': _('Top right'), 'value': 'topright'}],
|
{'label': _('Top right'), 'value': 'topright'}],
|
||||||
orientation='vertical',
|
orientation='vertical',
|
||||||
stretch=False)
|
stretch=False)
|
||||||
|
|
||||||
|
@ -331,7 +334,7 @@ class Film(FlatCAMTool):
|
||||||
|
|
||||||
self.exc_label = QtWidgets.QLabel('%s:' % _("Excellon Obj"))
|
self.exc_label = QtWidgets.QLabel('%s:' % _("Excellon Obj"))
|
||||||
self.exc_label.setToolTip(
|
self.exc_label.setToolTip(
|
||||||
_("Remove the geometry of Excellon from the Film to create tge holes in pads.")
|
_("Remove the geometry of Excellon from the Film to create the holes in pads.")
|
||||||
)
|
)
|
||||||
self.exc_combo = QtWidgets.QComboBox()
|
self.exc_combo = QtWidgets.QComboBox()
|
||||||
self.exc_combo.setModel(self.app.collection)
|
self.exc_combo.setModel(self.app.collection)
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
|
||||||
|
|
||||||
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner
|
|
||||||
from PyQt5 import QtGui, QtWidgets
|
from PyQt5 import QtGui, QtWidgets
|
||||||
|
|
||||||
|
from FlatCAMTool import FlatCAMTool
|
||||||
|
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
|
|
@ -5,12 +5,13 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtCore
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from FlatCAMObj import *
|
|
||||||
from flatcamGUI.VisPyVisuals import *
|
from flatcamGUI.VisPyVisuals import *
|
||||||
|
from FlatCAMObj import FlatCAMGerber
|
||||||
|
|
||||||
from copy import copy
|
from copy import copy
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -19,11 +20,13 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class ToolMove(FlatCAMTool):
|
class ToolMove(FlatCAMTool):
|
||||||
|
|
||||||
toolName = _("Move")
|
toolName = _("Move")
|
||||||
replot_signal = pyqtSignal(list)
|
replot_signal = QtCore.pyqtSignal(list)
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
FlatCAMTool.__init__(self, app)
|
FlatCAMTool.__init__(self, app)
|
||||||
|
|
|
@ -5,12 +5,23 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from copy import copy, deepcopy
|
from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog
|
||||||
from ObjectCollection import *
|
from flatcamParsers.ParseGerber import Gerber
|
||||||
import time
|
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
|
||||||
from shapely.geometry import base
|
import FlatCAMApp
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import math
|
||||||
|
from shapely.geometry import base
|
||||||
|
from shapely.ops import cascaded_union
|
||||||
|
from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -19,6 +30,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class NonCopperClear(FlatCAMTool, Gerber):
|
class NonCopperClear(FlatCAMTool, Gerber):
|
||||||
|
|
||||||
|
@ -261,7 +274,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
||||||
)
|
)
|
||||||
|
|
||||||
grid2.addWidget(self.addtool_btn, 0, 0)
|
grid2.addWidget(self.addtool_btn, 0, 0)
|
||||||
# grid2.addWidget(self.copytool_btn, 0, 1)
|
|
||||||
grid2.addWidget(self.deltool_btn, 0, 2)
|
grid2.addWidget(self.deltool_btn, 0, 2)
|
||||||
|
|
||||||
self.empty_label_0 = QtWidgets.QLabel('')
|
self.empty_label_0 = QtWidgets.QLabel('')
|
||||||
|
@ -269,6 +281,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
||||||
|
|
||||||
grid3 = QtWidgets.QGridLayout()
|
grid3 = QtWidgets.QGridLayout()
|
||||||
self.tools_box.addLayout(grid3)
|
self.tools_box.addLayout(grid3)
|
||||||
|
grid3.setColumnStretch(0, 0)
|
||||||
|
grid3.setColumnStretch(1, 1)
|
||||||
|
|
||||||
e_lab_1 = QtWidgets.QLabel('<b>%s:</b>' % _("Parameters"))
|
e_lab_1 = QtWidgets.QLabel('<b>%s:</b>' % _("Parameters"))
|
||||||
grid3.addWidget(e_lab_1, 0, 0)
|
grid3.addWidget(e_lab_1, 0, 0)
|
||||||
|
@ -472,7 +486,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
||||||
"Add", self.on_add_tool_by_key, icon=QtGui.QIcon("share/plus16.png"))
|
"Add", self.on_add_tool_by_key, icon=QtGui.QIcon("share/plus16.png"))
|
||||||
self.tools_table.addContextMenu(
|
self.tools_table.addContextMenu(
|
||||||
"Delete", lambda:
|
"Delete", lambda:
|
||||||
self.on_tool_delete(rows_to_delete=None, all=None), icon=QtGui.QIcon("share/delete32.png"))
|
self.on_tool_delete(rows_to_delete=None, all_tools=None), icon=QtGui.QIcon("share/delete32.png"))
|
||||||
|
|
||||||
# #############################################################################
|
# #############################################################################
|
||||||
# ########################## VARIABLES ########################################
|
# ########################## VARIABLES ########################################
|
||||||
|
@ -739,7 +753,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
||||||
tool_type_item = QtWidgets.QComboBox()
|
tool_type_item = QtWidgets.QComboBox()
|
||||||
for item in self.tool_type_item_options:
|
for item in self.tool_type_item_options:
|
||||||
tool_type_item.addItem(item)
|
tool_type_item.addItem(item)
|
||||||
tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
# tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
idx = tool_type_item.findText(tooluid_value['tool_type'])
|
idx = tool_type_item.findText(tooluid_value['tool_type'])
|
||||||
tool_type_item.setCurrentIndex(idx)
|
tool_type_item.setCurrentIndex(idx)
|
||||||
|
|
||||||
|
@ -747,9 +761,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
||||||
|
|
||||||
operation_type = QtWidgets.QComboBox()
|
operation_type = QtWidgets.QComboBox()
|
||||||
operation_type.addItem('iso_op')
|
operation_type.addItem('iso_op')
|
||||||
operation_type.setStyleSheet('background-color: rgb(255,255,255)')
|
# operation_type.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
operation_type.addItem('clear_op')
|
operation_type.addItem('clear_op')
|
||||||
operation_type.setStyleSheet('background-color: rgb(255,255,255)')
|
# operation_type.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
op_idx = operation_type.findText(tooluid_value['operation'])
|
op_idx = operation_type.findText(tooluid_value['operation'])
|
||||||
operation_type.setCurrentIndex(op_idx)
|
operation_type.setCurrentIndex(op_idx)
|
||||||
|
|
||||||
|
@ -1039,12 +1053,19 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
||||||
"New diameter value is already in the Tool Table."))
|
"New diameter value is already in the Tool Table."))
|
||||||
self.build_ui()
|
self.build_ui()
|
||||||
|
|
||||||
def on_tool_delete(self, rows_to_delete=None, all=None):
|
def on_tool_delete(self, rows_to_delete=None, all_tools=None):
|
||||||
|
"""
|
||||||
|
Will delete a tool in the tool table
|
||||||
|
|
||||||
|
:param rows_to_delete: which rows to delete; can be a list
|
||||||
|
:param all_tools: delete all tools in the tool table
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
self.ui_disconnect()
|
self.ui_disconnect()
|
||||||
|
|
||||||
deleted_tools_list = []
|
deleted_tools_list = []
|
||||||
|
|
||||||
if all:
|
if all_tools:
|
||||||
self.paint_tools.clear()
|
self.paint_tools.clear()
|
||||||
self.build_ui()
|
self.build_ui()
|
||||||
return
|
return
|
||||||
|
|
|
@ -5,13 +5,19 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||||
from FlatCAMObj import *
|
|
||||||
from shapely.geometry import Point
|
|
||||||
from shapely import affinity
|
|
||||||
from shapely.ops import nearest_points
|
|
||||||
from PyQt5 import QtCore
|
|
||||||
|
|
||||||
|
from FlatCAMTool import FlatCAMTool
|
||||||
|
from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox
|
||||||
|
from FlatCAMObj import FlatCAMGerber
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
|
from shapely.geometry import MultiPolygon
|
||||||
|
from shapely.ops import nearest_points
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -20,13 +26,15 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class ToolOptimal(FlatCAMTool):
|
class ToolOptimal(FlatCAMTool):
|
||||||
|
|
||||||
toolName = _("Optimal Tool")
|
toolName = _("Optimal Tool")
|
||||||
|
|
||||||
update_text = pyqtSignal(list)
|
update_text = QtCore.pyqtSignal(list)
|
||||||
update_sec_distances = pyqtSignal(dict)
|
update_sec_distances = QtCore.pyqtSignal(dict)
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
FlatCAMTool.__init__(self, app)
|
FlatCAMTool.__init__(self, app)
|
||||||
|
|
|
@ -5,19 +5,22 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtCore
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from shapely.geometry import Point, Polygon, LineString
|
import FlatCAMApp
|
||||||
from shapely.ops import cascaded_union, unary_union
|
|
||||||
|
|
||||||
from FlatCAMObj import *
|
from shapely.geometry import Point, Polygon, LineString, MultiPolygon
|
||||||
|
from shapely.ops import unary_union
|
||||||
|
|
||||||
import math
|
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
import zlib
|
import zlib
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -27,6 +30,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class ToolPDF(FlatCAMTool):
|
class ToolPDF(FlatCAMTool):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -5,10 +5,25 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||||
|
from PyQt5.QtCore import Qt
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from copy import copy, deepcopy
|
from copy import deepcopy
|
||||||
from ObjectCollection import *
|
# from ObjectCollection import *
|
||||||
from shapely.geometry import base
|
from flatcamParsers.ParseGerber import Gerber
|
||||||
|
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
|
||||||
|
from camlib import Geometry
|
||||||
|
from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet
|
||||||
|
import FlatCAMApp
|
||||||
|
|
||||||
|
from shapely.geometry import base, Polygon, MultiPolygon, LinearRing
|
||||||
|
from shapely.ops import cascaded_union
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from numpy import Inf
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -18,6 +33,8 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class ToolPaint(FlatCAMTool, Gerber):
|
class ToolPaint(FlatCAMTool, Gerber):
|
||||||
|
|
||||||
|
@ -374,6 +391,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
||||||
|
|
||||||
self.mm = None
|
self.mm = None
|
||||||
self.mp = None
|
self.mp = None
|
||||||
|
self.mr = None
|
||||||
|
|
||||||
self.sel_rect = []
|
self.sel_rect = []
|
||||||
|
|
||||||
|
@ -641,10 +659,10 @@ class ToolPaint(FlatCAMTool, Gerber):
|
||||||
for tooluid_key, tooluid_value in self.paint_tools.items():
|
for tooluid_key, tooluid_value in self.paint_tools.items():
|
||||||
if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted:
|
if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted:
|
||||||
tool_id += 1
|
tool_id += 1
|
||||||
id = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
|
id_item = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
|
||||||
id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||||
row_no = tool_id - 1
|
row_no = tool_id - 1
|
||||||
self.tools_table.setItem(row_no, 0, id) # Tool name/id
|
self.tools_table.setItem(row_no, 0, id_item) # Tool name/id
|
||||||
|
|
||||||
# Make sure that the drill diameter when in MM is with no more than 2 decimals
|
# 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 2 decimals diameter
|
# There are no drill bits in MM with more than 2 decimals diameter
|
||||||
|
@ -657,7 +675,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
||||||
tool_type_item = QtWidgets.QComboBox()
|
tool_type_item = QtWidgets.QComboBox()
|
||||||
for item in self.tool_type_item_options:
|
for item in self.tool_type_item_options:
|
||||||
tool_type_item.addItem(item)
|
tool_type_item.addItem(item)
|
||||||
tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
# tool_type_item.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
idx = tool_type_item.findText(tooluid_value['tool_type'])
|
idx = tool_type_item.findText(tooluid_value['tool_type'])
|
||||||
tool_type_item.setCurrentIndex(idx)
|
tool_type_item.setCurrentIndex(idx)
|
||||||
|
|
||||||
|
@ -2213,7 +2231,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
||||||
log.debug("Could not Paint the polygons. %s" % str(e))
|
log.debug("Could not Paint the polygons. %s" % str(e))
|
||||||
self.app.inform.emit('[ERROR] %s\n%s' %
|
self.app.inform.emit('[ERROR] %s\n%s' %
|
||||||
(_("Could not do Paint All. Try a different combination of parameters. "
|
(_("Could not do Paint All. Try a different combination of parameters. "
|
||||||
"Or a different Method of paint"), str(e)))
|
"Or a different Method of paint"), str(e)))
|
||||||
return
|
return
|
||||||
|
|
||||||
pol_nr += 1
|
pol_nr += 1
|
||||||
|
@ -2373,7 +2391,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
||||||
log.debug("Could not Paint the polygons. %s" % str(e))
|
log.debug("Could not Paint the polygons. %s" % str(e))
|
||||||
self.app.inform.emit('[ERROR] %s\n%s' %
|
self.app.inform.emit('[ERROR] %s\n%s' %
|
||||||
(_("Could not do Paint All. Try a different combination of parameters. "
|
(_("Could not do Paint All. Try a different combination of parameters. "
|
||||||
"Or a different Method of paint"), str(e)))
|
"Or a different Method of paint"), str(e)))
|
||||||
return
|
return
|
||||||
|
|
||||||
pol_nr += 1
|
pol_nr += 1
|
||||||
|
|
|
@ -5,19 +5,29 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from copy import copy, deepcopy
|
|
||||||
from ObjectCollection import *
|
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection
|
||||||
import time
|
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber, FlatCAMExcellon
|
||||||
|
import FlatCAMApp
|
||||||
|
from copy import deepcopy
|
||||||
|
# from ObjectCollection import *
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
import shapely.affinity as affinity
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
import logging
|
||||||
|
|
||||||
fcTranslate.apply_language('strings')
|
fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class Panelize(FlatCAMTool):
|
class Panelize(FlatCAMTool):
|
||||||
|
|
||||||
|
@ -367,15 +377,13 @@ class Panelize(FlatCAMTool):
|
||||||
|
|
||||||
# Get source object.
|
# Get source object.
|
||||||
try:
|
try:
|
||||||
obj = self.app.collection.get_by_name(str(name))
|
panel_obj = self.app.collection.get_by_name(str(name))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.debug("Panelize.on_panelize() --> %s" % str(e))
|
log.debug("Panelize.on_panelize() --> %s" % str(e))
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
||||||
(_("Could not retrieve object"), name))
|
(_("Could not retrieve object"), name))
|
||||||
return "Could not retrieve object: %s" % name
|
return "Could not retrieve object: %s" % name
|
||||||
|
|
||||||
panel_obj = obj
|
|
||||||
|
|
||||||
if panel_obj is None:
|
if panel_obj is None:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
||||||
(_("Object not found"), panel_obj))
|
(_("Object not found"), panel_obj))
|
||||||
|
@ -443,6 +451,18 @@ class Panelize(FlatCAMTool):
|
||||||
rows -= 1
|
rows -= 1
|
||||||
panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
|
panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
|
||||||
|
|
||||||
|
if isinstance(panel_obj, FlatCAMExcellon) or isinstance(panel_obj, FlatCAMGeometry):
|
||||||
|
# make a copy of the panelized Excellon or Geometry tools
|
||||||
|
copied_tools = dict()
|
||||||
|
for tt, tt_val in list(panel_obj.tools.items()):
|
||||||
|
copied_tools[tt] = deepcopy(tt_val)
|
||||||
|
|
||||||
|
if isinstance(panel_obj, FlatCAMGerber):
|
||||||
|
# make a copy of the panelized Gerber apertures
|
||||||
|
copied_apertures = dict()
|
||||||
|
for tt, tt_val in list(panel_obj.apertures.items()):
|
||||||
|
copied_apertures[tt] = deepcopy(tt_val)
|
||||||
|
|
||||||
def panelize_2():
|
def panelize_2():
|
||||||
if panel_obj is not None:
|
if panel_obj is not None:
|
||||||
self.app.inform.emit(_("Generating panel ... "))
|
self.app.inform.emit(_("Generating panel ... "))
|
||||||
|
@ -452,7 +472,7 @@ class Panelize(FlatCAMTool):
|
||||||
def job_init_excellon(obj_fin, app_obj):
|
def job_init_excellon(obj_fin, app_obj):
|
||||||
currenty = 0.0
|
currenty = 0.0
|
||||||
self.app.progress.emit(10)
|
self.app.progress.emit(10)
|
||||||
obj_fin.tools = panel_obj.tools.copy()
|
obj_fin.tools = copied_tools
|
||||||
obj_fin.drills = []
|
obj_fin.drills = []
|
||||||
obj_fin.slots = []
|
obj_fin.slots = []
|
||||||
obj_fin.solid_geometry = []
|
obj_fin.solid_geometry = []
|
||||||
|
@ -472,7 +492,6 @@ class Panelize(FlatCAMTool):
|
||||||
currentx = 0.0
|
currentx = 0.0
|
||||||
for col in range(columns):
|
for col in range(columns):
|
||||||
element += 1
|
element += 1
|
||||||
disp_number = 0
|
|
||||||
old_disp_number = 0
|
old_disp_number = 0
|
||||||
|
|
||||||
if panel_obj.drills:
|
if panel_obj.drills:
|
||||||
|
@ -493,7 +512,7 @@ class Panelize(FlatCAMTool):
|
||||||
drill_nr += 1
|
drill_nr += 1
|
||||||
disp_number = int(np.interp(drill_nr, [0, geo_len_drills], [0, 100]))
|
disp_number = int(np.interp(drill_nr, [0, geo_len_drills], [0, 100]))
|
||||||
|
|
||||||
if disp_number > old_disp_number and disp_number <= 100:
|
if old_disp_number < disp_number <= 100:
|
||||||
self.app.proc_container.update_view_text(' %s: %d D:%d%%' %
|
self.app.proc_container.update_view_text(' %s: %d D:%d%%' %
|
||||||
(_("Copy"),
|
(_("Copy"),
|
||||||
int(element),
|
int(element),
|
||||||
|
@ -520,7 +539,7 @@ class Panelize(FlatCAMTool):
|
||||||
slot_nr += 1
|
slot_nr += 1
|
||||||
disp_number = int(np.interp(slot_nr, [0, geo_len_slots], [0, 100]))
|
disp_number = int(np.interp(slot_nr, [0, geo_len_slots], [0, 100]))
|
||||||
|
|
||||||
if disp_number > old_disp_number and disp_number <= 100:
|
if old_disp_number < disp_number <= 100:
|
||||||
self.app.proc_container.update_view_text(' %s: %d S:%d%%' %
|
self.app.proc_container.update_view_text(' %s: %d S:%d%%' %
|
||||||
(_("Copy"),
|
(_("Copy"),
|
||||||
int(element),
|
int(element),
|
||||||
|
@ -557,12 +576,12 @@ class Panelize(FlatCAMTool):
|
||||||
# create the initial structure on which to create the panel
|
# create the initial structure on which to create the panel
|
||||||
if isinstance(panel_obj, FlatCAMGeometry):
|
if isinstance(panel_obj, FlatCAMGeometry):
|
||||||
obj_fin.multigeo = panel_obj.multigeo
|
obj_fin.multigeo = panel_obj.multigeo
|
||||||
obj_fin.tools = deepcopy(panel_obj.tools)
|
obj_fin.tools = copied_tools
|
||||||
if panel_obj.multigeo is True:
|
if panel_obj.multigeo is True:
|
||||||
for tool in panel_obj.tools:
|
for tool in panel_obj.tools:
|
||||||
obj_fin.tools[tool]['solid_geometry'][:] = []
|
obj_fin.tools[tool]['solid_geometry'][:] = []
|
||||||
elif isinstance(panel_obj, FlatCAMGerber):
|
elif isinstance(panel_obj, FlatCAMGerber):
|
||||||
obj_fin.apertures = deepcopy(panel_obj.apertures)
|
obj_fin.apertures = copied_apertures
|
||||||
for ap in obj_fin.apertures:
|
for ap in obj_fin.apertures:
|
||||||
obj_fin.apertures[ap]['geometry'] = list()
|
obj_fin.apertures[ap]['geometry'] = list()
|
||||||
|
|
||||||
|
@ -594,7 +613,6 @@ class Panelize(FlatCAMTool):
|
||||||
|
|
||||||
for col in range(columns):
|
for col in range(columns):
|
||||||
element += 1
|
element += 1
|
||||||
disp_number = 0
|
|
||||||
old_disp_number = 0
|
old_disp_number = 0
|
||||||
|
|
||||||
if isinstance(panel_obj, FlatCAMGeometry):
|
if isinstance(panel_obj, FlatCAMGeometry):
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from PyQt5 import QtWidgets, QtCore
|
||||||
|
|
||||||
|
from FlatCAMTool import FlatCAMTool
|
||||||
|
from flatcamGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable
|
||||||
|
|
||||||
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner, FCButton, FCTable
|
|
||||||
from PyQt5 import QtGui, QtWidgets, QtCore
|
|
||||||
from PyQt5.QtCore import pyqtSignal
|
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
@ -26,7 +26,7 @@ if '_' not in builtins.__dict__:
|
||||||
|
|
||||||
class PcbWizard(FlatCAMTool):
|
class PcbWizard(FlatCAMTool):
|
||||||
|
|
||||||
file_loaded = pyqtSignal(str, str)
|
file_loaded = QtCore.pyqtSignal(str, str)
|
||||||
|
|
||||||
toolName = _("PcbWizard Import Tool")
|
toolName = _("PcbWizard Import Tool")
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,14 @@
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||||
from PyQt5.QtCore import Qt
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from FlatCAMObj import *
|
from FlatCAMObj import FlatCAMCNCjob
|
||||||
|
|
||||||
|
from shapely.geometry import MultiPolygon, Polygon
|
||||||
|
from shapely.ops import cascaded_union
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -18,11 +22,13 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class Properties(FlatCAMTool):
|
class Properties(FlatCAMTool):
|
||||||
toolName = _("Properties")
|
toolName = _("Properties")
|
||||||
|
|
||||||
calculations_finished = pyqtSignal(float, float, float, float, object)
|
calculations_finished = QtCore.pyqtSignal(float, float, float, float, object)
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
FlatCAMTool.__init__(self, app)
|
FlatCAMTool.__init__(self, app)
|
||||||
|
@ -150,18 +156,18 @@ class Properties(FlatCAMTool):
|
||||||
|
|
||||||
self.addChild(obj_name, [obj.options['name']])
|
self.addChild(obj_name, [obj.options['name']])
|
||||||
|
|
||||||
def job_thread(obj):
|
def job_thread(obj_prop):
|
||||||
proc = self.app.proc_container.new(_("Calculating dimensions ... Please wait."))
|
proc = self.app.proc_container.new(_("Calculating dimensions ... Please wait."))
|
||||||
|
|
||||||
length = 0.0
|
length = 0.0
|
||||||
width = 0.0
|
width = 0.0
|
||||||
area = 0.0
|
area = 0.0
|
||||||
|
|
||||||
geo = obj.solid_geometry
|
geo = obj_prop.solid_geometry
|
||||||
if geo:
|
if geo:
|
||||||
# calculate physical dimensions
|
# calculate physical dimensions
|
||||||
try:
|
try:
|
||||||
xmin, ymin, xmax, ymax = obj.bounds()
|
xmin, ymin, xmax, ymax = obj_prop.bounds()
|
||||||
|
|
||||||
length = abs(xmax - xmin)
|
length = abs(xmax - xmin)
|
||||||
width = abs(ymax - ymin)
|
width = abs(ymax - ymin)
|
||||||
|
@ -179,9 +185,9 @@ class Properties(FlatCAMTool):
|
||||||
xmax = []
|
xmax = []
|
||||||
ymax = []
|
ymax = []
|
||||||
|
|
||||||
for tool in obj.tools:
|
for tool_k in obj_prop.tools:
|
||||||
try:
|
try:
|
||||||
x0, y0, x1, y1 = cascaded_union(obj.tools[tool]['solid_geometry']).bounds
|
x0, y0, x1, y1 = cascaded_union(obj_prop.tools[tool_k]['solid_geometry']).bounds
|
||||||
xmin.append(x0)
|
xmin.append(x0)
|
||||||
ymin.append(y0)
|
ymin.append(y0)
|
||||||
xmax.append(x1)
|
xmax.append(x1)
|
||||||
|
@ -207,25 +213,25 @@ class Properties(FlatCAMTool):
|
||||||
log.debug("Properties.addItems() --> %s" % str(e))
|
log.debug("Properties.addItems() --> %s" % str(e))
|
||||||
|
|
||||||
area_chull = 0.0
|
area_chull = 0.0
|
||||||
if not isinstance(obj, FlatCAMCNCjob):
|
if not isinstance(obj_prop, FlatCAMCNCjob):
|
||||||
# calculate and add convex hull area
|
# calculate and add convex hull area
|
||||||
if geo:
|
if geo:
|
||||||
if isinstance(geo, MultiPolygon):
|
if isinstance(geo, MultiPolygon):
|
||||||
env_obj = geo.convex_hull
|
env_obj = geo.convex_hull
|
||||||
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
|
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
|
||||||
(isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
|
(isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
|
||||||
env_obj = cascaded_union(obj.solid_geometry)
|
env_obj = cascaded_union(obj_prop.solid_geometry)
|
||||||
env_obj = env_obj.convex_hull
|
env_obj = env_obj.convex_hull
|
||||||
else:
|
else:
|
||||||
env_obj = cascaded_union(obj.solid_geometry)
|
env_obj = cascaded_union(obj_prop.solid_geometry)
|
||||||
env_obj = env_obj.convex_hull
|
env_obj = env_obj.convex_hull
|
||||||
|
|
||||||
area_chull = env_obj.area
|
area_chull = env_obj.area
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
area_chull = []
|
area_chull = []
|
||||||
for tool in obj.tools:
|
for tool_k in obj_prop.tools:
|
||||||
area_el = cascaded_union(obj.tools[tool]['solid_geometry']).convex_hull
|
area_el = cascaded_union(obj_prop.tools[tool_k]['solid_geometry']).convex_hull
|
||||||
area_chull.append(area_el.area)
|
area_chull.append(area_el.area)
|
||||||
area_chull = max(area_chull)
|
area_chull = max(area_chull)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
@ -5,15 +5,18 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from PyQt5 import QtWidgets
|
||||||
from copy import copy, deepcopy
|
|
||||||
from ObjectCollection import *
|
|
||||||
import time
|
|
||||||
from FlatCAMPool import *
|
|
||||||
from os import getpid
|
|
||||||
from shapely.ops import nearest_points
|
|
||||||
from shapely.geometry.base import BaseGeometry
|
|
||||||
|
|
||||||
|
from FlatCAMTool import FlatCAMTool
|
||||||
|
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from FlatCAMPool import *
|
||||||
|
# from os import getpid
|
||||||
|
from shapely.ops import nearest_points
|
||||||
|
from shapely.geometry import MultiPolygon, Polygon
|
||||||
|
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -22,12 +25,14 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class RulesCheck(FlatCAMTool):
|
class RulesCheck(FlatCAMTool):
|
||||||
|
|
||||||
toolName = _("Check Rules")
|
toolName = _("Check Rules")
|
||||||
|
|
||||||
tool_finished = pyqtSignal(list)
|
tool_finished = QtCore.pyqtSignal(list)
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
super(RulesCheck, self).__init__(self)
|
super(RulesCheck, self).__init__(self)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
# from PyQt5.QtCore import pyqtSignal
|
|
||||||
from PyQt5.QtCore import Qt
|
from PyQt5.QtCore import Qt
|
||||||
from PyQt5.QtGui import QTextCursor
|
from PyQt5.QtGui import QTextCursor
|
||||||
from PyQt5.QtWidgets import QVBoxLayout, QWidget
|
from PyQt5.QtWidgets import QVBoxLayout, QWidget
|
||||||
|
|
|
@ -278,7 +278,7 @@ class SolderPaste(FlatCAMTool):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.pp_combo = FCComboBox()
|
self.pp_combo = FCComboBox()
|
||||||
self.pp_combo.setStyleSheet('background-color: rgb(255,255,255)')
|
# self.pp_combo.setStyleSheet('background-color: rgb(255,255,255)')
|
||||||
self.gcode_form_layout.addRow(pp_label, self.pp_combo)
|
self.gcode_form_layout.addRow(pp_label, self.pp_combo)
|
||||||
|
|
||||||
# ## Buttons
|
# ## Buttons
|
||||||
|
|
|
@ -5,12 +5,18 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets, QtCore
|
||||||
|
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
# from copy import copy, deepcopy
|
from flatcamGUI.GUIElements import FCCheckBox, FCButton
|
||||||
from ObjectCollection import *
|
|
||||||
import time
|
|
||||||
|
|
||||||
|
from shapely.geometry import Polygon, MultiPolygon, MultiLineString, LineString
|
||||||
|
from shapely.ops import cascaded_union
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
from copy import deepcopy
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
import builtins
|
import builtins
|
||||||
|
@ -19,12 +25,14 @@ fcTranslate.apply_language('strings')
|
||||||
if '_' not in builtins.__dict__:
|
if '_' not in builtins.__dict__:
|
||||||
_ = gettext.gettext
|
_ = gettext.gettext
|
||||||
|
|
||||||
|
log = logging.getLogger('base')
|
||||||
|
|
||||||
|
|
||||||
class ToolSub(FlatCAMTool):
|
class ToolSub(FlatCAMTool):
|
||||||
|
|
||||||
job_finished = QtCore.pyqtSignal(bool)
|
job_finished = QtCore.pyqtSignal(bool)
|
||||||
|
|
||||||
toolName = _("Substract Tool")
|
toolName = _("Subtract Tool")
|
||||||
|
|
||||||
def __init__(self, app):
|
def __init__(self, app):
|
||||||
self.app = app
|
self.app = app
|
||||||
|
@ -64,8 +72,8 @@ class ToolSub(FlatCAMTool):
|
||||||
|
|
||||||
self.target_gerber_label = QtWidgets.QLabel('%s:' % _("Target"))
|
self.target_gerber_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||||
self.target_gerber_label.setToolTip(
|
self.target_gerber_label.setToolTip(
|
||||||
_("Gerber object from which to substract\n"
|
_("Gerber object from which to subtract\n"
|
||||||
"the substractor Gerber object.")
|
"the subtractor Gerber object.")
|
||||||
)
|
)
|
||||||
|
|
||||||
form_layout.addRow(self.target_gerber_label, self.target_gerber_combo)
|
form_layout.addRow(self.target_gerber_label, self.target_gerber_combo)
|
||||||
|
@ -76,9 +84,9 @@ class ToolSub(FlatCAMTool):
|
||||||
self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
self.sub_gerber_combo.setRootModelIndex(self.app.collection.index(0, 0, QtCore.QModelIndex()))
|
||||||
self.sub_gerber_combo.setCurrentIndex(1)
|
self.sub_gerber_combo.setCurrentIndex(1)
|
||||||
|
|
||||||
self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Substractor"))
|
self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
|
||||||
self.sub_gerber_label.setToolTip(
|
self.sub_gerber_label.setToolTip(
|
||||||
_("Gerber object that will be substracted\n"
|
_("Gerber object that will be subtracted\n"
|
||||||
"from the target Gerber object.")
|
"from the target Gerber object.")
|
||||||
)
|
)
|
||||||
e_lab_1 = QtWidgets.QLabel('')
|
e_lab_1 = QtWidgets.QLabel('')
|
||||||
|
@ -87,7 +95,7 @@ class ToolSub(FlatCAMTool):
|
||||||
|
|
||||||
self.intersect_btn = FCButton(_('Substract Gerber'))
|
self.intersect_btn = FCButton(_('Substract Gerber'))
|
||||||
self.intersect_btn.setToolTip(
|
self.intersect_btn.setToolTip(
|
||||||
_("Will remove the area occupied by the substractor\n"
|
_("Will remove the area occupied by the subtractor\n"
|
||||||
"Gerber from the Target Gerber.\n"
|
"Gerber from the Target Gerber.\n"
|
||||||
"Can be used to remove the overlapping silkscreen\n"
|
"Can be used to remove the overlapping silkscreen\n"
|
||||||
"over the soldermask.")
|
"over the soldermask.")
|
||||||
|
@ -110,8 +118,8 @@ class ToolSub(FlatCAMTool):
|
||||||
|
|
||||||
self.target_geo_label = QtWidgets.QLabel('%s:' % _("Target"))
|
self.target_geo_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||||
self.target_geo_label.setToolTip(
|
self.target_geo_label.setToolTip(
|
||||||
_("Geometry object from which to substract\n"
|
_("Geometry object from which to subtract\n"
|
||||||
"the substractor Geometry object.")
|
"the subtractor Geometry object.")
|
||||||
)
|
)
|
||||||
|
|
||||||
form_geo_layout.addRow(self.target_geo_label, self.target_geo_combo)
|
form_geo_layout.addRow(self.target_geo_label, self.target_geo_combo)
|
||||||
|
@ -122,9 +130,9 @@ class ToolSub(FlatCAMTool):
|
||||||
self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
self.sub_geo_combo.setRootModelIndex(self.app.collection.index(2, 0, QtCore.QModelIndex()))
|
||||||
self.sub_geo_combo.setCurrentIndex(1)
|
self.sub_geo_combo.setCurrentIndex(1)
|
||||||
|
|
||||||
self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Substractor"))
|
self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
|
||||||
self.sub_geo_label.setToolTip(
|
self.sub_geo_label.setToolTip(
|
||||||
_("Geometry object that will be substracted\n"
|
_("Geometry object that will be subtracted\n"
|
||||||
"from the target Geometry object.")
|
"from the target Geometry object.")
|
||||||
)
|
)
|
||||||
e_lab_1 = QtWidgets.QLabel('')
|
e_lab_1 = QtWidgets.QLabel('')
|
||||||
|
@ -132,12 +140,12 @@ class ToolSub(FlatCAMTool):
|
||||||
form_geo_layout.addRow(self.sub_geo_label, self.sub_geo_combo)
|
form_geo_layout.addRow(self.sub_geo_label, self.sub_geo_combo)
|
||||||
|
|
||||||
self.close_paths_cb = FCCheckBox(_("Close paths"))
|
self.close_paths_cb = FCCheckBox(_("Close paths"))
|
||||||
self.close_paths_cb.setToolTip(_("Checking this will close the paths cut by the Geometry substractor object."))
|
self.close_paths_cb.setToolTip(_("Checking this will close the paths cut by the Geometry subtractor object."))
|
||||||
self.tools_box.addWidget(self.close_paths_cb)
|
self.tools_box.addWidget(self.close_paths_cb)
|
||||||
|
|
||||||
self.intersect_geo_btn = FCButton(_('Substract Geometry'))
|
self.intersect_geo_btn = FCButton(_('Subtract Geometry'))
|
||||||
self.intersect_geo_btn.setToolTip(
|
self.intersect_geo_btn.setToolTip(
|
||||||
_("Will remove the area occupied by the substractor\n"
|
_("Will remove the area occupied by the subtractor\n"
|
||||||
"Geometry from the Target Geometry.")
|
"Geometry from the Target Geometry.")
|
||||||
)
|
)
|
||||||
self.tools_box.addWidget(self.intersect_geo_btn)
|
self.tools_box.addWidget(self.intersect_geo_btn)
|
||||||
|
@ -256,7 +264,7 @@ class ToolSub(FlatCAMTool):
|
||||||
self.sub_grb_obj_name = self.sub_gerber_combo.currentText()
|
self.sub_grb_obj_name = self.sub_gerber_combo.currentText()
|
||||||
if self.sub_grb_obj_name == '':
|
if self.sub_grb_obj_name == '':
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
_("No Substractor object loaded."))
|
_("No Subtractor object loaded."))
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get substractor object.
|
# Get substractor object.
|
||||||
|
@ -458,7 +466,7 @@ class ToolSub(FlatCAMTool):
|
||||||
self.sub_geo_obj_name = self.sub_geo_combo.currentText()
|
self.sub_geo_obj_name = self.sub_geo_combo.currentText()
|
||||||
if self.sub_geo_obj_name == '':
|
if self.sub_geo_obj_name == '':
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
_("No Substractor object loaded."))
|
_("No Subtractor object loaded."))
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get substractor object.
|
# Get substractor object.
|
||||||
|
@ -472,7 +480,7 @@ class ToolSub(FlatCAMTool):
|
||||||
|
|
||||||
if self.sub_geo_obj.multigeo:
|
if self.sub_geo_obj.multigeo:
|
||||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||||
_("Currently, the Substractor geometry cannot be of type Multigeo."))
|
_("Currently, the Subtractor geometry cannot be of type Multigeo."))
|
||||||
return
|
return
|
||||||
|
|
||||||
# create the target_options obj
|
# create the target_options obj
|
||||||
|
|
|
@ -5,8 +5,10 @@
|
||||||
# MIT Licence #
|
# MIT Licence #
|
||||||
# ##########################################################
|
# ##########################################################
|
||||||
|
|
||||||
|
from PyQt5 import QtWidgets
|
||||||
from FlatCAMTool import FlatCAMTool
|
from FlatCAMTool import FlatCAMTool
|
||||||
from FlatCAMObj import *
|
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, EvalEntry2
|
||||||
|
from FlatCAMObj import FlatCAMCNCjob
|
||||||
|
|
||||||
import gettext
|
import gettext
|
||||||
import FlatCAMTranslation as fcTranslate
|
import FlatCAMTranslation as fcTranslate
|
||||||
|
@ -271,7 +273,7 @@ class ToolTransform(FlatCAMTool):
|
||||||
_("Flip the selected object(s) over the X axis.")
|
_("Flip the selected object(s) over the X axis.")
|
||||||
)
|
)
|
||||||
|
|
||||||
hlay0= QtWidgets.QHBoxLayout()
|
hlay0 = QtWidgets.QHBoxLayout()
|
||||||
self.transform_lay.addLayout(hlay0)
|
self.transform_lay.addLayout(hlay0)
|
||||||
|
|
||||||
hlay0.addWidget(self.flipx_button)
|
hlay0.addWidget(self.flipx_button)
|
||||||
|
@ -312,7 +314,7 @@ class ToolTransform(FlatCAMTool):
|
||||||
|
|
||||||
self.ois_flip = OptionalInputSection(self.flip_ref_cb, [self.flip_ref_entry, self.flip_ref_button], logic=True)
|
self.ois_flip = OptionalInputSection(self.flip_ref_cb, [self.flip_ref_entry, self.flip_ref_button], logic=True)
|
||||||
|
|
||||||
hlay1= QtWidgets.QHBoxLayout()
|
hlay1 = QtWidgets.QHBoxLayout()
|
||||||
self.transform_lay.addLayout(hlay1)
|
self.transform_lay.addLayout(hlay1)
|
||||||
|
|
||||||
hlay1.addWidget(self.flip_ref_label)
|
hlay1.addWidget(self.flip_ref_label)
|
||||||
|
|
After Width: | Height: | Size: 485 B |
After Width: | Height: | Size: 648 B |
After Width: | Height: | Size: 453 B |
After Width: | Height: | Size: 590 B |
After Width: | Height: | Size: 533 B |
After Width: | Height: | Size: 785 B |
After Width: | Height: | Size: 690 B |
After Width: | Height: | Size: 504 B |
After Width: | Height: | Size: 700 B |
After Width: | Height: | Size: 393 B |
After Width: | Height: | Size: 481 B |
After Width: | Height: | Size: 463 B |
After Width: | Height: | Size: 669 B |
After Width: | Height: | Size: 425 B |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 499 B |
After Width: | Height: | Size: 602 B |
After Width: | Height: | Size: 443 B |
After Width: | Height: | Size: 553 B |
After Width: | Height: | Size: 496 B |
After Width: | Height: | Size: 605 B |