- overwritten the Beta_8.995 branch with the Gerber_Editor_Upgrade branch

This commit is contained in:
Marius Stanciu
2023-05-24 18:07:05 +03:00
parent c23d0c4ed6
commit 63071a9bae
214 changed files with 22249 additions and 6251 deletions

View File

@@ -5,13 +5,16 @@
# MIT Licence #
# ##########################################################
from shapely.geometry import LineString, Point
from shapely.affinity import rotate
from appParsers.ParseDXF_Spline import spline2Polyline, normalize_2
from appParsers.ParseDXF_Spline import Vector as DxfVector
from shapely import LineString, Point, Polygon
from shapely.affinity import rotate, translate, scale
# from ezdxf.math import Vector as ezdxf_vector
from ezdxf.math import Vec3 as ezdxf_vector
from appParsers.ParseFont import *
from appParsers.ParseDXF_Spline import *
import math
import logging
log = logging.getLogger('base2')
@@ -176,7 +179,7 @@ def dxfellipse2shapely(ellipse, ellipse_segments=100):
ratio = ellipse.dxf.ratio
points_list = []
major_axis = Vector(list(major_axis))
major_axis = DxfVector(list(major_axis))
major_x = major_axis[0]
major_y = major_axis[1]
@@ -191,7 +194,7 @@ def dxfellipse2shapely(ellipse, ellipse_segments=100):
for step in range(line_seg + 1):
if direction == 'CW':
major_dim = normalize_2(major_axis)
minor_dim = normalize_2(Vector([ratio * k for k in major_axis]))
minor_dim = normalize_2(DxfVector([ratio * k for k in major_axis]))
vx = (major_dim[0] + major_dim[1]) * math.cos(angle)
vy = (minor_dim[0] - minor_dim[1]) * math.sin(angle)
x = center[0] + major_x * vx - major_y * vy
@@ -199,7 +202,7 @@ def dxfellipse2shapely(ellipse, ellipse_segments=100):
angle += step_angle
else:
major_dim = normalize_2(major_axis)
minor_dim = (Vector([ratio * k for k in major_dim]))
minor_dim = (DxfVector([ratio * k for k in major_dim]))
vx = (major_dim[0] + major_dim[1]) * math.cos(angle)
vy = (minor_dim[0] + minor_dim[1]) * math.sin(angle)
x = center[0] + major_x * vx + major_y * vy

View File

@@ -102,7 +102,7 @@ def spline2Polyline(xyz, degree, closed, segments, knots):
# equal to the order at the ends.
# c = order of the basis function
# n = the number of defining polygon vertices
# n+2 = index of x[] for the first occurence of the maximum knot vector value
# n+2 = index of x[] for the first occurrence of the maximum knot vector value
# n+order = maximum value of the knot vector -- $n + c$
# x[] = array containing the knot vector
# ------------------------------------------------------------------------------
@@ -659,167 +659,3 @@ class Vector(list):
"""@return the transverse component
(R in cylindrical coordinate system)."""
return math.sqrt(self.perp2())
# ----------------------------------------------------------------------
# Return a random 3D vector
# ----------------------------------------------------------------------
# @staticmethod
# def random():
# cosTheta = 2.0 * random.random() - 1.0
# sinTheta = math.sqrt(1.0 - cosTheta ** 2)
# phi = 2.0 * math.pi * random.random()
# return Vector(math.cos(phi) * sinTheta, math.sin(phi) * sinTheta, cosTheta)
# #===============================================================================
# # Cardinal cubic spline class
# #===============================================================================
# class CardinalSpline:
# def __init__(self, A=0.5):
# # The default matrix is the Catmull-Rom spline
# # which is equal to Cardinal matrix
# # for A = 0.5
# #
# # Note: Vasilis
# # The A parameter should be the fraction in t where
# # the second derivative is zero
# self.setMatrix(A)
#
# #-----------------------------------------------------------------------
# # Set the matrix according to Cardinal
# #-----------------------------------------------------------------------
# def setMatrix(self, A=0.5):
# self.M = []
# self.M.append([ -A, 2.-A, A-2., A ])
# self.M.append([2.*A, A-3., 3.-2.*A, -A ])
# self.M.append([ -A, 0., A, 0.])
# self.M.append([ 0., 1., 0, 0.])
#
# #-----------------------------------------------------------------------
# # Evaluate Cardinal spline at position t
# # @param P list or tuple with 4 points y positions
# # @param t [0..1] fraction of interval from points 1..2
# # @param k index of starting 4 elements in P
# # @return spline evaluation
# #-----------------------------------------------------------------------
# def __call__(self, P, t, k=1):
# T = [t*t*t, t*t, t, 1.0]
# R = [0.0]*4
# for i in range(4):
# for j in range(4):
# R[i] += T[j] * self.M[j][i]
# y = 0.0
# for i in range(4):
# y += R[i]*P[k+i-1]
#
# return y
#
# #-----------------------------------------------------------------------
# # Return the coefficients of a 3rd degree polynomial
# # f(x) = a t^3 + b t^2 + c t + d
# # @return [a, b, c, d]
# #-----------------------------------------------------------------------
# def coefficients(self, P, k=1):
# C = [0.0]*4
# for i in range(4):
# for j in range(4):
# C[i] += self.M[i][j] * P[k+j-1]
# return C
#
# #-----------------------------------------------------------------------
# # Evaluate the value of the spline using the coefficients
# #-----------------------------------------------------------------------
# def evaluate(self, C, t):
# return ((C[0]*t + C[1])*t + C[2])*t + C[3]
#
# #===============================================================================
# # Cubic spline ensuring that the first and second derivative are continuous
# # adapted from Penelope Manual Appending B.1
# # It requires all the points (xi,yi) and the assumption on how to deal
# # with the second derivative on the extremities
# # Option 1: assume zero as second derivative on both ends
# # Option 2: assume the same as the next or previous one
# #===============================================================================
# class CubicSpline:
# def __init__(self, X, Y):
# self.X = X
# self.Y = Y
# self.n = len(X)
#
# # Option #1
# s1 = 0.0 # zero based = s0
# sN = 0.0 # zero based = sN-1
#
# # Construct the tri-diagonal matrix
# A = []
# B = [0.0] * (self.n-2)
# for i in range(self.n-2):
# A.append([0.0] * (self.n-2))
#
# for i in range(1,self.n-1):
# hi = self.h(i)
# Hi = 2.0*(self.h(i-1) + hi)
# j = i-1
# A[j][j] = Hi
# if i+1<self.n-1:
# A[j][j+1] = A[j+1][j] = hi
#
# if i==1:
# B[j] = 6.*(self.d(i) - self.d(j)) - hi*s1
# elif i<self.n-2:
# B[j] = 6.*(self.d(i) - self.d(j))
# else:
# B[j] = 6.*(self.d(i) - self.d(j)) - hi*sN
#
#
# self.s = gauss(A,B)
# self.s.insert(0,s1)
# self.s.append(sN)
# # print ">> s <<"
# # pprint(self.s)
#
# #-----------------------------------------------------------------------
# def h(self, i):
# return self.X[i+1] - self.X[i]
#
# #-----------------------------------------------------------------------
# def d(self, i):
# return (self.Y[i+1] - self.Y[i]) / (self.X[i+1] - self.X[i])
#
# #-----------------------------------------------------------------------
# def coefficients(self, i):
# """return coefficients of cubic spline for interval i a*x**3+b*x**2+c*x+d"""
# hi = self.h(i)
# si = self.s[i]
# si1 = self.s[i+1]
# xi = self.X[i]
# xi1 = self.X[i+1]
# fi = self.Y[i]
# fi1 = self.Y[i+1]
#
# a = 1./(6.*hi)*(si*xi1**3 - si1*xi**3 + 6.*(fi*xi1 - fi1*xi)) + hi/6.*(si1*xi - si*xi1)
# b = 1./(2.*hi)*(si1*xi**2 - si*xi1**2 + 2*(fi1 - fi)) + hi/6.*(si - si1)
# c = 1./(2.*hi)*(si*xi1 - si1*xi)
# d = 1./(6.*hi)*(si1-si)
#
# return [d,c,b,a]
#
# #-----------------------------------------------------------------------
# def __call__(self, i, x):
# C = self.coefficients(i)
# return ((C[0]*x + C[1])*x + C[2])*x + C[3]
#
# #-----------------------------------------------------------------------
# # @return evaluation of cubic spline at x using coefficients C
# #-----------------------------------------------------------------------
# def evaluate(self, C, x):
# return ((C[0]*x + C[1])*x + C[2])*x + C[3]
#
# #-----------------------------------------------------------------------
# # Return evaluated derivative at x using coefficients C
# #-----------------------------------------------------------------------
# def derivative(self, C, x):
# a = 3.0*C[0] # derivative coefficients
# b = 2.0*C[1] # ... for sampling with rejection
# c = C[2]
# return (3.0*C[0]*x + 2.0*C[1])*x + C[2]
#

1628
appParsers/ParseExcellon.py Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -15,13 +15,14 @@ import os
import sys
import glob
from shapely.geometry import Polygon, MultiPolygon
from shapely import Polygon, MultiPolygon
from shapely.affinity import translate, scale
import freetype as ft
from fontTools import ttLib
import logging
import gettext
import appTranslation as fcTranslate
import builtins

View File

@@ -1,20 +1,24 @@
from PyQt6 import QtWidgets
from camlib import Geometry, arc, arc_angle, ApertureMacro, grace, flatten_shapely_geometry
from appParsers.ParseDXF import getdxfgeo
from appParsers.ParseSVG import svgparselength, getsvggeo, svgparse_viewbox
import numpy as np
import traceback
from copy import deepcopy
from shapely.ops import unary_union, linemerge
import shapely.affinity as affinity
from shapely.geometry import box as shply_box
from shapely.geometry import LinearRing, MultiLineString
from shapely import box as shply_box
from shapely import LinearRing, MultiLineString, LineString, Polygon, MultiPolygon, Point, prepare, is_prepared
from lxml import etree as ET
import ezdxf
from appParsers.ParseDXF import *
from appParsers.ParseSVG import svgparselength, getsvggeo, svgparse_viewbox
import logging
import re
import sys
import gettext
import builtins
@@ -505,6 +509,7 @@ class Gerber(Geometry):
geo_dict = {}
geo_f = LineString(path)
prepare(geo_f)
if not geo_f.is_empty:
follow_buffer.append(geo_f)
geo_dict['follow'] = geo_f
@@ -513,6 +518,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
if not geo_s.is_empty and geo_s.is_valid:
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
@@ -675,7 +681,7 @@ class Gerber(Geometry):
# ################################################################
if current_macro is None: # No macro started yet
match = self.am1_re.search(gline)
# Start macro if match, else not an AM, carry on.
# Start macro if there is a match, else not an AM, carry on.
if match:
self.app.log.debug("Starting macro. Line %d: %s" % (line_num, gline))
current_macro = match.group(1)
@@ -733,8 +739,9 @@ class Gerber(Geometry):
if not flash.is_empty:
if self.app.options['gerber_simplification']:
flash = flash.simplify(s_tol)
poly_buffer.append(flash)
prepare(flash)
poly_buffer.append(flash)
if self.is_lpc is True:
geo_dict['clear'] = flash
else:
@@ -784,6 +791,7 @@ class Gerber(Geometry):
else:
geo_dict = {}
geo_f = LineString(path)
prepare(geo_f)
if not geo_f.is_empty:
follow_buffer.append(geo_f)
geo_dict['follow'] = geo_f
@@ -793,6 +801,7 @@ class Gerber(Geometry):
geo_s = LineString(path).buffer(width / 1.999, int(self.steps_per_circle))
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
if not geo_s.is_empty:
poly_buffer.append(geo_s)
@@ -851,6 +860,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
pol = pol.simplify(s_tol)
prepare(pol)
poly_buffer.append(pol)
if self.is_lpc is True:
geo_dict['clear'] = pol
@@ -865,6 +875,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
geo_dict['clear'] = geo_s
@@ -907,6 +918,7 @@ class Gerber(Geometry):
geo_dict = {}
if geo_f:
if not geo_f.is_empty:
prepare(geo_f)
follow_buffer.append(geo_f)
geo_dict['follow'] = geo_f
if geo_s:
@@ -916,6 +928,7 @@ class Gerber(Geometry):
if not geo_s.is_valid:
print("Not valid: ", line_num)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
geo_dict['clear'] = geo_s
@@ -970,7 +983,9 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
pol = pol.simplify(s_tol)
prepare(pol)
pol_f = pol.exterior
prepare(pol_f)
if not pol_f.is_empty:
follow_buffer.append(pol_f)
geo_dict['follow'] = pol
@@ -991,9 +1006,11 @@ class Gerber(Geometry):
region_f = region_s.exterior
if not region_f.is_empty:
prepare(region_f)
follow_buffer.append(region_f)
geo_dict['follow'] = region_f
prepare(region_s)
poly_buffer.append(region_s)
if self.is_lpc is True:
@@ -1010,9 +1027,11 @@ class Gerber(Geometry):
region_f = region_s.exterior
if not region_f.is_empty:
prepare(region_f)
follow_buffer.append(region_f)
geo_dict['follow'] = region_f
prepare(region_s)
poly_buffer.append(region_s)
if self.is_lpc is True:
@@ -1107,6 +1126,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
flash = flash.simplify(s_tol)
prepare(flash)
poly_buffer.append(flash)
if self.is_lpc is True:
@@ -1136,6 +1156,7 @@ class Gerber(Geometry):
geo_dict = {}
geo_f = Point([current_x, current_y])
prepare(geo_f)
follow_buffer.append(geo_f)
geo_dict['follow'] = geo_f
@@ -1143,6 +1164,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
@@ -1240,6 +1262,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
@@ -1251,6 +1274,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
@@ -1308,6 +1332,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
@@ -1318,6 +1343,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
@@ -1339,6 +1365,7 @@ class Gerber(Geometry):
# this treats the case when we are storing geometry as paths
geo_dict = {}
geo_flash = Point([linear_x, linear_y])
prepare(geo_flash)
follow_buffer.append(geo_flash)
geo_dict['follow'] = geo_flash
@@ -1353,6 +1380,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
flash = flash.simplify(s_tol)
prepare(flash)
poly_buffer.append(flash)
if self.is_lpc is True:
@@ -1422,7 +1450,8 @@ class Gerber(Geometry):
j = 0
if quadrant_mode is None:
self.app.log.error("Found arc without preceding quadrant specification G74 or G75. (%d)" % line_num)
self.app.log.error(
"Found arc without preceding quadrant specification G74 or G75. (%d)" % line_num)
self.app.log.error(gline)
continue
@@ -1457,6 +1486,7 @@ class Gerber(Geometry):
# this treats the case when we are storing geometry as paths
geo_f = LineString(path)
if not geo_f.is_empty:
prepare(geo_f)
follow_buffer.append(geo_f)
geo_dict['follow'] = geo_f
@@ -1466,6 +1496,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
buffered = buffered.simplify(s_tol)
prepare(buffered)
poly_buffer.append(buffered)
if self.is_lpc is True:
@@ -1609,6 +1640,7 @@ class Gerber(Geometry):
# this treats the case when we are storing geometry as paths
geo_f = LineString(path)
if not geo_f.is_empty:
prepare(geo_f)
follow_buffer.append(geo_f)
geo_dict['follow'] = geo_f
@@ -1619,6 +1651,7 @@ class Gerber(Geometry):
if self.app.options['gerber_simplification']:
geo_s = geo_s.simplify(s_tol)
prepare(geo_s)
poly_buffer.append(geo_s)
if self.is_lpc is True:
@@ -1678,6 +1711,10 @@ class Gerber(Geometry):
new_poly = new_poly.buffer(0, int(self.steps_per_circle))
self.app.log.warning("Union done.")
# #########################################################################################################
prepare(new_poly)
# #########################################################################################################
if current_polarity == 'D':
self.app.inform.emit('%s' % _("Gerber processing. Applying Gerber polarity."))
if new_poly.is_valid:
@@ -1722,6 +1759,13 @@ class Gerber(Geometry):
# flatten the solid geometry
self.solid_geometry = flatten_shapely_geometry(self.solid_geometry)
# import time
# start = time.time()
# #########################################################################################################
prepare(self.solid_geometry)
# #########################################################################################################
# print(f"Time elapsed: {time.time() - start}; Is prepared? {is_prepared(self.solid_geometry)}")
if self.app.options['gerber_clean_apertures']:
# clean the Gerber file of apertures with no geometry
for apid, apvalue in list(self.tools.items()):
@@ -1762,7 +1806,7 @@ class Gerber(Geometry):
maxx = loc[0] + width / 2
miny = loc[1] - height / 2
maxy = loc[1] + height / 2
return shply_box(minx, miny, maxx, maxy)
return shply_box(minx, miny, maxx, maxy).buffer(0.0000001)
if aperture['type'] == 'O': # Obround
loc = location.coords[0]
@@ -1959,7 +2003,7 @@ class Gerber(Geometry):
self.app.log.debug("appParsers.ParseGerber.Gerber.import_svg(). Finished parsing the SVG geometry.")
if flip:
geos = [translate(scale(g, 1.0, -1.0, origin=(0, 0)), yoff=h) for g in geos]
geos = [affinity.translate(affinity.scale(g, 1.0, -1.0, origin=(0, 0)), yoff=h) for g in geos]
self.app.log.debug("appParsers.ParseGerber.Gerber.import_svg(). SVG geometry was flipped.")
# Add to object
@@ -2008,6 +2052,7 @@ class Gerber(Geometry):
}
for pol in self.solid_geometry:
prepare(pol)
new_el = {'solid': pol, 'follow': LineString(pol.exterior.coords)}
self.tools[0]['geometry'].append(new_el)
@@ -2065,6 +2110,7 @@ class Gerber(Geometry):
flat_geo = list(self.flatten_list(self.solid_geometry))
if flat_geo:
self.solid_geometry = unary_union(flat_geo)
prepare(self.solid_geometry)
self.follow_geometry = self.solid_geometry
else:
return "fail"
@@ -2529,7 +2575,7 @@ class Gerber(Geometry):
try:
if isinstance(self.solid_geometry, (MultiPolygon, MultiLineString)):
self.geo_len = len(self.solid_geometry.geoms)
else:
if isinstance(self.solid_geometry, list):
self.geo_len = len(self.solid_geometry)
except (TypeError, ValueError, RuntimeError):
self.geo_len = 1
@@ -2634,8 +2680,8 @@ class Gerber(Geometry):
geo_p = shply_box(minx, miny, maxx, maxy)
new_geo_el['solid'] = geo_p
else:
self.app.log.debug("appParsers.ParseGerber.Gerber.buffer() --> "
"ap type not supported")
self.app.log.debug(
"appParsers.ParseGerber.Gerber.buffer() --> ap type not supported")
else:
new_geo_el['solid'] = geo_el['follow'].buffer(
size/1.9999,

View File

@@ -16,9 +16,8 @@ from copy import deepcopy
import sys
from shapely.ops import unary_union
from shapely.geometry import LineString, Point
from shapely import LineString, Point
# import AppTranslation as fcTranslate
import gettext
import builtins

View File

@@ -9,7 +9,7 @@ from PyQt6 import QtCore
from appCommon.Common import GracefulException as grace
from shapely.geometry import Polygon, LineString, MultiPolygon
from shapely import Polygon, LineString, MultiPolygon
from copy import copy, deepcopy
import numpy as np

View File

@@ -24,7 +24,7 @@ from svg.path import Line, Arc, CubicBezier, QuadraticBezier, parse_path
# from svg.path.path import Move
# from svg.path.path import Close
import svg.path
from shapely.geometry import LineString, MultiLineString, Point
from shapely import LineString, MultiLineString, Point
from shapely.affinity import skew, affine_transform, rotate
import numpy as np