多元微积分可视化

求立体图形体积

围绕求立体图形体积,观察积分求体积、二重积分、空间区域之间的关系与推理路径。

打开原视频

volume_calculation_demo.py
1from manim import *2import numpy as np3 4class VolumeCalculationDemo(ThreeDScene):5    def construct(self):6        # 第一步:清屏显示题目7        problem_title = Text("求立体体积", font_size=32, color=YELLOW)8        problem_desc = Text("求由以下两曲面围成的立体体积", font_size=20, color=WHITE)9        surface_eq1 = MathTex("z = x^2 + y^2", color=BLUE).scale(1.2)10        surface_eq2 = MathTex("z = x + y", color=RED).scale(1.2)11        12        # 居中显示题目13        problem_title.move_to(ORIGIN + UP * 1.5)14        problem_desc.next_to(problem_title, DOWN, buff=0.5)15        surface_eq1.next_to(problem_desc, DOWN, buff=0.8)16        surface_eq2.next_to(surface_eq1, DOWN, buff=0.4)17        18        # 动画1:显示题目和曲面方程19        self.play(Write(problem_title))20        self.wait(1)21        self.play(Write(problem_desc))22        self.wait(1)23        self.play(Write(surface_eq1))24        self.wait(0.8)25        self.play(Write(surface_eq2))26        self.wait(2)27        28        # 动画2:将题目移到右上角保持显示(放大字体)29        title_corner = Text("求立体体积", font_size=24, color=YELLOW).to_corner(UR).shift(LEFT * 0.5 + DOWN * 0.5)30        desc_corner = Text("z=x²+y²与z=x+y围成的立体", font_size=16, color=WHITE).next_to(title_corner, DOWN, buff=0.2)31        32        self.play(33            Transform(problem_title, title_corner),34            Transform(problem_desc, desc_corner),35            FadeOut(surface_eq1),36            FadeOut(surface_eq2)37        )38        self.wait(0.5)39        40        # 设置3D相机41        self.set_camera_orientation(phi=75 * DEGREES, theta=45 * DEGREES)42        43        # 固定题目在屏幕上44        self.add_fixed_in_frame_mobjects(problem_title, problem_desc)45        46        # 创建坐标轴(全屏居中)47        axes = ThreeDAxes(48            x_range=[-2, 2, 0.5],49            y_range=[-2, 2, 0.5],50            z_range=[-1, 3, 0.5],51            x_length=6,52            y_length=6,53            z_length=654        )55        56        # 坐标轴标签57        x_label = axes.get_x_axis_label("x").scale(0.8)58        y_label = axes.get_y_axis_label("y").scale(0.8)59        z_label = axes.get_z_axis_label("z").scale(0.8)60        61        # 动画3:创建坐标轴62        self.play(Create(axes), Write(x_label), Write(y_label), Write(z_label))63        self.wait(1)64        65        # 定义曲面函数66        def paraboloid(u, v):67            return np.array([u, v, u**2 + v**2])68        69        def plane(u, v):70            return np.array([u, v, u + v])71        72        # 创建抛物面 z = x² + y²73        paraboloid_surface = Surface(74            lambda u, v: paraboloid(u, v),75            u_range=[-1.5, 1.5],76            v_range=[-1.5, 1.5],77            resolution=(20, 20),78            fill_color=BLUE,79            fill_opacity=0.7,80            stroke_color=BLUE,81            stroke_width=0.582        )83        84        # 创建平面 z = x + y85        plane_surface = Surface(86            lambda u, v: plane(u, v),87            u_range=[-1.5, 1.5],88            v_range=[-1.5, 1.5],89            resolution=(15, 15),90            fill_color=RED,91            fill_opacity=0.6,92            stroke_color=RED,93            stroke_width=0.594        )95        96        # 创建角落显示的公式(左上角,放大字体)97        surface_eq1_corner = MathTex("z = x^2 + y^2", color=BLUE).scale(0.9).to_corner(UL).shift(DOWN * 0.3 + RIGHT * 0.2)98        surface_eq2_corner = MathTex("z = x + y", color=RED).scale(0.9).next_to(surface_eq1_corner, DOWN, buff=0.2)99        100        # 动画4:显示抛物面和公式101        self.add_fixed_in_frame_mobjects(surface_eq1_corner)102        self.play(Create(paraboloid_surface), Write(surface_eq1_corner))103        self.wait(1)104        105        # 动画5:显示平面和公式106        self.add_fixed_in_frame_mobjects(surface_eq2_corner)107        self.play(Create(plane_surface), Write(surface_eq2_corner))108        self.wait(1)109        110        # 动画6:旋转视角查看两个曲面111        self.move_camera(phi=60 * DEGREES, theta=120 * DEGREES, run_time=3)112        self.wait(1)113        114        # 计算交线:x² + y² = x + y115        # 即 x² - x + y² - y = 0116        # 完成平方:(x - 1/2)² + (y - 1/2)² = 1/2117        118        # 创建交线119        intersection_curve = ParametricFunction(120            lambda t: np.array([121                0.5 + np.sqrt(0.5) * np.cos(t),122                0.5 + np.sqrt(0.5) * np.sin(t),123                0.5 + np.sqrt(0.5) * np.cos(t) + 0.5 + np.sqrt(0.5) * np.sin(t)124            ]),125            t_range=[0, 2*PI],126            color=YELLOW,127            stroke_width=4128        )129        130        # 创建角落显示的交线公式(移动到右边投影区域下面)131        intersection_eq_corner = MathTex("x^2 + y^2 = x + y", color=YELLOW).scale(0.8).to_corner(UR).shift(LEFT * 1.2 + DOWN * 2.0)132        intersection_simplified_corner = MathTex(r"(x-\frac{1}{2})^2 + (y-\frac{1}{2})^2 = \frac{1}{2}", color=YELLOW).scale(0.7).next_to(intersection_eq_corner, DOWN, buff=0.15)133        134        # 动画7:显示交线135        self.play(Create(intersection_curve))136        self.wait(1)137        138        # 动画8:着重显示围成的立体区域139        # 突出显示两个曲面围成的立体140        self.play(141            paraboloid_surface.animate.set_fill_opacity(0.8),142            plane_surface.animate.set_fill_opacity(0.7),143            intersection_curve.animate.set_stroke(width=6),144            run_time=2145        )146        self.wait(1)147        148        # 动画9:先显示投影到xy平面149        # 创建投影圆150        projection_circle = Circle(151            radius=np.sqrt(0.5),152            color=GREEN,153            fill_opacity=0.4,154            stroke_color=GREEN,155            stroke_width=3156        ).shift([0.5, 0.5, 0])157        158        # 投影说明放在题目正下方(左移)159        projection_label = Text("投影区域边界", font_size=20, color=GREEN).to_corner(UR).shift(LEFT * 1.2 + DOWN * 1.5)160        self.add_fixed_in_frame_mobjects(projection_label)161        162        self.play(Create(projection_circle), Write(projection_label))163        self.wait(2)164        165        # 动画10:然后显示交线方程166        self.add_fixed_in_frame_mobjects(intersection_eq_corner)167        self.play(Write(intersection_eq_corner))168        self.wait(1)169        170        # 显示交线简化形式171        self.add_fixed_in_frame_mobjects(intersection_simplified_corner)172        self.play(Write(intersection_simplified_corner))173        self.wait(1)174        175        # 动画11:然后演示z上下限的确定方法176        # 创建一个垂直的线段来显示z的范围177        sample_point = [0.3, 0.3, 0]  # 在积分区域内选择一个点178        z_lower = sample_point[0]**2 + sample_point[1]**2  # 抛物面的z值179        z_upper = sample_point[0] + sample_point[1]  # 平面的z值180        181        # 创建垂直线段182        z_line = Line(183            [sample_point[0], sample_point[1], z_lower],184            [sample_point[0], sample_point[1], z_upper],185            color=ORANGE,186            stroke_width=6187        )188        189        # 标记点190        lower_point = Dot([sample_point[0], sample_point[1], z_lower], color=BLUE, radius=0.1)191        upper_point = Dot([sample_point[0], sample_point[1], z_upper], color=RED, radius=0.1)192        193        # 说明文字(在投影区域下方显示,左移)194        z_demo_text = Text("z的上下限演示", font_size=18, color=ORANGE).to_corner(UR).shift(LEFT * 1.2 + DOWN * 3.5)195        self.add_fixed_in_frame_mobjects(z_demo_text)196        197        self.play(198            Write(z_demo_text),199            Create(z_line),200            Create(lower_point),201            Create(upper_point)202        )203        self.wait(2)204        205        # z的上下限说明(在z演示下方显示,左移)206        z_limit_text = Text("确定z的上下限:", font_size=18, color=ORANGE).to_corner(UR).shift(LEFT * 1.2 + DOWN * 4.5)207        z_limit_label1 = Text("下限:", font_size=16, color=BLUE).next_to(z_limit_text, DOWN, buff=0.2)208        z_limit_eq = MathTex(r"z = x^2 + y^2").scale(0.8).next_to(z_limit_label1, RIGHT, buff=0.2)209        z_limit_label2 = Text("上限:", font_size=16, color=RED).next_to(z_limit_label1, DOWN, buff=0.15)210        z_limit_eq2 = MathTex(r"z = x + y").scale(0.8).next_to(z_limit_label2, RIGHT, buff=0.2)211        212        # 动画12:显示z上下限说明(右边)213        self.add_fixed_in_frame_mobjects(z_limit_text)214        self.play(Write(z_limit_text))215        self.wait(1)216        217        # 动画13:显示z下限218        self.add_fixed_in_frame_mobjects(z_limit_label1, z_limit_eq)219        self.play(Write(z_limit_label1), Write(z_limit_eq))220        self.wait(1)221        222        # 动画14:显示z上限223        self.add_fixed_in_frame_mobjects(z_limit_label2, z_limit_eq2)224        self.play(Write(z_limit_label2), Write(z_limit_eq2))225        self.wait(1)226        227        # 创建详细的计算过程公式(左下角上移并右移0.5个单位)228        step1 = Text("计算步骤:", font_size=18, color=YELLOW).to_corner(DL).shift(UP * 4.5 + RIGHT * 1.5)229        step2 = MathTex(r"V = \iint_D \int_{x^2+y^2}^{x+y} dz \, dx \, dy").scale(0.6).next_to(step1, DOWN, buff=0.15)230        step3 = MathTex(r"D: (x-\frac{1}{2})^2 + (y-\frac{1}{2})^2 \leq \frac{1}{2}").scale(0.55).next_to(step2, DOWN, buff=0.1)231        step4 = MathTex(r"V = \iint_D (x+y-x^2-y^2) \, dx \, dy").scale(0.6).next_to(step3, DOWN, buff=0.1)232        step5 = MathTex(r"x = \frac{1}{2} + r\cos\theta, y = \frac{1}{2} + r\sin\theta").scale(0.55).next_to(step4, DOWN, buff=0.1)233        step6 = MathTex(r"V = \int_0^{2\pi} \int_0^{\sqrt{1/2}} r \cdot (\frac{1}{2} - r^2) \, dr \, d\theta").scale(0.6).next_to(step5, DOWN, buff=0.1)234        step7 = MathTex(r"V = \frac{\pi}{8}", color=GREEN).scale(0.9).next_to(step6, DOWN, buff=0.15)235        236        # 动画15:显示积分设置237        self.move_camera(phi=30 * DEGREES, theta=0 * DEGREES, run_time=2)238        239        # 动画16:显示计算步骤标题(左下角)240        self.add_fixed_in_frame_mobjects(step1)241        self.play(Write(step1))242        self.wait(0.8)243        244        # 动画17:显示积分表达式245        self.add_fixed_in_frame_mobjects(step2)246        self.play(Write(step2))247        self.wait(1)248        249        # 动画18:显示积分区域250        self.add_fixed_in_frame_mobjects(step3)251        self.play(Write(step3))252        self.wait(1)253        254        # 动画19:显示简化的积分255        self.add_fixed_in_frame_mobjects(step4)256        self.play(Write(step4))257        self.wait(1)258        259        # 动画20:显示极坐标变换260        self.add_fixed_in_frame_mobjects(step5)261        self.play(Write(step5))262        self.wait(1.5)263        264        # 动画21:显示极坐标积分(包含具体的f表达式)265        self.add_fixed_in_frame_mobjects(step6)266        self.play(Write(step6))267        self.wait(2)268        269        # 动画22:显示最终结果270        self.add_fixed_in_frame_mobjects(step7)271        self.play(Write(step7))272        self.wait(1)273        274        # 动画23:最终旋转展示275        self.move_camera(phi=75 * DEGREES, theta=360 * DEGREES, run_time=4)276        277        self.wait(2)278        279        # 动画24:最终突出显示(避免放大造成重叠)280        self.play(281            projection_circle.animate.set_fill_opacity(0.6),282            projection_label.animate.scale(1.1),283            step7.animate.scale(1.1),284            run_time=2285        )286        287        self.wait(3)

讲解

这个视频围绕「求立体图形体积」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

开头先建立问题背景和主要对象,让观察从标题、坐标或第一组关系进入。

画面中出现的文字「求立体体积」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。

随后出现更具体的图像或公式提示,动画会把局部对象和整体结论联系起来。这里可以重点观察变量、曲线、区域或向量如何随镜头推进而变化。

核心公式可以写成:

z=x2+y2z = x^2 + y^2

这类公式可以和画面中的符号一一对应。

观察路径

观察路径可以分三步:先锁定「求立体图形体积」中的核心对象,尤其留意积分求体积、二重积分、空间区域之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。

本页可以从积分求体积、二重积分、空间区域、曲面围成区域这些概念进入,继续沿相邻问题观察同一类数学结构。