文档章节

挖一挖贝塞尔曲线那些事

珲少
 珲少
发布于 2017/08/23 18:20
字数 1414
阅读 312
收藏 2

挖一挖贝塞尔曲线那些事

一、前世今生

      贝塞尔曲线的最初设计是服务于工业设计,尤其应用与汽车曲线设计。随着计算机画图的应用广泛,若想在计算机上画出平滑精准的曲线并不是一件容易的事,贝塞尔曲线解决了这样的问题,贝塞尔虚线通过起始点与结束点来确定曲线的首尾,通过若干个控制点来确定曲线的走向。由于其由法国工程师皮埃尔·贝塞尔广泛推广,因此这种曲线被命名为贝塞尔曲线。

二、数学基础

      平面上的任意连续曲线可以通过伯恩斯坦多项式来进行逼近拟合,因此,当我们想在平面中画一条曲线的时候,如果可以模拟出此曲线的函数,则可以十分精准的控制计算机来描绘一系列曲线上的点来绘制曲线。贝塞尔曲线就是基于这样的数学基础。

      首先,对于一条贝塞尔曲线,其3要素分别是:起始点,结束点和控制点。其中曲线的起点在起始点,终点在结束点,曲线并不穿过控制点,控制点来掌握曲线的走向,控制点个数可以不定。

1、一阶贝塞尔曲线

      一阶贝塞尔曲线控制点的个数为0,只有起始点与结束点。其实一阶贝塞尔曲线就是一条从起始点到结束点的直线段。其公式如下:

上面公式中,P为曲线上的点,P0为起始点,P1为结束点。(对于平面上的点,分别用上面公式计算x,y坐标即可)。由于其公式为线性公式,所有这种贝塞尔曲线也被称为一阶贝塞尔曲线。下图可以很好的描述当t从0到1变化时,线段的绘制过程:

2、二阶贝塞尔曲线

      二阶贝塞尔曲线有一个控制点,假设起始点,控制点和结束点分别为P0、P1、P2。连接P0P1,P1P2,在区间0-1之间,在P0P1线段上取点M,在P1P2线段上取点N,使得P0M/P0P1=P1N/P1P2,找到线段MN上一点Q,同时使得MQ/QN=P0M/P0P1=P1N/P1P2,所有Q点的集合即为所求贝塞尔曲线。上面的描述有些抽象,使用数学推导就义一目了然了,公式推导如下:

绘图过程如下:

3.高阶贝塞尔曲线

      有了一阶与二阶的基础,高阶贝塞尔曲线也是通过相同的方式来推导,一个通用的递推公式如下:

三阶和四阶的绘制过程演示如下:

三、iOS中的贝塞尔曲线的应用

    虽然贝塞尔曲线在很多开发领域都十分容易实现,由于我对iOS开发比较熟,并且上面的曲线绘制示例也是我通过iOS程序实现的。这里就对在iOS中应用贝塞尔曲线进行简单的讨论,首先CoreGraphics核心图形框架中提供了CGPath可以直接创建贝塞尔曲线,系统支持的贝塞尔曲线函数有二阶与三阶。前面有博客专门讨论,这里就不再赘述,地址如下:

https://my.oschina.net/u/2340880/blog/757072

这里主要列举UIKit框架中的UIBezierPath类。

//构造方法
+ (instancetype)bezierPath;
//使用矩形进行构造
+ (instancetype)bezierPathWithRect:(CGRect)rect;
//使用圆角矩形进行构造
+ (instancetype)bezierPathWithOvalInRect:(CGRect)rect;
//创建圆角矩形贝塞尔路径 并设置圆角半径
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect cornerRadius:(CGFloat)cornerRadius; 
+ (instancetype)bezierPathWithRoundedRect:(CGRect)rect byRoundingCorners:(UIRectCorner)corners cornerRadii:(CGSize)cornerRadii;
//使用圆弧创建
+ (instancetype)bezierPathWithArcCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
//使用CGPath创建
+ (instancetype)bezierPathWithCGPath:(CGPathRef)CGPath;

//CGPath对象
@property(nonatomic) CGPathRef CGPath;

//将路径移动到某个点
- (void)moveToPoint:(CGPoint)point;
//添加一天线
- (void)addLineToPoint:(CGPoint)point;
//添加一个二阶贝塞尔曲线段
- (void)addCurveToPoint:(CGPoint)endPoint controlPoint1:(CGPoint)controlPoint1 controlPoint2:(CGPoint)controlPoint2;
//添加一个三阶贝塞尔曲线段
- (void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
//添加圆弧
- (void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle endAngle:(CGFloat)endAngle clockwise:(BOOL)clockwise;
//关闭路径
- (void)closePath;
//移除所有点
- (void)removeAllPoints;
//添加一段路径
- (void)appendPath:(UIBezierPath *)bezierPath;
//对路径进行逆向
- (UIBezierPath *)bezierPathByReversingPath;
//进行transform变换
- (void)applyTransform:(CGAffineTransform)transform;
//路径是否为空
@property(readonly,getter=isEmpty) BOOL empty;
//尺寸
@property(nonatomic,readonly) CGRect bounds;
//当前点
@property(nonatomic,readonly) CGPoint currentPoint;
//判断是否包含某个点
- (BOOL)containsPoint:(CGPoint)point;

//设置线宽
@property(nonatomic) CGFloat lineWidth;
//设置线帽风格
@property(nonatomic) CGLineCap lineCapStyle;
//设置折点风格
@property(nonatomic) CGLineJoin lineJoinStyle;
@property(nonatomic) CGFloat miterLimit;
@property(nonatomic) CGFloat flatness;
//奇偶规则
@property(nonatomic) BOOL usesEvenOddFillRule;
//进行虚线设置
- (void)setLineDash:(nullable const CGFloat *)pattern count:(NSInteger)count phase:(CGFloat)phase;
- (void)getLineDash:(nullable CGFloat *)pattern count:(nullable NSInteger *)count phase:(nullable CGFloat *)phase;
//进行填充绘制
- (void)fill;
//进行路径绘制
- (void)stroke;

四、示例程序

      下面是一个iOS平台的演示小Demo,使用它可以动态进行贝塞尔曲线的绘制并观察到辅助线与绘制过程,可以灵活的配置绘制的速度和控制点:

Github地址如下:

https://github.com/ZYHshao/Bezel

© 著作权归作者所有

珲少

珲少

粉丝 881
博文 394
码字总数 475753
作品 0
上海
程序员
私信 提问
UIBezierPath 基础(一)

首先了解贝塞尔曲线的初始化方法都有那些,可以根据不同的需求来初始化;其次设置贝塞尔曲线的绘制路线;最后把贝塞尔曲线设置为layer的path,把layer添加到相应的view就能显示出你要绘制的贝...

Sunnyyangzx
2017/12/14
0
0
贝塞尔曲线原理分析及其Android的实现

本文主要内容为贝塞尔曲线原理解析并用 SurfaceView 实现其展示动画 关于SurfaceView 的使用,大家可以看我的上一篇文章 Android:SurfaceView 的使用(附代码模板) 概述 贝塞尔曲线(Bézie...

涤生_Woo
2017/05/24
0
0
用canvas绘制一个曲线动画——深入理解贝塞尔曲线

摘要:在前端开发中,贝赛尔曲线无处不在:这篇文章我准备从实现一个非常简单的曲线动画效果入手,帮助大家彻底地弄懂什么是贝塞尔曲线,以及它有哪些特性,文章中有一点点数学公式,但是都非...

hujiulong/blog
2018/01/04
0
0
文字渲染那些事(二)文字的形状是怎么表示的?

在上期文章里,我们介绍了字体文件的结构,也就是一系列的二进制表。在这一期里,我们关注的是这件事情:计算机中的数据是怎么表达文字形状的呢?让我们从点和线的概念开始吧: 从点到线 我们...

doodlewind
02/02
0
0
贝塞尔曲线之购物车动画效果

question 贝塞尔曲线是什么? 贝塞尔曲线可以做什么? 怎么做? what is it? 贝塞尔曲线在百度定义是贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学...

码无止境
2016/09/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

CentOS7.6中安装使用fcitx框架

内容目录 一、为什么要使用fcitx?二、安装fcitx框架三、安装搜狗输入法 一、为什么要使用fcitx? Gnome3桌面自带的输入法框架为ibus,而在使用ibus时会时不时出现卡顿无法输入的现象。 搜狗和...

技术训练营
昨天
5
0
《Designing.Data-Intensive.Applications》笔记 四

第九章 一致性与共识 分布式系统最重要的的抽象之一是共识(consensus):让所有的节点对某件事达成一致。 最终一致性(eventual consistency)只提供较弱的保证,需要探索更高的一致性保证(stro...

丰田破产标志
昨天
8
0
docker 使用mysql

1, 进入容器 比如 myslq1 里面进行操作 docker exec -it mysql1 /bin/bash 2. 退出 容器 交互: exit 3. mysql 启动在容器里面,并且 可以本地连接mysql docker run --name mysql1 --env MY...

之渊
昨天
10
0
python数据结构

1、字符串及其方法(案例来自Python-100-Days) def main(): str1 = 'hello, world!' # 通过len函数计算字符串的长度 print(len(str1)) # 13 # 获得字符串首字母大写的...

huijue
昨天
6
0
PHP+Ajax微信手机端九宫格抽奖实例

PHP+Ajax结合lottery.js制作的一款微信手机端九宫格抽奖实例,抽奖完成后有收货地址添加表单出现。支持可以设置中奖概率等。 奖品列表 <div class="lottery_list clearfix" id="lottery"> ......

ymkjs1990
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部