diameter_moment_of_inertia.py
1from manim import *2import numpy as np3 4class PointMassInertiaScene(ThreeDScene):5 def construct(self):6 # 设置相机7 self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)8 self.camera.set_zoom(0.8)9 10 # 标题11 title = Text("质点的转动惯量", font_size=36)12 title.to_corner(UL)13 self.add_fixed_in_frame_mobjects(title)14 self.play(Write(title), run_time=1)15 16 # 创建坐标系17 axes = ThreeDAxes(18 x_range=[-3, 3, 1],19 y_range=[-3, 3, 1],20 z_range=[-1, 3, 1],21 x_length=6,22 y_length=6,23 z_length=424 )25 26 x_label = axes.get_x_axis_label("x")27 y_label = axes.get_y_axis_label("y")28 z_label = axes.get_z_axis_label("z")29 labels = VGroup(x_label, y_label, z_label)30 31 self.play(32 Create(axes),33 Create(labels),34 run_time=1.535 )36 37 # 创建旋转轴(x轴)38 rotation_axis = Line3D(39 start=np.array([-3, 0, 0]),40 end=np.array([3, 0, 0]),41 color=RED42 )43 axis_label = Text("旋转轴", font_size=24).set_color(RED)44 axis_label.next_to(rotation_axis.get_end(), RIGHT)45 self.add_fixed_in_frame_mobjects(axis_label)46 47 self.play(48 Create(rotation_axis),49 Write(axis_label),50 run_time=151 )52 self.wait(0.5)53 54 # 创建质点55 point_position = np.array([1, 2, 0]) # 修改z坐标为0,使点位于xoy平面56 point = Sphere(radius=0.15, color=BLUE).move_to(point_position)57 point_label = Text("质点m", font_size=24).set_color(BLUE)58 point_label.next_to(point, UP+RIGHT)59 self.add_fixed_in_frame_mobjects(point_label)60 61 self.play(62 Create(point),63 Write(point_label),64 run_time=165 )66 self.wait(0.5)67 68 # 显示质点到旋转轴的距离69 # 找到质点到x轴的最短距离点70 projection_point = np.array([point_position[0], 0, 0])71 72 # 创建从质点到投影点的线段(表示垂直距离)73 distance_line = Line3D(74 start=point_position,75 end=projection_point,76 color=GREEN77 )78 79 # 距离标签使用字母r80 distance_label = MathTex("r", font_size=30).set_color(GREEN)81 distance_label.move_to((point_position + projection_point) / 2 + np.array([0.3, 0.3, 0]))82 self.add_fixed_in_frame_mobjects(distance_label)83 84 self.play(85 Create(distance_line),86 Write(distance_label),87 run_time=1.588 )89 self.wait(1)90 91 # 展示转动惯量公式92 formula = MathTex(r"I = mr^2", font_size=36)93 formula.to_edge(RIGHT).shift(UP * 2)94 self.add_fixed_in_frame_mobjects(formula)95 self.play(Write(formula), run_time=1)96 self.wait(1)97 98 # 演示转动99 self.begin_ambient_camera_rotation(rate=0.2)100 101 self.play(102 Rotating(103 point,104 axis=RIGHT,105 about_point=ORIGIN,106 radians=2*PI,107 run_time=4,108 rate_func=linear109 )110 )111 112 # 显示多个质点的转动惯量113 self.stop_ambient_camera_rotation()114 115 # 淡出单个质点的内容116 self.play(117 FadeOut(point),118 FadeOut(point_label),119 FadeOut(distance_line),120 FadeOut(distance_label),121 run_time=1122 )123 124 # 创建多个质点125 points = []126 point_positions = [127 np.array([1, 2, 0]), # 修改z坐标为0128 np.array([-1, 1, 0]), # 修改z坐标为0129 np.array([0, -1.5, 0]), # 修改z坐标为0130 np.array([-2, -1, 0]) # 修改z坐标为0131 ]132 133 point_masses = [2, 1, 3, 2] # 不同质点的质量,仅用于设置半径大小134 135 for i, pos in enumerate(point_positions):136 p = Sphere(radius=0.1 + 0.05 * point_masses[i], color=BLUE).move_to(pos)137 points.append(p)138 139 # 一次性创建所有质点140 self.play(141 *[Create(p) for p in points],142 run_time=1.5143 )144 145 # 为每个质点创建到旋转轴的距离线146 distance_lines = []147 distance_labels = []148 149 for i, pos in enumerate(point_positions):150 proj = np.array([pos[0], 0, 0])151 line = Line3D(start=pos, end=proj, color=GREEN)152 # 使用字母r_i表示距离153 label = MathTex(f"r_{i+1}", font_size=24).set_color(GREEN)154 label_pos = (pos + proj) / 2 + np.array([0.3, 0.3, 0])155 label.move_to(label_pos)156 157 distance_lines.append(line)158 distance_labels.append(label)159 self.add_fixed_in_frame_mobjects(label)160 161 self.play(162 *[Create(line) for line in distance_lines],163 *[Write(label) for label in distance_labels],164 run_time=2165 )166 167 # 计算每个质点的转动惯量贡献 - 使用字母168 inertia_contributions = []169 170 for i in range(4):171 contrib = MathTex(172 f"I_{i+1} = m_{i+1} r_{i+1}^2",173 font_size=24174 )175 inertia_contributions.append(contrib)176 177 # 垂直排列所有贡献178 contributions_group = VGroup(*inertia_contributions).arrange(DOWN, aligned_edge=LEFT)179 contributions_group.to_corner(DL).shift(UP * 2 + RIGHT)180 181 for contrib in inertia_contributions:182 self.add_fixed_in_frame_mobjects(contrib)183 self.play(Write(contrib), run_time=0.8)184 185 # 总和186 total_inertia = MathTex(187 r"I_{\text{total}} = \sum_i I_i = \sum_i m_i r_i^2",188 font_size=30189 )190 total_inertia.next_to(contributions_group, DOWN, aligned_edge=LEFT)191 self.add_fixed_in_frame_mobjects(total_inertia)192 193 self.play(Write(total_inertia), run_time=1.5)194 195 # 强调总和196 total_box = SurroundingRectangle(total_inertia, buff=0.2, color=YELLOW)197 self.add_fixed_in_frame_mobjects(total_box)198 self.play(Create(total_box), run_time=1)199 self.wait(1)200 201 # 展示所有质点同时转动202 self.begin_ambient_camera_rotation(rate=0.15)203 204 self.play(205 *[Rotating(206 p, 207 axis=RIGHT,208 about_point=ORIGIN, 209 radians=2*PI, 210 run_time=4,211 rate_func=linear212 ) for p in points],213 run_time=4214 )215 216 self.stop_ambient_camera_rotation()217 218 # 结论219 conclusion = Text("从离散质点到连续质量分布", font_size=32)220 conclusion.to_edge(DOWN)221 self.add_fixed_in_frame_mobjects(conclusion)222 223 self.play(224 FadeOut(contributions_group),225 FadeOut(total_inertia),226 FadeOut(total_box),227 Write(conclusion),228 run_time=1.5229 )230 231 self.wait(2)232 233 # 淡出所有元素,为下一个场景做准备234 self.play(235 *[FadeOut(mob) for mob in self.mobjects],236 run_time=1.5237 )238 239 240class DiameterMomentOfInertiaScene(ThreeDScene):241 def construct(self):242 # 设置相机243 self.set_camera_orientation(phi=70 * DEGREES, theta=30 * DEGREES)244 self.camera.set_zoom(0.8)245 246 # 标题 - 居中显示247 title = Text("圆盘对直径的转动惯量", font_size=36)248 title.to_edge(UP) # 居中显示在顶部249 self.add_fixed_in_frame_mobjects(title)250 self.play(Write(title), run_time=1)251 252 # 先创建坐标系253 axes = ThreeDAxes(254 x_range=[-3, 3, 1],255 y_range=[-3, 3, 1],256 z_range=[-1, 3, 1],257 x_length=6,258 y_length=6,259 z_length=4260 )261 262 x_label = axes.get_x_axis_label("x")263 y_label = axes.get_y_axis_label("y")264 z_label = axes.get_z_axis_label("z")265 labels = VGroup(x_label, y_label, z_label)266 267 self.play(268 Create(axes),269 Create(labels),270 run_time=1.5271 )272 273 # 创建圆盘274 disk = Surface(275 lambda u, v: np.array([276 v * np.cos(u),277 v * np.sin(u),278 0279 ]),280 u_range=[0, 2*PI],281 v_range=[0, 2],282 resolution=(24, 10),283 fill_opacity=0.3,284 fill_color=BLUE,285 stroke_color=BLUE_E,286 stroke_width=1287 )288 289 # 创建直径旋转轴(x轴)290 diameter = Line3D(291 start=np.array([-2.5, 0, 0]),292 end=np.array([2.5, 0, 0]),293 color=RED294 )295 axis_label = Text("旋转轴(直径)", font_size=24).set_color(RED)296 axis_label.next_to(diameter.get_end(), RIGHT+UP)297 self.add_fixed_in_frame_mobjects(axis_label)298 299 # 显示圆盘和旋转轴300 self.play(301 Create(disk),302 Create(diameter),303 Write(axis_label),304 run_time=2305 )306 self.wait(1)307 308 # 展示圆盘微元(在圆盘平面内的水平矩形条带)309 strips = []310 strip_heights = [] # 每个条带的y坐标中心位置311 312 num_strips = 10313 strip_colors = [BLUE_B, BLUE_C, BLUE_D, BLUE_E] * 3314 radius = 2 # 圆盘半径315 316 strip_height = (2 * radius) / num_strips # 每个矩形条带的高度317 318 for i in range(num_strips):319 # 计算条带中心的y坐标320 y_center = -radius + (i + 0.5) * strip_height321 strip_heights.append(y_center)322 323 # 根据圆的方程计算该y坐标处的宽度324 width = 2 * np.sqrt(radius**2 - y_center**2)325 326 # 创建矩形条带327 strip = Rectangle(328 width=width,329 height=strip_height,330 fill_opacity=0.4,331 fill_color=strip_colors[i % len(strip_colors)],332 stroke_color=WHITE,333 stroke_width=1334 )335 336 # 将矩形移动到对应位置337 strip.move_to(np.array([0, y_center, 0]))338 strips.append(strip)339 340 # 一次性绘制所有矩形条带341 self.play(342 *[Create(strip) for strip in strips],343 run_time=1.5344 )345 self.wait(1)346 347 # 高亮显示一个条带 - 保持黄色高亮348 highlight_index = 6349 strips[highlight_index].set_fill(YELLOW, opacity=0.7)350 351 # 标记这个条带的y坐标(到x轴的距离)352 y_center = strip_heights[highlight_index]353 354 # 创建标记线和标签 - 使用更明显的颜色355 distance_line = Line3D(356 start=np.array([0, y_center, 0]),357 end=np.array([0, 0, 0]),358 color=ORANGE359 )360 361 # 创建距离标签 - 使用更明显的颜色362 distance_label = MathTex("r", font_size=30).set_color(ORANGE)363 distance_label.move_to(np.array([0.3, y_center/2, 0.1]))364 self.add_fixed_in_frame_mobjects(distance_label)365 366 # 添加微元标签367 dm_label = MathTex("dm", font_size=26).set_color(YELLOW)368 dm_label.move_to(np.array([1, y_center, 0.1]))369 self.add_fixed_in_frame_mobjects(dm_label)370 371 # 显示标记372 self.play(373 Create(distance_line),374 Write(distance_label),375 Write(dm_label),376 run_time=1.5377 )378 self.wait(1)379 380 # 现在开始显示微元计算公式381 # 首先展示单个微元的转动惯量贡献 - 调整位置382 contribution = MathTex(r"dI = r^2 \cdot dm", font_size=28)383 contribution.next_to(title, DOWN, buff=0.5).align_to(title, LEFT).shift(LEFT * 4) # 更靠左显示384 self.add_fixed_in_frame_mobjects(contribution)385 self.play(Write(contribution), run_time=1.5)386 387 # 解释微元的特点 - 右移388 explanation = Text("对于平行于y轴的条带微元,r=|y|是常量", font_size=20)389 explanation.next_to(contribution, RIGHT, buff=1.0)390 self.add_fixed_in_frame_mobjects(explanation)391 self.play(Write(explanation), run_time=1.5)392 393 # 添加I=积分dI的表达式394 integral_connection = MathTex(r"I = \iint_{D} dI", font_size=28)395 integral_connection.next_to(contribution, DOWN, buff=0.4).align_to(contribution, LEFT)396 self.add_fixed_in_frame_mobjects(integral_connection)397 self.play(Write(integral_connection), run_time=1.5)398 399 # 添加I=二重积分r^2dm的表示400 r_squared_dm = MathTex(r"I = \iint_{D} r^2 \, dm", font_size=28)401 r_squared_dm.next_to(integral_connection, DOWN, buff=0.4).align_to(integral_connection, LEFT)402 self.add_fixed_in_frame_mobjects(r_squared_dm)403 self.play(Write(r_squared_dm), run_time=1.5)404 self.wait(0.5) # 减少等待时间405 406 # 展示二重积分形式 - 改用rho表示密度,dsigma表示面积微元407 double_integral = MathTex(r"I = \iint_D y^2 \, \rho \, d\sigma", font_size=24)408 double_integral.next_to(r_squared_dm, DOWN, buff=0.4).align_to(r_squared_dm, LEFT)409 self.add_fixed_in_frame_mobjects(double_integral)410 self.play(Write(double_integral), run_time=1.5)411 412 # 解释二重积分413 integral_explain = Text("D是圆盘区域,dσ是面积微元", font_size=16)414 integral_explain.next_to(double_integral, RIGHT, buff=0.5)415 self.add_fixed_in_frame_mobjects(integral_explain)416 self.play(Write(integral_explain), run_time=1.5)417 self.wait(0.5) # 减少等待时间418 419 # 极坐标下的积分表达式 - 改用rho表示密度420 polar_integral = MathTex(r"I = \rho \int_{0}^{R} \int_{0}^{2\pi} r^2\sin^2\theta \cdot r \, d\theta \, dr", font_size=22)421 polar_integral.next_to(double_integral, DOWN, buff=0.4).align_to(double_integral, LEFT)422 self.add_fixed_in_frame_mobjects(polar_integral)423 self.play(Write(polar_integral), run_time=1.5)424 self.wait(0.5) # 减少等待时间425 426 # 极坐标下的解释 - 修复错误427 explanation_1 = Text("ρ: 面密度", font_size=16)428 explanation_2 = Text("r sin θ: 到x轴的距离", font_size=16)429 polar_explanations = VGroup(explanation_1, explanation_2).arrange(DOWN, aligned_edge=LEFT, buff=0.1)430 polar_explanations.next_to(polar_integral, RIGHT, buff=0.5)431 self.add_fixed_in_frame_mobjects(polar_explanations)432 self.play(Write(polar_explanations), run_time=1.5)433 self.wait(0.5) # 减少等待时间434 435 # 积分计算过程 - 使用rho替代sigma436 calc_1 = MathTex(r"I &= \rho \int_{0}^{R} r^3 \, dr \int_{0}^{2\pi} \sin^2 \theta \, d\theta \\", font_size=20)437 calc_2 = MathTex(r"&= \rho \int_{0}^{R} r^3 \, dr \cdot \pi \\", font_size=20)438 calc_3 = MathTex(r"&= \pi \rho \cdot \frac{R^4}{4} \\", font_size=20)439 calc_4 = MathTex(r"&= \frac{\pi R^2 \rho \cdot R^2}{4} \\", font_size=20)440 calc_5 = MathTex(r"&= \frac{1}{4} M R^2", font_size=20)441 442 calculations = VGroup(calc_1, calc_2, calc_3, calc_4, calc_5).arrange(DOWN, aligned_edge=LEFT, buff=0.15)443 calculations.next_to(polar_integral, DOWN, buff=0.4, aligned_edge=LEFT)444 445 for calc in calculations:446 self.add_fixed_in_frame_mobjects(calc)447 self.play(Write(calc), run_time=0.6) # 减少每步计算的显示时间448 self.wait(0.1) # 减少每步之间的等待时间449 450 # 最终结果451 final_box = SurroundingRectangle(calc_5, buff=0.2, color=YELLOW)452 self.add_fixed_in_frame_mobjects(final_box)453 self.play(Create(final_box), run_time=0.8) # 减少框显示时间454 self.wait(0.2) # 减少等待时间455 456 # 将最终结果显示在屏幕下方,不使用飞入动画457 final_result = MathTex(r"I = \frac{1}{4} M R^2", font_size=32, color=YELLOW)458 final_result.to_edge(DOWN).shift(UP * 0.5)459 self.add_fixed_in_frame_mobjects(final_result)460 self.play(Write(final_result), run_time=1.0) # 缩短结果显示时间461 self.wait(0.5) # 减少最终结果后的等待时间462 463 # 淡出微元划分,只保留整个圆盘464 self.play(465 *[FadeOut(strip) for strip in strips],466 FadeOut(distance_line),467 FadeOut(distance_label),468 FadeOut(dm_label),469 run_time=1.0470 )471 472 # 演示旋转 - 只旋转圆盘473 self.move_camera(phi=90 * DEGREES, theta=0)474 self.begin_ambient_camera_rotation(rate=0.15)475 476 # 只旋转圆盘477 self.play(478 Rotating(479 disk,480 axis=RIGHT,481 radians=2*PI,482 run_time=5,483 rate_func=linear484 ),485 run_time=5486 )487 488 self.stop_ambient_camera_rotation()489 self.wait(2) # 添加一点等待时间后结束490 491 492class CombinedInertiaScene(ThreeDScene):493 def construct(self):494 # 设置相机495 self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)496 self.camera.set_zoom(0.8)497 498 # 标题499 title = Text("转动惯量计算演示", font_size=42)500 title.to_edge(UP)501 self.add_fixed_in_frame_mobjects(title)502 self.play(Write(title), run_time=1.5)503 504 # 介绍文本505 intro = Text("从质点到连续质量分布", font_size=36)506 intro.next_to(title, DOWN, buff=1)507 self.add_fixed_in_frame_mobjects(intro)508 509 self.play(Write(intro), run_time=1.5)510 self.wait(1)511 512 # 淡出介绍513 self.play(514 FadeOut(title),515 FadeOut(intro),516 run_time=1.5517 )518 519 #-------------------------------------------520 # 第一部分:质点的转动惯量521 #-------------------------------------------522 # 标题523 title = Text("质点的转动惯量", font_size=36)524 title.to_edge(UP) # 改为居中显示525 self.add_fixed_in_frame_mobjects(title)526 self.play(Write(title), run_time=1)527 528 # 创建坐标系529 axes = ThreeDAxes(530 x_range=[-3, 3, 1],531 y_range=[-3, 3, 1],532 z_range=[-1, 3, 1],533 x_length=6,534 y_length=6,535 z_length=4536 )537 538 x_label = axes.get_x_axis_label("x")539 y_label = axes.get_y_axis_label("y")540 z_label = axes.get_z_axis_label("z")541 labels = VGroup(x_label, y_label, z_label)542 543 self.play(544 Create(axes),545 Create(labels),546 run_time=1.5547 )548 549 # 创建旋转轴(x轴)- 修改为x轴550 rotation_axis = Line3D(551 start=np.array([-3, 0, 0]),552 end=np.array([3, 0, 0]),553 color=RED554 )555 axis_label = Text("旋转轴", font_size=24).set_color(RED)556 axis_label.next_to(rotation_axis.get_end(), RIGHT)557 self.add_fixed_in_frame_mobjects(axis_label)558 559 self.play(560 Create(rotation_axis),561 Write(axis_label),562 run_time=1563 )564 self.wait(0.5)565 566 # 创建质点567 point_position = np.array([1, 2, 0]) # 修改z坐标为0,使点位于xoy平面568 point = Sphere(radius=0.15, color=BLUE).move_to(point_position)569 point_label = Text("质点m", font_size=24).set_color(BLUE)570 point_label.next_to(point, UP+RIGHT)571 self.add_fixed_in_frame_mobjects(point_label)572 573 self.play(574 Create(point),575 Write(point_label),576 run_time=1577 )578 self.wait(0.5)579 580 # 显示质点到旋转轴的距离581 # 找到质点到x轴的最短距离点582 projection_point = np.array([point_position[0], 0, 0])583 584 # 创建从质点到投影点的线段(表示垂直距离)585 distance_line = Line3D(586 start=point_position,587 end=projection_point,588 color=GREEN589 )590 591 # 距离标签使用字母r592 distance_label = MathTex("r", font_size=30).set_color(GREEN)593 # 调整标签位置594 distance_label.move_to((point_position + projection_point) / 2 + np.array([0.3, 0.3, 0]))595 self.add_fixed_in_frame_mobjects(distance_label)596 597 self.play(598 Create(distance_line),599 Write(distance_label),600 run_time=1.5601 )602 self.wait(1)603 604 # 展示转动惯量公式605 formula = MathTex(r"I = mr^2", font_size=36)606 formula.to_edge(RIGHT).shift(UP * 2)607 self.add_fixed_in_frame_mobjects(formula)608 self.play(Write(formula), run_time=1)609 self.wait(1)610 611 # 演示转动612 self.begin_ambient_camera_rotation(rate=0.2)613 614 self.play(615 Rotating(616 point,617 axis=RIGHT, # 修改为绕x轴旋转618 about_point=ORIGIN,619 radians=2*PI,620 run_time=4,621 rate_func=linear622 )623 )624 625 # 显示多个质点的转动惯量626 self.stop_ambient_camera_rotation()627 628 # 淡出单个质点的内容629 self.play(630 FadeOut(point),631 FadeOut(point_label),632 FadeOut(distance_line),633 FadeOut(distance_label),634 run_time=1635 )636 637 # 创建多个质点638 points = []639 point_positions = [640 np.array([1, 2, 0]), # 修改z坐标为0641 np.array([-1, 1, 0]), # 修改z坐标为0642 np.array([0, -1.5, 0]), # 修改z坐标为0643 np.array([-2, -1, 0]) # 修改z坐标为0644 ]645 646 point_masses = [2, 1, 3, 2] # 不同质点的质量,仅用于设置半径大小647 648 for i, pos in enumerate(point_positions):649 p = Sphere(radius=0.1 + 0.05 * point_masses[i], color=BLUE).move_to(pos)650 points.append(p)651 652 # 一次性创建所有质点653 self.play(654 *[Create(p) for p in points],655 run_time=1.5656 )657 658 # 为每个质点创建到旋转轴的距离线659 distance_lines = []660 distance_labels = []661 662 for i, pos in enumerate(point_positions):663 proj = np.array([pos[0], 0, 0]) # 修改为到x轴的投影664 line = Line3D(start=pos, end=proj, color=GREEN)665 # 使用字母r_i表示距离666 label = MathTex(f"r_{i+1}", font_size=24).set_color(GREEN)667 label_pos = (pos + proj) / 2 + np.array([0.3, 0.3, 0])668 label.move_to(label_pos)669 670 distance_lines.append(line)671 distance_labels.append(label)672 self.add_fixed_in_frame_mobjects(label)673 674 self.play(675 *[Create(line) for line in distance_lines],676 *[Write(label) for label in distance_labels],677 run_time=2678 )679 680 # 计算每个质点的转动惯量贡献 - 使用字母681 inertia_contributions = []682 683 for i in range(4):684 contrib = MathTex(685 f"I_{i+1} = m_{i+1} r_{i+1}^2",686 font_size=24687 )688 inertia_contributions.append(contrib)689 690 # 垂直排列所有贡献691 contributions_group = VGroup(*inertia_contributions).arrange(DOWN, aligned_edge=LEFT)692 contributions_group.to_corner(DL).shift(UP * 2 + RIGHT)693 694 for contrib in inertia_contributions:695 self.add_fixed_in_frame_mobjects(contrib)696 self.play(Write(contrib), run_time=0.8)697 698 # 总和699 total_inertia = MathTex(700 r"I_{\text{total}} = \sum_i I_i = \sum_i m_i r_i^2",701 font_size=30702 )703 total_inertia.next_to(contributions_group, DOWN, aligned_edge=LEFT)704 self.add_fixed_in_frame_mobjects(total_inertia)705 706 self.play(Write(total_inertia), run_time=1.5)707 708 # 强调总和709 total_box = SurroundingRectangle(total_inertia, buff=0.2, color=YELLOW)710 self.add_fixed_in_frame_mobjects(total_box)711 self.play(Create(total_box), run_time=1)712 self.wait(1)713 714 # 展示所有质点同时转动715 self.begin_ambient_camera_rotation(rate=0.15)716 717 self.play(718 *[Rotating(719 p, 720 axis=RIGHT, # 修改为绕x轴旋转721 about_point=ORIGIN, 722 radians=2*PI, 723 run_time=4,724 rate_func=linear725 ) for p in points],726 run_time=4727 )728 729 self.stop_ambient_camera_rotation()730 731 # 结论和过渡到下一部分732 transition = Text("从离散质点到连续质量分布", font_size=32)733 transition.to_edge(DOWN)734 self.add_fixed_in_frame_mobjects(transition)735 736 self.play(737 FadeOut(contributions_group),738 FadeOut(total_inertia),739 FadeOut(total_box),740 Write(transition),741 run_time=1.5742 )743 744 self.wait(2)745 746 # 淡出所有元素,为下一个场景做准备747 self.play(748 *[FadeOut(mob) for mob in self.mobjects],749 run_time=1.5750 )751 752 #-------------------------------------------753 # 第二部分:圆盘对直径的转动惯量754 #-------------------------------------------755 756 # 重新设置相机757 self.set_camera_orientation(phi=70 * DEGREES, theta=30 * DEGREES)758 self.camera.set_zoom(0.8)759 760 # 标题 - 居中显示761 title = Text("圆盘对直径的转动惯量", font_size=36)762 title.to_edge(UP) # 居中显示在顶部763 self.add_fixed_in_frame_mobjects(title)764 self.play(Write(title), run_time=1)765 766 # 先创建坐标系767 axes = ThreeDAxes(768 x_range=[-3, 3, 1],769 y_range=[-3, 3, 1],770 z_range=[-1, 3, 1],771 x_length=6,772 y_length=6,773 z_length=4774 )775 776 x_label = axes.get_x_axis_label("x")777 y_label = axes.get_y_axis_label("y")778 z_label = axes.get_z_axis_label("z")779 labels = VGroup(x_label, y_label, z_label)780 781 self.play(782 Create(axes),783 Create(labels),784 run_time=1.5785 )786 787 # 创建圆盘788 disk = Surface(789 lambda u, v: np.array([790 v * np.cos(u),791 v * np.sin(u),792 0793 ]),794 u_range=[0, 2*PI],795 v_range=[0, 2],796 resolution=(24, 10),797 fill_opacity=0.3,798 fill_color=BLUE,799 stroke_color=BLUE_E,800 stroke_width=1801 )802 803 # 创建直径旋转轴(x轴)804 diameter = Line3D(805 start=np.array([-2.5, 0, 0]),806 end=np.array([2.5, 0, 0]),807 color=RED808 )809 axis_label = Text("旋转轴(直径)", font_size=24).set_color(RED)810 axis_label.next_to(diameter.get_end(), RIGHT+UP)811 self.add_fixed_in_frame_mobjects(axis_label)812 813 # 显示圆盘和旋转轴814 self.play(815 Create(disk),816 Create(diameter),817 Write(axis_label),818 run_time=2819 )820 self.wait(1)821 822 # 展示圆盘微元(在圆盘平面内的水平矩形条带)823 strips = []824 strip_heights = [] # 每个条带的y坐标中心位置825 826 num_strips = 10827 strip_colors = [BLUE_B, BLUE_C, BLUE_D, BLUE_E] * 3828 radius = 2 # 圆盘半径829 830 strip_height = (2 * radius) / num_strips # 每个矩形条带的高度831 832 for i in range(num_strips):833 # 计算条带中心的y坐标834 y_center = -radius + (i + 0.5) * strip_height835 strip_heights.append(y_center)836 837 # 根据圆的方程计算该y坐标处的宽度838 width = 2 * np.sqrt(radius**2 - y_center**2)839 840 # 创建矩形条带841 strip = Rectangle(842 width=width,843 height=strip_height,844 fill_opacity=0.4,845 fill_color=strip_colors[i % len(strip_colors)],846 stroke_color=WHITE,847 stroke_width=1848 )849 850 # 将矩形移动到对应位置851 strip.move_to(np.array([0, y_center, 0]))852 strips.append(strip)853 854 # 一次性绘制所有矩形条带855 self.play(856 *[Create(strip) for strip in strips],857 run_time=1.5858 )859 self.wait(1)860 861 # 高亮显示一个条带 - 保持黄色高亮862 highlight_index = 6863 strips[highlight_index].set_fill(YELLOW, opacity=0.7)864 865 # 标记这个条带的y坐标(到x轴的距离)866 y_center = strip_heights[highlight_index]867 868 # 创建标记线和标签 - 使用更明显的颜色869 distance_line = Line3D(870 start=np.array([0, y_center, 0]),871 end=np.array([0, 0, 0]),872 color=ORANGE873 )874 875 # 创建距离标签 - 使用更明显的颜色876 distance_label = MathTex("r", font_size=30).set_color(ORANGE)877 distance_label.move_to(np.array([0.3, y_center/2, 0.1]))878 self.add_fixed_in_frame_mobjects(distance_label)879 880 # 添加微元标签881 dm_label = MathTex("dm", font_size=26).set_color(YELLOW)882 dm_label.move_to(np.array([1, y_center, 0.1]))883 self.add_fixed_in_frame_mobjects(dm_label)884 885 # 显示标记886 self.play(887 Create(distance_line),888 Write(distance_label),889 Write(dm_label),890 run_time=1.5891 )892 self.wait(1)893 894 # 现在开始显示微元计算公式895 # 首先展示单个微元的转动惯量贡献 - 调整位置896 contribution = MathTex(r"dI = r^2 \cdot dm", font_size=28)897 contribution.next_to(title, DOWN, buff=0.5).align_to(title, LEFT).shift(LEFT * 4) # 更靠左显示898 self.add_fixed_in_frame_mobjects(contribution)899 self.play(Write(contribution), run_time=1.5)900 901 # 解释微元的特点 - 右移902 explanation = Text("对于平行于y轴的条带微元,r=|y|是形同的", font_size=20)903 explanation.next_to(contribution, RIGHT, buff=1.0)904 self.add_fixed_in_frame_mobjects(explanation)905 self.play(Write(explanation), run_time=1.5)906 907 # 添加I=积分dI的表达式908 integral_connection = MathTex(r"I = \iint_{D} dI", font_size=28)909 integral_connection.next_to(contribution, DOWN, buff=0.4).align_to(contribution, LEFT)910 self.add_fixed_in_frame_mobjects(integral_connection)911 self.play(Write(integral_connection), run_time=1.5)912 913 # 添加I=二重积分r^2dm的表示914 r_squared_dm = MathTex(r"I = \iint_{D} r^2 \, dm", font_size=28)915 r_squared_dm.next_to(integral_connection, DOWN, buff=0.4).align_to(integral_connection, LEFT)916 self.add_fixed_in_frame_mobjects(r_squared_dm)917 self.play(Write(r_squared_dm), run_time=1.5)918 self.wait(0.5) # 减少等待时间919 920 # 展示二重积分形式 - 改用rho表示密度,dsigma表示面积微元921 double_integral = MathTex(r"I = \iint_D y^2 \, \rho \, d\sigma", font_size=24)922 double_integral.next_to(r_squared_dm, DOWN, buff=0.4).align_to(r_squared_dm, LEFT)923 self.add_fixed_in_frame_mobjects(double_integral)924 self.play(Write(double_integral), run_time=1.5)925 926 # 解释二重积分927 integral_explain = Text("D是圆盘区域,dσ是面积微元", font_size=16)928 integral_explain.next_to(double_integral, RIGHT, buff=0.5)929 self.add_fixed_in_frame_mobjects(integral_explain)930 self.play(Write(integral_explain), run_time=1.5)931 self.wait(0.5) # 减少等待时间932 933 # 极坐标下的积分表达式 - 改用rho表示密度934 polar_integral = MathTex(r"I = \rho \int_{0}^{R} \int_{0}^{2\pi} r^2\sin^2\theta \cdot r \, d\theta \, dr", font_size=22)935 polar_integral.next_to(double_integral, DOWN, buff=0.4).align_to(double_integral, LEFT)936 self.add_fixed_in_frame_mobjects(polar_integral)937 self.play(Write(polar_integral), run_time=1.5)938 self.wait(0.5) # 减少等待时间939 940 # 极坐标下的解释 - 修复错误941 explanation_1 = Text("ρ: 面密度", font_size=16)942 explanation_2 = Text("r sin θ: 到x轴的距离", font_size=16)943 polar_explanations = VGroup(explanation_1, explanation_2).arrange(DOWN, aligned_edge=LEFT, buff=0.1)944 polar_explanations.next_to(polar_integral, RIGHT, buff=0.5)945 self.add_fixed_in_frame_mobjects(polar_explanations)946 self.play(Write(polar_explanations), run_time=1.5)947 self.wait(0.5) # 减少等待时间948 949 # 积分计算过程 - 使用rho替代sigma950 calc_1 = MathTex(r"I &= \rho \int_{0}^{R} r^3 \, dr \int_{0}^{2\pi} \sin^2 \theta \, d\theta \\", font_size=20)951 calc_2 = MathTex(r"&= \rho \int_{0}^{R} r^3 \, dr \cdot \pi \\", font_size=20)952 calc_3 = MathTex(r"&= \pi \rho \cdot \frac{R^4}{4} \\", font_size=20)953 calc_4 = MathTex(r"&= \frac{\pi R^2 \rho \cdot R^2}{4} \\", font_size=20)954 calc_5 = MathTex(r"&= \frac{1}{4} M R^2", font_size=20)955 956 calculations = VGroup(calc_1, calc_2, calc_3, calc_4, calc_5).arrange(DOWN, aligned_edge=LEFT, buff=0.15)957 calculations.next_to(polar_integral, DOWN, buff=0.4, aligned_edge=LEFT)958 959 for calc in calculations:960 self.add_fixed_in_frame_mobjects(calc)961 self.play(Write(calc), run_time=0.6) # 减少每步计算的显示时间962 self.wait(0.1) # 减少每步之间的等待时间963 964 # 最终结果965 final_box = SurroundingRectangle(calc_5, buff=0.2, color=YELLOW)966 self.add_fixed_in_frame_mobjects(final_box)967 self.play(Create(final_box), run_time=0.8) # 减少框显示时间968 self.wait(0.2) # 减少等待时间969 970 # 将最终结果显示在屏幕下方,不使用飞入动画971 final_result = MathTex(r"I = \frac{1}{4} M R^2", font_size=32, color=YELLOW)972 final_result.to_edge(DOWN).shift(UP * 0.5)973 self.add_fixed_in_frame_mobjects(final_result)974 self.play(Write(final_result), run_time=1.0) # 缩短结果显示时间975 self.wait(0.5) # 减少最终结果后的等待时间976 977 # 淡出微元划分,只保留整个圆盘978 self.play(979 *[FadeOut(strip) for strip in strips],980 FadeOut(distance_line),981 FadeOut(distance_label),982 FadeOut(dm_label),983 run_time=1.0984 )985 986 # 演示旋转 - 只旋转圆盘987 self.move_camera(phi=90 * DEGREES, theta=0)988 self.begin_ambient_camera_rotation(rate=0.15)989 990 # 只旋转圆盘991 self.play(992 Rotating(993 disk,994 axis=RIGHT,995 radians=2*PI,996 run_time=5,997 rate_func=linear998 ),999 run_time=51000 )1001 1002 self.stop_ambient_camera_rotation()1003 self.wait(2) # 添加一点等待时间后结束1004 1005 # 删除以下结束语部分1006 # self.move_camera(phi=70 * DEGREES, theta=30 * DEGREES)1007 # 1008 # end_title = Text("转动惯量计算演示完成", font_size=42)1009 # end_title.to_edge(UP)1010 # self.add_fixed_in_frame_mobjects(end_title)1011 # 1012 # conclusion = Text("从微元到积分的物理意义", font_size=36)1013 # conclusion.next_to(end_title, DOWN, buff=1)1014 # self.add_fixed_in_frame_mobjects(conclusion)1015 # 1016 # self.play(1017 # FadeOut(title),1018 # Write(end_title),1019 # Write(conclusion),1020 # run_time=21021 # )1022 # self.wait(2)1023 # 1024 # self.play(1025 # FadeOut(end_title),1026 # FadeOut(conclusion),1027 # run_time=1.51028 # ) 讲解
这个视频围绕「微元法计算转动惯量」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。
开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。
画面中出现的文字「质点的转动惯量」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。
随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。
核心公式可以写成:
这类公式可以和画面中的符号一一对应。
观察路径
观察路径可以分三步:先锁定「微元法计算转动惯量」中的核心对象,尤其留意转动惯量、微元法、定积分之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。
本页可以从转动惯量、微元法、定积分、物理量微元这些概念进入,继续沿相邻问题观察同一类数学结构。