用 Swift 進行貝塞爾曲線繪制

級別: ★★☆☆☆
標(biāo)簽:「iOS」「Swift」「塞爾曲線」
作者: 大成小棧
審校: QiShare團隊


1. 貝塞爾曲線介紹

以三階為例:設(shè)P0、P02、P2是一條拋物線上順序三個不同的點。過P0和P2點的兩切線交于P1點,在P02點的切線交P0P1和P2P1于P01和P11,則如下比例成立:

這是所謂拋物線的三切線定理。

當(dāng)P0,P2固定,引入?yún)?shù)t,令上述比值為t:(1-t),即有:

當(dāng)P0,P2固定,引入?yún)?shù)t,令上述比值為t:(1-t),即有:

t從0變到1,第一、二式就分別表示控制二邊形的第一、二條邊,它們是兩條一次Bezier曲線。將一、二式代入第三式得:


當(dāng)t從0變到1時,它表示了由三頂點P0、P1、P2三點定義的一條二次Bezier曲線。

并且表明:

這二次Bezier曲線P02可以定義為分別由前兩個頂點(P0,P1)和后兩個頂點(P1,P2)決定的一次Bezier曲線的線性組合。

依次類推,

由四個控制點定義的三次Bezier曲線P03可被定義為分別由(P0,P1,P2)和(P1,P2,P3)確定的二條二次Bezier曲線的線性組合,由(n+1)個控制點Pi(i=0,1,...,n)定義的n次Bezier曲線P0n可被定義為分別由前、后n個控制點定義的兩條(n-1)次Bezier曲線P0n-1與P1n-1的線性組合:

由此得到Bezier曲線的遞推計算公式

Bézier curve(貝塞爾曲線)是應(yīng)用于二維圖形應(yīng)用程序的數(shù)學(xué)曲線。 曲線定義:起始點、終止點(也稱錨點)、控制點。通過調(diào)整控制點,貝塞爾曲線的形狀會發(fā)生變化。 1962年,法國數(shù)學(xué)家Pierre Bézier第一個研究了這種矢量繪制曲線的方法,并給出了詳細的計算公式,因此按照這樣的公式繪制出來的曲線就用他的姓氏來命名,稱為貝塞爾曲線。

2. 用Swift進行貝塞爾曲線的繪制

2.1 普通線條繪制

用Swift進行普通線條的繪制代碼,如下:

import UIKit

class BezierPathView: UIView {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func draw(_ rect: CGRect) {
        super.draw(rect)
        
        self.drawLine()
        self.drawCommonCurve()
        self.drawSmoothPath()
    }
    
    func drawLine() {
        
        let offset:CGFloat = 50.0
        
        // 繪制矩形
        //let rectpath = UIBezierPath(rect: CGRect.init(x: 15, y: offset, width: 300, height: 60))
        let rectpath = UIBezierPath(roundedRect: CGRect.init(x: 15, y: offset, width: 300, height: 60), cornerRadius: 5.0)

        rectpath.lineWidth = 5.0
        UIColor.green.setStroke()
        rectpath.stroke()
        UIColor.red.setFill()
        rectpath.fill()
        
        // 繪制直線
        let path = UIBezierPath()
        path.move(to: CGPoint(x: 25.0, y: offset + 130.0))
        path.addLine(to: CGPoint(x: 300.0, y: offset + 130.0))
        path.lineWidth = 5.0
        UIColor.cyan.setStroke()
        path.stroke()
    }
    
    func drawCommonCurve() {
        
        let offset:CGFloat = 260.0
        
        let curvePath = UIBezierPath()
        curvePath.move(to: CGPoint(x: 30.0, y: offset))
        curvePath.addQuadCurve(to: CGPoint(x: 350.0, y: offset), controlPoint: CGPoint(x: 350.0, y: offset + 100))
        UIColor.blue.setStroke()
        curvePath.stroke()
    }
    
    func drawSmoothPath() {
        
        let offset:CGFloat = 430
        
        let pointCount:Int = 4
        let pointArr:NSMutableArray = NSMutableArray.init()
        for i in 0...pointCount {
            let px: CGFloat = 15 + CGFloat(i) * CGFloat(80)
            let py: CGFloat = i % 2 == 0 ? offset - 60 : offset + 60
            let point: CGPoint = CGPoint.init(x: px, y: py)
            pointArr.add(point)
        }
        
        let bezierPath = UIBezierPath()
        bezierPath.lineWidth = 2.0
        var prevPoint: CGPoint!
        
        for i in 0 ..< pointArr.count {
            let currPoint:CGPoint = pointArr.object(at: i) as! CGPoint
            
            // 繪制綠色圓圈
            let arcPath = UIBezierPath()
            arcPath.addArc(withCenter: currPoint, radius: 3, startAngle: 0, endAngle: CGFloat(2 * Double.pi), clockwise: true)
            UIColor.green.setStroke()
            arcPath.stroke()
            
            // 繪制平滑曲線
            if i==0 {
                bezierPath.move(to: currPoint)
            }
            else {
                let conPoint1: CGPoint = CGPoint.init(x: CGFloat(prevPoint.x + currPoint.x) / 2.0, y: prevPoint.y)
                let conPoint2: CGPoint = CGPoint.init(x: CGFloat(prevPoint.x + currPoint.x) / 2.0, y: currPoint.y)
                bezierPath.addCurve(to: currPoint, controlPoint1: conPoint1, controlPoint2: conPoint2)
            }
            prevPoint = currPoint
        }
        UIColor.red.setStroke()
        bezierPath.stroke()
    }
}

運行結(jié)果:


還可以進行復(fù)雜圖形的繪制。

源碼Github地址


推薦文章:
Swift 5.1 (10) - 屬性
iOS App后臺?;?/a>
Swift 中使用 CGAffineTransform
iOS 性能監(jiān)控(一)—— CPU功耗監(jiān)控
iOS 性能監(jiān)控(二)—— 主線程卡頓監(jiān)控
iOS 性能監(jiān)控(三)—— 方法耗時監(jiān)控
初識Flutter web
用SwiftUI給視圖添加動畫
用SwiftUI寫一個簡單頁面
iOS App啟動優(yōu)化(三)—— 自己做一個工具監(jiān)控App的啟動耗時
iOS App啟動優(yōu)化(二)—— 使用“Time Profiler”工具監(jiān)控App的啟動耗時
iOS App啟動優(yōu)化(一)—— 了解App的啟動流程
奇舞周刊

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容