贝塞尔曲线的最初设计是服务于工业设计,尤为应用与汽车曲线设计。随着计算机画图的应用普遍,若想在计算机上画出平滑精准的曲线并非一件容易的事,贝塞尔曲线解决了这样的问题,贝塞尔虚线经过起始点与结束点来肯定曲线的首尾,经过若干个控制点来肯定曲线的走向。因为其由法国工程师皮埃尔·贝塞尔普遍推广,所以这种曲线被命名为贝塞尔曲线。git
平面上的任意连续曲线能够经过伯恩斯坦多项式来进行逼近拟合,所以,当咱们想在平面中画一条曲线的时候,若是能够模拟出此曲线的函数,则能够十分精准的控制计算机来描绘一系列曲线上的点来绘制曲线。贝塞尔曲线就是基于这样的数学基础。github
首先,对于一条贝塞尔曲线,其3要素分别是:起始点,结束点和控制点。其中曲线的起点在起始点,终点在结束点,曲线并不穿过控制点,控制点来掌握曲线的走向,控制点个数能够不定。app
一阶贝塞尔曲线控制点的个数为0,只有起始点与结束点。其实一阶贝塞尔曲线就是一条从起始点到结束点的直线段。其公式以下:框架
上面公式中,P为曲线上的点,P0为起始点,P1为结束点。(对于平面上的点,分别用上面公式计算x,y坐标便可)。因为其公式为线性公式,全部这种贝塞尔曲线也被称为一阶贝塞尔曲线。下图能够很好的描述当t从0到1变化时,线段的绘制过程:函数
二阶贝塞尔曲线有一个控制点,假设起始点,控制点和结束点分别为P0、P一、P2。链接P0P1,P1P2,在区间0-1之间,在P0P1线段上取点M,在P1P2线段上取点N,使得P0M/P0P1=P1N/P1P2,找到线段MN上一点Q,同时使得MQ/QN=P0M/P0P1=P1N/P1P2,全部Q点的集合即为所求贝塞尔曲线。上面的描述有些抽象,使用数学推导就义一目了然了,公式推导以下:atom
绘图过程以下:spa
有了一阶与二阶的基础,高阶贝塞尔曲线也是经过相同的方式来推导,一个通用的递推公式以下:.net
三阶和四阶的绘制过程演示以下:设计
虽然贝塞尔曲线在不少开发领域都十分容易实现,因为我对iOS开发比较熟,而且上面的曲线绘制示例也是我经过iOS程序实现的。这里就对在iOS中应用贝塞尔曲线进行简单的讨论,首先CoreGraphics核心图形框架中提供了CGPath能够直接建立贝塞尔曲线,系统支持的贝塞尔曲线函数有二阶与三阶。前面有博客专门讨论,这里就再也不赘述,地址以下:code
http://www.javashuo.com/article/p-czajqrsj-cd.html。
这里主要列举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地址以下: