跳转至

尺寸与角度

影片代码
import manimgx as m


class SizeAndAngleHero(m.Scene):
    def construct(self) -> None:
        shapes = m.VGroup(
            *[
                m.Square(side_length=1.6, color=m.BLUE, fill_opacity=0.5)
                for _ in range(4)
            ]
        )
        shapes.arrange(buff=1.2)
        names = m.VGroup(
            m.Text("scale(1.4)", font="monospace", font_size=30),
            m.Text("rotate(PI / 4)", font="monospace", font_size=30),
            m.Text("stretch(1.6, 0)", font="monospace", font_size=30),
            m.Text("flip()", font="monospace", font_size=30),
        )
        for shape, name in zip(shapes, names, strict=True):
            name.next_to(shape, m.DOWN, buff=1.1)
        marker = m.Dot(color=m.YELLOW).move_to(shapes[3].get_corner(m.UR))
        shapes[3].add(marker)
        self.add(shapes, names)
        self.play(
            shapes[0].animate.scale(1.4),
            shapes[1].animate.rotate(m.PI / 4),
            shapes[2].animate.stretch(1.6, 0),
            shapes[3].animate.flip(),
            run_time=2,
        )
        self.wait()

mobject 的尺寸即其包围盒的尺寸:其宽度和 高度。大多数形状在创建时确定尺寸(圆通过 radius,文本通过 font_size);以下方法在之后更改尺寸,默认围绕 mobject 的中心,除非你指定其他点。

角度以弧度表示:完整一圈为 m.TAU,半圈为 m.PI,30 * m.DEGREES 即 30 度。正角度 逆时针旋转。

尺寸

width

mobject 的宽度,以场景单位表示:即其 边界框 沿 x 的范围,从其绘制内容的最左 到最右。设置它可按比例将 mobject 缩放至该宽度, 关于其中心。

mobject.width
源码

manimgx\mobject.py

def width(self) -> float:
    """mobject 的宽度,以场景单位表示:即其
    [边界框][manimgx.Mobject.boundary_box] 沿 x 的范围,从其绘制内容的最左
    到最右。设置它可按比例将 mobject 缩放至该宽度,
    关于其中心。"""
    return self.length_over_dim(0)

height

mobject 的高度,以场景单位表示:即其 边界框 沿 y 的范围,从其绘制内容的最低 到最高。设置它可按比例将 mobject 缩放至该高度, 关于其中心。

mobject.height
源码

manimgx\mobject.py

def height(self) -> float:
    """mobject 的高度,以场景单位表示:即其
    [边界框][manimgx.Mobject.boundary_box] 沿 y 的范围,从其绘制内容的最低
    到最高。设置它可按比例将 mobject 缩放至该高度,
    关于其中心。"""
    return self.length_over_dim(1)

scale

代码
import manimgx as m


class MobjectScaleExample(m.Scene):
    def construct(self) -> None:
        a = m.Square(color=m.BLUE, fill_opacity=0.5)
        b, c = a.copy(), a.copy()
        m.VGroup(a, b, c).arrange(buff=2.5)
        for square, text in zip(
            (a, b, c), ("scale(2)", "about_edge=DL", "[0.5, 1.5, 1]")
        ):
            self.add(m.Text(text, font_size=32).next_to(square, m.DOWN, 2))
        self.add(a, b, c)
        self.play(
            a.animate.scale(2),
            b.animate.scale(2, about_edge=m.DL),
            c.animate.scale([0.5, 1.5, 1]),
        )

关于某点缩放 mobject 及其整个家族:按一个因子,或 按每轴一个因子。

描边宽度保持不变,除非指定 scale_stroke。

mobject.scale(scale_factor, scale_stroke=False, *, about_point=None, about_edge=None)
scale_factor

因子:2 将 mobject 的尺寸加倍,0.5 将其减半, 负因子还使其关于该点反射;或其沿 x、y 和 z 的因子。

scale_stroke

描边宽度是否也按因子缩放(对于每轴因子的情况, 为 x 和 y 尺寸的几何平均值)。

about_point

保持不动的点;None:参见 about_edge。

about_edge

mobject 边界框上保持不动的点,以 方向命名(DL 表示其左下角);None 表示其中心。

源码

manimgx\mobject.py

def scale(
    self,
    scale_factor: float | Vector3DLike,
    scale_stroke: bool = False,
    *,
    about_point: Point3DLike | None = None,
    about_edge: Vector3DLike | None = None,
) -> Self:
    """关于某点缩放 mobject 及其整个家族:按一个因子,或
    按每轴一个因子。

    描边宽度保持不变,除非指定 `scale_stroke`。

    Args:
        scale_factor: 因子:2 将 mobject 的尺寸加倍,0.5 将其减半,
            负因子还使其关于该点反射;或其沿
            x、y 和 z 的因子。
        scale_stroke: 描边宽度是否也按因子缩放(对于每轴因子的情况,
            为 x 和 y 尺寸的几何平均值)。
        about_point: 保持不动的点;None:参见 `about_edge`。
        about_edge: mobject 边界框上保持不动的点,以
            方向命名(DL 表示其左下角);None 表示其中心。

    Examples:
        ```python
        import manimgx as m


        class MobjectScaleExample(m.Scene):
            def construct(self) -> None:
                a = m.Square(color=m.BLUE, fill_opacity=0.5)
                b, c = a.copy(), a.copy()
                m.VGroup(a, b, c).arrange(buff=2.5)
                for square, text in zip(
                    (a, b, c), ("scale(2)", "about_edge=DL", "[0.5, 1.5, 1]")
                ):
                    self.add(m.Text(text, font_size=32).next_to(square, m.DOWN, 2))
                self.add(a, b, c)
                self.play(
                    a.animate.scale(2),
                    b.animate.scale(2, about_edge=m.DL),
                    c.animate.scale([0.5, 1.5, 1]),
                )
        ```
    """
    if scale_stroke:
        length = length_factor(scale_factor)
        for mob in self.get_family():
            mob.paint = mob.paint.but(
                stroke_width=length * mob.get_stroke_width(),
                background_width=length * mob.get_stroke_width(background=True),
            )
    if isinstance(scale_factor, (int, float)):  # one factor: a scale about a point
        if about_point is None:
            edge = ORIGIN if about_edge is None else about_edge
            about_point = self.get_critical_point(edge)
        about = np.array(about_point, dtype=float)
        for mob in self.family_members_with_points():
            mob._geometry = mob._geometry.scaled(float(scale_factor), about)
        return self
    return self._apply_linear(
        np.diag(axis_factors(scale_factor)), about_point, about_edge
    )

scale_to_fit_width

按比例缩放 mobject 至某宽度。

mobject.scale_to_fit_width(width, **kwargs)
width

宽度,以场景单位表示。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

源码

manimgx\mobject.py

def scale_to_fit_width(self, width: float, **kwargs: Unpack[Pivot]) -> Self:
    """按比例缩放 mobject 至某宽度。

    Args:
        width: 宽度,以场景单位表示。
        **kwargs: [Pivot 关键字][manimgx.mobject.Pivot]:保持不动的
            点(默认:其中心)。
    """
    return self.rescale_to_fit(width, 0, stretch=False, **kwargs)

scale_to_fit_height

按比例缩放 mobject 至某高度。

mobject.scale_to_fit_height(height, **kwargs)
height

高度,以场景单位表示。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

源码

manimgx\mobject.py

def scale_to_fit_height(self, height: float, **kwargs: Unpack[Pivot]) -> Self:
    """按比例缩放 mobject 至某高度。

    Args:
        height: 高度,以场景单位表示。
        **kwargs: [Pivot keywords][manimgx.mobject.Pivot]: the point that stays
            fixed (default: its center).
    """
    return self.rescale_to_fit(height, 1, stretch=False, **kwargs)

match_width

按比例缩放 mobject 至另一个的宽度。

mobject.match_width(mobject, **kwargs)
mobject

要匹配的 mobject。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

源码

manimgx\mobject.py

def match_width(self, mobject: "Mobject", **kwargs: Unpack[Pivot]) -> Self:
    """按比例缩放 mobject 至另一个的宽度。

    Args:
        mobject: 要匹配的 mobject。
        **kwargs: [Pivot 关键字][manimgx.mobject.Pivot]:保持不动的
            点(默认:其中心)。
    """
    return self.match_dim_size(mobject, 0, **kwargs)

match_height

按比例缩放 mobject 至另一个的高度。

mobject.match_height(mobject, **kwargs)
mobject

要匹配的 mobject。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

源码

manimgx\mobject.py

def match_height(self, mobject: "Mobject", **kwargs: Unpack[Pivot]) -> Self:
    """按比例缩放 mobject 至另一个的高度。

    Args:
        mobject: 要匹配的 mobject。
        **kwargs: [Pivot 关键字][manimgx.mobject.Pivot]:保持不动的
            点(默认:其中心)。
    """
    return self.match_dim_size(mobject, 1, **kwargs)

stretch

代码
import manimgx as m


class MobjectStretchExample(m.Scene):
    def construct(self) -> None:
        circle = m.Circle(radius=1.5, color=m.BLUE, fill_opacity=0.5)
        self.add(circle)
        self.play(circle.animate.stretch(3, 0))
        self.play(circle.animate.stretch(0.5, 1, about_edge=m.DOWN))

沿一个轴拉伸 mobject 及其整个家族:关于某点缩放每个点的 该坐标,并保持其他坐标不变。

描边宽度保持不变。

mobject.stretch(factor, dim, *, about_point=None, about_edge=None)
factor

因子:2 使 mobject 沿该轴长度加倍。

dim

轴:0 表示 x(其宽度),1 表示 y(其高度),2 表示 z。

about_point

保持不动的点;None:参见 about_edge。

about_edge

mobject 边界框上保持不动的点,以 方向命名(DOWN 表示其底边中点);None 表示其 中心。

源码

manimgx\mobject.py

def stretch(
    self,
    factor: float,
    dim: int,
    *,
    about_point: Point3DLike | None = None,
    about_edge: Vector3DLike | None = None,
) -> Self:
    """沿一个轴拉伸 mobject 及其整个家族:关于某点缩放每个点的
    该坐标,并保持其他坐标不变。

    描边宽度保持不变。

    Args:
        factor: 因子:2 使 mobject 沿该轴长度加倍。
        dim: 轴:0 表示 x(其宽度),1 表示 y(其高度),2 表示 z。
        about_point: 保持不动的点;None:参见 `about_edge`。
        about_edge: mobject 边界框上保持不动的点,以
            方向命名(DOWN 表示其底边中点);None 表示其
            中心。

    Examples:
        ```python
        import manimgx as m


        class MobjectStretchExample(m.Scene):
            def construct(self) -> None:
                circle = m.Circle(radius=1.5, color=m.BLUE, fill_opacity=0.5)
                self.add(circle)
                self.play(circle.animate.stretch(3, 0))
                self.play(circle.animate.stretch(0.5, 1, about_edge=m.DOWN))
        ```
    """
    linear = np.eye(3)
    linear[dim, dim] = factor
    return self._apply_linear(linear, about_point, about_edge)

stretch_to_fit_width

水平拉伸 mobject 至某宽度;其高度不变。

mobject.stretch_to_fit_width(width, **kwargs)
width

宽度,以场景单位表示。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

源码

manimgx\mobject.py

def stretch_to_fit_width(self, width: float, **kwargs: Unpack[Pivot]) -> Self:
    """水平拉伸 mobject 至某宽度;其高度不变。

    Args:
        width: 宽度,以场景单位表示。
        **kwargs: [Pivot 关键字][manimgx.mobject.Pivot]:保持不动的
            点(默认:其中心)。
    """
    return self.rescale_to_fit(width, 0, stretch=True, **kwargs)

stretch_to_fit_height

垂直拉伸 mobject 至某高度;其宽度不变。

mobject.stretch_to_fit_height(height, **kwargs)
height

高度,以场景单位表示。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

源码

manimgx\mobject.py

def stretch_to_fit_height(self, height: float, **kwargs: Unpack[Pivot]) -> Self:
    """垂直拉伸 mobject 至某高度;其宽度不变。

    Args:
        height: 高度,以场景单位表示。
        **kwargs: [Pivot 关键字][manimgx.mobject.Pivot]:保持不动的
            点(默认:其中心)。
    """
    return self.rescale_to_fit(height, 1, stretch=True, **kwargs)

replace

将 mobject 放到另一个的位置:缩放至其沿一个轴的范围(或 拉伸至其宽度和高度),并以其为中心。

另一个 mobject 保持原位。

mobject.replace(mobject, dim_to_match=0, stretch=False)
mobject

要占据其位置的 mobject。

dim_to_match

按比例取其范围的轴:0 表示 x( 宽度),1 表示 y(高度),2 表示 z。

stretch

是否改为拉伸至另一个的宽度和高度。

源码

manimgx\mobject.py

def replace(
    self, mobject: "Mobject", dim_to_match: int = 0, stretch: bool = False
) -> Self:
    """将 mobject 放到另一个的位置:缩放至其沿一个轴的范围(或
    拉伸至其宽度和高度),并以其为中心。

    另一个 mobject 保持原位。

    Args:
        mobject: 要占据其位置的 mobject。
        dim_to_match: 按比例取其范围的轴:0 表示 x(
            宽度),1 表示 y(高度),2 表示 z。
        stretch: 是否改为拉伸至另一个的宽度和高度。
    """
    if stretch:
        self.stretch_to_fit_width(mobject.width)
        self.stretch_to_fit_height(mobject.height)
    else:
        self.rescale_to_fit(mobject.length_over_dim(dim_to_match), dim_to_match)
    return self.shift(mobject.get_center() - self.get_center())

角度

m.PI

π:半圈,以弧度表示。

m.TAU

τ = 2π:一整圈,以弧度表示。

m.DEGREES

一度的弧度值:30 * DEGREES 表示一圈的十二分之一。

rotate

代码
import manimgx as m


class MobjectRotateExample(m.Scene):
    def construct(self) -> None:
        a = m.Square(side_length=2.5, color=m.BLUE, fill_opacity=0.5)
        b = m.Square(side_length=2.5, color=m.YELLOW, fill_opacity=0.5)
        m.VGroup(a, b).arrange(buff=4)
        pivot = m.Dot(b.get_corner(m.DL), radius=0.12, color=m.RED)
        self.add(a, b, pivot)
        self.play(
            a.animate.rotate(m.PI / 4),
            b.animate.rotate(m.PI / 2, about_edge=m.DL),
        )

将 mobject 及其整个家族旋转一个角度,绕过某点的 轴。

其光泽方向随之转动。通过 animate, mobject 刚性地转过整个角度。

mobject.rotate(angle, axis=OUT, *, about_point=None, about_edge=None)
angle

角度,以弧度表示:从 axis 所指方向看去为逆时针 (对于默认轴,即在屏幕上)。

axis

轴的方向(默认 OUT,即屏幕外:平面内的旋转)。

about_point

轴所经过的点;None:参见 about_edge。

about_edge

mobject 边界框上轴所经过的点, 以方向命名(DL 表示其左下角);None 表示其 center.

源码

manimgx\mobject.py

def rotate(
    self,
    angle: float,
    axis: Vector3DLike = OUT,
    *,
    about_point: Point3DLike | None = None,
    about_edge: Vector3DLike | None = None,
) -> Self:
    """将 mobject 及其整个家族旋转一个角度,绕过某点的
    轴。

    其光泽方向随之转动。通过 [animate][manimgx.Mobject.animate],
    mobject 刚性地转过整个角度。

    Args:
        angle: 角度,以弧度表示:从 `axis` 所指方向看去为逆时针
            (对于默认轴,即在屏幕上)。
        axis: 轴的方向(默认 OUT,即屏幕外:平面内的旋转)。
        about_point: 轴所经过的点;None:参见 `about_edge`。
        about_edge: mobject 边界框上轴所经过的点,
            以方向命名(DL 表示其左下角);None 表示其
            center.

    Examples:
        ```python
        import manimgx as m


        class MobjectRotateExample(m.Scene):
            def construct(self) -> None:
                a = m.Square(side_length=2.5, color=m.BLUE, fill_opacity=0.5)
                b = m.Square(side_length=2.5, color=m.YELLOW, fill_opacity=0.5)
                m.VGroup(a, b).arrange(buff=4)
                pivot = m.Dot(b.get_corner(m.DL), radius=0.12, color=m.RED)
                self.add(a, b, pivot)
                self.play(
                    a.animate.rotate(m.PI / 4),
                    b.animate.rotate(m.PI / 2, about_edge=m.DL),
                )
        ```
    """
    rot = rotation_matrix(angle, axis)
    self._rotate_direction_state(rot)
    return self._apply_linear(rot, about_point, about_edge)

flip

代码
import manimgx as m


class MobjectFlipExample(m.Scene):
    def construct(self) -> None:
        word = m.Text("flip", font_size=160, color=m.YELLOW)
        self.add(word)
        self.play(word.animate.flip())
        self.play(word.animate.flip(m.RIGHT))

翻转 mobject 及其整个家族:绕过某点的轴转半圈, 即关于该轴镜像。

关于默认的 UP 轴,左右镜像;关于 RIGHT 轴,上下颠倒。 通过 animate,它翻转,穿过空间。

mobject.flip(axis=UP, *, about_point=None, about_edge=None)
axis

轴的方向(默认 UP)。

about_point

轴所经过的点;None:参见 about_edge。

about_edge

mobject 边界框上轴所经过的点, 以方向命名;None 表示其中心。

源码

manimgx\mobject.py

def flip(
    self,
    axis: Vector3DLike = UP,
    *,
    about_point: Point3DLike | None = None,
    about_edge: Vector3DLike | None = None,
) -> Self:
    """翻转 mobject 及其整个家族:绕过某点的轴转半圈,
    即关于该轴镜像。

    关于默认的 UP 轴,左右镜像;关于 RIGHT 轴,上下颠倒。
    通过 [animate][manimgx.Mobject.animate],它翻转,穿过空间。

    Args:
        axis: 轴的方向(默认 UP)。
        about_point: 轴所经过的点;None:参见 `about_edge`。
        about_edge: mobject 边界框上轴所经过的点,
            以方向命名;None 表示其中心。

    Examples:
        ```python
        import manimgx as m


        class MobjectFlipExample(m.Scene):
            def construct(self) -> None:
                word = m.Text("flip", font_size=160, color=m.YELLOW)
                self.add(word)
                self.play(word.animate.flip())
                self.play(word.animate.flip(m.RIGHT))
        ```
    """
    return self.rotate(
        TAU / 2, axis, about_point=about_point, about_edge=about_edge
    )

rotation_matrix

绕一条过原点的轴旋转的矩阵。

零轴会引发 ValueError:绕无轴的转动根本不是转动。

m.rotation_matrix(angle, axis=_OUT)
angle

角度,以弧度为单位,从 axis 顶端看去为逆时针方向。

axis

该轴的方向(其长度无关紧要)。

返回 3×3 旋转矩阵。

源码

manimgx\drawing\geometry.py

def rotation_matrix(angle: float, axis: Vector3DLike = _OUT) -> MatrixMN:
    """绕一条过原点的轴旋转的矩阵。

    零轴会引发 ValueError:绕无轴的转动根本不是转动。

    Args:
        angle: 角度,以弧度为单位,从 `axis` 顶端看去为逆时针方向。
        axis: 该轴的方向(其长度无关紧要)。

    Returns:
        3×3 旋转矩阵。
    """
    # Rodrigues' formula; identical to scipy's
    # `Rotation.from_rotvec(angle * axis).as_matrix()`
    x, y, z = normalize(axis)
    if x == y == z == 0:
        raise ValueError(f"a rotation's axis must not be zero, not {axis}")
    c, s = np.cos(angle), np.sin(angle)
    C = 1 - c
    return np.array(
        [
            [c + x * x * C, x * y * C - z * s, x * z * C + y * s],
            [y * x * C + z * s, c + y * y * C, y * z * C - x * s],
            [z * x * C - y * s, z * y * C + x * s, c + z * z * C],
        ]
    )

任意变换

put_start_and_end_on

移动、旋转并缩放 mobject 使其第一个点位于 start, 最后一个点位于 end;其形状保持不变,按比例缩放。

第一个和最后一个点重合的 mobject 仅被移动。

mobject.put_start_and_end_on(start, end)
start

其第一个点要去的位置。

end

其最后一个点要去的位置。

源码

manimgx\mobject.py

def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self:
    """移动、旋转并缩放 mobject 使其第一个点位于 `start`,
    最后一个点位于 `end`;其形状保持不变,按比例缩放。

    第一个和最后一个点重合的 mobject 仅被移动。

    Args:
        start: 其第一个点要去的位置。
        end: 其最后一个点要去的位置。
    """
    cur_start, cur_end = self.get_start_and_end()
    cur_vec = cur_end - cur_start
    if np.all(cur_vec == 0):
        return self.shift(np.asarray(start) - cur_start)
    target_vec = np.asarray(end) - np.asarray(start)
    angle, axis = turn_between(cur_vec, target_vec)
    self.scale(
        np.linalg.norm(target_vec) / np.linalg.norm(cur_vec), about_point=cur_start
    )
    self.rotate(angle, about_point=cur_start, axis=axis)
    return self.shift(np.asarray(start) - cur_start)

apply_matrix

代码
import manimgx as m


class MobjectApplyMatrixExample(m.Scene):
    def construct(self) -> None:
        grid = m.NumberPlane()
        square = m.Square(color=m.YELLOW, fill_opacity=0.5).shift(m.UR)
        shear = [[1, 1], [0, 1]]
        self.add(grid, square)
        self.play(
            grid.animate.apply_matrix(shear),
            square.animate.apply_matrix(shear),
            run_time=2,
        )

通过矩阵变换 mobject 及其整个家族:每个点取相对于 固定点的坐标,乘以该矩阵。

mobject.apply_matrix(matrix, *, about_point=None, about_edge=None)
matrix

一个 3 × 3 矩阵,或更小的矩阵(2 × 2),作用于前几个 坐标并保持其余不变。

about_point

保持不动的点;当此参数和 about_edge 均未指定时, 为原点。

about_edge

mobject 边界框上保持不动的点,以 方向命名。

源码

manimgx\mobject.py

def apply_matrix(
    self,
    matrix: MatrixMN,
    *,
    about_point: Point3DLike | None = None,
    about_edge: Vector3DLike | None = None,
) -> Self:
    """通过矩阵变换 mobject 及其整个家族:每个点取相对于
    固定点的坐标,乘以该矩阵。

    Args:
        matrix: 一个 3 × 3 矩阵,或更小的矩阵(2 × 2),作用于前几个
            坐标并保持其余不变。
        about_point: 保持不动的点;当此参数和 `about_edge` 均未指定时,
            为原点。
        about_edge: mobject 边界框上保持不动的点,以
            方向命名。

    Examples:
        ```python
        import manimgx as m


        class MobjectApplyMatrixExample(m.Scene):
            def construct(self) -> None:
                grid = m.NumberPlane()
                square = m.Square(color=m.YELLOW, fill_opacity=0.5).shift(m.UR)
                shear = [[1, 1], [0, 1]]
                self.add(grid, square)
                self.play(
                    grid.animate.apply_matrix(shear),
                    square.animate.apply_matrix(shear),
                    run_time=2,
                )
        ```
    """
    if about_point is None and about_edge is None:
        about_point = ORIGIN
    full = np.identity(self.dim)
    m = np.array(matrix)
    full[: m.shape[0], : m.shape[1]] = m
    return self._apply_linear(full, about_point, about_edge)

apply_function

代码
import numpy as np

import manimgx as m


def wave(p: np.ndarray) -> np.ndarray:
    return p + 0.5 * np.array([np.sin(p[1]), np.sin(p[0]), 0])


class MobjectApplyFunctionExample(m.Scene):
    def construct(self) -> None:
        grid = m.NumberPlane()
        grid.prepare_for_nonlinear_transform()
        self.add(grid)
        self.play(grid.animate.apply_function(wave), run_time=2)

通过函数移动 mobject 的整个家族,关于某点:每个 绘制成员变为其在该函数下的像。

路径的曲线被映射为其像的曲线。每条曲线被映射为经过其端点之像、 沿其方向之像的曲线;当某条曲线在其中点处偏离真实像超过 0.001 场景单位(4K 下四分之一像素)时,路径的每条曲线被切割为 2、 4、8、… 等份(每条最多 256 份),然后映射各份。其他类型映射其点。 通过 animate,路径的每个点以相同方式切割, 直线移动到其像。

mobject.apply_function(function, *, about_point=None, about_edge=None)
function

一个关于点的函数,相对于固定点,返回 其新位置。

about_point

函数应用所关于的点;当此参数和 about_edge 均未指定时,为原点,因此函数看到的是场景坐标。

about_edge

mobject 边界框上函数应用所关于的点, 以方向命名。

源码

manimgx\mobject.py

def apply_function(
    self,
    function: Callable[[Point3D], Point3D],
    *,
    about_point: Point3DLike | None = None,
    about_edge: Vector3DLike | None = None,
) -> Self:
    """通过函数移动 mobject 的整个家族,关于某点:每个
    绘制成员变为其在该函数下的像。

    路径的曲线被映射为其像的曲线。每条曲线被映射为经过其端点之像、
    沿其方向之像的曲线;当某条曲线在其中点处偏离真实像超过 0.001
    场景单位(4K 下四分之一像素)时,路径的每条曲线被切割为 2、
    4、8、… 等份(每条最多 256 份),然后映射各份。其他类型映射其点。
    通过 [animate][manimgx.Mobject.animate],路径的每个点以相同方式切割,
    直线移动到其像。

    Args:
        function: 一个关于点的函数,相对于固定点,返回
            其新位置。
        about_point: 函数应用所关于的点;当此参数和
            `about_edge` 均未指定时,为原点,因此函数看到的是场景坐标。
        about_edge: mobject 边界框上函数应用所关于的点,
            以方向命名。

    Examples:
        ```python
        import numpy as np

        import manimgx as m


        def wave(p: np.ndarray) -> np.ndarray:
            return p + 0.5 * np.array([np.sin(p[1]), np.sin(p[0]), 0])


        class MobjectApplyFunctionExample(m.Scene):
            def construct(self) -> None:
                grid = m.NumberPlane()
                grid.prepare_for_nonlinear_transform()
                self.add(grid)
                self.play(grid.animate.apply_function(wave), run_time=2)
        ```
    """
    # each leaf becomes its image its own way (`_map_points`): a mobject's points
    # map; a path's curves become the curves of their image (`VMobject._map_points`)
    if about_point is None:
        about_point = (
            ORIGIN if about_edge is None else self.get_critical_point(about_edge)
        )
    about = np.array(about_point, dtype=float)
    for mob in self.family_members_with_points():
        mob._map_points(function, about)
    return self

apply_complex_function

代码
import manimgx as m


class MobjectApplyComplexFunctionExample(m.Scene):
    def construct(self) -> None:
        grid = m.ComplexPlane(x_range=(-4, 4, 0.5), y_range=(-4, 4, 0.5))
        grid.prepare_for_nonlinear_transform()
        self.add(grid)
        self.play(
            grid.animate.apply_complex_function(lambda z: z**2 / 4),
            run_time=2,
        )

通过复数函数移动 mobject 的整个家族:点 (x, y, z) 视为 x + iy,送往 function 所映射的位置,保持其 z。

路径的曲线按 apply_function 的方式映射。

mobject.apply_complex_function(function, **kwargs)
function

一个复数函数,返回一个复数。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

源码

manimgx\mobject.py

def apply_complex_function(
    self, function: Callable[[complex], complex], **kwargs: Unpack[Pivot]
) -> Self:
    """通过复数函数移动 mobject 的整个家族:点
    (x, y, z) 视为 x + iy,送往 `function` 所映射的位置,保持其 z。

    路径的曲线按 [apply_function][manimgx.Mobject.apply_function]
    的方式映射。

    Args:
        function: 一个复数函数,返回一个复数。
        **kwargs: [Pivot 关键字][manimgx.mobject.Pivot]:函数应用
            所关于的点(默认:原点)。

    Examples:
        ```python
        import manimgx as m


        class MobjectApplyComplexFunctionExample(m.Scene):
            def construct(self) -> None:
                grid = m.ComplexPlane(x_range=(-4, 4, 0.5), y_range=(-4, 4, 0.5))
                grid.prepare_for_nonlinear_transform()
                self.add(grid)
                self.play(
                    grid.animate.apply_complex_function(lambda z: z**2 / 4),
                    run_time=2,
                )
        ```
    """

    def r3(point: Point3D) -> Point3D:
        z = function(complex(point[0], point[1]))
        return np.array([z.real, z.imag, point[2]])

    return self.apply_function(r3, **kwargs)

set

按名称设置 mobject 的属性:其属性,如 width、 height 或 color(或文本的 font_size),或任何其他属性。

通过 animate 可为变化制作动画: mobject.animate.set(width=4)。

mobject.set(**kwargs)

属性的名称及其值。

源码

manimgx\mobject.py

def set(self, **kwargs: object) -> Self:
    """按名称设置 mobject 的属性:其属性,如 `width`、
    `height` 或 `color`(或文本的 `font_size`),或任何其他属性。

    通过 [animate][manimgx.Mobject.animate] 可为变化制作动画:
    `mobject.animate.set(width=4)`。

    Args:
        **kwargs: 属性的名称及其值。
    """
    # CE's
    for attr, value in kwargs.items():
        setattr(self, attr, value)
    return self

Pivot

变换所保持不动的点:给定的点,或 mobject 边界框上的一个点。

当两个关键字均未指定时,缩放、旋转或拉伸保持 mobject 的中心不动, 而函数或矩阵关于原点应用。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。

about_point

保持不动的点,以场景坐标表示;它优先于 about_edge。

about_edge

mobject 边界框上保持不动的点,以方向命名: UP 表示其顶边的中点,UR 表示其右上角,ORIGIN 表示其中心。