美文网首页
三阶贝塞尔曲线真牛逼啊!

三阶贝塞尔曲线真牛逼啊!

作者: 大成小栈 | 来源:发表于2024-01-01 16:44 被阅读0次

    1. 三阶贝塞尔曲线

    2. 算法描述

    如果我们把三阶贝塞尔曲线的 P0 和 P3 视为原始数据,只要找到 P1 和 P2 两个点(我们称其为控制点),就可以根据三阶贝塞尔曲线公式,计算出 P0 和 P3 之间平滑曲线上的任意点。

    现在,平滑问题变成了如何计算两个原始数据点之间的控制点的问题。步骤如下:


    第1步:绿色直线连接相邻的原始数据点,计算出个线段的中点,红色直线连接相邻的中点


    第2步:根据相邻两条绿色直线长度之比,分割其中点之间红色连线,标记分割点


    第3步:平移红色连线,使其分割点与相对的原始数据点重合


    第4步:调整平移后红色连线的端点与原始数据点的距离,通常缩减40%-80%


    3. 算法实现

    代码如下:

    static func smoothingBezierTuples(points: Array<CGPoint>, k: CGFloat, closed: Bool) -> [(CGPoint, CGPoint, CGPoint)] {
            guard points.count > 1 else { return [] }
            // 第1步
            var midPoints: [(CGPoint, CGPoint, CGPoint)] = []
            for i in 1..<points.count {
                let start = points[i-1]
                let end = points[i]
                let mid = CGPoint(x: (start.x + end.x)/2.0, y: (start.y + end.y)/2.0)
                midPoints.append((start, end, mid))
            }
            if closed {
                let start = points[points.count - 1]
                let end = points[0]
                let mid = CGPoint(x: (start.x + end.x)/2.0, y: (start.y + end.y)/2.0)
                midPoints.append((start, end, mid))
            }
            // 第2步
            var splitPoints: [(CGPoint, CGPoint, CGPoint)] = []
            for i in 0..<midPoints.count {
                var j = 0
                if i < (midPoints.count - 1) {
                    j = i + 1
                } else if closed {
                    j = 0
                } else {
                    continue
                }
                
                let (iStart, iEnd, iMid) = midPoints[i]
                let iLength = sqrt(pow(iStart.x - iEnd.x, 2) + pow(iStart.y - iEnd.y, 2))
                let (jStart, jEnd, jMid) = midPoints[j]
                let jLength = sqrt(pow(jStart.x - jEnd.x, 2) + pow(jStart.y - jEnd.y, 2))
                
                let kSplit = 1.0 * iLength / (iLength + jLength)
                let split = CGPoint(x: iMid.x + (jMid.x - iMid.x)*kSplit, y: iMid.y + (jMid.y - iMid.y)*kSplit)
                splitPoints.append((iMid, jMid, split))
            }
            // 第3步
            var crtPoints: [(CGPoint, CGPoint, CGPoint)] = []
            for i in 0..<splitPoints.count {
                let (_, vertex, _) = midPoints[i]
                let (start, end, split) = splitPoints[i]
                
                let dx = vertex.x - split.x
                let dy = vertex.y - split.y
                
                let crtStart = CGPoint(x: start.x + dx, y: start.y + dy)
                let crtEnd = CGPoint(x: end.x + dx, y: end.y + dy)
                
                let kCrtStart = CGPoint(x: crtStart.x + (vertex.x - crtStart.x)*k, y: crtStart.y + (vertex.y - crtStart.y)*k)
                let kCrtEnd = CGPoint(x: crtEnd.x + (vertex.x - crtEnd.x)*k, y: crtEnd.y + (vertex.y - crtEnd.y)*k)
                
                // (顶点,其左侧控制点,其右侧控制点)
                crtPoints.append((vertex, kCrtStart, kCrtEnd))
            }
            return crtPoints
        }
    

    效果截图:


    参考文章:
    https://blog.csdn.net/fzhlee/article/details/114375724
    https://blog.csdn.net/xufive/article/details/86163741

    相关文章

      网友评论

          本文标题:三阶贝塞尔曲线真牛逼啊!

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