142 lines
4.4 KiB
Python
142 lines
4.4 KiB
Python
|
# -*- coding: utf-8 -*-.py
|
||
|
# -*- coding: utf-8 -*-
|
||
|
# Skeleton.py
|
||
|
from manim import *
|
||
|
import numpy as np
|
||
|
|
||
|
class Skeleton(Scene):
|
||
|
# 定义坐标轴范围常量
|
||
|
X_MIN = -3.5 * PI
|
||
|
X_MAX = 3.5 * PI
|
||
|
Y_MIN = -1.5
|
||
|
Y_MAX = 1.5
|
||
|
|
||
|
def construct(self):
|
||
|
# 创建坐标系
|
||
|
axes = Axes(
|
||
|
x_range=[self.X_MIN, self.X_MAX, PI],
|
||
|
y_range=[self.Y_MIN, self.Y_MAX, 0.5],
|
||
|
axis_config={
|
||
|
"color": WHITE,
|
||
|
"include_tip": True,
|
||
|
"include_numbers": False,
|
||
|
"tick_size": 0
|
||
|
}
|
||
|
)
|
||
|
|
||
|
# 添加坐标轴标签
|
||
|
x_label = axes.get_x_axis_label(Text("x").scale(0.7), direction=DOWN)
|
||
|
y_label = axes.get_y_axis_label(Text("y").scale(0.7), direction=LEFT)
|
||
|
|
||
|
# 动画展示坐标轴(淡入效果)
|
||
|
self.play(FadeIn(axes), run_time=1)
|
||
|
self.play(Write(x_label), Write(y_label), run_time=1)
|
||
|
|
||
|
# 创建正弦函数曲线
|
||
|
sin_graph = axes.plot(
|
||
|
lambda x: np.sin(x),
|
||
|
color=GREEN
|
||
|
)
|
||
|
|
||
|
# 创建正弦函数标签
|
||
|
sin_label = MathTex(r"\sin(x)").scale(0.7)
|
||
|
sin_label.move_to(axes.c2p(-3 * PI, 1))
|
||
|
|
||
|
# 动画: 绘制正弦曲线和标签
|
||
|
self.play(Create(sin_graph), run_time=3)
|
||
|
self.play(Write(sin_label), run_time=1)
|
||
|
self.wait(1)
|
||
|
|
||
|
# 创建余弦函数曲线(红色)
|
||
|
cos_graph = axes.plot(
|
||
|
lambda x: np.cos(x),
|
||
|
color=RED
|
||
|
)
|
||
|
|
||
|
# 创建余弦函数标签位置(3π,-1)
|
||
|
cos_label = MathTex(r"\cos(x)").scale(0.7)
|
||
|
cos_label.move_to(axes.c2p(3 * PI, -1))
|
||
|
|
||
|
# 动画: 将正弦曲线转换为余弦曲线
|
||
|
self.play(TransformFromCopy(sin_graph, cos_graph), run_time=3)
|
||
|
# 显示余弦函数标签
|
||
|
self.play(Write(cos_label), run_time=1)
|
||
|
self.wait(1)
|
||
|
|
||
|
# 在屏幕上方显示三角函数关系式(黄色)
|
||
|
formula = MathTex(
|
||
|
r"\cos(x) = \sin\left(x + \frac{\pi}{2}\right)",
|
||
|
color=YELLOW
|
||
|
)
|
||
|
formula.to_edge(UP)
|
||
|
self.play(Write(formula), run_time=2)
|
||
|
self.wait(2)
|
||
|
|
||
|
# 创建值追踪器,从 -3π 到 3π
|
||
|
x_tracker = ValueTracker(-3 * PI)
|
||
|
|
||
|
# 创建动态虚线(黄色)
|
||
|
vertical_line = always_redraw(lambda: DashedLine(
|
||
|
start=axes.c2p(x_tracker.get_value(), self.Y_MIN),
|
||
|
end=axes.c2p(x_tracker.get_value(), self.Y_MAX),
|
||
|
color=YELLOW,
|
||
|
stroke_width=2,
|
||
|
dash_length=0.1
|
||
|
))
|
||
|
|
||
|
# 创建动态点(绿色跟踪sin, 红色跟踪cos)
|
||
|
sin_dot = always_redraw(lambda: Dot(
|
||
|
point=axes.c2p(x_tracker.get_value(), np.sin(x_tracker.get_value())),
|
||
|
color=GREEN,
|
||
|
radius=0.08
|
||
|
))
|
||
|
|
||
|
cos_dot = always_redraw(lambda: Dot(
|
||
|
point=axes.c2p(x_tracker.get_value(), np.cos(x_tracker.get_value())),
|
||
|
color=RED,
|
||
|
radius=0.08
|
||
|
))
|
||
|
|
||
|
# 添加动态元素到场景
|
||
|
self.add(vertical_line, sin_dot, cos_dot)
|
||
|
|
||
|
# 播放扫描动画(6秒匀速)
|
||
|
self.play(
|
||
|
x_tracker.animate.set_value(3 * PI),
|
||
|
run_time=6,
|
||
|
rate_func=linear
|
||
|
)
|
||
|
|
||
|
# 最后等待1秒
|
||
|
self.wait(1)
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
# 导入必要的模块
|
||
|
import sys
|
||
|
import os
|
||
|
from manim import *
|
||
|
|
||
|
# 设置 UTF-8 编码
|
||
|
os.environ['PYTHONIOENCODING'] = 'utf-8'
|
||
|
sys.stdout.reconfigure(encoding='utf-8')
|
||
|
sys.stderr.reconfigure(encoding='utf-8')
|
||
|
|
||
|
# 全局指定 ctex 模板(一次性)
|
||
|
config.tex_template = TexTemplateLibrary.ctex
|
||
|
# 设置输出格式为MP4
|
||
|
config.output_format = "mp4"
|
||
|
# 设置输出目录
|
||
|
config.media_dir = "./output/videos/1080p60"
|
||
|
# 使用临时配置渲染场景(配置只在with块内有效)
|
||
|
with tempconfig({
|
||
|
"quality": "high_quality",
|
||
|
"background_color": BLACK,
|
||
|
"preview": True,
|
||
|
"pixel_height": 1080,
|
||
|
"pixel_width": 1920,
|
||
|
"frame_rate": 30
|
||
|
}):
|
||
|
# 实例化场景类
|
||
|
scene = Skeleton()
|
||
|
# 执行渲染流程(包含文件生成和预览)
|
||
|
scene.render()
|