bspy 4.2__py3-none-any.whl → 4.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bspy/__init__.py +1 -1
- bspy/_spline_domain.py +74 -92
- bspy/_spline_evaluation.py +3 -3
- bspy/_spline_fitting.py +33 -12
- bspy/_spline_intersection.py +294 -279
- bspy/_spline_milling.py +233 -0
- bspy/_spline_operations.py +98 -81
- bspy/hyperplane.py +7 -3
- bspy/manifold.py +8 -3
- bspy/solid.py +8 -4
- bspy/spline.py +124 -21
- bspy/splineOpenGLFrame.py +346 -303
- bspy/spline_block.py +155 -38
- bspy/viewer.py +20 -11
- {bspy-4.2.dist-info → bspy-4.4.dist-info}/METADATA +14 -11
- bspy-4.4.dist-info/RECORD +19 -0
- {bspy-4.2.dist-info → bspy-4.4.dist-info}/WHEEL +1 -1
- bspy-4.2.dist-info/RECORD +0 -18
- {bspy-4.2.dist-info → bspy-4.4.dist-info/licenses}/LICENSE +0 -0
- {bspy-4.2.dist-info → bspy-4.4.dist-info}/top_level.txt +0 -0
bspy/spline.py
CHANGED
|
@@ -5,8 +5,9 @@ from bspy.manifold import Manifold
|
|
|
5
5
|
import bspy.spline_block
|
|
6
6
|
import bspy._spline_domain
|
|
7
7
|
import bspy._spline_evaluation
|
|
8
|
-
import bspy._spline_intersection
|
|
9
8
|
import bspy._spline_fitting
|
|
9
|
+
import bspy._spline_intersection
|
|
10
|
+
import bspy._spline_milling
|
|
10
11
|
import bspy._spline_operations
|
|
11
12
|
|
|
12
13
|
@Manifold.register
|
|
@@ -59,8 +60,8 @@ class Spline(Manifold):
|
|
|
59
60
|
self.knots = tuple(np.array(kk) for kk in knots)
|
|
60
61
|
for knots, order, nCoef in zip(self.knots, self.order, self.nCoef):
|
|
61
62
|
for i in range(nCoef):
|
|
62
|
-
if not(knots[i] <= knots[i + 1] and knots[i]
|
|
63
|
-
raise ValueError("
|
|
63
|
+
if not(knots[i] <= knots[i + 1] and knots[i + order] - knots[i] > 0):
|
|
64
|
+
raise ValueError("Improper knot order or multiplicity")
|
|
64
65
|
totalCoefs = 1
|
|
65
66
|
for nCoef in self.nCoef:
|
|
66
67
|
totalCoefs *= nCoef
|
|
@@ -79,7 +80,7 @@ class Spline(Manifold):
|
|
|
79
80
|
|
|
80
81
|
def __repr__(self):
|
|
81
82
|
return f"Spline({self.nInd}, {self.nDep}, {self.order}, " + \
|
|
82
|
-
f"{self.nCoef}, {self.knots} {self.coefs}, {self.metadata})"
|
|
83
|
+
f"{self.nCoef}, {self.knots}, {self.coefs}, {self.metadata})"
|
|
83
84
|
|
|
84
85
|
def __add__(self, other):
|
|
85
86
|
if isinstance(other, Spline):
|
|
@@ -969,17 +970,20 @@ class Spline(Manifold):
|
|
|
969
970
|
|
|
970
971
|
f : Python function
|
|
971
972
|
The function to approximate. It is a vector-valued function of nDep
|
|
972
|
-
components in nInd variables.
|
|
973
|
+
components in nInd variables. Alternatively, it can return a spline of any
|
|
974
|
+
number independent variables and nDep dependent variables. In this case, the
|
|
975
|
+
resulting spline function will have nInd + number of independent variables
|
|
976
|
+
in the splines returned independent variables and nDep dependent variables.
|
|
973
977
|
|
|
974
|
-
order : `array-like
|
|
978
|
+
order : `array-like`, optional
|
|
975
979
|
An optional integer array of length nInd which specifies the polynomial
|
|
976
980
|
order to use in each of the independent variables. It will default to order
|
|
977
981
|
4 (degree 3) if None is specified (the default)
|
|
978
982
|
|
|
979
|
-
knots : `array-like
|
|
983
|
+
knots : `array-like`, optional
|
|
980
984
|
The initial knot sequence to use, if given
|
|
981
985
|
|
|
982
|
-
tolerance : `scalar
|
|
986
|
+
tolerance : `scalar`, optional
|
|
983
987
|
The maximum 2-norm of the difference between the given function and the
|
|
984
988
|
spline fit. Defaults to 1.0e-4.
|
|
985
989
|
|
|
@@ -1109,7 +1113,7 @@ class Spline(Manifold):
|
|
|
1109
1113
|
`to_dict` : Return a `dict` with `Spline` data.
|
|
1110
1114
|
"""
|
|
1111
1115
|
return Spline(dictionary["nInd"], dictionary["nDep"], dictionary["order"], dictionary["nCoef"],
|
|
1112
|
-
[np.array(knots) for knots in dictionary["knots"]], np.array(dictionary["coefs"]), dictionary
|
|
1116
|
+
[np.array(knots) for knots in dictionary["knots"]], np.array(dictionary["coefs"]), dictionary.get("metadata", {}))
|
|
1113
1117
|
|
|
1114
1118
|
def full_domain(self):
|
|
1115
1119
|
"""
|
|
@@ -1126,7 +1130,7 @@ class Spline(Manifold):
|
|
|
1126
1130
|
"""
|
|
1127
1131
|
return bspy._spline_intersection.full_domain(self)
|
|
1128
1132
|
|
|
1129
|
-
def geodesic(self, uvStart, uvEnd, tolerance = 1.0e-
|
|
1133
|
+
def geodesic(self, uvStart, uvEnd, tolerance = 1.0e-5):
|
|
1130
1134
|
"""
|
|
1131
1135
|
Determine a geodesic between two points on a surface
|
|
1132
1136
|
|
|
@@ -1138,9 +1142,9 @@ class Spline(Manifold):
|
|
|
1138
1142
|
uvEnd : `array-like`
|
|
1139
1143
|
The parameter values for the surface at the other end of the desired geodesic.
|
|
1140
1144
|
|
|
1141
|
-
tolerance : scalar
|
|
1145
|
+
tolerance : scalar, optional
|
|
1142
1146
|
The maximum error in parameter space to which the geodesic should get computed.
|
|
1143
|
-
Defaults to 1.0e-
|
|
1147
|
+
Defaults to 1.0e-5.
|
|
1144
1148
|
|
|
1145
1149
|
Returns
|
|
1146
1150
|
-------
|
|
@@ -1211,7 +1215,12 @@ class Spline(Manifold):
|
|
|
1211
1215
|
----------
|
|
1212
1216
|
newKnots : `iterable` of length `nInd`
|
|
1213
1217
|
An iterable that specifies the knots to be added to each independent variable's knots.
|
|
1214
|
-
len(newKnots[ind]) == 0 if no knots are to be added for the `ind` independent variable.
|
|
1218
|
+
len(newKnots[ind]) == 0 if no knots are to be added for the `ind` independent variable.
|
|
1219
|
+
|
|
1220
|
+
Each knot may be specified as its knot value or a tuple indicating the knot value and its multiplicity.
|
|
1221
|
+
For example, spline.insert_knots([[0.1, (0.3, 2)], [(.5, 3), .2, .5]]) will insert 0.1 once and 0.3 twice into
|
|
1222
|
+
the knots of the first independent variable, and will insert 0.2 once and 0.5 four times into the knots of the
|
|
1223
|
+
second independent variable. Knots do not need to be sorted.
|
|
1215
1224
|
|
|
1216
1225
|
Returns
|
|
1217
1226
|
-------
|
|
@@ -1491,6 +1500,36 @@ class Spline(Manifold):
|
|
|
1491
1500
|
"""
|
|
1492
1501
|
return bspy._spline_fitting.line(startPoint, endPoint)
|
|
1493
1502
|
|
|
1503
|
+
def line_of_curvature(self, uvStart, is_max = True, tolerance = 1.0e-3):
|
|
1504
|
+
"""
|
|
1505
|
+
Determine a line of curvature along a surface
|
|
1506
|
+
|
|
1507
|
+
Parameters
|
|
1508
|
+
----------
|
|
1509
|
+
uvStart : `array-like`
|
|
1510
|
+
The parameter values for the surface at one end of the desired line of curvature.
|
|
1511
|
+
|
|
1512
|
+
is_max : `bool`, optional
|
|
1513
|
+
Boolean value indicating that the line of curvature should be the maximal curvature line.
|
|
1514
|
+
If False, the minimal curvature line is returned. Defaults to True.
|
|
1515
|
+
|
|
1516
|
+
tolerance : scalar, optional
|
|
1517
|
+
The maximum error in parameter space to which the geodesic should get computed.
|
|
1518
|
+
Defaults to 1.0e-3.
|
|
1519
|
+
|
|
1520
|
+
Returns
|
|
1521
|
+
-------
|
|
1522
|
+
spline : `Spline`
|
|
1523
|
+
A spline curve whose range is in the domain of the given surface. The range of the
|
|
1524
|
+
curve is the locus of points whose image under the surface map form the line of curvature
|
|
1525
|
+
starting at the given point.
|
|
1526
|
+
|
|
1527
|
+
See Also
|
|
1528
|
+
--------
|
|
1529
|
+
`solve_ode` : Solve an ordinary differential equation using spline collocation.
|
|
1530
|
+
"""
|
|
1531
|
+
return bspy._spline_milling.line_of_curvature(self, uvStart, is_max, tolerance)
|
|
1532
|
+
|
|
1494
1533
|
@staticmethod
|
|
1495
1534
|
def load(fileName):
|
|
1496
1535
|
"""
|
|
@@ -1645,6 +1684,61 @@ class Spline(Manifold):
|
|
|
1645
1684
|
the matrix formed by the tangents of the spline. If the null space is greater than one dimension, the normal will be zero.
|
|
1646
1685
|
"""
|
|
1647
1686
|
return bspy._spline_operations.normal_spline(bspy.spline_block.SplineBlock(self), indices)
|
|
1687
|
+
|
|
1688
|
+
def offset(self, edgeRadius, bitRadius=None, angle=np.pi / 2.2, path=None, subtract=False, removeCusps=False, tolerance = 1.0e-4):
|
|
1689
|
+
"""
|
|
1690
|
+
Compute the offset of a spline to a given tolerance.
|
|
1691
|
+
|
|
1692
|
+
Parameters
|
|
1693
|
+
----------
|
|
1694
|
+
edgeRadius : scalar
|
|
1695
|
+
The radius of offset. If a bit radius is specified, the edge radius is the
|
|
1696
|
+
smaller radius of the cutting edge of the drill bit, whereas bit radius specifies
|
|
1697
|
+
half of the full width of the drill bit.
|
|
1698
|
+
|
|
1699
|
+
bitRadius : scalar, optional
|
|
1700
|
+
The radius of the drill bit (half its full width). For a ball nose cutter (the default),
|
|
1701
|
+
the bit radius is the same as the edge radius. For an end mill,
|
|
1702
|
+
the bit radius is larger (typically much larger) than the edge radius.
|
|
1703
|
+
|
|
1704
|
+
angle : scalar, optional
|
|
1705
|
+
The angle at which the drill bit transitions from the edge radius to the
|
|
1706
|
+
flatter bottom of the drill bit. The angle must be in the range [0, pi/2).
|
|
1707
|
+
Defaults to pi / 2.2.
|
|
1708
|
+
|
|
1709
|
+
path : `Spline`, optional
|
|
1710
|
+
The path along self that the drill bit should contact.
|
|
1711
|
+
If specified, the path must be a 2D curve in the domain of self, self must be a 3D surface,
|
|
1712
|
+
and the offset returned is a 3D curve providing the 3D position of the drill bit,
|
|
1713
|
+
rather than the full offset surface. Defaults to None.
|
|
1714
|
+
|
|
1715
|
+
subtract : boolean, optional
|
|
1716
|
+
Flag indicating if the drill bit should be subtracted from the spline instead of added.
|
|
1717
|
+
Subtracting the drill bit returns the tool path that cuts out the spline. Defaults to False.
|
|
1718
|
+
|
|
1719
|
+
removeCusps : boolean, optional
|
|
1720
|
+
Flag indicating if cusps and their associated self-intersections should be removed from the
|
|
1721
|
+
offset. Only applicable to offset curves and paths along offset surfaces. Defaults to False.
|
|
1722
|
+
|
|
1723
|
+
tolerance : `scalar`, optional
|
|
1724
|
+
The maximum 2-norm of the difference between the offset and the
|
|
1725
|
+
spline fit. Defaults to 1.0e-4.
|
|
1726
|
+
|
|
1727
|
+
Returns
|
|
1728
|
+
-------
|
|
1729
|
+
offset : `Spline`
|
|
1730
|
+
The spline that represents the offset.
|
|
1731
|
+
|
|
1732
|
+
See Also
|
|
1733
|
+
--------
|
|
1734
|
+
`fit` : Fit the function f with a spline to a given tolerance.
|
|
1735
|
+
|
|
1736
|
+
Notes
|
|
1737
|
+
-----
|
|
1738
|
+
The offset is only defined for 2D curves and 3D surfaces with well-defined normals.
|
|
1739
|
+
The bottom of the drill bit is tangent to its lowest y value.
|
|
1740
|
+
"""
|
|
1741
|
+
return bspy._spline_milling.offset(self, edgeRadius, bitRadius, angle, path, subtract, removeCusps, tolerance)
|
|
1648
1742
|
|
|
1649
1743
|
@staticmethod
|
|
1650
1744
|
def point(point):
|
|
@@ -1963,7 +2057,7 @@ class Spline(Manifold):
|
|
|
1963
2057
|
"""
|
|
1964
2058
|
return bspy._spline_fitting.section(xytk)
|
|
1965
2059
|
|
|
1966
|
-
def solve_ode(self, nLeft, nRight, FAndF_u, tolerance = 1.0e-6, args = ()):
|
|
2060
|
+
def solve_ode(self, nLeft, nRight, FAndF_u, tolerance = 1.0e-6, args = (), includeEstimate = False):
|
|
1967
2061
|
"""
|
|
1968
2062
|
Numerically solve an ordinary differential equation with boundary conditions.
|
|
1969
2063
|
|
|
@@ -1986,26 +2080,31 @@ class Spline(Manifold):
|
|
|
1986
2080
|
FAndF_u : Python function
|
|
1987
2081
|
FAndF_u must have exactly this calling sequence: FAndF_u(t, uData, *args). t is a scalar set
|
|
1988
2082
|
to the desired value of the independent variable of the ODE. uData will be a numpy matrix of shape
|
|
1989
|
-
(self.nDep, nOrder) whose columns are
|
|
2083
|
+
(self.nDep, nOrder) whose columns are u, ... , u^(nOrder - 1). It must return a numpy
|
|
1990
2084
|
vector of length self.nDep and a numpy array whose shape is (self.nDep, self.nDep, nOrder).
|
|
1991
2085
|
The first output vector is the value of the forcing function F at (t, uData). The numpy
|
|
1992
2086
|
array is the array of partial derivatives with respect to all the numbers in uData. Thus, if
|
|
1993
2087
|
this array is called jacobian, then jacobian[:, i, j] is the gradient of the forcing function with
|
|
1994
2088
|
respect to uData[i, j].
|
|
1995
2089
|
|
|
1996
|
-
tolerance : scalar
|
|
1997
|
-
The relative error to which the ODE should get solved.
|
|
2090
|
+
tolerance : scalar, optional
|
|
2091
|
+
The relative error to which the ODE should get solved. Default is 1.0e-6.
|
|
1998
2092
|
|
|
1999
|
-
args : tuple
|
|
2093
|
+
args : tuple, optional
|
|
2000
2094
|
Additional arguments to pass to the user-defined function FAndF_u. For example, if FAndF_u has the
|
|
2001
|
-
FAndF_u(t, uData, a, b, c), then args must be a tuple of length 3.
|
|
2095
|
+
FAndF_u(t, uData, a, b, c), then args must be a tuple of length 3. Default is ().
|
|
2096
|
+
|
|
2097
|
+
includeEstimate : bool, optional
|
|
2098
|
+
If `includeEstimate` is True, the uData passed to `FAndF_u` will be a numpy matrix of shape
|
|
2099
|
+
(self.nDep, nOrder + 1) whose columns are u, ... , u^(nOrder). The last column will be the most
|
|
2100
|
+
recent estimate of u^(nOrder)(t). Default is False.
|
|
2002
2101
|
|
|
2003
2102
|
Notes
|
|
2004
2103
|
=====
|
|
2005
2104
|
This method uses B-splines as finite elements. The ODE itself is discretized using
|
|
2006
2105
|
collocation.
|
|
2007
2106
|
"""
|
|
2008
|
-
return bspy._spline_fitting.solve_ode(self, nLeft, nRight, FAndF_u, tolerance, args)
|
|
2107
|
+
return bspy._spline_fitting.solve_ode(self, nLeft, nRight, FAndF_u, tolerance, args, includeEstimate)
|
|
2009
2108
|
|
|
2010
2109
|
@staticmethod
|
|
2011
2110
|
def sphere(radius, tolerance = None):
|
|
@@ -2065,7 +2164,11 @@ class Spline(Manifold):
|
|
|
2065
2164
|
--------
|
|
2066
2165
|
`join` : Join a list of splines together into a single spline.
|
|
2067
2166
|
"""
|
|
2068
|
-
|
|
2167
|
+
splineArray = bspy.spline_block.SplineBlock(self).split(minContinuity, breaks)
|
|
2168
|
+
splines = splineArray.ravel()
|
|
2169
|
+
for i, block in enumerate(splines):
|
|
2170
|
+
splines[i] = block.block[0][0][1]
|
|
2171
|
+
return splines.reshape(splineArray.shape)
|
|
2069
2172
|
|
|
2070
2173
|
def subtract(self, other, indMap = None):
|
|
2071
2174
|
"""
|