1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
| from manim import * import numpy as np
class ThreeDWorldDemo(ThreeDScene): def construct(self): # 设置相机视角 self.set_camera_orientation(phi=45 * DEGREES, theta=-35 * DEGREES) # 创建坐标系 axes = ThreeDAxes( x_range=[-4, 4, 1], y_range=[-4, 4, 1], z_range=[-4, 4, 1], x_length=8, y_length=8, z_length=8, ).add_coordinates() # 创建球体 sphere = Sphere( radius=3, resolution=(60, 80), stroke_width=0.5, stroke_color=BLUE ).set_color(BLUE).set_opacity(0.3) # 创建示例数据 - 模拟ggb中的点集合 # 这里创建两个示例曲线:一个螺旋线和一个圆形 # 曲线1: 螺旋线 list1 = [] for i in np.linspace(0, 2*np.pi, 50): # (r, theta, phi) - 使用弧度制 r = 3.0 # 固定半径 theta = i # 经度角 phi = i * 0.5 # 纬度角,创建螺旋效果 if phi > np.pi: # 限制phi在[0, π]范围内 phi = np.pi - (phi - np.pi) list1.append((r, theta, phi)) # 曲线2: 赤道上的圆 list2 = [] for i in np.linspace(0, 2*np.pi, 50): r = 2.8 # 稍微小于球体半径 theta = i # 经度角变化 phi = np.pi/2 # 固定phi在π/2,表示赤道 list2.append((r, theta, phi)) # 定义球极坐标转三维坐标的函数 def polar_to_vector(r, theta, phi): """将球坐标(r, theta, phi)转换为笛卡尔坐标(x, y, z)""" x = r * np.sin(phi) * np.cos(theta) y = r * np.sin(phi) * np.sin(theta) z = r * np.cos(phi) return np.array([x, y, z]) # 转换坐标点 list_point1 = [polar_to_vector(r, theta, phi) for r, theta, phi in list1] list_point2 = [polar_to_vector(r, theta, phi) for r, theta, phi in list2] # 创建路径 path1 = VMobject() path1.set_points_smoothly([*list_point1, list_point1[0]]) # 闭合曲线 path1.set_stroke(color=RED, width=3) path1.set_fill(color=RED, opacity=0.2) path2 = VMobject() path2.set_points_smoothly([*list_point2, list_point2[0]]) # 闭合曲线 path2.set_stroke(color=GREEN, width=3) path2.set_fill(color=GREEN, opacity=0.2) # 添加标签 title = Text("球极坐标可视化", font_size=36, color=WHITE).to_edge(UP) label1 = Text("螺旋路径", font_size=24, color=RED).next_to(path1, UP, buff=0.5) label2 = Text("赤道圆", font_size=24, color=GREEN).next_to(path2, DOWN, buff=0.5) # 添加参考网格 sphere_grid = Sphere( radius=3, resolution=(30, 30), stroke_width=0.2, stroke_color=BLUE, fill_opacity=0 ) # 添加坐标轴标签 axes_labels = axes.get_axis_labels( Tex("X").scale(0.7), Tex("Y").scale(0.7), Tex("Z").scale(0.7) ) # 动画序列 self.begin_ambient_camera_rotation(rate=0.1) # 缓慢旋转相机 # 显示标题 self.add_fixed_in_frame_mobjects(title) self.play(Write(title)) self.wait(0.5) # 显示坐标系 self.play(Create(axes), Write(axes_labels)) self.wait(0.5) # 显示球体和网格 self.play( Create(sphere_grid), Create(sphere) ) self.wait(1) # 显示第一条路径 self.play(Create(path1)) self.add_fixed_in_frame_mobjects(label1) self.play(Write(label1)) self.wait(1) # 显示第二条路径 self.play(Create(path2)) self.add_fixed_in_frame_mobjects(label2) self.play(Write(label2)) self.wait(2) # 停止相机旋转,然后围绕场景旋转查看 self.stop_ambient_camera_rotation() self.move_camera( phi=60 * DEGREES, theta=-45 * DEGREES, run_time=3 ) self.wait(2) # 展示坐标转换点 # 从每条路径中选择几个点进行高亮显示 highlight_points1 = [] highlight_points2 = [] for i in range(0, len(list_point1), 10): # 每10个点取一个 point = Dot3D(point=list_point1[i], color=YELLOW, radius=0.05) highlight_points1.append(point) for i in range(0, len(list_point2), 10): point = Dot3D(point=list_point2[i], color=PURPLE, radius=0.05) highlight_points2.append(point) highlight_group1 = VGroup(*highlight_points1) highlight_group2 = VGroup(*highlight_points2) self.play( LaggedStart( *[Create(point) for point in highlight_points1], lag_ratio=0.1 ), LaggedStart( *[Create(point) for point in highlight_points2], lag_ratio=0.1 ) ) self.wait(2) # 清理高亮点 self.play( FadeOut(highlight_group1), FadeOut(highlight_group2), FadeOut(label1), FadeOut(label2) ) self.wait(1) # 最终视图,缓慢旋转展示 self.begin_ambient_camera_rotation(rate=0.05) self.wait(8) self.stop_ambient_camera_rotation() # 淡出所有元素 self.play( FadeOut(title), FadeOut(sphere_grid), FadeOut(sphere), FadeOut(path1), FadeOut(path2), FadeOut(axes), FadeOut(axes_labels) )
|