【chatgpt代码系列】三阶贝塞尔曲线等距点算法
0x01 代码
#include <iostream>
#include <vector>
using namespace std;
// 定义二维坐标点结构体
struct Point {
double x;
double y;
};
// 计算三阶贝塞尔曲线上某个参数t对应的点坐标
Point getBezierPoint(vector<Point>& controlPoints, double t) {
double x = pow((1 - t), 3) * controlPoints[0].x +
3 * t * pow((1 - t), 2) * controlPoints[1].x +
3 * pow(t, 2) * (1 - t) * controlPoints[2].x +
pow(t, 3) * controlPoints[3].x;
double y = pow((1 - t), 3) * controlPoints[0].y +
3 * t * pow((1 - t), 2) * controlPoints[1].y +
3 * pow(t, 2) * (1 - t) * controlPoints[2].y +
pow(t, 3) * controlPoints[3].y;
Point p = {x, y};
return p;
}
// 递归计算三阶贝塞尔曲线上的等间距点
void recursiveDivide(vector<Point>& controlPoints, double t0, double t1,
vector<Point>& pointList, int& idx) {
// 当参数范围小于1e-6时停止递归
if ((t1 - t0) < 1e-6) {
return;
}
// 计算参数区间的中点
double tMid = (t0 + t1) / 2.0;
// 计算中点对应的贝塞尔曲线上的坐标
Point pMid = getBezierPoint(controlPoints, tMid);
// 将中点添加到结果列表中
pointList[idx++] = pMid;
// 递归计算左右两段曲线上的等间距点
recursiveDivide(controlPoints, t0, tMid, pointList, idx);
recursiveDivide(controlPoints, tMid, t1, pointList, idx);
}
int main() {
// 定义控制点
vector<Point> controlPoints = {{10, 10}, {50, 60}, {100, 30}, {150, 150}};
// 定义采样个数
int N = 10;
// 计算初始和末尾点
vector<Point> pointList(N + 1);
pointList[0] = controlPoints.front();
pointList[N] = controlPoints.back();
// 递归计算曲线上的等间距点
int idx = 1;
recursiveDivide(controlPoints, 0.0, 1.0, pointList, idx);
// 输出等间距的点容器
for (auto& p : pointList) {
cout << "(" << p.x << ", " << p.y << ")" << endl;
}
return 0;
}
这是一个 C++ 的程序,用于计算三阶贝塞尔曲线上等间距的点。程序在 main 函数中运行,包含以下步骤:
- 定义四个控制点,并将它们存储在一个二维向量
controlPoints中。 - 定义需要采样的点数
N,并将采样结果存储在一个二维向量pointList中。 - 调用递归函数
recursiveDivide来计算贝塞尔曲线上的等间距点。该函数通过二分法的方式递归计算左右两个子区间的点,直到整个区间小于某个阈值。 - 输出等间距的点容器
pointList中的各个元素。
请注意,贝塞尔曲线是一种可描述平滑曲线的数学模型,三阶贝塞尔曲线由四个控制点确定。对于任意参数 t∈[0,1]t \in [0, 1]t∈[0,1],三阶贝塞尔曲线上可以计算出对应的点坐标。本程序利用递归方式计算贝塞尔曲线上等间距的点坐标,主要涉及递归算法和贝塞尔曲线的基本原理。
0x02 公式
3阶贝塞尔曲线沿线长等距分割方法可以简述如下:
- 计算曲线长度,即对参数 ttt 在 [0,1][0,1][0,1] 区间上积分 (dx/dt)2+(dy/dt)2\sqrt{(dx/dt)^2+(dy/dt)^2}(dx/dt)2+(dy/dt)2,其中 dx/dtdx/dtdx/dt 和 dy/dtdy/dtdy/dt 分别为贝塞尔曲线在 xxx 和 yyy 方向上的导数。
- 根据总采样点数 NNN,计算出采样点的间隔 s=L/(N−1)s=L/(N-1)s=L/(N−1),其中 LLL 为曲线长度。
- 初始化采样点列表,包括起始点和终止点,并将起始点和终止点的参数值分别设为 t0=0t_0=0t0=0 和 tN=1t_N=1tN=1。
- 对于 i∈[1,N−1]i \in [1,N-1]i∈[1,N−1],计算参数值 tit_iti 使得从起点到第 iii 个采样点的长度为 i×si \times si×s,并计算对应的点坐标。
对于3阶贝塞尔曲线,上述分割方法稍加简化后的具体计算方式如下:
- 计算曲线长度公式为:
L=∫01(dx/dt)2+(dy/dt)2dt L=\int_{0}^{1} \sqrt{(dx/dt)^2+(dy/dt)^2} dt L=∫01(dx/dt)2+(dy/dt)2dt
其中 dx/dtdx/dtdx/dt 和 dy/dtdy/dtdy/dt 的计算公式如下:
dx/dt=3(1−t)2(x1−x0)+6t(1−t)(x2−x1)+3t2(x3−x2) dx/dt=3(1-t)^2(x_1-x_0)+6t(1-t)(x_2-x_1)+3t^2(x_3-x_2) dx/dt=3(1−t)2(x1−x0)+6t(1−t)(x2−x1)+3t2(x3−x2)
dy/dt=3(1−t)2(y1−y0)+6t(1−t)(y2−y1)+3t2(y3−y2) dy/dt=3(1-t)^2(y_1-y_0)+6t(1-t)(y_2-y_1)+3t^2(y_3-y_2) dy/dt=3(1−t)2(y1−y0)+6t(1−t)(y2−y1)+3t2(y3−y2)
其中 (x0,y0)(x_0,y_0)(x0,y0)、(x1,y1)(x_1,y_1)(x1,y1)、(x2,y2)(x_2,y_2)(x2,y2)、(x3,y3)(x_3,y_3)(x3,y3) 为3阶贝塞尔曲线的4个控制点坐标。
-
根据采样点数 NNN,计算出采样点的间隔 s=L/(N−1)s=L/(N-1)s=L/(N−1)。
-
初始化采样点列表,包括起始点 (x0,y0)(x_0,y_0)(x0,y0) 和终止点 (x3,y3)(x_3,y_3)(x3,y3) 并将起始点和终止点的参数值分别设为 t0=0t_0=0t0=0 和 tN=1t_N=1tN=1。
-
对于 i∈[1,N−1]i \in [1,N-1]i∈[1,N−1],通过二分法计算出满足以下条件的 tit_iti:
∫t0ti(dx/dt)2+(dy/dt)2dt=i×s\int_{t_0}^{t_i} \sqrt{(dx/dt)^2+(dy/dt)^2} dt = i \times s∫t0ti(dx/dt)2+(dy/dt)2dt=i×s
其中 (dx/dt)2+(dy/dt)2\sqrt{(dx/dt)^2+(dy/dt)^2}(dx/dt)2+(dy/dt)2 的计算公式如上。然后根据 tit_iti 计算出曲线上对应的点坐标,即 (xi,yi)(x_i,y_i)(xi,yi)。
更多推荐




所有评论(0)