bspy 2.2.2__py3-none-any.whl → 3.0.1__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 +17 -16
- bspy/_spline_evaluation.py +14 -6
- bspy/_spline_fitting.py +166 -137
- bspy/_spline_intersection.py +3 -3
- bspy/_spline_operations.py +60 -46
- bspy/bspyApp.py +36 -39
- bspy/drawableSpline.py +11 -13
- bspy/spline.py +202 -69
- bspy/splineOpenGLFrame.py +24 -16
- {bspy-2.2.2.dist-info → bspy-3.0.1.dist-info}/METADATA +14 -8
- bspy-3.0.1.dist-info/RECORD +15 -0
- bspy-2.2.2.dist-info/RECORD +0 -15
- {bspy-2.2.2.dist-info → bspy-3.0.1.dist-info}/LICENSE +0 -0
- {bspy-2.2.2.dist-info → bspy-3.0.1.dist-info}/WHEEL +0 -0
- {bspy-2.2.2.dist-info → bspy-3.0.1.dist-info}/top_level.txt +0 -0
bspy/spline.py
CHANGED
|
@@ -35,16 +35,11 @@ class Spline:
|
|
|
35
35
|
coefs : array-like
|
|
36
36
|
A list of the B-spline coefficients of the spline.
|
|
37
37
|
|
|
38
|
-
accuracy : `float`, optional
|
|
39
|
-
Each spline is presumed to be an approximation of something else.
|
|
40
|
-
The `accuracy` stores the infinity norm error of the difference between
|
|
41
|
-
the given spline and that something else. Default is zero.
|
|
42
|
-
|
|
43
38
|
metadata : `dict`, optional
|
|
44
39
|
A dictionary of ancillary data to store with the spline. Default is {}.
|
|
45
40
|
"""
|
|
46
41
|
|
|
47
|
-
def __init__(self, nInd, nDep, order, nCoef, knots, coefs,
|
|
42
|
+
def __init__(self, nInd, nDep, order, nCoef, knots, coefs, metadata = {}):
|
|
48
43
|
if not(nInd >= 0): raise ValueError("nInd < 0")
|
|
49
44
|
self.nInd = int(nInd)
|
|
50
45
|
if not(nDep >= 0): raise ValueError("nDep < 0")
|
|
@@ -74,7 +69,6 @@ class Spline:
|
|
|
74
69
|
self.coefs = self.coefs.reshape((*self.nCoef[::-1], self.nDep)).T
|
|
75
70
|
else:
|
|
76
71
|
self.coefs = np.array([c.T for c in self.coefs]).reshape((self.nDep, *self.nCoef))
|
|
77
|
-
self.accuracy = accuracy
|
|
78
72
|
self.metadata = dict(metadata)
|
|
79
73
|
|
|
80
74
|
def __call__(self, *uvw, **kwargs):
|
|
@@ -82,8 +76,7 @@ class Spline:
|
|
|
82
76
|
|
|
83
77
|
def __repr__(self):
|
|
84
78
|
return f"Spline({self.nInd}, {self.nDep}, {self.order}, " + \
|
|
85
|
-
f"{self.nCoef}, {self.knots} {self.coefs}, {self.
|
|
86
|
-
f"{self.metadata})"
|
|
79
|
+
f"{self.nCoef}, {self.knots} {self.coefs}, {self.metadata})"
|
|
87
80
|
|
|
88
81
|
def __add__(self, other):
|
|
89
82
|
if isinstance(other, Spline):
|
|
@@ -305,14 +298,15 @@ class Spline:
|
|
|
305
298
|
"""
|
|
306
299
|
return bspy._spline_domain.clamp(self, left, right)
|
|
307
300
|
|
|
308
|
-
|
|
301
|
+
@staticmethod
|
|
302
|
+
def common_basis(splines, indMap = None):
|
|
309
303
|
"""
|
|
310
304
|
Align a collection of splines to a common basis, elevating the order and adding knots as needed.
|
|
311
305
|
|
|
312
306
|
Parameters
|
|
313
307
|
----------
|
|
314
308
|
splines : `iterable`
|
|
315
|
-
The collection of N
|
|
309
|
+
The collection of N splines to align.
|
|
316
310
|
|
|
317
311
|
indMap : `iterable`
|
|
318
312
|
The collection of independent variables to align. Since each spline can have multiple
|
|
@@ -321,6 +315,7 @@ class Spline:
|
|
|
321
315
|
The domains of mapped independent variables must match.
|
|
322
316
|
An independent variable can map to no more than one other independent variable.
|
|
323
317
|
If all the splines are curves (1 independent variable), then `indMap` is ((0, 0, .. 0),).
|
|
318
|
+
If indMap is None (the default), then it is set to [N * [i] for i in range(nInd)]
|
|
324
319
|
|
|
325
320
|
Returns
|
|
326
321
|
-------
|
|
@@ -335,7 +330,47 @@ class Spline:
|
|
|
335
330
|
-----
|
|
336
331
|
Uses `elevate_and_insert_knots` to ensure mapped variables share the same order and knots.
|
|
337
332
|
"""
|
|
338
|
-
return bspy._spline_domain.common_basis(
|
|
333
|
+
return bspy._spline_domain.common_basis(splines, indMap)
|
|
334
|
+
|
|
335
|
+
@staticmethod
|
|
336
|
+
def cone(radius1, radius2, height, tolerance = None):
|
|
337
|
+
"""
|
|
338
|
+
Construct a cone of the two given radii and height.
|
|
339
|
+
|
|
340
|
+
Parameters
|
|
341
|
+
----------
|
|
342
|
+
radius1 : scalar
|
|
343
|
+
The desired radius of the cone at the bottom
|
|
344
|
+
|
|
345
|
+
radius2 : scalar
|
|
346
|
+
The desired radius of the cone at the top
|
|
347
|
+
|
|
348
|
+
height : scalar
|
|
349
|
+
The desired height of the cone
|
|
350
|
+
|
|
351
|
+
tolerance : scalar, optional
|
|
352
|
+
The desired absolute tolerance to which the cylinder should be constructed. Defaults
|
|
353
|
+
to 1.0e-12 if tolerance == None.
|
|
354
|
+
|
|
355
|
+
Returns
|
|
356
|
+
-------
|
|
357
|
+
spline : `Spline`
|
|
358
|
+
A bi-quartic spline approximation to a cone of the specified radii and height,
|
|
359
|
+
accurate to the given tolerance.
|
|
360
|
+
|
|
361
|
+
Notes
|
|
362
|
+
-----
|
|
363
|
+
The resulting mapping is defined over the unit square. The first independent variable
|
|
364
|
+
corresponds to the radial position on the cone, while the second independent variable
|
|
365
|
+
is the location along the height.
|
|
366
|
+
|
|
367
|
+
See Also
|
|
368
|
+
--------
|
|
369
|
+
`circular_arc` : Create a 2D circular arc for a given radius and angle accurate to within
|
|
370
|
+
a given tolerance.
|
|
371
|
+
`ruled_surface` : Construct a ruled surface between two curves.
|
|
372
|
+
"""
|
|
373
|
+
return bspy._spline_fitting.cone(radius1, radius2, height, tolerance)
|
|
339
374
|
|
|
340
375
|
def confine(self, range_bounds):
|
|
341
376
|
"""
|
|
@@ -390,8 +425,7 @@ class Spline:
|
|
|
390
425
|
|
|
391
426
|
epsilon : `float`, optional
|
|
392
427
|
Tolerance for contour precision. Evaluating `F` with contour values will be within epsilon
|
|
393
|
-
of zero. The default is square root of machine epsilon.
|
|
394
|
-
is returned as `spline.accuracy`.
|
|
428
|
+
of zero. The default is square root of machine epsilon.
|
|
395
429
|
|
|
396
430
|
metadata : `dict`, optional
|
|
397
431
|
A dictionary of ancillary data to store with the spline. Default is {}.
|
|
@@ -517,7 +551,7 @@ class Spline:
|
|
|
517
551
|
spline : `Spline`
|
|
518
552
|
The spline copy.
|
|
519
553
|
"""
|
|
520
|
-
return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, self.coefs,
|
|
554
|
+
return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, self.coefs, metadata)
|
|
521
555
|
|
|
522
556
|
def cross(self, vector):
|
|
523
557
|
"""
|
|
@@ -560,6 +594,43 @@ class Spline:
|
|
|
560
594
|
"""
|
|
561
595
|
return bspy._spline_evaluation.curvature(self, uvw)
|
|
562
596
|
|
|
597
|
+
@staticmethod
|
|
598
|
+
def cylinder(radius, height, tolerance = None):
|
|
599
|
+
"""
|
|
600
|
+
Construct a cylinder of the given radius and height.
|
|
601
|
+
|
|
602
|
+
Parameters
|
|
603
|
+
----------
|
|
604
|
+
radius : scalar
|
|
605
|
+
The desired radius of the cylinder
|
|
606
|
+
|
|
607
|
+
height : scalar
|
|
608
|
+
The desired height of the cylinder
|
|
609
|
+
|
|
610
|
+
tolerance : scalar, optional
|
|
611
|
+
The desired absolute tolerance to which the cylinder should be constructed. Defaults
|
|
612
|
+
to 1.0e-12 if tolerance == None.
|
|
613
|
+
|
|
614
|
+
Returns
|
|
615
|
+
-------
|
|
616
|
+
spline : `Spline`
|
|
617
|
+
A bi-quartic spline approximation to a cylinder of the specified radius and height,
|
|
618
|
+
accurate to the given tolerance.
|
|
619
|
+
|
|
620
|
+
Notes
|
|
621
|
+
-----
|
|
622
|
+
The resulting mapping is defined over the unit square. The first independent variable
|
|
623
|
+
corresponds to the radial position on the cylinder, while the second independent variable
|
|
624
|
+
is the location along the height.
|
|
625
|
+
|
|
626
|
+
See Also
|
|
627
|
+
--------
|
|
628
|
+
`circular_arc` : Create a 2D circular arc for a given radius and angle accurate to within
|
|
629
|
+
a given tolerance.
|
|
630
|
+
`ruled_surface` : Construct a ruled surface between two curves.
|
|
631
|
+
"""
|
|
632
|
+
return bspy._spline_fitting.cylinder(radius, height, tolerance)
|
|
633
|
+
|
|
563
634
|
def derivative(self, with_respect_to, *uvw, **kwargs):
|
|
564
635
|
"""
|
|
565
636
|
Compute the derivative of the spline at given parameter values.
|
|
@@ -597,11 +668,18 @@ class Spline:
|
|
|
597
668
|
evaluated, then the dot product of those B-splines with the vector of
|
|
598
669
|
B-spline coefficients is computed.
|
|
599
670
|
"""
|
|
600
|
-
if len(uvw)
|
|
671
|
+
if len(uvw) == 0 and self.nInd == 0:
|
|
672
|
+
return np.zeros(self.nDep, self.coefs.dtype)
|
|
673
|
+
elif np.isscalar(uvw[0]):
|
|
674
|
+
return bspy._spline_evaluation.derivative(self, with_respect_to, uvw)
|
|
675
|
+
elif len(uvw) > 1 or len(uvw[0]) > self.nInd:
|
|
601
676
|
def vectorized(*uvwInstance):
|
|
602
677
|
return tuple(bspy._spline_evaluation.derivative(self, with_respect_to, uvwInstance))
|
|
603
678
|
uFunc = np.frompyfunc(vectorized, self.nInd, self.nDep)
|
|
604
|
-
|
|
679
|
+
if self.nDep > 1:
|
|
680
|
+
return tuple([a.astype(self.coefs.dtype, copy=False) for a in uFunc(*uvw, **kwargs)])
|
|
681
|
+
else:
|
|
682
|
+
return np.array([x[0] for x in uFunc(*uvw, **kwargs)], self.coefs.dtype)
|
|
605
683
|
else:
|
|
606
684
|
return bspy._spline_evaluation.derivative(self, with_respect_to, *uvw)
|
|
607
685
|
|
|
@@ -760,11 +838,16 @@ class Spline:
|
|
|
760
838
|
"""
|
|
761
839
|
if len(uvw) == 0 and self.nInd == 0:
|
|
762
840
|
return self.coefs
|
|
763
|
-
|
|
841
|
+
elif np.isscalar(uvw[0]):
|
|
842
|
+
return bspy._spline_evaluation.evaluate(self, uvw)
|
|
843
|
+
elif len(uvw) > 1 or len(uvw[0]) > self.nInd:
|
|
764
844
|
def vectorized(*uvwInstance):
|
|
765
845
|
return tuple(bspy._spline_evaluation.evaluate(self, uvwInstance))
|
|
766
846
|
uFunc = np.frompyfunc(vectorized, self.nInd, self.nDep)
|
|
767
|
-
|
|
847
|
+
if self.nDep > 1:
|
|
848
|
+
return tuple([a.astype(self.coefs.dtype, copy=False) for a in uFunc(*uvw, **kwargs)])
|
|
849
|
+
else:
|
|
850
|
+
return np.array([x[0] for x in uFunc(*uvw, **kwargs)], self.coefs.dtype)
|
|
768
851
|
else:
|
|
769
852
|
return bspy._spline_evaluation.evaluate(self, *uvw)
|
|
770
853
|
|
|
@@ -1091,41 +1174,72 @@ class Spline:
|
|
|
1091
1174
|
return bspy._spline_domain.join(splineList)
|
|
1092
1175
|
|
|
1093
1176
|
@staticmethod
|
|
1094
|
-
def least_squares(
|
|
1177
|
+
def least_squares(uValues, dataPoints, order = None, knots = None, compression = 0.0,
|
|
1178
|
+
tolerance = None, fixEnds = False, metadata = {}):
|
|
1095
1179
|
"""
|
|
1096
1180
|
Fit a spline to an array of data points using the method of least squares.
|
|
1097
1181
|
|
|
1098
1182
|
Parameters
|
|
1099
1183
|
----------
|
|
1100
|
-
|
|
1101
|
-
The
|
|
1184
|
+
uValues : `iterable` of array-like values
|
|
1185
|
+
The values of the independent variables in each of the coordinate directions for
|
|
1186
|
+
each of the data points. It's either a simple array of length nU or it is an array
|
|
1187
|
+
of length nInd of arrays with corresponding lengths nU, nV, . . ., nW, where each
|
|
1188
|
+
length indicates the number of data points in that independent variable. For each
|
|
1189
|
+
independent variable, the values must be ordered, i.e. uValue[i] <= uValue[i+1]. The
|
|
1190
|
+
corresponding point in dataPoints will be an array of length nDep which represents the
|
|
1191
|
+
desired function values at that point. If the values in uValues are repeated, then
|
|
1192
|
+
the corresponding data in dataPoints represents a derivative value. Examples:
|
|
1193
|
+
|
|
1194
|
+
If uValues == [0.0, 1.0, 1.0, 2.0, 3.0, 3.0, 3.0], then nInd == 1 and dataPoints
|
|
1195
|
+
contains
|
|
1196
|
+
[f(0.0), f(1.0), f'(1.0), f(2.0), f(3.0), f'(3.0), f''(3.0)]
|
|
1102
1197
|
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
use `[4] * nInd` (a cubic spline).
|
|
1198
|
+
if uValues == [[0.0, 1.0, 1.0, 2.0], [0.0, 1.0, 2.0, 2.0, 3.0]], then nInd == 2 and
|
|
1199
|
+
dataPoints contains
|
|
1200
|
+
[[f(0,0), f(0,1), f(0,2), f_v(0,2), f(0,3)],
|
|
1201
|
+
[f(1,0), f(1,1), f(1,2), f_v(1,2), f(1,3)],
|
|
1202
|
+
[f_u(1,0), f_u(1,1), f_u(1,2), f_uv(1,2), f_u(1,3)],
|
|
1203
|
+
[f(2,0), f(2,1), f(2,2), f_v(2,2), f(2,3)]]
|
|
1110
1204
|
|
|
1111
1205
|
dataPoints : `iterable` of array-like values
|
|
1112
|
-
A collection of data points.
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1206
|
+
A collection of data points. The shape of this array mirrors the shape of
|
|
1207
|
+
Spline.coefs, i.e. it has shape (nDep, nU, nV, . . . , nW). The indices into this
|
|
1208
|
+
array also index into uValues to retrieve the independent variable values.
|
|
1209
|
+
For example, if nInd == 2 and nDep == 3, then the shape of dataPoints is (3, nU, nV)
|
|
1210
|
+
and dataPoint[:,i,j] has independent variable values given by uValues[0,i] and
|
|
1211
|
+
uValues[1,j].
|
|
1212
|
+
|
|
1213
|
+
order : `tuple`
|
|
1214
|
+
A tuple of length nInd where each integer entry represents the
|
|
1215
|
+
polynomial order of the spline in that variable. If order == None, then
|
|
1216
|
+
order == [4] * nInd is assumed.
|
|
1119
1217
|
|
|
1120
1218
|
knots : `list`, optional
|
|
1121
|
-
A list of the lists of the knots of the spline in each independent variable.
|
|
1122
|
-
|
|
1219
|
+
A list of the lists of the knots of the spline in each independent variable. The
|
|
1220
|
+
length of knots should be nInd if it is specified, where each of the arrays specify
|
|
1221
|
+
the knots of the spline to use in that independent variable. All of the dataPoints
|
|
1222
|
+
must lie within the domain specified by the knots. If knots == None (the default),
|
|
1223
|
+
then the knots are automatically determined.
|
|
1224
|
+
|
|
1225
|
+
compression : scalar, optional
|
|
1226
|
+
The desired compression of data used as a fraction of the number of data points, i.e
|
|
1227
|
+
compression is a number between 0 and 1. This fraction is used to determine the
|
|
1228
|
+
total number of spline coefficients when knots are chosen automatically (it's if the
|
|
1229
|
+
knots are specified). The actual compression will be slightly less because the number
|
|
1230
|
+
of coefficients is rounded up. The default value is zero (interpolation, no compression).
|
|
1231
|
+
|
|
1232
|
+
tolerance : scalar, optional
|
|
1233
|
+
If tolerance is specified, then a fit to tolerance is performed. Using the given knots
|
|
1234
|
+
as the initial set of knots, additional knots are inserted until the 2-norm of the
|
|
1235
|
+
difference between each of the each given dataPoints and the vector given by the
|
|
1236
|
+
spline is no larger than the specified tolerance.
|
|
1123
1237
|
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1238
|
+
fixEnds : Boolean, optional
|
|
1239
|
+
if fixEnds is True, then all of the dataPoints which lie on any of the domain
|
|
1240
|
+
boundaries of the spline become interpolation conditions, i.e. the spline will be
|
|
1241
|
+
fit in such a way that those boundary points are exactly satisfied by the computed
|
|
1242
|
+
spline. Otherwise, least-squares fitting will be performed on all of the dataPoints.
|
|
1129
1243
|
|
|
1130
1244
|
metadata : `dict`, optional
|
|
1131
1245
|
A dictionary of ancillary data to store with the spline. Default is {}.
|
|
@@ -1137,12 +1251,10 @@ class Spline:
|
|
|
1137
1251
|
|
|
1138
1252
|
Notes
|
|
1139
1253
|
-----
|
|
1140
|
-
Uses `numpy.linalg.lstsq` to compute the least squares solution.
|
|
1141
|
-
from the sum of the residual across dependent variables and the system epsilon.
|
|
1142
|
-
The algorithm to choose knots automatically is from Piegl, Les A., and Wayne Tiller.
|
|
1143
|
-
"Surface approximation to scanned data." The visual computer 16 (2000): 386-395.
|
|
1254
|
+
Uses `numpy.linalg.lstsq` to compute the least squares solution.
|
|
1144
1255
|
"""
|
|
1145
|
-
return bspy._spline_fitting.least_squares(
|
|
1256
|
+
return bspy._spline_fitting.least_squares(uValues, dataPoints, order, knots, compression,
|
|
1257
|
+
tolerance, fixEnds, metadata)
|
|
1146
1258
|
|
|
1147
1259
|
@staticmethod
|
|
1148
1260
|
def line(startPoint, endPoint):
|
|
@@ -1175,7 +1287,7 @@ class Spline:
|
|
|
1175
1287
|
@staticmethod
|
|
1176
1288
|
def load(fileName):
|
|
1177
1289
|
"""
|
|
1178
|
-
Load
|
|
1290
|
+
Load splines in json format from the specified filename (full path).
|
|
1179
1291
|
|
|
1180
1292
|
Parameters
|
|
1181
1293
|
----------
|
|
@@ -1184,8 +1296,8 @@ class Spline:
|
|
|
1184
1296
|
|
|
1185
1297
|
Returns
|
|
1186
1298
|
-------
|
|
1187
|
-
|
|
1188
|
-
The loaded
|
|
1299
|
+
splines : list of `Spline`
|
|
1300
|
+
The loaded splines.
|
|
1189
1301
|
|
|
1190
1302
|
See Also
|
|
1191
1303
|
--------
|
|
@@ -1200,7 +1312,7 @@ class Spline:
|
|
|
1200
1312
|
for i in range(nInd):
|
|
1201
1313
|
knots.append(kw[f"knots{i}"])
|
|
1202
1314
|
coefficients = kw["coefficients"]
|
|
1203
|
-
return Spline(nInd, coefficients.shape[0], order, coefficients.shape[1:], knots, coefficients, metadata=dict(Path=path, Name=path.splitext(path.split(fileName)[1])[0]))
|
|
1315
|
+
return [Spline(nInd, coefficients.shape[0], order, coefficients.shape[1:], knots, coefficients, metadata=dict(Path=path, Name=path.splitext(path.split(fileName)[1])[0]))]
|
|
1204
1316
|
except:
|
|
1205
1317
|
pass # Do nothing, an error is expected for json files
|
|
1206
1318
|
|
|
@@ -1208,15 +1320,13 @@ class Spline:
|
|
|
1208
1320
|
with open(fileName, 'r', encoding='utf-8') as file:
|
|
1209
1321
|
splineData = json.load(file)
|
|
1210
1322
|
|
|
1323
|
+
splines = []
|
|
1211
1324
|
if isinstance(splineData, dict):
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
splines.append(Spline(splineDict["nInd"], splineDict["nDep"], splineDict["order"], splineDict["nCoef"],
|
|
1218
|
-
[np.array(knots) for knots in splineDict["knots"]], np.array(splineDict["coefs"]), splineDict["accuracy"], splineDict["metadata"]))
|
|
1219
|
-
return splines
|
|
1325
|
+
splineData = [splineData]
|
|
1326
|
+
for splineDict in splineData:
|
|
1327
|
+
splines.append(Spline(splineDict["nInd"], splineDict["nDep"], splineDict["order"], splineDict["nCoef"],
|
|
1328
|
+
[np.array(knots) for knots in splineDict["knots"]], np.array(splineDict["coefs"]), splineDict["metadata"]))
|
|
1329
|
+
return splines
|
|
1220
1330
|
|
|
1221
1331
|
def multiply(self, other, indMap = None, productType = 'S'):
|
|
1222
1332
|
"""
|
|
@@ -1479,6 +1589,34 @@ class Spline:
|
|
|
1479
1589
|
"""
|
|
1480
1590
|
return bspy._spline_fitting.revolve(self, angle)
|
|
1481
1591
|
|
|
1592
|
+
def rotate(self, vector, angle):
|
|
1593
|
+
"""
|
|
1594
|
+
Rotate a spline around a vector by the specified angle.
|
|
1595
|
+
|
|
1596
|
+
Parameters
|
|
1597
|
+
----------
|
|
1598
|
+
vector : array-like
|
|
1599
|
+
A vector of length three about which to rotate the spline
|
|
1600
|
+
|
|
1601
|
+
angle : scalar
|
|
1602
|
+
The number of degrees to rotate the spline around vector by
|
|
1603
|
+
|
|
1604
|
+
Returns
|
|
1605
|
+
-------
|
|
1606
|
+
spline : `Spline`
|
|
1607
|
+
The rotated spline
|
|
1608
|
+
|
|
1609
|
+
See Also
|
|
1610
|
+
--------
|
|
1611
|
+
`transform` : Multiply a spline by a given matrix.
|
|
1612
|
+
|
|
1613
|
+
Notes
|
|
1614
|
+
-----
|
|
1615
|
+
Uses the well-known Rodrigues' rotation formula and mathematical operations
|
|
1616
|
+
on splines.
|
|
1617
|
+
"""
|
|
1618
|
+
return bspy._spline_operations.rotate(self, vector, angle)
|
|
1619
|
+
|
|
1482
1620
|
@staticmethod
|
|
1483
1621
|
def ruled_surface(spline1, spline2):
|
|
1484
1622
|
"""
|
|
@@ -1513,7 +1651,7 @@ class Spline:
|
|
|
1513
1651
|
|
|
1514
1652
|
See Also
|
|
1515
1653
|
--------
|
|
1516
|
-
`load` : Load
|
|
1654
|
+
`load` : Load splines in json format from the specified filename (full path).
|
|
1517
1655
|
"""
|
|
1518
1656
|
class SplineEncoder(json.JSONEncoder):
|
|
1519
1657
|
def default(self, obj):
|
|
@@ -1527,7 +1665,6 @@ class Spline:
|
|
|
1527
1665
|
"nCoef" : obj.nCoef,
|
|
1528
1666
|
"knots" : obj.knots,
|
|
1529
1667
|
"coefs" : obj.coefs,
|
|
1530
|
-
"accuracy" : obj.accuracy,
|
|
1531
1668
|
"metadata" : obj.metadata
|
|
1532
1669
|
}
|
|
1533
1670
|
return super().default(obj)
|
|
@@ -1708,7 +1845,7 @@ class Spline:
|
|
|
1708
1845
|
"""
|
|
1709
1846
|
return bspy._spline_fitting.torus(innerRadius, outerRadius, tolerance)
|
|
1710
1847
|
|
|
1711
|
-
def transform(self, matrix
|
|
1848
|
+
def transform(self, matrix):
|
|
1712
1849
|
"""
|
|
1713
1850
|
Transform a spline by the given matrix.
|
|
1714
1851
|
|
|
@@ -1717,10 +1854,6 @@ class Spline:
|
|
|
1717
1854
|
matrix : array-like
|
|
1718
1855
|
An array of size `newNDep`x`nDep` that specifies the transform matrix.
|
|
1719
1856
|
|
|
1720
|
-
maxSingularValue : `float`, optional
|
|
1721
|
-
The largest singular value of `matrix`, used to update the accuracy of the spline.
|
|
1722
|
-
If no value is provided (default), the largest singular value is computed.
|
|
1723
|
-
|
|
1724
1857
|
Returns
|
|
1725
1858
|
-------
|
|
1726
1859
|
spline : `Spline`
|
|
@@ -1735,7 +1868,7 @@ class Spline:
|
|
|
1735
1868
|
-----
|
|
1736
1869
|
Equivalent to spline @ matrix.
|
|
1737
1870
|
"""
|
|
1738
|
-
return bspy._spline_operations.transform(self, matrix
|
|
1871
|
+
return bspy._spline_operations.transform(self, matrix)
|
|
1739
1872
|
|
|
1740
1873
|
def translate(self, translationVector):
|
|
1741
1874
|
"""
|
|
@@ -1855,7 +1988,7 @@ class Spline:
|
|
|
1855
1988
|
----------
|
|
1856
1989
|
epsilon : `float`, optional
|
|
1857
1990
|
Tolerance for root precision. The root will be within epsilon of the actual root.
|
|
1858
|
-
The default is the
|
|
1991
|
+
The default is the machine epsilon.
|
|
1859
1992
|
|
|
1860
1993
|
Returns
|
|
1861
1994
|
-------
|
bspy/splineOpenGLFrame.py
CHANGED
|
@@ -2,13 +2,16 @@ import numpy as np
|
|
|
2
2
|
import tkinter as tk
|
|
3
3
|
from OpenGL.GL import *
|
|
4
4
|
import OpenGL.GL.shaders as shaders
|
|
5
|
-
|
|
5
|
+
try:
|
|
6
|
+
from pyopengltk import OpenGLFrame
|
|
7
|
+
except ImportError:
|
|
8
|
+
from tkinter import Frame as OpenGLFrame
|
|
6
9
|
from bspy import DrawableSpline
|
|
7
10
|
from bspy.drawableSpline import _set_color
|
|
8
11
|
|
|
9
12
|
class SplineOpenGLFrame(OpenGLFrame):
|
|
10
13
|
"""
|
|
11
|
-
A tkinter `OpenGLFrame` with shaders to display a `DrawableSpline
|
|
14
|
+
A tkinter `OpenGLFrame` with shaders to display a `DrawableSpline`.
|
|
12
15
|
"""
|
|
13
16
|
|
|
14
17
|
ROTATE = 1
|
|
@@ -939,10 +942,10 @@ class SplineOpenGLFrame(OpenGLFrame):
|
|
|
939
942
|
}
|
|
940
943
|
"""
|
|
941
944
|
|
|
942
|
-
def __init__(self, *args, eye=(0.0, 0.0, 3.0), center=(0.0, 0.0, 0.0), up=(0.0, 1.0, 0.0), **kw):
|
|
945
|
+
def __init__(self, *args, eye=(0.0, 0.0, 3.0), center=(0.0, 0.0, 0.0), up=(0.0, 1.0, 0.0), draw_func=None, **kw):
|
|
943
946
|
OpenGLFrame.__init__(self, *args, **kw)
|
|
944
947
|
|
|
945
|
-
self.
|
|
948
|
+
self.draw_func = draw_func
|
|
946
949
|
self.animating = False
|
|
947
950
|
self.animate = 0 # Set to number of milliseconds before showing next frame (0 means no animation)
|
|
948
951
|
self.frameCount = 0
|
|
@@ -994,12 +997,6 @@ class SplineOpenGLFrame(OpenGLFrame):
|
|
|
994
997
|
self.backgroundColor = _set_color(r, g, b, a)
|
|
995
998
|
if self.glInitialized:
|
|
996
999
|
glClearColor(self.backgroundColor[0], self.backgroundColor[1], self.backgroundColor[2], self.backgroundColor[3])
|
|
997
|
-
|
|
998
|
-
def SetSplineList(self, list):
|
|
999
|
-
"""
|
|
1000
|
-
Set the `DrawableSpline` list which determines the splines to display.
|
|
1001
|
-
"""
|
|
1002
|
-
self.splineDrawList = list
|
|
1003
1000
|
|
|
1004
1001
|
def ResetView(self):
|
|
1005
1002
|
"""
|
|
@@ -1174,8 +1171,8 @@ class SplineOpenGLFrame(OpenGLFrame):
|
|
|
1174
1171
|
(self.horizon[2], self.vertical[2], self.look[2], 0.0),
|
|
1175
1172
|
(-np.dot(self.horizon, self.eye), -np.dot(self.vertical, self.eye), -np.dot(self.look, self.eye), 1.0)), np.float32)
|
|
1176
1173
|
|
|
1177
|
-
|
|
1178
|
-
|
|
1174
|
+
if self.draw_func is not None:
|
|
1175
|
+
self.draw_func(self, transform)
|
|
1179
1176
|
|
|
1180
1177
|
glFlush()
|
|
1181
1178
|
|
|
@@ -1192,7 +1189,10 @@ class SplineOpenGLFrame(OpenGLFrame):
|
|
|
1192
1189
|
"""
|
|
1193
1190
|
Update the frame, typically after updating the spline list.
|
|
1194
1191
|
"""
|
|
1195
|
-
|
|
1192
|
+
try:
|
|
1193
|
+
self.tkExpose(None)
|
|
1194
|
+
except AttributeError:
|
|
1195
|
+
pass
|
|
1196
1196
|
|
|
1197
1197
|
def Reset(self):
|
|
1198
1198
|
"""
|
|
@@ -1216,14 +1216,22 @@ class SplineOpenGLFrame(OpenGLFrame):
|
|
|
1216
1216
|
|
|
1217
1217
|
def SetScale(self, scale):
|
|
1218
1218
|
"""
|
|
1219
|
-
Set
|
|
1219
|
+
Set anchor distance and/or flying speed (depending on mode).
|
|
1220
1220
|
|
|
1221
1221
|
Parameters
|
|
1222
1222
|
----------
|
|
1223
1223
|
scale : `float`
|
|
1224
|
-
|
|
1224
|
+
Scale between 0 and 1.
|
|
1225
1225
|
"""
|
|
1226
|
-
self.
|
|
1226
|
+
if self.mode == self.FLY:
|
|
1227
|
+
self.speed = 0.033 * self.anchorDistance * (100.0 ** float(scale) - 1.0) / 99.0
|
|
1228
|
+
else:
|
|
1229
|
+
defaultAnchorDistance = np.linalg.norm(self.defaultEye - self.defaultCenter)
|
|
1230
|
+
self.anchorDistance = 2.0 * float(scale) * defaultAnchorDistance
|
|
1231
|
+
self.anchorDistance = max(self.anchorDistance, 0.01)
|
|
1232
|
+
self.speed = 0.033 * self.anchorDistance
|
|
1233
|
+
self.eye = self.anchorPosition + self.anchorDistance * self.look
|
|
1234
|
+
self.Update()
|
|
1227
1235
|
|
|
1228
1236
|
def SetAnimating(self, animating):
|
|
1229
1237
|
self.animating = animating
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: bspy
|
|
3
|
-
Version:
|
|
4
|
-
Summary: Library for manipulating and rendering non-uniform
|
|
3
|
+
Version: 3.0.1
|
|
4
|
+
Summary: Library for manipulating and rendering non-uniform B-splines
|
|
5
5
|
Home-page: http://github.com/ericbrec/BSpy
|
|
6
6
|
Author: Eric Brechner
|
|
7
7
|
Author-email: ericbrec@msn.com
|
|
@@ -32,12 +32,12 @@ Requires-Dist: pyopengltk
|
|
|
32
32
|
Library for manipulating and rendering B-spline curves, surfaces, and multidimensional manifolds with non-uniform knots in each dimension.
|
|
33
33
|
|
|
34
34
|
The [Spline](https://ericbrec.github.io/BSpy/bspy/spline.html) class has a method to fit multidimensional data for
|
|
35
|
-
scalar and vector functions of single and multiple variables. It also has methods to create points, lines, circular arcs, spheres, tori, ruled surfaces, surfaces of revolution, and four-sided patches.
|
|
36
|
-
Other methods add, subtract,
|
|
37
|
-
There are methods to evaluate spline values, derivatives, integrals, normals, curvature, and the Jacobian, as well as methods that return spline representations of derivatives, normals, integrals, graphs, and convolutions. In addition, there are methods to manipulate the domain of splines, including trim, join, reparametrize, transpose, reverse, add and remove knots, elevate and extrapolate, and fold and unfold. Finally, there are methods to compute the zeros and contours of a spline and to intersect two splines.
|
|
35
|
+
scalar and vector functions of single and multiple variables. It also has methods to create points, lines, circular arcs, spheres, cones, cylinders, tori, ruled surfaces, surfaces of revolution, and four-sided patches.
|
|
36
|
+
Other methods add, subtract, and multiply splines, as well as confine spline curves to a given range.
|
|
37
|
+
There are methods to evaluate spline values, derivatives, integrals, normals, curvature, and the Jacobian, as well as methods that return spline representations of derivatives, normals, integrals, graphs, and convolutions. In addition, there are methods to manipulate the domain of splines, including trim, join, reparametrize, transpose, reverse, add and remove knots, elevate and extrapolate, and fold and unfold. There are methods to manipulate the range of splines, including dot product, cross product, translate, rotate, scale, and transform. Finally, there are methods to compute the zeros and contours of a spline and to intersect two splines.
|
|
38
38
|
|
|
39
39
|
The [SplineOpenGLFrame](https://ericbrec.github.io/BSpy/bspy/splineOpenGLFrame.html) class is an
|
|
40
|
-
[OpenGLFrame](https://pypi.org/project/pyopengltk/) with custom shaders to render spline curves and surfaces.
|
|
40
|
+
[OpenGLFrame](https://pypi.org/project/pyopengltk/) with custom shaders to render spline curves and surfaces. Only tested on Windows systems.
|
|
41
41
|
|
|
42
42
|
The [DrawableSpline](https://ericbrec.github.io/BSpy/bspy/drawableSpline.html) class converts a
|
|
43
43
|
[Spline](https://ericbrec.github.io/BSpy/bspy/spline.html) to a curve, surface, or solid that can be drawn in a
|
|
@@ -48,14 +48,20 @@ Spline surfaces and solids with more than 3 dependent variables will have their
|
|
|
48
48
|
The [bspyApp](https://ericbrec.github.io/BSpy/bspy/bspyApp.html) class is a
|
|
49
49
|
[tkinter.Tk](https://docs.python.org/3/library/tkinter.html) app that hosts a
|
|
50
50
|
[SplineOpenGLFrame](https://ericbrec.github.io/BSpy/bspy/splineOpenGLFrame.html),
|
|
51
|
-
a listbox full of splines, and a set of controls to adjust and view the selected splines.
|
|
51
|
+
a listbox full of splines, and a set of controls to adjust and view the selected splines. Only tested on Windows systems.
|
|
52
52
|
|
|
53
53
|
The [bspyGraphics](https://ericbrec.github.io/BSpy/bspy/bspyApp.html#bspyGraphics) class is a graphics engine to display splines.
|
|
54
54
|
It launches a [bspyApp](https://ericbrec.github.io/BSpy/bspy/bspyApp.html) and issues commands to the app for use
|
|
55
|
-
in [jupyter](https://jupyter.org/) notebooks and other scripting environments.
|
|
55
|
+
in [jupyter](https://jupyter.org/) notebooks and other scripting environments. Only tested on Windows systems.
|
|
56
56
|
|
|
57
57
|

|
|
58
58
|
|
|
59
59
|
The full documentation for BSpy can be found [here](https://ericbrec.github.io/BSpy), its GitHub project can be found
|
|
60
60
|
[here](https://github.com/ericbrec/BSpy), a test suite can be found [here](https://github.com/ericbrec/BSpy/tree/main/tests), and
|
|
61
61
|
a set of examples, including a jupyter notebook, can be found [here](https://github.com/ericbrec/BSpy/tree/main/examples).
|
|
62
|
+
|
|
63
|
+
### Release 3.0 breaking changes
|
|
64
|
+
* Removed accuracy as a member of Spline
|
|
65
|
+
* Spline.common_basis is now a static method (see documentation for details)
|
|
66
|
+
* Spline.least_squares changed arguments (see documentation for details)
|
|
67
|
+
* Spline.load always returns a list of splines
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
bspy/__init__.py,sha256=6COMVL3vEPGglirXvBWB9vadEMhj0tetOj7134im5wY,851
|
|
2
|
+
bspy/_spline_domain.py,sha256=rES03UdvxB6yu_ccumcckLR0xX51C6Dv_-nK0wuTlGg,28689
|
|
3
|
+
bspy/_spline_evaluation.py,sha256=rZLqruff8BT6MZdlfV5MBFzSnYuJgzgbpxk1W0mRHeI,7892
|
|
4
|
+
bspy/_spline_fitting.py,sha256=P6rwnIdjjrC_tKqWgIIh5OHl48z04MJBT0QMh18Dvyk,31797
|
|
5
|
+
bspy/_spline_intersection.py,sha256=ArdRkYMUc4JWRuj0CfhdGSWyBs_SBDnbvZtwb5Elo4U,40865
|
|
6
|
+
bspy/_spline_operations.py,sha256=eHSRSd7ez6WrjtM-YlvKjn-LRcaRSObIdf9b8eV1chE,42898
|
|
7
|
+
bspy/bspyApp.py,sha256=M7Uc3TL6GcuqwdWeTdQTH79yKdQ_eHD16ed3xWJipIg,18746
|
|
8
|
+
bspy/drawableSpline.py,sha256=tM54Tk11qwGextRDCCkMn-NJUFp_XtlPkUK9X4Xxyyo,25076
|
|
9
|
+
bspy/spline.py,sha256=clO9hxqrjImWDGW7dkDu_vqUGgLEKi5tYKlEVkM044A,84589
|
|
10
|
+
bspy/splineOpenGLFrame.py,sha256=Fns8QjTiVX7jyolhwpty6RqoUE9RtPs8pHkDi1SlwFg,64643
|
|
11
|
+
bspy-3.0.1.dist-info/LICENSE,sha256=nLfJULN68Jw6GfCJp4xeMksGuRdyWNdgEsZGjw2twig,1091
|
|
12
|
+
bspy-3.0.1.dist-info/METADATA,sha256=gEk1OHK15MToVxRcDTeB_4igZzkBo5O39_9pAODUKo8,4688
|
|
13
|
+
bspy-3.0.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
14
|
+
bspy-3.0.1.dist-info/top_level.txt,sha256=fotZnJn6aCwgUbBEV3hslIko7Nw-eqtHLq2eyJLlFsY,5
|
|
15
|
+
bspy-3.0.1.dist-info/RECORD,,
|
bspy-2.2.2.dist-info/RECORD
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
bspy/__init__.py,sha256=XRBelbYtbhB6AWKh8DTsWVMDIteVxUm7Cf_S1fkqeEs,851
|
|
2
|
-
bspy/_spline_domain.py,sha256=EF6f6y1aMSrDf65UoqQwmBOarTO79TO-hszZAFpxeJw,28821
|
|
3
|
-
bspy/_spline_evaluation.py,sha256=1aCf4Op5zQNv-_wW2IOR13MieuYPVJrN1cJCBiI8AaY,7534
|
|
4
|
-
bspy/_spline_fitting.py,sha256=IT89LPainTWoHtzBK6s2VnWiM1c76zzZLDJmsPFlSNA,31369
|
|
5
|
-
bspy/_spline_intersection.py,sha256=gWs22hfIKqD6YZaeFWJO_3t0ohCNzVvxdiWJqVNlJMI,40934
|
|
6
|
-
bspy/_spline_operations.py,sha256=javGKxiSPomhTruJU3ojJvGASoblZnjZG8MGQ3PrOHQ,42400
|
|
7
|
-
bspy/bspyApp.py,sha256=Q_TAdKEtRgHzdbp9qj1xPq9oACQyRNnJXnGGvkiVQks,19051
|
|
8
|
-
bspy/drawableSpline.py,sha256=lLWUjrgNROJ41wtl_XwAL-2RlKdMFo5SDsT5FopI3Xk,25131
|
|
9
|
-
bspy/spline.py,sha256=RRJZRdsEE9_tSTTP980NnIUpmMYqMR4WGN2F4qZkHII,79308
|
|
10
|
-
bspy/splineOpenGLFrame.py,sha256=h-XDC-KEcjiC8pNj9cqWBjZgVDiI6mOq1jljfk6fmV4,64194
|
|
11
|
-
bspy-2.2.2.dist-info/LICENSE,sha256=nLfJULN68Jw6GfCJp4xeMksGuRdyWNdgEsZGjw2twig,1091
|
|
12
|
-
bspy-2.2.2.dist-info/METADATA,sha256=QQSRHSYTE03xFgwMLhrXguPDRpdqms-6Yy4n3wroKU4,4183
|
|
13
|
-
bspy-2.2.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
14
|
-
bspy-2.2.2.dist-info/top_level.txt,sha256=fotZnJn6aCwgUbBEV3hslIko7Nw-eqtHLq2eyJLlFsY,5
|
|
15
|
-
bspy-2.2.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|