在python中沿参数化曲线查找给定弧距的位置

时间:2012-04-26 06:05:18

标签: python geometry distance

我有一个参数化的2D曲线: (x,y)= f(t)

函数f是任意的但可微分的,因此我可以使用标准公式计算出任意点沿曲线的微分弧长ds。通过在数值上积分差分弧长公式,我还可以从曲线的起点到任意点获得总弧长S(t)。我可以控制计算的准确性。

我想找到从曲线的开头找到总弧长S = D的点(x,y)。如果实现是在python中更好。我将这样做很多次,它是计算应用程序的一部分,我需要严格控制精度和收敛的信心。

我不知道根寻找是否是最好的方法,但我的问题相当于g(t)= S(t)-D的根发现问题,其中函数g(t)不是完全评估是因为S(t)不是。不精确的功能评估不仅会影响准确性,还会影响g(t)的单调性。我从一开始就尝试进行紧密的数值积分,但这需要永远。我非常肯定会收敛到我所要求的容忍度,根寻找算法必须随着时间的推移懒洋洋地控制积分精度,要求在开始时进行粗略的评估,并在根算法收敛时提高准确性。

有这样的东西随时可用吗?有没有其他聪明的方法来做到这一点?

感谢帮助

2 个答案:

答案 0 :(得分:2)

您可以发布一些代码,并告诉我们它有什么问题吗?

这是我的版本,计算t其中S(t)== D:

from scipy.integrate import quad
from scipy.optimize import fsolve
from math import cos, sin, sqrt, pi

def circle_diff(t):
    dx = -sin(t)
    dy = cos(t)
    return sqrt(dx*dx+dy*dy)

def sin_diff(t):
    dx = 1
    dy = cos(t)
    return sqrt(dx*dx+dy*dy)

def curve_length(t0, S, length):
    return quad(S, 0, t0)[0] - length

def solve_t(curve_diff, length):    
    return fsolve(curve_length, 0.0, (curve_diff, length))[0]

print solve_t(circle_diff, 2*pi)
print solve_t(sin_diff, 7.640395578)

答案 1 :(得分:0)

好的,@ HYRY,这是一个很大程度上基于你的代码片段。你给了我成功所需的提示:使用“quad”而不是“quadrature”。所以我至少会投票给你答案,但我想补充一下这个故事。

首先,你的代码运行得很快,但是大约有五个地方没有我追求的精度。我在你的例子中添加了quadtol和opttol,试图说明正交和根寻找精度的相互作用。我还添加了一个基于默认高容差的循环来暴露速度差异。

罪的例子比精确度上的圆要敏感得多。我还添加了一个paremerized曲线,其弧长由超几何函数给出,并且“brentq”选项被注释掉,因为fsolve在这个例子中失败,并且在这个任务中任何甚至brentq都相等或更好。

“正交”是缓慢的,但表现出预期的行为:根寻找速度,准确度和成功随正交公差变化。

相比之下,“quad”似乎忽略了所要求的容差并始终产生更准确的答案。这种未经请求的准确性会令人讨厌或邀请解释,除了它在例子上的工作速度也很快,我不确定我的问题是否有趣。谢谢!

from scipy.integrate import quad, quadrature
from scipy.optimize import fsolve, brentq 
from math import cos, sin, sqrt, pi, pow

def circle_diff(t): 
    dx = -sin(t) 
    dy = cos(t) 
    return sqrt(dx*dx+dy*dy) 

def sin_diff(t): 
    dx = 1 
    dy = cos(t) 
    return sqrt(dx*dx+dy*dy) 

def hypergeom_diff(t):
    """ y = t^5 x = t^3 """
    dx = 3*t*t
    dy = 5*pow(t,4)
    return sqrt(dx*dx+dy*dy)

def curve_length(t0, S, length,quadtol): 
    integral = quad(S, 0, t0,epsabs=quadtol,epsrel=quadtol)
    #integral = quadrature(S, 0, t0,tol=quadtol,rtol=quadtol, vec_func = False)
    return integral[0] - length 

def solve_t(curve_diff, length,opttol=1.e-15,quadtol=1e-10):
    return fsolve(curve_length, 0.0, (curve_diff, length,quadtol), xtol = opttol)[0] 
    #return brentq(curve_length, 0.0, 3.2*pi,(curve_diff, length, quadtol), rtol = opttol)

for i in range(1000):
    y = solve_t(circle_diff, 2*pi)

print 2*pi
print solve_t(circle_diff, 2*pi)
print solve_t(sin_diff, 7.640395578)
print solve_t(circle_diff, 2*pi,opttol=1e-5,quadtol=1e-3)
print solve_t(sin_diff, 7.640395578,opttol = 1e-12,quadtol=1e-6)
print "hypergeom"
print solve_t(hypergeom_diff, 2.0,opttol = 1e-12,quadtol=1e-12)
print solve_t(hypergeom_diff, 2.0,opttol = 1e-12,quadtol=1e-6)