跳转至

路径

影片代码
import manimgx as m


class PathsHero(m.Scene):
    def construct(self) -> None:
        path = m.VMobject(color=m.YELLOW, stroke_width=6)
        path.start_new_path([-5, -1, 0])
        path.add_line_to([-3, 2, 0])
        path.add_smooth_curve_to([0, 0, 0])
        path.add_cubic_bezier_curve_to([1, 3, 0], [3, -3, 0], [5, 1, 0])
        anchors = m.VGroup(
            *[m.Dot(point, color=m.BLUE) for point in path.get_anchors()]
        )
        dot = m.Dot(color=m.RED).move_to(path.get_start())
        self.play(m.Create(path), run_time=2)
        self.play(m.FadeIn(anchors))
        self.play(m.MoveAlongPath(dot, path), run_time=2)
        self.wait()

形状即路径:由曲线组成,每条曲线从一个点到下一个点。曲线从锚点出发,弯向两个控制柄, 最终到达下一个锚点。描边沿曲线行进,填充则将路径的每个部分闭合回其起点。圆、多边形、 文本和图表都是路径,因此以下内容对它们同样适用。

要绘制自定义路径,创建一个空的 m.VMobject(),然后赋予其点:作为角点、作为穿过它们的 平滑曲线,或逐条添加线和曲线。

VMobject

代码
import manimgx as m


class VMobjectExample(m.Scene):
    def construct(self) -> None:
        path = m.VMobject(color=m.BLUE, fill_opacity=0.5, stroke_width=8)
        path.set_points_as_corners([[-3, -2, 0], [-3, 2, 0], [0, 2, 0]])
        path.add_cubic_bezier_curve_to([3, 2, 0], [3, -2, 0], [0, -2, 0])
        path.close_path()
        self.play(m.Create(path, run_time=2))

一条路径:三次贝塞尔曲线,默认白色描边、无填充,除非设置样式。

每条曲线有四个控制点:从锚点出发,弯向两个手柄, 到达下一个锚点。路径的 points 是其 曲线的控制点,每四个一组,当某条曲线的起点不与前一条曲线的终点重合时 开始新的子路径。描边沿曲线行进;填充 用直线将每个子路径闭合回其起点,当子路径 重叠时,某点是否填充取决于它们绕该点的环绕数是否抵消:在另一个 子路径内部反向运行的子路径切出一个洞。

圆、多边形、文本和图都是路径。普通的 VMobject 在被赋予形状之前没有点: 将其点设为角点,或从某点开始并添加 直线和曲线。

m.VMobject(**kwargs)
color

填充与描边共用的颜色(默认白色);None 表示该类的默认值。

fill_color

填充的颜色;未给出时为 color。多个颜色沿 sheen_direction 构成渐变。

fill_opacity

填充的不透明度,取值从 0 到 1(默认 0:无填充)。

stroke_color

描边的颜色;未给出时为 color。多个颜色构成渐变。

stroke_opacity

描边的不透明度,取值从 0 到 1(默认 1)。

stroke_width

描边的宽度,以场景单位的百分之一计(默认 4;0:无描边)。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

还接受 样式关键字。

源码

manimgx\mobject.py

def __init__(self, **kwargs: Unpack[Style]) -> None:
    if (
        "color" in kwargs and kwargs["color"] is None
    ):  # not given: the class's default
        del kwargs["color"]
    self.style = style_defaults(type(self)) | kwargs
    """待定的构造器样式,包括类的默认值。基础颜色初始化会消耗此实例条目;
    当前外观保存在 [paint][manimgx.Mobject.paint] 中。点云保留其默认值供后续点使用。"""
    name = self.style.get("name")
    self.name = type(self).__name__ if name is None else name
    """mobject 的名称:其类的名称,除非创建时指定了名称。"""
    self.dim = 3
    """其每个点拥有的坐标数:3。"""
    self.target: Mobject | None = self.style.get("target")
    """[MoveToTarget][manimgx.MoveToTarget] 将 mobject 移动到的状态:由
    [generate_target][manimgx.Mobject.generate_target] 创建,或在创建 mobject 时给定;
    若两者皆无则为 None。"""
    self.z_index = self.style.get("z_index", 0.0)
    """mobject 在绘制顺序中的位置:索引值较高的绘制在索引值较低的之上
    (默认 0);参见 [set_z_index][manimgx.Mobject.set_z_index]。"""
    self.submobjects: list[Mobject] = []
    """mobject 的子对象,按绘制顺序排列:在相同 z 索引下,每个绘制在之前的之上。"""
    self.updaters: list[Updater[Self]] = []
    """mobject 自身的更新器,按运行顺序排列;参见
    [add_updater][manimgx.Mobject.add_updater]。"""
    self.updating_suspended = False
    """mobject 的更新器是否被暂停;参见
    [suspend_updating][manimgx.Mobject.suspend_updating]。"""
    self.paint = _UNPAINTED
    """mobject 自身当前的样式,作为一个值:其颜色、不透明度、
    描边宽度和光泽。样式方法会替换它;它永远不会被就地修改。"""
    self.reset_points()
    self.generate_points()
    self.init_colors()

绘制路径

set_points_as_corners

VMobjectSetPointsAsCornersExample
代码
import manimgx as m


class VMobjectSetPointsAsCornersExample(m.Scene):
    def construct(self) -> None:
        zigzag = m.VMobject(color=m.YELLOW, stroke_width=8)
        zigzag.set_points_as_corners(
            [[-3, -1.5, 0], [-1.5, 1.5, 0], [0, -1.5, 0], [1.5, 1.5, 0]]
        )
        triangle = m.VMobject(color=m.BLUE, fill_opacity=0.5)
        triangle.set_points_as_corners(
            [[-2, -1.5, 0], [0, 2, 0], [2, -1.5, 0], [-2, -1.5, 0]]
        )
        self.add(m.VGroup(zigzag, triangle).arrange(buff=2))

给路径新点,替换其自身的点:依次经过 给定点的直线。

路径是开放的:要闭合它,以第一个点再次结束。

path.set_points_as_corners(points)
points

角点,场景坐标,按顺序。

源码

manimgx\mobject.py

def set_points_as_corners(self, points: Point3DLike_Array) -> Self:
    """给路径新点,替换其自身的点:依次经过
    给定点的直线。

    路径是开放的:要闭合它,以第一个点再次结束。

    Args:
        points: 角点,场景坐标,按顺序。

    Examples:
        ```python
        import manimgx as m


        class VMobjectSetPointsAsCornersExample(m.Scene):
            def construct(self) -> None:
                zigzag = m.VMobject(color=m.YELLOW, stroke_width=8)
                zigzag.set_points_as_corners(
                    [[-3, -1.5, 0], [-1.5, 1.5, 0], [0, -1.5, 0], [1.5, 1.5, 0]]
                )
                triangle = m.VMobject(color=m.BLUE, fill_opacity=0.5)
                triangle.set_points_as_corners(
                    [[-2, -1.5, 0], [0, 2, 0], [2, -1.5, 0], [-2, -1.5, 0]]
                )
                self.add(m.VGroup(zigzag, triangle).arrange(buff=2))
        ```
    """
    pts = np.asarray(points, dtype=float)
    if len(pts) == 2:  # a segment: the one segment, placed
        self._geometry = segment(pts[0], pts[1])
        return self
    return self.set_anchors_and_handles(
        *(interpolate(pts[:-1], pts[1:], t) for t in _T_VALUES)
    )

set_points_smoothly

代码
import manimgx as m


class VMobjectSetPointsSmoothlyExample(m.Scene):
    def construct(self) -> None:
        points = [[-5, -1, 0], [-3, 2, 0], [-1, -2, 0], [1, 2, 0]]
        points += [[3, -1, 0], [5, 1, 0]]
        corners = m.VMobject(color=m.GREY).set_points_as_corners(points)
        curve = m.VMobject(color=m.YELLOW, stroke_width=8)
        curve.set_points_smoothly(points)
        self.add(corners, *(m.Dot(p, radius=0.12) for p in points))
        self.play(m.Create(curve, run_time=2))

给路径新点,替换其自身的点:依次经过 给定点的平滑曲线。

曲线经过每个点,在该处平滑弯曲,曲率无 突变(三次样条);若最后一个点为第一个点,则平滑闭合。

path.set_points_smoothly(points)
points

曲线经过的点,场景坐标,按顺序。

源码

manimgx\mobject.py

def set_points_smoothly(self, points: Point3DLike_Array) -> Self:
    """给路径新点,替换其自身的点:依次经过
    给定点的平滑曲线。

    曲线经过每个点,在该处平滑弯曲,曲率无
    突变(三次样条);若最后一个点为第一个点,则平滑闭合。

    Args:
        points: 曲线经过的点,场景坐标,按顺序。

    Examples:
        ```python
        import manimgx as m


        class VMobjectSetPointsSmoothlyExample(m.Scene):
            def construct(self) -> None:
                points = [[-5, -1, 0], [-3, 2, 0], [-1, -2, 0], [1, 2, 0]]
                points += [[3, -1, 0], [5, 1, 0]]
                corners = m.VMobject(color=m.GREY).set_points_as_corners(points)
                curve = m.VMobject(color=m.YELLOW, stroke_width=8)
                curve.set_points_smoothly(points)
                self.add(corners, *(m.Dot(p, radius=0.12) for p in points))
                self.play(m.Create(curve, run_time=2))
        ```
    """
    self.set_points_as_corners(points)
    return self.make_smooth()

start_new_path

在某点开始新的子路径:下一条添加的曲线从该点开始,而非 路径终点。

未完成的曲线(已开始但尚未添加曲线的子路径)以 其第一个点的副本补全,作为零长度曲线。若在路径终点处开始, 子路径直接延续。

path.start_new_path(point)
point

新子路径的起点,场景坐标。

源码

manimgx\mobject.py

def start_new_path(self, point: Point3DLike) -> Self:
    """在某点开始新的子路径:下一条添加的曲线从该点开始,而非
    路径终点。

    未完成的曲线(已开始但尚未添加曲线的子路径)以
    其第一个点的副本补全,作为零长度曲线。若在路径终点处开始,
    子路径直接延续。

    Args:
        point: 新子路径的起点,场景坐标。
    """
    n = self._geometry.n
    if n % _NPPCC != 0:
        last = self._geometry.point(n // _NPPCC * _NPPCC)
        self.append_points([last] * (_NPPCC - n % _NPPCC) + [point])
    else:
        self.append_points([point])
    return self

add_line_to

代码
import manimgx as m


class VMobjectAddLineToExample(m.Scene):
    def construct(self) -> None:
        stairs = m.VMobject(color=m.BLUE, stroke_width=8)
        stairs.start_new_path([-5, -3, 0])
        for _ in range(5):
            stairs.add_line_to(stairs.get_end() + 1.2 * m.UP)
            stairs.add_line_to(stairs.get_end() + 2 * m.RIGHT)
        self.play(m.Create(stairs, run_time=3))

从路径终点到某点添加直线。

路径必须有一个点作为起点。

path.add_line_to(point)
point

直线终点,场景坐标。

源码

manimgx\mobject.py

def add_line_to(self, point: Point3DLike) -> Self:
    """从路径终点到某点添加直线。

    路径必须有一个点作为起点。

    Args:
        point: 直线终点,场景坐标。

    Examples:
        ```python
        import manimgx as m


        class VMobjectAddLineToExample(m.Scene):
            def construct(self) -> None:
                stairs = m.VMobject(color=m.BLUE, stroke_width=8)
                stairs.start_new_path([-5, -3, 0])
                for _ in range(5):
                    stairs.add_line_to(stairs.get_end() + 1.2 * m.UP)
                    stairs.add_line_to(stairs.get_end() + 2 * m.RIGHT)
                self.play(m.Create(stairs, run_time=3))
        ```
    """
    last = self.get_last_point()
    p = np.asarray(point, dtype=float)
    return self.add_cubic_bezier_curve_to(
        *(interpolate(last, p, t) for t in _T_VALUES[1:])
    )

add_points_as_corners

从路径终点依次经过每个点添加直线。

路径必须有一个点作为起点。

path.add_points_as_corners(points)
points

角点,场景坐标,按顺序:路径随后在 最后一个点处结束。

源码

manimgx\mobject.py

def add_points_as_corners(self, points: Point3DLike_Array) -> Self:
    """从路径终点依次经过每个点添加直线。

    路径必须有一个点作为起点。

    Args:
        points: 角点,场景坐标,按顺序:路径随后在
            最后一个点处结束。
    """
    self._require_points()
    pts = np.asarray(points, dtype=float).reshape(-1, self.dim)
    if len(pts) == 0:
        return self
    starts = np.vstack([self.points[-1:], pts[:-1]])
    if self.has_new_path_started():
        self.points = self.points[:-1]
    new = np.empty((_NPPCC * len(starts), self.dim))
    for i, t in enumerate(_T_VALUES):
        new[i::_NPPCC] = interpolate(starts, pts, t)
    return self.append_points(new)

add_smooth_curve_to

代码
import manimgx as m


class VMobjectAddSmoothCurveToExample(m.Scene):
    def construct(self) -> None:
        wave = m.VMobject(color=m.YELLOW, stroke_width=8)
        wave.start_new_path([-6, 0, 0])
        wave.add_cubic_bezier_curve_to([-6, 2, 0], [-4, 2, 0], [-4, 0, 0])
        for x in (-2, 0, 2, 4, 6):
            wave.add_smooth_curve_to([x, 0, 0])
        self.play(m.Create(wave, run_time=3))

添加平滑延续路径的曲线:它从路径终点沿 路径到达该处的方向离开。

其第一个手柄是路径最后一个手柄关于路径终点的镜像。 仅给出锚点时,曲线以其离开方式的镜像到达该处 (关于其两端连线的垂直平分线镜像);先给出第二个手柄时, 曲线背离该手柄到达。若无曲线可延续,在 start_new_path 之后, 为到锚点的直线。

path.add_smooth_curve_to(*points)
*points

曲线终点的锚点,或先第二个手柄再 锚点,场景坐标。

源码

manimgx\mobject.py

def add_smooth_curve_to(self, *points: Point3DLike) -> Self:
    """添加平滑延续路径的曲线:它从路径终点沿
    路径到达该处的方向离开。

    其第一个手柄是路径最后一个手柄关于路径终点的镜像。
    仅给出锚点时,曲线以其离开方式的镜像到达该处
    (关于其两端连线的垂直平分线镜像);先给出第二个手柄时,
    曲线背离该手柄到达。若无曲线可延续,在
    [start_new_path][manimgx.VMobject.start_new_path] 之后,
    为到锚点的直线。

    Args:
        *points: 曲线终点的锚点,或先第二个手柄再
            锚点,场景坐标。

    Examples:
        ```python
        import manimgx as m


        class VMobjectAddSmoothCurveToExample(m.Scene):
            def construct(self) -> None:
                wave = m.VMobject(color=m.YELLOW, stroke_width=8)
                wave.start_new_path([-6, 0, 0])
                wave.add_cubic_bezier_curve_to([-6, 2, 0], [-4, 2, 0], [-4, 0, 0])
                for x in (-2, 0, 2, 4, 6):
                    wave.add_smooth_curve_to([x, 0, 0])
                self.play(m.Create(wave, run_time=3))
        ```
    """
    if len(points) == 1:
        handle2, new_anchor = None, np.asarray(points[0])
    elif len(points) == 2:
        handle2, new_anchor = np.asarray(points[0]), np.asarray(points[1])
    else:
        raise ValueError("Only call add_smooth_curve_to with 1 or 2 points")
    if self.has_new_path_started():
        return self.add_line_to(new_anchor)
    last_h2, last_a2 = self.points[-2:]
    tangent = last_a2 - last_h2
    handle1 = last_a2 + tangent
    if handle2 is None:  # the tangent mirrored across the ends' bisector
        chord = normalize(new_anchor - last_a2)
        handle2 = new_anchor + tangent - 2 * (tangent @ chord) * chord
    return self.append_points([last_a2, handle1, handle2, new_anchor])

add_cubic_bezier_curve_to

代码
import manimgx as m


class VMobjectAddCubicBezierCurveToExample(m.Scene):
    def construct(self) -> None:
        start, h1, h2, end = [-4, -2, 0], [-2, 3, 0], [2, 3, 0], [4, -2, 0]
        path = m.VMobject(color=m.YELLOW, stroke_width=8)
        path.start_new_path(start).add_cubic_bezier_curve_to(h1, h2, end)
        handles = m.VGroup(m.Line(start, h1), m.Line(h2, end))
        dots = [m.Dot(p, radius=0.12) for p in (start, h1, h2, end)]
        self.add(handles.set_color(m.GREY), *dots)
        self.play(m.Create(path, run_time=2))

从路径终点到 anchor 添加曲线,弯向两个手柄。

曲线从路径最后一个点朝向 handle1 离开,到达 anchor 时背离 handle2。路径必须有一个点作为起点。

path.add_cubic_bezier_curve_to(handle1, handle2, anchor)
handle1

第一个手柄,场景坐标。

handle2

第二个手柄。

anchor

曲线终点。

源码

manimgx\mobject.py

def add_cubic_bezier_curve_to(
    self, handle1: Point3DLike, handle2: Point3DLike, anchor: Point3DLike
) -> Self:
    """从路径终点到 `anchor` 添加曲线,弯向两个手柄。

    曲线从路径最后一个点朝向 `handle1` 离开,到达
    `anchor` 时背离 `handle2`。路径必须有一个点作为起点。

    Args:
        handle1: 第一个手柄,场景坐标。
        handle2: 第二个手柄。
        anchor: 曲线终点。

    Examples:
        ```python
        import manimgx as m


        class VMobjectAddCubicBezierCurveToExample(m.Scene):
            def construct(self) -> None:
                start, h1, h2, end = [-4, -2, 0], [-2, 3, 0], [2, 3, 0], [4, -2, 0]
                path = m.VMobject(color=m.YELLOW, stroke_width=8)
                path.start_new_path(start).add_cubic_bezier_curve_to(h1, h2, end)
                handles = m.VGroup(m.Line(start, h1), m.Line(h2, end))
                dots = [m.Dot(p, radius=0.12) for p in (start, h1, h2, end)]
                self.add(handles.set_color(m.GREY), *dots)
                self.play(m.Create(path, run_time=2))
        ```
    """
    self._require_points()
    new = [handle1, handle2, anchor]
    return self.append_points(
        new if self.has_new_path_started() else [self.get_last_point(), *new]
    )

add_quadratic_bezier_curve_to

代码
import manimgx as m


class VMobjectAddQuadraticBezierCurveToExample(m.Scene):
    def construct(self) -> None:
        start, handle, end = [-4, -2, 0], [0, 3, 0], [4, -2, 0]
        path = m.VMobject(color=m.TEAL, stroke_width=8)
        path.start_new_path(start)
        path.add_quadratic_bezier_curve_to(handle, end)
        handles = m.VGroup(m.Line(start, handle), m.Line(handle, end))
        dots = [m.Dot(p, radius=0.12) for p in (start, handle, end)]
        self.add(handles.set_color(m.GREY), *dots)
        self.play(m.Create(path, run_time=2))

从路径终点到 anchor 添加二次贝塞尔曲线,弯向 一个手柄。

它作为同形状的三次曲线添加。路径必须有一个点作为起点。

path.add_quadratic_bezier_curve_to(handle, anchor)
handle

手柄,场景坐标:曲线从路径最后 一个点朝向它离开,到达 anchor 时背离它。

anchor

曲线终点。

源码

manimgx\mobject.py

def add_quadratic_bezier_curve_to(
    self, handle: Point3DLike, anchor: Point3DLike
) -> Self:
    """从路径终点到 `anchor` 添加二次贝塞尔曲线,弯向
    一个手柄。

    它作为同形状的三次曲线添加。路径必须有一个点作为起点。

    Args:
        handle: 手柄,场景坐标:曲线从路径最后
            一个点朝向它离开,到达 `anchor` 时背离它。
        anchor: 曲线终点。

    Examples:
        ```python
        import manimgx as m


        class VMobjectAddQuadraticBezierCurveToExample(m.Scene):
            def construct(self) -> None:
                start, handle, end = [-4, -2, 0], [0, 3, 0], [4, -2, 0]
                path = m.VMobject(color=m.TEAL, stroke_width=8)
                path.start_new_path(start)
                path.add_quadratic_bezier_curve_to(handle, end)
                handles = m.VGroup(m.Line(start, handle), m.Line(handle, end))
                dots = [m.Dot(p, radius=0.12) for p in (start, handle, end)]
                self.add(handles.set_color(m.GREY), *dots)
                self.play(m.Create(path, run_time=2))
        ```
    """
    h, a, last = np.asarray(handle), np.asarray(anchor), self.get_last_point()
    return self.add_cubic_bezier_curve_to(
        2 / 3 * h + 1 / 3 * last, 2 / 3 * h + 1 / 3 * a, a
    )

add_cubic_bezier_curve

添加从 anchor1 到 anchor2 的曲线,弯向两个手柄:新的 子路径,除非 anchor1 是路径终点。

其四个点按原样追加,因此路径的曲线必须全部 完整:在 start_new_path 之后,使用 add_cubic_bezier_curve_to。

path.add_cubic_bezier_curve(anchor1, handle1, handle2, anchor2)
anchor1

曲线起点,场景坐标。

handle1

离开 anchor1 时所朝向的手柄。

handle2

到达 anchor2 时所背离的手柄。

anchor2

曲线终点。

源码

manimgx\mobject.py

def add_cubic_bezier_curve(
    self,
    anchor1: Point3DLike,
    handle1: Point3DLike,
    handle2: Point3DLike,
    anchor2: Point3DLike,
) -> Self:
    """添加从 `anchor1` 到 `anchor2` 的曲线,弯向两个手柄:新的
    子路径,除非 `anchor1` 是路径终点。

    其四个点按原样追加,因此路径的曲线必须全部
    完整:在 [start_new_path][manimgx.VMobject.start_new_path] 之后,使用
    [add_cubic_bezier_curve_to][manimgx.VMobject.add_cubic_bezier_curve_to]。

    Args:
        anchor1: 曲线起点,场景坐标。
        handle1: 离开 `anchor1` 时所朝向的手柄。
        handle2: 到达 `anchor2` 时所背离的手柄。
        anchor2: 曲线终点。
    """
    return self.append_points([anchor1, handle1, handle2, anchor2])

add_cubic_bezier_curves

在路径自身的曲线之后添加曲线,由控制点给出,每条曲线四个: 锚点、手柄、手柄、锚点。

path.add_cubic_bezier_curves(curves)
curves

曲线的控制点,场景坐标:(n, 4, 3) 数组,或依次排列的点。

源码

manimgx\mobject.py

def add_cubic_bezier_curves(self, curves: Point3DLike_Array) -> Self:
    """在路径自身的曲线之后添加曲线,由控制点给出,每条曲线四个:
    锚点、手柄、手柄、锚点。

    Args:
        curves: 曲线的控制点,场景坐标:(n, 4, 3)
            数组,或依次排列的点。
    """
    return self.append_points(np.asarray(curves).reshape(-1, 3))

add_subpath

在路径自身的曲线之后添加曲线,由控制点给出,每条曲线四个: 新的子路径,除非它们从路径终点开始。

path.add_subpath(points)
points

曲线的控制点,场景坐标。

源码

manimgx\mobject.py

def add_subpath(self, points: Point3DLike_Array) -> Self:
    """在路径自身的曲线之后添加曲线,由控制点给出,每条曲线四个:
    新的子路径,除非它们从路径终点开始。

    Args:
        points: 曲线的控制点,场景坐标。
    """
    return self.append_points(points)

append_vectorized_mobject

在此路径自身的曲线之后添加另一路径的曲线:其点,而非其 子 mobject。

刚开始但尚未添加曲线的子路径(参见 start_new_path)被丢弃。

path.append_vectorized_mobject(vmobject)
vmobject

要添加其点的路径。

源码

manimgx\mobject.py

def append_vectorized_mobject(self, vmobject: "VMobject") -> Self:
    """在此路径自身的曲线之后添加另一路径的曲线:其点,而非其
    子 mobject。

    刚开始但尚未添加曲线的子路径(参见
    [start_new_path][manimgx.VMobject.start_new_path])被丢弃。

    Args:
        vmobject: 要添加其点的路径。
    """
    if self.has_new_path_started():  # its start begins the path that was begun
        self.points = self.points[:-1]
    return self.append_points(vmobject.points)

close_path

VMobjectClosePathExample
代码
import manimgx as m


class VMobjectClosePathExample(m.Scene):
    def construct(self) -> None:
        corners = [[-2, -1.5, 0], [0, 1.5, 0], [2, -1.5, 0]]
        style = {"fill_opacity": 0.5, "stroke_width": 8}
        open_path = m.VMobject(color=m.GREEN, **style)
        closed_path = m.VMobject(color=m.YELLOW, **style)
        open_path.set_points_as_corners(corners)
        closed_path.set_points_as_corners(corners).close_path()
        self.add(m.VGroup(open_path, closed_path).arrange(buff=2))

闭合路径:从路径终点到其最后一个子路径起点添加直线, 除非路径已在起点处结束。

填充无论如何都会闭合每个子路径;闭合子路径使其描边 完整绕行一圈。

path.close_path()
源码

manimgx\mobject.py

def close_path(self) -> Self:
    """闭合路径:从路径终点到其最后一个子路径起点添加直线,
    除非路径已在起点处结束。

    填充无论如何都会闭合每个子路径;闭合子路径使其描边
    完整绕行一圈。

    Examples:
        ```python
        import manimgx as m


        class VMobjectClosePathExample(m.Scene):
            def construct(self) -> None:
                corners = [[-2, -1.5, 0], [0, 1.5, 0], [2, -1.5, 0]]
                style = {"fill_opacity": 0.5, "stroke_width": 8}
                open_path = m.VMobject(color=m.GREEN, **style)
                closed_path = m.VMobject(color=m.YELLOW, **style)
                open_path.set_points_as_corners(corners)
                closed_path.set_points_as_corners(corners).close_path()
                self.add(m.VGroup(open_path, closed_path).arrange(buff=2))
        ```
    """
    if not self.is_closed():
        self.add_line_to(self.get_subpaths()[-1][0])
    return self

is_closed

路径是否在起点处结束:其第一个和最后一个点在 百万分之一单位内重合。

path.is_closed()
源码

manimgx\mobject.py

def is_closed(self) -> bool:
    """路径是否在起点处结束:其第一个和最后一个点在
    百万分之一单位内重合。"""
    return self.consider_points_equals(
        self._geometry.point(0), self._geometry.point(-1)
    )

平滑或锐利

make_smooth

代码
import manimgx as m


class VMobjectMakeSmoothExample(m.Scene):
    def construct(self) -> None:
        square = m.Square(side_length=4, color=m.BLUE, stroke_width=8)
        self.add(square.copy().set_stroke(m.GREY, 3))
        self.play(square.animate.make_smooth(), run_time=2)

使家族中每个子路径成为经过其锚点的平滑曲线,在任何锚点处 曲率无突变(三次样条);闭合的子路径平滑闭合。

锚点保持不变,手柄移动:多边形变为经过其 角点的圆滑环线。

path.make_smooth()
源码

manimgx\mobject.py

def make_smooth(self) -> Self:
    """使家族中每个子路径成为经过其锚点的平滑曲线,在任何锚点处
    曲率无突变(三次样条);闭合的子路径平滑闭合。

    锚点保持不变,手柄移动:多边形变为经过其
    角点的圆滑环线。

    Examples:
        ```python
        import manimgx as m


        class VMobjectMakeSmoothExample(m.Scene):
            def construct(self) -> None:
                square = m.Square(side_length=4, color=m.BLUE, stroke_width=8)
                self.add(square.copy().set_stroke(m.GREY, 3))
                self.play(square.animate.make_smooth(), run_time=2)
        ```
    """
    return self.change_anchor_mode("smooth")

make_jagged

使家族中每个子路径成为其锚点间的直线:经过点的曲线 变为经过它们的多边形。

path.make_jagged()
源码

manimgx\mobject.py

def make_jagged(self) -> Self:
    """使家族中每个子路径成为其锚点间的直线:经过点的曲线
    变为经过它们的多边形。
    """
    return self.change_anchor_mode("jagged")

insert_n_curves

将路径的曲线分成更多曲线,形状不变。

每条曲线按参数等分,新曲线尽可能均匀地分布在各曲线之间 (m 条中的第 i 条获得 n 条中的第 j 条新曲线,满足 j·m // n = i): 这是变换使两条路径拥有相同曲线数的方式。

path.insert_n_curves(n)
n

要添加多少条曲线。

源码

manimgx\mobject.py

def insert_n_curves(self, n: int) -> Self:
    """将路径的曲线分成更多曲线,形状不变。

    每条曲线按参数等分,新曲线尽可能均匀地分布在各曲线之间
    (m 条中的第 i 条获得 n 条中的第 j 条新曲线,满足 j·m // n = i):
    这是变换使两条路径拥有相同曲线数的方式。

    Args:
        n: 要添加多少条曲线。
    """
    new_path_point = self.get_last_point() if self.has_new_path_started() else None
    self.set_points(self.insert_n_curves_to_point_list(n, self.points))
    if new_path_point is not None:
        self.append_points([new_path_point])
    return self

沿路径

get_start

mobject 的第一个点:路径的起点。

如果 mobject 没有自身的点,则抛出异常。

mobject.get_start()

返回 该点,以场景坐标表示。

源码

manimgx\mobject.py

def get_start(self) -> Point3D:
    """mobject 的第一个点:路径的起点。

    如果 mobject 没有自身的点,则抛出异常。

    Returns:
        该点,以场景坐标表示。
    """
    self._require_points()
    return np.array(self.points[0])

get_end

mobject 的最后一个点:路径的终点。

如果 mobject 没有自身的点,则抛出异常。

mobject.get_end()

返回 该点,以场景坐标表示。

源码

manimgx\mobject.py

def get_end(self) -> Point3D:
    """mobject 的最后一个点:路径的终点。

    如果 mobject 没有自身的点,则抛出异常。

    Returns:
        该点,以场景坐标表示。
    """
    self._require_points()
    return np.array(self.points[-1])

get_midpoint

mobject 上中点处的点:对于路径,为从起点出发其长度一半处。

mobject.get_midpoint()

返回 该点,以场景坐标表示。

源码

manimgx\mobject.py

def get_midpoint(self) -> Point3D:
    """mobject 上中点处的点:对于路径,为从起点出发其长度一半处。

    Returns:
        该点,以场景坐标表示。
    """
    return self.point_from_proportion(0.5)

point_from_proportion

VMobjectPointFromProportionExample
代码
import manimgx as m


class VMobjectPointFromProportionExample(m.Scene):
    def construct(self) -> None:
        points = [[-5, -2, 0], [-2, 2, 0], [1, -1, 0], [5, 2, 0]]
        curve = m.VMobject(color=m.BLUE, stroke_width=6)
        curve.set_points_smoothly(points)
        self.add(curve)
        for alpha in (0, 0.25, 0.5, 0.75, 1):
            point = curve.point_from_proportion(alpha)
            dot = m.Dot(point, radius=0.15, color=m.YELLOW)
            label = m.Text(str(alpha), font_size=32).next_to(dot, m.DOWN)
            self.add(dot, label)

沿路径按长度比例处的点:0 为起点, 1 为终点。

长度是路径自身的度量,即揭示动画所依据的度量(每条曲线九个直线 段),因此它是 Create 在该比例处 已绘制到的位置,MoveAlongPath 以匀速 移动。若 alpha 在 [0, 1] 之外或路径无点则抛出异常。

path.point_from_proportion(alpha)
alpha

比例,从 0 到 1。

返回 该点,场景坐标。

源码

manimgx\mobject.py

def point_from_proportion(self, alpha: float) -> Point3D:
    """沿路径按长度比例处的点:0 为起点,
    1 为终点。

    长度是路径自身的度量,即揭示动画所依据的度量(每条曲线九个直线
    段),因此它是 [Create][manimgx.Create] 在该比例处
    已绘制到的位置,[MoveAlongPath][manimgx.MoveAlongPath] 以匀速
    移动。若 `alpha` 在 [0, 1] 之外或路径无点则抛出异常。

    Args:
        alpha: 比例,从 0 到 1。

    Returns:
        该点,场景坐标。

    Examples:
        ```python
        import manimgx as m


        class VMobjectPointFromProportionExample(m.Scene):
            def construct(self) -> None:
                points = [[-5, -2, 0], [-2, 2, 0], [1, -1, 0], [5, 2, 0]]
                curve = m.VMobject(color=m.BLUE, stroke_width=6)
                curve.set_points_smoothly(points)
                self.add(curve)
                for alpha in (0, 0.25, 0.5, 0.75, 1):
                    point = curve.point_from_proportion(alpha)
                    dot = m.Dot(point, radius=0.15, color=m.YELLOW)
                    label = m.Text(str(alpha), font_size=32).next_to(dot, m.DOWN)
                    self.add(dot, label)
        ```
    """
    if alpha < 0 or alpha > 1:
        raise ValueError(f"Alpha {alpha} not between 0 and 1.")
    self._require_points()
    curves = self.get_num_curves()
    if curves == 0:  # a point, or a subpath just started
        return self.points[-1]
    at = self._geometry.parameter_at(alpha)
    n = min(int(at), curves - 1)
    return self.get_nth_curve_function(n)(at - n)

proportion_from_point

路径上某点沿路径的位置,按长度计算: point_from_proportion 的逆。

以点所在的第一条曲线为准。若点不在路径上则抛出异常。

path.proportion_from_point(point, tolerance=1e-06)
point

该点,场景坐标。

tolerance

点离路径多近才算在上面:沿每个轴在 此值的 100 倍以内,场景单位。

返回 比例,从 0(路径起点)到 1(路径终点)。

源码

manimgx\mobject.py

def proportion_from_point(
    self, point: Point3DLike, tolerance: float = 1e-6
) -> float:
    """路径上某点沿路径的位置,按长度计算:
    [point_from_proportion][manimgx.VMobject.point_from_proportion] 的逆。

    以点所在的第一条曲线为准。若点不在路径上则抛出异常。

    Args:
        point: 该点,场景坐标。
        tolerance: 点离路径多近才算在上面:沿每个轴在
            此值的 100 倍以内,场景单位。

    Returns:
        比例,从 0(路径起点)到 1(路径终点)。
    """
    p = np.asarray(point, dtype=float)
    for n in range(self.get_num_curves()):
        curve = self.get_nth_curve_points(n)
        dim = int(
            np.argmax(np.ptp(curve, axis=0))
        )  # solve along the curve's widest coordinate, then check all
        c = [
            curve[0],
            3 * (curve[1] - curve[0]),
            3 * (curve[2] - 2 * curve[1] + curve[0]),
            curve[3] - 3 * curve[2] + 3 * curve[1] - curve[0],
        ]
        coeffs = np.array([ci[dim] for ci in c])
        coeffs[0] -= p[dim]
        roots = [
            r.real
            for r in (
                np.polynomial.Polynomial(coeffs).roots()
                if coeffs[1:].any()
                else [0.0]  # constant along its widest coordinate: a point
            )
            # candidates, each checked below: a double root (a stationary end) comes
            # back as a complex pair with parts near √ε
            if abs(r.imag) < 1e-4 and -1e-4 <= r.real <= 1 + 1e-4
        ]
        hits = [
            t
            for t in roots
            if np.allclose(
                bezier(curve)(min(max(t, 0), 1)), p, atol=tolerance * 100
            )
        ]
        if hits:  # by the path's own measure: the inverse of point_from_proportion
            return self._geometry.fraction_at(n + min(max(max(hits), 0.0), 1.0))
    raise ValueError(f"Point {point} does not lie on this curve.")

get_arc_length

路径的长度:各曲线长度之和,每条沿其上点间 直线段测量。

path.get_arc_length(sample_points_per_curve=None)
sample_points_per_curve

每条曲线经过多少个点测量,包含 端点;None 为 10,即路径自身的度量。

返回 长度,场景单位。

源码

manimgx\mobject.py

def get_arc_length(self, sample_points_per_curve: int | None = None) -> float:
    """路径的长度:各曲线长度之和,每条沿其上点间
    直线段测量。

    Args:
        sample_points_per_curve: 每条曲线经过多少个点测量,包含
            端点;None 为 10,即路径自身的度量。

    Returns:
        长度,场景单位。
    """
    if sample_points_per_curve in (None, 10):
        return float(self._geometry.curve_lengths().sum())
    return sum(
        length
        for _, length in self.get_curve_functions_with_lengths(
            sample_points_per_curve
        )
    )

get_subcurve

代码
import manimgx as m


class VMobjectGetSubcurveExample(m.Scene):
    def construct(self) -> None:
        circle = m.Circle(radius=2.5, color=m.GREY)
        half = circle.get_subcurve(0.25, 0.75).set_stroke(m.YELLOW, 12)
        self.add(circle)
        self.play(m.Create(half))

路径的副本,截取从比例 a 到比例 b 的部分。

比例按路径的曲线计算,每条曲线等份额不论其 长度,沿每条曲线按其参数 (point_from_proportion 按长度 计算)。副本的子 mobject 整体复制。

path.get_subcurve(a, b)
a

部分起点,从 0 到 1。

b

部分终点,从 a 到 1。

返回 新路径。

源码

manimgx\mobject.py

def get_subcurve(self, a: float, b: float) -> Self:
    """路径的副本,截取从比例 `a` 到比例 `b` 的部分。

    比例按路径的曲线计算,每条曲线等份额不论其
    长度,沿每条曲线按其参数
    ([point_from_proportion][manimgx.VMobject.point_from_proportion] 按长度
    计算)。副本的子 mobject 整体复制。

    Args:
        a: 部分起点,从 0 到 1。
        b: 部分终点,从 `a` 到 1。

    Returns:
        新路径。

    Examples:
        ```python
        import manimgx as m


        class VMobjectGetSubcurveExample(m.Scene):
            def construct(self) -> None:
                circle = m.Circle(radius=2.5, color=m.GREY)
                half = circle.get_subcurve(0.25, 0.75).set_stroke(m.YELLOW, 12)
                self.add(circle)
                self.play(m.Create(half))
        ```
    """
    return self.copy().pointwise_become_partial(self, a, b)

走向

get_direction

路径的转向:"CW"(顺时针)或 "CCW"(逆时针),由 其曲线起始锚点所围面积的符号决定。

path.get_direction()

返回 "CW" 或 "CCW"。

源码

manimgx\mobject.py

def get_direction(self) -> str:
    """路径的转向:"CW"(顺时针)或 "CCW"(逆时针),由
    其曲线起始锚点所围面积的符号决定。

    Returns:
        "CW" 或 "CCW"。
    """
    return shoelace_direction(self.get_start_anchors())

reverse_direction

VMobjectReverseDirectionExample
代码
import manimgx as m


class VMobjectReverseDirectionExample(m.Scene):
    def construct(self) -> None:
        outer, inner = m.Square(side_length=4), m.Square(side_length=2)
        same = m.VMobject(color=m.BLUE, fill_opacity=0.8)
        same.append_vectorized_mobject(outer)
        same.append_vectorized_mobject(inner)
        opposite = m.VMobject(color=m.YELLOW, fill_opacity=0.8)
        opposite.append_vectorized_mobject(outer)
        opposite.append_vectorized_mobject(inner.reverse_direction())
        self.add(m.VGroup(same, opposite).arrange(buff=2))

反转路径自身点的顺序,使其反向运行:从 终点到起点。

其子 mobject 保持不变。绘制动画随后以另一方向绘制它, 在另一个子路径内部的子路径仅当两者反向运行时才在填充中 切出一个洞。

path.reverse_direction()
源码

manimgx\mobject.py

def reverse_direction(self) -> Self:
    """反转路径自身点的顺序,使其反向运行:从
    终点到起点。

    其子 mobject 保持不变。绘制动画随后以另一方向绘制它,
    在另一个子路径内部的子路径仅当两者反向运行时才在填充中
    切出一个洞。

    Examples:
        ```python
        import manimgx as m


        class VMobjectReverseDirectionExample(m.Scene):
            def construct(self) -> None:
                outer, inner = m.Square(side_length=4), m.Square(side_length=2)
                same = m.VMobject(color=m.BLUE, fill_opacity=0.8)
                same.append_vectorized_mobject(outer)
                same.append_vectorized_mobject(inner)
                opposite = m.VMobject(color=m.YELLOW, fill_opacity=0.8)
                opposite.append_vectorized_mobject(outer)
                opposite.append_vectorized_mobject(inner.reverse_direction())
                self.add(m.VGroup(same, opposite).arrange(buff=2))
        ```
    """
    self.points = self.points[::-1].copy()
    return self

force_direction

使路径顺时针或逆时针运行:若方向相反则反转 (参见 get_direction)。

path.force_direction(target_direction)
target_direction

"CW" 为顺时针,"CCW" 为逆时针。

源码

manimgx\mobject.py

def force_direction(self, target_direction: Literal["CW", "CCW"]) -> Self:
    """使路径顺时针或逆时针运行:若方向相反则反转
    (参见 [get_direction][manimgx.VMobject.get_direction])。

    Args:
        target_direction: "CW" 为顺时针,"CCW" 为逆时针。
    """
    if self.get_direction() != target_direction:
        self.reverse_direction()
    return self

其点

points

mobject 自身的点,以场景坐标表示:一个 (n, 3) 数组,只读。

路径的点是其三次贝塞尔曲线的控制点,每条曲线四个。 赋值一个数组可重塑 mobject;其子 mobject 保持各自的点。赋值它已有的点不会改变 任何东西(它保持其几何形状及从其导出的所有内容),除非它们是形状的混合(如变形 中间态),此时会合为一体;在其后追加更多点会使它增长。

mobject.points
源码

manimgx\mobject.py

def points(self) -> Point3D_Array:
    """mobject 自身的点,以场景坐标表示:一个 (n, 3) 数组,只读。

    路径的点是其三次贝塞尔曲线的控制点,每条曲线四个。
    赋值一个数组可重塑 mobject;其子 mobject 保持各自的点。赋值它已有的点不会改变
    任何东西(它保持其几何形状及从其导出的所有内容),除非它们是形状的混合(如变形
    中间态),此时会合为一体;在其后追加更多点会使它增长。
    """
    # the geometry blend, materialized (cached, hence read-only)
    return self._geometry.points()

set_points

为 mobject 赋予新的自身点,替换其现有点。

mobject.set_points(points)
points

这些点,以场景坐标表示:一个 (n, 3) 数组。

源码

manimgx\mobject.py

def set_points(self, points: Point3DLike_Array) -> Self:
    """为 mobject 赋予新的自身点,替换其现有点。

    Args:
        points: 这些点,以场景坐标表示:一个 (n, 3) 数组。
    """
    self.points = np.array(points, dtype=float)
    return self

reset_points

移除 mobject 自身的点;其子 mobject 保持各自的点。

mobject.reset_points()
源码

manimgx\mobject.py

def reset_points(self) -> Self:
    """移除 mobject 自身的点;其子 mobject 保持各自的点。"""
    self._geometry: Blend = EMPTY
    return self

has_points

mobject 是否拥有自身的点(组没有自身的点:其成员有)。

mobject.has_points()
源码

manimgx\mobject.py

def has_points(self) -> bool:
    """mobject 是否拥有自身的点(组没有自身的点:其成员有)。"""
    return self._geometry.n > 0

append_points

在路径自身的点之后添加控制点:每四个一组,路径的 点即其曲线。

path.append_points(new_points)
new_points

点,场景坐标:(n, 3) 数组。

源码

manimgx\mobject.py

def append_points(self, new_points: Point3DLike_Array) -> Self:
    """在路径自身的点之后添加控制点:每四个一组,路径的
    点即其曲线。

    Args:
        new_points: 点,场景坐标:(n, 3) 数组。
    """
    # the path grows in place (its shape is a prefix of an append-only log), so a
    # traced path grows by what it gains, not by a copy of all it has
    rows = np.asarray(new_points, dtype=float).reshape(-1, self.dim)
    g = self._geometry
    if len(g.terms) == 1 and np.array_equal(g.terms[0][0][:, :3], np.eye(3)):
        m, shape = g.terms[0]
        self._geometry = Blend(
            ((m, shape.extended(rows - m[:, 3])),), g.n + len(rows)
        )
        return self
    self.points = np.concatenate([self.points, rows])
    return self

get_anchors

路径的锚点,逐条曲线:每条曲线的起点,然后终点,因此 两条曲线共享的锚点列出两次。

path.get_anchors()

返回 点数组,场景坐标;对于只有一个点的路径,为该 点。

源码

manimgx\mobject.py

def get_anchors(self) -> Point3D_Array:
    """路径的锚点,逐条曲线:每条曲线的起点,然后终点,因此
    两条曲线共享的锚点列出两次。

    Returns:
        点数组,场景坐标;对于只有一个点的路径,为该
        点。
    """
    if self.points.shape[0] == 1:
        return self.points
    s, e = self.get_start_anchors(), self.get_end_anchors()
    out = np.empty((len(s) + len(e), self.dim))
    out[0::2], out[1::2] = s, e
    return out

get_subpaths

路径的子路径:当某条曲线的起点不与前一条曲线的终点 重合时开始新的子路径。

path.get_subpaths()

返回 子路径,每个为其控制点数组,每条曲线四个。

源码

manimgx\mobject.py

def get_subpaths(self) -> list[Point3D_Array]:
    """路径的子路径:当某条曲线的起点不与前一条曲线的终点
    重合时开始新的子路径。

    Returns:
        子路径,每个为其控制点数组,每条曲线四个。
    """
    return self.get_subpaths_from_points(self.points)

get_num_curves

路径有多少条曲线:其点,每条曲线四个。

path.get_num_curves()

返回 曲线数量。

源码

manimgx\mobject.py

def get_num_curves(self) -> int:
    """路径有多少条曲线:其点,每条曲线四个。

    Returns:
        曲线数量。
    """
    return self._geometry.n // _NPPCC

bezier

作为函数的三次贝塞尔曲线:从 0 处的第一个控制点到 1 处的最后一个。

m.bezier(points)
points

其四个控制点:锚点、手柄、手柄、锚点。

返回 以曲线参数(从 0 到 1)为自变量的函数,给出该处的点。

源码

manimgx\drawing\geometry.py

def bezier(points: Point3D_Array) -> Callable[[float], Point3D]:
    """作为函数的三次贝塞尔曲线:从 0 处的第一个控制点到 1 处的最后一个。

    Args:
        points: 其四个控制点:锚点、手柄、手柄、锚点。

    Returns:
        以曲线参数(从 0 到 1)为自变量的函数,给出该处的点。
    """
    P = np.asarray(points)

    def cubic(t: float) -> Point3D:
        mt = 1 - t
        return mt**3 * P[0] + 3 * t * mt**2 * P[1] + 3 * t**2 * mt * P[2] + t**3 * P[3]

    return cubic

由路径构成的路径

CubicBezier

代码
import manimgx as m


class CubicBezierExample(m.Scene):
    def construct(self) -> None:
        start, end = [-5, -2, 0], [5, -2, 0]
        handle1, handle2 = [-3, 3, 0], [6, 3, 0]
        curve = m.CubicBezier(start, handle1, handle2, end, color=m.YELLOW)
        levers = m.VGroup(m.Line(start, handle1), m.Line(end, handle2))
        levers.set_stroke(m.GREY, width=2)
        anchors = m.VGroup(m.Dot(start), m.Dot(end)).set_color(m.BLUE)
        handles = m.VGroup(m.Dot(handle1), m.Dot(handle2)).set_color(m.RED)
        self.add(levers, anchors, handles)
        self.play(m.Create(curve, run_time=2))

三次贝塞尔曲线:从一个锚点到另一个,被两个控制柄拉向; 未加样式时为白色。

曲线离开起点时朝向 start_handle,进入终点时来自 end_handle 方向; 控制柄越远,曲线沿其方向走得越长。曲线不经过任一控制柄。

m.CubicBezier(start_anchor, start_handle, end_handle, end_anchor, **kwargs)
start_anchor

曲线起点。

start_handle

起点的控制柄。

end_handle

终点的控制柄。

end_anchor

曲线终点。

color

填充与描边共用的颜色(默认白色);None 表示该类的默认值。

fill_color

填充的颜色;未给出时为 color。多个颜色沿 sheen_direction 构成渐变。

fill_opacity

填充的不透明度,取值从 0 到 1(默认 0:无填充)。

stroke_color

描边的颜色;未给出时为 color。多个颜色构成渐变。

stroke_opacity

描边的不透明度,取值从 0 到 1(默认 1)。

stroke_width

描边的宽度,以场景单位的百分之一计(默认 4;0:无描边)。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

还接受 样式关键字。

源码

manimgx\mobjects\shapes.py

def __init__(
    self,
    start_anchor: Point3DLike,
    start_handle: Point3DLike,
    end_handle: Point3DLike,
    end_anchor: Point3DLike,
    **kwargs: Unpack[Style],
) -> None:
    super().__init__(**kwargs)
    self.add_cubic_bezier_curve(start_anchor, start_handle, end_handle, end_anchor)

DashedVMobject

代码
import manimgx as m


class DashedVMobjectExample(m.Scene):
    def construct(self) -> None:
        circle = m.Circle(radius=1.5, color=m.BLUE, stroke_width=6)
        square = m.Square(side_length=3, color=m.GREEN, stroke_width=6)
        arc = m.Arc(radius=2, angle=m.PI, color=m.YELLOW, stroke_width=6)
        shapes = m.VGroup(
            m.DashedVMobject(circle, num_dashes=12),
            m.DashedVMobject(square, num_dashes=16, dashed_ratio=0.7),
            m.DashedVMobject(arc, num_dashes=7, dashed_ratio=0.3),
        ).arrange(buff=1)
        self.play(m.Create(shapes, run_time=2))

以虚线绘制的路径:沿另一路径均匀分布的虚线,取其样式。

开放路径以虚线开始和结束;闭合路径有与虚线等多的间隙,环绕整圈。每条虚线 按路径的 cap_style 结束,箭头的尖端完整绘制。

m.DashedVMobject(vmobject, num_dashes=15, dashed_ratio=0.5, dash_offset=0, equal_lengths=True, **kwargs)
vmobject

要以虚线绘制的路径。

num_dashes

虚线数;0 不绘制。

dashed_ratio

虚线覆盖路径的比例,从 0 到 1;其余为间隙。

dash_offset

虚线沿路径向终点移动多远,以一条虚线及其后间隙的分数计。

equal_lengths

虚线是否等长;若为 False 则为路径参数的等长段, 路径运行更快处更长。

color

填充与描边共用的颜色(默认白色);None 表示该类的默认值。

fill_color

填充的颜色;未给出时为 color。多个颜色沿 sheen_direction 构成渐变。

fill_opacity

填充的不透明度,取值从 0 到 1(默认 0:无填充)。

stroke_color

描边的颜色;未给出时为 color。多个颜色构成渐变。

stroke_opacity

描边的不透明度,取值从 0 到 1(默认 1)。

stroke_width

描边的宽度,以场景单位的百分之一计(默认 4;0:无描边)。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

还接受 样式关键字。

源码

manimgx\mobjects\shapes.py

def __init__(
    self,
    vmobject: VMobject,
    num_dashes: int = 15,
    dashed_ratio: float = 0.5,
    dash_offset: float = 0,
    equal_lengths: bool = True,
    **kwargs: Unpack[Style],
) -> None:
    self.dashed_ratio = dashed_ratio
    self.num_dashes = num_dashes
    super().__init__(**kwargs)
    base = vmobject

    tips = base.get_tips().submobjects if isinstance(base, TipableVMobject) else []
    whole = all(any(m is t for t in tips) for m in base.submobjects)
    # the path itself, drawn in dashes (a window over it; its tips drawn whole)
    if (
        num_dashes > 0
        and whole
        and base.has_points()
        and (not equal_lengths or _even(base))
    ):
        self._geometry = base._geometry
        self.match_style(base, family=False)
        self.paint = self.paint.but(
            dash=dash_pattern(
                num_dashes, dashed_ratio, dash_offset, base.is_closed()
            )
        )
        self.add(*(tip.copy() for tip in tips))
        return
    vmobject = base.copy()

    tips = vmobject.pop_tips() if isinstance(vmobject, TipableVMobject) else None
    r, n = dashed_ratio, num_dashes
    if n > 0:
        closed = vmobject.is_closed()
        dash_len = r / n
        void_len = (
            (1 - r) / n if closed else (1 - r if n == 1 else (1 - r) / (n - 1))
        )
        period = dash_len + void_len
        phase = dash_offset % 1 * period
        pattern_len = 1 if closed else 1 + void_len
        starts = [(i * period + phase) % pattern_len for i in range(n)]
        ends = [(i * period + dash_len + phase) % pattern_len for i in range(n)]
        if not closed:
            if ends[-1] > 1 and starts[-1] > 1:
                ends.pop()
                starts.pop()
            elif ends[-1] < dash_len:
                if starts[-1] < 1:
                    starts.append(0)
                    ends.append(ends[-1])
                    ends[-2] = 1
                else:
                    starts[-1] = 0
            elif starts[-1] > 1 - dash_len:
                ends[-1] = 1
        if equal_lengths:
            lengths = np.cumsum(
                np.r_[0.0, vmobject._geometry.piece_lengths().ravel()]
            )
            refs = np.linspace(0, 1, lengths.size)
            total = lengths[-1]
            self.add(
                *(
                    vmobject.get_subcurve(
                        np.interp(s * total, lengths, refs),
                        np.interp(e * total, lengths, refs),
                    )
                    for s, e in zip(starts, ends, strict=True)
                )
            )
        else:
            self.add(
                *(
                    vmobject.get_subcurve(s, e)
                    for s, e in zip(starts, ends, strict=True)
                )
            )
    self.match_style(base, family=False)
    if tips is not None and tips.submobjects:
        self.add(*tips.submobjects)

CurvesAsSubmobjects

代码
import numpy as np

import manimgx as m


class CurvesAsSubmobjectsExample(m.Scene):
    def construct(self) -> None:
        curve = m.ParametricFunction(
            lambda t: [2 * t, 2 * np.sin(t), 0], t_range=(-3, 3, 0.1)
        )
        parts = m.CurvesAsSubmobjects(curve.set_stroke(width=12))
        parts.set_color_by_gradient(m.BLUE, m.YELLOW, m.RED)
        self.play(m.Create(parts, run_time=2))

将路径拆分为其曲线的组:每条曲线一个路径,各以路径的样式样式化。

每部分可独立样式化或动画化:跨部分的渐变沿路径长度为其上色。仅取路径自身的 曲线,而非其子对象的。

m.CurvesAsSubmobjects(vmobject, **kwargs)
vmobject

要拆分的路径。

color

填充与描边共用的颜色(默认白色);None 表示该类的默认值。

fill_color

填充的颜色;未给出时为 color。多个颜色沿 sheen_direction 构成渐变。

fill_opacity

填充的不透明度,取值从 0 到 1(默认 0:无填充)。

stroke_color

描边的颜色;未给出时为 color。多个颜色构成渐变。

stroke_opacity

描边的不透明度,取值从 0 到 1(默认 1)。

stroke_width

描边的宽度,以场景单位的百分之一计(默认 4;0:无描边)。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

还接受 样式关键字。

源码

manimgx\mobjects\shapes.py

def __init__(self, vmobject: VMobject, **kwargs: Unpack[Style]) -> None:
    super().__init__(**kwargs)
    for tup in vmobject.get_cubic_bezier_tuples():
        part = VMobject()
        part.set_points(tup)
        part.match_style(vmobject)
        self.add(part)

VectorizedPoint

代码
import manimgx as m


class VectorizedPointExample(m.Scene):
    def construct(self) -> None:
        point = m.VectorizedPoint(4 * m.LEFT)
        square = m.Square(side_length=3, color=m.BLUE, fill_opacity=0.5)
        self.play(m.ReplacementTransform(point, square.shift(2 * m.RIGHT)))

一个点的路径:不可见,用作放置物体的位置或生长的起点。

它是黑色的,无描边无填充。其宽度和高度是自身的数值, 不是从其点测量的。

m.VectorizedPoint(location=ORIGIN, artificial_width=0.01, artificial_height=0.01, **kwargs)
location

点的位置,场景坐标。

artificial_width

它报告的宽度,场景单位。

artificial_height

它报告的高度,场景单位。

color

填充与描边共用的颜色(默认白色);None 表示该类的默认值。

fill_color

填充的颜色;未给出时为 color。多个颜色沿 sheen_direction 构成渐变。

fill_opacity

填充的不透明度,取值从 0 到 1(默认 0:无填充)。

stroke_color

描边的颜色;未给出时为 color。多个颜色构成渐变。

stroke_opacity

描边的不透明度,取值从 0 到 1(默认 1)。

stroke_width

描边的宽度,以场景单位的百分之一计(默认 4;0:无描边)。

background_stroke_color

绘制于填充之后的轮廓颜色(默认黑色)。

background_stroke_opacity

轮廓的不透明度,取值从 0 到 1(默认 1)。

background_stroke_width

轮廓的宽度,以场景单位的百分之一计(默认 0:无)。

sheen_factor

颜色朝 sheen_direction 变亮的程度,取值从 -1 到 1(默认 0); 负值变暗。

sheen_direction

颜色变亮的方向(默认 UL)。

joint_type

描边在路径转折处的连接方式:圆角、斜切或斜接,按二维场景的绘制方式 (参见 LineJointType;默认 AUTO:斜接)。

cap_style

描边在其显示的每一端的端点样式(开放路径的端点、虚线的端点):圆头、平头 或方头,按二维场景的绘制方式(参见 CapStyleType;默认 AUTO:平头)。

shade_in_3d

三维场景的光是否对该 mobject 着色。

material

其表面在三维场景中如何反射场景的光(参见 Material);None:Manim 的着色(默认)。

name

mobject 的名称;未给出时为其类名。

z_index

其在绘制顺序中的位置:索引较高者绘制于较低者之上 (默认 0)。

target

MoveToTarget 将 mobject 移动至的状态。

还接受 样式关键字。

源码

manimgx\mobject.py

def __init__(
    self,
    location: Point3DLike = ORIGIN,
    artificial_width: float = 0.01,
    artificial_height: float = 0.01,
    **kwargs: Unpack[Style],
) -> None:
    self.artificial_width = artificial_width
    self.artificial_height = artificial_height
    super().__init__(**kwargs)
    self.set_points(np.array([location], dtype=float))

width

点的宽度,场景单位:其 artificial_width,非测量值。 设置它仅改变该数值。

vectorized_point.width
源码

manimgx\mobject.py

def width(self) -> float:
    """点的宽度,场景单位:其 `artificial_width`,非测量值。
    设置它仅改变该数值。"""
    return self.artificial_width

height

点的高度,场景单位:其 artificial_height,非测量值。 设置它仅改变该数值。

vectorized_point.height
源码

manimgx\mobject.py

def height(self) -> float:
    """点的高度,场景单位:其 `artificial_height`,非测量值。
    设置它仅改变该数值。"""
    return self.artificial_height