QT画贝塞尔曲线 和 曲线与斜率、一阶导数 、二阶导数的关系

QT绘制贝塞尔曲线


程序演示
刚开始学习计算机图形学,觉得很有趣,我的水平不高,代码可供参考。

部分代码

typedef struct
{
	float X;
	float Y;
} PointF;
 
PointF bezier_interpolation_func(float t, PointF *points)
{
	//PointF *tmp_points = (PointF *)malloc(point_count * sizeof(PointF));
	//内存溢出?
	PointF tmp_points[300];
	for (int i = 1; i < point_count; ++i)
	{
		for (int j = 0; j < point_count - i; ++j)
		{
			if (i == 1)
			{
				tmp_points[j].X = (float)(points[j].X * (1 - t) + points[j + 1].X * t);
				tmp_points[j].Y = (float)(points[j].Y * (1 - t) + points[j + 1].Y * t);
				continue;
			}
			tmp_points[j].X = (float)(tmp_points[j].X * (1 - t) + tmp_points[j + 1].X * t);
			tmp_points[j].Y = (float)(tmp_points[j].Y * (1 - t) + tmp_points[j + 1].Y * t);
		}
	}
	return tmp_points[0];
}

    void Widget::mouseMoveEvent(QMouseEvent *event)
    {
    	QPoint p1;
    	int x, y;
    	int i;
    	bool if_in;
    	p1 = event->pos();
    	x = p1.x();
    	y = p1.y();
    	if (right_move == true)
    	{
    		now = point_count - 1;
    		point[now].setX(x);
    		point[now].setY(y);
    		if (point_count > 2)
    		{
    			bezier_point.clear();
    			bezier(point);
    		}
    		update();
    	}
    	else
    	{
    		if (now == 0)
    		{
    			for (i = 0; i < point_count; i++)
    			{
    				if (x > point[i].x() - 40 && x < point[i].x() + 40 && y > point[i].y() - 40 && y < point[i].y() + 40)
    				{
    					now = i;
    					break;
    				}
    			}
    		}
    		if (con > 0 || x > point[now].x() - 10 && x < point[now].x() + 10 && y > point[now].y() - 10 && y < point[now].y() + 10)
    		{
    			if_in = true;
    		}
    		else
    		{
    			if_in = false;
    		}
    		if (if_in == true)
    		{
    			con = 5;
    			point[now].setX(x);
    			point[now].setY(y);
    		}
    		if (point_count > 2)
    		{
    			bezier_point.clear();
    			bezier(point);
    		}
    		update();
    	}
    }
    void Widget::mouseReleaseEvent(QMouseEvent *event)
    {
    	con = 0;
    	now = 0;
    	right_move = false;
    }
     
    void Widget::mousePressEvent(QMouseEvent *event)
    {
    	if (event->button() == Qt::RightButton)
    	{
    		right_move = true;
    		Pt = event->pos();
    		point.push_back(Pt);
    		point_count++;
    		if (point_count > 2)
    		{
    			bezier_point.clear();
    			bezier(point);
    		}
    		update();
    	}
    	else if (event->button() == Qt::LeftButton)
    	{
    		update();
    	}
    	else if (event->button() == Qt::MidButton)
    	{
    		if (point_count > 0)
    		{
    			--point_count;
    			point.pop_back();
    			bezier_point.clear();
    			bezier(point);
    			update();
    		}
    	}
    }

下载(笔者根据原文和链接,进行了强势优化,增加注释,使用qt的api函数绘图,不用重复造轮子)

下载: https://download.csdn.net/download/jiesunliu3215/20705613

动感的贝塞尔曲线

相信很多同学都知道“贝塞尔曲线”这个词,我们在很多地方都能经常看到。但是,可能并不是每位同学都清楚地知道,到底什么是“贝塞尔曲线”,又是什么特点让它有这么高的知名度。

贝塞尔曲线的数学基础是早在 1912 年就广为人知的伯恩斯坦多项式。但直到 1959 年,当时就职于雪铁龙的法国数学家 Paul de Casteljau 才开始对它进行图形化应用的尝试,并提出了一种数值稳定的 de Casteljau 算法。然而贝塞尔曲线的得名,却是由于 1962 年另一位就职于雷诺的法国工程师 Pierre Bézier 的广泛宣传。他使用这种只需要很少的控制点就能够生成复杂平滑曲线的方法,来辅助汽车车体的工业设计。

正是因为控制简便却具有极强的描述能力,贝塞尔曲线在工业设计领域迅速得到了广泛的应用。不仅如此,在计算机图形学领域,尤其是矢量图形学,贝塞尔曲线也占有重要的地位。今天我们最常见的一些矢量绘图软件,如 Flash、Illustrator、CorelDraw 等,无一例外都提供了绘制贝塞尔曲线的功能。甚至像 Photoshop 这样的位图编辑软件,也把贝塞尔曲线作为仅有的矢量绘制工具(钢笔工具)包含其中。

贝塞尔曲线在 web 开发领域同样占有一席之地。CSS3 新增了 transition-timing-function 属性,它的取值就可以设置为一个三次贝塞尔曲线方程。在此之前,也有不少 JavaScript 动画库使用贝塞尔曲线来实现美观逼真的缓动效果。

下面我们就通过例子来了解一下如何用 de Casteljau 算法绘制一条贝塞尔曲线。

在平面内任选 3 个不共线的点,依次用线段连接。图片

在第一条线段上任选一个点 D。计算该点到线段起点的距离 AD,与该线段总长 AB 的比例。

图片

根据上一步得到的比例,从第二条线段上找出对应的点 E,使得 AD:AB = BE:BC图片

连接这两点 DE。

图片

从新的线段 DE 上再次找出相同比例的点 F,使得 DF:DE = AD:AB = BE:BC图片

到这里,我们就确定了贝塞尔曲线上的一个点 F。接下来,请稍微回想一下中学所学的极限知识,让选取的点 D 在第一条线段上从起点 A 移动到终点 B,找出所有的贝塞尔曲线上的点 F。所有的点找出来之后,我们也得到了这条贝塞尔曲线。图片

如果你实在想象不出这个过程,没关系,看动画!


图片

回过头来看这条贝塞尔曲线,为了确定曲线上的一个点,需要进行两轮取点的操作,因此我们称得到的贝塞尔曲线为二次曲线(这样记忆很直观,但曲线的次数其实是由前面提到的伯恩斯坦多项式决定的)。

当控制点个数为 4 时,情况是怎样的?图片

步骤都是相同的,只不过我们每确定一个贝塞尔曲线上的点,要进行三轮取点操作。如图,AE:AB = BF:BC = CG:CD = EH:EF = FI:FG = HJ:HI,其中点 J 就是最终得到的贝塞尔曲线上的一个点。

图片

这样我们得到的是一条三次贝塞尔曲线。图片

看过了二次和三次曲线,更高次的贝塞尔曲线大家应该也知道要怎么画了吧。那么比二次曲线更简单的一次(线性)贝塞尔曲线存在吗?长什么样?根据前面的介绍,只要稍作思考,想必你也能猜出来了。哈!就是一条直线

贝塞尔曲线数学公式

一阶贝塞尔曲线(线段):

图片

图片

 意义:由 P0 至 P1 的连续点, 描述的一条线段

二阶贝塞尔曲线(抛物线)

图片

图片

 原理:由 P0 至 P1 的连续点 Q0,描述一条线段。 
      由 P1 至 P2 的连续点 Q1,描述一条线段。 
      由 Q0 至 Q1 的连续点 B(t),描述一条二次贝塞尔曲线。

经验:P1-P0为曲线在P0处的切线。

三阶贝塞尔曲线:

图片

图片

通用公式:

图片

4阶曲线:

图片

 5阶曲线:

图片

 上面介绍的内容并不足以展示贝塞尔曲线的真正威力。推广到三维空间的贝塞尔曲面,以及更进一步的非均匀有理 B 样条(NURBS),早已成为当今计算机辅助设计(CAD)的行业标准,不论是我们平常用到的各种产品,还是在电影院看到的精彩大片,都少不了它们的功劳。图片

参考链接:

https://mp.weixin.qq.com/s/yFM6iZl-5F-u23nNrgToBQ

基本公式推导链接:

https://blog.csdn.net/cfan927/article/details/104649623/

此文到此结束*************************************************************此文到此结束

附件:对于之后可能用到的对贝塞尔曲线求解一阶导数和二阶导数

所以附上,基本公式,以作笔记使;

 

 
cotθ=1/tanθ  secx=1/(cosx)  cscx=1/(sinx)

简单来说,一阶导数是自变量的变化率,二阶导数是一阶导数的变化率,也就是一
连续函数的一阶导数就是相应的切线斜率。一阶导大于0,则递增,一阶导小
0,则递减,一阶导等于0,则不增不减。
而二阶导数可以反应图像的凹凸。二阶导数大于0,图像为凹,二阶导数小于0,
0,不凸不凹。
结合一阶、二阶导数可以求函数的极值。当一阶导数等于0,而二阶导数大于0
0,而二阶导数小于0时,为极大值点,当一阶0时,为驻点。

曲线在某点的曲率和导数的关系:

参考链接:https://www.docin.com/p-341333864.html

                   https://www.zhihu.com/question/50500344/answer/1413729175

其中两个关键转化过程:

y'=dy/dx = ᵩ'(t)/ ᵠ'(t);

y"=d(y')/dx = d(dy/dx)  /dx = d( ᵩ'(t)/ ᵠ'(t) )  /  ᵠ'(t)

 

 

 

 

 另外:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值