教你直白的理解贝塞尔曲线???

本文深入浅出地介绍了贝塞尔曲线的基本概念,从一次贝塞尔曲线到多次贝塞尔曲线的公式及运动原理,提供了直观的运动示意图,帮助读者理解不同阶数的贝塞尔曲线是如何通过递归方式确定动点位置的。

序言

这是第一篇在掘金写的文章,写的不对的或者不好的地方希望友人能够指出便于修改与其他人分享. =.= 实在不善于表达啊 阿西吧。。。

一.什么是贝塞尔曲线? (百度百科你就知道)

贝塞尔曲线(Bézier curve),又称贝兹曲线或贝济埃曲线,是应用于二维图形应用程序的数学曲线。一般的矢量图形软件通过它来精确画出曲线,贝兹曲线由线段与节点组成,节点是可拖动的支点,线段像可伸缩的皮筋,我们在绘图工具上看到的钢笔工具就是来做这种矢量曲线的。贝塞尔曲线是计算机图形学中相当重要的参数曲线,在一些比较成熟的位图软件中也有贝塞尔曲线工具,如PhotoShop等。在Flash4中还没有完整的曲线工具,而在Flash5里面已经提供出贝塞尔曲线工具。

二.贝塞尔曲线的公式

由于贝塞尔曲线是有固定公式的 所以只用 一次 二次 以及三次 贝塞尔曲线作为示例进行分析

  1. 公式: 有了解过贝塞尔曲线的朋友一定知道,贝塞尔曲线是需要两组固定参数的( 点( array ) , 进度( T ) ),而我们需要求的只是当下瞬时运动的点在哪,在一次贝塞尔曲线中也就是 x = Ax+(Bx-Ax)*t , y = Ay+(By-Ay)*t。 这个规则在一次贝塞尔曲线中是最直接的( 无非就是动点替换 公式递归而已 希望多阶自己思考动手 )
    let PointA = {x:200,y:20},
        PointB = {x:100,y:20},
        PointS = [ PointA , PointB ],
        T = 0;
    // 那么公式为:
        function getPoint({Points,T}){ // 这个是点组 和 进度
            return {
                x:(PointA.x + (PointB.x - PointA.x) *T),
                y:(PointA.y + (PointB.y - PointA.y) *T),
            }
        }
    // 这个时候我们可以尝试调用
    // 当进度( T ) 等于 0 的时候 我们得到的位置和 第一个点的位置是一致的
        var PointCurve = getPoint({PointS,T}) ; // {x:200,y:20} 
    // 当进度( T ) 等于 1 的时候 我们得到的位置和 第二个点的位置是一致的
        T = 1;
        var PointCurve = getPoint({PointS,T}) ; // {x:100,y:20}
    
    // 推导出的公式其实就是在直线 AB 上移动 T 的位置;  直白说就是百分比位置;
复制代码

这里演示运动示意图:

三.二次贝塞尔曲线

上面说了一次贝塞尔曲线的公式,那么二次贝塞尔曲线怎么运动的呢? 有一种非常非常粗暴的理解方式:任何两条相邻的线 都会产生出另外一根随着进度而变化的线 , 而他们的子级也是相互作用的!!! 所以请注意!!!所有的线最终就是递归求一(逐一递减)!!!,而最后这一根线上的进度,则是当前所在点的位置

也可以理解为:任何两个点能确定另外一个点( 动点 ),如果同级的点( 动点仍然可以往下计算 )为复数则可以继续往下衍生,直到最后只剩下一个动点;

  • 一次贝塞尔曲线 两个点 确定一个点
  • 二次贝塞尔曲线 三个点 =》 两个点 =》 一个点
  • 三次贝塞尔曲线 四个点 =》 三个点 =》 两个点 =》 一个点 以此类推

现在我们开始分析刚才的那句话:

  1. 任何两条相邻的线 都会产生出另外一根随进度变化的线 ==》 二次贝塞尔曲线有两个基线 ==》 衍生出第三根基线( 求一 )
  2. 衍生出的第三根线没有相邻的产物线 无法作为基线继续求一 那么当前点的位置就是该线上的进度比位。 再次说明 请灵活运用上面的公式自己推导 , 使用递归或者其他方式都可以.( 反正我只会递归的方法。。。 自己推导的 不难 ) 这里演示运动示意图:

我们看到 红色点在运动的时候A B C三点的线都是固定的,假设 AB上的动点为E,BC上的动点为F, 那么EF则是求一后的线, 而红色点的当前位置就是EF * T的位置 。是不是很简单粗暴?

四.三次贝塞尔曲线

接下来比较复杂 但是按照我的逻辑来想则会非常简单 这里演示运动示意图:

我们可以看到现在有固点A , B , C , D四点, 假设AB动点为E,BC动点为F,CD则为G点~(好邪恶啊), 那么这时候我们发现EF并不是求一的线 而是唯二 他与FG相连, 那么我们继续EF上也有个动点H(好嗨哟~) , FG上的动点为I点,则得出唯一线HI(真的好hi哟~); 红色点运动轨迹则为HI * T

我就问看这篇文章的人 这理解粗暴不粗暴?

所以不论多少阶的贝塞尔曲线 都是用一个递归式的方式不断的在线上抽点 多点抽线 直到剩下一个点为止( 递减规则 每次少一根线或者一个点 )

五.多次贝塞尔曲线

最后 我们看到一个神奇的现象, 最后所有的动点都会归属到他父级走到的尽头 , B 点的尽头会多一个 C 点多两个 D点多三个...... 依次类推 这些则是 任何两个点能确定另外一个点( 动点 ),如果同级的点( 动点仍然可以往下计算 )为复数则可以继续往下衍生,直到最后只剩下一个动点 这个规则所带来的影响

呃,上述表达可能仍然不是特别清楚 图都是自己绘制的 希望能够给阅读的你带来帮助。 补充: 刚想到可以使用动态规划来进行处理,所有的贝塞尔曲线最终都可以化简为一 最后一步永远是一阶贝塞尔曲线。

转载于:https://juejin.im/post/5cb583e4f265da03aa4d9f5e

<think>好的,用户现在想了解如何使用CGPath绘制贝塞尔曲线,特别是具体的用法和示例。我之前已经回答过关于CGPath的MoveToPoint、AddLineToPoint和AddArcToPoint的用法,现在需要扩展到贝塞尔曲线部分。 首先,用户的问题明确提到了CGPath,所以需要专注于Core Graphics框架中的方法,而不是UIBezierPath,虽然两者有关联。根据用户提供的引用,特别是引用[2]提到CoreGraphics中的CGPath支持二阶和三阶贝塞尔曲线,所以应该重点介绍这两个方法:addQuadCurve和addCurveToPoint。 接下来需要确定用户可能需要的示例类型。用户可能希望看到具体的代码示例,最好是Swift和Objective-C两种,因为之前的回答中两种语言都有出现。同时,需要解释每个参数的作用,比如控制点的意义,以及如何影响曲线形状。 考虑到用户之前的问题中提到了路径的起始点、直线绘制和圆弧,现在需要将贝塞尔曲线融入同样的上下文中。可能需要展示如何结合直线和曲线绘制复杂路径,比如一个带有曲线的图形,或者波浪线等常见应用场景。 另外,用户提供的引用[5]中有一个addCurveToPoint的示例,使用的是两个控制点,这对应的是三次贝塞尔曲线。而二次贝塞尔曲线使用一个控制点。需要区分这两种情况,分别给出示例。 还要注意引用[3]中的UIBezierPath代码,虽然用户现在关注的是CGPath,但可能需要对比两者的区别,不过用户的问题没有提到这个,所以可能不需要深入,但可以简要说明CGPath和UIBezierPath的关系,如引用[2]中提到的。 用户可能存在的深层需求是理解贝塞尔曲线在CGPath中的具体实现,以及如何控制曲线的形状。因此,除了代码示例,还需要解释控制点如何影响曲线,例如二次贝塞尔曲线的控制点定义,三次的两个控制点如何作用。 另外,需要注意错误处理或常见问题,比如未设置起始点直接添加曲线会导致的问题,或者在闭合路径时的注意事项。之前的回答中提到过路径初始化必须先调用MoveToPoint,这点在贝塞尔曲线中同样重要,需要再次强调。 最后,生成相关问题时要考虑用户可能接下来会问的内容,比如如何结合多种路径方法,或者性能优化等,但根据之前的回答,可能的问题包括贝塞尔曲线的控制点调整、动态绘制、UIBezierPath的转换等。 总结步骤: 1. 介绍CGPath中绘制贝塞尔曲线的两种方法:二次和三次。 2. 分别给出Swift和Objective-C的代码示例。 3. 解释参数含义,特别是控制点的作用。 4. 提供组合使用的示例,比如绘制波浪线或复杂形状。 5. 强调起始点设置的重要性。 6. 对比CGPath和UIBezierPath的异同(简要)。 7. 添加注意事项,如闭合路径、控制点选择。 8. 生成相关问题,引导用户深入。</think>#### CGPath绘制贝塞尔曲线详解 ##### 一、核心方法 CGPath提供两种贝塞尔曲线绘制方法: 1. **二次贝塞尔曲线**(单控制点) $$ B(t) = (1-t)^2P_0 + 2t(1-t)P_1 + t^2P_2 \quad (t \in [0,1]) $$ 对应方法:`CGPathAddQuadCurveToPoint` 2. **三次贝塞尔曲线**(双控制点) $$ B(t) = (1-t)^3P_0 + 3t(1-t)^2P_1 + 3t^2(1-t)P_2 + t^3P_3 $$ 对应方法:`CGPathAddCurveToPoint` ##### 二、代码示例 ###### Swift版本 ```swift let path = CGMutablePath() // 设置起点 path.move(to: CGPoint(x: 50, y: 150)) // 二次贝塞尔曲线(单控制点) path.addQuadCurve(to: CGPoint(x: 250, y: 150), control: CGPoint(x: 150, y: 50)) // 三次贝塞尔曲线(双控制点) path.addCurve(to: CGPoint(x: 250, y: 300), control1: CGPoint(x: 150, y: 200), control2: CGPoint(x: 200, y: 400)) ``` ###### Objective-C版本 ```objective-c CGMutablePathRef path = CGPathCreateMutable(); // 起点设置 CGPathMoveToPoint(path, NULL, 50, 150); // 二次曲线 CGPathAddQuadCurveToPoint(path, NULL, 150, 50, // 控制点 250, 150); // 终点 // 三次曲线 CGPathAddCurveToPoint(path, NULL, 150, 200, // 控制点1 200, 400, // 控制点2 250, 300); // 终点 ``` ##### 三、参数解析 | 方法类型 | 参数说明 | 示意图 | |-----------------|-------------------------------|--------------------| | 二次贝塞尔曲线 | `control`: 曲线弯曲的控制锚点 | ![quad_curve](https://via.placeholder.com/150x100?text=Quad+Curve) | | 三次贝塞尔曲线 | `control1`: 起始方向控制点<br>`control2`: 结束方向控制点 | ![cubic_curve](https://via.placeholder.com/150x100?text=Cubic+Curve) | ##### 四、组合应用(波浪线绘制) ```swift func createWavePath() -> CGPath { let path = CGMutablePath() path.move(to: CGPoint(x: 0, y: 100)) // 连续三次贝塞尔曲线 path.addCurveToPoint(CGPoint(x: 100, y: 100), control1: CGPoint(x: 25, y: 50), control2: CGPoint(x: 75, y: 150)) path.addCurveToPoint(CGPoint(x: 200, y: 100), control1: CGPoint(x: 125, y: 50), control2: CGPoint(x: 175, y: 150)) return path } ``` ##### 五、关键注意事项 1. **必须设置起点**:未调用`moveToPoint`直接绘制曲线会导致路径错误[^1] 2. **控制点定位规律**: - 二次曲线控制点决定曲线弯曲的"拉力"方向 - 三次曲线双控制点分别控制起始端和结束端的弯曲形态 3. **闭合路径处理**:使用`CGPathCloseSubpath`闭合时,会自动连接终点起点形成闭合区域 ##### 六、UIBezierPath的关系 `UIBezierPath`是UIKit对`CGPath`的高级封装,二者可通过以下方式转换: ```swift // CGPath转UIBezierPath let uiPath = UIBezierPath(cgPath: cgPath) // UIBezierPath转CGPath let cgPath = uiPath.cgPath ``` --相关问题-- 1. 如何动态调整贝塞尔曲线的控制点? 2. CGPath如何实现路径的动画效果? 3. 贝塞尔曲线在游戏开发中有哪些典型应用?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值