#ifndef B_SPLINE_H
#define B_SPLINE_H
#include <vector>
//节点个数 m + 1
//最大次数 p = m
//定义基函数
class BaseFunction {
public:
BaseFunction(){};
~BaseFunction(){};
void setKnots(std::vector<double> knots_) {
knots = knots_;
m = knots.size() - 1;
max_p = m - 1;
};
// i_: 0 -- m-1
// p_: 0 -- max_p
// u_: knots.front() -- knots.back()
// i_ + p_ <= max_p
double baseN(int i_, int p_, double u_) {
if (p_ == 0) {
if (u_ >= knots[i_] && u_ < knots[i_ + 1])
return 1;
else
return 0;
} else {
double a = 0;
if ((knots[i_ + p_] - knots[i_]) != 0)
a = (u_ - knots[i_]) / (knots[i_ + p_] - knots[i_]);
double b = 0;
if ((knots[i_ + p_ + 1] - knots[i_ + 1]) != 0)
b = (knots[i_ + p_ + 1] - u_) / (knots[i_ + p_ + 1] - knots[i_ + 1]);
return a * baseN(i_, p_ - 1, u_) + b * baseN(i_ + 1, p_ - 1, u_);
}
}
private:
std::vector<double> knots;
int m = 1;
int max_p = 1;
};
//对一组数据计算BSpline
class BSpline {
public:
BSpline(){};
~BSpline(){};
void setP(int p_) {
p = p_;
m = n + p + 1;
generateKnots();
};
void addControlPoints(std::vector<double> control_points_) {
control_points = control_points_;
n = control_points.size() - 1;
m = n + p + 1;
generateKnots();
};
void setPointsNum(int points_num_) {
points_num = points_num_;
u.clear();
for (int i = 0; i < points_num; i++) {
u.emplace_back((double)i / (double)(points_num - 1));
}
};
bool bSplineCal() {
if (n < 2) {
return false;
}
data_out.clear();
BaseFunction bf;
bf.setKnots(knots);
for (int j = 0; j < u.size(); j++) {
double c_u = 0;
for (int i = 0; i <= n; i++) {
if (j == u.size() - 1 && i == n)
c_u += control_points[i];
else
c_u += (bf.baseN(i, p, u[j]) * control_points[i]);
}
data_out.emplace_back(c_u);
}
return true;
}
public:
std::vector<double> getDataOut() const { return data_out; };
private:
std::vector<double> control_points; //控制点
int n = 1; //控制点n+1个
std::vector<double> knots; //节点0-1范围内
int m = 1; //节点数量m+1个
int p = 3; //曲线阶数
int points_num = 10;
std::vector<double> u; //根据points_num计算采样点的
std::vector<double> data_out; //计算完成后的数据
//生成knots
void generateKnots() {
knots.clear();
for (size_t i = 0; i < m + 1; i++) {
if (i <= p)
knots.emplace_back(0);
else if (i >= m - p)
knots.emplace_back(1);
else {
// p+1 --- m-p-1区间范围内
int num = m - p - p;
if (num < 2) return;
double step = 1.0 / (double)num;
knots.emplace_back(step * (i - p));
}
}
}
};
class BSpline2D {
public:
BSpline2D(){};
~BSpline2D(){};
std::vector<double> getXOut() const { return x_out; };
std::vector<double> getYOut() const { return y_out; };
void setP(int p_) { p = p_; };
void setPointsNum(int points_num_) { points_num = points_num_; };
void addXControlData(std::vector<double> x_control_data_) {
x_control_data = x_control_data_;
};
void addYControlData(std::vector<double> y_control_data_) {
y_control_data = y_control_data_;
};
bool bSpline2DCal() {
BSpline bs;
bs.setP(p);
bs.setPointsNum(points_num);
// x方向
bs.addControlPoints(x_control_data);
if (!bs.bSplineCal()) {
return false;
}
x_out = bs.getDataOut();
// y方向
bs.addControlPoints(y_control_data);
if (!bs.bSplineCal()) {
return false;
}
y_out = bs.getDataOut();
return true;
};
private:
std::vector<double> x_control_data, y_control_data;
std::vector<double> x_out, y_out;
int p = 3;
int points_num = 30;
};
#endif
使用方法:
BSpline2D bs2d;
bs2d.setPointsNum(point_num);//设置点数量(默认30个点)
bs2d.setP(3);//设置曲线阶数(默认3阶数)
bs2d.addXControlData(x_control_data);//设置控制点
bs2d.addYControlData(y_control_data);
//进行计算
if (!bs2d.bSpline2DCal()) {
return false;
}
//提取插值点数据
std::vector<double> x_out = bs2d.getXOut();
std::vector<double> y_out = bs2d.getYOut();