包教包会-贝塞尔曲线的绘制原理与应用

图来自pexels

说来话长,这一切都得从PhotoShop中的钢笔工具开始说起...

声明:本文不含复杂数学公式,学渣放心阅读吧😂(我仿佛看到了学渣们留下了激动的泪水)

背景

贝塞尔曲线(Bézier curve)是应用于二维图形应用程序的数学曲线,贝塞尔曲线基于多个点构成。它的应用非常广泛,比如说PS中的钢笔工具所绘画的曲线就是贝塞尔曲线,绘制动画的运动轨迹等等,而最近一次想用到贝塞尔曲线是想做一个 路径动画

简介

在iOS开发中一般通过UIBezierPath来实现贝塞尔曲线的绘制,平时一般使用绘制二阶和三阶贝塞尔曲线的方法。而我们要做的远超二三阶的贝塞尔曲线,本文 iOS Demo在原理上实现了N阶贝塞尔曲线的绘制,未使用任何相关API,纯手动绘制贝塞尔曲线,并且可以拖动滑块浏览贝塞尔曲线的绘制过程。

本文 iOS Demo 实现以下功能:

实现功能 描述
绘制贝塞尔曲线 1、点击空白处设置贝塞尔曲线的点 </br>2、可以设置贝塞尔曲线阶数 </br>3、播放贝塞尔曲线绘制过程 </br> 4、拖动滑块,自由查看绘制过程每一个瞬间
简易曲线图表 每两个点之间都是用3阶贝塞尔曲线连接(细节待完善)
过山车 1、在空白处绘制贝塞尔曲线 </br>2、过山车沿着绘制的贝塞尔曲线行驶</br>3、支持多个连接的贝塞尔曲线路径

Demo示例图

8阶贝塞尔曲线绘制过程

贝塞尔曲线的绘制原理

说到绘制原理,如果贴👇这张图,我只能说:什么鬼!!!我看不懂,听不见,你说什么...
路人甲:简单点...说话的方式简单点~

失败案例

首先提供一个可以动态绘制贝塞尔曲线的网站帮助你更好地理解贝塞尔曲线的绘制。

1. 点

贝塞尔曲线点的数量决定了曲线的阶数,一般N个点构成的N-1阶贝塞尔曲线,即3个点为二阶,至少由3个点组成,为什么两个点不行,两个点组成的是直线。按顺序,第一个点为 起点 ,最后一个点为 终点 ,其余点都为 控制点

A起点、B控制点 、C终点以及绘制的贝塞尔曲线

2. 点生线

这里说的线不是贝塞尔曲线,而是各个点按顺序连接起来,形成的直线,如上图ABBC两条线。在这里我们要将整个曲线的绘制量化为从0~1的过程,用progress为当前过程的进度,progress的区间即0~1。每一条线都需要根据progress生成一个点,如下图,一个点从P0移动到P1,这是这条线从0~1的过程。

根据进度点从起点向终点移动

下面是绘制一个二阶贝塞尔曲线过程,先给口诀: 点生线,线生点 😂。由ABC这3个点组成2条线ABBC,2条线根据progress分别生成2个移动的点DE,而DE又连成一条线,始终保持AD:DB=BE:EC

progress为0.3 的连线

移动的线

DE,DE再根据progress生成点F,只剩一个点,无法构成线,即为最终构成贝塞尔曲线的点。红色点为progress0~1过程中点F的移动过程,保持AD:DB=BE:EC=DF:FE

progress为0.3 最终的点
点F的移动过程

3. 绘制贝塞尔曲线

经过上面 点生线,线生点 的过程 ,我们拿到了点F在移动中所有点的,将这些点集合连接起来,即形成了贝塞尔曲线。progress自增越慢,点集合的点越多,曲线就越细致。

绘制二阶贝塞尔曲线过程

4. N阶贝塞尔曲线

稍微了解算法的同学就能发现,其实 点生线,线生点 是一个递归的过程,通过底层的点,一步步推算出最高阶的点。整个推导过程像一个金字塔,底部点的数量最多,每高一阶点的数量就减1,直至最高阶只有1个点。

**下面是递归代码: **

// 贝塞尔曲线每高一阶  需要递归次数+1
+ (NSArray *)recursionGetsubLevelPointsWithSuperPoints:(NSArray *)points progress:(CGFloat)progress{
    // 得到最终的点 正确结束递归 
    if (points.count == 1) return points;
    
    NSMutableArray *tempArr = [[NSMutableArray alloc] init];
    for (int i = 0; i < points.count-1; i++) {
        // 第一个点 
        NSValue *preValue = [points objectAtIndex:i];
        CGPoint prePoint = preValue.CGPointValue;
        // 第二个点
        NSValue *lastValue = [points objectAtIndex:i+1];
        CGPoint lastPoint = lastValue.CGPointValue;

        // 两点坐标差
        CGFloat diffX = lastPoint.x-prePoint.x;
        CGFloat diffY = lastPoint.y-prePoint.y;

        // 根据当前progress得出高一阶的点
        CGPoint currentPoint = CGPointMake(prePoint.x+diffX*progress, prePoint.y+diffY*progress);
        [tempArr addObject:[NSValue valueWithCGPoint:currentPoint]];
    }
    // 继续下一次递归过程
    return [self recursionGetsubLevelPointsWithSuperPoints:tempArr progress:progress];
}

8阶贝塞尔曲线绘制过程:

8阶贝塞尔曲线绘制过程

贝塞尔曲线的应用

光讲原理脱离实践这不是程序员的风格,简单地写了2个贝塞尔曲线的应用,都在本文 iOS Demo 里面,欢迎运行体验。

1. 过山车

通过点击屏幕收集点,将点集合生成贝塞尔曲线,可生成多个相连的贝塞尔曲线。小车按照生成的贝塞尔曲线路径前进。

a. 画路径
通过计算贝塞尔曲线的长度,根据曲线长度分配点的数量,达到点的相对均匀分布,使过山车 匀速前进

画路径

b. 发车
每个点都与前面一个点连线,通过计算得出两点的连线与水平形成的夹角,将角度赋予过山车实现 转向功能

发车

2. 简易曲线图表

a. 直线图表
即最简单的两点连成直线。

直线图表

b. 曲线图表
曲线图表的曲线全部由3阶贝塞尔曲线构成,整个曲线图不含任何棱角。

曲线图表

拓展

PaintCode

推荐一个iOS画路径神器PaintCode,画好图形直接生成代码,用钢笔工具画贝塞尔曲线也十分方便。下图为用钢笔工具画一个圆球(貌似不够圆😆):

生成代码

总结

为了准备这一篇文章差不多理解了贝塞尔曲线的绘制原理,但是在细节处,比如说真正意义上贝塞尔曲线点的均匀分布还有待完善,求曲线公式也没有去研究,贝塞尔曲线在复杂的动画方向地应用也是大有作为。

参考

贝塞尔曲线开发的艺术
Android:贝塞尔曲线原理分析

个人水平有限,欢迎提出建议。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容