因为我是小白,所以我第一次制作效果可能不是太好,生成上述视频的代码如下所示:
from manim import *
# 适配 ManimCE v0.18+
class EuclidEquilateralConstruction(MovingCameraScene):
def construct(self):
# ===== 基本参数 =====
A = LEFT * 3 + DOWN * 1
B = RIGHT * 3 + DOWN * 1
color_segment = YELLOW
color_circleA = BLUE
color_circleB = GREEN
color_triangle = RED
# ===== 标题 =====
title = Text("欧几里得作图:在给定线段上作等边三角形", font="Noto Sans CJK SC", weight=BOLD).to_edge(UP)
subtitle = Text("命题 I:给定线段 AB,作等边三角形 ABC", font="Noto Sans CJK SC").next_to(title, DOWN, buff=0.2)
self.play(FadeIn(title, shift=UP*0.3), FadeIn(subtitle, shift=UP*0.3))
self.wait(0.5)
# ===== 给定线段 AB =====
dotA = Dot(A, color=WHITE)
dotB = Dot(B, color=WHITE)
labelA = MathTex("A").next_to(dotA, DOWN)
labelB = MathTex("B").next_to(dotB, DOWN)
segAB = Line(A, B, color=color_segment)
self.play(Create(segAB), FadeIn(dotA), FadeIn(dotB), FadeIn(labelA), FadeIn(labelB))
self.wait(0.5)
note1 = Text("已知线段 AB", font="Noto Sans CJK SC").scale(0.6).to_edge(DOWN)
self.play(Write(note1))
self.wait(0.5)
# ===== 以 A 为圆心、AB 为半径作圆 =====
circleA = Circle(radius=segAB.get_length(), color=color_circleA).move_to(A)
braceA = BraceBetweenPoints(A, B, direction=UP)
braceA_text = braceA.get_tex("AB")
self.play(GrowFromCenter(circleA), FadeIn(braceA), FadeIn(braceA_text))
self.wait(0.5)
note2 = Text("以 A 为圆心、AB 为半径作圆", font="Noto Sans CJK SC").scale(0.6).to_edge(DOWN)
self.play(ReplacementTransform(note1, note2))
self.wait(0.5)
# ===== 以 B 为圆心、BA 为半径作圆 =====
circleB = Circle(radius=segAB.get_length(), color=color_circleB).move_to(B)
self.play(GrowFromCenter(circleB))
self.wait(0.5)
note3 = Text("以 B 为圆心、BA 为半径作圆", font="Noto Sans CJK SC").scale(0.6).to_edge(DOWN)
self.play(ReplacementTransform(note2, note3))
self.wait(0.5)
# ===== 两圆交点 C(取上方交点)=====
# 解析几何求交点(上方)
# 圆心分别为 A(x1,y1), B(x2,y2),半径相等 r = |AB|
# 两圆连线的中垂线上,交点到中点的距离 h = sqrt(r^2 - (d/2)^2)
A_np = A
B_np = B
mid = (A_np + B_np) / 2
d = np.linalg.norm(B_np - A_np)
r = d
# 单位法向向量(垂直于 AB,指向上方)
dir_vec = B_np - A_np
perp = np.array([-dir_vec[1], dir_vec[0], 0.0])
perp = perp / np.linalg.norm(perp)
h = np.sqrt(max(r**2 - (d/2)**2, 0))
C = mid + h * perp # 上方交点
dotC = Dot(C, color=WHITE)
labelC = MathTex("C").next_to(dotC, UP*0.6)
self.play(FadeIn(dotC, scale=0.8), FadeIn(labelC))
self.wait(0.5)
note4 = Text("两圆交于点 C", font="Noto Sans CJK SC").scale(0.6).to_edge(DOWN)
self.play(ReplacementTransform(note3, note4))
self.wait(0.5)
# ===== 连接 AC、BC 得等边三角形 =====
segAC = Line(A, C, color=color_triangle)
segBC = Line(B, C, color=color_triangle)
tri = VGroup(segAB.copy(), segAC, segBC)
self.play(Create(segAC), Create(segBC))
self.wait(0.5)
# ===== 高亮等边性质:AB = BC = CA =====
# 用弧或标注方式表示相等
mark1 = CurvedDoubleArrow(A + 0.18*(C-A), B + 0.18*(C-B), color=YELLOW, tip_length=0.15)
mark2 = CurvedDoubleArrow(B + 0.18*(A-B), C + 0.18*(A-C), color=YELLOW, tip_length=0.15)
mark3 = CurvedDoubleArrow(C + 0.18*(B-C), A + 0.18*(B-A), color=YELLOW, tip_length=0.15)
eq_text = MathTex("AB = BC = CA", color=YELLOW).scale(1.0).to_edge(LEFT).shift(UP*0.5)
self.play(Create(mark1), Create(mark2), Create(mark3))
self.play(FadeIn(eq_text, shift=RIGHT*0.3))
self.wait(0.5)
# ===== 解释文字 =====
reasoning = VGroup(
Text("理由:", font="Noto Sans CJK SC").scale(0.6),
Text("C 在以 A 为圆心、AB 为半径的圆上 ⇒ AC = AB;", font="Noto Sans CJK SC").scale(0.6),
Text("C 也在以 B 为圆心、BA 为半径的圆上 ⇒ BC = BA;", font="Noto Sans CJK SC").scale(0.6),
Text("而 AB = BA,故 AB = BC = CA。", font="Noto Sans CJK SC").scale(0.6),
).arrange(DOWN, aligned_edge=LEFT).to_edge(RIGHT).shift(DOWN*0.5)
self.play(LaggedStart(*[Write(m) for m in reasoning], lag_ratio=0.2))
self.wait(1.0)
# ===== 收尾:淡出圆,只留等边三角形与结论 =====
self.play(FadeOut(circleA), FadeOut(circleB), FadeOut(braceA), FadeOut(braceA_text), FadeOut(mark1), FadeOut(mark2), FadeOut(mark3), FadeOut(note4))
final_box = SurroundingRectangle(tri, color=WHITE, buff=0.2)
conclusion = Text("作图完成:△ABC 为等边三角形", font="Noto Sans CJK SC").to_edge(DOWN)
self.play(Create(final_box), FadeIn(conclusion))
self.wait(1.5)
# 轻微镜头移动以增强传统“定格”效果
self.play(self.camera.frame.animate.shift(UP*0.1).set_width(self.camera.frame.get_width()*0.98), run_time=1.5)
self.wait(1.0) ,,上面这些代码如何用manim运行
