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

在python中沿参数化曲线查找给定弧距离的位置,python,geometry,distance,Python,Geometry,Distance,我有一条参数化的二维曲线: (x,y)=f(t) 函数f是任意的,但可微,因此我可以用标准公式计算出沿曲线任意点的微分弧长ds。通过数值积分微分弧长公式,我还可以得到从起点到曲线上任意点的总弧长S(t)。我可以控制计算的准确性 我想找到一个点(x,y),它的总弧长是S=D,从曲线的开始。如果用python实现,效果会更好。我会做很多次,这是一个计算应用程序的一部分,我需要严格控制精度和一些收敛的信心 我不知道根查找是否是最好的方法,但我的问题相当于g(t)=S(t)-D的根查找问题,其中函数g(

我有一条参数化的二维曲线: (x,y)=f(t)

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

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

我不知道根查找是否是最好的方法,但我的问题相当于g(t)=S(t)-D的根查找问题,其中函数g(t)没有精确计算,因为S(t)没有。不精确函数求值不仅影响精度,而且影响g(t)的单调性。我从一开始就试着做严格的数值积分,但这需要很长时间。我很确定,要收敛到我所要求的容差,根查找算法必须在进行时惰性地控制积分精度,在开始时要求草率的计算,并随着根算法的收敛而提高精度

有现成的吗?有没有其他聪明的方法


感谢您的帮助

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

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


好的,@HYRY,这是一段主要基于您的代码片段。你给了我成功所需的提示:使用“quad”而不是“quadrature”。所以我至少会投票支持你的答案,但我想补充一点

首先,您的代码运行速度很快,但比我所追求的精度差了五位左右。我在您的示例中添加了quadtol和optol,试图说明求积和求根精度的相互作用。我还添加了一个基于默认高公差的循环,以暴露速度差异

sin示例在精度上比圆更敏感。我还添加了一条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)

只是想了解情况:时间对吗?您知道的是:开始时间、开始位置、结束时间和结束曲线长度(t0、x0、y0、tF、S(tF)=D)。您希望找到该位移的最终位置(xF,yF)。您是否能够将曲线作为显式函数写入x,即:y=h(x)?Hi-fraxel:t只是一个虚拟变量,用于参数化曲线。我不认为把它当作时间有什么坏处。顺便说一句,我认为HYRY帮了我的忙,他发布的代码正好说明了我的方法。但是。。你能消除t并得到x中的显式函数吗,即:y=h(x)?(想必你可以)如果是这样的话,我可能有一个很酷的方法来做。不,这对我来说不是一个常见的情况。例如,参考圆圈。此外,这必须经常与各种形状,以最低限度的特殊情况。因此,我认为参数化路径上的标准方法可能是一条出路。
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)