首页 > 其他 > 详细

[计算机图形学]贝塞尔曲线

时间:2021-01-24 18:34:51      阅读:37      评论:0      收藏:0      [点我收藏+]

一、 贝塞尔曲线

简介摘抄自某度百科:

贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。
一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。
贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。
贝塞尔曲线于1962,由法国工程师皮埃尔·贝塞尔(Pierre Bézier)所广泛发表,他运用贝塞尔曲线来为汽车的主体进行设计。贝塞尔曲线最初由Paul de Casteljau于1959年运用de Casteljau演算法开发,以稳定数值的方法求出贝兹曲线。

简单说,贝塞尔曲线就是通过若干控制点来控制的曲线。通过调整控制点,可以决定曲线的走势(不知道大家有没有被Word中曲线箭头支配的恐惧)。

贝塞尔曲线公式:

\[P_i^k = \left\{ \begin{array}{l} P_i, k=0 \ (1-t)P_i^{k-1} + tP_{i+1}^{k-1}, k=1,2,...,n, i=0,1,...,n-k-1\\end{array} \right. \]

先不考究公式的含义,先看公式的元素,不难发现,本质是点的线性组合

\(P_i^k\)中的\(P\)指的点的坐标(二维的也好,三维的也罢);\(k\)指的第\(k\)次处理,\(k=0\)指的就是初始情况;\(i\)指的点的索引;\(n\)指的初始点的个数。

大概知道这些参数的含义(可能不太准确),举个例子:

//初始n=3,同时给定三个点P0、P1、P2坐标信息
//k=0,得到P0_0、P1_0、P2_0
//k=1,得到P0_1、P1_1
//k=2,得到P0_2

可以发现,每次迭代后生成的点的个数递减,因此每个\(t\)最终对应一个点,将这个点绘制即可。然后重复操作。

以上只是对公式的通俗解释,实际上公式的含义很明确,就是线性组合。
而贝塞尔曲线要完成的事情也很简单,就是根据给定的点,把曲线绘制出来就行了。怎么绘制?带进公式就行了。

1. 一阶贝塞尔曲线

一阶贝塞尔曲线有两个控制点,所以公式可以简化为:\(P = (1-t)P_0 + tP_1, t \in [0,1]\),显然,这是一个点的线性组合,所以最终得到的是一条直线。

2. 二阶贝塞尔曲线

二阶贝塞尔曲线有三个控制点,所以公式可以简化为:\(P = (1-t)^2P_0 + 2(1-t)tP_1 + t^2P_2, t \in [0,1]\),显然,这是一个关于\(t\)的二次函数,所以是一条抛物线。

3. 三阶贝塞尔曲线

三阶贝塞尔曲线有四个控制点,就不简化了,原理一样。
对于高阶贝塞尔曲线,直接从公式入手,递归即可,每次递归绘制一个点。

二、代码示例

//-----------------------------------------------
//功能描述:绘制贝塞尔曲线
//
//参    数:*ppoint[in],		顶点坐标,[x1, y2],[x2, y2],...
//	   num[in],		ppoint个数(num大于等于3,目前最大支持_BEZIER_POINT_NUM_MAX)
//	   color[in],		颜色值
//	   step[in],		步长(0<step<1)
//	   *pInOut[in/out],	传入前一点计算坐标,传出本次计算的点坐标
//
//返 回 值:void
//
//备注内容:无
//-----------------------------------------------
#define _BEZIER_POINT_NUM_MAX		10
void G2D_DrawBezierCurve( float *ppoint, uint16_t num, uint16_t color, float step, float *pInOut )
{
	float new_point[2*_BEZIER_POINT_NUM_MAX];
	
	if (num > _BEZIER_POINT_NUM_MAX) {
		USR_LOG_D("bezier curve point must between [3,%d]!", _BEZIER_POINT_NUM_MAX);
		return;
	}

	if (1 == num) 
	{
		TFT_DrawLine(pInOut[0], pInOut[1], ppoint[0], ppoint[1], color);
		pInOut[0] = ppoint[0];
		pInOut[1] = ppoint[1];
		return;
	}
	else
	{
		for (int i=0; i<(num-1); i++) 
		{
			new_point[2*i+0] = (1-step)*ppoint[2*i] + step*ppoint[2*(i+1)];
			new_point[2*i+1] = (1-step)*ppoint[2*i+1] + step*ppoint[2*(i+1)+1];
		}
		
		G2D_DrawBezierCurve(new_point, num-1, color, step, pInOut);
	}
}
//贝塞尔曲线控制点1
_internal_ro float _k_bezier_ctl_point_buf1[][2] = {
	{20, 220},
	{70, 110},
	{120, 115},
	{170, 200},
	{220, 100},
};

//贝塞尔曲线控制点2
_internal_ro float _k_bezier_ctl_point_buf2[][2] = {
	{25,220},
	{190,170},
	{200,140},
	{180,80},
	{60,90},
	{30,120},
	{33,165},
	{40,185},
	{80,230},
	{200,230},
};

//贝塞尔曲线控制点
_internal_ro float *_k_bezier_ctl_point[] = {
	(float*)_k_bezier_ctl_point_buf1,
	(float*)_k_bezier_ctl_point_buf2,
};
_internal_ro uint32_t _k_bezier_ctl_point_num[] = {
	GET_ARRAY_NUM(_k_bezier_ctl_point_buf1),
	GET_ARRAY_NUM(_k_bezier_ctl_point_buf2),
};

memcpy(dummy_result, _k_bezier_ctl_point[index], VERTEX_DATA_SIZE_2F);

for (int i=0; i<100; i++) 
{
    G2D_DrawBezierCurve((float*)_k_bezier_ctl_point[index], _k_bezier_ctl_point_num[index], RED, 0.01f*i, dummy_result);
    delay_ms(1000/25);
}

[计算机图形学]贝塞尔曲线

原文:https://www.cnblogs.com/dengchow/p/14320983.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!