bspy 4.0__py3-none-any.whl → 4.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 +13 -3
- bspy/_spline_domain.py +9 -0
- bspy/_spline_evaluation.py +16 -10
- bspy/_spline_fitting.py +56 -82
- bspy/_spline_intersection.py +187 -23
- bspy/_spline_operations.py +8 -2
- bspy/hyperplane.py +540 -0
- bspy/manifold.py +332 -29
- bspy/solid.py +839 -0
- bspy/spline.py +176 -27
- bspy/splineOpenGLFrame.py +262 -14
- bspy/viewer.py +130 -87
- {bspy-4.0.dist-info → bspy-4.1.dist-info}/METADATA +8 -3
- bspy-4.1.dist-info/RECORD +17 -0
- bspy-4.0.dist-info/RECORD +0 -15
- {bspy-4.0.dist-info → bspy-4.1.dist-info}/LICENSE +0 -0
- {bspy-4.0.dist-info → bspy-4.1.dist-info}/WHEEL +0 -0
- {bspy-4.0.dist-info → bspy-4.1.dist-info}/top_level.txt +0 -0
bspy/spline.py
CHANGED
|
@@ -8,6 +8,7 @@ import bspy._spline_intersection
|
|
|
8
8
|
import bspy._spline_fitting
|
|
9
9
|
import bspy._spline_operations
|
|
10
10
|
|
|
11
|
+
@Manifold.register
|
|
11
12
|
class Spline(Manifold):
|
|
12
13
|
"""
|
|
13
14
|
A class to model, represent, and process piecewise polynomial tensor product
|
|
@@ -313,6 +314,35 @@ class Spline(Manifold):
|
|
|
313
314
|
"""
|
|
314
315
|
return bspy._spline_domain.common_basis(splines, indMap)
|
|
315
316
|
|
|
317
|
+
def complete_slice(self, slice, solid):
|
|
318
|
+
"""
|
|
319
|
+
Add any missing inherent (implicit) boundaries of this spline's domain to the given slice of the
|
|
320
|
+
given solid that are needed to make the slice valid and complete.
|
|
321
|
+
|
|
322
|
+
Parameters
|
|
323
|
+
----------
|
|
324
|
+
slice : `solid.Solid`
|
|
325
|
+
The slice of the given solid formed by the spline. The slice may be incomplete, missing some of the
|
|
326
|
+
spline's inherent domain boundaries. Its dimension must match `self.domain_dimension()`.
|
|
327
|
+
|
|
328
|
+
solid : `solid.Solid`
|
|
329
|
+
The solid being sliced by the manifold. Its dimension must match `self.range_dimension()`.
|
|
330
|
+
|
|
331
|
+
See Also
|
|
332
|
+
--------
|
|
333
|
+
`solid.Solid.slice` : slice the solid by a manifold.
|
|
334
|
+
`domain` : Return the domain of a spline.
|
|
335
|
+
|
|
336
|
+
Notes
|
|
337
|
+
-----
|
|
338
|
+
A spline's inherent domain is determined by its knot array for each dimension. This method only works for
|
|
339
|
+
nInd of 1 or 2.
|
|
340
|
+
"""
|
|
341
|
+
if self.domain_dimension() != slice.dimension: raise ValueError("Spline domain dimension must match slice dimension")
|
|
342
|
+
if self.range_dimension() != solid.dimension: raise ValueError("Spline range dimension must match solid dimension")
|
|
343
|
+
if slice.dimension != 1 and slice.dimension != 2: raise ValueError("Only works for nInd = 1 or 2")
|
|
344
|
+
return bspy._spline_intersection.complete_slice(self, slice, solid)
|
|
345
|
+
|
|
316
346
|
@staticmethod
|
|
317
347
|
def cone(radius1, radius2, height, tolerance = None):
|
|
318
348
|
"""
|
|
@@ -518,21 +548,16 @@ class Spline(Manifold):
|
|
|
518
548
|
indMap = [(mapping, mapping, True) if np.isscalar(mapping) else (*mapping, True) for mapping in indMap]
|
|
519
549
|
return bspy._spline_operations.multiplyAndConvolve(self, other, indMap, productType)
|
|
520
550
|
|
|
521
|
-
def copy(self
|
|
551
|
+
def copy(self):
|
|
522
552
|
"""
|
|
523
553
|
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
554
|
|
|
530
555
|
Returns
|
|
531
556
|
-------
|
|
532
557
|
spline : `Spline`
|
|
533
558
|
The spline copy.
|
|
534
559
|
"""
|
|
535
|
-
return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, self.coefs, metadata)
|
|
560
|
+
return type(self)(self.nInd, self.nDep, self.order, self.nCoef, self.knots, self.coefs, self.metadata)
|
|
536
561
|
|
|
537
562
|
def cross(self, vector):
|
|
538
563
|
"""
|
|
@@ -693,7 +718,7 @@ class Spline(Manifold):
|
|
|
693
718
|
Returns
|
|
694
719
|
-------
|
|
695
720
|
bounds : `numpy.array`
|
|
696
|
-
nInd x 2 array of the
|
|
721
|
+
nInd x 2 array of the lower and upper bounds on each of the independent variables.
|
|
697
722
|
|
|
698
723
|
See Also
|
|
699
724
|
--------
|
|
@@ -702,6 +727,17 @@ class Spline(Manifold):
|
|
|
702
727
|
"""
|
|
703
728
|
return bspy._spline_evaluation.domain(self)
|
|
704
729
|
|
|
730
|
+
def domain_dimension(self):
|
|
731
|
+
"""
|
|
732
|
+
Return the domain dimension of a spline (nInd).
|
|
733
|
+
|
|
734
|
+
Returns
|
|
735
|
+
-------
|
|
736
|
+
dimension : `int`
|
|
737
|
+
The dimension of the spline's domain (nInd)
|
|
738
|
+
"""
|
|
739
|
+
return self.nInd
|
|
740
|
+
|
|
705
741
|
def dot(self, vector):
|
|
706
742
|
"""
|
|
707
743
|
Dot product a spline by the given vector.
|
|
@@ -839,7 +875,7 @@ class Spline(Manifold):
|
|
|
839
875
|
Parameters
|
|
840
876
|
----------
|
|
841
877
|
newDomain : array-like
|
|
842
|
-
nInd x 2 array of the new
|
|
878
|
+
nInd x 2 array of the new lower and upper bounds on each of the independent variables (same form as
|
|
843
879
|
returned from `domain`). If a bound is None or nan then the original bound (and knots) are left unchanged.
|
|
844
880
|
|
|
845
881
|
continuityOrder : `int`
|
|
@@ -859,6 +895,23 @@ class Spline(Manifold):
|
|
|
859
895
|
"""
|
|
860
896
|
return bspy._spline_domain.extrapolate(self, newDomain, continuityOrder)
|
|
861
897
|
|
|
898
|
+
def flip_normal(self):
|
|
899
|
+
"""
|
|
900
|
+
Flip the direction of the normal.
|
|
901
|
+
|
|
902
|
+
Returns
|
|
903
|
+
-------
|
|
904
|
+
spline : `Spline`
|
|
905
|
+
The spline with flipped normal. The spline retains the same tangent space.
|
|
906
|
+
|
|
907
|
+
See Also
|
|
908
|
+
--------
|
|
909
|
+
`solid.Solid.complement` : Return the complement of the solid: whatever was inside is outside and vice-versa.
|
|
910
|
+
"""
|
|
911
|
+
spline = self.copy()
|
|
912
|
+
spline.metadata["flipNormal"] = not self.metadata.get("flipNormal", False)
|
|
913
|
+
return spline
|
|
914
|
+
|
|
862
915
|
def fold(self, foldedInd):
|
|
863
916
|
"""
|
|
864
917
|
Fold the coefficients of a spline's indicated independent variables into the coefficients of the remaining independent variables, retaining the
|
|
@@ -937,6 +990,42 @@ class Spline(Manifold):
|
|
|
937
990
|
"""
|
|
938
991
|
return bspy._spline_fitting.four_sided_patch(bottom, right, top, left, surfParam)
|
|
939
992
|
|
|
993
|
+
@staticmethod
|
|
994
|
+
def from_dict(dictionary):
|
|
995
|
+
"""
|
|
996
|
+
Create a `Spline` from a data in a `dict`.
|
|
997
|
+
|
|
998
|
+
Parameters
|
|
999
|
+
----------
|
|
1000
|
+
dictionary : `dict`
|
|
1001
|
+
The `dict` containing `Spline` data.
|
|
1002
|
+
|
|
1003
|
+
Returns
|
|
1004
|
+
-------
|
|
1005
|
+
spline : `Spline`
|
|
1006
|
+
|
|
1007
|
+
See Also
|
|
1008
|
+
--------
|
|
1009
|
+
`to_dict` : Return a `dict` with `Spline` data.
|
|
1010
|
+
"""
|
|
1011
|
+
return Spline(dictionary["nInd"], dictionary["nDep"], dictionary["order"], dictionary["nCoef"],
|
|
1012
|
+
[np.array(knots) for knots in dictionary["knots"]], np.array(dictionary["coefs"]), dictionary["metadata"])
|
|
1013
|
+
|
|
1014
|
+
def full_domain(self):
|
|
1015
|
+
"""
|
|
1016
|
+
Return a solid that represents the full domain of the spline.
|
|
1017
|
+
|
|
1018
|
+
Returns
|
|
1019
|
+
-------
|
|
1020
|
+
domain : `Solid`
|
|
1021
|
+
The full (untrimmed) domain of the spline.
|
|
1022
|
+
|
|
1023
|
+
See Also
|
|
1024
|
+
--------
|
|
1025
|
+
`Boundary` : A portion of the boundary of a solid.
|
|
1026
|
+
"""
|
|
1027
|
+
return bspy._spline_intersection.full_domain(self)
|
|
1028
|
+
|
|
940
1029
|
def geodesic(self, uvStart, uvEnd, tolerance = 1.0e-6):
|
|
941
1030
|
"""
|
|
942
1031
|
Determine a geodesic between two points on a surface
|
|
@@ -1137,12 +1226,13 @@ class Spline(Manifold):
|
|
|
1137
1226
|
--------
|
|
1138
1227
|
`zeros` : Find the roots of a spline (nInd must match nDep).
|
|
1139
1228
|
`contours` : Find all the contour curves of a spline.
|
|
1229
|
+
`solid.Solid.slice` : slice the solid by a manifold.
|
|
1140
1230
|
|
|
1141
1231
|
Notes
|
|
1142
1232
|
-----
|
|
1143
1233
|
Uses `zeros` to find all intersection points and `contours` to find all the intersection curves.
|
|
1144
1234
|
"""
|
|
1145
|
-
if not(self.
|
|
1235
|
+
if not(self.range_dimension() == other.range_dimension()): raise ValueError("The number of dependent variables for both splines much match.")
|
|
1146
1236
|
return bspy._spline_intersection.intersect(self, other)
|
|
1147
1237
|
|
|
1148
1238
|
def jacobian(self, uvw):
|
|
@@ -1343,9 +1433,8 @@ class Spline(Manifold):
|
|
|
1343
1433
|
if isinstance(splineData, dict):
|
|
1344
1434
|
splineData = [splineData]
|
|
1345
1435
|
for splineDict in splineData:
|
|
1346
|
-
splines.append(Spline(splineDict
|
|
1347
|
-
|
|
1348
|
-
return splines
|
|
1436
|
+
splines.append(Spline.from_dict(splineDict))
|
|
1437
|
+
return splines
|
|
1349
1438
|
|
|
1350
1439
|
def multiply(self, other, indMap = None, productType = 'S'):
|
|
1351
1440
|
"""
|
|
@@ -1487,10 +1576,21 @@ class Spline(Manifold):
|
|
|
1487
1576
|
def range_bounds(self):
|
|
1488
1577
|
"""
|
|
1489
1578
|
Return the range of a spline as lower and upper bounds on each of the
|
|
1490
|
-
dependent variables
|
|
1579
|
+
dependent variables.
|
|
1491
1580
|
"""
|
|
1492
1581
|
return bspy._spline_evaluation.range_bounds(self)
|
|
1493
1582
|
|
|
1583
|
+
def range_dimension(self):
|
|
1584
|
+
"""
|
|
1585
|
+
Return the range dimension of a spline (nDep).
|
|
1586
|
+
|
|
1587
|
+
Returns
|
|
1588
|
+
-------
|
|
1589
|
+
dimension : `int`
|
|
1590
|
+
The dimension of the spline's range (nDep)
|
|
1591
|
+
"""
|
|
1592
|
+
return self.nDep
|
|
1593
|
+
|
|
1494
1594
|
def remove_knot(self, iKnot, nLeft = 0, nRight = 0):
|
|
1495
1595
|
"""
|
|
1496
1596
|
Remove a single knot from a univariate spline.
|
|
@@ -1573,7 +1673,7 @@ class Spline(Manifold):
|
|
|
1573
1673
|
Parameters
|
|
1574
1674
|
----------
|
|
1575
1675
|
newDomain : array-like
|
|
1576
|
-
nInd x 2 array of the new
|
|
1676
|
+
nInd x 2 array of the new lower and upper bounds on each of the independent variables (same form as
|
|
1577
1677
|
returned from `domain`). If a bound pair is `None` then the original bound (and knots) are left unchanged.
|
|
1578
1678
|
For example, `[[0.0, 1.0], None]` will reparametrize the first independent variable and leave the second unchanged)
|
|
1579
1679
|
|
|
@@ -1610,7 +1710,7 @@ class Spline(Manifold):
|
|
|
1610
1710
|
|
|
1611
1711
|
def revolve(self, angle):
|
|
1612
1712
|
"""
|
|
1613
|
-
|
|
1713
|
+
Revolve the spline to create a surface of revolution (nDep must equal 2,
|
|
1614
1714
|
first dimension provides the radius for x and y, second dimension provides the z).
|
|
1615
1715
|
|
|
1616
1716
|
Parameters
|
|
@@ -1698,15 +1798,7 @@ class Spline(Manifold):
|
|
|
1698
1798
|
if isinstance(obj, np.ndarray):
|
|
1699
1799
|
return obj.tolist()
|
|
1700
1800
|
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
|
-
}
|
|
1801
|
+
return obj.to_dict()
|
|
1710
1802
|
return super().default(obj)
|
|
1711
1803
|
|
|
1712
1804
|
with open(fileName, 'w', encoding='utf-8') as file:
|
|
@@ -1891,6 +1983,37 @@ class Spline(Manifold):
|
|
|
1891
1983
|
indMap = [(mapping, mapping) if np.isscalar(mapping) else mapping for mapping in indMap]
|
|
1892
1984
|
return self.add(other.scale(-1.0), indMap)
|
|
1893
1985
|
|
|
1986
|
+
def tangent_space(self, uvw):
|
|
1987
|
+
"""
|
|
1988
|
+
Return the tangent space of the spline.
|
|
1989
|
+
|
|
1990
|
+
Parameters
|
|
1991
|
+
----------
|
|
1992
|
+
uvw : array-like
|
|
1993
|
+
The value at which to evaluate the tangent space.
|
|
1994
|
+
|
|
1995
|
+
Returns
|
|
1996
|
+
-------
|
|
1997
|
+
tangentSpace : `numpy.array`
|
|
1998
|
+
The nDep x nInd matrix of tangent vectors (tangents are the columns).
|
|
1999
|
+
"""
|
|
2000
|
+
return bspy._spline_evaluation.tangent_space(self, uvw)
|
|
2001
|
+
|
|
2002
|
+
def to_dict(self):
|
|
2003
|
+
"""
|
|
2004
|
+
Return a `dict` with `Spline` data.
|
|
2005
|
+
|
|
2006
|
+
Returns
|
|
2007
|
+
-------
|
|
2008
|
+
dictionary : `dict`
|
|
2009
|
+
|
|
2010
|
+
See Also
|
|
2011
|
+
--------
|
|
2012
|
+
`from_dict` : Create a `Spline` from a data in a `dict`.
|
|
2013
|
+
"""
|
|
2014
|
+
return {"type" : "Spline", "nInd" : self.nInd, "nDep" : self.nDep, "order" : self.order, "nCoef" : self.nCoef,
|
|
2015
|
+
"knots" : self.knots, "coefs" : self.coefs, "metadata" : self.metadata}
|
|
2016
|
+
|
|
1894
2017
|
@staticmethod
|
|
1895
2018
|
def torus(innerRadius, outerRadius, tolerance = None):
|
|
1896
2019
|
"""
|
|
@@ -1929,7 +2052,7 @@ class Spline(Manifold):
|
|
|
1929
2052
|
"""
|
|
1930
2053
|
return bspy._spline_fitting.torus(innerRadius, outerRadius, tolerance)
|
|
1931
2054
|
|
|
1932
|
-
def transform(self, matrix):
|
|
2055
|
+
def transform(self, matrix, matrixInverseTranspose = None):
|
|
1933
2056
|
"""
|
|
1934
2057
|
Transform a spline by the given matrix.
|
|
1935
2058
|
|
|
@@ -1938,6 +2061,9 @@ class Spline(Manifold):
|
|
|
1938
2061
|
matrix : array-like
|
|
1939
2062
|
An array of size `newNDep`x`nDep` that specifies the transform matrix.
|
|
1940
2063
|
|
|
2064
|
+
matrixInverseTranspose : `numpy.array`, optional
|
|
2065
|
+
The inverse transpose of matrix (not used for splines).
|
|
2066
|
+
|
|
1941
2067
|
Returns
|
|
1942
2068
|
-------
|
|
1943
2069
|
spline : `Spline`
|
|
@@ -2012,7 +2138,7 @@ class Spline(Manifold):
|
|
|
2012
2138
|
Parameters
|
|
2013
2139
|
----------
|
|
2014
2140
|
newDomain : array-like
|
|
2015
|
-
nInd x 2 array of the new
|
|
2141
|
+
nInd x 2 array of the new lower and upper bounds on each of the independent variables (same form as
|
|
2016
2142
|
returned from `domain`). If a bound is None or nan then the original bound (and knots) are left unchanged.
|
|
2017
2143
|
|
|
2018
2144
|
Returns
|
|
@@ -2027,6 +2153,29 @@ class Spline(Manifold):
|
|
|
2027
2153
|
"""
|
|
2028
2154
|
return bspy._spline_domain.trim(self, newDomain)
|
|
2029
2155
|
|
|
2156
|
+
def trimmed_range_bounds(self, domainBounds):
|
|
2157
|
+
"""
|
|
2158
|
+
Return the trimmed range bounds for the spline.
|
|
2159
|
+
|
|
2160
|
+
Parameters
|
|
2161
|
+
----------
|
|
2162
|
+
domainBounds : array-like
|
|
2163
|
+
An array with shape (nInd, 2) of lower and upper and lower bounds on each independent variable.
|
|
2164
|
+
|
|
2165
|
+
Returns
|
|
2166
|
+
-------
|
|
2167
|
+
trimmedSpline, rangeBounds : `Spline`, `np.array`
|
|
2168
|
+
A spline trimmed to the given domain bounds, and the range of the trimmed spline given as
|
|
2169
|
+
lower and upper bounds on each dependent variable.
|
|
2170
|
+
|
|
2171
|
+
See Also
|
|
2172
|
+
--------
|
|
2173
|
+
`trim` : Trim the domain of a spline.
|
|
2174
|
+
`range_bounds` : Return the range of a spline as lower and upper bounds on each of the
|
|
2175
|
+
dependent variables.
|
|
2176
|
+
"""
|
|
2177
|
+
return bspy._spline_domain.trimmed_range_bounds(self, domainBounds)
|
|
2178
|
+
|
|
2030
2179
|
def unfold(self, foldedInd, coefficientlessSpline):
|
|
2031
2180
|
"""
|
|
2032
2181
|
Unfold the coefficients of an original spline's indicated independent variables back into the spline, using the
|