三阶贝塞尔曲线只能计算近似解,由于使用时对长度的精度要求不高,因此用博客
【Unity】贝塞尔曲线关于点、长度、切线计算在 Unity中的C#实现
中提供的C#方法改写为C++的,只是替换了一个结构体,因为并不懂原文中的Vector3类的使用而已。
- 定义一个POINT结构体,用于后面计算:
typedef struct
{
double x, y;
} POINT;
- 定义一个三阶贝塞尔曲线函数,t的范围在[0,1];
- 输入P0, P1, P2, P3,分别为起始点,控制1点,控制2点,终止点;
- 返回POINT类型,也就是贝塞尔曲线上的点
POINT BezierPoint(double t, POINT p0, POINT p1, POINT p2, POINT p3)
{
double u = 1 - t;
double tt = t * t;
double uu = u * u;
double uuu = uu * u;
double ttt = tt * t;
POINT p;
p.x = uuu * p0.x;
p.y = uuu * p0.y;
p.x += 3 * uu * t * p1.x;
p.y += 3 * uu * t * p1.y;
p.x += 3 * u * tt * p2.x;
p.y += 3 * u * tt * p2.y;
p.x += ttt * p3.x;
p.y += ttt * p3.y;
return p;
}
- 把当前贝塞尔曲线切割N等份,计算每一段的欧氏距离,累加之后得到近似值,N越大越近似;
- 计算三阶贝塞尔曲线的长度;
double getBezier_length(POINT p0, POINT p1, POINT p2, POINT p3, int pointCount)
{
//取点 默认 30个
pointCount = 30;
double length = 0.0;
POINT lastPoint = BezierPoint(0.0 / (double)pointCount, p0, p1, p2, p3);
for (int i = 1; i <= pointCount; i++)
{
POINT point = BezierPoint((doube)i / (double)pointCount, p0, p1, p2, p3);
length += sqrt((point.x - lastPoint.x) * (point.x - lastPoint.x) + (point.y - lastPoint.y) * (point.y - lastPoint.y));
lastPoint = point;
}
return length;
}