- 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)
This commit is contained in:
Marius Stanciu 2019-10-16 02:28:18 +03:00 committed by Marius
parent 4be989fa5c
commit dfc0b98181
38 changed files with 567 additions and 407 deletions

View File

@ -9,6 +9,8 @@
import urllib.request import urllib.request
import urllib.parse import urllib.parse
import urllib.error import urllib.error
import webbrowser
import getopt import getopt
import random import random
import simplejson as json import simplejson as json
@ -40,10 +42,12 @@ import vispy.scene as scene
# ####################################### # #######################################
from ObjectCollection import * from ObjectCollection import *
from FlatCAMObj import * from FlatCAMObj import *
from camlib import to_dict, dict2obj, ET, ParseError
from flatcamGUI.PlotCanvas import * from flatcamGUI.PlotCanvas import *
from flatcamGUI.PlotCanvasLegacy import * from flatcamGUI.PlotCanvasLegacy import *
from flatcamGUI.FlatCAMGUI import * from flatcamGUI.FlatCAMGUI import *
from FlatCAMCommon import LoudDict from FlatCAMCommon import LoudDict
from FlatCAMPostProc import load_postprocessors from FlatCAMPostProc import load_postprocessors

View File

@ -10,24 +10,33 @@
# File modified by: Marius Stanciu # # File modified by: Marius Stanciu #
# ########################################################## # ##########################################################
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QTextDocument from shapely.geometry import Point, Polygon, MultiPolygon, MultiLineString, LineString, LinearRing
from shapely.ops import cascaded_union
import shapely.affinity as affinity
import copy import copy
from copy import deepcopy
from io import StringIO
import traceback
import inspect # TODO: For debugging only. import inspect # TODO: For debugging only.
from datetime import datetime from datetime import datetime
from flatcamEditors.FlatCAMTextEditor import TextEditor from flatcamEditors.FlatCAMTextEditor import TextEditor
from flatcamGUI.ObjectUI import * from flatcamGUI.ObjectUI import *
from FlatCAMCommon import LoudDict from FlatCAMCommon import LoudDict
from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy from flatcamGUI.PlotCanvasLegacy import ShapeCollectionLegacy
from camlib import *
from flatcamParsers.ParseExcellon import Excellon from flatcamParsers.ParseExcellon import Excellon
from flatcamParsers.ParseGerber import Gerber from flatcamParsers.ParseGerber import Gerber
from camlib import Geometry, CNCjob
import FlatCAMApp
import itertools
import tkinter as tk import tkinter as tk
import sys import os, sys, itertools
import ezdxf
import math
import numpy as np
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -66,7 +75,7 @@ class FlatCAMObj(QtCore.QObject):
app = None app = None
# signal to plot a single object # signal to plot a single object
plot_single_object = pyqtSignal() plot_single_object = QtCore.pyqtSignal()
def __init__(self, name): def __init__(self, name):
""" """

View File

@ -9,8 +9,6 @@
from importlib.machinery import SourceFileLoader from importlib.machinery import SourceFileLoader
import os import os
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from datetime import datetime
import math
# module-root dictionary of postprocessors # module-root dictionary of postprocessors
import FlatCAMApp import FlatCAMApp

View File

@ -11,13 +11,20 @@
# File modified by: Marius Stanciu # # File modified by: Marius Stanciu #
# ########################################################## # ##########################################################
# from PyQt5.QtCore import QModelIndex
from FlatCAMObj import *
import inspect # TODO: Remove
import FlatCAMApp
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, QSettings from PyQt5.QtCore import Qt, QSettings
# import webbrowser from PyQt5.QtGui import QColor
# from PyQt5.QtCore import QModelIndex
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry, FlatCAMExcellon, FlatCAMCNCjob, FlatCAMDocument, FlatCAMScript
import inspect # TODO: Remove
import FlatCAMApp
import re
import logging
import collections
from copy import deepcopy
from numpy import Inf
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -27,6 +34,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class KeySensitiveListView(QtWidgets.QTreeView): class KeySensitiveListView(QtWidgets.QTreeView):
""" """

View File

@ -12,6 +12,8 @@ CAD program, and create G-Code for Isolation routing.
15.10.2019 15.10.2019
- adjusted the layout in NCC Tool - 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)
14.10.2019 14.10.2019

View File

@ -11,12 +11,9 @@ from PyQt5 import QtWidgets
from io import StringIO from io import StringIO
import numpy as np import numpy as np
from numpy import arctan2, Inf, array, sqrt, pi, ceil, sin, cos, dot, float32, \
transpose
from numpy.linalg import solve, norm from numpy.linalg import solve, norm
import re, sys, os, platform import platform
import math
from copy import deepcopy from copy import deepcopy
import traceback import traceback
@ -26,8 +23,8 @@ from rtree import index as rtindex
from lxml import etree as ET from lxml import etree as ET
# See: http://toblerity.org/shapely/manual.html # See: http://toblerity.org/shapely/manual.html
from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString from shapely.geometry import Polygon, LineString, Point, LinearRing, MultiLineString, MultiPoint, MultiPolygon
from shapely.geometry import MultiPoint, MultiPolygon
from shapely.geometry import box as shply_box from shapely.geometry import box as shply_box
from shapely.ops import cascaded_union, unary_union, polygonize from shapely.ops import cascaded_union, unary_union, polygonize
import shapely.affinity as affinity import shapely.affinity as affinity
@ -64,7 +61,6 @@ import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
fcTranslate.apply_language('strings') fcTranslate.apply_language('strings')
log = logging.getLogger('base2') log = logging.getLogger('base2')
@ -336,8 +332,8 @@ class ApertureMacro:
points = [(0, 0)]*nverts points = [(0, 0)]*nverts
for i in range(nverts): for i in range(nverts):
points[i] = (x + 0.5 * dia * cos(2*pi * i/nverts), points[i] = (x + 0.5 * dia * np.cos(2*np.pi * i/nverts),
y + 0.5 * dia * sin(2*pi * i/nverts)) y + 0.5 * dia * np.sin(2*np.pi * i/nverts))
poly = Polygon(points) poly = Polygon(points)
poly_rotated = affinity.rotate(poly, angle, origin=(0, 0)) poly_rotated = affinity.rotate(poly, angle, origin=(0, 0))
@ -637,10 +633,10 @@ class Geometry(object):
def bounds_rec(obj): def bounds_rec(obj):
if type(obj) is list: if type(obj) is list:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in obj: for k in obj:
if type(k) is dict: if type(k) is dict:
@ -1155,7 +1151,7 @@ class Geometry(object):
log.debug("Image import as monochrome.") log.debug("Image import as monochrome.")
else: else:
mask_setting = (red <= mask[1]) + (green <= mask[2]) + (blue <= mask[3]) mask_setting = (red <= mask[1]) + (green <= mask[2]) + (blue <= mask[3])
total = np.zeros(red.shape, dtype=float32) total = np.zeros(red.shape, dtype=np.float32)
for band in red, green, blue: for band in red, green, blue:
total += band total += band
total /= 3 total /= 3
@ -3298,10 +3294,10 @@ class CNCjob(Geometry):
def bounds_rec(obj): def bounds_rec(obj):
if type(obj) is list: if type(obj) is list:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in obj: for k in obj:
if type(k) is dict: if type(k) is dict:
@ -4049,9 +4045,9 @@ class CNCjob(Geometry):
arcdir = [None, None, "cw", "ccw"] arcdir = [None, None, "cw", "ccw"]
if current['G'] in [2, 3]: # arc if current['G'] in [2, 3]: # arc
center = [gobj['I'] + current['X'], gobj['J'] + current['Y']] center = [gobj['I'] + current['X'], gobj['J'] + current['Y']]
radius = sqrt(gobj['I']**2 + gobj['J']**2) radius = np.sqrt(gobj['I']**2 + gobj['J']**2)
start = arctan2(-gobj['J'], -gobj['I']) start = np.arctan2(-gobj['J'], -gobj['I'])
stop = arctan2(-center[1] + y, -center[0] + x) stop = np.arctan2(-center[1] + y, -center[0] + x)
path += arc(center, radius, start, stop, arcdir[current['G']], int(self.steps_per_circle / 4)) path += arc(center, radius, start, stop, arcdir[current['G']], int(self.steps_per_circle / 4))
# Update current instruction # Update current instruction
@ -4710,10 +4706,10 @@ class CNCjob(Geometry):
def bounds_rec(obj): def bounds_rec(obj):
if type(obj) is list: if type(obj) is list:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in obj: for k in obj:
if type(k) is dict: if type(k) is dict:
@ -4742,15 +4738,15 @@ class CNCjob(Geometry):
bounds_coords = bounds_rec(self.solid_geometry) bounds_coords = bounds_rec(self.solid_geometry)
else: else:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k, v in self.cnc_tools.items(): for k, v in self.cnc_tools.items():
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
try: try:
for k in v['solid_geometry']: for k in v['solid_geometry']:
minx_, miny_, maxx_, maxy_ = bounds_rec(k) minx_, miny_, maxx_, maxy_ = bounds_rec(k)
@ -5186,10 +5182,10 @@ class CNCjob(Geometry):
def get_bounds(geometry_list): def get_bounds(geometry_list):
xmin = Inf xmin = np.Inf
ymin = Inf ymin = np.Inf
xmax = -Inf xmax = -np.Inf
ymax = -Inf ymax = -np.Inf
for gs in geometry_list: for gs in geometry_list:
try: try:
@ -5229,33 +5225,33 @@ def arc(center, radius, start, stop, direction, steps_per_circ):
da_sign = {"cw": -1.0, "ccw": 1.0} da_sign = {"cw": -1.0, "ccw": 1.0}
points = [] points = []
if direction == "ccw" and stop <= start: if direction == "ccw" and stop <= start:
stop += 2 * pi stop += 2 * np.pi
if direction == "cw" and stop >= start: if direction == "cw" and stop >= start:
stop -= 2 * pi stop -= 2 * np.pi
angle = abs(stop - start) angle = abs(stop - start)
# angle = stop-start # angle = stop-start
steps = max([int(ceil(angle / (2 * pi) * steps_per_circ)), 2]) steps = max([int(np.ceil(angle / (2 * np.pi) * steps_per_circ)), 2])
delta_angle = da_sign[direction] * angle * 1.0 / steps delta_angle = da_sign[direction] * angle * 1.0 / steps
for i in range(steps + 1): for i in range(steps + 1):
theta = start + delta_angle * i theta = start + delta_angle * i
points.append((center[0] + radius * cos(theta), center[1] + radius * sin(theta))) points.append((center[0] + radius * np.cos(theta), center[1] + radius * np.sin(theta)))
return points return points
def arc2(p1, p2, center, direction, steps_per_circ): def arc2(p1, p2, center, direction, steps_per_circ):
r = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2) r = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
start = arctan2(p1[1] - center[1], p1[0] - center[0]) start = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stop = arctan2(p2[1] - center[1], p2[0] - center[0]) stop = np.arctan2(p2[1] - center[1], p2[0] - center[0])
return arc(center, r, start, stop, direction, steps_per_circ) return arc(center, r, start, stop, direction, steps_per_circ)
def arc_angle(start, stop, direction): def arc_angle(start, stop, direction):
if direction == "ccw" and stop <= start: if direction == "ccw" and stop <= start:
stop += 2 * pi stop += 2 * np.pi
if direction == "cw" and stop >= start: if direction == "cw" and stop >= start:
stop -= 2 * pi stop -= 2 * np.pi
angle = abs(stop - start) angle = abs(stop - start)
return angle return angle
@ -5665,12 +5661,12 @@ def three_point_circle(p1, p2, p3):
a2 = (p2 + p3) / 2.0 a2 = (p2 + p3) / 2.0
# Normals # Normals
b1 = dot((p2 - p1), array([[0, -1], [1, 0]], dtype=float32)) b1 = np.dot((p2 - p1), np.array([[0, -1], [1, 0]], dtype=np.float32))
b2 = dot((p3 - p2), array([[0, 1], [-1, 0]], dtype=float32)) b2 = np.dot((p3 - p2), np.array([[0, 1], [-1, 0]], dtype=np.float32))
# Params # Params
try: try:
T = solve(transpose(array([-b1, b2])), a1 - a2) T = solve(np.transpose(np.array([-b1, b2])), a1 - a2)
except Exception as e: except Exception as e:
log.debug("camlib.three_point_circle() --> %s" % str(e)) log.debug("camlib.three_point_circle() --> %s" % str(e))
return return
@ -5685,11 +5681,11 @@ def three_point_circle(p1, p2, p3):
def distance(pt1, pt2): def distance(pt1, pt2):
return sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2) return np.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
def distance_euclidian(x1, y1, x2, y2): def distance_euclidian(x1, y1, x2, y2):
return sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2) return np.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
class FlatCAMRTree(object): class FlatCAMRTree(object):

View File

@ -8,19 +8,23 @@
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, QSettings from PyQt5.QtCore import Qt, QSettings
from shapely.geometry import LineString, LinearRing, MultiLineString from camlib import distance, arc, FlatCAMRTreeStorage
from shapely.ops import cascaded_union
import shapely.affinity as affinity
from numpy import arctan2, Inf, array, sqrt, sign, dot
from rtree import index as rtindex
from camlib import *
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, SpinBoxDelegate
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor from flatcamEditors.FlatCAMGeoEditor import FCShapeTool, DrawTool, DrawToolShape, DrawToolUtilityShape, FlatCAMGeoEditor
from flatcamParsers.ParseExcellon import Excellon from flatcamParsers.ParseExcellon import Excellon
import FlatCAMApp
from copy import copy, deepcopy from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon, Point
import shapely.affinity as affinity
import numpy as np
from rtree import index as rtindex
import traceback
import math
import logging
from copy import deepcopy
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -30,6 +34,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class FCDrillAdd(FCShapeTool): class FCDrillAdd(FCShapeTool):
""" """
@ -3214,8 +3220,7 @@ class FlatCAMExcEditor(QtCore.QObject):
_("An internal error has ocurred. See Shell.\n") _("An internal error has ocurred. See Shell.\n")
msg += traceback.format_exc() msg += traceback.format_exc()
app_obj.inform.emit(msg) app_obj.inform.emit(msg)
raise return
# raise
with self.app.proc_container.new(_("Creating Excellon.")): with self.app.proc_container.new(_("Creating Excellon.")):
@ -3998,10 +4003,10 @@ class FlatCAMExcEditor(QtCore.QObject):
def get_shapely_list_bounds(geometry_list): def get_shapely_list_bounds(geometry_list):
xmin = Inf xmin = np.Inf
ymin = Inf ymin = np.Inf
xmax = -Inf xmax = -np.Inf
ymax = -Inf ymax = -np.Inf
for gs in geometry_list: for gs in geometry_list:
try: try:

View File

@ -13,24 +13,26 @@
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, QSettings from PyQt5.QtCore import Qt, QSettings
from camlib import *
from camlib import distance, arc, three_point_circle, Geometry, FlatCAMRTreeStorage
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from flatcamGUI.ObjectUI import LengthEntry, RadioSet from flatcamGUI.ObjectUI import RadioSet
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog
from flatcamParsers.ParseFont import *
import FlatCAMApp
from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon from shapely.geometry import LineString, LinearRing, MultiLineString, Polygon, MultiPolygon
# from shapely.geometry import mapping
from shapely.ops import cascaded_union, unary_union from shapely.ops import cascaded_union, unary_union
import shapely.affinity as affinity import shapely.affinity as affinity
from shapely.geometry.polygon import orient from shapely.geometry.polygon import orient
from numpy import arctan2, Inf, array, sqrt, sign, dot import numpy as np
from numpy.linalg import norm as numpy_norm from numpy.linalg import norm as numpy_norm
from rtree import index as rtindex from rtree import index as rtindex
from flatcamGUI.GUIElements import OptionalInputSection, FCCheckBox, FCEntry, FCComboBox, FCTextAreaRich, \
FCTable, FCDoubleSpinner, FCButton, EvalEntry2, FCInputDialog
from flatcamParsers.ParseFont import *
from copy import deepcopy
# from vispy.io import read_png # from vispy.io import read_png
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -684,8 +686,8 @@ class TransformEditorTool(FlatCAMTool):
self.rotate_button.set_value(_("Rotate")) self.rotate_button.set_value(_("Rotate"))
self.rotate_button.setToolTip( self.rotate_button.setToolTip(
_("Rotate the selected shape(s).\n" _("Rotate the selected shape(s).\n"
"The point of reference is the middle of\n" "The point of reference is the middle of\n"
"the bounding box for all selected shapes.") "the bounding box for all selected shapes.")
) )
self.rotate_button.setFixedWidth(60) self.rotate_button.setFixedWidth(60)
@ -802,7 +804,7 @@ class TransformEditorTool(FlatCAMTool):
self.scale_link_cb.setText(_("Link")) self.scale_link_cb.setText(_("Link"))
self.scale_link_cb.setToolTip( self.scale_link_cb.setToolTip(
_("Scale the selected shape(s)\n" _("Scale the selected shape(s)\n"
"using the Scale Factor X for both axis.")) "using the Scale Factor X for both axis."))
self.scale_link_cb.setFixedWidth(50) self.scale_link_cb.setFixedWidth(50)
self.scale_zero_ref_cb = FCCheckBox() self.scale_zero_ref_cb = FCCheckBox()
@ -1060,7 +1062,6 @@ class TransformEditorTool(FlatCAMTool):
_("Transformation cancelled. No shape selected.")) _("Transformation cancelled. No shape selected."))
return return
self.draw_app.select_tool("select") self.draw_app.select_tool("select")
self.app.ui.notebook.setTabText(2, "Tools") self.app.ui.notebook.setTabText(2, "Tools")
self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab) self.app.ui.notebook.setCurrentWidget(self.app.ui.project_tab)
@ -1081,10 +1082,7 @@ class TransformEditorTool(FlatCAMTool):
self.app.inform.emit('[ERROR_NOTCL] %s' % self.app.inform.emit('[ERROR_NOTCL] %s' %
_("Wrong value format entered, use a number.")) _("Wrong value format entered, use a number."))
return return
self.app.worker_task.emit({'fcn': self.on_rotate_action, self.app.worker_task.emit({'fcn': self.on_rotate_action, 'params': [value]})
'params': [value]})
# self.on_rotate_action(value)
return
def on_flipx(self): def on_flipx(self):
# self.on_flip("Y") # self.on_flip("Y")
@ -1205,13 +1203,9 @@ class TransformEditorTool(FlatCAMTool):
axis = 'Y' axis = 'Y'
point = (0, 0) point = (0, 0)
if self.scale_zero_ref_cb.get_value(): if self.scale_zero_ref_cb.get_value():
self.app.worker_task.emit({'fcn': self.on_scale, self.app.worker_task.emit({'fcn': self.on_scale, 'params': [axis, xvalue, yvalue, point]})
'params': [axis, xvalue, yvalue, point]})
# self.on_scale("Y", xvalue, yvalue, point=(0,0))
else: else:
# self.on_scale("Y", xvalue, yvalue) self.app.worker_task.emit({'fcn': self.on_scale, 'params': [axis, xvalue, yvalue]})
self.app.worker_task.emit({'fcn': self.on_scale,
'params': [axis, xvalue, yvalue]})
return return
@ -1304,7 +1298,7 @@ class TransformEditorTool(FlatCAMTool):
except Exception as e: except Exception as e:
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
(_("Rotation action was not executed"),str(e))) (_("Rotation action was not executed"), str(e)))
return return
def on_flip(self, axis): def on_flip(self, axis):
@ -1664,10 +1658,10 @@ class DrawToolShape(object):
# now it can get bounds for nested lists of objects # now it can get bounds for nested lists of objects
def bounds_rec(shape_el): def bounds_rec(shape_el):
if type(shape_el) is list: if type(shape_el) is list:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in shape_el: for k in shape_el:
minx_, miny_, maxx_, maxy_ = bounds_rec(k) minx_, miny_, maxx_, maxy_ = bounds_rec(k)
@ -1904,10 +1898,10 @@ class DrawTool(object):
def bounds(self, obj): def bounds(self, obj):
def bounds_rec(o): def bounds_rec(o):
if type(o) is list: if type(o) is list:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in o: for k in o:
try: try:
@ -1977,7 +1971,7 @@ class FCCircle(FCShapeTool):
if len(self.points) == 1: if len(self.points) == 1:
p1 = self.points[0] p1 = self.points[0]
p2 = data p2 = data
radius = sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) radius = np.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
return DrawToolUtilityShape(Point(p1).buffer(radius, int(self.steps_per_circ / 4))) return DrawToolUtilityShape(Point(p1).buffer(radius, int(self.steps_per_circ / 4)))
return None return None
@ -2086,36 +2080,36 @@ class FCArc(FCShapeTool):
p1 = self.points[1] p1 = self.points[1]
p2 = data p2 = data
radius = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2) radius = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2)
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0]) stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle, return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
self.direction, self.steps_per_circ)), self.direction, self.steps_per_circ)),
Point(center)]) Point(center)])
elif self.mode == '132': elif self.mode == '132':
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p3 = array(self.points[1]) p3 = np.array(self.points[1])
p2 = array(data) p2 = np.array(data)
try: try:
center, radius, t = three_point_circle(p1, p2, p3) center, radius, t = three_point_circle(p1, p2, p3)
except TypeError: except TypeError:
return return
direction = 'cw' if sign(t) > 0 else 'ccw' direction = 'cw' if np.sign(t) > 0 else 'ccw'
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0]) stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle, return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
direction, self.steps_per_circ)), direction, self.steps_per_circ)),
Point(center), Point(p1), Point(p3)]) Point(center), Point(p1), Point(p3)])
else: # '12c' else: # '12c'
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p2 = array(self.points[1]) p2 = np.array(self.points[1])
# Midpoint # Midpoint
a = (p1 + p2) / 2.0 a = (p1 + p2) / 2.0
@ -2124,7 +2118,7 @@ class FCArc(FCShapeTool):
c = p2 - p1 c = p2 - p1
# Perpendicular vector # Perpendicular vector
b = dot(c, array([[0, -1], [1, 0]], dtype=float32)) b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
b /= numpy_norm(b) b /= numpy_norm(b)
# Distance # Distance
@ -2133,14 +2127,14 @@ class FCArc(FCShapeTool):
# Which side? Cross product with c. # Which side? Cross product with c.
# cross(M-A, B-A), where line is AB and M is test point. # cross(M-A, B-A), where line is AB and M is test point.
side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0] side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0]
t *= sign(side) t *= np.sign(side)
# Center = a + bt # Center = a + bt
center = a + b * t center = a + b * t
radius = numpy_norm(center - p1) radius = numpy_norm(center - p1)
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0]) stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle, return DrawToolUtilityShape([LineString(arc(center, radius, startangle, stopangle,
self.direction, self.steps_per_circ)), self.direction, self.steps_per_circ)),
@ -2156,29 +2150,29 @@ class FCArc(FCShapeTool):
p2 = self.points[2] p2 = self.points[2]
radius = distance(center, p1) radius = distance(center, p1)
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0]) stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle, self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
self.direction, self.steps_per_circ))) self.direction, self.steps_per_circ)))
elif self.mode == '132': elif self.mode == '132':
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p3 = array(self.points[1]) p3 = np.array(self.points[1])
p2 = array(self.points[2]) p2 = np.array(self.points[2])
center, radius, t = three_point_circle(p1, p2, p3) center, radius, t = three_point_circle(p1, p2, p3)
direction = 'cw' if sign(t) > 0 else 'ccw' direction = 'cw' if np.sign(t) > 0 else 'ccw'
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0]) stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle, self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
direction, self.steps_per_circ))) direction, self.steps_per_circ)))
else: # self.mode == '12c' else: # self.mode == '12c'
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p2 = array(self.points[1]) p2 = np.array(self.points[1])
pc = array(self.points[2]) pc = np.array(self.points[2])
# Midpoint # Midpoint
a = (p1 + p2) / 2.0 a = (p1 + p2) / 2.0
@ -2187,7 +2181,7 @@ class FCArc(FCShapeTool):
c = p2 - p1 c = p2 - p1
# Perpendicular vector # Perpendicular vector
b = dot(c, array([[0, -1], [1, 0]], dtype=float32)) b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
b /= numpy_norm(b) b /= numpy_norm(b)
# Distance # Distance
@ -2196,14 +2190,14 @@ class FCArc(FCShapeTool):
# Which side? Cross product with c. # Which side? Cross product with c.
# cross(M-A, B-A), where line is AB and M is test point. # cross(M-A, B-A), where line is AB and M is test point.
side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0] side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0]
t *= sign(side) t *= np.sign(side)
# Center = a + bt # Center = a + bt
center = a + b * t center = a + b * t
radius = numpy_norm(center - p1) radius = numpy_norm(center - p1)
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0]) stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle, self.geometry = DrawToolShape(LineString(arc(center, radius, startangle, stopangle,
self.direction, self.steps_per_circ))) self.direction, self.steps_per_circ)))
@ -4237,7 +4231,7 @@ class FlatCAMGeoEditor(QtCore.QObject):
""" """
snap_x, snap_y = (x, y) snap_x, snap_y = (x, y)
snap_distance = Inf snap_distance = np.Inf
# # ## Object (corner?) snap # # ## Object (corner?) snap
# # ## No need for the objects, just the coordinates # # ## No need for the objects, just the coordinates
@ -4814,11 +4808,11 @@ class FlatCAMGeoEditor(QtCore.QObject):
def distance(pt1, pt2): def distance(pt1, pt2):
return sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2) return np.sqrt((pt1[0] - pt2[0]) ** 2 + (pt1[1] - pt2[1]) ** 2)
def mag(vec): def mag(vec):
return sqrt(vec[0] ** 2 + vec[1] ** 2) return np.sqrt(vec[0] ** 2 + vec[1] ** 2)
def poly2rings(poly): def poly2rings(poly):
@ -4826,10 +4820,10 @@ def poly2rings(poly):
def get_shapely_list_bounds(geometry_list): def get_shapely_list_bounds(geometry_list):
xmin = Inf xmin = np.Inf
ymin = Inf ymin = np.Inf
xmax = -Inf xmax = -np.Inf
ymax = -Inf ymax = -np.Inf
for gs in geometry_list: for gs in geometry_list:
try: try:

View File

@ -8,29 +8,28 @@
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, QSettings from PyQt5.QtCore import Qt, QSettings
from shapely.geometry import LineString, LinearRing, MultiLineString from shapely.geometry import LineString, LinearRing, MultiLineString, Point, Polygon, MultiPolygon
# from shapely.geometry import mapping from shapely.ops import cascaded_union
from shapely.ops import cascaded_union, unary_union
import shapely.affinity as affinity import shapely.affinity as affinity
from numpy import arctan2, Inf, array, sqrt, sign, dot
from rtree import index as rtindex
import threading import threading
import time import time
from copy import copy, deepcopy from copy import copy, deepcopy
import logging
from camlib import * from camlib import distance, arc, three_point_circle
from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, \ from flatcamGUI.GUIElements import FCEntry, FCComboBox, FCTable, FCDoubleSpinner, LengthEntry, RadioSet, \
SpinBoxDelegate, EvalEntry, EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox EvalEntry2, FCInputDialog, FCButton, OptionalInputSection, FCCheckBox
from FlatCAMObj import FlatCAMGerber
from flatcamParsers.ParseGerber import Gerber
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
import FlatCAMApp
import numpy as np
from numpy.linalg import norm as numpy_norm from numpy.linalg import norm as numpy_norm
import math
# from vispy.io import read_png # from vispy.io import read_png
# import pngcanvas # import pngcanvas
import traceback
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -39,6 +38,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class DrawToolShape(object): class DrawToolShape(object):
""" """
@ -147,10 +148,10 @@ class DrawTool(object):
def bounds(obj): def bounds(obj):
def bounds_rec(o): def bounds_rec(o):
if type(o) is list: if type(o) is list:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in o: for k in o:
try: try:
@ -311,13 +312,13 @@ class FCPad(FCShapeTool):
p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width) p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width)
down_center = [point_x, point_y - self.half_height + self.half_width] down_center = [point_x, point_y - self.half_height + self.half_width]
d_start_angle = math.pi d_start_angle = np.pi
d_stop_angle = 0.0 d_stop_angle = 0.0
down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ) down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
up_center = [point_x, point_y + self.half_height - self.half_width] up_center = [point_x, point_y + self.half_height - self.half_width]
u_start_angle = 0.0 u_start_angle = 0.0
u_stop_angle = math.pi u_stop_angle = np.pi
up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ) up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
geo.append(p1) geo.append(p1)
@ -340,13 +341,13 @@ class FCPad(FCShapeTool):
p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height) p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height)
left_center = [point_x - self.half_width + self.half_height, point_y] left_center = [point_x - self.half_width + self.half_height, point_y]
d_start_angle = math.pi / 2 d_start_angle = np.pi / 2
d_stop_angle = 1.5 * math.pi d_stop_angle = 1.5 * np.pi
left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ) left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
right_center = [point_x + self.half_width - self.half_height, point_y] right_center = [point_x + self.half_width - self.half_height, point_y]
u_start_angle = 1.5 * math.pi u_start_angle = 1.5 * np.pi
u_stop_angle = math.pi / 2 u_stop_angle = np.pi / 2
right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ) right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
geo.append(p1) geo.append(p1)
@ -618,13 +619,13 @@ class FCPadArray(FCShapeTool):
p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width) p4 = (point_x - self.half_width, point_y + self.half_height - self.half_width)
down_center = [point_x, point_y - self.half_height + self.half_width] down_center = [point_x, point_y - self.half_height + self.half_width]
d_start_angle = math.pi d_start_angle = np.pi
d_stop_angle = 0.0 d_stop_angle = 0.0
down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ) down_arc = arc(down_center, self.half_width, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
up_center = [point_x, point_y + self.half_height - self.half_width] up_center = [point_x, point_y + self.half_height - self.half_width]
u_start_angle = 0.0 u_start_angle = 0.0
u_stop_angle = math.pi u_stop_angle = np.pi
up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ) up_arc = arc(up_center, self.half_width, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
geo.append(p1) geo.append(p1)
@ -647,13 +648,13 @@ class FCPadArray(FCShapeTool):
p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height) p4 = (point_x - self.half_width + self.half_height, point_y + self.half_height)
left_center = [point_x - self.half_width + self.half_height, point_y] left_center = [point_x - self.half_width + self.half_height, point_y]
d_start_angle = math.pi / 2 d_start_angle = np.pi / 2
d_stop_angle = 1.5 * math.pi d_stop_angle = 1.5 * np.pi
left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ) left_arc = arc(left_center, self.half_height, d_start_angle, d_stop_angle, 'ccw', self.steps_per_circ)
right_center = [point_x + self.half_width - self.half_height, point_y] right_center = [point_x + self.half_width - self.half_height, point_y]
u_start_angle = 1.5 * math.pi u_start_angle = 1.5 * np.pi
u_stop_angle = math.pi / 2 u_stop_angle = np.pi / 2
right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ) right_arc = arc(right_center, self.half_height, u_start_angle, u_stop_angle, 'ccw', self.steps_per_circ)
geo.append(p1) geo.append(p1)
@ -1296,7 +1297,7 @@ class FCTrack(FCRegion):
self.draw_app.bend_mode = 2 self.draw_app.bend_mode = 2
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path2.png')) self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path2.png'))
QtGui.QGuiApplication.setOverrideCursor(self.cursor) QtGui.QGuiApplication.setOverrideCursor(self.cursor)
msg = _('Track Mode 2: Reverse 45 degrees ...') msg = _('Track Mode 2: Reverse 45 degrees ...')
elif self.draw_app.bend_mode == 2: elif self.draw_app.bend_mode == 2:
self.draw_app.bend_mode = 3 self.draw_app.bend_mode = 3
self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path3.png')) self.cursor = QtGui.QCursor(QtGui.QPixmap('share/aero_path3.png'))
@ -1415,7 +1416,7 @@ class FCDisc(FCShapeTool):
if len(self.points) == 1: if len(self.points) == 1:
p1 = self.points[0] p1 = self.points[0]
p2 = data p2 = data
radius = sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) radius = math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
new_geo_el['solid'] = Point(p1).buffer((radius + self.buf_val / 2), int(self.steps_per_circ / 4)) new_geo_el['solid'] = Point(p1).buffer((radius + self.buf_val / 2), int(self.steps_per_circ / 4))
return DrawToolUtilityShape(new_geo_el) return DrawToolUtilityShape(new_geo_el)
@ -1557,9 +1558,9 @@ class FCSemiDisc(FCShapeTool):
p1 = self.points[1] p1 = self.points[1]
p2 = data p2 = data
radius = sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2) + (self.buf_val / 2) radius = np.sqrt((center[0] - p1[0]) ** 2 + (center[1] - p1[1]) ** 2) + (self.buf_val / 2)
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0]) stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
new_geo_el['solid'] = LineString( new_geo_el['solid'] = LineString(
arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ)) arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ))
@ -1567,20 +1568,20 @@ class FCSemiDisc(FCShapeTool):
return DrawToolUtilityShape([new_geo_el, new_geo_el_pt1]) return DrawToolUtilityShape([new_geo_el, new_geo_el_pt1])
elif self.mode == '132': elif self.mode == '132':
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p3 = array(self.points[1]) p3 = np.array(self.points[1])
p2 = array(data) p2 = np.array(data)
try: try:
center, radius, t = three_point_circle(p1, p2, p3) center, radius, t = three_point_circle(p1, p2, p3)
except TypeError: except TypeError:
return return
direction = 'cw' if sign(t) > 0 else 'ccw' direction = 'cw' if np.sign(t) > 0 else 'ccw'
radius += (self.buf_val / 2) radius += (self.buf_val / 2)
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p3[1] - center[1], p3[0] - center[0]) stopangle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
new_geo_el['solid'] = LineString( new_geo_el['solid'] = LineString(
arc(center, radius, startangle, stopangle, direction, self.steps_per_circ)) arc(center, radius, startangle, stopangle, direction, self.steps_per_circ))
@ -1591,8 +1592,8 @@ class FCSemiDisc(FCShapeTool):
return DrawToolUtilityShape([new_geo_el, new_geo_el_pt2, new_geo_el_pt1, new_geo_el_pt3]) return DrawToolUtilityShape([new_geo_el, new_geo_el_pt2, new_geo_el_pt1, new_geo_el_pt3])
else: # '12c' else: # '12c'
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p2 = array(self.points[1]) p2 = np.array(self.points[1])
# Midpoint # Midpoint
a = (p1 + p2) / 2.0 a = (p1 + p2) / 2.0
@ -1600,7 +1601,7 @@ class FCSemiDisc(FCShapeTool):
c = p2 - p1 c = p2 - p1
# Perpendicular vector # Perpendicular vector
b = dot(c, array([[0, -1], [1, 0]], dtype=float32)) b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
b /= numpy_norm(b) b /= numpy_norm(b)
# Distance # Distance
@ -1609,14 +1610,14 @@ class FCSemiDisc(FCShapeTool):
# Which side? Cross product with c. # Which side? Cross product with c.
# cross(M-A, B-A), where line is AB and M is test point. # cross(M-A, B-A), where line is AB and M is test point.
side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0] side = (data[0] - p1[0]) * c[1] - (data[1] - p1[1]) * c[0]
t *= sign(side) t *= np.sign(side)
# Center = a + bt # Center = a + bt
center = a + b * t center = a + b * t
radius = numpy_norm(center - p1) + (self.buf_val / 2) radius = numpy_norm(center - p1) + (self.buf_val / 2)
startangle = arctan2(p1[1] - center[1], p1[0] - center[0]) startangle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stopangle = arctan2(p2[1] - center[1], p2[0] - center[0]) stopangle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
new_geo_el['solid'] = LineString( new_geo_el['solid'] = LineString(
arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ)) arc(center, radius, startangle, stopangle, self.direction, self.steps_per_circ))
@ -1636,8 +1637,8 @@ class FCSemiDisc(FCShapeTool):
p2 = self.points[2] p2 = self.points[2]
radius = distance(center, p1) + (self.buf_val / 2) radius = distance(center, p1) + (self.buf_val / 2)
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0]) start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stop_angle = arctan2(p2[1] - center[1], p2[0] - center[0]) stop_angle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
new_geo_el['solid'] = Polygon( new_geo_el['solid'] = Polygon(
arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ)) arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ))
new_geo_el['follow'] = Polygon( new_geo_el['follow'] = Polygon(
@ -1645,16 +1646,16 @@ class FCSemiDisc(FCShapeTool):
self.geometry = DrawToolShape(new_geo_el) self.geometry = DrawToolShape(new_geo_el)
elif self.mode == '132': elif self.mode == '132':
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p3 = array(self.points[1]) p3 = np.array(self.points[1])
p2 = array(self.points[2]) p2 = np.array(self.points[2])
center, radius, t = three_point_circle(p1, p2, p3) center, radius, t = three_point_circle(p1, p2, p3)
direction = 'cw' if sign(t) > 0 else 'ccw' direction = 'cw' if np.sign(t) > 0 else 'ccw'
radius += (self.buf_val / 2) radius += (self.buf_val / 2)
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0]) start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stop_angle = arctan2(p3[1] - center[1], p3[0] - center[0]) stop_angle = np.arctan2(p3[1] - center[1], p3[0] - center[0])
new_geo_el['solid'] = Polygon(arc(center, radius, start_angle, stop_angle, direction, self.steps_per_circ)) new_geo_el['solid'] = Polygon(arc(center, radius, start_angle, stop_angle, direction, self.steps_per_circ))
new_geo_el['follow'] = Polygon( new_geo_el['follow'] = Polygon(
@ -1662,9 +1663,9 @@ class FCSemiDisc(FCShapeTool):
self.geometry = DrawToolShape(new_geo_el) self.geometry = DrawToolShape(new_geo_el)
else: # self.mode == '12c' else: # self.mode == '12c'
p1 = array(self.points[0]) p1 = np.array(self.points[0])
p2 = array(self.points[1]) p2 = np.array(self.points[1])
pc = array(self.points[2]) pc = np.array(self.points[2])
# Midpoint # Midpoint
a = (p1 + p2) / 2.0 a = (p1 + p2) / 2.0
@ -1673,7 +1674,7 @@ class FCSemiDisc(FCShapeTool):
c = p2 - p1 c = p2 - p1
# Perpendicular vector # Perpendicular vector
b = dot(c, array([[0, -1], [1, 0]], dtype=float32)) b = np.dot(c, np.array([[0, -1], [1, 0]], dtype=np.float32))
b /= numpy_norm(b) b /= numpy_norm(b)
# Distance # Distance
@ -1682,14 +1683,14 @@ class FCSemiDisc(FCShapeTool):
# Which side? Cross product with c. # Which side? Cross product with c.
# cross(M-A, B-A), where line is AB and M is test point. # cross(M-A, B-A), where line is AB and M is test point.
side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0] side = (pc[0] - p1[0]) * c[1] - (pc[1] - p1[1]) * c[0]
t *= sign(side) t *= np.sign(side)
# Center = a + bt # Center = a + bt
center = a + b * t center = a + b * t
radius = numpy_norm(center - p1) + (self.buf_val / 2) radius = numpy_norm(center - p1) + (self.buf_val / 2)
start_angle = arctan2(p1[1] - center[1], p1[0] - center[0]) start_angle = np.arctan2(p1[1] - center[1], p1[0] - center[0])
stop_angle = arctan2(p2[1] - center[1], p2[0] - center[0]) stop_angle = np.arctan2(p2[1] - center[1], p2[0] - center[0])
new_geo_el['solid'] = Polygon( new_geo_el['solid'] = Polygon(
arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ)) arc(center, radius, start_angle, stop_angle, self.direction, self.steps_per_circ))
@ -2437,9 +2438,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.apertures_box.addLayout(grid1) self.apertures_box.addLayout(grid1)
apcode_lbl = QtWidgets.QLabel('%s:' % _('Aperture Code')) apcode_lbl = QtWidgets.QLabel('%s:' % _('Aperture Code'))
apcode_lbl.setToolTip( apcode_lbl.setToolTip(_("Code for the new aperture"))
_("Code for the new aperture")
)
grid1.addWidget(apcode_lbl, 1, 0) grid1.addWidget(apcode_lbl, 1, 0)
self.apcode_entry = FCEntry() self.apcode_entry = FCEntry()
@ -2448,11 +2447,11 @@ class FlatCAMGrbEditor(QtCore.QObject):
apsize_lbl = QtWidgets.QLabel('%s:' % _('Aperture Size')) apsize_lbl = QtWidgets.QLabel('%s:' % _('Aperture Size'))
apsize_lbl.setToolTip( apsize_lbl.setToolTip(
_("Size for the new aperture.\n" _("Size for the new aperture.\n"
"If aperture type is 'R' or 'O' then\n" "If aperture type is 'R' or 'O' then\n"
"this value is automatically\n" "this value is automatically\n"
"calculated as:\n" "calculated as:\n"
"sqrt(width**2 + height**2)") "sqrt(width**2 + height**2)")
) )
grid1.addWidget(apsize_lbl, 2, 0) grid1.addWidget(apsize_lbl, 2, 0)
@ -2462,10 +2461,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
aptype_lbl = QtWidgets.QLabel('%s:' % _('Aperture Type')) aptype_lbl = QtWidgets.QLabel('%s:' % _('Aperture Type'))
aptype_lbl.setToolTip( aptype_lbl.setToolTip(
_("Select the type of new aperture. Can be:\n" _("Select the type of new aperture. Can be:\n"
"C = circular\n" "C = circular\n"
"R = rectangular\n" "R = rectangular\n"
"O = oblong") "O = oblong")
) )
grid1.addWidget(aptype_lbl, 3, 0) grid1.addWidget(aptype_lbl, 3, 0)
@ -2475,9 +2474,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.apdim_lbl = QtWidgets.QLabel('%s:' % _('Aperture Dim')) self.apdim_lbl = QtWidgets.QLabel('%s:' % _('Aperture Dim'))
self.apdim_lbl.setToolTip( self.apdim_lbl.setToolTip(
_("Dimensions for the new aperture.\n" _("Dimensions for the new aperture.\n"
"Active only for rectangular apertures (type R).\n" "Active only for rectangular apertures (type R).\n"
"The format is (width, height)") "The format is (width, height)")
) )
grid1.addWidget(self.apdim_lbl, 4, 0) grid1.addWidget(self.apdim_lbl, 4, 0)
@ -2495,12 +2494,12 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.addaperture_btn = QtWidgets.QPushButton(_('Add')) self.addaperture_btn = QtWidgets.QPushButton(_('Add'))
self.addaperture_btn.setToolTip( self.addaperture_btn.setToolTip(
_( "Add a new aperture to the aperture list.") _("Add a new aperture to the aperture list.")
) )
self.delaperture_btn = QtWidgets.QPushButton(_('Delete')) self.delaperture_btn = QtWidgets.QPushButton(_('Delete'))
self.delaperture_btn.setToolTip( self.delaperture_btn.setToolTip(
_( "Delete a aperture in the aperture list") _("Delete a aperture in the aperture list")
) )
hlay_ad.addWidget(self.addaperture_btn) hlay_ad.addWidget(self.addaperture_btn)
hlay_ad.addWidget(self.delaperture_btn) hlay_ad.addWidget(self.delaperture_btn)
@ -2677,8 +2676,8 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.array_type_combo = FCComboBox() self.array_type_combo = FCComboBox()
self.array_type_combo.setToolTip( self.array_type_combo.setToolTip(
_( "Select the type of pads array to create.\n" _("Select the type of pads array to create.\n"
"It can be Linear X(Y) or Circular") "It can be Linear X(Y) or Circular")
) )
self.array_type_combo.addItem(_("Linear")) self.array_type_combo.addItem(_("Linear"))
self.array_type_combo.addItem(_("Circular")) self.array_type_combo.addItem(_("Circular"))
@ -2733,10 +2732,10 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.linear_angle_label = QtWidgets.QLabel('%s:' % _('Angle')) self.linear_angle_label = QtWidgets.QLabel('%s:' % _('Angle'))
self.linear_angle_label.setToolTip( self.linear_angle_label.setToolTip(
_( "Angle at which the linear array is placed.\n" _("Angle at which the linear array is placed.\n"
"The precision is of max 2 decimals.\n" "The precision is of max 2 decimals.\n"
"Min value is: -359.99 degrees.\n" "Min value is: -359.99 degrees.\n"
"Max value is: 360.00 degrees.") "Max value is: 360.00 degrees.")
) )
self.linear_angle_label.setMinimumWidth(100) self.linear_angle_label.setMinimumWidth(100)
@ -2808,9 +2807,9 @@ class FlatCAMGrbEditor(QtCore.QObject):
"scale": {"button": self.app.ui.aperture_scale_btn, "scale": {"button": self.app.ui.aperture_scale_btn,
"constructor": FCScale}, "constructor": FCScale},
"markarea": {"button": self.app.ui.aperture_markarea_btn, "markarea": {"button": self.app.ui.aperture_markarea_btn,
"constructor": FCMarkArea}, "constructor": FCMarkArea},
"eraser": {"button": self.app.ui.aperture_eraser_btn, "eraser": {"button": self.app.ui.aperture_eraser_btn,
"constructor": FCEraser}, "constructor": FCEraser},
"copy": {"button": self.app.ui.aperture_copy_btn, "copy": {"button": self.app.ui.aperture_copy_btn,
"constructor": FCApertureCopy}, "constructor": FCApertureCopy},
"transform": {"button": self.app.ui.grb_transform_btn, "transform": {"button": self.app.ui.grb_transform_btn,
@ -3245,7 +3244,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.storage_dict[ap_id]['width'] = dims[0] self.storage_dict[ap_id]['width'] = dims[0]
self.storage_dict[ap_id]['height'] = dims[1] self.storage_dict[ap_id]['height'] = dims[1]
size_val = math.sqrt((dims[0] ** 2) + (dims[1] ** 2)) size_val = np.sqrt((dims[0] ** 2) + (dims[1] ** 2))
self.apsize_entry.set_value(size_val) self.apsize_entry.set_value(size_val)
except Exception as e: except Exception as e:
@ -3613,7 +3612,6 @@ class FlatCAMGrbEditor(QtCore.QObject):
self.app.ui.grb_draw_eraser.triggered.connect(self.on_eraser) self.app.ui.grb_draw_eraser.triggered.connect(self.on_eraser)
self.app.ui.grb_draw_transformations.triggered.connect(self.on_transform) self.app.ui.grb_draw_transformations.triggered.connect(self.on_transform)
def disconnect_canvas_event_handlers(self): def disconnect_canvas_event_handlers(self):
# we restore the key and mouse control to FlatCAMApp method # we restore the key and mouse control to FlatCAMApp method
@ -3803,7 +3801,7 @@ class FlatCAMGrbEditor(QtCore.QObject):
# we subtract the big "negative" (clear) geometry from each solid polygon but only the part of clear geometry # we subtract the big "negative" (clear) geometry from each solid polygon but only the part of clear geometry
# that fits inside the solid. otherwise we may loose the solid # that fits inside the solid. otherwise we may loose the solid
for apid in self.gerber_obj.apertures: for apid in self.gerber_obj.apertures:
temp_solid_geometry= [] temp_solid_geometry = []
if 'geometry' in self.gerber_obj.apertures[apid]: if 'geometry' in self.gerber_obj.apertures[apid]:
# for elem in self.gerber_obj.apertures[apid]['geometry']: # for elem in self.gerber_obj.apertures[apid]['geometry']:
# if 'solid' in elem: # if 'solid' in elem:
@ -6032,10 +6030,10 @@ class TransformEditorTool(FlatCAMTool):
def get_shapely_list_bounds(geometry_list): def get_shapely_list_bounds(geometry_list):
xmin = Inf xmin = np.Inf
ymin = Inf ymin = np.Inf
xmax = -Inf xmax = -np.Inf
ymax = -Inf ymax = -np.Inf
for gs in geometry_list: for gs in geometry_list:
try: try:

View File

@ -14,6 +14,8 @@
from flatcamGUI.PreferencesUI import * from flatcamGUI.PreferencesUI import *
from matplotlib.backend_bases import KeyEvent as mpl_key_event from matplotlib.backend_bases import KeyEvent as mpl_key_event
from copy import deepcopy
from datetime import datetime
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -3696,7 +3698,7 @@ class FlatCAMSystemTray(QtWidgets.QSystemTrayIcon):
class BookmarkManager(QtWidgets.QWidget): class BookmarkManager(QtWidgets.QWidget):
mark_rows = pyqtSignal() mark_rows = QtCore.pyqtSignal()
def __init__(self, app, storage, parent=None): def __init__(self, app, storage, parent=None):
super(BookmarkManager, self).__init__(parent) super(BookmarkManager, self).__init__(parent)

View File

@ -12,18 +12,14 @@
# ########################################################## # ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt5.QtCore import Qt, pyqtSlot
from PyQt5.QtWidgets import QTextEdit, QCompleter, QAction from PyQt5.QtWidgets import QTextEdit, QCompleter, QAction
from PyQt5.QtGui import QColor, QKeySequence, QPalette, QTextCursor from PyQt5.QtGui import QKeySequence, QTextCursor
from copy import copy from copy import copy
import re import re
import logging import logging
import html import html
import webbrowser
from copy import deepcopy
import sys
from datetime import datetime
log = logging.getLogger('base') log = logging.getLogger('base')
@ -513,7 +509,7 @@ class EvalEntry2(QtWidgets.QLineEdit):
class FCSpinner(QtWidgets.QSpinBox): class FCSpinner(QtWidgets.QSpinBox):
returnPressed = pyqtSignal() returnPressed = QtCore.pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
super(FCSpinner, self).__init__(parent) super(FCSpinner, self).__init__(parent)
@ -580,7 +576,7 @@ class FCSpinner(QtWidgets.QSpinBox):
class FCDoubleSpinner(QtWidgets.QDoubleSpinBox): class FCDoubleSpinner(QtWidgets.QDoubleSpinBox):
returnPressed = pyqtSignal() returnPressed = QtCore.pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
super(FCDoubleSpinner, self).__init__(parent) super(FCDoubleSpinner, self).__init__(parent)
@ -869,16 +865,16 @@ class FCTextAreaExtended(QtWidgets.QTextEdit):
if self.textCursor().block().text().startswith(" "): if self.textCursor().block().text().startswith(" "):
# skip the white space # skip the white space
self.moveCursor(QtGui.QTextCursor.NextWord) self.moveCursor(QtGui.QTextCursor.NextWord)
self.moveCursor(QtGui.QTextCursor.NextCharacter,QtGui.QTextCursor.KeepAnchor) self.moveCursor(QtGui.QTextCursor.NextCharacter, QtGui.QTextCursor.KeepAnchor)
character = self.textCursor().selectedText() character = self.textCursor().selectedText()
if character == "#": if character == "#":
# delete # # delete #
self.textCursor().deletePreviousChar() self.textCursor().deletePreviousChar()
# delete white space # delete white space
self.moveCursor(QtGui.QTextCursor.NextWord,QtGui.QTextCursor.KeepAnchor) self.moveCursor(QtGui.QTextCursor.NextWord, QtGui.QTextCursor.KeepAnchor)
self.textCursor().removeSelectedText() self.textCursor().removeSelectedText()
else: else:
self.moveCursor(QtGui.QTextCursor.PreviousCharacter,QtGui.QTextCursor.KeepAnchor) self.moveCursor(QtGui.QTextCursor.PreviousCharacter, QtGui.QTextCursor.KeepAnchor)
self.textCursor().insertText("# ") self.textCursor().insertText("# ")
cursor = QtGui.QTextCursor(self.textCursor()) cursor = QtGui.QTextCursor(self.textCursor())
cursor.setPosition(pos) cursor.setPosition(pos)
@ -1261,7 +1257,6 @@ class FCDetachableTab(QtWidgets.QTabWidget):
attached = True attached = True
break break
# If the tab is not attached, close it's window and # If the tab is not attached, close it's window and
# remove the reference to it # remove the reference to it
if not attached: if not attached:
@ -1342,8 +1337,8 @@ class FCDetachableTab(QtWidgets.QTabWidget):
can be re-attached by closing the dialog or by dragging the window into the tab bar can be re-attached by closing the dialog or by dragging the window into the tab bar
""" """
onCloseSignal = pyqtSignal(QtWidgets.QWidget, str, QtGui.QIcon) onCloseSignal = QtCore.pyqtSignal(QtWidgets.QWidget, str, QtGui.QIcon)
onDropSignal = pyqtSignal(str, QtCore.QPoint) onDropSignal = QtCore.pyqtSignal(str, QtCore.QPoint)
def __init__(self, name, contentWidget): def __init__(self, name, contentWidget):
QtWidgets.QMainWindow.__init__(self, None) QtWidgets.QMainWindow.__init__(self, None)
@ -1384,7 +1379,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
An event filter class to detect a QMainWindow drop event An event filter class to detect a QMainWindow drop event
""" """
onDropSignal = pyqtSignal(QtCore.QPoint) onDropSignal = QtCore.pyqtSignal(QtCore.QPoint)
def __init__(self): def __init__(self):
QtCore.QObject.__init__(self) QtCore.QObject.__init__(self)
@ -1416,11 +1411,11 @@ class FCDetachableTab(QtWidgets.QTabWidget):
return False return False
class FCTabBar(QtWidgets.QTabBar): class FCTabBar(QtWidgets.QTabBar):
onDetachTabSignal = pyqtSignal(int, QtCore.QPoint) onDetachTabSignal = QtCore.pyqtSignal(int, QtCore.QPoint)
onMoveTabSignal = pyqtSignal(int, int) onMoveTabSignal = QtCore.pyqtSignal(int, int)
detachedTabDropSignal = pyqtSignal(str, int, QtCore.QPoint) detachedTabDropSignal = QtCore.pyqtSignal(str, int, QtCore.QPoint)
right_click = pyqtSignal(int) right_click = QtCore.pyqtSignal(int)
def __init__(self, parent=None): def __init__(self, parent=None):
QtWidgets.QTabBar.__init__(self, parent) QtWidgets.QTabBar.__init__(self, parent)
@ -1498,7 +1493,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
self.dragInitiated = True self.dragInitiated = True
# If the current movement is a drag initiated by the left button # If the current movement is a drag initiated by the left button
if (((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged): if ((event.buttons() & QtCore.Qt.LeftButton)) and self.dragInitiated and self.can_be_dragged:
# Stop the move event # Stop the move event
finishMoveEvent = QtGui.QMouseEvent( finishMoveEvent = QtGui.QMouseEvent(
@ -1591,7 +1586,7 @@ class FCDetachableTab(QtWidgets.QTabWidget):
class FCDetachableTab2(FCDetachableTab): class FCDetachableTab2(FCDetachableTab):
tab_closed_signal = pyqtSignal(object) tab_closed_signal = QtCore.pyqtSignal(object)
def __init__(self, protect=None, protect_by_name=None, parent=None): def __init__(self, protect=None, protect_by_name=None, parent=None):
super(FCDetachableTab2, self).__init__(protect=protect, protect_by_name=protect_by_name, parent=parent) super(FCDetachableTab2, self).__init__(protect=protect, protect_by_name=protect_by_name, parent=parent)
@ -1729,7 +1724,7 @@ class OptionalHideInputSection:
class FCTable(QtWidgets.QTableWidget): class FCTable(QtWidgets.QTableWidget):
drag_drop_sig = pyqtSignal() drag_drop_sig = QtCore.pyqtSignal()
def __init__(self, drag_drop=False, protected_rows=None, parent=None): def __init__(self, drag_drop=False, protected_rows=None, parent=None):
super(FCTable, self).__init__(parent) super(FCTable, self).__init__(parent)
@ -2024,8 +2019,8 @@ class _ExpandableTextEdit(QTextEdit):
Class implements edit line, which expands themselves automatically Class implements edit line, which expands themselves automatically
""" """
historyNext = pyqtSignal() historyNext = QtCore.pyqtSignal()
historyPrev = pyqtSignal() historyPrev = QtCore.pyqtSignal()
def __init__(self, termwidget, *args): def __init__(self, termwidget, *args):
QTextEdit.__init__(self, *args) QTextEdit.__init__(self, *args)
@ -2148,7 +2143,7 @@ class _ExpandableTextEdit(QTextEdit):
class MyCompleter(QCompleter): class MyCompleter(QCompleter):
insertText = pyqtSignal(str) insertText = QtCore.pyqtSignal(str)
def __init__(self, parent=None): def __init__(self, parent=None):
QCompleter.__init__(self) QCompleter.__init__(self)
@ -2166,4 +2161,3 @@ class MyCompleter(QCompleter):
def getSelected(self): def getSelected(self):
return self.lastSelected return self.lastSelected

View File

@ -11,8 +11,6 @@
# Date: 3/10/2019 # # Date: 3/10/2019 #
# ########################################################## # ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt
from flatcamGUI.GUIElements import * from flatcamGUI.GUIElements import *
import sys import sys

View File

@ -7,7 +7,7 @@
# Modified by Marius Stanciu 09/21/2019 # # Modified by Marius Stanciu 09/21/2019 #
############################################################ ############################################################
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtCore
from PyQt5.QtCore import pyqtSignal from PyQt5.QtCore import pyqtSignal
# needed for legacy mode # needed for legacy mode

View File

@ -8,11 +8,8 @@
from PyQt5.QtCore import QSettings from PyQt5.QtCore import QSettings
from flatcamGUI.GUIElements import * from flatcamGUI.GUIElements import *
import platform import platform
import webbrowser
import sys import sys
from flatcamEditors.FlatCAMGeoEditor import FCShapeTool
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins

View File

@ -6,12 +6,15 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
import numpy as np
from PyQt5.QtGui import QPalette from PyQt5.QtGui import QPalette
from PyQt5.QtCore import QSettings from PyQt5.QtCore import QSettings
import numpy as np
import vispy.scene as scene import vispy.scene as scene
from vispy.scene.cameras.base_camera import BaseCamera from vispy.scene.cameras.base_camera import BaseCamera
from vispy.color import Color from vispy.color import Color
import time import time
white = Color("#ffffff") white = Color("#ffffff")

View File

@ -9,7 +9,6 @@
# ########################################################## # ##########################################################
import math import math
import sys
def norm(v): def norm(v):

View File

@ -1,4 +1,14 @@
from camlib import *
from camlib import Geometry
import FlatCAMApp
import shapely.affinity as affinity
from shapely.geometry import Point, LineString
import numpy as np
import re
import logging
import traceback
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -8,6 +18,8 @@ import builtins
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class Excellon(Geometry): class Excellon(Geometry):
""" """
@ -1017,10 +1029,10 @@ class Excellon(Geometry):
def bounds_rec(obj): def bounds_rec(obj):
if type(obj) is list: if type(obj) is list:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in obj: for k in obj:
if type(k) is dict: if type(k) is dict:

View File

@ -11,12 +11,11 @@
# ###################################################################### # ######################################################################
import re, os, sys, glob import re, os, sys, glob
import itertools
from shapely.geometry import Point, Polygon from shapely.geometry import Point, Polygon
from shapely.affinity import translate, scale, rotate from shapely.affinity import translate, scale
from shapely.geometry import MultiPolygon from shapely.geometry import MultiPolygon
from shapely.geometry.base import BaseGeometry
import freetype as ft import freetype as ft
from fontTools import ttLib from fontTools import ttLib

View File

@ -1,4 +1,19 @@
from camlib import *
from camlib import Geometry, arc, arc_angle, ApertureMacro
import FlatCAMApp
import numpy as np
import re
import logging
import traceback
from copy import deepcopy
import sys
from shapely.ops import cascaded_union
from shapely.geometry import Polygon, MultiPolygon, LineString, Point
import shapely.affinity as affinity
from shapely.geometry import box as shply_box
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import gettext import gettext
@ -7,6 +22,8 @@ import builtins
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class Gerber(Geometry): class Gerber(Geometry):
""" """
@ -253,14 +270,14 @@ class Gerber(Geometry):
self.apertures[apid] = {"type": "R", self.apertures[apid] = {"type": "R",
"width": float(paramList[0]), "width": float(paramList[0]),
"height": float(paramList[1]), "height": float(paramList[1]),
"size": sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack "size": np.sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack
return apid return apid
if apertureType == "O": # Obround if apertureType == "O": # Obround
self.apertures[apid] = {"type": "O", self.apertures[apid] = {"type": "O",
"width": float(paramList[0]), "width": float(paramList[0]),
"height": float(paramList[1]), "height": float(paramList[1]),
"size": sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack "size": np.sqrt(float(paramList[0]) ** 2 + float(paramList[1]) ** 2)} # Hack
return apid return apid
if apertureType == "P": # Polygon (regular) if apertureType == "P": # Polygon (regular)
@ -1231,15 +1248,15 @@ class Gerber(Geometry):
if quadrant_mode == 'MULTI': if quadrant_mode == 'MULTI':
center = [i + current_x, j + current_y] center = [i + current_x, j + current_y]
radius = sqrt(i ** 2 + j ** 2) radius = np.sqrt(i ** 2 + j ** 2)
start = arctan2(-j, -i) # Start angle start = np.arctan2(-j, -i) # Start angle
# Numerical errors might prevent start == stop therefore # Numerical errors might prevent start == stop therefore
# we check ahead of time. This should result in a # we check ahead of time. This should result in a
# 360 degree arc. # 360 degree arc.
if current_x == circular_x and current_y == circular_y: if current_x == circular_x and current_y == circular_y:
stop = start stop = start
else: else:
stop = arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle stop = np.arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
this_arc = arc(center, radius, start, stop, this_arc = arc(center, radius, start, stop,
arcdir[current_interpolation_mode], arcdir[current_interpolation_mode],
@ -1273,10 +1290,10 @@ class Gerber(Geometry):
valid = False valid = False
log.debug("I: %f J: %f" % (i, j)) log.debug("I: %f J: %f" % (i, j))
for center in center_candidates: for center in center_candidates:
radius = sqrt(i ** 2 + j ** 2) radius = np.sqrt(i ** 2 + j ** 2)
# Make sure radius to start is the same as radius to end. # Make sure radius to start is the same as radius to end.
radius2 = sqrt((center[0] - circular_x) ** 2 + (center[1] - circular_y) ** 2) radius2 = np.sqrt((center[0] - circular_x) ** 2 + (center[1] - circular_y) ** 2)
if radius2 < radius * 0.95 or radius2 > radius * 1.05: if radius2 < radius * 0.95 or radius2 > radius * 1.05:
continue # Not a valid center. continue # Not a valid center.
@ -1284,16 +1301,16 @@ class Gerber(Geometry):
i = center[0] - current_x i = center[0] - current_x
j = center[1] - current_y j = center[1] - current_y
start = arctan2(-j, -i) # Start angle start = np.arctan2(-j, -i) # Start angle
stop = arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle stop = np.arctan2(-center[1] + circular_y, -center[0] + circular_x) # Stop angle
angle = abs(arc_angle(start, stop, arcdir[current_interpolation_mode])) angle = abs(arc_angle(start, stop, arcdir[current_interpolation_mode]))
log.debug("ARC START: %f, %f CENTER: %f, %f STOP: %f, %f" % log.debug("ARC START: %f, %f CENTER: %f, %f STOP: %f, %f" %
(current_x, current_y, center[0], center[1], circular_x, circular_y)) (current_x, current_y, center[0], center[1], circular_x, circular_y))
log.debug("START Ang: %f, STOP Ang: %f, DIR: %s, ABS: %.12f <= %.12f: %s" % log.debug("START Ang: %f, STOP Ang: %f, DIR: %s, ABS: %.12f <= %.12f: %s" %
(start * 180 / pi, stop * 180 / pi, arcdir[current_interpolation_mode], (start * 180 / np.pi, stop * 180 / np.pi, arcdir[current_interpolation_mode],
angle * 180 / pi, pi / 2 * 180 / pi, angle <= (pi + 1e-6) / 2)) angle * 180 / np.pi, np.pi / 2 * 180 / np.pi, angle <= (np.pi + 1e-6) / 2))
if angle <= (pi + 1e-6) / 2: if angle <= (np.pi + 1e-6) / 2:
log.debug("########## ACCEPTING ARC ############") log.debug("########## ACCEPTING ARC ############")
this_arc = arc(center, radius, start, stop, this_arc = arc(center, radius, start, stop,
arcdir[current_interpolation_mode], arcdir[current_interpolation_mode],
@ -1478,8 +1495,8 @@ class Gerber(Geometry):
n_vertices = aperture['nVertices'] n_vertices = aperture['nVertices']
points = [] points = []
for i in range(0, n_vertices): for i in range(0, n_vertices):
x = loc[0] + 0.5 * diam * (cos(2 * pi * i / n_vertices)) x = loc[0] + 0.5 * diam * (np.cos(2 * np.pi * i / n_vertices))
y = loc[1] + 0.5 * diam * (sin(2 * pi * i / n_vertices)) y = loc[1] + 0.5 * diam * (np.sin(2 * np.pi * i / n_vertices))
points.append((x, y)) points.append((x, y))
ply = Polygon(points) ply = Polygon(points)
if 'rotation' in aperture: if 'rotation' in aperture:
@ -1553,10 +1570,10 @@ class Gerber(Geometry):
def bounds_rec(obj): def bounds_rec(obj):
if type(obj) is list and type(obj) is not MultiPolygon: if type(obj) is list and type(obj) is not MultiPolygon:
minx = Inf minx = np.Inf
miny = Inf miny = np.Inf
maxx = -Inf maxx = -np.Inf
maxy = -Inf maxy = -np.Inf
for k in obj: for k in obj:
if type(k) is dict: if type(k) is dict:

View File

@ -5,8 +5,9 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from FlatCAMObj import * from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, FCEntry
import math import math
import gettext import gettext
@ -321,11 +322,11 @@ class ToolCalculator(FlatCAMTool):
def on_calculate_inch_units(self): def on_calculate_inch_units(self):
mm_val = float(self.mm_entry.get_value()) mm_val = float(self.mm_entry.get_value())
self.inch_entry.set_value('%.*f' % (self.decimals,(mm_val / 25.4))) self.inch_entry.set_value('%.*f' % (self.decimals, (mm_val / 25.4)))
def on_calculate_mm_units(self): def on_calculate_mm_units(self):
inch_val = float(self.inch_entry.get_value()) inch_val = float(self.inch_entry.get_value())
self.mm_entry.set_value('%.*f' % (self.decimals,(inch_val * 25.4))) self.mm_entry.set_value('%.*f' % (self.decimals, (inch_val * 25.4)))
def on_calculate_eplate(self): def on_calculate_eplate(self):
length = float(self.pcblength_entry.get_value()) length = float(self.pcblength_entry.get_value())

View File

@ -5,12 +5,21 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from ObjectCollection import * from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, RadioSet, FCComboBox
from FlatCAMApp import * from FlatCAMObj import FlatCAMGerber
from shapely.geometry import box
from shapely.ops import cascaded_union, unary_union
from shapely.geometry import box, MultiPolygon, Polygon, LineString, LinearRing
from shapely.ops import cascaded_union, unary_union
import shapely.affinity as affinity
from matplotlib.backend_bases import KeyEvent as mpl_key_event
from numpy import Inf
from copy import deepcopy
import math
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -19,6 +28,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class CutOut(FlatCAMTool): class CutOut(FlatCAMTool):

View File

@ -1,9 +1,14 @@
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from FlatCAMObj import * from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, EvalEntry
from FlatCAMObj import FlatCAMGerber, FlatCAMExcellon, FlatCAMGeometry
from shapely.geometry import Point from shapely.geometry import Point
from shapely import affinity from shapely import affinity
from PyQt5 import QtCore
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -12,6 +17,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class DblSidedTool(FlatCAMTool): class DblSidedTool(FlatCAMTool):

View File

@ -5,12 +5,15 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from FlatCAMObj import *
from flatcamGUI.VisPyVisuals import * from flatcamGUI.VisPyVisuals import *
from flatcamGUI.GUIElements import FCEntry
from math import sqrt import copy
import math
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -19,6 +22,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class Distance(FlatCAMTool): class Distance(FlatCAMTool):
@ -335,7 +340,7 @@ class Distance(FlatCAMTool):
elif len(self.points) == 2: elif len(self.points) == 2:
dx = self.points[1][0] - self.points[0][0] dx = self.points[1][0] - self.points[0][0]
dy = self.points[1][1] - self.points[0][1] dy = self.points[1][1] - self.points[0][1]
d = sqrt(dx ** 2 + dy ** 2) d = math.sqrt(dx ** 2 + dy ** 2)
self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1])) self.stop_entry.set_value("(%.*f, %.*f)" % (self.decimals, pos[0], self.decimals, pos[1]))
self.app.inform.emit(_("MEASURING: Result D(x) = {d_x} | D(y) = {d_y} | Distance = {d_z}").format( self.app.inform.emit(_("MEASURING: Result D(x) = {d_x} | D(y) = {d_y} | Distance = {d_z}").format(

View File

@ -5,14 +5,16 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from FlatCAMObj import *
from flatcamGUI.VisPyVisuals import * from flatcamGUI.VisPyVisuals import *
from flatcamGUI.GUIElements import FCEntry
from shapely.ops import nearest_points from shapely.ops import nearest_points
from shapely.geometry import Point
from math import sqrt import math
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -21,6 +23,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class DistanceMin(FlatCAMTool): class DistanceMin(FlatCAMTool):
@ -260,7 +264,7 @@ class DistanceMin(FlatCAMTool):
except Exception as e: except Exception as e:
pass pass
d = sqrt(dx ** 2 + dy ** 2) d = math.sqrt(dx ** 2 + dy ** 2)
self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d))) self.total_distance_entry.set_value('%.*f' % (self.decimals, abs(d)))
self.h_point = (min(first_pos.x, last_pos.x) + (abs(dx) / 2), min(first_pos.y, last_pos.y) + (abs(dy) / 2)) self.h_point = (min(first_pos.x, last_pos.x) + (abs(dx) / 2), min(first_pos.y, last_pos.y) + (abs(dy) / 2))

View File

@ -5,14 +5,15 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from FlatCAMTool import FlatCAMTool
from FlatCAMObj import *
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
OptionalHideInputSection, OptionalInputSection
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import RadioSet, FCDoubleSpinner, FCCheckBox, \
OptionalHideInputSection, OptionalInputSection
from copy import deepcopy from copy import deepcopy
import logging
from shapely.geometry import Polygon, MultiPolygon, Point
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -22,6 +23,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class Film(FlatCAMTool): class Film(FlatCAMTool):
@ -166,7 +169,7 @@ class Film(FlatCAMTool):
self.ois_scale = OptionalInputSection(self.film_scale_cb, [self.film_scalex_label, self.film_scalex_entry, self.ois_scale = OptionalInputSection(self.film_scale_cb, [self.film_scalex_label, self.film_scalex_entry,
self.film_scaley_label, self.film_scaley_entry]) self.film_scaley_label, self.film_scaley_entry])
# Skew Geometry # Skew Geometry
self.film_skew_cb =FCCheckBox('%s' % _("Skew Film geometry")) self.film_skew_cb = FCCheckBox('%s' % _("Skew Film geometry"))
self.film_skew_cb.setToolTip( self.film_skew_cb.setToolTip(
_("Positive values will skew to the right\n" _("Positive values will skew to the right\n"
"while negative values will skew to the left.") "while negative values will skew to the left.")
@ -202,9 +205,9 @@ class Film(FlatCAMTool):
"It can be one of the four points of the geometry bounding box.") "It can be one of the four points of the geometry bounding box.")
) )
self.film_skew_reference = RadioSet([{'label': _('Bottom Left'), 'value': 'bottomleft'}, self.film_skew_reference = RadioSet([{'label': _('Bottom Left'), 'value': 'bottomleft'},
{'label': _('Top Left'), 'value': 'topleft'}, {'label': _('Top Left'), 'value': 'topleft'},
{'label': _('Bottom Right'), 'value': 'bottomright'}, {'label': _('Bottom Right'), 'value': 'bottomright'},
{'label': _('Top right'), 'value': 'topright'}], {'label': _('Top right'), 'value': 'topright'}],
orientation='vertical', orientation='vertical',
stretch=False) stretch=False)

View File

@ -5,11 +5,11 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner
from PyQt5 import QtGui, QtWidgets from PyQt5 import QtGui, QtWidgets
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins

View File

@ -5,12 +5,13 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from FlatCAMObj import *
from flatcamGUI.VisPyVisuals import * from flatcamGUI.VisPyVisuals import *
from FlatCAMObj import FlatCAMGerber
from copy import copy from copy import copy
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -19,11 +20,13 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class ToolMove(FlatCAMTool): class ToolMove(FlatCAMTool):
toolName = _("Move") toolName = _("Move")
replot_signal = pyqtSignal(list) replot_signal = QtCore.pyqtSignal(list)
def __init__(self, app): def __init__(self, app):
FlatCAMTool.__init__(self, app) FlatCAMTool.__init__(self, app)

View File

@ -5,12 +5,23 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtCore, QtGui
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from copy import copy, deepcopy from flatcamGUI.GUIElements import FCCheckBox, FCDoubleSpinner, RadioSet, FCTable, FCInputDialog
from ObjectCollection import * from flatcamParsers.ParseGerber import Gerber
import time from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber
from shapely.geometry import base import FlatCAMApp
from copy import deepcopy
import numpy as np
import math
from shapely.geometry import base
from shapely.ops import cascaded_union
from shapely.geometry import MultiPolygon, Polygon, MultiLineString, LineString, LinearRing
import logging
import traceback
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -19,6 +30,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class NonCopperClear(FlatCAMTool, Gerber): class NonCopperClear(FlatCAMTool, Gerber):
@ -473,7 +486,7 @@ class NonCopperClear(FlatCAMTool, Gerber):
"Add", self.on_add_tool_by_key, icon=QtGui.QIcon("share/plus16.png")) "Add", self.on_add_tool_by_key, icon=QtGui.QIcon("share/plus16.png"))
self.tools_table.addContextMenu( self.tools_table.addContextMenu(
"Delete", lambda: "Delete", lambda:
self.on_tool_delete(rows_to_delete=None, all=None), icon=QtGui.QIcon("share/delete32.png")) self.on_tool_delete(rows_to_delete=None, all_tools=None), icon=QtGui.QIcon("share/delete32.png"))
# ############################################################################# # #############################################################################
# ########################## VARIABLES ######################################## # ########################## VARIABLES ########################################
@ -1040,12 +1053,19 @@ class NonCopperClear(FlatCAMTool, Gerber):
"New diameter value is already in the Tool Table.")) "New diameter value is already in the Tool Table."))
self.build_ui() self.build_ui()
def on_tool_delete(self, rows_to_delete=None, all=None): def on_tool_delete(self, rows_to_delete=None, all_tools=None):
"""
Will delete a tool in the tool table
:param rows_to_delete: which rows to delete; can be a list
:param all_tools: delete all tools in the tool table
:return:
"""
self.ui_disconnect() self.ui_disconnect()
deleted_tools_list = [] deleted_tools_list = []
if all: if all_tools:
self.paint_tools.clear() self.paint_tools.clear()
self.build_ui() self.build_ui()
return return

View File

@ -5,13 +5,19 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from FlatCAMTool import FlatCAMTool from PyQt5 import QtWidgets, QtCore, QtGui
from FlatCAMObj import *
from shapely.geometry import Point
from shapely import affinity
from shapely.ops import nearest_points
from PyQt5 import QtCore
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import OptionalHideInputSection, FCTextArea, FCEntry, FCSpinner, FCCheckBox
from FlatCAMObj import FlatCAMGerber
import FlatCAMApp
from shapely.geometry import MultiPolygon
from shapely.ops import nearest_points
import numpy as np
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -20,13 +26,15 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class ToolOptimal(FlatCAMTool): class ToolOptimal(FlatCAMTool):
toolName = _("Optimal Tool") toolName = _("Optimal Tool")
update_text = pyqtSignal(list) update_text = QtCore.pyqtSignal(list)
update_sec_distances = pyqtSignal(dict) update_sec_distances = QtCore.pyqtSignal(dict)
def __init__(self, app): def __init__(self, app):
FlatCAMTool.__init__(self, app) FlatCAMTool.__init__(self, app)

View File

@ -5,19 +5,22 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from shapely.geometry import Point, Polygon, LineString import FlatCAMApp
from shapely.ops import cascaded_union, unary_union
from FlatCAMObj import * from shapely.geometry import Point, Polygon, LineString, MultiPolygon
from shapely.ops import unary_union
import math
from copy import copy, deepcopy from copy import copy, deepcopy
import numpy as np import numpy as np
import zlib import zlib
import re import re
import time import time
import logging
import traceback
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -27,6 +30,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class ToolPDF(FlatCAMTool): class ToolPDF(FlatCAMTool):
""" """

View File

@ -5,10 +5,25 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtGui, QtCore
from PyQt5.QtCore import Qt
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from copy import copy, deepcopy from copy import deepcopy
from ObjectCollection import * # from ObjectCollection import *
from shapely.geometry import base from flatcamParsers.ParseGerber import Gerber
from FlatCAMObj import FlatCAMGerber, FlatCAMGeometry
from camlib import Geometry
from flatcamGUI.GUIElements import FCTable, FCDoubleSpinner, FCCheckBox, FCInputDialog, RadioSet
import FlatCAMApp
from shapely.geometry import base, Polygon, MultiPolygon, LinearRing
from shapely.ops import cascaded_union
import numpy as np
from numpy import Inf
import traceback
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -18,6 +33,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class ToolPaint(FlatCAMTool, Gerber): class ToolPaint(FlatCAMTool, Gerber):
@ -374,6 +391,7 @@ class ToolPaint(FlatCAMTool, Gerber):
self.mm = None self.mm = None
self.mp = None self.mp = None
self.mr = None
self.sel_rect = [] self.sel_rect = []
@ -641,10 +659,10 @@ class ToolPaint(FlatCAMTool, Gerber):
for tooluid_key, tooluid_value in self.paint_tools.items(): for tooluid_key, tooluid_value in self.paint_tools.items():
if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted: if float('%.*f' % (self.decimals, tooluid_value['tooldia'])) == tool_sorted:
tool_id += 1 tool_id += 1
id = QtWidgets.QTableWidgetItem('%d' % int(tool_id)) id_item = QtWidgets.QTableWidgetItem('%d' % int(tool_id))
id.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) id_item.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)
row_no = tool_id - 1 row_no = tool_id - 1
self.tools_table.setItem(row_no, 0, id) # Tool name/id self.tools_table.setItem(row_no, 0, id_item) # Tool name/id
# Make sure that the drill diameter when in MM is with no more than 2 decimals # Make sure that the drill diameter when in MM is with no more than 2 decimals
# There are no drill bits in MM with more than 2 decimals diameter # There are no drill bits in MM with more than 2 decimals diameter
@ -2213,7 +2231,7 @@ class ToolPaint(FlatCAMTool, Gerber):
log.debug("Could not Paint the polygons. %s" % str(e)) log.debug("Could not Paint the polygons. %s" % str(e))
self.app.inform.emit('[ERROR] %s\n%s' % self.app.inform.emit('[ERROR] %s\n%s' %
(_("Could not do Paint All. Try a different combination of parameters. " (_("Could not do Paint All. Try a different combination of parameters. "
"Or a different Method of paint"), str(e))) "Or a different Method of paint"), str(e)))
return return
pol_nr += 1 pol_nr += 1
@ -2373,7 +2391,7 @@ class ToolPaint(FlatCAMTool, Gerber):
log.debug("Could not Paint the polygons. %s" % str(e)) log.debug("Could not Paint the polygons. %s" % str(e))
self.app.inform.emit('[ERROR] %s\n%s' % self.app.inform.emit('[ERROR] %s\n%s' %
(_("Could not do Paint All. Try a different combination of parameters. " (_("Could not do Paint All. Try a different combination of parameters. "
"Or a different Method of paint"), str(e))) "Or a different Method of paint"), str(e)))
return return
pol_nr += 1 pol_nr += 1

View File

@ -5,19 +5,29 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtGui, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from copy import copy, deepcopy
from ObjectCollection import * from flatcamGUI.GUIElements import FCSpinner, FCDoubleSpinner, RadioSet, FCCheckBox, OptionalInputSection
import time from FlatCAMObj import FlatCAMGeometry, FlatCAMGerber, FlatCAMExcellon
import FlatCAMApp
from copy import deepcopy
# from ObjectCollection import *
import numpy as np
import shapely.affinity as affinity
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
import logging
fcTranslate.apply_language('strings') fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class Panelize(FlatCAMTool): class Panelize(FlatCAMTool):
@ -367,15 +377,13 @@ class Panelize(FlatCAMTool):
# Get source object. # Get source object.
try: try:
obj = self.app.collection.get_by_name(str(name)) panel_obj = self.app.collection.get_by_name(str(name))
except Exception as e: except Exception as e:
log.debug("Panelize.on_panelize() --> %s" % str(e)) log.debug("Panelize.on_panelize() --> %s" % str(e))
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
(_("Could not retrieve object"), name)) (_("Could not retrieve object"), name))
return "Could not retrieve object: %s" % name return "Could not retrieve object: %s" % name
panel_obj = obj
if panel_obj is None: if panel_obj is None:
self.app.inform.emit('[ERROR_NOTCL] %s: %s' % self.app.inform.emit('[ERROR_NOTCL] %s: %s' %
(_("Object not found"), panel_obj)) (_("Object not found"), panel_obj))
@ -443,6 +451,18 @@ class Panelize(FlatCAMTool):
rows -= 1 rows -= 1
panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1)) panel_lengthy = ((ymax - ymin) * rows) + (spacing_rows * (rows - 1))
if isinstance(panel_obj, FlatCAMExcellon) or isinstance(panel_obj, FlatCAMGeometry):
# make a copy of the panelized Excellon or Geometry tools
copied_tools = dict()
for tt, tt_val in list(panel_obj.tools.items()):
copied_tools[tt] = deepcopy(tt_val)
if isinstance(panel_obj, FlatCAMGerber):
# make a copy of the panelized Gerber apertures
copied_apertures = dict()
for tt, tt_val in list(panel_obj.apertures.items()):
copied_apertures[tt] = deepcopy(tt_val)
def panelize_2(): def panelize_2():
if panel_obj is not None: if panel_obj is not None:
self.app.inform.emit(_("Generating panel ... ")) self.app.inform.emit(_("Generating panel ... "))
@ -452,7 +472,7 @@ class Panelize(FlatCAMTool):
def job_init_excellon(obj_fin, app_obj): def job_init_excellon(obj_fin, app_obj):
currenty = 0.0 currenty = 0.0
self.app.progress.emit(10) self.app.progress.emit(10)
obj_fin.tools = panel_obj.tools.copy() obj_fin.tools = copied_tools
obj_fin.drills = [] obj_fin.drills = []
obj_fin.slots = [] obj_fin.slots = []
obj_fin.solid_geometry = [] obj_fin.solid_geometry = []
@ -472,7 +492,6 @@ class Panelize(FlatCAMTool):
currentx = 0.0 currentx = 0.0
for col in range(columns): for col in range(columns):
element += 1 element += 1
disp_number = 0
old_disp_number = 0 old_disp_number = 0
if panel_obj.drills: if panel_obj.drills:
@ -493,7 +512,7 @@ class Panelize(FlatCAMTool):
drill_nr += 1 drill_nr += 1
disp_number = int(np.interp(drill_nr, [0, geo_len_drills], [0, 100])) disp_number = int(np.interp(drill_nr, [0, geo_len_drills], [0, 100]))
if disp_number > old_disp_number and disp_number <= 100: if old_disp_number < disp_number <= 100:
self.app.proc_container.update_view_text(' %s: %d D:%d%%' % self.app.proc_container.update_view_text(' %s: %d D:%d%%' %
(_("Copy"), (_("Copy"),
int(element), int(element),
@ -520,7 +539,7 @@ class Panelize(FlatCAMTool):
slot_nr += 1 slot_nr += 1
disp_number = int(np.interp(slot_nr, [0, geo_len_slots], [0, 100])) disp_number = int(np.interp(slot_nr, [0, geo_len_slots], [0, 100]))
if disp_number > old_disp_number and disp_number <= 100: if old_disp_number < disp_number <= 100:
self.app.proc_container.update_view_text(' %s: %d S:%d%%' % self.app.proc_container.update_view_text(' %s: %d S:%d%%' %
(_("Copy"), (_("Copy"),
int(element), int(element),
@ -557,12 +576,12 @@ class Panelize(FlatCAMTool):
# create the initial structure on which to create the panel # create the initial structure on which to create the panel
if isinstance(panel_obj, FlatCAMGeometry): if isinstance(panel_obj, FlatCAMGeometry):
obj_fin.multigeo = panel_obj.multigeo obj_fin.multigeo = panel_obj.multigeo
obj_fin.tools = deepcopy(panel_obj.tools) obj_fin.tools = copied_tools
if panel_obj.multigeo is True: if panel_obj.multigeo is True:
for tool in panel_obj.tools: for tool in panel_obj.tools:
obj_fin.tools[tool]['solid_geometry'][:] = [] obj_fin.tools[tool]['solid_geometry'][:] = []
elif isinstance(panel_obj, FlatCAMGerber): elif isinstance(panel_obj, FlatCAMGerber):
obj_fin.apertures = deepcopy(panel_obj.apertures) obj_fin.apertures = copied_apertures
for ap in obj_fin.apertures: for ap in obj_fin.apertures:
obj_fin.apertures[ap]['geometry'] = list() obj_fin.apertures[ap]['geometry'] = list()
@ -594,7 +613,6 @@ class Panelize(FlatCAMTool):
for col in range(columns): for col in range(columns):
element += 1 element += 1
disp_number = 0
old_disp_number = 0 old_disp_number = 0
if isinstance(panel_obj, FlatCAMGeometry): if isinstance(panel_obj, FlatCAMGeometry):

View File

@ -5,11 +5,11 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from FlatCAMTool import FlatCAMTool from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import RadioSet, FCSpinner, FCButton, FCTable
from flatcamGUI.GUIElements import RadioSet, FCComboBox, FCSpinner, FCButton, FCTable
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtCore import pyqtSignal
import re import re
import os import os
from datetime import datetime from datetime import datetime
@ -26,7 +26,7 @@ if '_' not in builtins.__dict__:
class PcbWizard(FlatCAMTool): class PcbWizard(FlatCAMTool):
file_loaded = pyqtSignal(str, str) file_loaded = QtCore.pyqtSignal(str, str)
toolName = _("PcbWizard Import Tool") toolName = _("PcbWizard Import Tool")

View File

@ -6,10 +6,14 @@
# ########################################################## # ##########################################################
from PyQt5 import QtGui, QtCore, QtWidgets from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from FlatCAMObj import * from FlatCAMObj import FlatCAMCNCjob
from shapely.geometry import MultiPolygon, Polygon
from shapely.ops import cascaded_union
from copy import deepcopy
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -18,11 +22,13 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class Properties(FlatCAMTool): class Properties(FlatCAMTool):
toolName = _("Properties") toolName = _("Properties")
calculations_finished = pyqtSignal(float, float, float, float, object) calculations_finished = QtCore.pyqtSignal(float, float, float, float, object)
def __init__(self, app): def __init__(self, app):
FlatCAMTool.__init__(self, app) FlatCAMTool.__init__(self, app)
@ -150,18 +156,18 @@ class Properties(FlatCAMTool):
self.addChild(obj_name, [obj.options['name']]) self.addChild(obj_name, [obj.options['name']])
def job_thread(obj): def job_thread(obj_prop):
proc = self.app.proc_container.new(_("Calculating dimensions ... Please wait.")) proc = self.app.proc_container.new(_("Calculating dimensions ... Please wait."))
length = 0.0 length = 0.0
width = 0.0 width = 0.0
area = 0.0 area = 0.0
geo = obj.solid_geometry geo = obj_prop.solid_geometry
if geo: if geo:
# calculate physical dimensions # calculate physical dimensions
try: try:
xmin, ymin, xmax, ymax = obj.bounds() xmin, ymin, xmax, ymax = obj_prop.bounds()
length = abs(xmax - xmin) length = abs(xmax - xmin)
width = abs(ymax - ymin) width = abs(ymax - ymin)
@ -179,9 +185,9 @@ class Properties(FlatCAMTool):
xmax = [] xmax = []
ymax = [] ymax = []
for tool in obj.tools: for tool_k in obj_prop.tools:
try: try:
x0, y0, x1, y1 = cascaded_union(obj.tools[tool]['solid_geometry']).bounds x0, y0, x1, y1 = cascaded_union(obj_prop.tools[tool_k]['solid_geometry']).bounds
xmin.append(x0) xmin.append(x0)
ymin.append(y0) ymin.append(y0)
xmax.append(x1) xmax.append(x1)
@ -207,25 +213,25 @@ class Properties(FlatCAMTool):
log.debug("Properties.addItems() --> %s" % str(e)) log.debug("Properties.addItems() --> %s" % str(e))
area_chull = 0.0 area_chull = 0.0
if not isinstance(obj, FlatCAMCNCjob): if not isinstance(obj_prop, FlatCAMCNCjob):
# calculate and add convex hull area # calculate and add convex hull area
if geo: if geo:
if isinstance(geo, MultiPolygon): if isinstance(geo, MultiPolygon):
env_obj = geo.convex_hull env_obj = geo.convex_hull
elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \ elif (isinstance(geo, MultiPolygon) and len(geo) == 1) or \
(isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon): (isinstance(geo, list) and len(geo) == 1) and isinstance(geo[0], Polygon):
env_obj = cascaded_union(obj.solid_geometry) env_obj = cascaded_union(obj_prop.solid_geometry)
env_obj = env_obj.convex_hull env_obj = env_obj.convex_hull
else: else:
env_obj = cascaded_union(obj.solid_geometry) env_obj = cascaded_union(obj_prop.solid_geometry)
env_obj = env_obj.convex_hull env_obj = env_obj.convex_hull
area_chull = env_obj.area area_chull = env_obj.area
else: else:
try: try:
area_chull = [] area_chull = []
for tool in obj.tools: for tool_k in obj_prop.tools:
area_el = cascaded_union(obj.tools[tool]['solid_geometry']).convex_hull area_el = cascaded_union(obj_prop.tools[tool_k]['solid_geometry']).convex_hull
area_chull.append(area_el.area) area_chull.append(area_el.area)
area_chull = max(area_chull) area_chull = max(area_chull)
except Exception as e: except Exception as e:

View File

@ -5,15 +5,18 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from FlatCAMTool import FlatCAMTool from PyQt5 import QtWidgets
from copy import copy, deepcopy
from ObjectCollection import *
import time
from FlatCAMPool import *
from os import getpid
from shapely.ops import nearest_points
from shapely.geometry.base import BaseGeometry
from FlatCAMTool import FlatCAMTool
from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, OptionalInputSection
from copy import deepcopy
from FlatCAMPool import *
# from os import getpid
from shapely.ops import nearest_points
from shapely.geometry import MultiPolygon, Polygon
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -22,12 +25,14 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class RulesCheck(FlatCAMTool): class RulesCheck(FlatCAMTool):
toolName = _("Check Rules") toolName = _("Check Rules")
tool_finished = pyqtSignal(list) tool_finished = QtCore.pyqtSignal(list)
def __init__(self, app): def __init__(self, app):
super(RulesCheck, self).__init__(self) super(RulesCheck, self).__init__(self)

View File

@ -6,7 +6,7 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
# from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt
from PyQt5.QtGui import QTextCursor from PyQt5.QtGui import QTextCursor
from PyQt5.QtWidgets import QVBoxLayout, QWidget from PyQt5.QtWidgets import QVBoxLayout, QWidget

View File

@ -5,12 +5,18 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets, QtCore
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
# from copy import copy, deepcopy from flatcamGUI.GUIElements import FCCheckBox, FCButton
from ObjectCollection import *
import time
from shapely.geometry import Polygon, MultiPolygon, MultiLineString, LineString
from shapely.ops import cascaded_union
import traceback
from copy import deepcopy
import time
import logging
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
import builtins import builtins
@ -19,6 +25,8 @@ fcTranslate.apply_language('strings')
if '_' not in builtins.__dict__: if '_' not in builtins.__dict__:
_ = gettext.gettext _ = gettext.gettext
log = logging.getLogger('base')
class ToolSub(FlatCAMTool): class ToolSub(FlatCAMTool):

View File

@ -5,8 +5,10 @@
# MIT Licence # # MIT Licence #
# ########################################################## # ##########################################################
from PyQt5 import QtWidgets
from FlatCAMTool import FlatCAMTool from FlatCAMTool import FlatCAMTool
from FlatCAMObj import * from flatcamGUI.GUIElements import FCDoubleSpinner, FCCheckBox, FCButton, OptionalInputSection, EvalEntry2
from FlatCAMObj import FlatCAMCNCjob
import gettext import gettext
import FlatCAMTranslation as fcTranslate import FlatCAMTranslation as fcTranslate
@ -271,7 +273,7 @@ class ToolTransform(FlatCAMTool):
_("Flip the selected object(s) over the X axis.") _("Flip the selected object(s) over the X axis.")
) )
hlay0= QtWidgets.QHBoxLayout() hlay0 = QtWidgets.QHBoxLayout()
self.transform_lay.addLayout(hlay0) self.transform_lay.addLayout(hlay0)
hlay0.addWidget(self.flipx_button) hlay0.addWidget(self.flipx_button)
@ -312,7 +314,7 @@ class ToolTransform(FlatCAMTool):
self.ois_flip = OptionalInputSection(self.flip_ref_cb, [self.flip_ref_entry, self.flip_ref_button], logic=True) self.ois_flip = OptionalInputSection(self.flip_ref_cb, [self.flip_ref_entry, self.flip_ref_button], logic=True)
hlay1= QtWidgets.QHBoxLayout() hlay1 = QtWidgets.QHBoxLayout()
self.transform_lay.addLayout(hlay1) self.transform_lay.addLayout(hlay1)
hlay1.addWidget(self.flip_ref_label) hlay1.addWidget(self.flip_ref_label)