bspy 4.0__py3-none-any.whl → 4.2__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 +16 -3
- bspy/_spline_domain.py +101 -9
- bspy/_spline_evaluation.py +82 -17
- bspy/_spline_fitting.py +244 -114
- bspy/_spline_intersection.py +467 -156
- bspy/_spline_operations.py +70 -49
- bspy/hyperplane.py +540 -0
- bspy/manifold.py +334 -31
- bspy/solid.py +842 -0
- bspy/spline.py +350 -71
- bspy/splineOpenGLFrame.py +262 -14
- bspy/spline_block.py +343 -0
- bspy/viewer.py +134 -90
- {bspy-4.0.dist-info → bspy-4.2.dist-info}/METADATA +17 -6
- bspy-4.2.dist-info/RECORD +18 -0
- {bspy-4.0.dist-info → bspy-4.2.dist-info}/WHEEL +1 -1
- bspy-4.0.dist-info/RECORD +0 -15
- {bspy-4.0.dist-info → bspy-4.2.dist-info}/LICENSE +0 -0
- {bspy-4.0.dist-info → bspy-4.2.dist-info}/top_level.txt +0 -0
bspy/spline.py
CHANGED
|
@@ -2,12 +2,14 @@ import numpy as np
|
|
|
2
2
|
from os import path
|
|
3
3
|
import json
|
|
4
4
|
from bspy.manifold import Manifold
|
|
5
|
+
import bspy.spline_block
|
|
5
6
|
import bspy._spline_domain
|
|
6
7
|
import bspy._spline_evaluation
|
|
7
8
|
import bspy._spline_intersection
|
|
8
9
|
import bspy._spline_fitting
|
|
9
10
|
import bspy._spline_operations
|
|
10
11
|
|
|
12
|
+
@Manifold.register
|
|
11
13
|
class Spline(Manifold):
|
|
12
14
|
"""
|
|
13
15
|
A class to model, represent, and process piecewise polynomial tensor product
|
|
@@ -123,6 +125,9 @@ class Spline(Manifold):
|
|
|
123
125
|
else:
|
|
124
126
|
return self.scale(other)
|
|
125
127
|
|
|
128
|
+
def __neg__(self):
|
|
129
|
+
return self.scale(-1.0)
|
|
130
|
+
|
|
126
131
|
def __sub__(self, other):
|
|
127
132
|
if isinstance(other, Spline):
|
|
128
133
|
return self.subtract(other, [(ix, ix) for ix in range(min(self.nInd, other.nInd))])
|
|
@@ -313,6 +318,71 @@ class Spline(Manifold):
|
|
|
313
318
|
"""
|
|
314
319
|
return bspy._spline_domain.common_basis(splines, indMap)
|
|
315
320
|
|
|
321
|
+
def complete_slice(self, slice, solid):
|
|
322
|
+
"""
|
|
323
|
+
Add any missing inherent (implicit) boundaries of this spline's domain to the given slice of the
|
|
324
|
+
given solid that are needed to make the slice valid and complete.
|
|
325
|
+
|
|
326
|
+
Parameters
|
|
327
|
+
----------
|
|
328
|
+
slice : `solid.Solid`
|
|
329
|
+
The slice of the given solid formed by the spline. The slice may be incomplete, missing some of the
|
|
330
|
+
spline's inherent domain boundaries. Its dimension must match `self.domain_dimension()`.
|
|
331
|
+
|
|
332
|
+
solid : `solid.Solid`
|
|
333
|
+
The solid being sliced by the manifold. Its dimension must match `self.range_dimension()`.
|
|
334
|
+
|
|
335
|
+
See Also
|
|
336
|
+
--------
|
|
337
|
+
`solid.Solid.slice` : slice the solid by a manifold.
|
|
338
|
+
`domain` : Return the domain of a spline.
|
|
339
|
+
|
|
340
|
+
Notes
|
|
341
|
+
-----
|
|
342
|
+
A spline's inherent domain is determined by its knot array for each dimension. This method only works for
|
|
343
|
+
nInd of 1 or 2.
|
|
344
|
+
"""
|
|
345
|
+
if self.domain_dimension() != slice.dimension: raise ValueError("Spline domain dimension must match slice dimension")
|
|
346
|
+
if self.range_dimension() != solid.dimension: raise ValueError("Spline range dimension must match solid dimension")
|
|
347
|
+
if slice.dimension != 1 and slice.dimension != 2: raise ValueError("Only works for nInd = 1 or 2")
|
|
348
|
+
return bspy._spline_intersection.complete_slice(self, slice, solid)
|
|
349
|
+
|
|
350
|
+
@staticmethod
|
|
351
|
+
def composition(splines, tolerance = 1.0e-6):
|
|
352
|
+
"""
|
|
353
|
+
Construct a spline approximation to a composition of splines sequence.
|
|
354
|
+
|
|
355
|
+
Parameters
|
|
356
|
+
----------
|
|
357
|
+
splines : `array-like`
|
|
358
|
+
An array of splines. The splines should have the property that the number
|
|
359
|
+
of independent variables of the ith spline should be the same as the number
|
|
360
|
+
of dependent variables of the (i+1)st spline. The number of dependent
|
|
361
|
+
variables of the first spline is arbitrary, as is the number of independent
|
|
362
|
+
variables of the last one. Moreover, the range of the ith spline should be
|
|
363
|
+
a subset of the domain of the (i-1)st spline. The interpretation of the
|
|
364
|
+
sequence is s_0(s_1(... s_(n-1)(u)))).
|
|
365
|
+
|
|
366
|
+
tolerance : `scalar`
|
|
367
|
+
The maximum 2-norm of the difference between the given function and the
|
|
368
|
+
spline fit. Defaults to 1.0e-6.
|
|
369
|
+
|
|
370
|
+
Returns
|
|
371
|
+
-------
|
|
372
|
+
spline : `Spline`
|
|
373
|
+
The spline which approximates the given composition.
|
|
374
|
+
|
|
375
|
+
Notes
|
|
376
|
+
-----
|
|
377
|
+
This currently defaults to a cubic spline. Depending on user experience, this
|
|
378
|
+
may change in the future.
|
|
379
|
+
|
|
380
|
+
See also
|
|
381
|
+
--------
|
|
382
|
+
`fit` : Fit a given function to a specified tolerance.
|
|
383
|
+
"""
|
|
384
|
+
return bspy._spline_fitting.composition(splines, tolerance)
|
|
385
|
+
|
|
316
386
|
@staticmethod
|
|
317
387
|
def cone(radius1, radius2, height, tolerance = None):
|
|
318
388
|
"""
|
|
@@ -379,6 +449,24 @@ class Spline(Manifold):
|
|
|
379
449
|
"""
|
|
380
450
|
return bspy._spline_operations.confine(self, range_bounds)
|
|
381
451
|
|
|
452
|
+
def continuity(self):
|
|
453
|
+
"""
|
|
454
|
+
Return the smoothness of the spline in each of its independent variables.
|
|
455
|
+
|
|
456
|
+
Returns
|
|
457
|
+
-------
|
|
458
|
+
`smoothness` : `iterable`
|
|
459
|
+
An array of length nInd containing the number of times the function is continuously
|
|
460
|
+
in each of the independent variables of the input spline.
|
|
461
|
+
|
|
462
|
+
Notes
|
|
463
|
+
-----
|
|
464
|
+
The value -1 is returned if the spline is discontinuous in that variable. The degree of the spline
|
|
465
|
+
is returned if the spline contains no interior knots even though the spline is an analytic function
|
|
466
|
+
of that variable.
|
|
467
|
+
"""
|
|
468
|
+
return bspy._spline_evaluation.continuity(self)
|
|
469
|
+
|
|
382
470
|
@staticmethod
|
|
383
471
|
def contour(F, knownXValues, dF = None, epsilon = None, metadata = {}):
|
|
384
472
|
"""
|
|
@@ -388,8 +476,8 @@ class Spline(Manifold):
|
|
|
388
476
|
|
|
389
477
|
Parameters
|
|
390
478
|
----------
|
|
391
|
-
F : function or `
|
|
392
|
-
A function or spline that takes an array-like argument of length `n` and returns an
|
|
479
|
+
F : function, `Spline`, or `SplineBlock`
|
|
480
|
+
A function, spline, or spline block that takes an array-like argument of length `n` and returns an
|
|
393
481
|
array-like result of length `n - 1`.
|
|
394
482
|
|
|
395
483
|
knownXValues : `iterable` of array-like
|
|
@@ -398,11 +486,12 @@ class Spline(Manifold):
|
|
|
398
486
|
All x values must be length `n` and be listed in the order they appear on the contour.
|
|
399
487
|
`F(x)` for all known x values must be a zero vector of length `n-1`.
|
|
400
488
|
|
|
401
|
-
dF : `iterable
|
|
402
|
-
|
|
489
|
+
dF : function, `iterable`, or `None`, optional
|
|
490
|
+
A function that returns the Jacobian of F as an array with shape (n - 1, n).
|
|
491
|
+
Can also be an `iterable` of `n` functions that return the `n` first derivatives of `F`.
|
|
403
492
|
If `dF` is `None` (the default), the first derivatives will be computed for you.
|
|
404
|
-
If `F` is not a spline, computing the first derivatives involves
|
|
405
|
-
and can be numerically unstable.
|
|
493
|
+
If `F` is not a spline or spline block, computing the first derivatives involves
|
|
494
|
+
multiple calls to `F` and can be numerically unstable.
|
|
406
495
|
|
|
407
496
|
epsilon : `float`, optional
|
|
408
497
|
Tolerance for contour precision. Evaluating `F` with contour values will be within epsilon
|
|
@@ -425,7 +514,7 @@ class Spline(Manifold):
|
|
|
425
514
|
Notes
|
|
426
515
|
-----
|
|
427
516
|
The returned spline has constant parametric speed (the length of its derivative is constant).
|
|
428
|
-
If `F` is a `Spline`, then the range of the returned contour is confined to the domain of `F`.
|
|
517
|
+
If `F` is a `Spline` or a `SplineBlock`, then the range of the returned contour is confined to the domain of `F`.
|
|
429
518
|
Implements the algorithm described in section 7 of Grandine, Thomas A.
|
|
430
519
|
"Applications of contouring." Siam Review 42, no. 2 (2000): 297-316.
|
|
431
520
|
"""
|
|
@@ -453,7 +542,7 @@ class Spline(Manifold):
|
|
|
453
542
|
The algorithm used to to find all intersection curves is from Grandine, Thomas A., and Frederick W. Klein IV.
|
|
454
543
|
"A new approach to the surface intersection problem." Computer Aided Geometric Design 14, no. 2 (1997): 111-134.
|
|
455
544
|
"""
|
|
456
|
-
return bspy._spline_intersection.contours(self)
|
|
545
|
+
return bspy._spline_intersection.contours(bspy.spline_block.SplineBlock(self))
|
|
457
546
|
|
|
458
547
|
def contract(self, uvw):
|
|
459
548
|
"""
|
|
@@ -518,21 +607,16 @@ class Spline(Manifold):
|
|
|
518
607
|
indMap = [(mapping, mapping, True) if np.isscalar(mapping) else (*mapping, True) for mapping in indMap]
|
|
519
608
|
return bspy._spline_operations.multiplyAndConvolve(self, other, indMap, productType)
|
|
520
609
|
|
|
521
|
-
def copy(self
|
|
610
|
+
def copy(self):
|
|
522
611
|
"""
|
|
523
612
|
Create a copy of a spline.
|
|
524
|
-
|
|
525
|
-
Parameters
|
|
526
|
-
----------
|
|
527
|
-
metadata : `dict`, optional
|
|
528
|
-
A dictionary of ancillary data to store with the spline. Default is {}.
|
|
529
613
|
|
|
530
614
|
Returns
|
|
531
615
|
-------
|
|
532
616
|
spline : `Spline`
|
|
533
617
|
The spline copy.
|
|
534
618
|
"""
|
|
535
|
-
return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, self.coefs, metadata)
|
|
619
|
+
return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, self.coefs, self.metadata)
|
|
536
620
|
|
|
537
621
|
def cross(self, vector):
|
|
538
622
|
"""
|
|
@@ -556,7 +640,7 @@ class Spline(Manifold):
|
|
|
556
640
|
|
|
557
641
|
def curvature(self, uvw):
|
|
558
642
|
"""
|
|
559
|
-
Compute the curvature of a univariate spline.
|
|
643
|
+
Compute the curvature of a univariate or bivariate spline.
|
|
560
644
|
|
|
561
645
|
Parameters
|
|
562
646
|
----------
|
|
@@ -566,7 +650,8 @@ class Spline(Manifold):
|
|
|
566
650
|
Returns
|
|
567
651
|
-------
|
|
568
652
|
value : scalar
|
|
569
|
-
The value of the curvature at the given point on the curve.
|
|
653
|
+
The value of the curvature at the given point on the curve or surface. If called on a surface,
|
|
654
|
+
the value will represent the Gaussian curvature of the surface at the given point.
|
|
570
655
|
|
|
571
656
|
Notes
|
|
572
657
|
-----
|
|
@@ -693,7 +778,7 @@ class Spline(Manifold):
|
|
|
693
778
|
Returns
|
|
694
779
|
-------
|
|
695
780
|
bounds : `numpy.array`
|
|
696
|
-
nInd x 2 array of the
|
|
781
|
+
nInd x 2 array of the lower and upper bounds on each of the independent variables.
|
|
697
782
|
|
|
698
783
|
See Also
|
|
699
784
|
--------
|
|
@@ -702,6 +787,17 @@ class Spline(Manifold):
|
|
|
702
787
|
"""
|
|
703
788
|
return bspy._spline_evaluation.domain(self)
|
|
704
789
|
|
|
790
|
+
def domain_dimension(self):
|
|
791
|
+
"""
|
|
792
|
+
Return the domain dimension of a spline (nInd).
|
|
793
|
+
|
|
794
|
+
Returns
|
|
795
|
+
-------
|
|
796
|
+
dimension : `int`
|
|
797
|
+
The dimension of the spline's domain (nInd)
|
|
798
|
+
"""
|
|
799
|
+
return self.nInd
|
|
800
|
+
|
|
705
801
|
def dot(self, vector):
|
|
706
802
|
"""
|
|
707
803
|
Dot product a spline by the given vector.
|
|
@@ -839,7 +935,7 @@ class Spline(Manifold):
|
|
|
839
935
|
Parameters
|
|
840
936
|
----------
|
|
841
937
|
newDomain : array-like
|
|
842
|
-
nInd x 2 array of the new
|
|
938
|
+
nInd x 2 array of the new lower and upper bounds on each of the independent variables (same form as
|
|
843
939
|
returned from `domain`). If a bound is None or nan then the original bound (and knots) are left unchanged.
|
|
844
940
|
|
|
845
941
|
continuityOrder : `int`
|
|
@@ -859,6 +955,63 @@ class Spline(Manifold):
|
|
|
859
955
|
"""
|
|
860
956
|
return bspy._spline_domain.extrapolate(self, newDomain, continuityOrder)
|
|
861
957
|
|
|
958
|
+
@staticmethod
|
|
959
|
+
def fit(domain, f, order = None, knots = None, tolerance = 1.0e-4):
|
|
960
|
+
"""
|
|
961
|
+
Fit the function f with a spline to a given tolerance.
|
|
962
|
+
|
|
963
|
+
Parameters
|
|
964
|
+
----------
|
|
965
|
+
domain - `array-like`
|
|
966
|
+
An nInd x 2 array which specifies the rectangular domain (in nInd dimensions)
|
|
967
|
+
over which the function f is defined. The approximating spline which is the
|
|
968
|
+
output will be defined over the same rectangular domain
|
|
969
|
+
|
|
970
|
+
f : Python function
|
|
971
|
+
The function to approximate. It is a vector-valued function of nDep
|
|
972
|
+
components in nInd variables.
|
|
973
|
+
|
|
974
|
+
order : `array-like`
|
|
975
|
+
An optional integer array of length nInd which specifies the polynomial
|
|
976
|
+
order to use in each of the independent variables. It will default to order
|
|
977
|
+
4 (degree 3) if None is specified (the default)
|
|
978
|
+
|
|
979
|
+
knots : `array-like`
|
|
980
|
+
The initial knot sequence to use, if given
|
|
981
|
+
|
|
982
|
+
tolerance : `scalar`
|
|
983
|
+
The maximum 2-norm of the difference between the given function and the
|
|
984
|
+
spline fit. Defaults to 1.0e-4.
|
|
985
|
+
|
|
986
|
+
Returns
|
|
987
|
+
-------
|
|
988
|
+
spline : `Spline`
|
|
989
|
+
A spline which approximates the given function to within the specified
|
|
990
|
+
tolerance.
|
|
991
|
+
|
|
992
|
+
See Also
|
|
993
|
+
--------
|
|
994
|
+
`least_squares` : Fit a least squares approximation to given data.
|
|
995
|
+
"""
|
|
996
|
+
return bspy._spline_fitting.fit(domain, f, order, knots, tolerance)
|
|
997
|
+
|
|
998
|
+
def flip_normal(self):
|
|
999
|
+
"""
|
|
1000
|
+
Flip the direction of the normal.
|
|
1001
|
+
|
|
1002
|
+
Returns
|
|
1003
|
+
-------
|
|
1004
|
+
spline : `Spline`
|
|
1005
|
+
The spline with flipped normal. The spline retains the same tangent space.
|
|
1006
|
+
|
|
1007
|
+
See Also
|
|
1008
|
+
--------
|
|
1009
|
+
`solid.Solid.complement` : Return the complement of the solid: whatever was inside is outside and vice-versa.
|
|
1010
|
+
"""
|
|
1011
|
+
spline = self.copy()
|
|
1012
|
+
spline.metadata["flipNormal"] = not self.metadata.get("flipNormal", False)
|
|
1013
|
+
return spline
|
|
1014
|
+
|
|
862
1015
|
def fold(self, foldedInd):
|
|
863
1016
|
"""
|
|
864
1017
|
Fold the coefficients of a spline's indicated independent variables into the coefficients of the remaining independent variables, retaining the
|
|
@@ -937,6 +1090,42 @@ class Spline(Manifold):
|
|
|
937
1090
|
"""
|
|
938
1091
|
return bspy._spline_fitting.four_sided_patch(bottom, right, top, left, surfParam)
|
|
939
1092
|
|
|
1093
|
+
@staticmethod
|
|
1094
|
+
def from_dict(dictionary):
|
|
1095
|
+
"""
|
|
1096
|
+
Create a `Spline` from data in a `dict`.
|
|
1097
|
+
|
|
1098
|
+
Parameters
|
|
1099
|
+
----------
|
|
1100
|
+
dictionary : `dict`
|
|
1101
|
+
The `dict` containing `Spline` data.
|
|
1102
|
+
|
|
1103
|
+
Returns
|
|
1104
|
+
-------
|
|
1105
|
+
spline : `Spline`
|
|
1106
|
+
|
|
1107
|
+
See Also
|
|
1108
|
+
--------
|
|
1109
|
+
`to_dict` : Return a `dict` with `Spline` data.
|
|
1110
|
+
"""
|
|
1111
|
+
return Spline(dictionary["nInd"], dictionary["nDep"], dictionary["order"], dictionary["nCoef"],
|
|
1112
|
+
[np.array(knots) for knots in dictionary["knots"]], np.array(dictionary["coefs"]), dictionary["metadata"])
|
|
1113
|
+
|
|
1114
|
+
def full_domain(self):
|
|
1115
|
+
"""
|
|
1116
|
+
Return a solid that represents the full domain of the spline.
|
|
1117
|
+
|
|
1118
|
+
Returns
|
|
1119
|
+
-------
|
|
1120
|
+
domain : `Solid`
|
|
1121
|
+
The full (untrimmed) domain of the spline.
|
|
1122
|
+
|
|
1123
|
+
See Also
|
|
1124
|
+
--------
|
|
1125
|
+
`Boundary` : A portion of the boundary of a solid.
|
|
1126
|
+
"""
|
|
1127
|
+
return bspy._spline_intersection.full_domain(self)
|
|
1128
|
+
|
|
940
1129
|
def geodesic(self, uvStart, uvEnd, tolerance = 1.0e-6):
|
|
941
1130
|
"""
|
|
942
1131
|
Determine a geodesic between two points on a surface
|
|
@@ -1039,48 +1228,46 @@ class Spline(Manifold):
|
|
|
1039
1228
|
"""
|
|
1040
1229
|
return bspy._spline_domain.insert_knots(self, newKnots)
|
|
1041
1230
|
|
|
1042
|
-
def integral(self,
|
|
1231
|
+
def integral(self, integrand = None, domain = None):
|
|
1043
1232
|
"""
|
|
1044
|
-
Compute the
|
|
1233
|
+
Compute the integral of a function composed with a spline. In particular, compute the
|
|
1234
|
+
nInd-dimensional integral over the specified domain of the quantity f(x_0, x_1, ..., x_{nDep - 1})dA,
|
|
1235
|
+
where x_i is the (i+1)-th dependent variable, and dA is the multivariate measure of the spline mapping.
|
|
1045
1236
|
|
|
1046
1237
|
Parameters
|
|
1047
1238
|
----------
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1239
|
+
integrand : Python function, optional
|
|
1240
|
+
A Python function which takes an array-like object of length nDep as input and returns a
|
|
1241
|
+
scalar. If None is specified for integrand, then the function which returns a constant value
|
|
1242
|
+
of one is used. This computes the volume measure of the spline itself (arc length, surface area,
|
|
1243
|
+
volume, etc.) depending on the dimensionality of the spline itself.
|
|
1244
|
+
|
|
1245
|
+
domain : array-like
|
|
1246
|
+
nInd x 2 array of the lower and upper limits of integration for the spline on each of the
|
|
1247
|
+
independent variables. If domain is None, then the actual domain of the spline is used.
|
|
1054
1248
|
|
|
1055
|
-
uvw2 : `iterable`
|
|
1056
|
-
An iterable of length `nInd` that specifies the upper limit of each independent variable (the parameter values).
|
|
1057
|
-
|
|
1058
|
-
returnSpline : `boolean`, optional
|
|
1059
|
-
A boolean flag that if true returns the integrated spline along with the value of its integral. Default is false.
|
|
1060
|
-
|
|
1061
1249
|
Returns
|
|
1062
1250
|
-------
|
|
1063
|
-
|
|
1064
|
-
The value of the integral
|
|
1065
|
-
|
|
1066
|
-
spline : `Spline`
|
|
1067
|
-
The integrated spline, which is only returned if `returnSpline` is `True`.
|
|
1068
|
-
|
|
1251
|
+
integral_value : `float`
|
|
1252
|
+
The computed value of the specified integral
|
|
1253
|
+
|
|
1069
1254
|
See Also
|
|
1070
1255
|
--------
|
|
1071
|
-
`integrate` : Integrate a spline with respect to one of its independent variables, returning
|
|
1072
|
-
|
|
1073
|
-
`differentiate` : Differentiate a spline with respect to one of its independent variables, returning the resulting spline.
|
|
1074
|
-
`derivative` : Compute the derivative of the spline at a given parameter value.
|
|
1256
|
+
`integrate` : Integrate a spline with respect to one of its independent variables, returning
|
|
1257
|
+
the resulting spline.
|
|
1075
1258
|
|
|
1076
1259
|
Notes
|
|
1077
1260
|
-----
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
the
|
|
1261
|
+
This function is very useful for computing mass properties of splines. If the integrand function
|
|
1262
|
+
returns one, then the volume measure of the spline itself is computed (arc length, surface area,
|
|
1263
|
+
volume, etc.). If the integrand function returns one of the dependent variable values, then the
|
|
1264
|
+
integral will be the first moment of the spline with respect to that variable, making it possible
|
|
1265
|
+
to compute centroids and center of mass. The integrand function should be smooth, but is otherwise
|
|
1266
|
+
unrestricted.
|
|
1267
|
+
|
|
1268
|
+
Attempts to compute the integral to two digits less than machine precision.
|
|
1082
1269
|
"""
|
|
1083
|
-
return bspy._spline_evaluation.
|
|
1270
|
+
return bspy._spline_evaluation.composed_integral(self, integrand, domain)
|
|
1084
1271
|
|
|
1085
1272
|
def integrate(self, with_respect_to = 0):
|
|
1086
1273
|
"""
|
|
@@ -1089,7 +1276,7 @@ class Spline(Manifold):
|
|
|
1089
1276
|
Parameters
|
|
1090
1277
|
----------
|
|
1091
1278
|
with_respect_to : integer, optional
|
|
1092
|
-
The
|
|
1279
|
+
The index of the independent variable to integrate. Default is zero.
|
|
1093
1280
|
|
|
1094
1281
|
Returns
|
|
1095
1282
|
-------
|
|
@@ -1137,12 +1324,13 @@ class Spline(Manifold):
|
|
|
1137
1324
|
--------
|
|
1138
1325
|
`zeros` : Find the roots of a spline (nInd must match nDep).
|
|
1139
1326
|
`contours` : Find all the contour curves of a spline.
|
|
1327
|
+
`solid.Solid.slice` : slice the solid by a manifold.
|
|
1140
1328
|
|
|
1141
1329
|
Notes
|
|
1142
1330
|
-----
|
|
1143
1331
|
Uses `zeros` to find all intersection points and `contours` to find all the intersection curves.
|
|
1144
1332
|
"""
|
|
1145
|
-
if not(self.
|
|
1333
|
+
if not(self.range_dimension() == other.range_dimension()): raise ValueError("The number of dependent variables for both splines much match.")
|
|
1146
1334
|
return bspy._spline_intersection.intersect(self, other)
|
|
1147
1335
|
|
|
1148
1336
|
def jacobian(self, uvw):
|
|
@@ -1343,9 +1531,8 @@ class Spline(Manifold):
|
|
|
1343
1531
|
if isinstance(splineData, dict):
|
|
1344
1532
|
splineData = [splineData]
|
|
1345
1533
|
for splineDict in splineData:
|
|
1346
|
-
splines.append(Spline(splineDict
|
|
1347
|
-
|
|
1348
|
-
return splines
|
|
1534
|
+
splines.append(Spline.from_dict(splineDict))
|
|
1535
|
+
return splines
|
|
1349
1536
|
|
|
1350
1537
|
def multiply(self, other, indMap = None, productType = 'S'):
|
|
1351
1538
|
"""
|
|
@@ -1457,7 +1644,7 @@ class Spline(Manifold):
|
|
|
1457
1644
|
dependent variables (instead of one less, as is typical). In that case, the normal represents the null space of
|
|
1458
1645
|
the matrix formed by the tangents of the spline. If the null space is greater than one dimension, the normal will be zero.
|
|
1459
1646
|
"""
|
|
1460
|
-
return bspy._spline_operations.normal_spline(self, indices)
|
|
1647
|
+
return bspy._spline_operations.normal_spline(bspy.spline_block.SplineBlock(self), indices)
|
|
1461
1648
|
|
|
1462
1649
|
@staticmethod
|
|
1463
1650
|
def point(point):
|
|
@@ -1487,10 +1674,21 @@ class Spline(Manifold):
|
|
|
1487
1674
|
def range_bounds(self):
|
|
1488
1675
|
"""
|
|
1489
1676
|
Return the range of a spline as lower and upper bounds on each of the
|
|
1490
|
-
dependent variables
|
|
1677
|
+
dependent variables.
|
|
1491
1678
|
"""
|
|
1492
1679
|
return bspy._spline_evaluation.range_bounds(self)
|
|
1493
1680
|
|
|
1681
|
+
def range_dimension(self):
|
|
1682
|
+
"""
|
|
1683
|
+
Return the range dimension of a spline (nDep).
|
|
1684
|
+
|
|
1685
|
+
Returns
|
|
1686
|
+
-------
|
|
1687
|
+
dimension : `int`
|
|
1688
|
+
The dimension of the spline's range (nDep)
|
|
1689
|
+
"""
|
|
1690
|
+
return self.nDep
|
|
1691
|
+
|
|
1494
1692
|
def remove_knot(self, iKnot, nLeft = 0, nRight = 0):
|
|
1495
1693
|
"""
|
|
1496
1694
|
Remove a single knot from a univariate spline.
|
|
@@ -1573,7 +1771,7 @@ class Spline(Manifold):
|
|
|
1573
1771
|
Parameters
|
|
1574
1772
|
----------
|
|
1575
1773
|
newDomain : array-like
|
|
1576
|
-
nInd x 2 array of the new
|
|
1774
|
+
nInd x 2 array of the new lower and upper bounds on each of the independent variables (same form as
|
|
1577
1775
|
returned from `domain`). If a bound pair is `None` then the original bound (and knots) are left unchanged.
|
|
1578
1776
|
For example, `[[0.0, 1.0], None]` will reparametrize the first independent variable and leave the second unchanged)
|
|
1579
1777
|
|
|
@@ -1610,7 +1808,7 @@ class Spline(Manifold):
|
|
|
1610
1808
|
|
|
1611
1809
|
def revolve(self, angle):
|
|
1612
1810
|
"""
|
|
1613
|
-
|
|
1811
|
+
Revolve the spline to create a surface of revolution (nDep must equal 2,
|
|
1614
1812
|
first dimension provides the radius for x and y, second dimension provides the z).
|
|
1615
1813
|
|
|
1616
1814
|
Parameters
|
|
@@ -1698,15 +1896,7 @@ class Spline(Manifold):
|
|
|
1698
1896
|
if isinstance(obj, np.ndarray):
|
|
1699
1897
|
return obj.tolist()
|
|
1700
1898
|
if isinstance(obj, Spline):
|
|
1701
|
-
return
|
|
1702
|
-
"nInd" : obj.nInd,
|
|
1703
|
-
"nDep" : obj.nDep,
|
|
1704
|
-
"order" : obj.order,
|
|
1705
|
-
"nCoef" : obj.nCoef,
|
|
1706
|
-
"knots" : obj.knots,
|
|
1707
|
-
"coefs" : obj.coefs,
|
|
1708
|
-
"metadata" : obj.metadata
|
|
1709
|
-
}
|
|
1899
|
+
return obj.to_dict()
|
|
1710
1900
|
return super().default(obj)
|
|
1711
1901
|
|
|
1712
1902
|
with open(fileName, 'w', encoding='utf-8') as file:
|
|
@@ -1851,6 +2041,31 @@ class Spline(Manifold):
|
|
|
1851
2041
|
`multiply` : Multiply two splines together.
|
|
1852
2042
|
"""
|
|
1853
2043
|
return bspy._spline_fitting.sphere(radius, tolerance)
|
|
2044
|
+
|
|
2045
|
+
def split(self, minContinuity = 0, breaks = None):
|
|
2046
|
+
"""
|
|
2047
|
+
Split a spline into separate spline pieces.
|
|
2048
|
+
|
|
2049
|
+
Parameters
|
|
2050
|
+
----------
|
|
2051
|
+
minContinuity : `int`, optional
|
|
2052
|
+
The minimum expected continuity of each spline piece. The default is zero, for C0 continuity.
|
|
2053
|
+
|
|
2054
|
+
breaks : `iterable` of length `nInd` or `None`, optional
|
|
2055
|
+
An iterable that specifies the breaks at which to separate the spline.
|
|
2056
|
+
len(breaks[ind]) == 0 if there the spline isn't separated for the `ind` independent variable.
|
|
2057
|
+
If breaks is `None` (the default), the spline will only be separated at discontinuities.
|
|
2058
|
+
|
|
2059
|
+
Returns
|
|
2060
|
+
-------
|
|
2061
|
+
splineArray : array of `Spline`
|
|
2062
|
+
A array of splines with nInd dimensions containing the spline pieces.
|
|
2063
|
+
|
|
2064
|
+
See Also
|
|
2065
|
+
--------
|
|
2066
|
+
`join` : Join a list of splines together into a single spline.
|
|
2067
|
+
"""
|
|
2068
|
+
return bspy._spline_domain.split(self, minContinuity, breaks)
|
|
1854
2069
|
|
|
1855
2070
|
def subtract(self, other, indMap = None):
|
|
1856
2071
|
"""
|
|
@@ -1891,6 +2106,37 @@ class Spline(Manifold):
|
|
|
1891
2106
|
indMap = [(mapping, mapping) if np.isscalar(mapping) else mapping for mapping in indMap]
|
|
1892
2107
|
return self.add(other.scale(-1.0), indMap)
|
|
1893
2108
|
|
|
2109
|
+
def tangent_space(self, uvw):
|
|
2110
|
+
"""
|
|
2111
|
+
Return the tangent space of the spline. (Same as Jacobian.)
|
|
2112
|
+
|
|
2113
|
+
Parameters
|
|
2114
|
+
----------
|
|
2115
|
+
uvw : array-like
|
|
2116
|
+
The value at which to evaluate the tangent space.
|
|
2117
|
+
|
|
2118
|
+
Returns
|
|
2119
|
+
-------
|
|
2120
|
+
tangentSpace : `numpy.array`
|
|
2121
|
+
The nDep x nInd matrix of tangent vectors (tangents are the columns).
|
|
2122
|
+
"""
|
|
2123
|
+
return bspy._spline_evaluation.jacobian(self, uvw)
|
|
2124
|
+
|
|
2125
|
+
def to_dict(self):
|
|
2126
|
+
"""
|
|
2127
|
+
Return a `dict` with `Spline` data.
|
|
2128
|
+
|
|
2129
|
+
Returns
|
|
2130
|
+
-------
|
|
2131
|
+
dictionary : `dict`
|
|
2132
|
+
|
|
2133
|
+
See Also
|
|
2134
|
+
--------
|
|
2135
|
+
`from_dict` : Create a `Spline` from a data in a `dict`.
|
|
2136
|
+
"""
|
|
2137
|
+
return {"type" : "Spline", "nInd" : self.nInd, "nDep" : self.nDep, "order" : self.order, "nCoef" : self.nCoef,
|
|
2138
|
+
"knots" : self.knots, "coefs" : self.coefs, "metadata" : self.metadata}
|
|
2139
|
+
|
|
1894
2140
|
@staticmethod
|
|
1895
2141
|
def torus(innerRadius, outerRadius, tolerance = None):
|
|
1896
2142
|
"""
|
|
@@ -1929,7 +2175,7 @@ class Spline(Manifold):
|
|
|
1929
2175
|
"""
|
|
1930
2176
|
return bspy._spline_fitting.torus(innerRadius, outerRadius, tolerance)
|
|
1931
2177
|
|
|
1932
|
-
def transform(self, matrix):
|
|
2178
|
+
def transform(self, matrix, matrixInverseTranspose = None):
|
|
1933
2179
|
"""
|
|
1934
2180
|
Transform a spline by the given matrix.
|
|
1935
2181
|
|
|
@@ -1938,6 +2184,9 @@ class Spline(Manifold):
|
|
|
1938
2184
|
matrix : array-like
|
|
1939
2185
|
An array of size `newNDep`x`nDep` that specifies the transform matrix.
|
|
1940
2186
|
|
|
2187
|
+
matrixInverseTranspose : `numpy.array`, optional
|
|
2188
|
+
The inverse transpose of matrix (not used for splines).
|
|
2189
|
+
|
|
1941
2190
|
Returns
|
|
1942
2191
|
-------
|
|
1943
2192
|
spline : `Spline`
|
|
@@ -2012,7 +2261,7 @@ class Spline(Manifold):
|
|
|
2012
2261
|
Parameters
|
|
2013
2262
|
----------
|
|
2014
2263
|
newDomain : array-like
|
|
2015
|
-
nInd x 2 array of the new
|
|
2264
|
+
nInd x 2 array of the new lower and upper bounds on each of the independent variables (same form as
|
|
2016
2265
|
returned from `domain`). If a bound is None or nan then the original bound (and knots) are left unchanged.
|
|
2017
2266
|
|
|
2018
2267
|
Returns
|
|
@@ -2027,6 +2276,31 @@ class Spline(Manifold):
|
|
|
2027
2276
|
"""
|
|
2028
2277
|
return bspy._spline_domain.trim(self, newDomain)
|
|
2029
2278
|
|
|
2279
|
+
def trimmed_range_bounds(self, domainBounds):
|
|
2280
|
+
"""
|
|
2281
|
+
Return the trimmed range bounds for the spline.
|
|
2282
|
+
|
|
2283
|
+
Parameters
|
|
2284
|
+
----------
|
|
2285
|
+
domainBounds : array-like
|
|
2286
|
+
An array with shape (nInd, 2) of lower and upper and lower bounds on each independent variable.
|
|
2287
|
+
|
|
2288
|
+
Returns
|
|
2289
|
+
-------
|
|
2290
|
+
trimmedSpline : `Spline`
|
|
2291
|
+
A spline trimmed to the given domain bounds.
|
|
2292
|
+
|
|
2293
|
+
rangeBounds : `np.array`
|
|
2294
|
+
The range of the trimmed spline given as lower and upper bounds on each dependent variable.
|
|
2295
|
+
|
|
2296
|
+
See Also
|
|
2297
|
+
--------
|
|
2298
|
+
`trim` : Trim the domain of a spline.
|
|
2299
|
+
`range_bounds` : Return the range of a spline as lower and upper bounds on each of the
|
|
2300
|
+
dependent variables.
|
|
2301
|
+
"""
|
|
2302
|
+
return bspy._spline_domain.trimmed_range_bounds(self, domainBounds)
|
|
2303
|
+
|
|
2030
2304
|
def unfold(self, foldedInd, coefficientlessSpline):
|
|
2031
2305
|
"""
|
|
2032
2306
|
Unfold the coefficients of an original spline's indicated independent variables back into the spline, using the
|
|
@@ -2064,7 +2338,7 @@ class Spline(Manifold):
|
|
|
2064
2338
|
"""
|
|
2065
2339
|
return bspy._spline_domain.unfold(self, foldedInd, coefficientlessSpline)
|
|
2066
2340
|
|
|
2067
|
-
def zeros(self, epsilon=None):
|
|
2341
|
+
def zeros(self, epsilon=None, initialScale=None):
|
|
2068
2342
|
"""
|
|
2069
2343
|
Find the roots of a spline (nInd must match nDep).
|
|
2070
2344
|
|
|
@@ -2074,6 +2348,10 @@ class Spline(Manifold):
|
|
|
2074
2348
|
Tolerance for root precision. The root will be within epsilon of the actual root.
|
|
2075
2349
|
The default is the machine epsilon.
|
|
2076
2350
|
|
|
2351
|
+
initialScale : array-like, optional
|
|
2352
|
+
The initial scale of each dependent variable (as opposed to the current scale of
|
|
2353
|
+
the spline, which may have been normalized). The default is an array of ones (size nDep).
|
|
2354
|
+
|
|
2077
2355
|
Returns
|
|
2078
2356
|
-------
|
|
2079
2357
|
roots : `iterable`
|
|
@@ -2084,7 +2362,7 @@ class Spline(Manifold):
|
|
|
2084
2362
|
See Also
|
|
2085
2363
|
--------
|
|
2086
2364
|
`intersect` : Intersect two splines.
|
|
2087
|
-
`
|
|
2365
|
+
`contours` : Find all the contour curves of a spline whose `nInd` is one larger than its `nDep`.
|
|
2088
2366
|
|
|
2089
2367
|
Notes
|
|
2090
2368
|
-----
|
|
@@ -2097,4 +2375,5 @@ class Spline(Manifold):
|
|
|
2097
2375
|
if self.nInd <= 1:
|
|
2098
2376
|
return bspy._spline_intersection.zeros_using_interval_newton(self)
|
|
2099
2377
|
else:
|
|
2100
|
-
return bspy._spline_intersection.zeros_using_projected_polyhedron(self, epsilon)
|
|
2378
|
+
return bspy._spline_intersection.zeros_using_projected_polyhedron(bspy.spline_block.SplineBlock(self), epsilon, initialScale)
|
|
2379
|
+
|