贝塞尔曲线理解与应用

贝塞尔曲线并非是由贝塞尔发明的,但是是因为他把这个东西应用到当时的汽车领域而闻名的,所以取名为贝塞尔曲线。
在我看来,用简单的话来理解一下贝塞尔曲线,他是通过少量几个点,使用一套公式,生成一条平滑曲线。

原理

先盗用人家的图,嘿嘿。

Alt text
平面ABC 3个点。
Alt text
在AB上找一个点D,在BC上找一个点E,使得AD:AB = BE:BC
Alt text
然后在DE上找一个点F,使得DF:DE = AD:AB = BE:BC 接着,我们将D点从A点 --> B点慢慢移动,在这个过程中,会产生一系列的F点,将这些F点相连,就会形成一条曲线,嘿嘿,就是我们的贝塞尔曲线,
Alt text
从这里可以看出,这里有3个关键点,起始点、终止点、控制点。 数学上的推理验证,这里就不讲了,直接给出公式。

二阶贝塞尔曲线,一个控制点

Alt text
Alt text

三阶贝塞尔曲线,二个控制点

Alt text
Alt text

一阶贝塞尔曲线,就是一条直线

Alt text
Alt text

为了完整性,我给出贝塞尔曲线的n阶通式

Alt text
想看这个公式推导,我给出一个文章链接 n公式推导推导。 但是在一般应用中,二阶,三阶贝塞尔曲线是已经够用了。

应用

先简单的来使用一下,通过公式来描绘曲线。

***d2(){this.name = '二次贝赛尔曲线方程';let _this = this;let oCanvas = document.querySelector("#canvas"),oGc = oCanvas.getContext('2d');let percent = 0;function animate() {oGc.clearRect(0, 0, 800, 800);oGc.beginPath();oGc.strokeStyle = 'red';oGc.moveTo( 40, 80 );//oGc.quadraticCurveTo( 137, 80, 140, 280 );_this.d2_(oGc,[40, 80],[137, 80],[140, 280],percent);oGc.stroke();percent = (percent   1) % 100;requestAnimationFrame(animate);}animate()},d2_(oGc,start,cp,end, percent){for (var t = 0; t <=  percent / 100; t  = 0.01) { var x = this.quadraticBezier(start[0], cp[0], end[0], t); var y = this.quadraticBezier(start[1], cp[1], end[1], t);oGc.lineTo(x, y);} },quadraticBezier(p0, p1, p2, t) {var k = 1 - t;return k * k * p0   2 * (1 - t) * t * p1   t * t * p2; // 这个方程就是二次贝赛尔曲线方程 },***

这个就是根据公式描述出相关的点,然后连接起来。 但是在实际应用中,很大程度上会在canvas中绘图,canvas提供2个api,
quadraticCurveTo:二阶贝塞尔曲线,参数是 控制点,结束点
bezierCurveTo :三阶贝塞尔曲线,参数是 控制点1,控制点2,结束点
你们发现没,它们没有开始点,它们的开始点是画笔开始的位置。

在举一个例子,画起伏波浪

直接讲思路,就是先画一个静止的波浪

好,现在来看一下,这个该怎么入手,先把这个轮廓描绘出来,要描绘,先拆分, 它是由一条曲线,3条直接拼接而成,有了这个思路,已经完成了一半, 那条曲线该如何绘制,其实我觉得思路不止一种,我们应该先自己给这个曲线下定义,我认为他应该是半圆的弧连接,应该是椭圆的弧链接,应该是其他。我先给它下一个定义

Alt text

我用二阶和三阶分别来描述这个曲线,1,2,3,4这4个点描述出来了,那么这个曲线也就绘制完成了
1: (0.5d,waveH)
2: (d, 0)
3: (1.5d,-waveH)
4: (2d,0)
我选择的这个规则是很中规中矩的,上一个波形是画2个二阶贝塞尔曲线,下一个波形是画一个3阶贝塞尔曲线。这个就可以把静止的波形给绘制出来了,然后你想象一个给这个坐标加横向偏移,加纵向偏移,他就可以起伏波动了

***init2(){this.name = '2阶';let c = document.getElementById("myCanvas"),ctx = c.getContext("2d"),waveWidth = 800,offset = 0, //xwaveHeight = 20, // 波浪大小waveCount = 5,startX = -200,startY = 208,progress = 0,  //高度progressStep = 0.5,d2 = waveWidth / waveCount,d = d2 / 2,hd = d / 2;ctx.fillStyle = "rgba(0,222,255, 0.2)";function tick() {offset -= 4;  // x 移动progress  = progressStep;if (progress > 220 || progress < 0) progressStep *= -1;if (-1 * offset === d2) offset = 0;ctx.clearRect(0, 0, c.width, c.height);ctx.beginPath();let offsetY = startY - progress; //y 坐标高低ctx.moveTo(startX - offset, offsetY);for (var i = 0; i < waveCount; i  ) {var dx = i * d2;var offsetX = dx   startX - offset;ctx.quadraticCurveTo(offsetX   hd, offsetY   waveHeight, offsetX   d, offsetY);ctx.quadraticCurveTo(offsetX   hd   d, offsetY - waveHeight, offsetX   d2, offsetY);}ctx.lineTo(startX   waveWidth, 300);ctx.lineTo(startX, 300);ctx.fill();requestAnimationFrame(tick);}tick();},
***

上面是二阶贝塞尔曲线,用三阶画的话,就是
ctx.quadraticCurveTo(offsetX hd, offsetY waveHeight, offsetX d, offsetY);
ctx.quadraticCurveTo(offsetX hd d, offsetY - waveHeight, offsetX d2, offsetY);

换成
ctx.bezierCurveTo(offsetX hd, offsetY waveHeight, offsetX d hd, offsetY-waveHeight, offsetX d2, offsetY );
就可以了。

其实我觉得贝塞尔曲线在使用过程中,最关键的是控制点的选择,不同点的选择,会展现不同的效果,但是选择控制点,是一件挺有意思的事。
下面我们再来看一个案例,粘性拖动

Alt text
要实现这个功能,来理一下思路,首先来描绘一下这个轮廓,一样的套路,是不是,来,思考一下,这个图形是由什么组成的。
画的丑,别介意,这么看这个轮廓,是不是出来了,你可以想象,是由2个半圆的圆弧和2条曲线,可以先画ABCD这个路径,再画2个圆,这样这个轮廓就出来了。接下来,再看这个曲线如何完成。这个曲线开始和结束点已经有了,再找一个控制点也能画出来,那么控制点在哪里,我下的定义简单粗暴,在2圆心的链接线的终点,然后再把ABCD 4个点描述出来,这个路径就解决了,如何描述ABCD,请允许我盗图
Alt text
如何让这个图形动起来,可以这么想第一个圆,可以是手开始触摸的点,也可以自己先写死,另一个圆是手拖动的位置,所以只要动态的改变第二个圆心的位置,那么这个拖动的效果就出来了。 我在拖动的时候,d的距离在改变,那么制定一个规则,d越大,第一个圆的半径就越小,那么基本上就可以实现了。

***data() {return {radius: 7,x: 300,//手移动y: 300,//手移动anchorX: 200,// 控制点anchorY: 200,// 控制点startX: 100, //开始startY: 100,//开始}},mounted() {document.removeEventListener('touchstart', this.wrapTouchStart);document.addEventListener("touchstart", this.wrapTouchStart);document.removeEventListener('touchmove', this.wrapTouchMove);document.addEventListener('touchmove', this.wrapTouchMove);document.removeEventListener('touchend', this.wrapTouchEnd);document.addEventListener('touchend', this.wrapTouchEnd);document.removeEventListener('touchcancel', this.wrapTouchCancel);document.addEventListener('touchcancel', this.wrapTouchCancel);},methods: {wrapTouchStart(e) {},wrapTouchMove(e) {this.x = e.changedTouches[0].clientX;this.y = e.changedTouches[0].clientY;this.anchorX = (e.changedTouches[0].clientX   this.startX) / 2;this.anchorY = (e.changedTouches[0].clientY   this.startY) / 2;this.d2();},wrapTouchEnd() {this.radius = 20;// 手势坐标this.x = 300;this.y = 300;// 控制点坐标this.anchorX = 200;this.anchorY = 200;// 起点坐标this.startX = 100;this.startY = 100;},wrapTouchCancel() {let oCanvas = document.querySelector("#canvas"),ctx = oCanvas.getContext('2d');ctx.clearRect(0, 0, 360, 600);},d2() {let _this = this;let oCanvas = document.querySelector("#canvas");ctx = oCanvas.getContext('2d');ctx.strokeStyle = 'red';var distance = Math.sqrt(Math.pow(this.y - this.startY, 2)   Math.pow(this.x - this.startX, 2));this.radius = -distance / 15   20;// 当气泡拉到一定程度,断开链条且链条消失//if (this.radius < 7) {if(distance > 250){ctx.clearRect(0, 0, 360, 600);ctx.beginPath();ctx.arc(this.x, this.y, 20, 0, 2 * Math.PI);ctx.strokeStyle = 'red';ctx.fill();console.log('end');return;}let sin = (this.x - this.startX) / distance;let cos = (this.y - this.startY) / distance;var x1 = this.startX - this.radius * cos;var y1 = this.startY   this.radius * sin;var x2 = this.x - 20 * cos;var y2 = this.y   20 * sin;var x3 = this.x   20 * cos;var y3 = this.y - 20 * sin;var x4 = this.startX   this.radius * cos;var y4 = this.startY - this.radius * sin;ctx.clearRect(0, 0, 360, 600);ctx.beginPath();ctx.moveTo(x1, y1);ctx.quadraticCurveTo(this.anchorX, this.anchorY, x2, y2);ctx.lineTo(x3, y3);ctx.quadraticCurveTo(this.anchorX, this.anchorY, x4, y4);ctx.lineTo(x1, y1);ctx.fillStyle = 'red'; ctx.stroke();ctx.fill();// 两圆圈ctx.beginPath();ctx.arc(this.startX, this.startY, this.radius, 0, 2 * Math.PI)ctx.arc(this.x, this.y, 20, 0, 2 * Math.PI)ctx.strokeStyle = 'red';ctx.fill();},}***

到这里,应该要结束了,但是我想说这控制点,其实还有其他选择,还有一种是是AC连线的中点,和BD连线的中点,具体的项目我晚一点附上地址。

by cs

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367355.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构 算法与应用C 语言描述答案,数据结构算法与应用-C语言描述.pdf

下载下载第1 6章 回 溯寻找问题的解的一种可靠的方法是首先列出所有候选解&#xff0c;然后依次检查每一个&#xff0c;在检查完所有或部分候选解后&#xff0c;即可找到所需要的解。理论上&#xff0c;当候选解数量有限并且通过检查所有或部分候选解能够得到所需解时&#xff…

云服务器布置_【阿里云ECS】(一)云服务器上安装RStudio-server

【阿里云ECS】&#xff08;一&#xff09;云服务器上安装RStudio-server最近注册了阿里云个人版&#xff0c;打算研究研究shiny部署问题。进了阿里云ECS因为是Ubuntu16.04的对于安装R和RStudio还是要学习实践一下的。第一步&#xff0c;安装R语言。我们使用apt的方式进行安装,步…

H5前期知识点总结 9月12日

知识点补充&#xff1a; 属性继承例子&#xff0c;color、font&#xff08;font-size/style/family/weight&#xff09; 1、浏览器的默认字体大小是16px,谷歌浏览器的最小字体是10px,其他浏览器的最小字体是12px。 2、通配符选择器 “*”&#xff0c;即选中body里所有的标签。 …

由原型模式引出的关于Cloneable接口和Object的clone()方法的一些问题

为什么要克隆快速到底 示例代码 1 class Resume2 {3 private String name;4 private String age;5 private String university;6 private String specialSkills;7 8 public Resume(String name, String age, String university, String specialSkills)…

Spring MVC:Ajax和JQuery

今天&#xff0c;我想演示如何将AJAX集成到Spring MVC应用程序中。 我将在客户端使用JQuery来发送请求和接收响应。 本教程将基于我以前关于Spring MVC和REST服务的教程之一。 在本文中&#xff0c;您将了解如何在异步请求的帮助下使Web应用程序更具交互性。 准备工作 我需要通…

C语言程序设计孙家啸第一版,广东年月自考各专业课程使用教材.doc

广东年月自考各专业课程使用教材附件2&#xff1a;广东2013年4月自考各专业课程使用教材序号课程代码课程名称使用教材作者出版社版次100009政治经济学(财经类)政治经济学(财经类)张雷声外语教学与研究出版社2012年版200012英语(一)大学英语自学教程(上册)高远高等教育出版社19…

手把手带你写一个JavaScript类型判断小工具

业务写了很多&#xff0c;依然不是前端大神&#xff0c;我相信这是很多‘入坑’前端开发同学的迷茫之处&#xff0c;个人觉得前端职业发展是有路径可寻的&#xff0c;前期写业务是一个积累过程&#xff0c;后期提炼总结&#xff0c;比如编程思想&#xff0c;父子类的原型继承&a…

【目录】《剑指Offer》Java实现

如题&#xff1a; 1) 找出数组中重复的数字 2) 不修改数组找出重复的数字 3) 二维数组中的查找 4) 替换空格 5) 从尾到头打印链表 6) 重建二叉树 7) 二叉树的下一个结点 8) 用两个栈实现队列 9) 斐波那契数列及青蛙跳台阶问题 10) 旋转数组的最小数字 11) 矩阵中的路…

yolov3之pytorch源码解析_springmvc源码架构解析之view

说在前面前期回顾sharding-jdbc源码解析 更新完毕spring源码解析 更新完毕spring-mvc源码解析 更新完毕spring-tx源码解析 更新完毕spring-boot源码解析 更新完毕rocketmq源码解析 更新完毕dubbbo源码解析 更新完毕netty源码解析 更新完毕spring源码架构更新完毕springmvc源码架…

Xstream将XML转换为javabean的问题

1.问题&#xff1a;Xstream is not security 解决方法&#xff1a;加上 2.问题&#xff1a;如果没有第二行代码&#xff0c;会出现xstream forbiddenclassexception 解决方法&#xff1a;加上第二行&#xff0c;其中参数是要进行解析的对象&#xff01; 调用该方法&#xff1a;…

蚂蚁属性细微差别

每隔一段时间&#xff0c;我会想起Ant属性的一些细微差别 &#xff0c;一旦忘记它们&#xff0c;在与Ant交互时会引起混乱。 特别是&#xff0c; Ant属性 通常是不可变的 &#xff08;不包括Ant 1.8版本的 局部属性 &#xff09;&#xff0c;并且在其首次设置时“永久”设置&am…

c语言约瑟夫环问题,C++_详解约瑟夫环问题及其相关的C语言算法实现,约瑟夫环问题 N个人围成一圈 - phpStudy...

详解约瑟夫环问题及其相关的C语言算法实现约瑟夫环问题N个人围成一圈顺序编号&#xff0c;从1号开始按1、2、3......顺序报数&#xff0c;报p者退出圈外&#xff0c;其余的人再从1、2、3开始报数&#xff0c;报p的人再退出圈外&#xff0c;以此类推。请按退出顺序输出每个退出人…

《从零构建前后分离的web项目》准备 - 前端了解过关了吗?

前端基础架构和硬核介绍 技术栈的选择 首先我们构建前端架构需要对前端生态圈有一切了解&#xff0c;并且最好带有一定的技术前瞻性&#xff0c;好的技术架构可能日后会方便的扩展&#xff0c;减少重构的次数&#xff0c;即使重构也不需要大动干戈&#xff0c;我通常选型技术栈…

联想w540笔记本参数_2020年12月笔记本电脑推荐!联想、惠普、华为笔记本电脑推荐!18款高性价比笔记本电脑推荐!!!...

前言&#xff1a;笔记本电脑&#xff0c;主要分为三种&#xff1a;轻薄本<全能本<游戏本。轻薄本&#xff0c;又称办公笔记本电脑&#xff0c;因为轻薄方便携带&#xff0c;通常用于移动办公使用。全能本&#xff0c;就是把轻薄本的集显变成了小独显&#xff0c;增加了独…

【BZOJ 1098】办公楼(补图连通块个数,Bfs)

补图连通块个数这大概是一个套路吧&#xff0c;我之前没有见到过&#xff0c;想了好久都没有想出来QaQ 事实上这个做法本身就是一个朴素算法&#xff0c;但进行巧妙的实现&#xff0c;就可以分析出它的上界不会超过 $O(n m)$。 接下来介绍一下这个技巧&#xff1a; 很显然一个…

Spring MVC:资源

我从博客读者那里收到的最常见的问题之一是如何在Spring MVC的应用程序中使用CSS和javascript文件。 因此&#xff0c;这是撰写有关Spring MVC中资源使用情况的文章的好机会。 通常&#xff0c;我将使用基于Java的配置方法。 如今&#xff0c;很难想象没有CSS和JavaScript文件…

map

头文件 首先要引入头文件 #include <map> . 并使用命名空间 using namespace std; 1、插入元素 用pair 或者 make_pair 均可&#xff0c;map键值不能重复。 map1.insert(pair<int,string>(123,"aaaaa")); //pair map1.insert(make_pair<int,string&…

c语言读文件空格间隔,c语言文件流实现按单个词读取(以空格、分号等作间隔)...

c语言文件流实现按词读取(以空格、分号等作间隔)1.基本描述在之前的作业中&#xff0c;认真编写代码&#xff0c;从中发现不少知识积累上的欠缺。编程中使用到的c语言文件读取&#xff0c;要求是按照获取到一个完整的词&#xff0c;并对其进行处理。写有java或c语言源程序的.tx…

山东专升本access知识点_全国各省份每年的专升本考试大纲啥时候公布?考纲公布之前你该做什么?...

?星标/置顶专升本招考下一个上岸的就是你最近小编在专升本招考后台收到很多同学的留言&#xff0c;大多同学都是看到好多省都公布了专升本考试政策和大纲&#xff0c;却迟迟不见自己所在的省份出&#xff0c;于是火急火燎地找到小编来问&#xff1a;XX省的考试大纲到底啥时候出…

2018091-2 博客作业

此作业的要求参见https://edu.cnblogs.com/campus/nenu/2018fall/homework/2101 1.建博客 在 cnblogs.com (博客园)建账号。博客地址&#xff1a;https://www.cnblogs.com/LY0503/ 2. 博客作业 &#xff08;1&#xff09;回想一下你曾经对计算机专业的畅想 当初你是如何做出选择…