#include <stdio.h>
#include<stdlib.h>
#include"b_spline.h"
/*
计算最终b样条平滑时生成的点数.
num_points:输入的散点数量.
degree:b样条曲线的阶次,可选2次或者3次
num_div:两点之间细分的线段数量.
*/
int cal_b_spline_points_num(int num_points,int degree, int num_div)
{
int num;
num = (num_points +2-degree) *num_div+ 1;
return num;
}
/*
生成多个控制点之间的b样条的曲线.
p_array:三个点或者四个点组成的数组,数据排布格式为x0,y0,z0,x1,y1,z1,...,xn,yn,zn.
degree:样条曲线的阶次,可选二次或者三次.
num_div : 两点之间细分线段的数量.
dims:坐标点的维度数,可以是二维或者三维.
results:保存计算结果的缓冲区,数据排布格式为x0,y0,z0,x1,y1,z1.....xn,yn,zn
'*/
void b_spline(float* p_array, int degree, int num_div, int dims, float* results)
{
float scale = 1.0f / num_div;
float t, t1, t2, t3, b0, b1, b2, b3;
if (degree == 2)
{
for (int i = 0; i <= num_div; i++)
{
t = i * scale;
t1 = t;
t2 = t1 * t;
b0 = 0.5 * (t2 - 2 * t1 + 1);
b1 = 0.5*(-2*t2+2*t1+1);
b2 = 0.5 * t2;
for (int j = 0; j < dims; j++)
{
results[i * dims + j] = p_array[j] * b0 + p_array[dims+j] * b1 + p_array[2*dims+j] * b2;
}
}
}
else
{
for (int i = 0; i <= num_div; i++)
{
t = i * scale;
t1 = t;
t2 = t1 * t;
t3 = t2 * t;
b0 =(-t3+3*t2-3*t1+1)/6.0;
b1 =(3*t3-6*t2+4)/6.0;
b2 =(-3*t3+3*t2+3*t1+1)/6.0;
b3 =t3/6.0;
for (int j = 0; j < dims; j++)
{
results[i * dims + j] = p_array[j] * b0 + p_array[dims+j] * b1 + p_array[2*dims+j] * b2+p_array[3*dims+j]*b3;
}
}
}
}
/*
通过一系列散点生成b样条平滑曲线.
p_array : 曲线散点序列,数组形状为(N, 2), 或者(N, 3), 点的坐标是二维坐标(x, y)或三维坐标(x, y, z).例如,散点输入为 [[1, 2, 3], [2, 1, 1], ...] .
num_points:输入散的点数量.
degree:样条曲线的阶次.
num_div : 两散点之间划分的线段数量,数值越大,线段越多,曲线越平滑.
dims:坐标点的维度数,可以是二维或者三维.
results:保存计算结果的缓冲区,数据排布格式为x0,y0,z0,x1,y1,z1.....xn,yn,zn.
*/
void b_spline_curve(float* p_array, int num_points, int degree, int num_div, int dims, float* results)
{
float* points = (float*)malloc(sizeof(float) * (num_points+2) * dims);
if (degree == 2)
{
for (int i = 0; i < dims; i++)
{
points[i] = p_array[i];
}
float* q = &points[dims];
int m = num_points * dims;
for (int i = 0; i < m; i++)
{
*q= p_array[i];
q++;
}
for (int i = 0; i < dims; i++)
{
q[i] = p_array[(num_points - 1) * dims + i];
}
}
else
{
for (int i = 0; i < dims; i++)
{
points[i] = 2 * p_array[i] - p_array[dims+i];
}
float* q = &points[dims];
int m = num_points * dims;
for (int i = 0; i < m; i++)
{
*q = p_array[i];
q++;
}
for (int i = 0; i < dims; i++)
{
q[i] = 2 * p_array[(num_points - 1) * dims + i] - p_array[(num_points - 2) * dims + i];
}
}
int num_seg = num_points+2-degree;
for (int i = 0; i <num_seg; i++)
{
int j = i * dims;
int offset = i * num_div * dims;
b_spline(&points[j],degree,num_div,dims,&results[offset]);
}
free(points);
}