多元微积分可视化

直角坐标计算二重积分

围绕直角坐标计算二重积分,观察二重积分、累次积分、曲顶柱体之间的关系与推理路径。

打开原视频

torus_volume_integral.py
1from manim import *2import numpy as np3 4class TorusVolumeIntegral(ThreeDScene):5    def construct(self):6        # 在开始添加标题7        title = Text("直角坐标计算二重积分", font="SimSun", font_size=36)8        title.to_edge(UP)9        self.add_fixed_in_frame_mobjects(title)10        self.play(Write(title))11        self.wait(1)12 13        # 设置相机角度(初始视角旋转180度)14        self.set_camera_orientation(15            phi=65 * DEGREES, 16            theta=(30 + 260) * DEGREES  # 增加180度17        )18        19        # 创建3D坐标系并向左移动20        axes = ThreeDAxes(21            x_range=[0, 4],22            y_range=[0, 2],23            z_range=[0, 4],24            x_length=6,25            y_length=6,26            z_length=4,27            axis_config={28                "color": GREY,29                "include_numbers": False  # 移除数字标识30            }31        ).shift(LEFT * 2)  # 向左移动3个单位32 33        # 添加坐标轴标签34        x_label = MathTex("x").next_to(axes.x_axis.get_end(), RIGHT)35        y_label = MathTex("y").next_to(axes.y_axis.get_end(), UP)36        z_label = MathTex("z").next_to(axes.z_axis.get_end(), OUT)37        axes_labels = VGroup(x_label, y_label, z_label)38 39        # 显示坐标系和标签40        self.play(Create(axes))41        self.play(Write(axes_labels))42        self.wait(1)43 44        # 创建底面区域的边界曲线45        def curve1(x): return np.sqrt(x)  # y = √x46        def curve2(x): return (1/5)*(x-1)**2  # y = (1/5)(x-1)²47        48        x_vals = np.linspace(1, 3, 100)49        curve1_points = [[x, curve1(x), 0] for x in x_vals]50        curve2_points = [[x, curve2(x), 0] for x in x_vals]51        52        # 创建完整的底面区域轮廓53        region_points = [54            *curve1_points,  # 上边界:y = √x55            [3, curve2(3), 0],  # 右边界:x = 356            *curve2_points[::-1],  # 下边界:y = (1/5)(x-1)²57            [1, curve2(1), 0],  # 左边界:x = 158        ]59        60        # 创建底面61        region = Polygon(62            *[axes.c2p(*p) for p in region_points],63            color=BLUE,64            fill_opacity=0.365        )66 67        # 创建高度函数68        def height_func(x, y):69            return 2 - (1/10)*(x**2 + y**2)70 71        # 创建立体图形(包括顶面和侧面)72        # 顶面73        def param_surface(u, v):74            x = u75            y = v * curve1(x) + (1-v) * curve2(x)76            return axes.c2p(x, y, height_func(x, y))77 78        top_surface = Surface(79            param_surface,80            u_range=[1, 3],81            v_range=[0, 1],82            resolution=(30, 30),83            fill_opacity=0.7,84            fill_color=BLUE,85            stroke_color=WHITE,86            stroke_width=0.587        )88 89        # 添加曲面方程标注90        surface_equation = MathTex(91            r"z=f(x,y)",92            font_size=32,93            color=BLUE94        ).move_to(95            axes.c2p(2, 1, height_func(2, 1) + 0.5)  # 将标注放在曲面上方96        )97        self.play(Write(surface_equation))98 99        # 创建所有侧面100        side_surfaces = VGroup()101        102        # 前侧面(x=1)103        front_surface = Surface(104            lambda u, v: axes.c2p(105                1,  # x固定为1106                u,  # y从下边界到上边界107                v * height_func(1, u)  # z从0到对应高度108            ),109            u_range=[curve2(1), curve1(1)],110            v_range=[0, 1],  # 使用参数v来控制高度111            fill_opacity=0,  # 完全透明112            fill_color=BLUE_E,113            stroke_color=BLUE_E,114            stroke_width=2115        )116        117        # 后侧面(x=3)118        back_surface = Surface(119            lambda u, v: axes.c2p(120                3,  # x固定为3121                u,  # y从下边界到上边界122                v * height_func(3, u)  # z从0到对应高度123            ),124            u_range=[curve2(3), curve1(3)],125            v_range=[0, 1],  # 使用参数v来控制高度126            fill_opacity=0,  # 完全透明127            fill_color=BLUE_E,128            stroke_color=BLUE_E,129            stroke_width=2130        )131 132        # 上边界曲面(y = √x)133        upper_surface = Surface(134            lambda u, v: axes.c2p(135                u,136                curve1(u),137                v * height_func(u, curve1(u))138            ),139            u_range=[1, 3],140            v_range=[0, 1],141            fill_opacity=0,  # 完全透明142            fill_color=BLUE_E,143            stroke_color=BLUE_E,144            stroke_width=2145        )146 147        # 下边界曲面(y = (1/5)(x-1)²)148        lower_surface = Surface(149            lambda u, v: axes.c2p(150                u,151                curve2(u),152                v * height_func(u, curve2(u))153            ),154            u_range=[1, 3],155            v_range=[0, 1],156            fill_opacity=0,  # 完全透明157            fill_color=BLUE_E,158            stroke_color=BLUE_E,159            stroke_width=2160        )161 162        # 底面163        bottom_surface = Surface(164            lambda u, v: axes.c2p(165                u,166                v * curve1(u) + (1-v) * curve2(u),167                0168            ),169            u_range=[1, 3],170            v_range=[0, 1],171            fill_opacity=0,  # 完全透明172            fill_color=BLUE,173            stroke_color=BLUE,174            stroke_width=2175        )176 177        side_surfaces.add(front_surface, back_surface, upper_surface, lower_surface, bottom_surface)178 179        # 添加边界函数标注180        boundary_labels = VGroup(181            # 上边界标注182            MathTex(r"y=\varphi_2(x)", font_size=32).next_to(183                axes.c2p(2, curve1(2), 0),184                UP,185                buff=0.2186            ),187            # 下边界标注188            MathTex(r"y=\varphi_1(x)", font_size=32).next_to(189                axes.c2p(2, curve2(2), 0),190                DOWN,191                buff=0.2192            )193        )194 195        # 添加x=a和x=b的边界标注196        x_boundary_labels = VGroup(197            MathTex(r"x=a", font_size=32).next_to(198                axes.c2p(1, 0, 0),199                DOWN,200                buff=0.2201            ),202            MathTex(r"x=b", font_size=32).next_to(203                axes.c2p(3, 0, 0),204                DOWN,205                buff=0.2206            )207        )208 209        # 修改显示顺序210        # 1. 显示顶面211        self.play(Create(top_surface))212        self.wait(1)213 214        # 2. 显示底面215        self.play(Create(bottom_surface))216        self.wait(1)217 218        # 3. 显示边界函数标注219        self.play(220            Write(boundary_labels),221            Write(x_boundary_labels)222        )223        self.wait(1)224 225        # 4. 显示侧面226        self.play(227            Create(front_surface),228            Create(back_surface),229            Create(upper_surface),230            Create(lower_surface)231        )232        self.wait(1)233 234        # 创建切片平面(x=2和x=2.1)235        def create_slice_plane(x_val):236            y_min = curve2(x_val)237            y_max = curve1(x_val)238            239            # 创建填充面240            slice_plane = Surface(241                lambda u, v: axes.c2p(242                    x_val,243                    u,244                    v * height_func(x_val, u)245                ),246                u_range=[y_min, y_max],247                v_range=[0, 1],248                fill_opacity=0.8,249                stroke_width=0250            )251            252            # 创建完整边界253            slice_border = VGroup(254                # 上边界曲线255                ParametricFunction(256                    lambda t: axes.c2p(257                        x_val,258                        t,259                        height_func(x_val, t)260                    ),261                    t_range=[y_min, y_max],262                    color=YELLOW,263                    stroke_width=2264                ),265                # 下边界(底部)266                ParametricFunction(267                    lambda t: axes.c2p(x_val, t, 0),268                    t_range=[y_min, y_max],269                    color=YELLOW,270                    stroke_width=2271                ),272                # 左边界273                Line(274                    axes.c2p(x_val, y_min, 0),275                    axes.c2p(x_val, y_min, height_func(x_val, y_min)),276                    color=YELLOW,277                    stroke_width=2278                ),279                # 右边界280                Line(281                    axes.c2p(x_val, y_max, 0),282                    axes.c2p(x_val, y_max, height_func(x_val, y_max)),283                    color=YELLOW,284                    stroke_width=2285                )286            )287            288            return VGroup(slice_plane, slice_border)289 290        # 创建两个切片291        slice_1 = create_slice_plane(2.0)292        slice_1[0].set_fill(color=YELLOW)  # 设置填充颜色293        slice_2 = create_slice_plane(2.1)294        slice_2[0].set_fill(color=YELLOW)  # 设置填充颜色295 296        # 显示立体图形和切片297        # self.play(298        #     Create(top_surface),299        #     Create(side_surfaces)300        # )301        #self#.wait(1)302        303        self.play(304            Create(slice_1),305            Create(slice_2)306        )307        self.wait(1)308 309        # 修改右侧2D截面显示310        section_axes = Axes(311            x_range=[0, 4],312            y_range=[0, 4],313            x_length=3,314            y_length=4,315            axis_config={316                "color": GREY,317                "include_numbers": False  # 移除数字标识318            }319        ).shift(RIGHT * 4)320 321        # 添加2D坐标轴标签322        section_x_label = MathTex("y").next_to(section_axes.x_axis.get_end(), RIGHT)323        section_y_label = MathTex("z").next_to(section_axes.y_axis.get_end(), UP)324        section_labels = VGroup(section_x_label, section_y_label)325 326        # 固定2D坐标系、标签和截面在屏幕上327        self.add_fixed_in_frame_mobjects(section_axes, section_labels)328 329        # 显示2D坐标系和标签330        self.play(331            Create(section_axes),332            Write(section_labels)333        )334 335        # 在新坐标系中绘制完整截面336        def create_section_curve(x_val):337            y_min = curve2(x_val)338            y_max = curve1(x_val)339            340            # 计算z的范围341            z_max = height_func(x_val, y_min)  # 计算最大高度342            343            return VGroup(344                # 主曲线(y-z平面上的曲线)345                ParametricFunction(346                    lambda t: section_axes.c2p(347                        t,  # y坐标作为横坐标348                        height_func(x_val, t)  # z坐标作为纵坐标349                    ),350                    t_range=[y_min, y_max],351                    color=YELLOW,352                    stroke_width=2353                ),354                # 底边(y轴上的线段)355                Line(356                    section_axes.c2p(y_min, 0),  # 从最小y值开始357                    section_axes.c2p(y_max, 0),  # 到最大y值结束358                    color=YELLOW,359                    stroke_width=2360                ),361                # 左边界(垂直线)362                Line(363                    section_axes.c2p(y_min, 0),364                    section_axes.c2p(y_min, height_func(x_val, y_min)),365                    color=YELLOW,366                    stroke_width=2367                ),368                # 右边界(垂直线)369                Line(370                    section_axes.c2p(y_max, 0),371                    section_axes.c2p(y_max, height_func(x_val, y_max)),372                    color=YELLOW,373                    stroke_width=2374                )375            )376 377        # 定义切片位置和边界378        x_val = 2.0379        y_min = curve2(x_val)  # φ₁(x₀)380        y_max = curve1(x_val)  # φ₂(x₀)381 382        # 创建x=2处的截面曲线383        section_curve = create_section_curve(2.0)384        self.add_fixed_in_frame_mobjects(section_curve)385 386        # 显示截面387        self.play(Create(section_curve))388 389        # 添加z=f(x₀,y)标注390        section_equation = MathTex(391            r"z=f(x_0,y)",392            font_size=28,393            color=YELLOW394        ).move_to(395            section_axes.c2p(396                (y_min + y_max)/2,  # y坐标取中点397                height_func(x_val, (y_min + y_max)/2) + 0.5  # 曲线上方0.5个单位398            )399        )400        self.add_fixed_in_frame_mobjects(section_equation)401        self.play(Write(section_equation))402 403        # 添加φ₁(x₀)和φ₂(x₀)标注404        phi_labels = VGroup(405            # φ₁(x₀)标注406            MathTex(r"\varphi_1(x_0)", font_size=20).next_to(407                section_axes.c2p(y_min, 0),408                LEFT,409                buff=0.1410            ),411            # φ₂(x₀)标注412            MathTex(r"\varphi_2(x_0)", font_size=20).next_to(413                section_axes.c2p(y_max, 0),414                LEFT,415                buff=0.1416            )417        )418        self.add_fixed_in_frame_mobjects(phi_labels)419        self.play(Write(phi_labels))420 421        # 修改标注文字422        section_label = VGroup(423            MathTex(r"x=x_0", font_size=24),424            Text("处的截面", font="SimSun", font_size=24)425        ).arrange(RIGHT, buff=0.1).next_to(section_axes, UP)426        self.add_fixed_in_frame_mobjects(section_label)427        self.play(Write(section_label))428 429        # 在切片内添加A(x₀)标注430        area_label = MathTex(431            r"A(x_0)",432            font_size=28,433            color=YELLOW434        ).move_to(435            section_axes.c2p(436                (y_min + y_max)/2,  # y坐标取中点437                height_func(x_val, (y_min + y_max)/2)/2  # z坐标取高度的一半438            )439        )440        self.add_fixed_in_frame_mobjects(area_label)441        self.play(Write(area_label))442 443        # 添加面积计算公式444        area_formula = MathTex(445            r"A(x_0) = \int_{\varphi_1(x_0)}^{\varphi_2(x_0)} f(x_0,y)dy",446            font_size=28447        ).next_to(section_axes, DOWN, buff=0.5)  # 在坐标系下方显示448        self.add_fixed_in_frame_mobjects(area_formula)449        self.play(Write(area_formula))450 451        # 修改积分公式为两行452        conversion_formulas = VGroup(453            # 第一行:二重积分454            MathTex(455                r"\iint_D f(x,y)dxdy",456                font_size=32457            ),458            # 第二行:等号和累次积分459            VGroup(460                MathTex(r"=", font_size=32),461                MathTex(462                    r"\int_a^b \left(\int_{\varphi_1(x)}^{\varphi_2(x)} f(x,y)dy\right)dx",463                    font_size=32464                )465            ).arrange(RIGHT, buff=0.3)466        ).arrange(DOWN, buff=0.3).to_corner(DL)467 468        # 显示转换公式469        self.add_fixed_in_frame_mobjects(conversion_formulas)470        self.play(Write(conversion_formulas[0]))471        self.wait(0.5)472        self.play(Write(conversion_formulas[1]))473        self.wait(1)474 475        # 最后等待几秒476        self.wait(3)

讲解

这个视频围绕「直角坐标计算二重积分」展开。画面把问题、图像和公式放在同一条理解路径中,让抽象关系先被看见。

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

画面中出现的文字「直角坐标计算二重积分」给出视觉入口。随后画面通过对象创建、移动、淡入淡出和高亮,把抽象命题拆成可以跟随的步骤。

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

核心公式可以写成:

y=φ2(x)y=\varphi_2(x)

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

观察路径

观察路径可以分三步:先锁定「直角坐标计算二重积分」中的核心对象,尤其留意二重积分、累次积分、曲顶柱体之间的联系;再跟随画面中变量、图像或向量的变化;最后回到公式或结论,判断局部变化如何支撑整体关系。

本页可以从二重积分、累次积分、曲顶柱体、坐标网格这些概念进入,继续沿相邻问题观察同一类数学结构。