Python 开放均匀 B 样条曲线中的 ZeroDivisionError
Python ZeroDivisionError in Open Uniform B-Spline Curve
所以我正在 python 中实现 B 样条曲线(我知道有现有的库,但我想自己做)并且它适用于非开放式统一 B-样条曲线如下所示:
右侧显示基函数(Cox de Boor 的递归公式)计算的图表与该视频中显示的内容非常吻合,唯一的区别是控制点的数量。 (https://www.youtube.com/watch?v=qhQrRCJ-mVg&t=2136):
一旦我尝试将其设为开放的均匀 B 样条曲线。我期待这样的图表 (https://www.youtube.com/watch?v=qhQrRCJ-mVg&t=2501):
但是,我得到了一个 ZeroDivisionError:
a = ((t - knotVector[i]) / (knotVector[i + j] - knotVector[i]) * CoxDeBoorRecursion(i, j - 1, t, knotVector))
ZeroDivisionError: float division by zero
其中结向量定义为 [0, 0, 0, 1, 2, 3, 3, 3]
,如视频 https://www.youtube.com/watch?v=qhQrRCJ-mVg&t=2460 中所示。
这是我的代码:
def UniformBSpline(t, controlPoints, open=False):
sumX, sumY = 0, 0
degree = 2
knotVector = [x for x in range(len(controlPoints) + 2 + degree)]
if open:
knotVector = knotVector[0:len(controlPoints)]
for _ in range(degree):
knotVector.insert(0, knotVector[0])
knotVector.insert(-1, knotVector[-1])
for i in range(len(controlPoints)):
sumX += CoxDeBoorRecursion(i, degree, t, knotVector) * controlPoints[i].x
sumY += CoxDeBoorRecursion(i, degree, t, knotVector) * controlPoints[i].y
return sumX, sumY
def CoxDeBoorRecursion(i, j, t, knotVector):
if j == 0:
return 1 if knotVector[i] <= t < knotVector[i+1] else 0
a = ((t - knotVector[i]) / (knotVector[i + j] - knotVector[i]) * CoxDeBoorRecursion(i, j - 1, t, knotVector))
b = (((knotVector[i + j + 1] - t)/(knotVector[i + j + 1] - knotVector[i + 1])) * CoxDeBoorRecursion(i + 1, j - 1, t, knotVector))
return a + b
这似乎是我正在使用的函数中的一个问题,该函数定义为:
我该如何解决这个问题?对于 Math StackExchange,这可能是一个更好的问题吗?
您的代码中有两个错误:
均匀闭合 B 样条曲线的结向量应该计算到段数,而不是控制点数。段数是控制点数减去度数。也就是说,如果你有一个 2 阶样条的三个点(即,一个简单的贝塞尔曲线),你会得到一个单一的线段。对于每一个额外的点,你会得到一个更多的部分。因此,结向量必须是:
if open:
knotVector = [x for x in range(len(controlPoints) - degree + 1)]
for _ in range(degree):
knotVector.insert(0, knotVector[0])
knotVector.insert(-1, knotVector[-1])
对于四个控制点,这会给你
[0, 0, 0, 1, 2, 2, 2]
您对关闭的案例有类似的问题。这就是为什么样条曲线的角位于 (0, 0)。不过还没有具体检查过。
第二个问题:如果节点重复,权重的除数可以为零。如果是这种情况,就忽略那部分权重:
d1 = (knotVector[i + j] - knotVector[i])
a = ((t - knotVector[i]) / d1 * CoxDeBoorRecursion(i, j - 1, t, knotVector)) if d1 > 0 else 0
d2 = (knotVector[i + j + 1] - knotVector[i + 1])
b = (((knotVector[i + j + 1] - t)/d2) * CoxDeBoorRecursion(i + 1, j - 1, t, knotVector)) if d2 > 0 else 0
您也可以将该部分提取到一个单独的函数中,就像 Wikipedia article 那样(函数 ω)。
所以我正在 python 中实现 B 样条曲线(我知道有现有的库,但我想自己做)并且它适用于非开放式统一 B-样条曲线如下所示:
右侧显示基函数(Cox de Boor 的递归公式)计算的图表与该视频中显示的内容非常吻合,唯一的区别是控制点的数量。 (https://www.youtube.com/watch?v=qhQrRCJ-mVg&t=2136):
一旦我尝试将其设为开放的均匀 B 样条曲线。我期待这样的图表 (https://www.youtube.com/watch?v=qhQrRCJ-mVg&t=2501):
但是,我得到了一个 ZeroDivisionError:
a = ((t - knotVector[i]) / (knotVector[i + j] - knotVector[i]) * CoxDeBoorRecursion(i, j - 1, t, knotVector))
ZeroDivisionError: float division by zero
其中结向量定义为 [0, 0, 0, 1, 2, 3, 3, 3]
,如视频 https://www.youtube.com/watch?v=qhQrRCJ-mVg&t=2460 中所示。
这是我的代码:
def UniformBSpline(t, controlPoints, open=False):
sumX, sumY = 0, 0
degree = 2
knotVector = [x for x in range(len(controlPoints) + 2 + degree)]
if open:
knotVector = knotVector[0:len(controlPoints)]
for _ in range(degree):
knotVector.insert(0, knotVector[0])
knotVector.insert(-1, knotVector[-1])
for i in range(len(controlPoints)):
sumX += CoxDeBoorRecursion(i, degree, t, knotVector) * controlPoints[i].x
sumY += CoxDeBoorRecursion(i, degree, t, knotVector) * controlPoints[i].y
return sumX, sumY
def CoxDeBoorRecursion(i, j, t, knotVector):
if j == 0:
return 1 if knotVector[i] <= t < knotVector[i+1] else 0
a = ((t - knotVector[i]) / (knotVector[i + j] - knotVector[i]) * CoxDeBoorRecursion(i, j - 1, t, knotVector))
b = (((knotVector[i + j + 1] - t)/(knotVector[i + j + 1] - knotVector[i + 1])) * CoxDeBoorRecursion(i + 1, j - 1, t, knotVector))
return a + b
这似乎是我正在使用的函数中的一个问题,该函数定义为:
我该如何解决这个问题?对于 Math StackExchange,这可能是一个更好的问题吗?
您的代码中有两个错误:
均匀闭合 B 样条曲线的结向量应该计算到段数,而不是控制点数。段数是控制点数减去度数。也就是说,如果你有一个 2 阶样条的三个点(即,一个简单的贝塞尔曲线),你会得到一个单一的线段。对于每一个额外的点,你会得到一个更多的部分。因此,结向量必须是:
if open:
knotVector = [x for x in range(len(controlPoints) - degree + 1)]
for _ in range(degree):
knotVector.insert(0, knotVector[0])
knotVector.insert(-1, knotVector[-1])
对于四个控制点,这会给你
[0, 0, 0, 1, 2, 2, 2]
您对关闭的案例有类似的问题。这就是为什么样条曲线的角位于 (0, 0)。不过还没有具体检查过。
第二个问题:如果节点重复,权重的除数可以为零。如果是这种情况,就忽略那部分权重:
d1 = (knotVector[i + j] - knotVector[i])
a = ((t - knotVector[i]) / d1 * CoxDeBoorRecursion(i, j - 1, t, knotVector)) if d1 > 0 else 0
d2 = (knotVector[i + j + 1] - knotVector[i + 1])
b = (((knotVector[i + j + 1] - t)/d2) * CoxDeBoorRecursion(i + 1, j - 1, t, knotVector)) if d2 > 0 else 0
您也可以将该部分提取到一个单独的函数中,就像 Wikipedia article 那样(函数 ω)。