python动画:实现贝塞尔曲线【bezier】

贝塞尔曲线在计算机图形学中用于绘制形状、用于 CSS 动画和许多其他地方。它们是一件非常简单的事情,值得学习一次,然后在矢量图形和高级动画的世界中感到舒适。

一.控制点

贝塞尔曲线由控制点可能有 2、3、4 或更多。

例如,二次贝塞尔曲线:

三次贝塞尔曲线:

四次贝塞尔曲线:

如果你仔细观察这些曲线,你会立即注意到:

  1. **点并不总是在曲线上。**这是完全正常的,稍后我们将看到曲线是如何构建的。

  2. 曲线顺序等于点数减去 1。 对于两点,我们有一条线性曲线(一条直线),对于三点 -- 二次曲线(抛物线),对于四点 -- 三次曲线。

  3. 曲线始终位于控制点的凸包内:

|-------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
| 1. | 1. |

由于最后一个属性,在计算机图形学中,可以优化交叉点测试。如果凸包不相交,则曲线也不相交。因此,首先检查凸包相交可以给出非常快速的"无相交"结果。检查凸壳的交点要容易得多,因为它们是矩形、三角形等(见上图),比曲线简单得多。

贝塞尔曲线用于绘图的主要价值 -- 通过移动点,曲线以直观、明显的方式发生变化。

二.数学表达式

贝塞尔曲线可以用数学公式来描述。正如我们所看到的------实际上没有必要知道它,大多数人只是通过用鼠标移动点来绘制曲线。但如果你喜欢数学------就在这里。

给定控制点的坐标:第一个控制点有坐标,第二个控制点有坐标:,依此类推,曲线坐标由依赖于线段参数的方程来描述

  • 2 点曲线的公式:

  • 对于 3 个控制点:

  • 对于 4 个控制点:

这些是向量方程。换句话说,我们可以把 and 而不是来获取相应的坐标。x,y,P

例如,3 点曲线由计算如下的点组成:(x,y)

相反,我们应该放置 3 个控制点的坐标,然后随着从 移动到 ,我们将拥有曲线的每个值。x1, y1, x2, y2, x3, y3,``t``0``1t(x,y)

例如,如果控制点为 , 和 ,则方程变为:(0,0)(0.5, 1)(1, 0)

现在,当从 到 运行时,每个值的集合构成了此类控制点的曲线。t``0``1(x,y)t

三,manim实现:应用函数

1.CubicBezier 曲线

在 Manim 中,CubicBezier 曲线需要指定起点、终点和两个控制点。CubicBezier 的构造函数的参数通常是 start, end, start_control, 和 end_control。

正确的使用方法 为了创建一条立方贝塞尔曲线,您需要提供开始和结束点,以及它们各自的控制点。下面是一个示例代码片段:

python 复制代码
from manim import *

    class BezierExample(Scene):
    def construct(self):
    # 定义起点、结束点和控制点
    start_point = LEFT
    end_point = RIGHT
    start_control = UP
    end_control = DOWN



# 创建三次贝塞尔曲线 
bezier_curve = CubicBezier(start_point, start_control, end_control, end_point) # 绘制曲线 self.play(Create(bezier_curve)) self.wait(2)

解释

start_point: 曲线的起始坐标(左边的点)。

end_point: 曲线的结束坐标(右边的点)。

start_control: 控制曲线形状的第一个控制点。

end_control: 控制曲线形状的第二个控制点。

总结 :

确保在实例化 CubicBezier 时提供了所有必需的参数:起点、终点、起始控制点和结束控制点。这样可以避免 TypeError 并正确创建贝塞尔曲线。

2.常见的贝塞尔相关类和函数

在 Manim 中,除了 CubicBezier 函数外,还有其他几种函数和方法用于绘制不同类型的贝塞尔曲线。以下是一些常见的贝塞尔相关类和函数:

Bezier Bezier(points): 这个类可以用来表示任意阶的贝塞尔曲线。它的构造函数接受一个点的列表,这些点可以是任意数量的控制点。适用于线性、二次、三次乃至更高阶的贝塞尔曲线。

python 复制代码
from manim import *
class BezierExample(Scene):
    def construct(self):
    points = [LEFT, UP, RIGHT] # 三个控制点
    bezier_curve = Bezier(points) # 创建贝塞尔曲线
    self.play(Create(bezier_curve))  
    self.wait(2)  

QuadraticBezier QuadraticBezier(start, control, end): 创建一条二次贝塞尔曲线。需要提供起点、控制点和终点。

python 复制代码
from manim import *

class QuadraticBezierExample(Scene):
    def construct(self):
# 定义点
        start = LEFT
        control = UP
        end = RIGHT



# 创建二次贝塞尔曲线 
        bezier_curve = QuadraticBezier(start, control, end) self.play(Create(bezier_curve))                 
        self.wait(2)

CubicBezier CubicBezier(start, start_control, end_control, end): 创建一条三次贝塞尔曲线,使用起点、两个控制点和终点。 其他贝塞尔相关函数 在 Manim 中,除了以上类,您还可能遇到一些其他有用的函数和方法,如在动画中与路径相关的操作、插值和运动等。

使用示例 要使用这些不同类型的贝塞尔函数,您只需确保根据所需曲线类型提供适当数量和位置的点。

总结 在 Manim 中使用贝塞尔曲线时,您可以选择不同的类来创建线性、二次或三次贝塞尔曲线,具体取决于您所需的复杂性和形状。

四,实现贝塞尔曲线

python 复制代码
from manim import *  

class Bezier2305(Scene):  
    def construct(self):  
        # 定义控制点  
        P1 = np.array([-4, -2, 0])  
        P2 = np.array([0, 3, 0])  
        P3 = np.array([0, -1, 0])  # 二次贝塞尔曲线的控制点  
        P4 = np.array([2, 3, 0])    # 三次贝塞尔曲线的控制点  
        P5=np.array([5, 2, 0])
        
        

        # 根据控制点计算各种贝塞尔曲线  
        bezier_2_points = [self.bezier_2_points(P1, P2, t) for t in np.linspace(0, 1, 100)]  
        bezier_3_points = [self.bezier_3_points(P1, P2, P3, t) for t in np.linspace(0, 1, 50)]  
        bezier_4_points = [self.bezier_4_points(P1, P2, P3, P4, t) for t in np.linspace(0, 1, 100)] 
        bezier_5_points = [self.bezier_5_points(P1, P2, P3, P4,P5, t) for t in np.linspace(0, 1, 100)] 
        

        # 创建 Mobject  
        curve_2 = self.create_curve(bezier_2_points)
        curve_3 = self.create_curve(bezier_3_points)  
        curve_4 = self.create_curve(bezier_4_points)
        curve_5 = self.create_curve(bezier_5_points)

        # 动画展示
        
        #二次
        #点
        d1 = Dot(P1,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        self.add(d1)
        d2 = Dot(P2,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        self.add(d2)
        #线
        L1=Line(start=d1,end=d2,color=GREEN)
        
        self.play(Create(curve_2))
        self.play(Create(L1))
        a=Text("二次贝塞尔曲线",color=PINK).shift(2*DOWN)
        self.add(a)
        self.wait(1)  
        self.play(FadeOut(curve_2,L1,d1,d2,a)) 
        
        
        
        #三次
        d1 = Dot(P1,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        #self.add(d1)
        d2 = Dot(P2,radius=0.2,color=RED,stroke_width=10, fill_opacity=0)
        #self.add(d2)
        d3 = Dot(P3,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        #self.add(d3)
        L1=Line(start=d1,end=d2,color=GREEN)
        L2=Line(start=d2,end=d3,color=YELLOW)
        #self.play(Create(L1))
        b=Text("三次贝塞尔曲线",color=PINK).shift(2*DOWN)
        self.add(b)
        self.play(Create(curve_3))
        self.play(Create(L1))
        self.wait(1)  
        self.play(FadeOut(curve_3,d1,L1,d2,L2,d3,b)) 
        self.wait(1.5) 
        
        #四次
        d1 = Dot(P1,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        d2 = Dot(P2,radius=0.2,color=RED,stroke_width=10, fill_opacity=0)
        d3 = Dot(P3,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        d4 = Dot(P4,radius=0.2,color=RED,stroke_width=10, fill_opacity=0)
        #line
        L1=Line(start=d1,end=d2,color=GREEN)
        L2=Line(start=d2,end=d3,color=YELLOW)
        L3=Line(start=d3,end=d4,color=YELLOW)
        #曲线
        self.play(Create(curve_4)) 
        c=Text("四次贝塞尔曲线",color=PINK).shift(2*DOWN)
        self.add(c)
        self.wait(1)
        self.play(Create(d1),Create(L1),Create(d2),Create(L2),Create(d3),Create(L3),Create(d4))
        self.wait(1)
        self.play(FadeOut(curve_4,d1,L1,d2,L2,d3,L3,d4,c))
        
        #五次
        d1 = Dot(P1,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        d2 = Dot(P2,radius=0.2,color=RED,stroke_width=10, fill_opacity=0)
        d3 = Dot(P3,radius=0.2,color=GREEN,stroke_width=10, fill_opacity=0)
        d4 = Dot(P4,radius=0.2,color=RED,stroke_width=10, fill_opacity=0)
        d5=Dot(P5,radius=0.2,color=YELLOW,stroke_width=10, fill_opacity=0)
        #line
        L1=Line(start=d1,end=d2,color=GREEN)
        L2=Line(start=d2,end=d3,color=YELLOW)
        L3=Line(start=d3,end=d4,color=YELLOW)
        L4=Line(start=d4,end=d5,color=RED)
        
        #曲线
        self.play(Create(curve_5)) 
        d=Text("五次贝塞尔曲线",color=PINK).shift(2*DOWN)
        self.add(d)
        self.wait(1)
        self.play(Create(d1),Create(L1),Create(d2),Create(L2),Create(d3),
                  Create(L3),Create(d4),Create(L4),Create(d5))
        self.wait(1)
        self.play(FadeOut(curve_5,d1,L1,d2,L2,d3,L3,d4,L4,d5,d))
        self.wait(2)

    def bezier_2_points(self, P1, P2, t):  
        """计算2点贝塞尔曲线上的点"""  
        return (1 - t) * P1 + t * P2  

    def bezier_3_points(self, P1, P2, P3, t):  
        """计算3点贝塞尔曲线上的点"""  
        return (1 - t)**2 * P1 + 2 * (1 - t) * t * P2 + t**2 * P3  

    def bezier_4_points(self, P1, P2, P3, P4, t):  
        """计算4点贝塞尔曲线上的点"""  
        return (1 - t)**3 * P1 + 3 * (1 - t)**2 * t * P2 + 3 * (1 - t) * t**2 * P3 + t**3 * P4 
    
    def bezier_5_points(self, P1, P2, P3, P4,P5, t):  
        """计算4点贝塞尔曲线上的点"""  
        return (1 - t)**4 * P1 + 4 * (1 - t)**3 * t * P2 + 4 * (1 - t) * t**3 * P3+ 4 * (1 - t) * t**3 * P4 + t**4 * P5 

    def create_curve(self, points):  
        """创建通过给定点的曲线"""  
        return VMobject().set_points_smoothly(points)  

%manim -qm -v WARNING Bezier2305

完整运行结果:https://download.csdn.net/download/qq_45449625/89666944https://download.csdn.net/download/qq_45449625/89666944

运行片段:

|----------------------------------------------------------------------------|----------------------------------------------------------------------------|
| | |
| | |

相关推荐
Smile灬凉城66612 分钟前
反序列化为啥可以利用加号绕过php正则匹配
开发语言·php
lsx20240623 分钟前
SQL MID()
开发语言
Dream_Snowar26 分钟前
速通Python 第四节——函数
开发语言·python·算法
西猫雷婶28 分钟前
python学opencv|读取图像(十四)BGR图像和HSV图像通道拆分
开发语言·python·opencv
鸿蒙自习室28 分钟前
鸿蒙UI开发——组件滤镜效果
开发语言·前端·javascript
言、雲36 分钟前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
汪洪墩1 小时前
【Mars3d】设置backgroundImage、map.scene.skyBox、backgroundImage来回切换
开发语言·javascript·python·ecmascript·webgl·cesium
云空1 小时前
《QT 5.14.1 搭建 opencv 环境全攻略》
开发语言·qt·opencv
Anna。。1 小时前
Java入门2-idea 第五章:IO流(java.io包中)
java·开发语言·intellij-idea
我曾经是个程序员2 小时前
鸿蒙学习记录
开发语言·前端·javascript