基于boost库使用的Bézier曲线绘图
这几天在工作上遇到了图形优化相关的问题,于是区学了bezier曲线
具体原理的证明过程,我在此处就不再赘述,有兴趣者可以去知网查询相关文献(如:Bézier基函数的导出)
我们要做的就是把得到的线段按照比例分开,并根据每一段找到相应的点。
具体的操作还是看图说话好了。
第一步:点的存入
将点存入直线类型 a中,如绿色线集显示的
此处我们输入了四个点(0,0)(2,1)(3,-2)(5,-0.5),并且得到了由三条线段组成的线集
第二步:线段的分割
将线集a中每条线段都均匀的分成m份,并将线段记录在线集l1中(红色)
第三步:同序号点的连接
具体一点来说,就是: 一条线段的第k个点,与他下一条线段的第k个点相连。
图中黄色线段就是第一条线段的第2个点和第二条线段的第2个点相连。
第四步:线段的再次分割
你需要把第三步生成的线段分割,并找到上面对应的点。由第k个点生成的线段,就寻找第k个点。
如图,绿色是已经选择的点,黄色线段上面已经划分好的点中,因为该黄色线段是红色线段第二条的第5个点,和第三条线段的第5个点生成,因此取黄色线段上第5个点。
第五步:得到新线集
蓝色的就是根据红色l1生成的新的线集l2。
了解一些Bezier曲线的朋友可能已经看出来了,蓝色的每条线段就是两条红色线段的Bezier曲线
第六步:递归,直到线集只剩一条线段
l2变为新的l1,继续第三步到第五步的操作,直到l1只有一条线段。
第七步:完成,并对比
紫色为原图形,红色为他的Bezier曲线。
实现代码
#include<cstdio>
#include<iostream>
#include<vector>
#include<boost/geometry.hpp>
using namespace std;
namespace bg = boost::geometry;
typedef bg::model::d2::point_xy<double> point_t;
typedef bg::model::segment<point_t> segment_t;
typedef bg::model::linestring<point_t> line_t;
typedef bg::model::polygon<point_t> polygon_t;
typedef bg::model::multi_point<point_t> mpoint_t;
typedef bg::model::multi_linestring<line_t> mline_t;
typedef bg::model::multi_polygon<polygon_t> mpolygon_t;
typedef bg::strategy::transform::rotate_transformer<bg::radian,double,2,2> rotate_t;
int n,m;
mpoint_t ps;
line_t a;
mline_t l1,l2;
void makePoint()
{
for(int i=1;i<l1.size();i++)//寻找线段
{
line_t l;
l.push_back(l1[i-1][0]);
for(int j=1;j<l1[i].size();j++)//遍历线段切分点
{
segment_t s{l1[i-1][j],l1[i][j]};//根据切分点生成线段s
double len;
len=bg::distance(l1[i-1][j],l1[i][j]);
len/=m;
ps.clear();
bg::line_interpolate(s,len,ps);//线段s的切分
l.push_back(ps[j-1]);//线段s切分点的存入
}
l2.push_back(l);//生成线集l2
}
return;
}
int main()
{
scanf("%d%d",&n,&m);//记录点的个数n,每一条线段分开的数量m
while(n--)
{
double inx,iny;
point_t p;
scanf("%lf%lf",&inx,&iny);
p.set<0>(inx);
p.set<1>(iny);
a.push_back(p);//将点存入直线a中
}
for(int i=1;i<a.size();i++)
{
segment_t s{a[i-1],a[i]};
double len;
len=bg::distance(a[i-1],a[i]);
len/=m;
ps.clear();
bg::line_interpolate(s,len,ps);//将线段分割成m+1段
line_t l;
l.push_back(a[i-1]);
for(int j=0;j<ps.size();j++)
{
l.push_back(ps[j]);
}
l1.push_back(l);
}
while(l1.size()>1)
{
makePoint();//生成新的线集
l1=l2;//用l2更新l1
l2.clear();
}
return 0;
}
输入
4 10
0 0
2 1
3 -2
5 -0.5