多元微积分可视化

两类曲线积分的转换

用切向量、方向余弦和弧长微元解释第二类曲线积分如何转化为第一类曲线积分。

打开原视频

curve_integral_conversion.py
1from manim import *2import numpy as np3 4config.tex_template = TexTemplateLibrary.ctex5config.tex_template.add_to_preamble(r"\setCJKmainfont{STSong}")6 7 8class CurveIntegralConversion(Scene):9    def construct(self):10        # ========== 标题 ==========11        title = Text('两类曲线积分的转换', font="SimSun", color=YELLOW).scale(0.65)12        title.to_edge(UP, buff=0.3)13        self.play(Write(title), run_time=1)14        self.wait(0.3)15 16        # =============================================17        # 场景1:问题引入——为什么要转换?18        # =============================================19        # 曲线(左到右,波浪形,保证切线角α为正锐角)20        curve_func = lambda t: np.array([21            -2.0 + 1.5 * t,22            0.8 * np.sin(1.8 * t) - 0.3,23            024        ])25        curve = ParametricFunction(curve_func, t_range=[0.2, 2.5], color=WHITE, stroke_width=3)26        self.play(Create(curve), run_time=1.5)27 28        # 起终点29        start_dot = Dot(curve_func(0.2), color=GREEN, radius=0.07)30        end_dot = Dot(curve_func(2.5), color=RED, radius=0.07)31        A_label = MathTex("A", color=GREEN).scale(0.35).next_to(start_dot, DL, buff=0.05)32        B_label = MathTex("B", color=RED).scale(0.35).next_to(end_dot, DR, buff=0.05)33        self.play(FadeIn(start_dot), FadeIn(end_dot), Write(A_label), Write(B_label), run_time=0.6)34 35        # 向量场 F=(P,Q)36        def F_field(pos):37            x, y = pos[0], pos[1]38            return np.array([0.4 * y + 0.3, -0.3 * x + 0.4, 0])39 40        field_arrows = VGroup()41        for t_val in np.linspace(0.3, 2.4, 10):42            pos = curve_func(t_val)43            F_val = F_field(pos)44            F_norm = np.linalg.norm(F_val)45            if F_norm > 0.01:46                F_dir = F_val / F_norm * 0.547                arr = Arrow(pos, pos + F_dir, buff=0, color=BLUE_C, stroke_width=2.5, tip_length=0.08)48                field_arrows.add(arr)49        self.play(LaggedStartMap(Create, field_arrows, lag_ratio=0.06), run_time=1.2)50 51        f_label = MathTex(r"\vec{F}=(P,Q)", color=BLUE_C).scale(0.38)52        f_label.next_to(curve, UP, buff=0.3).shift(RIGHT * 0.5)53        self.play(Write(f_label), run_time=0.5)54 55        # 问题:计算第二型积分56        problem_eq = MathTex(r"\text{求:}\ \int_L P\,dx + Q\,dy\ = \ ?", color=BLUE).scale(0.45)57        problem_eq.to_edge(LEFT, buff=0.4).shift(UP * 2.5)58        self.play(Write(problem_eq), run_time=1)59        self.wait(0.8)60 61        # 动机文字62        motive = Text('能否转化为对弧长的积分?', font="SimSun", color=WHITE).scale(0.3)63        motive.next_to(problem_eq, RIGHT, buff=0.3)64        self.play(Write(motive), run_time=0.8)65        self.wait(1.5)66 67        # 清理场景1(保留曲线、起终点)68        self.play(69            FadeOut(field_arrows), FadeOut(f_label),70            FadeOut(problem_eq), FadeOut(motive),71            run_time=0.6,72        )73 74        # =============================================75        # 场景2:关键洞察——切向量76        # =============================================77        scene2_label = Text('关键:切向量 T', font="SimSun", color=ORANGE).scale(0.3)78        scene2_label.to_edge(LEFT, buff=0.4).shift(UP * 2.5)79        self.play(Write(scene2_label), run_time=0.5)80 81        # 动态切向量82        def get_tangent_at(t_val):83            dt = 0.0184            p1 = curve_func(t_val)85            p2 = curve_func(t_val + dt)86            T = (p2 - p1) / np.linalg.norm(p2 - p1)87            return T88 89        t_tracker = ValueTracker(0.5)90        moving_point = always_redraw(91            lambda: Dot(curve_func(t_tracker.get_value()), color=ORANGE, radius=0.08)92        )93        tangent_arrow = always_redraw(94            lambda: Arrow(95                curve_func(t_tracker.get_value()),96                curve_func(t_tracker.get_value()) + get_tangent_at(t_tracker.get_value()) * 1.0,97                buff=0, color=ORANGE, stroke_width=3.5, tip_length=0.12,98            )99        )100        t_label_dyn = always_redraw(101            lambda: MathTex(r"\vec{T}", color=ORANGE).scale(0.38).next_to(102                curve_func(t_tracker.get_value()) + get_tangent_at(t_tracker.get_value()) * 1.0,103                UR, buff=0.03,104            )105        )106 107        self.play(FadeIn(moving_point), Create(tangent_arrow), Write(t_label_dyn), run_time=0.6)108        self.play(t_tracker.animate.set_value(0.5), run_time=2.0, rate_func=linear)109        self.wait(0.3)110 111        # 冻结在 t=0.5(α≈30°,正锐角,位置清晰)112        t_stop = t_tracker.get_value()113        P_pos = curve_func(t_stop)114        T_vec = get_tangent_at(t_stop)115        self.remove(moving_point, tangent_arrow, t_label_dyn)116 117        static_point = Dot(P_pos, color=ORANGE, radius=0.08)118        static_tangent = Arrow(119            P_pos, P_pos + T_vec * 1.0,120            buff=0, color=ORANGE, stroke_width=3.5, tip_length=0.12,121        )122        static_t_label = MathTex(r"\vec{T}", color=ORANGE).scale(0.38)123        static_t_label.next_to(static_tangent.get_end(), UR, buff=0.03)124        self.add(static_point, static_tangent, static_t_label)125 126        # x轴参考线 + 角度127        x_ref = DashedLine(P_pos + LEFT * 0.2, P_pos + RIGHT * 1.3, color=GREY, stroke_width=1.5)128        self.play(Create(x_ref), run_time=0.4)129 130        alpha_val = np.arctan2(T_vec[1], T_vec[0])131        angle_arc = Angle(132            Line(P_pos, P_pos + RIGHT), Line(P_pos, P_pos + T_vec),133            radius=0.3, color=RED_C,134        )135        alpha_label = MathTex(r"\alpha", color=RED_C).scale(0.35)136        alpha_label.move_to(P_pos + 0.45 * np.array([np.cos(alpha_val / 2), np.sin(alpha_val / 2), 0]))137        self.play(Create(angle_arc), Write(alpha_label), run_time=0.8)138 139        # 分解为直角三角形140        dx_comp = np.array([T_vec[0], 0, 0]) * 1.0141        dy_comp = np.array([0, T_vec[1], 0]) * 1.0142 143        h_line = DashedLine(P_pos, P_pos + dx_comp, color=RED_C, stroke_width=2.5)144        v_line = DashedLine(P_pos + dx_comp, P_pos + dx_comp + dy_comp, color=TEAL, stroke_width=2.5)145        self.play(Create(h_line), Create(v_line), run_time=0.8)146 147        # 标注分量148        cos_a_label = MathTex(r"\cos\alpha", color=RED_C).scale(0.3)149        cos_a_label.next_to(h_line, DOWN, buff=0.05)150        cos_b_label = MathTex(r"\cos\beta", color=TEAL).scale(0.3)151        cos_b_label.next_to(v_line, RIGHT, buff=0.05)152        self.play(Write(cos_a_label), Write(cos_b_label), run_time=0.6)153 154        # 右侧公式155        formula_T = MathTex(r"\vec{T} = (\cos\alpha,\ \cos\beta)", color=ORANGE).scale(0.4)156        formula_T.to_edge(RIGHT, buff=0.4).shift(UP * 1.8)157        self.play(Write(formula_T), run_time=0.8)158        self.wait(1.5)159 160        self.play(FadeOut(scene2_label), run_time=0.3)161 162        # =============================================163        # 场景3:微元关系 ds, dx, dy164        # =============================================165        scene3_label = Text('微元关系:ds → dx, dy', font="SimSun", color=WHITE).scale(0.28)166        scene3_label.to_edge(LEFT, buff=0.4).shift(UP * 2.5)167        self.play(Write(scene3_label), run_time=0.5)168 169        # 用高亮曲线段表示 ds(实际弧长)170        dt_small = 0.35171        arc_segment = ParametricFunction(172            curve_func, t_range=[t_stop, t_stop + dt_small],173            color=YELLOW, stroke_width=5,174        )175        arc_end = curve_func(t_stop + dt_small)176        ds_brace = BraceBetweenPoints(P_pos, arc_end, color=YELLOW)177        ds_label = MathTex("ds", color=YELLOW).scale(0.4)178        ds_label.next_to(ds_brace, ds_brace.get_direction(), buff=0.05)179        self.play(Create(arc_segment), run_time=0.6)180        self.play(Create(ds_brace), Write(ds_label), run_time=0.6)181 182        # 显示切线段≈弧长段183        tangent_end = P_pos + T_vec * np.linalg.norm(arc_end - P_pos)184        tangent_seg = Line(P_pos, tangent_end, color=ORANGE, stroke_width=4)185        approx_text = MathTex(r"\text{\color{yellow}弧长} \approx \text{\color{orange}切线段}", color=WHITE).scale(0.3)186        approx_text.next_to(ds_brace, ds_brace.get_direction(), buff=0.35)187        self.play(Create(tangent_seg), Write(approx_text), run_time=0.8)188        self.wait(1)189 190        # 分解切线段为 dx, dy191        seg_len = np.linalg.norm(arc_end - P_pos)192        dx_comp_seg = np.array([T_vec[0], 0, 0]) * seg_len193        dy_comp_seg = np.array([0, T_vec[1], 0]) * seg_len194        h_line_seg = DashedLine(P_pos, P_pos + dx_comp_seg, color=RED_C, stroke_width=2.5)195        v_line_seg = DashedLine(P_pos + dx_comp_seg, P_pos + dx_comp_seg + dy_comp_seg, color=TEAL, stroke_width=2.5)196        self.play(Create(h_line_seg), Create(v_line_seg), run_time=0.6)197 198        # 标注 dx, dy199        dx_label = MathTex("dx", color=RED_C).scale(0.3)200        dx_label.next_to(h_line_seg, DOWN, buff=0.12)201        dy_label = MathTex("dy", color=TEAL).scale(0.3)202        dy_label.next_to(v_line_seg, RIGHT, buff=0.1)203        self.play(Write(dx_label), Write(dy_label), run_time=0.5)204 205        # 局部放大:复制几何元素居中放大显示206        zoom_copy = VGroup(207            arc_segment.copy(),208            tangent_seg.copy(),209            ds_brace.copy(), ds_label.copy(),210            h_line_seg.copy(), v_line_seg.copy(),211            dx_label.copy(), dy_label.copy(),212            angle_arc.copy(), alpha_label.copy(),213            static_point.copy(),214        )215        zoom_copy.scale(2.5).move_to(ORIGIN + LEFT * 0.5)216        zoom_bg = SurroundingRectangle(zoom_copy, color=WHITE, buff=0.2, corner_radius=0.1, fill_color=BLACK, fill_opacity=0.85)217        zoom_title = Text('放大:曲线段 ds → dx, dy', font="SimSun", color=YELLOW).scale(0.3)218        zoom_title.next_to(zoom_bg, UP, buff=0.1)219        self.play(FadeIn(zoom_bg), FadeIn(zoom_copy), Write(zoom_title), run_time=1)220        self.wait(3)221        self.play(FadeOut(zoom_bg), FadeOut(zoom_copy), FadeOut(zoom_title), run_time=0.8)222 223        # 关键公式(带闪烁提示)224        key_eq1 = MathTex(r"dx = \cos\alpha \cdot ds", color=RED_C).scale(0.42)225        key_eq1.next_to(formula_T, DOWN, buff=0.25)226        key_eq2 = MathTex(r"dy = \cos\beta \cdot ds", color=TEAL).scale(0.42)227        key_eq2.next_to(key_eq1, DOWN, buff=0.1)228 229        # 闪烁 h_line 同时写公式230        self.play(Write(key_eq1), h_line.animate.set_color(YELLOW), run_time=1)231        self.play(h_line.animate.set_color(RED_C), run_time=0.3)232        self.play(Write(key_eq2), v_line.animate.set_color(YELLOW), run_time=1)233        self.play(v_line.animate.set_color(TEAL), run_time=0.3)234 235        bridge_text = Text('这就是连接两类积分的桥梁!', font="SimSun", color=YELLOW).scale(0.25)236        bridge_text.next_to(key_eq2, DOWN, buff=0.15)237        self.play(Write(bridge_text), run_time=0.8)238        self.wait(2)239 240        # =============================================241        # 场景4:代入——得到转换公式242        # =============================================243        # 清理几何元素(保留曲线)244        geom_objs = VGroup(245            static_point, static_tangent, static_t_label,246            x_ref, angle_arc, alpha_label,247            h_line, v_line, cos_a_label, cos_b_label,248            arc_segment, tangent_seg, approx_text,249            h_line_seg, v_line_seg,250            ds_brace, ds_label, dx_label, dy_label,251            scene3_label, bridge_text,252        )253        self.play(FadeOut(geom_objs), run_time=0.8)254 255        # 推导放在右侧(下移避免重叠),曲线在左侧保留256        sub_title = Text('代入 dx, dy:', font="SimSun", color=WHITE).scale(0.28)257        sub_title.to_edge(RIGHT, buff=1.2).shift(DOWN * 0.2)258        self.play(Write(sub_title), run_time=0.5)259 260        line1 = MathTex(r"\int_L", r"P\,dx", r"+", r"Q\,dy", color=BLUE).scale(0.38)261        line1.next_to(sub_title, DOWN, buff=0.1)262        self.play(Write(line1), run_time=0.8)263 264        # 高亮 dx, dy265        self.play(266            line1[1].animate.set_color(RED_C),267            line1[3].animate.set_color(TEAL),268            run_time=0.5,269        )270 271        line2 = MathTex(272            r"= \int_L P\cos\alpha\,ds + Q\cos\beta\,ds",273            color=WHITE,274        ).scale(0.34)275        line2.next_to(line1, DOWN, buff=0.08)276        self.play(Write(line2), run_time=1.2)277 278        # 最终公式(黄色高亮框,包含完整等式,左移避免出框)279        final_eq = MathTex(280            r"\int_L P\,dx + Q\,dy",281            r"=",282            r"\int_L (P\cos\alpha + Q\cos\beta)\,ds",283            color=WHITE,284        ).scale(0.36)285        final_eq[0].set_color(BLUE)286        final_eq[2].set_color(YELLOW)287        final_eq.next_to(line2, DOWN, buff=0.12).shift(LEFT * 0.3)288        final_box = SurroundingRectangle(final_eq, color=YELLOW, buff=0.08, corner_radius=0.05)289        self.play(Write(final_eq), Create(final_box), run_time=1.5)290        self.wait(2)291 292        # 清理推导细节,保留最终公式293        deriv_cleanup = VGroup(formula_T, key_eq1, key_eq2, sub_title, line1, line2)294        self.play(FadeOut(deriv_cleanup), run_time=0.6)295 296        # 将最终公式移到上方保留297        self.play(298            final_eq.animate.scale(0.9).next_to(title, DOWN, buff=0.2),299            final_box.animate.scale(0.9).next_to(title, DOWN, buff=0.2),300            run_time=1,301        )302        new_box = SurroundingRectangle(final_eq, color=YELLOW, buff=0.08, corner_radius=0.05)303        self.play(Transform(final_box, new_box), run_time=0.3)304 305        # =============================================306        # 场景5:几何意义——向量场在切线方向的投影307        # =============================================308        # 重新显示向量场309        field_arrows2 = VGroup()310        for t_val in np.linspace(0.3, 2.4, 10):311            pos = curve_func(t_val)312            F_val = F_field(pos)313            F_norm = np.linalg.norm(F_val)314            if F_norm > 0.01:315                F_dir = F_val / F_norm * 0.5316                arr = Arrow(pos, pos + F_dir, buff=0, color=BLUE_C, stroke_width=2, tip_length=0.07)317                field_arrows2.add(arr)318        self.play(LaggedStartMap(Create, field_arrows2, lag_ratio=0.05), run_time=1.2)319 320        # 明确说明:被积函数 Pcosα+Qcosβ 的几何意义321        geo_title = MathTex(322            r"P\cos\alpha + Q\cos\beta",323            r"\ = \ ",324            r"\vec{F}\cdot\vec{T}",325            r"\ = \ ",326            r"\text{向量场在切线上的投影}",327            color=WHITE,328        ).scale(0.32)329        geo_title[0].set_color(YELLOW)330        geo_title[2].set_color(ORANGE)331        geo_title[4].set_color(YELLOW)332        geo_title.to_edge(DOWN, buff=0.5)333        self.play(Write(geo_title), run_time=1)334 335        # 动态投影演示336        proj_tracker = ValueTracker(0.5)337 338        demo_dot = always_redraw(339            lambda: Dot(curve_func(proj_tracker.get_value()), color=WHITE, radius=0.07)340        )341 342        def make_proj_visual():343            t_val = proj_tracker.get_value()344            pos = curve_func(t_val)345            T = get_tangent_at(t_val)346            F_val = F_field(pos)347            F_norm = np.linalg.norm(F_val)348            if F_norm < 0.01:349                return VGroup()350            F_dir = F_val / F_norm * 0.65351            f_arr = Arrow(pos, pos + F_dir, buff=0, color=BLUE, stroke_width=3, tip_length=0.1)352            t_arr = Arrow(pos, pos + T * 0.65, buff=0, color=ORANGE, stroke_width=3, tip_length=0.1)353            proj_len = np.dot(F_dir, T)354            proj_end = pos + T * proj_len355            proj_arr = Arrow(pos, proj_end, buff=0, color=YELLOW, stroke_width=3.5, tip_length=0.09)356            drop = DashedLine(pos + F_dir, proj_end, color=GREY_B, stroke_width=1.5)357            return VGroup(f_arr, t_arr, proj_arr, drop)358 359        proj_visual = always_redraw(make_proj_visual)360        self.add(demo_dot, proj_visual)361        self.wait(0.3)362 363        self.play(proj_tracker.animate.set_value(2.5), run_time=5, rate_func=linear)364        self.wait(1)365 366        # 清理367        self.remove(demo_dot, proj_visual)368        self.play(FadeOut(field_arrows2), FadeOut(geo_title), run_time=0.6)369 370        # =============================================371        # 场景6:方向性备注(配合切向量动画演示)372        # =============================================373        # 左侧:重新显示曲线 + 切向量动画演示方向反转374        dir_title = Text('补充:方向性', font="SimSun", color=ORANGE).scale(0.35)375        dir_title.to_edge(LEFT, buff=0.4).shift(UP * 2.5)376        self.play(Write(dir_title), run_time=0.5)377 378        # 正向切向量(锐角α)379        t_demo = 0.5380        P_demo = curve_func(t_demo)381        T_fwd = get_tangent_at(t_demo)382        fwd_arrow = Arrow(P_demo, P_demo + T_fwd * 1.2, buff=0, color=GREEN, stroke_width=4, tip_length=0.12)383        fwd_label = MathTex(r"\vec{T}", color=GREEN).scale(0.4).next_to(fwd_arrow.get_end(), UR, buff=0.05)384 385        # x轴参考线 + 角度386        x_ref_dir = DashedLine(P_demo + LEFT * 0.3, P_demo + RIGHT * 1.5, color=GREY, stroke_width=1.5)387        alpha_fwd = np.arctan2(T_fwd[1], T_fwd[0])388        arc_fwd = Angle(389            Line(P_demo, P_demo + RIGHT), Line(P_demo, P_demo + T_fwd),390            radius=0.35, color=GREEN,391        )392        alpha_fwd_label = MathTex(r"\alpha", color=GREEN).scale(0.35)393        alpha_fwd_label.move_to(P_demo + 0.55 * np.array([np.cos(alpha_fwd / 2), np.sin(alpha_fwd / 2), 0]))394 395        dot_demo = Dot(P_demo, color=WHITE, radius=0.07)396        self.play(FadeIn(dot_demo), Create(x_ref_dir), Create(fwd_arrow), Write(fwd_label), run_time=0.8)397        self.play(Create(arc_fwd), Write(alpha_fwd_label), run_time=0.6)398 399        # 右侧:逻辑链说明(正向)400        step0 = Text('正向行走:', font="SimSun", color=GREEN).scale(0.25)401        step0.to_edge(RIGHT, buff=1.2).shift(UP * 1.2)402        step1 = MathTex(403            r"\vec{T} \text{ 指向前方}",404            color=GREEN,405        ).scale(0.33)406        step1.next_to(step0, DOWN, buff=0.08)407        step1_alpha = MathTex(408            r"\Rightarrow \alpha \text{ 为锐角}",409            color=GREEN,410        ).scale(0.33)411        step1_alpha.next_to(step1, DOWN, buff=0.06)412        step1_cos = MathTex(413            r"\Rightarrow \cos\alpha > 0",414            color=GREEN,415        ).scale(0.33)416        step1_cos.next_to(step1_alpha, DOWN, buff=0.06)417        self.play(Write(step0), run_time=0.4)418        self.play(Write(step1), run_time=0.6)419        self.play(Write(step1_alpha), run_time=0.6)420        self.play(Write(step1_cos), run_time=0.6)421        self.wait(1.5)422 423        # 反向切向量(钝角)424        T_bwd = -T_fwd425        bwd_arrow = Arrow(P_demo, P_demo + T_bwd * 1.2, buff=0, color=RED_C, stroke_width=4, tip_length=0.12)426        bwd_label = MathTex(r"-\vec{T}", color=RED_C).scale(0.4).next_to(bwd_arrow.get_end(), DL, buff=0.05)427 428        alpha_bwd = np.arctan2(T_bwd[1], T_bwd[0])429        arc_bwd = Angle(430            Line(P_demo, P_demo + RIGHT), Line(P_demo, P_demo + T_bwd),431            radius=0.35, color=RED_C,432        )433        alpha_bwd_label = MathTex(r"\pi-\alpha", color=RED_C).scale(0.32)434        alpha_bwd_label.move_to(P_demo + 0.6 * np.array([np.cos((np.pi + alpha_bwd) / 2), np.sin((np.pi + alpha_bwd) / 2), 0]))435 436        self.play(437            Transform(fwd_arrow, bwd_arrow),438            Transform(fwd_label, bwd_label),439            Transform(arc_fwd, arc_bwd),440            Transform(alpha_fwd_label, alpha_bwd_label),441            run_time=1.5,442        )443 444        # 右侧:逻辑链说明(反向)445        step2 = Text('反向行走:', font="SimSun", color=RED_C).scale(0.25)446        step2.next_to(step1_cos, DOWN, buff=0.2)447        chain1 = MathTex(448            r"\text{方向反转}",449            r"\Rightarrow",450            r"\vec{T} \to -\vec{T}",451            color=RED_C,452        ).scale(0.33)453        chain1.next_to(step2, DOWN, buff=0.08)454        chain2 = MathTex(455            r"\Rightarrow \alpha \to \pi-\alpha \text{(变为钝角)}",456            color=RED_C,457        ).scale(0.33)458        chain2.next_to(chain1, DOWN, buff=0.06)459        chain3 = MathTex(460            r"\Rightarrow \cos\alpha < 0",461            color=RED_C,462        ).scale(0.33)463        chain3.next_to(chain2, DOWN, buff=0.06)464        self.play(Write(step2), run_time=0.4)465        self.play(Write(chain1), run_time=0.7)466        self.play(Write(chain2), run_time=0.7)467        self.play(Write(chain3), run_time=0.6)468        self.wait(1.5)469 470        # 结论471        dir_c1_note = MathTex(472            r"\therefore\quad",473            r"\int_L (P\cos\alpha+Q\cos\beta)\,ds",474            r"\text{ 变号}",475            color=BLUE,476        ).scale(0.34)477        dir_c1_note.next_to(chain3, DOWN, buff=0.15)478        self.play(Write(dir_c1_note), run_time=0.8)479        self.wait(3)480 481 482def main():483    import os484    os.system("manim -pql curve_integral_conversion.py CurveIntegralConversion")485 486 487if __name__ == "__main__":488    main()

讲解

这个视频围绕公式

LPdx+Qdy=L(Pcosα+Qcosβ)ds\int_L P\,dx + Q\,dy = \int_L (P\cos\alpha + Q\cos\beta)\,ds

展开。动画先提出第二类曲线积分的问题,再把曲线上的局部运动拆成切向量、方向余弦和弧长微元三件事。

开场画面建立曲线、端点和向量场,让观众先看到积分对象。切向量说明部分引入单位切向量 TT,并用角度 α\alphaβ\beta 表示它在坐标方向上的分量。

局部近似步骤是转换的核心:把一小段曲线近似为切线段,得到 dx=cosαdsdx=\cos\alpha\,dsdy=cosβdsdy=\cos\beta\,ds。这一步把第二类积分中的 dxdxdydy 接到第一类积分使用的弧长微元 dsds 上。

公式代入步骤完成转换。随后的几何解释把 Pcosα+QcosβP\cos\alpha + Q\cos\beta 识别为向量场在切线方向上的投影,也就是 FT\vec{F}\cdot\vec{T}

结尾的方向性讨论说明:曲线路径反向时,切向量变成 T-\vec{T},方向余弦随之变号,所以第二类曲线积分也会变号。