【manim】之圆规动画

概要

前端时间做尺规作图相关的动画的时候,封装了一个圆规的动画,顺便研究了下

manim
库的动画函数。

manim
本身就是做动画的库,所以,基于它封装自定义的动画非常方便。

动画原理

对于单个的元素,

manim
本身就提供了非常多的动画函数。
比如:创建/消除的动画,移动元素的动画,旋转元素的动画等等,具体可以参考: Animations

如果是做一些简单的演示视频的话,这些内置的动画函数满足要求绰绰有余。
但是,对于多个元素联动的动画,则需要编写各个元素之间的联动规则,来封装符合要求的动画。

下面以圆规动画为例,演示多元素动画如何封装。

圆规动画目的还是画出一个

圆弧
,只是在绘制的圆弧的过程中展示了圆弧的起点,终点以及连接起点终点之间的线。
这样,实际使用圆规作图的时候,可以更好的理解
圆弧
是如何画出来的。

函数的签名如下:

 def ruler(sc: Scene, p1, p2, angle=PI, axis=OUT):
"""
圆规动画


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

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

实现动画的思路如下:

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


Parameters
---------
sc
绘制动画的场景
p1
代表圆规的针,绘制时不动的点
p2
代表圆规的笔芯,绘制圆弧的点
angle
绘制圆弧的角度,默认PI,相当于绘制半个圆
axis
只有2个值 IN/OUT,分别表示顺时针还是逆时针作弧
"""
d1 = Dot(point=p1, color=RED)
d2 = Dot(point=p2, color=GREEN)
dl = DashedLine(d1.get_center(), d2.get_center())

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

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=GREEN)
)
)
if np.array_equal(axis, IN):
arc.add_updater(
lambda z: z.become(
ArcBetweenPoints(d2.get_center(), p2, radius=r, stroke_color=GREEN)
)
)

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

动画效果

封装之后,使用起来非常简单:

 # -*- 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()

上面演示了逆时针(默认是逆时针)和顺时针方式绘制半圆。
out.gif

各个元素的颜色等相关属性,没有暴露到函数参数中,可以直接在代码中修改。
这里主要演示如何基于

manim
制作多元素动画的。

标签: python

添加新评论