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_operations.py
CHANGED
|
@@ -105,9 +105,9 @@ def confine(self, range_bounds):
|
|
|
105
105
|
intersections.sort(key=lambda intersection: intersection[0])
|
|
106
106
|
|
|
107
107
|
# Remove repeat points at start and end.
|
|
108
|
-
|
|
108
|
+
while intersections[1][0] - intersections[0][0] < epsilon:
|
|
109
109
|
del intersections[1]
|
|
110
|
-
|
|
110
|
+
while intersections[-1][0] - intersections[-2][0] < epsilon:
|
|
111
111
|
del intersections[-2]
|
|
112
112
|
|
|
113
113
|
# Insert order-1 knots at each intersection point.
|
|
@@ -308,6 +308,8 @@ def multiplyAndConvolve(self, other, indMap = None, productType = 'S'):
|
|
|
308
308
|
# Construct new spline parameters.
|
|
309
309
|
nInd = self.nInd + other.nInd
|
|
310
310
|
nDep = other.nDep
|
|
311
|
+
if productType == 'C' and nDep == 2:
|
|
312
|
+
nDep = 1
|
|
311
313
|
order = [*self.order, *other.order]
|
|
312
314
|
nCoef = [*self.nCoef, *other.nCoef]
|
|
313
315
|
knots = [*self.knots, *other.knots]
|
|
@@ -628,74 +630,94 @@ def multiplyAndConvolve(self, other, indMap = None, productType = 'S'):
|
|
|
628
630
|
|
|
629
631
|
return type(self)(nInd, nDep, order, nCoef, knots, coefs, self.metadata)
|
|
630
632
|
|
|
631
|
-
# Return a matrix of booleans whose [i,j] value indicates if self's partial wrt variable i depends on variable j.
|
|
632
|
-
def _cross_correlation_matrix(self):
|
|
633
|
-
ccm = np.empty((self.nInd, self.nInd), bool)
|
|
634
|
-
for i in range(self.nInd - 1):
|
|
635
|
-
tangent = self.differentiate(i)
|
|
636
|
-
totalCoefs = tangent.coefs.size // tangent.nDep
|
|
637
|
-
ccm[i, i] = True
|
|
638
|
-
for j in range(i + 1, self.nInd):
|
|
639
|
-
coefs = np.moveaxis(tangent.coefs, (0, j + 1), (-1, -2))
|
|
640
|
-
coefs = coefs.reshape(totalCoefs // tangent.nCoef[j], tangent.nCoef[j], tangent.nDep)
|
|
641
|
-
match = True
|
|
642
|
-
for row in coefs:
|
|
643
|
-
first = row[0]
|
|
644
|
-
for point in row[1:]:
|
|
645
|
-
match = np.allclose(point, first)
|
|
646
|
-
if not match:
|
|
647
|
-
break
|
|
648
|
-
if not match:
|
|
649
|
-
break
|
|
650
|
-
ccm[i, j] = ccm[j, i] = not match
|
|
651
|
-
ccm[-1, -1] = True
|
|
652
|
-
return ccm
|
|
653
|
-
|
|
654
633
|
def normal_spline(self, indices=None):
|
|
655
|
-
if abs(self.nInd - self.nDep) != 1: raise ValueError("The number of independent variables must be
|
|
634
|
+
if abs(self.nInd - self.nDep) != 1: raise ValueError("The number of independent variables must be different than the number of dependent variables.")
|
|
656
635
|
|
|
657
|
-
# Construct order
|
|
636
|
+
# Construct order, nCoef, knots, and sample values for generalized cross product of the tangent space.
|
|
658
637
|
newOrder = []
|
|
659
638
|
newKnots = []
|
|
660
639
|
uvwValues = []
|
|
661
640
|
nCoefs = []
|
|
662
641
|
totalCoefs = [1]
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
642
|
+
for nInd in range(self.nInd):
|
|
643
|
+
knots = None
|
|
644
|
+
counts = None
|
|
645
|
+
maxOrder = 0
|
|
646
|
+
startInd = 0
|
|
647
|
+
endInd = 0
|
|
648
|
+
# First, collect the order, knots, and number of relevant columns for this independent variable.
|
|
649
|
+
for row in self.block:
|
|
650
|
+
rowInd = 0
|
|
651
|
+
for spline in row:
|
|
652
|
+
if rowInd <= nInd < rowInd + spline.nInd:
|
|
653
|
+
ind = nInd - rowInd
|
|
654
|
+
order = spline.order[ind]
|
|
655
|
+
k, c = np.unique(spline.knots[ind][order-1:spline.nCoef[ind]+1], return_counts=True)
|
|
656
|
+
if knots:
|
|
657
|
+
if maxOrder < order:
|
|
658
|
+
counts += order - maxOrder
|
|
659
|
+
maxOrder = order
|
|
660
|
+
endInd = max(endInd, rowInd + spline.nInd)
|
|
661
|
+
for knot, count in zip(k[1:-1], c[1:-1]):
|
|
662
|
+
ix = np.searchsorted(knots, knot)
|
|
663
|
+
if knots[ix] == knot:
|
|
664
|
+
counts[ix] = max(counts[ix], count + maxOrder - order)
|
|
665
|
+
else:
|
|
666
|
+
knots = np.insert(knots, ix, knot)
|
|
667
|
+
counts = np.insert(counts, ix, count + maxOrder - order)
|
|
668
|
+
else:
|
|
669
|
+
knots = k
|
|
670
|
+
counts = c
|
|
671
|
+
maxOrder = order
|
|
672
|
+
startInd = rowInd
|
|
673
|
+
endInd = rowInd + spline.nInd
|
|
674
|
+
|
|
675
|
+
break
|
|
676
|
+
|
|
677
|
+
rowInd += spline.nInd
|
|
678
|
+
|
|
679
|
+
# Next, calculate the order of the normal for this independent variable.
|
|
666
680
|
# Note that the total order will be one less than usual, because one of
|
|
667
681
|
# the tangents is the derivative with respect to that independent variable.
|
|
668
|
-
newOrd = 0
|
|
669
682
|
if self.nInd < self.nDep:
|
|
670
683
|
# If this normal involves all tangents, simply add the degree of each,
|
|
671
|
-
# so long as that tangent contains the independent variable.
|
|
672
|
-
|
|
673
|
-
newOrd += order - 1 if ccm[i, j] else 0
|
|
684
|
+
# so long as that tangent contains the independent variable.
|
|
685
|
+
order = (maxOrder - 1) * (endInd - startInd)
|
|
674
686
|
else:
|
|
675
687
|
# If this normal doesn't involve all tangents, find the max order of
|
|
676
688
|
# each returned combination (as defined by the indices).
|
|
677
|
-
|
|
689
|
+
order = 0
|
|
690
|
+
for index in range(startInd, endInd) if indices is None else indices:
|
|
678
691
|
# The order will be one larger if this independent variable's tangent is excluded by the index.
|
|
679
|
-
ord = 0 if index !=
|
|
692
|
+
ord = 0 if index != nInd else 1
|
|
680
693
|
# Add the degree of each tangent, so long as that tangent contains the
|
|
681
694
|
# independent variable and is not excluded by the index.
|
|
682
|
-
for
|
|
683
|
-
ord +=
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
counts
|
|
689
|
-
counts[
|
|
690
|
-
|
|
695
|
+
for ind in range(startInd, endInd):
|
|
696
|
+
ord += maxOrder - 1 if index != ind else 0
|
|
697
|
+
order = max(order, ord)
|
|
698
|
+
|
|
699
|
+
# Now, record the order of this independent variable and adjust the knot counts.
|
|
700
|
+
newOrder.append(order)
|
|
701
|
+
counts += order - maxOrder + 1 # Because we're multiplying all the tangents, the knot elevation is one more
|
|
702
|
+
counts[0] = order # But not at the endpoints, which are full order as usual
|
|
703
|
+
counts[-1] = order # But not at the endpoints, which are full order as usual
|
|
704
|
+
newKnots.append(np.repeat(knots, counts))
|
|
705
|
+
|
|
691
706
|
# Also calculate the total number of coefficients, capturing how it progressively increases, and
|
|
692
707
|
# using that calculation to span uvw from the starting knot to the end for each variable.
|
|
693
708
|
nCoef = len(newKnots[-1]) - newOrder[-1]
|
|
694
709
|
totalCoefs.append(totalCoefs[-1] * nCoef)
|
|
695
|
-
|
|
710
|
+
knotAverages = bspy.Spline(1, 0, [order], [nCoef], [newKnots[-1]], []).greville()
|
|
711
|
+
for iKnot in range(1, len(knotAverages) - 1):
|
|
712
|
+
if knotAverages[iKnot] == knotAverages[iKnot + 1]:
|
|
713
|
+
knotAverages[iKnot] = 0.5 * (knotAverages[iKnot - 1] + knotAverages[iKnot])
|
|
714
|
+
knotAverages[iKnot + 1] = 0.5 * (knotAverages[iKnot + 1] + knotAverages[iKnot + 2])
|
|
715
|
+
uvwValues.append(knotAverages)
|
|
696
716
|
nCoefs.append(nCoef)
|
|
717
|
+
|
|
718
|
+
# Construct data points for normal.
|
|
697
719
|
points = []
|
|
698
|
-
ijk = [0
|
|
720
|
+
ijk = [0] * self.nInd
|
|
699
721
|
for i in range(totalCoefs[-1]):
|
|
700
722
|
uvw = [uvwValues[j][k] for j, k in enumerate(ijk)]
|
|
701
723
|
points.append(self.normal(uvw, False, indices))
|
|
@@ -709,8 +731,7 @@ def normal_spline(self, indices=None):
|
|
|
709
731
|
nCoefs.reverse()
|
|
710
732
|
points = np.reshape(points, [nDep] + nCoefs)
|
|
711
733
|
points = np.transpose(points, [0] + list(range(self.nInd, 0, -1)))
|
|
712
|
-
return bspy.Spline.least_squares(uvwValues, points, order = newOrder, knots = newKnots
|
|
713
|
-
# return bspy.Spline.least_squares(self.nInd, nDep, newOrder, points, newKnots, 0, self.metadata)
|
|
734
|
+
return bspy.Spline.least_squares(uvwValues, points, order = newOrder, knots = newKnots)
|
|
714
735
|
|
|
715
736
|
def rotate(self, vector, angle):
|
|
716
737
|
vector = np.atleast_1d(vector)
|