美文网首页QiShare文章汇总swift
用 Swift 进行贝塞尔曲线绘制

用 Swift 进行贝塞尔曲线绘制

作者: QiShare | 来源:发表于2020-02-03 17:09 被阅读0次

    级别: ★★☆☆☆
    标签:「iOS」「Swift」「塞尔曲线」
    作者: 大成小栈
    审校: QiShare团队


    1. 贝塞尔曲线介绍

    以三阶为例:设P0、P02、P2是一条抛物线上顺序三个不同的点。过P0和P2点的两切线交于P1点,在P02点的切线交P0P1和P2P1于P01和P11,则如下比例成立:

    这是所谓抛物线的三切线定理

    当P0,P2固定,引入参数t,令上述比值为t:(1-t),即有:

    当P0,P2固定,引入参数t,令上述比值为t:(1-t),即有:

    t从0变到1,第一、二式就分别表示控制二边形的第一、二条边,它们是两条一次Bezier曲线。将一、二式代入第三式得:


    当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(贝塞尔曲线)是应用于二维图形应用程序的数学曲线。 曲线定义:起始点、终止点(也称锚点)、控制点。通过调整控制点,贝塞尔曲线的形状会发生变化。 1962年,法国数学家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()
        }
    }
    

    运行结果:


    还可以进行复杂图形的绘制。

    源码Github地址


    小编微信:可加并拉入《QiShare技术交流群》。

    关注我们的途径有:
    QiShare(简书)
    QiShare(掘金)
    QiShare(知乎)
    QiShare(GitHub)
    QiShare(CocoaChina)
    QiShare(StackOverflow)
    QiShare(微信公众号)

    推荐文章:
    Swift 5.1 (10) - 属性
    iOS App后台保活
    Swift 中使用 CGAffineTransform
    iOS 性能监控(一)—— CPU功耗监控
    iOS 性能监控(二)—— 主线程卡顿监控
    iOS 性能监控(三)—— 方法耗时监控
    初识Flutter web
    用SwiftUI给视图添加动画
    用SwiftUI写一个简单页面
    iOS App启动优化(三)—— 自己做一个工具监控App的启动耗时
    iOS App启动优化(二)—— 使用“Time Profiler”工具监控App的启动耗时
    iOS App启动优化(一)—— 了解App的启动流程
    奇舞周刊

    相关文章

      网友评论

        本文标题:用 Swift 进行贝塞尔曲线绘制

        本文链接:https://www.haomeiwen.com/subject/lnzvzctx.html