【manim】之圆规动画

1. 概要

Manim 是一个基于Python的动画库,主要用于创建数学和科学中难以用普通视频制作工具制作的图形和动画。

它提供了各种基础的动画对象,比如,点,线,面,三角形,矩形,立方体等等,

基于它们,可以组合定制出自己需要表达的动画效果。

本篇介绍如何基于Manim封装一个圆规动画。

2. 动画原理

对于单个的元素,manim本身就提供了非常多的动画函数。

比如:创建/消除的动画,移动元素的动画,旋转元素的动画等等,具体可以参考: Animations

但是,对于多个元素联动的动画,则需要编写各个元素之间的联动规则,来封装符合要求的动画。

圆规动画就是多个元素联动的动画,下面演示其如何封装。

圆规动画目的是画一个 圆弧 ,只是在绘制的圆弧的过程中还需要展示了圆弧的起点,终点,

以及绘制过程中动态更新起点终点之间的线。

首先,定义绘制函数:

python 复制代码
def ruler(sc: Scene, p1, p2, color=GREEN, angle=PI, axis=OUT):
    """
    圆规动画


    Parameters
    ---------
    sc
        绘制动画的场景
    p1
        代表圆规的针,绘制时不动的点
    p2
        代表圆规的笔芯,绘制圆弧的点
    color
        圆弧的颜色,默认绿色
    angle
        绘制圆弧的角度,默认PI,相当于绘制半个圆
    axis
        只有2个值 IN/OUT,分别表示顺时针还是逆时针作弧
    """
    # 省略。。。
    return arc

各个参数的含义参见注释。

实现动画的思路如下:

  1. 构建3个元素,即:
    1. d1(根据参数中p1坐标绘制的点)
    2. d2(根据参数中p2坐标绘制的点)
    3. dl(连接p1和p2的虚线)
  2. 设置dl的动画,随着 d1d2变化不断重新绘制(这里 d1其实是不会变的)
  3. 再设置圆弧的动画,随着 d2的变动,不断绘制新的圆弧(圆弧就是起点到d2的弧)
  4. 通过 manim自带的动画函数让 d2先动,其他动画随之运动
  5. 最后删除不必要的元素,只保留圆弧在 场景(sc)中
python 复制代码
def ruler(sc: Scene, p1, p2, color=GREEN, angle=PI, axis=OUT):
    d1 = Dot(point=p1, color=RED)
    d2 = Dot(point=p2, color=color)
    dl = DashedLine(d1.get_center(), d2.get_center())

    r = np.linalg.norm(p2 - p1)
    arc = ArcBetweenPoints(p2, p2, stroke_width=2)

    dl.add_updater(lambda z: z.become(DashedLine(d1.get_center(), d2.get_center())))
    if np.array_equal(axis, OUT):
        arc.add_updater(
            lambda z: z.become(
                ArcBetweenPoints(
                    p2, d2.get_center(), radius=r, stroke_color=color, stroke_width=2
                )
            )
        )
    if np.array_equal(axis, IN):
        arc.add_updater(
            lambda z: z.become(
                ArcBetweenPoints(
                    d2.get_center(), p2, radius=r, stroke_color=color, stroke_width=2
                )
            )
        )

    sc.add(d1, d2, dl, arc)
    sc.play(
        Rotate(
            d2,
            about_point=d1.get_center(),
            axis=axis,
            angle=angle,
            rate_func=linear,
        )
    )

    arc.clear_updaters()
    dl.clear_updaters()
    sc.remove(d1, d2, dl)
    return arc

3. 动画效果

封装之后,看看使用的效果。

首先,试试按照逆时针(默认是逆时针)和顺时针方式绘制半圆。

python 复制代码
# -*- coding: utf-8 -*-
from manim import *
import numpy as np


class Sample(Scene):
    def construct(self):
        ruler(self, np.array([-1, 0, 0]), np.array([-1, 1, 0]))
        ruler(self, np.array([1, 0, 0]), np.array([1, 1, 0]), axis=IN)
        self.wait()

然后,试试绘制2个圆弧的交叉点。

python 复制代码
class Sample(Scene):
    def construct(self):
        ruler(self, np.array([-1, -1, 0]), np.array([1.1, -0.2222, 0]), angle=PI / 3)
        ruler(
            self,
            np.array([1, -1, 0]),
            np.array([-1.1, -0.2222, 0]),
            axis=IN,
            angle=PI / 3,
        )
        self.wait()

4. 总结

联动动画的实现其实也不难,关键在于先确认起始的动画是哪个元素开始的,

比如,上文中起始动画是由d2发起的。

确定了起始动画,其他元素的联动都要基于起始动画的元素,

比如,上文中的dlarc元素。

这样,联动的效果就形成了。

我在视频号中基于此做了一个 高斯正17边形的尺规作图动画(weixin.qq.com/sph/AkfwsX)...%25E3%2580%2582 "https://weixin.qq.com/sph/AkfwsX)%E3%80%82")

注: 此链接是视频号中视频的链接,只能在微信中打开。

相关推荐
bug攻城狮1 天前
Alloy VS Promtail:基于 Loki 的日志采集架构对比与选型指南
运维·架构·grafana·数据可视化
今禾2 天前
" 当Base64遇上Blob,图像转换不再神秘,让你的网页瞬间变身魔法画布! "
前端·数据可视化
Coffeeee3 天前
Threejs粒子动效之龙卷风
前端·three.js·动效
JIAKSK4 天前
VitePress 接入百度统计:全面教程与优化指南
运维·数据可视化
datagear5 天前
如何在DataGear 5.4.1 中快速制作HTTP数据源服务端分页的数据表格看板
javascript·数据可视化
wenzhangli75 天前
OneCode 图表组件核心优势解析
数据可视化
镜舟科技5 天前
StarRocks × Tableau 连接器完整使用指南 | 高效数据分析从连接开始
starrocks·数据分析·数据可视化·tableau·连接器·交互式分析·mpp 数据库
永洪科技6 天前
永洪科技荣获商业智能品牌影响力奖,全力打造”AI+决策”引擎
大数据·人工智能·科技·数据分析·数据可视化·bi
Codebee6 天前
OneCode图表配置速查手册
大数据·前端·数据可视化
DataGear7 天前
如何在DataGear 5.4.1 中快速制作SQL服务端分页的数据表格看板
javascript·数据库·sql·信息可视化·数据分析·echarts·数据可视化