bspy 1.2.2__tar.gz → 1.2.4__tar.gz
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-1.2.2 → bspy-1.2.4}/PKG-INFO +1 -1
- {bspy-1.2.2 → bspy-1.2.4}/bspy/_spline_intersection.py +110 -55
- {bspy-1.2.2 → bspy-1.2.4}/bspy/_spline_operations.py +3 -3
- {bspy-1.2.2 → bspy-1.2.4}/bspy.egg-info/PKG-INFO +1 -1
- {bspy-1.2.2 → bspy-1.2.4}/setup.cfg +1 -1
- {bspy-1.2.2 → bspy-1.2.4}/tests/test_bspy.py +45 -23
- {bspy-1.2.2 → bspy-1.2.4}/LICENSE +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/README.md +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/__init__.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/_spline_domain.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/_spline_evaluation.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/_spline_fitting.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/bspyApp.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/drawableSpline.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/spline.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy/splineOpenGLFrame.py +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy.egg-info/SOURCES.txt +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy.egg-info/dependency_links.txt +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy.egg-info/requires.txt +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/bspy.egg-info/top_level.txt +0 -0
- {bspy-1.2.2 → bspy-1.2.4}/pyproject.toml +0 -0
|
@@ -67,12 +67,15 @@ def zeros_using_interval_newton(self):
|
|
|
67
67
|
adjustedLeftStep = min(leftNewtonStep, rightNewtonStep) - 0.5 * epsilon
|
|
68
68
|
adjustedRightStep = max(leftNewtonStep, rightNewtonStep) + 0.5 * epsilon
|
|
69
69
|
if derivativeBounds[0] * derivativeBounds[1] >= 0.0: # Refine interval
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
projectedLeftStep = max(0.0, adjustedLeftStep)
|
|
71
|
+
projectedRightStep = min(1.0, adjustedRightStep)
|
|
72
|
+
if projectedLeftStep <= projectedRightStep:
|
|
73
|
+
if projectedRightStep - projectedLeftStep <= epsilon:
|
|
74
|
+
myZeros = [0.5 * (projectedLeftStep + projectedRightStep)]
|
|
75
|
+
else:
|
|
76
|
+
trimmedSpline = mySpline.trim(((projectedLeftStep, projectedRightStep),))
|
|
77
|
+
myZeros = refine(trimmedSpline, intervalSize, functionMax)
|
|
78
|
+
else:
|
|
76
79
|
return []
|
|
77
80
|
else: # . . . or split as needed
|
|
78
81
|
myZeros = []
|
|
@@ -215,8 +218,9 @@ def _refine_projected_polyhedron(interval):
|
|
|
215
218
|
# No roots in this interval.
|
|
216
219
|
return root, intervals
|
|
217
220
|
scale = max(scale, abs(coefsMin), abs(coefsMax))
|
|
218
|
-
|
|
219
|
-
|
|
221
|
+
newScale = scale * interval.scale
|
|
222
|
+
|
|
223
|
+
if newScale < evaluationEpsilon:
|
|
220
224
|
# Return the bounds of the interval within which the spline is zero.
|
|
221
225
|
root = (interval.intercept, interval.slope + interval.intercept)
|
|
222
226
|
else:
|
|
@@ -262,7 +266,6 @@ def _refine_projected_polyhedron(interval):
|
|
|
262
266
|
domain.append(xInterval)
|
|
263
267
|
|
|
264
268
|
if domain is not None:
|
|
265
|
-
newScale = scale * interval.scale
|
|
266
269
|
domain = np.array(domain).T
|
|
267
270
|
width = domain[1] - domain[0]
|
|
268
271
|
newSlope = np.multiply(width, interval.slope)
|
|
@@ -270,10 +273,9 @@ def _refine_projected_polyhedron(interval):
|
|
|
270
273
|
# one iteration past being less than sqrt(machineEpsilon) or simply less than epsilon.
|
|
271
274
|
if interval.atMachineEpsilon or newSlope.max() < epsilon:
|
|
272
275
|
newIntercept = np.multiply(domain[0], interval.slope) + interval.intercept
|
|
273
|
-
root = newIntercept + 0.5 * newSlope
|
|
274
276
|
# Double-check that we're at an actual zero (avoids boundary case).
|
|
275
|
-
if newScale * np.linalg.norm(spline(0.5 * (domain[0] + domain[1])))
|
|
276
|
-
root =
|
|
277
|
+
if newScale * np.linalg.norm(spline(0.5 * (domain[0] + domain[1]))) < evaluationEpsilon:
|
|
278
|
+
root = (newIntercept, newIntercept + newSlope)
|
|
277
279
|
else:
|
|
278
280
|
# Split domain in dimensions that aren't decreasing in width sufficiently.
|
|
279
281
|
domains = [domain]
|
|
@@ -296,7 +298,10 @@ def _refine_projected_polyhedron(interval):
|
|
|
296
298
|
newIntercept = np.multiply(domain[0], interval.slope) + interval.intercept
|
|
297
299
|
for i, w in zip(range(spline.nInd), width):
|
|
298
300
|
if w < machineEpsilon:
|
|
299
|
-
|
|
301
|
+
if domain[0, i] > machineEpsilon:
|
|
302
|
+
domain[0, i] = domain[1, i] - machineEpsilon
|
|
303
|
+
else:
|
|
304
|
+
domain[1, i] = domain[0, i] + machineEpsilon
|
|
300
305
|
newDomain = [None if s < epsilon else (0.0, 1.0) for s in newSlope]
|
|
301
306
|
intervals.append(Interval(spline.trim(domain.T).reparametrize(newDomain), newScale, newSlope, newIntercept, epsilon, np.dot(newSlope, newSlope) < machineEpsilon))
|
|
302
307
|
|
|
@@ -330,25 +335,48 @@ def zeros_using_projected_polyhedron(self, epsilon=None):
|
|
|
330
335
|
nextIntervals += newIntervals
|
|
331
336
|
intervals = nextIntervals
|
|
332
337
|
|
|
333
|
-
#
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
while
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
338
|
+
# Connect intervals of zeros that overlap.
|
|
339
|
+
gotOverlap = True
|
|
340
|
+
while gotOverlap:
|
|
341
|
+
gotOverlap = False
|
|
342
|
+
i = 0
|
|
343
|
+
rootCount = len(roots)
|
|
344
|
+
while i < rootCount:
|
|
345
|
+
iRoot = roots[i]
|
|
346
|
+
root = (iRoot[0].copy(), iRoot[1].copy()) # Temporary storage for expanded interval
|
|
347
|
+
j = i + 1
|
|
348
|
+
# Check for overlap with other intervals.
|
|
349
|
+
while j < rootCount:
|
|
350
|
+
jRoot = roots[j]
|
|
351
|
+
overlapped = True
|
|
352
|
+
for d in range(self.nInd):
|
|
353
|
+
if iRoot[0][d] < jRoot[1][d] + epsilon and jRoot[0][d] < iRoot[1][d] + epsilon:
|
|
354
|
+
root[0][d] = min(iRoot[0][d], jRoot[0][d])
|
|
355
|
+
root[1][d] = max(iRoot[1][d], jRoot[1][d])
|
|
356
|
+
else:
|
|
357
|
+
overlapped = False
|
|
358
|
+
break
|
|
359
|
+
if overlapped:
|
|
360
|
+
# For an overlapped interval, expand original interval and toss overlapping interval.
|
|
361
|
+
iRoot[0][:] = root[0]
|
|
362
|
+
iRoot[1][:] = root[1]
|
|
363
|
+
roots.pop(j)
|
|
364
|
+
rootCount -= 1
|
|
365
|
+
gotOverlap = True
|
|
366
|
+
else:
|
|
367
|
+
j += 1
|
|
368
|
+
i += 1
|
|
369
|
+
|
|
370
|
+
# Collapse intervals to points as appropriate.
|
|
371
|
+
for i in range(len(roots)):
|
|
372
|
+
iRoot = roots[i]
|
|
373
|
+
# If interval is small, just return a single value (not an interval).
|
|
374
|
+
if True: # Skip small interval test, since it's typically a shallow point, not a flat section. np.linalg.norm(iRoot[1] - iRoot[0]) < 2.0 * epsilon:
|
|
375
|
+
roots[i] = 0.5 * (iRoot[0] + iRoot[1])
|
|
348
376
|
|
|
349
377
|
# Sort roots if there's only one dimension.
|
|
350
378
|
if self.nInd == 1:
|
|
351
|
-
roots.sort(key=lambda root: root[0] if
|
|
379
|
+
roots.sort(key=lambda root: root[0] if isinstance(root, tuple) else root)
|
|
352
380
|
|
|
353
381
|
return roots
|
|
354
382
|
|
|
@@ -367,9 +395,15 @@ def contours(self):
|
|
|
367
395
|
# No contours for this spline.
|
|
368
396
|
return []
|
|
369
397
|
|
|
398
|
+
# Record self's original domain and then reparametrize self's domain to [0, 1]^nInd.
|
|
399
|
+
domain = self.domain().T
|
|
400
|
+
self = self.reparametrize(((0.0, 1.0),) * self.nInd)
|
|
401
|
+
|
|
402
|
+
# Construct self's tangents and normal.
|
|
370
403
|
tangents = []
|
|
371
404
|
for nInd in range(self.nInd):
|
|
372
405
|
tangents.append(self.differentiate(nInd))
|
|
406
|
+
normal = self.normal_spline((0, 1)) # We only need the first two indices
|
|
373
407
|
|
|
374
408
|
theta = np.sqrt(2) # Arbitrary starting value for theta (picked one in [0, pi/2] unlikely to be a stationary point)
|
|
375
409
|
# Try different theta values until no border or turning points are degenerate.
|
|
@@ -381,7 +415,6 @@ def contours(self):
|
|
|
381
415
|
abort = False
|
|
382
416
|
|
|
383
417
|
# Construct the turning point determinant.
|
|
384
|
-
normal = self.normal_spline((0, 1)) # We only need the first two indices
|
|
385
418
|
turningPointDeterminant = normal.dot((cosTheta, sinTheta))
|
|
386
419
|
|
|
387
420
|
# Find intersections with u and v boundaries.
|
|
@@ -496,6 +529,20 @@ def contours(self):
|
|
|
496
529
|
# (3) Take all the points found in Step (1) and Step (2) and order them by distance in the theta direction from the origin.
|
|
497
530
|
points.sort()
|
|
498
531
|
|
|
532
|
+
# Extra step not in the paper: Add a panel between two consecutive turning points to uniquely determine contours between them.
|
|
533
|
+
if len(points) > 1:
|
|
534
|
+
i = 0
|
|
535
|
+
previousPoint = points[i]
|
|
536
|
+
while i < len(points) - 1:
|
|
537
|
+
i += 1
|
|
538
|
+
point = points[i]
|
|
539
|
+
if not previousPoint.onBoundary and not point.onBoundary and point.d - previousPoint.d > epsilon:
|
|
540
|
+
# We have two consecutive turning points on separate panels.
|
|
541
|
+
# Insert a panel in between them, with the uvw value of None, since there is no zero associated.
|
|
542
|
+
points.insert(i, Point(0.5 * (previousPoint.d + point.d), 0.0, False, None))
|
|
543
|
+
i += 1
|
|
544
|
+
previousPoint = point
|
|
545
|
+
|
|
499
546
|
# (4) Initialize an ordered list of contours. No contours will be on the list at first.
|
|
500
547
|
currentContourPoints = [] # Holds contours currently being identified
|
|
501
548
|
contourPoints = [] # Hold contours already identified
|
|
@@ -541,29 +588,34 @@ def contours(self):
|
|
|
541
588
|
# the list. Go back to Step (5).
|
|
542
589
|
# First, construct panel, whose zeros lie along the panel boundary, u * cosTheta + v * sinTheta - d = 0.
|
|
543
590
|
panel.coefs[self.nDep] -= point.d
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
591
|
+
|
|
592
|
+
if point.uvw is None:
|
|
593
|
+
# For an inserted panel between two consecutive turning points, just find zeros along the panel.
|
|
594
|
+
panelPoints = panel.zeros()
|
|
595
|
+
else:
|
|
596
|
+
# Split panel below and above the known zero point.
|
|
597
|
+
# This avoids extra computation and the high-zero at the known zero point.
|
|
598
|
+
panelPoints = [point.uvw]
|
|
599
|
+
# To split the panel, we need to determine the offset from the point.
|
|
600
|
+
# Since the objective function (self) is zero and its derivative is zero at the point,
|
|
601
|
+
# we use second derivatives to determine when the objective function will likely grow
|
|
602
|
+
# evaluationEpsilon above zero again.
|
|
603
|
+
wrt = [0] * self.nInd
|
|
604
|
+
wrt[0] = 2
|
|
605
|
+
selfUU = self.derivative(wrt, point.uvw)
|
|
606
|
+
wrt[0] = 1
|
|
607
|
+
wrt[1] = 1
|
|
608
|
+
selfUV = self.derivative(wrt, point.uvw)
|
|
609
|
+
wrt[0] = 0
|
|
610
|
+
wrt[1] = 2
|
|
611
|
+
selfVV = self.derivative(wrt, point.uvw)
|
|
612
|
+
offset = np.sqrt(2.0 * evaluationEpsilon / \
|
|
613
|
+
np.linalg.norm(selfUU * sinTheta * sinTheta - 2.0 * selfUV * sinTheta * cosTheta + selfVV * cosTheta * cosTheta))
|
|
614
|
+
# Now, we can find the zeros of the split panel, checking to ensure each panel is within bounds first.
|
|
615
|
+
if point.uvw[0] + sinTheta * offset < 1.0 - epsilon and epsilon < point.uvw[1] - cosTheta * offset:
|
|
616
|
+
panelPoints += panel.trim(((point.uvw[0] + sinTheta * offset, 1.0), (0.0, point.uvw[1] - cosTheta * offset)) + ((None, None),) * (self.nInd - 2)).zeros()
|
|
617
|
+
if epsilon < point.uvw[0] - sinTheta * offset and point.uvw[1] + cosTheta * offset < 1.0 - epsilon:
|
|
618
|
+
panelPoints += panel.trim(((0.0, point.uvw[0] - sinTheta * offset), (point.uvw[1] + cosTheta * offset, 1.0)) + ((None, None),) * (self.nInd - 2)).zeros()
|
|
567
619
|
# Sort zero points by their position along the panel boundary (using vector orthogonal to its normal).
|
|
568
620
|
panelPoints.sort(key=lambda uvw: uvw[1] * cosTheta - uvw[0] * sinTheta)
|
|
569
621
|
# Add d back to prepare for next turning point.
|
|
@@ -571,7 +623,7 @@ def contours(self):
|
|
|
571
623
|
# Go through panel points, adding them to existing contours, creating new ones, or closing old ones.
|
|
572
624
|
adjustment = 0 # Adjust index after a contour point is added or removed.
|
|
573
625
|
for i, uvw in zip(range(len(panelPoints)), panelPoints):
|
|
574
|
-
if np.allclose(point.uvw, uvw):
|
|
626
|
+
if point.uvw is not None and np.allclose(point.uvw, uvw):
|
|
575
627
|
if point.det > 0.0:
|
|
576
628
|
# Insert the turning point twice (second one appears before the first one in the points list).
|
|
577
629
|
currentContourPoints.insert(i, [True, point.uvw]) # True indicates end point
|
|
@@ -594,6 +646,9 @@ def contours(self):
|
|
|
594
646
|
# Now we just need to create splines for those contours using the Spline.contour method.
|
|
595
647
|
splineContours = []
|
|
596
648
|
for points in contourPoints:
|
|
597
|
-
|
|
649
|
+
contour = bspy.spline.Spline.contour(self, points[1:]) # Skip endPoint boolean at start of points list
|
|
650
|
+
# Transform the contour to self's original domain.
|
|
651
|
+
contour.coefs = (contour.coefs.T * (domain[1] - domain[0]) + domain[0]).T
|
|
652
|
+
splineContours.append(contour)
|
|
598
653
|
|
|
599
654
|
return splineContours
|
|
@@ -573,10 +573,10 @@ def normal_spline(self, indices=None):
|
|
|
573
573
|
ord += order - 1 if ccm[i, j] and index != j else 0
|
|
574
574
|
newOrd = max(newOrd, ord)
|
|
575
575
|
newOrder.append(newOrd)
|
|
576
|
-
uniqueKnots, counts = np.unique(knots, return_counts=True)
|
|
576
|
+
uniqueKnots, counts = np.unique(knots[order - 1:self.nCoef[i] + 1], return_counts=True)
|
|
577
577
|
counts += newOrd - order + 1 # Because we're multiplying all the tangents, the knot elevation is one more
|
|
578
|
-
counts[0]
|
|
579
|
-
counts[-1]
|
|
578
|
+
counts[0] = newOrd # But not at the endpoints, which are full order as usual
|
|
579
|
+
counts[-1] = newOrd # But not at the endpoints, which are full order as usual
|
|
580
580
|
newKnots.append(np.repeat(uniqueKnots, counts))
|
|
581
581
|
# Also calculate the total number of coefficients, capturing how it progressively increases, and
|
|
582
582
|
# using that calculation to span uvw from the starting knot to the end for each variable.
|
|
@@ -592,7 +592,7 @@ def test_blossom():
|
|
|
592
592
|
maxError = max(maxError, np.linalg.norm(myCurve.coefs[:,i] - coef))
|
|
593
593
|
assert maxError <= np.finfo(float).eps
|
|
594
594
|
|
|
595
|
-
def
|
|
595
|
+
def test_contours():
|
|
596
596
|
maxError = 0.0
|
|
597
597
|
F = lambda x: (x[0] - x[2], x[1] - x[3], x[0]*x[0] + x[1]*x[1]/9.0 - 1.0 + x[2]*x[2] + x[3]*x[3]/9.0 - 1.0)
|
|
598
598
|
spline = bspy.Spline.contour(F, ((1.0, 0.0, 1.0, 0.0), (0.0, 3.0, 0.0, 3.0)))
|
|
@@ -601,6 +601,41 @@ def test_contour():
|
|
|
601
601
|
maxError = max(maxError, np.linalg.norm(F(x)))
|
|
602
602
|
assert maxError <= 0.05
|
|
603
603
|
|
|
604
|
+
maxError = 0.0
|
|
605
|
+
order = 3
|
|
606
|
+
knots = [0.0] * order + [1.0] * order
|
|
607
|
+
nCoef = len(knots) - order
|
|
608
|
+
spline = bspy.Spline(2, 1, (order, order), (nCoef, nCoef), (knots, knots), \
|
|
609
|
+
(((1.0, 0.0, 1.0), (0.0, -5.0, 0.0), (1.0, 0.0, 1.0)),))
|
|
610
|
+
contours = spline.contours()
|
|
611
|
+
for contour in contours:
|
|
612
|
+
for t in np.linspace(0.0, 1.0, 11):
|
|
613
|
+
uvw = contour((t,))
|
|
614
|
+
maxError = max(maxError, np.linalg.norm(spline(uvw)))
|
|
615
|
+
assert maxError <= 0.05
|
|
616
|
+
|
|
617
|
+
return # Comment this line to run the following lengthy test
|
|
618
|
+
|
|
619
|
+
maxError = 0.0
|
|
620
|
+
F = lambda u , v : (u ** 2 + (v - 3/4) ** 2 - 1/25) * \
|
|
621
|
+
((u - 2/5) ** 2 + (v - 3/5) ** 2 - 1/25) * \
|
|
622
|
+
(u ** 2 + (v - 3/2) ** 2 - 25/16) * \
|
|
623
|
+
((u - 1) ** 2 + (v - 3/10) ** 2 - 1/25)
|
|
624
|
+
order = 9
|
|
625
|
+
knots = [0.0] * order + [1.0] * order
|
|
626
|
+
nCoef = order
|
|
627
|
+
points = []
|
|
628
|
+
for u in np.linspace(0.0, 1.0, nCoef):
|
|
629
|
+
for v in np.linspace(0.0, 1.0, nCoef):
|
|
630
|
+
points.append((u, v, F(u, v)))
|
|
631
|
+
spline = bspy.Spline.least_squares(2, 1, (order, order), points, (knots, knots))
|
|
632
|
+
contours = spline.contours()
|
|
633
|
+
for contour in contours:
|
|
634
|
+
for t in np.linspace(0.0, 1.0, 11):
|
|
635
|
+
uvw = contour((t,))
|
|
636
|
+
maxError = max(maxError, np.linalg.norm(spline(uvw)))
|
|
637
|
+
assert maxError <= 0.05
|
|
638
|
+
|
|
604
639
|
def test_contract():
|
|
605
640
|
maxError = 0.0
|
|
606
641
|
contracted = mySurface.contract([.25, None])
|
|
@@ -804,32 +839,14 @@ def test_integral():
|
|
|
804
839
|
assert maxError <= np.finfo(float).eps
|
|
805
840
|
|
|
806
841
|
def test_intersect():
|
|
842
|
+
|
|
843
|
+
return # Comment this line to run the following additional really lengthy test
|
|
844
|
+
|
|
807
845
|
maxError = 0.0
|
|
808
846
|
F = lambda u , v : (u ** 2 + (v - 3/4) ** 2 - 1/25) * \
|
|
809
847
|
((u - 2/5) ** 2 + (v - 3/5) ** 2 - 1/25) * \
|
|
810
848
|
(u ** 2 + (v - 3/2) ** 2 - 25/16) * \
|
|
811
849
|
((u - 1) ** 2 + (v - 3/10) ** 2 - 1/25)
|
|
812
|
-
|
|
813
|
-
order = 9
|
|
814
|
-
knots = [0.0] * order + [1.0] * order
|
|
815
|
-
nCoef = order
|
|
816
|
-
points = []
|
|
817
|
-
for u in np.linspace(0.0, 1.0, nCoef):
|
|
818
|
-
for v in np.linspace(0.0, 1.0, nCoef):
|
|
819
|
-
points.append((u, v, F(u, v)))
|
|
820
|
-
spline = bspy.Spline.least_squares(2, 1, (order, order), points, (knots, knots))
|
|
821
|
-
|
|
822
|
-
return # Comment this line to run the following lengthy test
|
|
823
|
-
|
|
824
|
-
contours = spline.contours()
|
|
825
|
-
for contour in contours:
|
|
826
|
-
for t in np.linspace(0.0, 1.0, 11):
|
|
827
|
-
uvw = contour((t,))
|
|
828
|
-
maxError = max(maxError, np.linalg.norm(spline(uvw)))
|
|
829
|
-
assert maxError <= np.finfo(float).eps ** 0.2
|
|
830
|
-
|
|
831
|
-
return # Comment this line to run the following additional really lengthy test
|
|
832
|
-
|
|
833
850
|
order = 9
|
|
834
851
|
knots = [0.0] * order + [1.0] * order
|
|
835
852
|
nCoef = order
|
|
@@ -1060,10 +1077,15 @@ def test_zeros():
|
|
|
1060
1077
|
assert expectedRootCount == len(roots)
|
|
1061
1078
|
for root in roots:
|
|
1062
1079
|
value = spline(root)
|
|
1063
|
-
assert np.dot(value, value) < tolerance
|
|
1080
|
+
assert np.dot(value, value) < np.sqrt(tolerance)
|
|
1064
1081
|
|
|
1065
1082
|
tolerance = 1.0e-14
|
|
1066
1083
|
|
|
1084
|
+
spline = bspy.Spline(1, 1, (3,), (3,), [[0., 0., 0., 1., 1., 1.]], [[-1.2, -0.2, 0.8]], 0.0, {})
|
|
1085
|
+
expectedRoots = (0.6,)
|
|
1086
|
+
roots = spline.zeros()
|
|
1087
|
+
check_1D_roots(expectedRoots, roots, tolerance)
|
|
1088
|
+
|
|
1067
1089
|
spline = bspy.Spline(1, 1, (4,), (4,), ((0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0),), ((1.0, -2.0, -2.0, 1.0),))
|
|
1068
1090
|
expectedRoots = (0.12732200375003502, 0.8726779962499649)
|
|
1069
1091
|
roots = spline.zeros()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|