挖一挖貝塞爾曲線那些事

挖一挖貝塞爾曲線那些事

1、前世此生

      貝塞爾曲線的最初設計是服務於工業設計,尤爲應用與汽車曲線設計。隨着計算機畫圖的應用普遍,若想在計算機上畫出平滑精準的曲線並非一件容易的事,貝塞爾曲線解決了這樣的問題,貝塞爾虛線經過起始點與結束點來肯定曲線的首尾,經過若干個控制點來肯定曲線的走向。因爲其由法國工程師皮埃爾·貝塞爾普遍推廣,所以這種曲線被命名爲貝塞爾曲線。git

2、數學基礎

      平面上的任意連續曲線能夠經過伯恩斯坦多項式來進行逼近擬合,所以,當咱們想在平面中畫一條曲線的時候,若是能夠模擬出此曲線的函數,則能夠十分精準的控制計算機來描繪一系列曲線上的點來繪製曲線。貝塞爾曲線就是基於這樣的數學基礎。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

3.高階貝塞爾曲線

      有了一階與二階的基礎,高階貝塞爾曲線也是經過相同的方式來推導,一個通用的遞推公式以下:.net

三階和四階的繪製過程演示以下:設計

3、iOS中的貝塞爾曲線的應用

    雖然貝塞爾曲線在不少開發領域都十分容易實現,因爲我對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;

4、示例程序

      下面是一個iOS平臺的演示小Demo,使用它能夠動態進行貝塞爾曲線的繪製並觀察到輔助線與繪製過程,能夠靈活的配置繪製的速度和控制點:

Github地址以下:

https://github.com/ZYHshao/Bezel

相關文章
相關標籤/搜索