概要 前端時間做尺規作圖相關的動畫的時候,封裝了一個圓規的動畫,順便研究了下 manim 庫的動畫函數。 manim 本身就是做動畫的庫,所以,基於它封裝自定義的動畫非常方便。 動畫原理 對於單個的元素,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
各個參數的含義參見註釋。
實現動畫的思路如下:
- 構建3個元素,也就是
d1
(根據參數中p1坐標繪製的點),d2
(根據參數中p2坐標繪製的點)以及dl
(連接p1和p2的虛線) - 設置
dl
的動畫,隨著d1
和d2
變化不斷重新繪製(這裡d1
其實是不會變的) - 再設置圓弧的動畫,隨著
d2
的變動,不斷繪製新的圓弧 - 通過
manim
自帶的動畫函數讓d2
先動,其他動畫則會隨之一起 - 最後刪除不必要的元素,只保留圓弧在 場景(
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()
上面演示了逆時針(預設是逆時針)和順時針方式繪製半圓。
各個元素的顏色等相關屬性,沒有暴露到函數參數中,可以直接在代碼中修改。
這裡主要演示如何基於 manim
製作多元素動畫的。