效果可查看上一篇博文:js手动画平滑曲线,贝塞尔曲线拟合【代码】js手动画平滑曲线,贝塞尔曲线拟合。https://blog.csdn.net/qiufeng_xinqing/article/details/131711963?spm=1001.2014.3001.5502
代码如下:
#include <cmath>
#include <cstdint>
#include <exception>
#include <vector>
namespace line {
// 二维坐标点定义:first对应x值,second对应y值
using point_t = std::pair<double, double>;
/// <summary>
/// 阶乘(递归),即 n! = n * (n-1) * (n-2) * (n-3) * ...* 1
/// </summary>
/// <param name="num">阶乘的数</param>
/// <returns>阶乘结果数</returns>
double factorial(double num)
{
return (num <= 1) ? 1 : (num * factorial(num - 1));
}
/// <summary>
/// 通过多个控制点计算当前贝塞尔曲线上的点坐标,横坐标为[0,1]
/// 关于 贝塞尔曲线:https://www.cnblogs.com/fangsmile/articles/11642607.html
/// </summary>
/// <param name="points">控制点集合</param>
/// <param name="stepTime">横轴的步长,如果为零则使用默认的 0.01 使用为步长</param>
/// <param name="retLine">贝塞尔曲线上的点坐标集</param>
/// <returns>贝塞尔曲线上的点坐标集</returns>
const std::vector<point_t>& calcBezierLine(const std::vector<point_t>& points, double stepTime, std::vector<point_t>& retLine)
{
if (points.size() < 2)
{
retLine.resize(1);
retLine[0] = points[0];
return retLine;
}
int32_t pointsn = points.size() - 1;
int64_t pointsFact = factorial(pointsn);
int32_t retCount = 0;
stepTime = stepTime == 0 ? 0.01 : stepTime;
retLine.resize((1 / stepTime) + 1);
for (double xt = 0; xt <= 1; xt += stepTime)
{
double x = 0.0;
double y = 0.0;
for (int32_t n = 0; n < points.size(); n++)
{
const auto& p = points[n];
if (!n)
{
double fact = std::pow((1 - xt), pointsn - n) * std::pow(xt, n);
x += p.first * fact;
y += p.second * fact;
}
else
{
double fact = pointsFact / factorial(n) / factorial((int64_t)pointsn - n)
* std::pow((1 - xt), (int64_t)pointsn - n) * std::pow(xt, n);
x += fact * p.first;
y += fact * p.second;
}
}
retLine[retCount++] = std::make_pair(x, y);
}
return retLine;
}
}
int main()
{
std::vector<line::point_t> points({ {115, 53},{392,105},{555,62}, {681, 94} });
std::vector<line::point_t> retPoints(100);
line::calcBezierLine(points, 0.01, retPoints);
return 0;
}