C++实现第一类贝塞尔函数

本文介绍了在实习中遇到的复数域下半整阶第一类贝塞尔函数的实现问题。由于递推公式求解存在精度不足的问题,作者选择了直接实现贝塞尔函数的定义公式来确保计算精确。通过求导递推公式,确保了贝塞尔函数的精确计算,特别是对于特殊值J(1/2)和J(-1/2)。函数能够处理任意大小的n值,包括负数和小数,且对于z为复数的情况(将虚部设为0)也适用。在实际应用中,发现循环次数设为15即可达到收敛,优于原先的100次循环设定。
摘要由CSDN通过智能技术生成
第一类贝塞尔函数

这几天实习碰到了半整阶的第一类的贝塞尔函数,而且是复数域的。最开始在网上查资料是用递推公式求解的,因为在计算特殊值J(1/2)和J(-1/2)的过程中会省略掉很多项并不精确,且在递推过程中也会省略很多项,导致最终递推得到的结果并不精确,故而又改为实现贝塞尔函数的定义函数。
定义公式:
在这里插入图片描述
递推公式:
在这里插入图片描述

求导递推公式:
对贝塞尔函数求导是用的如下递推公式,需要保证贝塞尔函数一定要算的精确,求导结果才能精确。在这里插入图片描述
该函数的n可以取任意值,包括负数、小数。因为项目需要,z为复数,把虚部设为0,同样适用于实数。

std::complex<double
求两条贝塞尔曲线的交点,可以通过求解方程组来实现。假设两条贝塞尔曲线分别为 $B_1(t)$ 和 $B_2(t)$,则它们的交点满足以下方程组: $$ \begin{cases} B_1(t_1) - B_2(t_2) = 0\\ B_1'(t_1) \cdot B_2''(t_2) - B_2'(t_2) \cdot B_1''(t_1) = 0 \end{cases} $$ 其中 $B_i(t)$ 表示第 $i$ 条贝塞尔曲线在参数 $t$ 处的点,$B_i'(t)$ 表示第 $i$ 条贝塞尔曲线在参数 $t$ 处的切向量,$B_i''(t)$ 表示第 $i$ 条贝塞尔曲线在参数 $t$ 处的二导向量。 具体实现可以采用牛顿迭代法来求解方程组的根。 以下是一个简单的 C++ 实现: ```cpp #include <iostream> #include <cmath> using namespace std; const double EPSILON = 1e-6; // 停止迭代的精度要求 struct Point { double x; double y; }; struct BezierCurve { Point p0; Point p1; Point p2; Point p3; }; Point bezier(BezierCurve curve, double t) { double u = 1 - t; double uu = u * u; double uuu = uu * u; double tt = t * t; double ttt = tt * t; Point p; p.x = uuu * curve.p0.x + 3 * uu * t * curve.p1.x + 3 * u * tt * curve.p2.x + ttt * curve.p3.x; p.y = uuu * curve.p0.y + 3 * uu * t * curve.p1.y + 3 * u * tt * curve.p2.y + ttt * curve.p3.y; return p; } Point bezierDerivative(BezierCurve curve, double t) { double u = 1 - t; double uu = u * u; double tt = t * t; Point p; p.x = 3 * uu * (curve.p1.x - curve.p0.x) + 6 * u * t * (curve.p2.x - curve.p1.x) + 3 * tt * (curve.p3.x - curve.p2.x); p.y = 3 * uu * (curve.p1.y - curve.p0.y) + 6 * u * t * (curve.p2.y - curve.p1.y) + 3 * tt * (curve.p3.y - curve.p2.y); return p; } Point bezierSecondDerivative(BezierCurve curve, double t) { double u = 1 - t; Point p; p.x = 6 * u * (curve.p2.x - 2 * curve.p1.x + curve.p0.x) + 6 * t * (curve.p3.x - 2 * curve.p2.x + curve.p1.x); p.y = 6 * u * (curve.p2.y - 2 * curve.p1.y + curve.p0.y) + 6 * t * (curve.p3.y - 2 * curve.p2.y + curve.p1.y); return p; } double distance(Point a, Point b) { double dx = a.x - b.x; double dy = a.y - b.y; return sqrt(dx * dx + dy * dy); } Point findIntersection(BezierCurve curve1, BezierCurve curve2) { double t1 = 0.5; // 初始化迭代参数 double t2 = 0.5; double dt = 1.0; while (dt > EPSILON) { // 迭代求解方程组 Point p1 = bezier(curve1, t1); Point p2 = bezier(curve2, t2); double d = distance(p1, p2); if (d < EPSILON) { // 当两条曲线已经相交时,直接返回交点 return p1; } Point v1 = bezierDerivative(curve1, t1); Point v2 = bezierDerivative(curve2, t2); Point a1 = bezierSecondDerivative(curve1, t1); Point a2 = bezierSecondDerivative(curve2, t2); double f1 = p1.x - p2.x; double f2 = p1.y - p2.y; double f3 = v1.x * a2.y - v1.y * a2.x - v2.x * a1.y + v2.y * a1.x; double f4 = a1.x * a2.y - a1.y * a2.x; double d1 = v1.x * a2.y - v1.y * a2.x; double d2 = v2.x * a1.y - v2.y * a1.x; double d3 = a1.x * a2.y - a1.y * a2.x; double h1 = f1 - d1 / d3 * f3; double h2 = f2 - d2 / d3 * f3; double h3 = f4; double det = h1 * h2 - h3 * h3; double t1_new = t1 - (h2 * f3 - h3 * f2) / det; double t2_new = t2 - (h1 * f3 - h3 * f1) / det; if (t1_new < 0 || t1_new > 1 || t2_new < 0 || t2_new > 1) { // 当迭代参数越界时,重新初始化 t1_new = 0.5; t2_new = 0.5; } dt = max(abs(t1_new - t1), abs(t2_new - t2)); t1 = t1_new; t2 = t2_new; } return bezier(curve1, t1); } int main() { BezierCurve curve1 = {{0, 0}, {1, 2}, {3, -1}, {4, 0}}; BezierCurve curve2 = {{2, 0}, {3, 1}, {1, 3}, {0, 2}}; Point p = findIntersection(curve1, curve2); cout << "Intersection point: (" << p.x << ", " << p.y << ")" << endl; return 0; } ``` 在上述代码中,`BezierCurve` 结构体表示一条贝塞尔曲线,包含四个控制点。`bezier` 函数用来计算曲线在参数 $t$ 处的点,`bezierDerivative` 和 `bezierSecondDerivative` 函数分别用来计算曲线在参数 $t$ 处的一导向量和二导向量。`distance` 函数用来计算两个点之间的距离。`findIntersection` 函数则用来求解两条贝塞尔曲线的交点,采用牛顿迭代法求解方程组的根。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值