jpcgt/flatcam/Beta слито с Beta
243
FlatCAMApp.py
|
@ -9,6 +9,8 @@
|
|||
import urllib.request
|
||||
import urllib.parse
|
||||
import urllib.error
|
||||
import webbrowser
|
||||
|
||||
import getopt
|
||||
import random
|
||||
import simplejson as json
|
||||
|
@ -21,7 +23,7 @@ import subprocess
|
|||
import ctypes
|
||||
|
||||
import tkinter as tk
|
||||
from PyQt5 import QtPrintSupport, QtNetwork
|
||||
from PyQt5 import QtPrintSupport
|
||||
|
||||
from contextlib import contextmanager
|
||||
import gc
|
||||
|
@ -40,10 +42,12 @@ import vispy.scene as scene
|
|||
# #######################################
|
||||
from ObjectCollection import *
|
||||
from FlatCAMObj import *
|
||||
from camlib import to_dict, dict2obj, ET, ParseError
|
||||
|
||||
from flatcamGUI.PlotCanvas import *
|
||||
from flatcamGUI.PlotCanvasLegacy import *
|
||||
|
||||
from flatcamGUI.FlatCAMGUI import *
|
||||
|
||||
from FlatCAMCommon import LoudDict
|
||||
from FlatCAMPostProc import load_postprocessors
|
||||
|
||||
|
@ -3061,7 +3065,7 @@ class App(QtCore.QObject):
|
|||
separator=True)
|
||||
|
||||
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.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.editgeo_btn.triggered.connect(self.object2editor)
|
||||
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.distance_btn.triggered.connect(lambda: self.distance_tool.run(toggle=True))
|
||||
|
@ -3228,6 +3233,9 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
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()
|
||||
|
||||
if isinstance(edited_object, FlatCAMGerber) or isinstance(edited_object, FlatCAMGeometry) or \
|
||||
|
@ -3316,6 +3324,9 @@ class App(QtCore.QObject):
|
|||
"""
|
||||
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
|
||||
if self.call_source != 'app':
|
||||
edited_obj = self.collection.get_active()
|
||||
|
@ -4527,10 +4538,10 @@ class App(QtCore.QObject):
|
|||
|
||||
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" '
|
||||
'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>'
|
||||
)
|
||||
)
|
||||
|
@ -4650,6 +4661,10 @@ class App(QtCore.QObject):
|
|||
self.prog_form_lay.addRow(QtWidgets.QLabel('%s' % "@mgix"))
|
||||
|
||||
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.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>' % _("Translator")), 0, 1)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("E-mail")), 0, 2)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Brasilian - Portuguese"), 1, 0)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('<b>%s</b>' % _("Corrections")), 0, 2)
|
||||
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' % " "), 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' % "Marius Stanciu (Google-Translation)"), 2, 1)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 2, 2)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 2, 1)
|
||||
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' % "Marius Stanciu (Google-Translation)"), 3, 1)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 3, 2)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 3, 1)
|
||||
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' % "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' % "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' % "Marius Stanciu (Google-Translation)"), 6, 1)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % " "), 6, 2)
|
||||
self.translator_grid_lay.addWidget(QtWidgets.QLabel('%s' % "Marius Stanciu"), 6, 1)
|
||||
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.translators_tab_layout.addStretch()
|
||||
|
||||
|
@ -7922,9 +7941,12 @@ class App(QtCore.QObject):
|
|||
def add_act(name):
|
||||
obj_for_icon = self.collection.get_by_name(name)
|
||||
add_action = QtWidgets.QAction(parent=self.ui.menuobjects)
|
||||
add_action.setCheckable(True)
|
||||
add_action.setText(name)
|
||||
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)
|
||||
|
||||
for name in gerber_list:
|
||||
|
@ -7950,6 +7972,17 @@ class App(QtCore.QObject):
|
|||
for name in doc_list:
|
||||
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':
|
||||
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.setText(obj.options['name'])
|
||||
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)
|
||||
|
||||
|
@ -7984,6 +8019,39 @@ class App(QtCore.QObject):
|
|||
pass
|
||||
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):
|
||||
if self.ui.grid_snap_btn.isChecked():
|
||||
return True
|
||||
|
@ -8426,93 +8494,40 @@ class App(QtCore.QObject):
|
|||
objects_under_the_click_list.append(obj.options['name'])
|
||||
|
||||
try:
|
||||
# If there is no element in the overlapped objects list then make everyone inactive
|
||||
# because we selected "nothing"
|
||||
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:
|
||||
if objects_under_the_click_list:
|
||||
curr_sel_obj = self.collection.get_active()
|
||||
# case when there is only an object under the click and we toggle it
|
||||
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])
|
||||
# create the selection box around the selected object
|
||||
curr_sel_obj = self.collection.get_active()
|
||||
|
||||
# create the selection box around the selected object
|
||||
if self.defaults['global_selection_shape'] is True:
|
||||
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:
|
||||
self.collection.set_all_inactive()
|
||||
self.on_objects_selection(False)
|
||||
self.delete_selection_shape()
|
||||
|
||||
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()
|
||||
|
||||
# create the selection box around the selected object
|
||||
if self.defaults['global_selection_shape'] is True:
|
||||
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'])))
|
||||
self.selected_message(curr_sel_obj=curr_sel_obj)
|
||||
|
||||
else:
|
||||
self.collection.set_all_inactive()
|
||||
self.on_objects_selection(False)
|
||||
self.delete_selection_shape()
|
||||
if self.call_source == 'app':
|
||||
# delete any text in the status bar, implicitly the last object name that was selected
|
||||
self.inform.emit("")
|
||||
else:
|
||||
|
||||
if self.call_source != 'app':
|
||||
self.call_source = 'app'
|
||||
|
||||
self.selected_message(curr_sel_obj=curr_sel_obj)
|
||||
|
||||
else:
|
||||
# If there is no selected object
|
||||
# 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]
|
||||
self.collection.set_active(name_sel_obj)
|
||||
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_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)])
|
||||
|
||||
curr_sel_obj = self.collection.get_active()
|
||||
|
@ -8539,8 +8554,32 @@ class App(QtCore.QObject):
|
|||
if self.defaults['global_selection_shape'] is True:
|
||||
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'])))
|
||||
self.selected_message(curr_sel_obj=curr_sel_obj)
|
||||
|
||||
else:
|
||||
# deselect everything
|
||||
self.on_objects_selection(False)
|
||||
# delete the possible selection box around a possible selected object
|
||||
self.delete_selection_shape()
|
||||
|
||||
# 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'
|
||||
except Exception as e:
|
||||
log.error("[ERROR] Something went bad in App.select_objects(). %s" % str(e))
|
||||
|
||||
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'])))
|
||||
|
@ -8554,16 +8593,6 @@ class App(QtCore.QObject):
|
|||
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():
|
||||
# obj.plot()
|
||||
# curr_sel_obj.plot(color=self.FC_dark_blue, face_color=self.FC_light_blue)
|
||||
|
||||
# TODO: on selected objects change the object colors and do not draw the selection box
|
||||
# self.plotcanvas.update() # this updates the canvas
|
||||
except Exception as e:
|
||||
log.error("[ERROR] Something went bad. %s" % str(e))
|
||||
return
|
||||
|
||||
def delete_hover_shape(self):
|
||||
self.hover_shapes.clear()
|
||||
self.hover_shapes.redraw()
|
||||
|
@ -8621,6 +8650,9 @@ class App(QtCore.QObject):
|
|||
:return:
|
||||
"""
|
||||
|
||||
if sel_obj is None:
|
||||
return
|
||||
|
||||
pt1 = (float(sel_obj.options['xmin']), 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']))
|
||||
|
@ -8634,13 +8666,6 @@ class App(QtCore.QObject):
|
|||
sel_rect = sel_rect.buffer(-0.00393)
|
||||
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:
|
||||
face = color[:-2] + str(hex(int(0.2 * 255)))[2:]
|
||||
outline = color[:-2] + str(hex(int(0.8 * 255)))[2:]
|
||||
|
@ -9044,7 +9069,7 @@ class App(QtCore.QObject):
|
|||
try:
|
||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(
|
||||
caption=_("Export SVG"),
|
||||
directory=self.get_last_save_folder() + '/' + str(name),
|
||||
directory=self.get_last_save_folder() + '/' + str(name) + '_svg',
|
||||
filter=_filter)
|
||||
except TypeError:
|
||||
filename, _f = QtWidgets.QFileDialog.getSaveFileName(caption=_("Export SVG"), filter=_filter)
|
||||
|
|
|
@ -10,24 +10,33 @@
|
|||
# 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
|
||||
from copy import deepcopy
|
||||
from io import StringIO
|
||||
import traceback
|
||||
import inspect # TODO: For debugging only.
|
||||
from datetime import datetime
|
||||
|
||||
from flatcamEditors.FlatCAMTextEditor import TextEditor
|
||||
|
||||
from flatcamGUI.ObjectUI import *
|
||||
from FlatCAMCommon import LoudDict
|
||||
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
|
||||
from camlib import *
|
||||
from flatcamParsers.ParseExcellon import Excellon
|
||||
from flatcamParsers.ParseGerber import Gerber
|
||||
from camlib import Geometry, CNCjob
|
||||
import FlatCAMApp
|
||||
|
||||
import itertools
|
||||
import tkinter as tk
|
||||
import sys
|
||||
import os, sys, itertools
|
||||
import ezdxf
|
||||
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -66,7 +75,7 @@ class FlatCAMObj(QtCore.QObject):
|
|||
app = None
|
||||
|
||||
# signal to plot a single object
|
||||
plot_single_object = pyqtSignal()
|
||||
plot_single_object = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, name):
|
||||
"""
|
||||
|
@ -2804,10 +2813,13 @@ class FlatCAMExcellon(FlatCAMObj, Excellon):
|
|||
|
||||
for tool in tools:
|
||||
if tooldia > self.tools[tool]["C"]:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s %s: %s' % (
|
||||
_("Milling tool for DRILLS is larger than hole size. Cancelled.",
|
||||
str(tool))
|
||||
))
|
||||
self.app.inform.emit(
|
||||
'[ERROR_NOTCL] %s %s: %s' % (
|
||||
_("Milling tool for DRILLS is larger than hole size. Cancelled."),
|
||||
_("Tool"),
|
||||
str(tool)
|
||||
)
|
||||
)
|
||||
return False, "Error: Milling tool is larger than hole."
|
||||
|
||||
def geo_init(geo_obj, app_obj):
|
||||
|
@ -3510,21 +3522,21 @@ class FlatCAMGeometry(FlatCAMObj, Geometry):
|
|||
offset_item = QtWidgets.QComboBox()
|
||||
for item in self.offset_item_options:
|
||||
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'])
|
||||
offset_item.setCurrentIndex(idx)
|
||||
|
||||
type_item = QtWidgets.QComboBox()
|
||||
for item in self.type_item_options:
|
||||
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'])
|
||||
type_item.setCurrentIndex(idx)
|
||||
|
||||
tool_type_item = QtWidgets.QComboBox()
|
||||
for item in self.tool_type_item_options:
|
||||
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'])
|
||||
tool_type_item.setCurrentIndex(idx)
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
from importlib.machinery import SourceFileLoader
|
||||
import os
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from datetime import datetime
|
||||
import math
|
||||
|
||||
# module-root dictionary of postprocessors
|
||||
|
|
|
@ -11,13 +11,20 @@
|
|||
# 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.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 FlatCAMTranslation as fcTranslate
|
||||
|
@ -27,6 +34,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class KeySensitiveListView(QtWidgets.QTreeView):
|
||||
"""
|
||||
|
@ -715,6 +724,16 @@ class ObjectCollection(QtCore.QAbstractItemModel):
|
|||
log.error("[ERROR] Cause: %s" % str(e))
|
||||
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):
|
||||
"""
|
||||
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
|
||||
|
||||
- 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 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
|
||||
- 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__()
|
||||
- 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
|
||||
|
||||
import numpy as np
|
||||
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, dot, float32, \
|
||||
transpose
|
||||
from numpy.linalg import solve, norm
|
||||
|
||||
import re, sys, os, platform
|
||||
import math
|
||||
import platform
|
||||
from copy import deepcopy
|
||||
|
||||
import traceback
|
||||
|
@ -26,8 +23,8 @@ from rtree import index as rtindex
|
|||
from lxml import etree as ET
|
||||
|
||||
# See: http://toblerity.org/shapely/manual.html
|
||||
from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString
|
||||
from shapely.geometry import MultiPoint, MultiPolygon
|
||||
from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString, MultiPoint, MultiPolygon
|
||||
|
||||
from shapely.geometry import box as shply_box
|
||||
from shapely.ops import cascaded_union, unary_union, polygonize
|
||||
import shapely.affinity as affinity
|
||||
|
@ -64,7 +61,6 @@ import gettext
|
|||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
|
||||
log = logging.getLogger('base2')
|
||||
|
@ -162,9 +158,9 @@ class ApertureMacro:
|
|||
|
||||
# ## Variables
|
||||
# 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
|
||||
# definition. All replacements ocurr here.
|
||||
# definition. All replacements occur here.
|
||||
match = ApertureMacro.amvar_re.search(part)
|
||||
if match:
|
||||
var = match.group(1)
|
||||
|
@ -336,8 +332,8 @@ class ApertureMacro:
|
|||
points = [(0, 0)]*nverts
|
||||
|
||||
for i in range(nverts):
|
||||
points[i] = (x + 0.5 * dia * cos(2*pi * i/nverts),
|
||||
y + 0.5 * dia * sin(2*pi * i/nverts))
|
||||
points[i] = (x + 0.5 * dia * np.cos(2*np.pi * i/nverts),
|
||||
y + 0.5 * dia * np.sin(2*np.pi * i/nverts))
|
||||
|
||||
poly = Polygon(points)
|
||||
poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
|
||||
|
@ -637,10 +633,10 @@ class Geometry(object):
|
|||
|
||||
def bounds_rec(obj):
|
||||
if type(obj) is list:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in obj:
|
||||
if type(k) is dict:
|
||||
|
@ -1155,7 +1151,7 @@ class Geometry(object):
|
|||
log.debug("Image import as monochrome.")
|
||||
else:
|
||||
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:
|
||||
total += band
|
||||
total /= 3
|
||||
|
@ -1847,8 +1843,6 @@ class Geometry(object):
|
|||
:return: SVG Element
|
||||
"""
|
||||
|
||||
geom = None
|
||||
|
||||
# Make sure we see a Shapely Geometry class and not a list
|
||||
if str(type(self)) == "<class 'FlatCAMObj.FlatCAMGeometry'>":
|
||||
flat_geo = []
|
||||
|
@ -1873,6 +1867,8 @@ class Geometry(object):
|
|||
elif skew_reference == 'bottomright':
|
||||
skew_ref = (xmax, ymin)
|
||||
|
||||
geom = geom_svg
|
||||
|
||||
if scale_factor_x:
|
||||
geom = affinity.scale(geom_svg, scale_factor_x, 1.0)
|
||||
if scale_factor_y:
|
||||
|
@ -3298,10 +3294,10 @@ class CNCjob(Geometry):
|
|||
|
||||
def bounds_rec(obj):
|
||||
if type(obj) is list:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in obj:
|
||||
if type(k) is dict:
|
||||
|
@ -4049,9 +4045,9 @@ class CNCjob(Geometry):
|
|||
arcdir = [None, None, "cw", "ccw"]
|
||||
if current['G'] in [2, 3]: # arc
|
||||
center = [gobj['I'] + current['X'], gobj['J'] + current['Y']]
|
||||
radius = sqrt(gobj['I']**2 + gobj['J']**2)
|
||||
start = arctan2(-gobj['J'], -gobj['I'])
|
||||
stop = arctan2(-center[1] + y, -center[0] + x)
|
||||
radius = np.sqrt(gobj['I']**2 + gobj['J']**2)
|
||||
start = np.arctan2(-gobj['J'], -gobj['I'])
|
||||
stop = np.arctan2(-center[1] + y, -center[0] + x)
|
||||
path += arc(center, radius, start, stop, arcdir[current['G']], int(self.steps_per_circle / 4))
|
||||
|
||||
# Update current instruction
|
||||
|
@ -4710,10 +4706,10 @@ class CNCjob(Geometry):
|
|||
|
||||
def bounds_rec(obj):
|
||||
if type(obj) is list:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in obj:
|
||||
if type(k) is dict:
|
||||
|
@ -4742,15 +4738,15 @@ class CNCjob(Geometry):
|
|||
|
||||
bounds_coords = bounds_rec(self.solid_geometry)
|
||||
else:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
for k, v in self.cnc_tools.items():
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
try:
|
||||
for k in v['solid_geometry']:
|
||||
minx_, miny_, maxx_, maxy_ = bounds_rec(k)
|
||||
|
@ -5186,10 +5182,10 @@ class CNCjob(Geometry):
|
|||
|
||||
|
||||
def get_bounds(geometry_list):
|
||||
xmin = Inf
|
||||
ymin = Inf
|
||||
xmax = -Inf
|
||||
ymax = -Inf
|
||||
xmin = np.Inf
|
||||
ymin = np.Inf
|
||||
xmax = -np.Inf
|
||||
ymax = -np.Inf
|
||||
|
||||
for gs in geometry_list:
|
||||
try:
|
||||
|
@ -5229,33 +5225,33 @@ def arc(center, radius, start, stop, direction, steps_per_circ):
|
|||
da_sign = {"cw": -1.0, "ccw": 1.0}
|
||||
points = []
|
||||
if direction == "ccw" and stop <= start:
|
||||
stop += 2 * pi
|
||||
stop += 2 * np.pi
|
||||
if direction == "cw" and stop >= start:
|
||||
stop -= 2 * pi
|
||||
stop -= 2 * np.pi
|
||||
|
||||
angle = abs(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
|
||||
for i in range(steps + 1):
|
||||
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
|
||||
|
||||
|
||||
def arc2(p1, p2, center, direction, steps_per_circ):
|
||||
r = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
||||
start = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stop = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
r = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
||||
start = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stop = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
return arc(center, r, start, stop, direction, steps_per_circ)
|
||||
|
||||
|
||||
def arc_angle(start, stop, direction):
|
||||
if direction == "ccw" and stop <= start:
|
||||
stop += 2 * pi
|
||||
stop += 2 * np.pi
|
||||
if direction == "cw" and stop >= start:
|
||||
stop -= 2 * pi
|
||||
stop -= 2 * np.pi
|
||||
|
||||
angle = abs(stop - start)
|
||||
return angle
|
||||
|
@ -5665,12 +5661,12 @@ def three_point_circle(p1, p2, p3):
|
|||
a2 = (p2 + p3) / 2.0
|
||||
|
||||
# Normals
|
||||
b1 = dot((p2 - p1), array([[0, -1], [1, 0]], dtype=float32))
|
||||
b2 = dot((p3 - p2), array([[0, 1], [-1, 0]], dtype=float32))
|
||||
b1 = np.dot((p2 - p1), np.array([[0, -1], [1, 0]], dtype=np.float32))
|
||||
b2 = np.dot((p3 - p2), np.array([[0, 1], [-1, 0]], dtype=np.float32))
|
||||
|
||||
# Params
|
||||
try:
|
||||
T = solve(transpose(array([-b1, b2])), a1 - a2)
|
||||
T = solve(np.transpose(np.array([-b1, b2])), a1 - a2)
|
||||
except Exception as e:
|
||||
log.debug("camlib.three_point_circle() --> %s" % str(e))
|
||||
return
|
||||
|
@ -5685,11 +5681,11 @@ def three_point_circle(p1, p2, p3):
|
|||
|
||||
|
||||
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):
|
||||
return sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
|
||||
return np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
|
||||
|
||||
|
||||
class FlatCAMRTree(object):
|
||||
|
|
|
@ -12,14 +12,17 @@ class Polygon(object):
|
|||
self.context = context
|
||||
else:
|
||||
self.context = getattr(context, '__geo_interface__', context)
|
||||
|
||||
@property
|
||||
def geom_type(self):
|
||||
return (getattr(self.context, 'geom_type', None)
|
||||
or self.context['type'])
|
||||
|
||||
@property
|
||||
def exterior(self):
|
||||
return (getattr(self.context, 'exterior', None)
|
||||
or self.context['coordinates'][0])
|
||||
|
||||
@property
|
||||
def interiors(self):
|
||||
value = getattr(self.context, 'interiors', None)
|
||||
|
|
|
@ -8,19 +8,23 @@
|
|||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from PyQt5.QtCore import Qt, QSettings
|
||||
|
||||
from shapely.geometry import LineString, LinearRing, MultiLineString
|
||||
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 camlib import distance, arc, FlatCAMRTreeStorage
|
||||
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
|
||||
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
|
@ -30,6 +34,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class FCDrillAdd(FCShapeTool):
|
||||
"""
|
||||
|
@ -556,7 +562,6 @@ class FCSlotArray(FCShapeTool):
|
|||
_("To add an Slot Array first select a tool in Tool Table"))
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
QtGui.QGuiApplication.restoreOverrideCursor()
|
||||
except Exception as e:
|
||||
|
@ -1006,7 +1011,6 @@ class FCDrillResize(FCShapeTool):
|
|||
|
||||
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)
|
||||
# is added.
|
||||
# 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)
|
||||
ordered_edited_points = sorted(zip(edited_points.keys(), edited_points.values()))
|
||||
|
||||
|
||||
current_tool = 0
|
||||
for tool_dia in ordered_edited_points:
|
||||
current_tool += 1
|
||||
|
@ -3214,8 +3217,7 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
_("An internal error has ocurred. See Shell.\n")
|
||||
msg += traceback.format_exc()
|
||||
app_obj.inform.emit(msg)
|
||||
raise
|
||||
# raise
|
||||
return
|
||||
|
||||
with self.app.proc_container.new(_("Creating Excellon.")):
|
||||
|
||||
|
@ -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
|
||||
# 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
|
||||
# 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]
|
||||
else:
|
||||
self.storage_dict[storage].remove(del_shape)
|
||||
|
@ -3998,10 +4001,10 @@ class FlatCAMExcEditor(QtCore.QObject):
|
|||
|
||||
|
||||
def get_shapely_list_bounds(geometry_list):
|
||||
xmin = Inf
|
||||
ymin = Inf
|
||||
xmax = -Inf
|
||||
ymax = -Inf
|
||||
xmin = np.Inf
|
||||
ymin = np.Inf
|
||||
xmax = -np.Inf
|
||||
ymax = -np.Inf
|
||||
|
||||
for gs in geometry_list:
|
||||
try:
|
||||
|
|
|
@ -13,24 +13,26 @@
|
|||
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from PyQt5.QtCore import Qt, QSettings
|
||||
from camlib import *
|
||||
|
||||
from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStorage
|
||||
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 mapping
|
||||
from shapely.ops import cascaded_union, unary_union
|
||||
import shapely.affinity as affinity
|
||||
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 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
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -1060,7 +1062,6 @@ class TransformEditorTool(FlatCAMTool):
|
|||
_("Transformation cancelled. No shape selected."))
|
||||
return
|
||||
|
||||
|
||||
self.draw_app.select_tool("select")
|
||||
self.app.ui.notebook.setTabText(2, "Tools")
|
||||
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
|
||||
|
@ -1081,10 +1082,7 @@ class TransformEditorTool(FlatCAMTool):
|
|||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Wrong value format entered, use a number."))
|
||||
return
|
||||
self.app.worker_task.emit({'fcn': self.on_rotate_action,
|
||||
'params': [value]})
|
||||
# self.on_rotate_action(value)
|
||||
return
|
||||
self.app.worker_task.emit({'fcn': self.on_rotate_action, 'params': [value]})
|
||||
|
||||
def on_flipx(self):
|
||||
# self.on_flip("Y")
|
||||
|
@ -1205,13 +1203,9 @@ class TransformEditorTool(FlatCAMTool):
|
|||
axis = 'Y'
|
||||
point = (0, 0)
|
||||
if self.scale_zero_ref_cb.get_value():
|
||||
self.app.worker_task.emit({'fcn': self.on_scale,
|
||||
'params': [axis, xvalue, yvalue, point]})
|
||||
# self.on_scale("Y", xvalue, yvalue, point=(0,0))
|
||||
self.app.worker_task.emit({'fcn': self.on_scale, 'params': [axis, xvalue, yvalue, point]})
|
||||
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
|
||||
|
||||
|
@ -1304,7 +1298,7 @@ class TransformEditorTool(FlatCAMTool):
|
|||
|
||||
except Exception as e:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
||||
(_("Rotation action was not executed"),str(e)))
|
||||
(_("Rotation action was not executed"), str(e)))
|
||||
return
|
||||
|
||||
def on_flip(self, axis):
|
||||
|
@ -1664,10 +1658,10 @@ class DrawToolShape(object):
|
|||
# now it can get bounds for nested lists of objects
|
||||
def bounds_rec(shape_el):
|
||||
if type(shape_el) is list:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in shape_el:
|
||||
minx_, miny_, maxx_, maxy_ = bounds_rec(k)
|
||||
|
@ -1904,10 +1898,10 @@ class DrawTool(object):
|
|||
def bounds(self, obj):
|
||||
def bounds_rec(o):
|
||||
if type(o) is list:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in o:
|
||||
try:
|
||||
|
@ -1977,7 +1971,7 @@ class FCCircle(FCShapeTool):
|
|||
if len(self.points) == 1:
|
||||
p1 = self.points[0]
|
||||
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 None
|
||||
|
@ -2086,36 +2080,36 @@ class FCArc(FCShapeTool):
|
|||
p1 = self.points[1]
|
||||
p2 = data
|
||||
|
||||
radius = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
radius = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
|
||||
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
||||
self.direction, self.steps_per_circ)),
|
||||
Point(center)])
|
||||
|
||||
elif self.mode == '132':
|
||||
p1 = array(self.points[0])
|
||||
p3 = array(self.points[1])
|
||||
p2 = array(data)
|
||||
p1 = np.array(self.points[0])
|
||||
p3 = np.array(self.points[1])
|
||||
p2 = np.array(data)
|
||||
|
||||
try:
|
||||
center, radius, t = three_point_circle(p1, p2, p3)
|
||||
except TypeError:
|
||||
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])
|
||||
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||
|
||||
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
||||
direction, self.steps_per_circ)),
|
||||
Point(center), Point(p1), Point(p3)])
|
||||
|
||||
else: # '12c'
|
||||
p1 = array(self.points[0])
|
||||
p2 = array(self.points[1])
|
||||
p1 = np.array(self.points[0])
|
||||
p2 = np.array(self.points[1])
|
||||
|
||||
# Midpoint
|
||||
a = (p1 + p2) / 2.0
|
||||
|
@ -2124,7 +2118,7 @@ class FCArc(FCShapeTool):
|
|||
c = p2 - p1
|
||||
|
||||
# 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)
|
||||
|
||||
# Distance
|
||||
|
@ -2133,14 +2127,14 @@ class FCArc(FCShapeTool):
|
|||
# Which side? Cross product with c.
|
||||
# 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]
|
||||
t *= sign(side)
|
||||
t *= np.sign(side)
|
||||
|
||||
# Center = a + bt
|
||||
center = a + b * t
|
||||
|
||||
radius = numpy_norm(center - p1)
|
||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
|
||||
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
|
||||
self.direction, self.steps_per_circ)),
|
||||
|
@ -2156,29 +2150,29 @@ class FCArc(FCShapeTool):
|
|||
p2 = self.points[2]
|
||||
|
||||
radius = distance(center, p1)
|
||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
||||
self.direction, self.steps_per_circ)))
|
||||
|
||||
elif self.mode == '132':
|
||||
p1 = array(self.points[0])
|
||||
p3 = array(self.points[1])
|
||||
p2 = array(self.points[2])
|
||||
p1 = np.array(self.points[0])
|
||||
p3 = np.array(self.points[1])
|
||||
p2 = np.array(self.points[2])
|
||||
|
||||
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])
|
||||
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||
|
||||
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
||||
direction, self.steps_per_circ)))
|
||||
|
||||
else: # self.mode == '12c'
|
||||
p1 = array(self.points[0])
|
||||
p2 = array(self.points[1])
|
||||
pc = array(self.points[2])
|
||||
p1 = np.array(self.points[0])
|
||||
p2 = np.array(self.points[1])
|
||||
pc = np.array(self.points[2])
|
||||
|
||||
# Midpoint
|
||||
a = (p1 + p2) / 2.0
|
||||
|
@ -2187,7 +2181,7 @@ class FCArc(FCShapeTool):
|
|||
c = p2 - p1
|
||||
|
||||
# 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)
|
||||
|
||||
# Distance
|
||||
|
@ -2196,14 +2190,14 @@ class FCArc(FCShapeTool):
|
|||
# Which side? Cross product with c.
|
||||
# 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]
|
||||
t *= sign(side)
|
||||
t *= np.sign(side)
|
||||
|
||||
# Center = a + bt
|
||||
center = a + b * t
|
||||
|
||||
radius = numpy_norm(center - p1)
|
||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
|
||||
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
|
||||
self.direction, self.steps_per_circ)))
|
||||
|
@ -2228,7 +2222,7 @@ class FCRectangle(FCShapeTool):
|
|||
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero.png'))
|
||||
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):
|
||||
self.points.append(point)
|
||||
|
@ -2705,7 +2699,6 @@ class FCText(FCShapeTool):
|
|||
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_text.png'))
|
||||
QtGui.QGuiApplication.setOverrideCursor(self.cursor)
|
||||
|
||||
|
||||
# self.shape_buffer = self.draw_app.shape_buffer
|
||||
self.draw_app = draw_app
|
||||
self.app = draw_app.app
|
||||
|
@ -2734,15 +2727,13 @@ class FCText(FCShapeTool):
|
|||
self.draw_app.select_tool('select')
|
||||
return
|
||||
else:
|
||||
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("No text to add."))
|
||||
self.draw_app.app.inform.emit('[WARNING_NOTCL] %s' % _("No text to add."))
|
||||
return
|
||||
|
||||
self.text_gui.text_path = []
|
||||
self.text_gui.hide_tool()
|
||||
self.complete = True
|
||||
self.draw_app.app.inform.emit('[success]%s' %
|
||||
_(" Done. Adding Text completed."))
|
||||
self.draw_app.app.inform.emit('[success]%s' % _(" Done. Adding Text completed."))
|
||||
|
||||
def utility_geometry(self, data=None):
|
||||
"""
|
||||
|
@ -3502,7 +3493,6 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
except (TypeError, AttributeError):
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
self.app.ui.draw_text.triggered.disconnect()
|
||||
except (TypeError, AttributeError):
|
||||
|
@ -3561,12 +3551,8 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.add_shape(subshape)
|
||||
return
|
||||
|
||||
assert isinstance(shape, DrawToolShape), \
|
||||
"Expected a DrawToolShape, got %s" % type(shape)
|
||||
|
||||
assert shape.geo is not None, \
|
||||
"Shape object has empty geometry (None)"
|
||||
|
||||
assert isinstance(shape, DrawToolShape), "Expected a DrawToolShape, got %s" % type(shape)
|
||||
assert shape.geo is not None, "Shape object has empty geometry (None)"
|
||||
assert (isinstance(shape.geo, list) and len(shape.geo) > 0) or \
|
||||
not isinstance(shape.geo, list), "Shape objects has empty geometry ([])"
|
||||
|
||||
|
@ -4122,13 +4108,17 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
continue
|
||||
|
||||
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
|
||||
|
||||
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:
|
||||
self.plot_shape(geometry=shape.geo, linewidth=1)
|
||||
self.plot_shape(geometry=shape.geo,
|
||||
linewidth=1)
|
||||
continue
|
||||
|
||||
self.shapes.redraw()
|
||||
|
@ -4237,7 +4227,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
"""
|
||||
|
||||
snap_x, snap_y = (x, y)
|
||||
snap_distance = Inf
|
||||
snap_distance = np.Inf
|
||||
|
||||
# # ## Object (corner?) snap
|
||||
# # ## No need for the objects, just the coordinates
|
||||
|
@ -4488,7 +4478,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
results = []
|
||||
for t in selected:
|
||||
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,
|
||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||
join_style=join_style)
|
||||
|
@ -4519,22 +4509,18 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
selected = self.get_selected()
|
||||
|
||||
if buf_distance < 0:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Negative buffer value is not accepted.")
|
||||
)
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' % _("Negative buffer value is not accepted."))
|
||||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
return 'fail'
|
||||
|
||||
if len(selected) == 0:
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Nothing selected for buffering."))
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Nothing selected for buffering."))
|
||||
return 'fail'
|
||||
|
||||
if not isinstance(buf_distance, float):
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' %
|
||||
_("Invalid distance for buffering."))
|
||||
self.app.inform.emit('[WARNING_NOTCL] %s' % _("Invalid distance for buffering."))
|
||||
# deselect everything
|
||||
self.selected = []
|
||||
self.replot()
|
||||
|
@ -4546,7 +4532,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
t.geo = Polygon(t.geo)
|
||||
|
||||
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,
|
||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||
join_style=join_style)
|
||||
|
@ -4564,8 +4550,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.add_shape(DrawToolShape(sha))
|
||||
|
||||
self.replot()
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("Interior buffer geometry created."))
|
||||
self.app.inform.emit('[success] %s' % _("Interior buffer geometry created."))
|
||||
|
||||
def buffer_ext(self, buf_distance, join_style):
|
||||
selected = self.get_selected()
|
||||
|
@ -4598,7 +4583,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
t.geo = Polygon(t.geo)
|
||||
|
||||
if isinstance(t.geo, Polygon) and not t.geo.is_empty:
|
||||
results.append((t.geo).buffer(
|
||||
results.append(t.geo.buffer(
|
||||
buf_distance,
|
||||
resolution=int(int(self.app.defaults["geometry_circle_steps"]) / 4),
|
||||
join_style=join_style)
|
||||
|
@ -4616,68 +4601,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
self.add_shape(DrawToolShape(sha))
|
||||
|
||||
self.replot()
|
||||
self.app.inform.emit('[success] %s' %
|
||||
_("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()
|
||||
self.app.inform.emit('[success] %s' % _("Exterior buffer geometry created."))
|
||||
|
||||
def paint(self, tooldia, overlap, margin, connect, contour, method):
|
||||
|
||||
self.paint_tooldia = tooldia
|
||||
|
||||
selected = self.get_selected()
|
||||
|
||||
if len(selected) == 0:
|
||||
|
@ -4814,11 +4742,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
|
|||
|
||||
|
||||
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):
|
||||
return sqrt(vec[0] ** 2 + vec[1] ** 2)
|
||||
return np.sqrt(vec[0] ** 2 + vec[1] ** 2)
|
||||
|
||||
|
||||
def poly2rings(poly):
|
||||
|
@ -4826,10 +4754,10 @@ def poly2rings(poly):
|
|||
|
||||
|
||||
def get_shapely_list_bounds(geometry_list):
|
||||
xmin = Inf
|
||||
ymin = Inf
|
||||
xmax = -Inf
|
||||
ymax = -Inf
|
||||
xmin = np.Inf
|
||||
ymin = np.Inf
|
||||
xmax = -np.Inf
|
||||
ymax = -np.Inf
|
||||
|
||||
for gs in geometry_list:
|
||||
try:
|
||||
|
|
|
@ -8,29 +8,28 @@
|
|||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from PyQt5.QtCore import Qt, QSettings
|
||||
|
||||
from shapely.geometry import LineString, LinearRing, MultiLineString
|
||||
# from shapely.geometry import mapping
|
||||
from shapely.ops import cascaded_union, unary_union
|
||||
from shapely.geometry import LineString, LinearRing, MultiLineString, Point, Polygon, MultiPolygon
|
||||
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
|
||||
import threading
|
||||
import time
|
||||
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, \
|
||||
SpinBoxDelegate, EvalEntry, EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
|
||||
from FlatCAMObj import FlatCAMGerber
|
||||
from flatcamParsers.ParseGerber import Gerber
|
||||
EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
import FlatCAMApp
|
||||
|
||||
import numpy as np
|
||||
from numpy.linalg import norm as numpy_norm
|
||||
import math
|
||||
|
||||
# from vispy.io import read_png
|
||||
# import pngcanvas
|
||||
|
||||
import traceback
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -39,6 +38,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class DrawToolShape(object):
|
||||
"""
|
||||
|
@ -147,10 +148,10 @@ class DrawTool(object):
|
|||
def bounds(obj):
|
||||
def bounds_rec(o):
|
||||
if type(o) is list:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in o:
|
||||
try:
|
||||
|
@ -311,13 +312,13 @@ class FCPad(FCShapeTool):
|
|||
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]
|
||||
d_start_angle = math.pi
|
||||
d_start_angle = np.pi
|
||||
d_stop_angle = 0.0
|
||||
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]
|
||||
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)
|
||||
|
||||
geo.append(p1)
|
||||
|
@ -340,13 +341,13 @@ class FCPad(FCShapeTool):
|
|||
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]
|
||||
d_start_angle = math.pi / 2
|
||||
d_stop_angle = 1.5 * math.pi
|
||||
d_start_angle = np.pi / 2
|
||||
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)
|
||||
|
||||
right_center = [point_x + self.half_width - self.half_height, point_y]
|
||||
u_start_angle = 1.5 * math.pi
|
||||
u_stop_angle = math.pi / 2
|
||||
u_start_angle = 1.5 * np.pi
|
||||
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)
|
||||
|
||||
geo.append(p1)
|
||||
|
@ -618,13 +619,13 @@ class FCPadArray(FCShapeTool):
|
|||
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]
|
||||
d_start_angle = math.pi
|
||||
d_start_angle = np.pi
|
||||
d_stop_angle = 0.0
|
||||
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]
|
||||
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)
|
||||
|
||||
geo.append(p1)
|
||||
|
@ -647,13 +648,13 @@ class FCPadArray(FCShapeTool):
|
|||
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]
|
||||
d_start_angle = math.pi / 2
|
||||
d_stop_angle = 1.5 * math.pi
|
||||
d_start_angle = np.pi / 2
|
||||
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)
|
||||
|
||||
right_center = [point_x + self.half_width - self.half_height, point_y]
|
||||
u_start_angle = 1.5 * math.pi
|
||||
u_stop_angle = math.pi / 2
|
||||
u_start_angle = 1.5 * np.pi
|
||||
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)
|
||||
|
||||
geo.append(p1)
|
||||
|
@ -1415,7 +1416,7 @@ class FCDisc(FCShapeTool):
|
|||
if len(self.points) == 1:
|
||||
p1 = self.points[0]
|
||||
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))
|
||||
return DrawToolUtilityShape(new_geo_el)
|
||||
|
||||
|
@ -1557,9 +1558,9 @@ class FCSemiDisc(FCShapeTool):
|
|||
p1 = self.points[1]
|
||||
p2 = data
|
||||
|
||||
radius = 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])
|
||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
radius = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2) + (self.buf_val / 2)
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
|
||||
new_geo_el['solid'] = LineString(
|
||||
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])
|
||||
|
||||
elif self.mode == '132':
|
||||
p1 = array(self.points[0])
|
||||
p3 = array(self.points[1])
|
||||
p2 = array(data)
|
||||
p1 = np.array(self.points[0])
|
||||
p3 = np.array(self.points[1])
|
||||
p2 = np.array(data)
|
||||
|
||||
try:
|
||||
center, radius, t = three_point_circle(p1, p2, p3)
|
||||
except TypeError:
|
||||
return
|
||||
|
||||
direction = 'cw' if sign(t) > 0 else 'ccw'
|
||||
direction = 'cw' if np.sign(t) > 0 else 'ccw'
|
||||
radius += (self.buf_val / 2)
|
||||
|
||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||
|
||||
new_geo_el['solid'] = LineString(
|
||||
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])
|
||||
|
||||
else: # '12c'
|
||||
p1 = array(self.points[0])
|
||||
p2 = array(self.points[1])
|
||||
p1 = np.array(self.points[0])
|
||||
p2 = np.array(self.points[1])
|
||||
# Midpoint
|
||||
a = (p1 + p2) / 2.0
|
||||
|
||||
|
@ -1600,7 +1601,7 @@ class FCSemiDisc(FCShapeTool):
|
|||
c = p2 - p1
|
||||
|
||||
# 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)
|
||||
|
||||
# Distance
|
||||
|
@ -1609,14 +1610,14 @@ class FCSemiDisc(FCShapeTool):
|
|||
# Which side? Cross product with c.
|
||||
# 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]
|
||||
t *= sign(side)
|
||||
t *= np.sign(side)
|
||||
|
||||
# Center = a + bt
|
||||
center = a + b * t
|
||||
|
||||
radius = numpy_norm(center - p1) + (self.buf_val / 2)
|
||||
startangle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
|
||||
new_geo_el['solid'] = LineString(
|
||||
arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ))
|
||||
|
@ -1636,8 +1637,8 @@ class FCSemiDisc(FCShapeTool):
|
|||
p2 = self.points[2]
|
||||
|
||||
radius = distance(center, p1) + (self.buf_val / 2)
|
||||
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stop_angle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stop_angle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
new_geo_el['solid'] = Polygon(
|
||||
arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ))
|
||||
new_geo_el['follow'] = Polygon(
|
||||
|
@ -1645,16 +1646,16 @@ class FCSemiDisc(FCShapeTool):
|
|||
self.geometry = DrawToolShape(new_geo_el)
|
||||
|
||||
elif self.mode == '132':
|
||||
p1 = array(self.points[0])
|
||||
p3 = array(self.points[1])
|
||||
p2 = array(self.points[2])
|
||||
p1 = np.array(self.points[0])
|
||||
p3 = np.array(self.points[1])
|
||||
p2 = np.array(self.points[2])
|
||||
|
||||
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)
|
||||
|
||||
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stop_angle = arctan2(p3[1] - center[1], p3[0] - center[0])
|
||||
start_angle = np.arctan2(p1[1] - center[1], p1[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['follow'] = Polygon(
|
||||
|
@ -1662,9 +1663,9 @@ class FCSemiDisc(FCShapeTool):
|
|||
self.geometry = DrawToolShape(new_geo_el)
|
||||
|
||||
else: # self.mode == '12c'
|
||||
p1 = array(self.points[0])
|
||||
p2 = array(self.points[1])
|
||||
pc = array(self.points[2])
|
||||
p1 = np.array(self.points[0])
|
||||
p2 = np.array(self.points[1])
|
||||
pc = np.array(self.points[2])
|
||||
|
||||
# Midpoint
|
||||
a = (p1 + p2) / 2.0
|
||||
|
@ -1673,7 +1674,7 @@ class FCSemiDisc(FCShapeTool):
|
|||
c = p2 - p1
|
||||
|
||||
# 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)
|
||||
|
||||
# Distance
|
||||
|
@ -1682,14 +1683,14 @@ class FCSemiDisc(FCShapeTool):
|
|||
# Which side? Cross product with c.
|
||||
# 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]
|
||||
t *= sign(side)
|
||||
t *= np.sign(side)
|
||||
|
||||
# Center = a + bt
|
||||
center = a + b * t
|
||||
|
||||
radius = numpy_norm(center - p1) + (self.buf_val / 2)
|
||||
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stop_angle = arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
|
||||
stop_angle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
|
||||
|
||||
new_geo_el['solid'] = Polygon(
|
||||
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)
|
||||
|
||||
apcode_lbl = QtWidgets.QLabel('%s:' % _('Aperture Code'))
|
||||
apcode_lbl.setToolTip(
|
||||
_("Code for the new aperture")
|
||||
)
|
||||
apcode_lbl.setToolTip(_("Code for the new aperture"))
|
||||
grid1.addWidget(apcode_lbl, 1, 0)
|
||||
|
||||
self.apcode_entry = FCEntry()
|
||||
|
@ -2495,12 +2494,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
self.addaperture_btn = QtWidgets.QPushButton(_('Add'))
|
||||
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.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.delaperture_btn)
|
||||
|
@ -2677,7 +2676,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
self.array_type_combo = FCComboBox()
|
||||
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")
|
||||
)
|
||||
self.array_type_combo.addItem(_("Linear"))
|
||||
|
@ -2733,7 +2732,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
|
||||
self.linear_angle_label = QtWidgets.QLabel('%s:' % _('Angle'))
|
||||
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"
|
||||
"Min value is: -359.99 degrees.\n"
|
||||
"Max value is: 360.00 degrees.")
|
||||
|
@ -3245,7 +3244,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
|
|||
self.storage_dict[ap_id]['width'] = dims[0]
|
||||
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)
|
||||
|
||||
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_transformations.triggered.connect(self.on_transform)
|
||||
|
||||
|
||||
def disconnect_canvas_event_handlers(self):
|
||||
|
||||
# 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
|
||||
# that fits inside the solid. otherwise we may loose the solid
|
||||
for apid in self.gerber_obj.apertures:
|
||||
temp_solid_geometry= []
|
||||
temp_solid_geometry = []
|
||||
if 'geometry' in self.gerber_obj.apertures[apid]:
|
||||
# for elem in self.gerber_obj.apertures[apid]['geometry']:
|
||||
# if 'solid' in elem:
|
||||
|
@ -6032,10 +6030,10 @@ class TransformEditorTool(FlatCAMTool):
|
|||
|
||||
|
||||
def get_shapely_list_bounds(geometry_list):
|
||||
xmin = Inf
|
||||
ymin = Inf
|
||||
xmax = -Inf
|
||||
ymax = -Inf
|
||||
xmin = np.Inf
|
||||
ymin = np.Inf
|
||||
xmax = -np.Inf
|
||||
ymax = -np.Inf
|
||||
|
||||
for gs in geometry_list:
|
||||
try:
|
||||
|
|
|
@ -12,8 +12,12 @@
|
|||
# ##########################################################
|
||||
|
||||
from flatcamGUI.PreferencesUI import *
|
||||
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool
|
||||
from matplotlib.backend_bases import KeyEvent as mpl_key_event
|
||||
|
||||
import webbrowser
|
||||
from copy import deepcopy
|
||||
from datetime import datetime
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -70,15 +74,15 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
self.menufilenew = self.menufile.addMenu(QtGui.QIcon('share/file16.png'), _('&New'))
|
||||
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(
|
||||
_("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(
|
||||
_("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(
|
||||
_("Will create a new, empty Excellon Object.")
|
||||
)
|
||||
|
@ -416,6 +420,12 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
# ########################## 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 # ######################################
|
||||
|
@ -682,22 +692,23 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
self.file_open_excellon_btn = self.toolbarfile.addAction(QtGui.QIcon('share/drill32.png'), _("Open Excellon"))
|
||||
self.toolbarfile.addSeparator()
|
||||
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# ###############################
|
||||
# ########################################################################
|
||||
self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32_bis.png'), _("New Blank Geometry"))
|
||||
self.newgrb_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32.png'), _("New Blank Gerber"))
|
||||
self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_exc32.png'), _("New Blank Excellon"))
|
||||
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_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.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(
|
||||
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.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.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'),
|
||||
|
@ -705,7 +716,6 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
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'))
|
||||
|
||||
|
||||
# ########################################################################
|
||||
# ########################## 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.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.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.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_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_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.toolbarfile.addSeparator()
|
||||
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 # ##
|
||||
self.newgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_geo32_bis.png'), _("New Blank Geometry"))
|
||||
self.newexc_btn = self.toolbargeo.addAction(QtGui.QIcon('share/new_exc32.png'), _("New Blank Excellon"))
|
||||
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_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.editgeo_btn = self.toolbargeo.addAction(QtGui.QIcon('share/edit32.png'), _("Editor"))
|
||||
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.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.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'),
|
||||
|
@ -2148,11 +2160,11 @@ class FlatCAMGUI(QtWidgets.QMainWindow):
|
|||
self.paint_btn = self.toolbartools.addAction(QtGui.QIcon('share/paint20_1.png'), _("Paint Tool"))
|
||||
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.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.toolbartools.addSeparator()
|
||||
|
||||
|
@ -3696,7 +3708,7 @@ class FlatCAMSystemTray(QtWidgets.QSystemTrayIcon):
|
|||
|
||||
class BookmarkManager(QtWidgets.QWidget):
|
||||
|
||||
mark_rows = pyqtSignal()
|
||||
mark_rows = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, app, storage, parent=None):
|
||||
super(BookmarkManager, self).__init__(parent)
|
||||
|
@ -3754,7 +3766,7 @@ class BookmarkManager(QtWidgets.QWidget):
|
|||
new_vlay = QtWidgets.QVBoxLayout()
|
||||
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)
|
||||
|
||||
form0 = QtWidgets.QFormLayout()
|
||||
|
@ -3958,8 +3970,9 @@ class BookmarkManager(QtWidgets.QWidget):
|
|||
|
||||
filter__ = "Text File (*.TXT);;All Files (*.*)"
|
||||
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()),
|
||||
n=_("Bookmarks"),
|
||||
date=date),
|
||||
filter=filter__)
|
||||
|
||||
|
@ -3986,7 +3999,7 @@ class BookmarkManager(QtWidgets.QWidget):
|
|||
self.app.log.error("Could not load defaults file.")
|
||||
self.app.log.error(str(e))
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("Could not load bookamrks file."))
|
||||
_("Could not load bookmarks file."))
|
||||
return
|
||||
|
||||
# Save update options
|
||||
|
@ -4019,7 +4032,7 @@ class BookmarkManager(QtWidgets.QWidget):
|
|||
with open(filename) as f:
|
||||
bookmarks = f.readlines()
|
||||
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' %
|
||||
_("Could not load bookmarks file."))
|
||||
return
|
||||
|
|
|
@ -12,18 +12,14 @@
|
|||
# ##########################################################
|
||||
|
||||
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.QtGui import QColor, QKeySequence, QPalette, QTextCursor
|
||||
from PyQt5.QtGui import QKeySequence, QTextCursor
|
||||
|
||||
from copy import copy
|
||||
import re
|
||||
import logging
|
||||
import html
|
||||
import webbrowser
|
||||
from copy import deepcopy
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
@ -513,7 +509,7 @@ class EvalEntry2(QtWidgets.QLineEdit):
|
|||
|
||||
class FCSpinner(QtWidgets.QSpinBox):
|
||||
|
||||
returnPressed = pyqtSignal()
|
||||
returnPressed = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(FCSpinner, self).__init__(parent)
|
||||
|
@ -580,7 +576,7 @@ class FCSpinner(QtWidgets.QSpinBox):
|
|||
|
||||
class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
|
||||
|
||||
returnPressed = pyqtSignal()
|
||||
returnPressed = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super(FCDoubleSpinner, self).__init__(parent)
|
||||
|
@ -869,16 +865,16 @@ class FCTextAreaExtended(QtWidgets.QTextEdit):
|
|||
if self.textCursor().block().text().startswith(" "):
|
||||
# skip the white space
|
||||
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()
|
||||
if character == "#":
|
||||
# delete #
|
||||
self.textCursor().deletePreviousChar()
|
||||
# delete white space
|
||||
self.moveCursor(QtGui.QTextCursor.NextWord,QtGui.QTextCursor.KeepAnchor)
|
||||
self.moveCursor(QtGui.QTextCursor.NextWord, QtGui.QTextCursor.KeepAnchor)
|
||||
self.textCursor().removeSelectedText()
|
||||
else:
|
||||
self.moveCursor(QtGui.QTextCursor.PreviousCharacter,QtGui.QTextCursor.KeepAnchor)
|
||||
self.moveCursor(QtGui.QTextCursor.PreviousCharacter, QtGui.QTextCursor.KeepAnchor)
|
||||
self.textCursor().insertText("# ")
|
||||
cursor = QtGui.QTextCursor(self.textCursor())
|
||||
cursor.setPosition(pos)
|
||||
|
@ -1261,7 +1257,6 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
attached = True
|
||||
break
|
||||
|
||||
|
||||
# If the tab is not attached, close it's window and
|
||||
# remove the reference to it
|
||||
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
|
||||
"""
|
||||
|
||||
onCloseSignal = pyqtSignal(QtWidgets.QWidget, str, QtGui.QIcon)
|
||||
onDropSignal = pyqtSignal(str, QtCore.QPoint)
|
||||
onCloseSignal = QtCore.pyqtSignal(QtWidgets.QWidget, str, QtGui.QIcon)
|
||||
onDropSignal = QtCore.pyqtSignal(str, QtCore.QPoint)
|
||||
|
||||
def __init__(self, name, contentWidget):
|
||||
QtWidgets.QMainWindow.__init__(self, None)
|
||||
|
@ -1384,7 +1379,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
An event filter class to detect a QMainWindow drop event
|
||||
"""
|
||||
|
||||
onDropSignal = pyqtSignal(QtCore.QPoint)
|
||||
onDropSignal = QtCore.pyqtSignal(QtCore.QPoint)
|
||||
|
||||
def __init__(self):
|
||||
QtCore.QObject.__init__(self)
|
||||
|
@ -1416,11 +1411,11 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
return False
|
||||
|
||||
class FCTabBar(QtWidgets.QTabBar):
|
||||
onDetachTabSignal = pyqtSignal(int, QtCore.QPoint)
|
||||
onMoveTabSignal = pyqtSignal(int, int)
|
||||
detachedTabDropSignal = pyqtSignal(str, int, QtCore.QPoint)
|
||||
onDetachTabSignal = QtCore.pyqtSignal(int, QtCore.QPoint)
|
||||
onMoveTabSignal = QtCore.pyqtSignal(int, int)
|
||||
detachedTabDropSignal = QtCore.pyqtSignal(str, int, QtCore.QPoint)
|
||||
|
||||
right_click = pyqtSignal(int)
|
||||
right_click = QtCore.pyqtSignal(int)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QtWidgets.QTabBar.__init__(self, parent)
|
||||
|
@ -1498,7 +1493,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
self.dragInitiated = True
|
||||
|
||||
# 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
|
||||
finishMoveEvent = QtGui.QMouseEvent(
|
||||
|
@ -1591,7 +1586,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
|
|||
|
||||
|
||||
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):
|
||||
super(FCDetachableTab2, self).__init__(protect=protect, protect_by_name=protect_by_name, parent=parent)
|
||||
|
@ -1729,7 +1724,7 @@ class OptionalHideInputSection:
|
|||
|
||||
class FCTable(QtWidgets.QTableWidget):
|
||||
|
||||
drag_drop_sig = pyqtSignal()
|
||||
drag_drop_sig = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, drag_drop=False, protected_rows=None, parent=None):
|
||||
super(FCTable, self).__init__(parent)
|
||||
|
@ -2024,8 +2019,8 @@ class _ExpandableTextEdit(QTextEdit):
|
|||
Class implements edit line, which expands themselves automatically
|
||||
"""
|
||||
|
||||
historyNext = pyqtSignal()
|
||||
historyPrev = pyqtSignal()
|
||||
historyNext = QtCore.pyqtSignal()
|
||||
historyPrev = QtCore.pyqtSignal()
|
||||
|
||||
def __init__(self, termwidget, *args):
|
||||
QTextEdit.__init__(self, *args)
|
||||
|
@ -2148,7 +2143,7 @@ class _ExpandableTextEdit(QTextEdit):
|
|||
|
||||
|
||||
class MyCompleter(QCompleter):
|
||||
insertText = pyqtSignal(str)
|
||||
insertText = QtCore.pyqtSignal(str)
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QCompleter.__init__(self)
|
||||
|
@ -2166,4 +2161,3 @@ class MyCompleter(QCompleter):
|
|||
|
||||
def getSelected(self):
|
||||
return self.lastSelected
|
||||
|
||||
|
|
|
@ -11,8 +11,6 @@
|
|||
# Date: 3/10/2019 #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from PyQt5.QtCore import Qt
|
||||
from flatcamGUI.GUIElements import *
|
||||
import sys
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
# Modified by Marius Stanciu 09/21/2019 #
|
||||
############################################################
|
||||
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
|
||||
# needed for legacy mode
|
||||
|
|
|
@ -8,11 +8,8 @@
|
|||
from PyQt5.QtCore import QSettings
|
||||
from flatcamGUI.GUIElements import *
|
||||
import platform
|
||||
import webbrowser
|
||||
import sys
|
||||
|
||||
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -5121,7 +5118,7 @@ class Tools2RulesCheckPrefGroupUI(OptionsGroupUI):
|
|||
|
||||
self.crlabel = QtWidgets.QLabel("<b>%s:</b>" % _("Parameters"))
|
||||
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.")
|
||||
)
|
||||
self.layout.addWidget(self.crlabel)
|
||||
|
|
|
@ -6,12 +6,15 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
import numpy as np
|
||||
from PyQt5.QtGui import QPalette
|
||||
from PyQt5.QtCore import QSettings
|
||||
|
||||
import numpy as np
|
||||
|
||||
import vispy.scene as scene
|
||||
from vispy.scene.cameras.base_camera import BaseCamera
|
||||
from vispy.color import Color
|
||||
|
||||
import time
|
||||
|
||||
white = Color("#ffffff")
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
# ##########################################################
|
||||
|
||||
from shapely.geometry import LineString
|
||||
from shapely.affinity import rotate
|
||||
|
||||
import logging
|
||||
|
||||
log = logging.getLogger('base2')
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
# ##########################################################
|
||||
|
||||
import math
|
||||
import sys
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
@ -8,6 +18,8 @@ import builtins
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class Excellon(Geometry):
|
||||
"""
|
||||
|
@ -1017,10 +1029,10 @@ class Excellon(Geometry):
|
|||
|
||||
def bounds_rec(obj):
|
||||
if type(obj) is list:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in obj:
|
||||
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.
|
||||
Tool sizes, feedrates an Z-plane dimensions are untouched.
|
||||
|
||||
:param factor: Number by which to scale the object.
|
||||
:type factor: float
|
||||
:param xfactor: Number by which to scale the object.
|
||||
:type xfactor: float
|
||||
:param yfactor: Number by which to scale the object.
|
||||
:type yfactor: float
|
||||
:return: None
|
||||
:rtype: NOne
|
||||
"""
|
||||
|
|
|
@ -11,12 +11,11 @@
|
|||
# ######################################################################
|
||||
|
||||
import re, os, sys, glob
|
||||
import itertools
|
||||
|
||||
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.base import BaseGeometry
|
||||
|
||||
|
||||
import freetype as ft
|
||||
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 gettext
|
||||
|
@ -7,6 +22,8 @@ import builtins
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class Gerber(Geometry):
|
||||
"""
|
||||
|
@ -253,14 +270,14 @@ class Gerber(Geometry):
|
|||
self.apertures[apid] = {"type": "R",
|
||||
"width": float(paramList[0]),
|
||||
"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
|
||||
|
||||
if apertureType == "O": # Obround
|
||||
self.apertures[apid] = {"type": "O",
|
||||
"width": float(paramList[0]),
|
||||
"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
|
||||
|
||||
if apertureType == "P": # Polygon (regular)
|
||||
|
@ -1231,15 +1248,15 @@ class Gerber(Geometry):
|
|||
|
||||
if quadrant_mode == 'MULTI':
|
||||
center = [i + current_x, j + current_y]
|
||||
radius = sqrt(i ** 2 + j ** 2)
|
||||
start = arctan2(-j, -i) # Start angle
|
||||
radius = np.sqrt(i ** 2 + j ** 2)
|
||||
start = np.arctan2(-j, -i) # Start angle
|
||||
# Numerical errors might prevent start == stop therefore
|
||||
# we check ahead of time. This should result in a
|
||||
# 360 degree arc.
|
||||
if current_x == circular_x and current_y == circular_y:
|
||||
stop = start
|
||||
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,
|
||||
arcdir[current_interpolation_mode],
|
||||
|
@ -1273,10 +1290,10 @@ class Gerber(Geometry):
|
|||
valid = False
|
||||
log.debug("I: %f J: %f" % (i, j))
|
||||
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.
|
||||
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:
|
||||
continue # Not a valid center.
|
||||
|
||||
|
@ -1284,16 +1301,16 @@ class Gerber(Geometry):
|
|||
i = center[0] - current_x
|
||||
j = center[1] - current_y
|
||||
|
||||
start = arctan2(-j, -i) # Start angle
|
||||
stop = arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
|
||||
start = np.arctan2(-j, -i) # Start angle
|
||||
stop = np.arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
|
||||
angle = abs(arc_angle(start, stop, arcdir[current_interpolation_mode]))
|
||||
log.debug("ARC START: %f, %f CENTER: %f, %f STOP: %f, %f" %
|
||||
(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" %
|
||||
(start * 180 / pi, stop * 180 / pi, arcdir[current_interpolation_mode],
|
||||
angle * 180 / pi, pi / 2 * 180 / pi, angle <= (pi + 1e-6) / 2))
|
||||
(start * 180 / np.pi, stop * 180 / np.pi, arcdir[current_interpolation_mode],
|
||||
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 ############")
|
||||
this_arc = arc(center, radius, start, stop,
|
||||
arcdir[current_interpolation_mode],
|
||||
|
@ -1367,7 +1384,7 @@ class Gerber(Geometry):
|
|||
|
||||
# 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.")
|
||||
return 'fail'
|
||||
|
||||
|
@ -1478,8 +1495,8 @@ class Gerber(Geometry):
|
|||
n_vertices = aperture['nVertices']
|
||||
points = []
|
||||
for i in range(0, n_vertices):
|
||||
x = loc[0] + 0.5 * diam * (cos(2 * pi * i / n_vertices))
|
||||
y = loc[1] + 0.5 * diam * (sin(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 * (np.sin(2 * np.pi * i / n_vertices))
|
||||
points.append((x, y))
|
||||
ply = Polygon(points)
|
||||
if 'rotation' in aperture:
|
||||
|
@ -1553,10 +1570,10 @@ class Gerber(Geometry):
|
|||
|
||||
def bounds_rec(obj):
|
||||
if type(obj) is list and type(obj) is not MultiPolygon:
|
||||
minx = Inf
|
||||
miny = Inf
|
||||
maxx = -Inf
|
||||
maxy = -Inf
|
||||
minx = np.Inf
|
||||
miny = np.Inf
|
||||
maxx = -np.Inf
|
||||
maxy = -np.Inf
|
||||
|
||||
for k in obj:
|
||||
if type(k) is dict:
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
from svg.path import Line, Arc, CubicBezier, QuadraticBezier, parse_path
|
||||
from svg.path.path import Move
|
||||
from shapely.geometry import LineString
|
||||
from shapely.affinity import skew, affine_transform
|
||||
from shapely.affinity import skew, affine_transform, rotate
|
||||
import numpy as np
|
||||
|
||||
from flatcamParsers.ParseFont import *
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from FlatCAMObj import *
|
||||
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, FCEntry
|
||||
import math
|
||||
|
||||
import gettext
|
||||
|
@ -321,11 +322,11 @@ class ToolCalculator(FlatCAMTool):
|
|||
|
||||
def on_calculate_inch_units(self):
|
||||
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):
|
||||
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):
|
||||
length = float(self.pcblength_entry.get_value())
|
||||
|
|
|
@ -5,12 +5,21 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from ObjectCollection import *
|
||||
from FlatCAMApp import *
|
||||
from shapely.geometry import box
|
||||
from shapely.ops import cascaded_union, unary_union
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox
|
||||
from FlatCAMObj import FlatCAMGerber
|
||||
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -19,6 +28,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class CutOut(FlatCAMTool):
|
||||
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
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 import affinity
|
||||
from PyQt5 import QtCore
|
||||
|
||||
import logging
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -12,6 +17,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class DblSidedTool(FlatCAMTool):
|
||||
|
||||
|
|
|
@ -5,12 +5,15 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from FlatCAMObj import *
|
||||
from flatcamGUI.VisPyVisuals import *
|
||||
from flatcamGUI.GUIElements import FCEntry
|
||||
|
||||
from math import sqrt
|
||||
|
||||
import copy
|
||||
import math
|
||||
import logging
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -19,6 +22,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class Distance(FlatCAMTool):
|
||||
|
||||
|
@ -335,7 +340,7 @@ class Distance(FlatCAMTool):
|
|||
elif len(self.points) == 2:
|
||||
dx = self.points[1][0] - self.points[0][0]
|
||||
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.app.inform.emit(_("MEASURING: Result D(x) = {d_x} | D(y) = {d_y} | Distance = {d_z}").format(
|
||||
|
|
|
@ -5,14 +5,16 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from FlatCAMObj import *
|
||||
from flatcamGUI.VisPyVisuals import *
|
||||
from flatcamGUI.GUIElements import FCEntry
|
||||
|
||||
from shapely.ops import nearest_points
|
||||
from shapely.geometry import Point
|
||||
|
||||
from math import sqrt
|
||||
|
||||
import math
|
||||
import logging
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -21,6 +23,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class DistanceMin(FlatCAMTool):
|
||||
|
||||
|
@ -260,7 +264,7 @@ class DistanceMin(FlatCAMTool):
|
|||
except Exception as e:
|
||||
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.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 #
|
||||
# ##########################################################
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from FlatCAMObj import *
|
||||
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
|
||||
OptionalHideInputSection, OptionalInputSection
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
|
||||
OptionalHideInputSection, OptionalInputSection
|
||||
|
||||
from copy import deepcopy
|
||||
import logging
|
||||
from shapely.geometry import Polygon, MultiPolygon, Point
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -22,6 +23,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
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.film_scaley_label, self.film_scaley_entry])
|
||||
# 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(
|
||||
_("Positive values will skew to the right\n"
|
||||
"while negative values will skew to the left.")
|
||||
|
@ -331,7 +334,7 @@ class Film(FlatCAMTool):
|
|||
|
||||
self.exc_label = QtWidgets.QLabel('%s:' % _("Excellon Obj"))
|
||||
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.setModel(self.app.collection)
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
|
||||
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner
|
||||
from PyQt5 import QtGui, QtWidgets
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
|
|
@ -5,12 +5,13 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from FlatCAMObj import *
|
||||
from flatcamGUI.VisPyVisuals import *
|
||||
from FlatCAMObj import FlatCAMGerber
|
||||
|
||||
from copy import copy
|
||||
|
||||
import logging
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -19,11 +20,13 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolMove(FlatCAMTool):
|
||||
|
||||
toolName = _("Move")
|
||||
replot_signal = pyqtSignal(list)
|
||||
replot_signal = QtCore.pyqtSignal(list)
|
||||
|
||||
def __init__(self, app):
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
|
|
@ -5,12 +5,23 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from copy import copy, deepcopy
|
||||
from ObjectCollection import *
|
||||
import time
|
||||
from shapely.geometry import base
|
||||
from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog
|
||||
from flatcamParsers.ParseGerber import Gerber
|
||||
from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -19,6 +30,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class NonCopperClear(FlatCAMTool, Gerber):
|
||||
|
||||
|
@ -261,7 +274,6 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
)
|
||||
|
||||
grid2.addWidget(self.addtool_btn, 0, 0)
|
||||
# grid2.addWidget(self.copytool_btn, 0, 1)
|
||||
grid2.addWidget(self.deltool_btn, 0, 2)
|
||||
|
||||
self.empty_label_0 = QtWidgets.QLabel('')
|
||||
|
@ -269,6 +281,8 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
|
||||
grid3 = QtWidgets.QGridLayout()
|
||||
self.tools_box.addLayout(grid3)
|
||||
grid3.setColumnStretch(0, 0)
|
||||
grid3.setColumnStretch(1, 1)
|
||||
|
||||
e_lab_1 = QtWidgets.QLabel('<b>%s:</b>' % _("Parameters"))
|
||||
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"))
|
||||
self.tools_table.addContextMenu(
|
||||
"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 ########################################
|
||||
|
@ -739,7 +753,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
tool_type_item = QtWidgets.QComboBox()
|
||||
for item in self.tool_type_item_options:
|
||||
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'])
|
||||
tool_type_item.setCurrentIndex(idx)
|
||||
|
||||
|
@ -747,9 +761,9 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
|
||||
operation_type = QtWidgets.QComboBox()
|
||||
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.setStyleSheet('background-color: rgb(255,255,255)')
|
||||
# operation_type.setStyleSheet('background-color: rgb(255,255,255)')
|
||||
op_idx = operation_type.findText(tooluid_value['operation'])
|
||||
operation_type.setCurrentIndex(op_idx)
|
||||
|
||||
|
@ -1039,12 +1053,19 @@ class NonCopperClear(FlatCAMTool, Gerber):
|
|||
"New diameter value is already in the Tool Table."))
|
||||
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()
|
||||
|
||||
deleted_tools_list = []
|
||||
|
||||
if all:
|
||||
if all_tools:
|
||||
self.paint_tools.clear()
|
||||
self.build_ui()
|
||||
return
|
||||
|
|
|
@ -5,13 +5,19 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from FlatCAMObj import *
|
||||
from shapely.geometry import Point
|
||||
from shapely import affinity
|
||||
from shapely.ops import nearest_points
|
||||
from PyQt5 import QtCore
|
||||
from PyQt5 import QtWidgets, QtCore, QtGui
|
||||
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -20,13 +26,15 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolOptimal(FlatCAMTool):
|
||||
|
||||
toolName = _("Optimal Tool")
|
||||
|
||||
update_text = pyqtSignal(list)
|
||||
update_sec_distances = pyqtSignal(dict)
|
||||
update_text = QtCore.pyqtSignal(list)
|
||||
update_sec_distances = QtCore.pyqtSignal(dict)
|
||||
|
||||
def __init__(self, app):
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
|
|
@ -5,19 +5,22 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from shapely.geometry import Point, Polygon, LineString
|
||||
from shapely.ops import cascaded_union, unary_union
|
||||
import FlatCAMApp
|
||||
|
||||
from FlatCAMObj import *
|
||||
from shapely.geometry import Point, Polygon, LineString, MultiPolygon
|
||||
from shapely.ops import unary_union
|
||||
|
||||
import math
|
||||
from copy import copy, deepcopy
|
||||
import numpy as np
|
||||
|
||||
import zlib
|
||||
import re
|
||||
import time
|
||||
import logging
|
||||
import traceback
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -27,6 +30,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolPDF(FlatCAMTool):
|
||||
"""
|
||||
|
|
|
@ -5,10 +5,25 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from PyQt5.QtCore import Qt
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from copy import copy, deepcopy
|
||||
from ObjectCollection import *
|
||||
from shapely.geometry import base
|
||||
from copy import deepcopy
|
||||
# from ObjectCollection import *
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
|
@ -18,6 +33,8 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolPaint(FlatCAMTool, Gerber):
|
||||
|
||||
|
@ -374,6 +391,7 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
|
||||
self.mm = None
|
||||
self.mp = None
|
||||
self.mr = None
|
||||
|
||||
self.sel_rect = []
|
||||
|
||||
|
@ -641,10 +659,10 @@ class ToolPaint(FlatCAMTool, Gerber):
|
|||
for tooluid_key, tooluid_value in self.paint_tools.items():
|
||||
if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted:
|
||||
tool_id += 1
|
||||
id = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
|
||||
id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
id_item = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
|
||||
id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
|
||||
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
|
||||
# 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()
|
||||
for item in self.tool_type_item_options:
|
||||
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'])
|
||||
tool_type_item.setCurrentIndex(idx)
|
||||
|
||||
|
|
|
@ -5,19 +5,29 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtGui, QtCore
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from copy import copy, deepcopy
|
||||
from ObjectCollection import *
|
||||
import time
|
||||
|
||||
from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
import logging
|
||||
|
||||
fcTranslate.apply_language('strings')
|
||||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class Panelize(FlatCAMTool):
|
||||
|
||||
|
@ -367,15 +377,13 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
# Get source object.
|
||||
try:
|
||||
obj = self.app.collection.get_by_name(str(name))
|
||||
panel_obj = self.app.collection.get_by_name(str(name))
|
||||
except Exception as e:
|
||||
log.debug("Panelize.on_panelize() --> %s" % str(e))
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
||||
(_("Could not retrieve object"), name))
|
||||
return "Could not retrieve object: %s" % name
|
||||
|
||||
panel_obj = obj
|
||||
|
||||
if panel_obj is None:
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
|
||||
(_("Object not found"), panel_obj))
|
||||
|
@ -443,6 +451,18 @@ class Panelize(FlatCAMTool):
|
|||
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():
|
||||
if panel_obj is not None:
|
||||
self.app.inform.emit(_("Generating panel ... "))
|
||||
|
@ -452,7 +472,7 @@ class Panelize(FlatCAMTool):
|
|||
def job_init_excellon(obj_fin, app_obj):
|
||||
currenty = 0.0
|
||||
self.app.progress.emit(10)
|
||||
obj_fin.tools = panel_obj.tools.copy()
|
||||
obj_fin.tools = copied_tools
|
||||
obj_fin.drills = []
|
||||
obj_fin.slots = []
|
||||
obj_fin.solid_geometry = []
|
||||
|
@ -472,7 +492,6 @@ class Panelize(FlatCAMTool):
|
|||
currentx = 0.0
|
||||
for col in range(columns):
|
||||
element += 1
|
||||
disp_number = 0
|
||||
old_disp_number = 0
|
||||
|
||||
if panel_obj.drills:
|
||||
|
@ -493,7 +512,7 @@ class Panelize(FlatCAMTool):
|
|||
drill_nr += 1
|
||||
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%%' %
|
||||
(_("Copy"),
|
||||
int(element),
|
||||
|
@ -520,7 +539,7 @@ class Panelize(FlatCAMTool):
|
|||
slot_nr += 1
|
||||
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%%' %
|
||||
(_("Copy"),
|
||||
int(element),
|
||||
|
@ -557,12 +576,12 @@ class Panelize(FlatCAMTool):
|
|||
# create the initial structure on which to create the panel
|
||||
if isinstance(panel_obj, FlatCAMGeometry):
|
||||
obj_fin.multigeo = panel_obj.multigeo
|
||||
obj_fin.tools = deepcopy(panel_obj.tools)
|
||||
obj_fin.tools = copied_tools
|
||||
if panel_obj.multigeo is True:
|
||||
for tool in panel_obj.tools:
|
||||
obj_fin.tools[tool]['solid_geometry'][:] = []
|
||||
elif isinstance(panel_obj, FlatCAMGerber):
|
||||
obj_fin.apertures = deepcopy(panel_obj.apertures)
|
||||
obj_fin.apertures = copied_apertures
|
||||
for ap in obj_fin.apertures:
|
||||
obj_fin.apertures[ap]['geometry'] = list()
|
||||
|
||||
|
@ -594,7 +613,6 @@ class Panelize(FlatCAMTool):
|
|||
|
||||
for col in range(columns):
|
||||
element += 1
|
||||
disp_number = 0
|
||||
old_disp_number = 0
|
||||
|
||||
if isinstance(panel_obj, FlatCAMGeometry):
|
||||
|
|
|
@ -5,11 +5,11 @@
|
|||
# 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 os
|
||||
from datetime import datetime
|
||||
|
@ -26,7 +26,7 @@ if '_' not in builtins.__dict__:
|
|||
|
||||
class PcbWizard(FlatCAMTool):
|
||||
|
||||
file_loaded = pyqtSignal(str, str)
|
||||
file_loaded = QtCore.pyqtSignal(str, str)
|
||||
|
||||
toolName = _("PcbWizard Import Tool")
|
||||
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtGui, QtCore, QtWidgets
|
||||
from PyQt5.QtCore import Qt
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -18,11 +22,13 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class Properties(FlatCAMTool):
|
||||
toolName = _("Properties")
|
||||
|
||||
calculations_finished = pyqtSignal(float, float, float, float, object)
|
||||
calculations_finished = QtCore.pyqtSignal(float, float, float, float, object)
|
||||
|
||||
def __init__(self, app):
|
||||
FlatCAMTool.__init__(self, app)
|
||||
|
@ -150,18 +156,18 @@ class Properties(FlatCAMTool):
|
|||
|
||||
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."))
|
||||
|
||||
length = 0.0
|
||||
width = 0.0
|
||||
area = 0.0
|
||||
|
||||
geo = obj.solid_geometry
|
||||
geo = obj_prop.solid_geometry
|
||||
if geo:
|
||||
# calculate physical dimensions
|
||||
try:
|
||||
xmin, ymin, xmax, ymax = obj.bounds()
|
||||
xmin, ymin, xmax, ymax = obj_prop.bounds()
|
||||
|
||||
length = abs(xmax - xmin)
|
||||
width = abs(ymax - ymin)
|
||||
|
@ -179,9 +185,9 @@ class Properties(FlatCAMTool):
|
|||
xmax = []
|
||||
ymax = []
|
||||
|
||||
for tool in obj.tools:
|
||||
for tool_k in obj_prop.tools:
|
||||
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)
|
||||
ymin.append(y0)
|
||||
xmax.append(x1)
|
||||
|
@ -207,25 +213,25 @@ class Properties(FlatCAMTool):
|
|||
log.debug("Properties.addItems() --> %s" % str(e))
|
||||
|
||||
area_chull = 0.0
|
||||
if not isinstance(obj, FlatCAMCNCjob):
|
||||
if not isinstance(obj_prop, FlatCAMCNCjob):
|
||||
# calculate and add convex hull area
|
||||
if geo:
|
||||
if isinstance(geo, MultiPolygon):
|
||||
env_obj = geo.convex_hull
|
||||
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
|
||||
(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
|
||||
else:
|
||||
env_obj = cascaded_union(obj.solid_geometry)
|
||||
env_obj = cascaded_union(obj_prop.solid_geometry)
|
||||
env_obj = env_obj.convex_hull
|
||||
|
||||
area_chull = env_obj.area
|
||||
else:
|
||||
try:
|
||||
area_chull = []
|
||||
for tool in obj.tools:
|
||||
area_el = cascaded_union(obj.tools[tool]['solid_geometry']).convex_hull
|
||||
for tool_k in obj_prop.tools:
|
||||
area_el = cascaded_union(obj_prop.tools[tool_k]['solid_geometry']).convex_hull
|
||||
area_chull.append(area_el.area)
|
||||
area_chull = max(area_chull)
|
||||
except Exception as e:
|
||||
|
|
|
@ -5,15 +5,18 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
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 PyQt5 import QtWidgets
|
||||
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -22,12 +25,14 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class RulesCheck(FlatCAMTool):
|
||||
|
||||
toolName = _("Check Rules")
|
||||
|
||||
tool_finished = pyqtSignal(list)
|
||||
tool_finished = QtCore.pyqtSignal(list)
|
||||
|
||||
def __init__(self, app):
|
||||
super(RulesCheck, self).__init__(self)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
# from PyQt5.QtCore import pyqtSignal
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QTextCursor
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QWidget
|
||||
|
|
|
@ -278,7 +278,7 @@ class SolderPaste(FlatCAMTool):
|
|||
)
|
||||
|
||||
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)
|
||||
|
||||
# ## Buttons
|
||||
|
|
|
@ -5,12 +5,18 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets, QtCore
|
||||
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
# from copy import copy, deepcopy
|
||||
from ObjectCollection import *
|
||||
import time
|
||||
from flatcamGUI.GUIElements import FCCheckBox, FCButton
|
||||
|
||||
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 FlatCAMTranslation as fcTranslate
|
||||
import builtins
|
||||
|
@ -19,12 +25,14 @@ fcTranslate.apply_language('strings')
|
|||
if '_' not in builtins.__dict__:
|
||||
_ = gettext.gettext
|
||||
|
||||
log = logging.getLogger('base')
|
||||
|
||||
|
||||
class ToolSub(FlatCAMTool):
|
||||
|
||||
job_finished = QtCore.pyqtSignal(bool)
|
||||
|
||||
toolName = _("Substract Tool")
|
||||
toolName = _("Subtract Tool")
|
||||
|
||||
def __init__(self, app):
|
||||
self.app = app
|
||||
|
@ -64,8 +72,8 @@ class ToolSub(FlatCAMTool):
|
|||
|
||||
self.target_gerber_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||
self.target_gerber_label.setToolTip(
|
||||
_("Gerber object from which to substract\n"
|
||||
"the substractor Gerber object.")
|
||||
_("Gerber object from which to subtract\n"
|
||||
"the subtractor Gerber object.")
|
||||
)
|
||||
|
||||
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.setCurrentIndex(1)
|
||||
|
||||
self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Substractor"))
|
||||
self.sub_gerber_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
|
||||
self.sub_gerber_label.setToolTip(
|
||||
_("Gerber object that will be substracted\n"
|
||||
_("Gerber object that will be subtracted\n"
|
||||
"from the target Gerber object.")
|
||||
)
|
||||
e_lab_1 = QtWidgets.QLabel('')
|
||||
|
@ -87,7 +95,7 @@ class ToolSub(FlatCAMTool):
|
|||
|
||||
self.intersect_btn = FCButton(_('Substract Gerber'))
|
||||
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"
|
||||
"Can be used to remove the overlapping silkscreen\n"
|
||||
"over the soldermask.")
|
||||
|
@ -110,8 +118,8 @@ class ToolSub(FlatCAMTool):
|
|||
|
||||
self.target_geo_label = QtWidgets.QLabel('%s:' % _("Target"))
|
||||
self.target_geo_label.setToolTip(
|
||||
_("Geometry object from which to substract\n"
|
||||
"the substractor Geometry object.")
|
||||
_("Geometry object from which to subtract\n"
|
||||
"the subtractor Geometry object.")
|
||||
)
|
||||
|
||||
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.setCurrentIndex(1)
|
||||
|
||||
self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Substractor"))
|
||||
self.sub_geo_label = QtWidgets.QLabel('%s:' % _("Subtractor"))
|
||||
self.sub_geo_label.setToolTip(
|
||||
_("Geometry object that will be substracted\n"
|
||||
_("Geometry object that will be subtracted\n"
|
||||
"from the target Geometry object.")
|
||||
)
|
||||
e_lab_1 = QtWidgets.QLabel('')
|
||||
|
@ -132,12 +140,12 @@ class ToolSub(FlatCAMTool):
|
|||
form_geo_layout.addRow(self.sub_geo_label, self.sub_geo_combo)
|
||||
|
||||
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.intersect_geo_btn = FCButton(_('Substract Geometry'))
|
||||
self.intersect_geo_btn = FCButton(_('Subtract Geometry'))
|
||||
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.")
|
||||
)
|
||||
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()
|
||||
if self.sub_grb_obj_name == '':
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("No Substractor object loaded."))
|
||||
_("No Subtractor object loaded."))
|
||||
return
|
||||
|
||||
# Get substractor object.
|
||||
|
@ -458,7 +466,7 @@ class ToolSub(FlatCAMTool):
|
|||
self.sub_geo_obj_name = self.sub_geo_combo.currentText()
|
||||
if self.sub_geo_obj_name == '':
|
||||
self.app.inform.emit('[ERROR_NOTCL] %s' %
|
||||
_("No Substractor object loaded."))
|
||||
_("No Subtractor object loaded."))
|
||||
return
|
||||
|
||||
# Get substractor object.
|
||||
|
@ -472,7 +480,7 @@ class ToolSub(FlatCAMTool):
|
|||
|
||||
if self.sub_geo_obj.multigeo:
|
||||
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
|
||||
|
||||
# create the target_options obj
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
# MIT Licence #
|
||||
# ##########################################################
|
||||
|
||||
from PyQt5 import QtWidgets
|
||||
from FlatCAMTool import FlatCAMTool
|
||||
from FlatCAMObj import *
|
||||
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, EvalEntry2
|
||||
from FlatCAMObj import FlatCAMCNCjob
|
||||
|
||||
import gettext
|
||||
import FlatCAMTranslation as fcTranslate
|
||||
|
@ -271,7 +273,7 @@ class ToolTransform(FlatCAMTool):
|
|||
_("Flip the selected object(s) over the X axis.")
|
||||
)
|
||||
|
||||
hlay0= QtWidgets.QHBoxLayout()
|
||||
hlay0 = QtWidgets.QHBoxLayout()
|
||||
self.transform_lay.addLayout(hlay0)
|
||||
|
||||
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)
|
||||
|
||||
hlay1= QtWidgets.QHBoxLayout()
|
||||
hlay1 = QtWidgets.QHBoxLayout()
|
||||
self.transform_lay.addLayout(hlay1)
|
||||
|
||||
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 |