級別: ★★☆☆☆
標(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ù)雜圖形的繪制。
推薦文章:
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的啟動流程
奇舞周刊