Bezier 曲线可以用来画不规则曲线
from manim import *
class ClosedBezierCurveWithControlPoints(Scene):
def construct(self):
# 定义控制点的坐标
control_points = [
[0, 0, 0], # 起始点
[.5, 1, 0],
[2, .5, 0], # 控制点 1
[3.5, 1, 0],
[4, 0, 0], # 控制点 3
[2, -1.2, 0], # 控制点 4
[0, 0, 0] # 回到起始点,封闭曲线
]
# 创建 VMobject 对象并设置贝塞尔曲线的控制点
closed_curve = VMobject()
closed_curve.set_points_smoothly(control_points)
closed_curve.close_path() # 确保路径封闭
closed_curve.set_color(BLUE)
# 创建并显示贝塞尔曲线
self.play(Create(closed_curve))
# 在控制点的位置上添加 Dot 来标记
dots = [Dot(point=point, color=RED) for point in control_points]
labels = [Text(f"P{i}", font_size=24).next_to(dots[i], UP) for i in range(len(dots))]
for dot, label in zip(dots, labels):
self.play(FadeIn(dot), Write(label))
self.wait(2)
创建点
dot_P1 = Dot(P1, color=RED) dot_P3 = Dot(P3, color=RED) self.play(FadeIn(dot_P1), FadeIn(dot_P3))
创建线条和虚线条
tangent_line1 = Line(P1, P3, color=YELLOW) self.play(Create(tangent_line)) tangent_line2 = DashedLine(P1, P3, color=YELLOW) self.play(Create(tangent_line), run_time=.5)
镜面对称. 这里的对称轴是过 about_point 以 axis 为方向的直线
如果希望展示旋转过程可以直接 self.play(Rotate())
partial_curve_copy = partial_curve.copy()
self.play(Rotate(partial_curve_copy, angle=-PI, axis=tangent_vector, about_point=midpoint))
如果不希望展示旋转过程就这样
extra_area2_copy = extra_area2.copy() self.add(extra_area2_copy) extra_area2_copy.rotate(angle=-PI, axis=[0,1,0], about_point=ORIGIN) self.play(FadeIn(extra_area2_copy)) self.wait(1)
如何将不同的曲线段合并成一条闭合曲线?
extra_area1 = VMobject() extra_area1.append_vectorized_mobject(partial_curve) extra_area1.append_vectorized_mobject(partial_curve_copy)
如何提取一条曲线的一部分?这里的 0.14 和 0.61 分别是起点和终点, 每个点在范围 [0,1] 中.
partial_curve = VMobject() partial_curve.pointwise_become_partial(closed_curve,0.14, 0.61) partial_curve.set_color(RED)
动态更新点的位置
# 线段AB定义为动态更新
line_ab = always_redraw(lambda: DashedLine(curve_ap.get_start(),
curve_bp.get_end(),
color=YELLOW))
设置图层
# 使用 set_z_index() 方法来设置图层顺序 circle1.set_z_index(1) # 最后渲染,显示在最前面 circle2.set_z_index(0) # 默认图层 circle3.set_z_index(-1) # 最先渲染,显示在最底部
标签
label_a = MathTex("A").next_to(dot_a, RIGHT)
在 Python 中的切片操作遵循以下规则:
- 索引从 0 开始:第一个元素的索引是
0,第二个是1,以此类推。 - 负数索引:负数索引从列表的末尾开始,
-1表示最后一个元素,-2表示倒数第二个元素,以此类推。 - 切片的结束位置是排他的:也就是说,
start:end中的end索引对应的元素并不包含在切片结果中,切片会取到end的前一个位置。
下面代码表示从索引为 7 的元素取到最后一位
one[0][7:]
来回往复运动效果
self.play(Rotate(curve_ap, angle=PI/3, about_point=point_p, rate_func=there_and_back),
Rotate(area1, angle=PI/3, about_point=point_p, rate_func=there_and_back),
run_time=4)
角的圆弧 Angle, 可以用 quadrant 选择象限, other_angle=True 显示补角
Angle( line_bp,line_ap, quadrant=(1,-1), radius=0.5, color=YELLOW)
直角符号
RightAngle(line1, line2, length=0.4, quadrant=(1,-1))
清除更新函数
angle.clear_updaters()
获取线段中点坐标
line.get_center()
轨迹追踪
# 计算半径为A到中点的距离 radius = np.linalg.norm(midpoint- point_a) # 创建半圆的路径(隐藏半圆,仅用于让点P沿路径运动) hidden_semicircle = ArcBetweenPoints(point_a, point_b, angle=PI, radius=radius, color=WHITE, stroke_opacity=0) # 创建点P,初始位置在A point_p = Dot(point_a, color=RED) # 创建线段PA和PB line_pa = always_redraw(lambda: Line(point_p.get_center(), point_a)) line_pb = always_redraw(lambda: Line(point_p.get_center(), point_b)) # 使用 TracedPath 动态追踪P点的路径,绘制出圆弧 traced_path = TracedPath(point_p.get_center, stroke_color=YELLOW, stroke_width=4) # 将点P、线段PA和PB以及追踪路径添加到场景中 self.add(point_p, line_pa, line_pb, traced_path) # 让点P沿着隐藏的半圆路径运动,逐步绘制圆弧 self.play(MoveAlongPath(point_p, hidden_semicircle), run_time=4, rate_func=linear) self.wait()
平滑的移动效果
object.animate.move_to(target_point)
清除所有更新器和上移所有对象
for mob in self.mobjects:
mob.clear_updaters()
self.play(*[obj.animate.shift(UP) for obj in self.mobjects])
打包所有对象
everything1 = Group(*self.mobjects)
打包所有对象,除了某个特定对象
everything1 = Group(*self.mobjects) everything1.remove(title)
也可以这样
self.play(*[obj.animate.shift(UP) for obj in self.mobjects if obj!= title])
导入图片
image = ImageMobject("path/to/your/image.png")
贴到屏幕左边
Weierstrass.to_edge(LEFT, buff=0)