选择类型提示

为了提供最佳用户体验,正确选择类型提示至关重要。Manim 提供了大量不同类型的提示,选择合适的可能很困难。本指南旨在帮助您选择适用于特定场景的正确类型。

第一步是确定您的类型提示属于哪个类别。

坐标

坐标包含两个主要类别:点和向量。

点的用途非常直接:它们表示空间中的一个点。例如

def print_point2D(coord: Point2DLike) -> None:
    x, y = coord
    print(f"Point at {x=},{y=}")


def print_point3D(coord: Point3DLike) -> None:
    x, y, z = coord
    print(f"Point at {x=},{y=},{z=}")


def print_point_array(coords: Point2DLike_Array | Point3DLike_Array) -> None:
    for coord in coords:
        if len(coord) == 2:
            # it's a Point2DLike
            print_point2D(coord)
        else:
            # it's a Point3DLike
            print_point3D(coord)

def shift_point_up(coord: Point3DLike) -> Point3D:
    result = np.asarray(coord)
    result += UP
    print(f"New point: {result}")
    return result

请注意,最后一个函数 shift_point_up() 接受 Point3DLike 作为参数,并返回 Point3D。一个 Point3D 始终表示由 3 个浮点数组成的 NumPy 数组,而 Point3DLike 可以表示任何类似于 3D 点的东西:要么是一个 NumPy 数组,要么是一个包含 3 个浮点数的元组/列表,因此有了 Like 这个词。同样的情况也发生在 Point2DPoint2D_ArrayPoint3D_Array,以及它们对应的 Like 类型 Point2DLikePoint2DLike_ArrayPoint3DLike_Array 上。

函数类型标注的规则是:参数类型应尽可能宽泛,返回类型应尽可能具体。 因此,对于旨在供用户调用的函数,如果可能,我们应始终接受 Like 类型作为参数,并返回 NumPy、非 Like 类型。 主要原因是,为了给那些可能更倾向于传递元组或列表作为参数而不是 NumPy 数组的用户提供更大的灵活性,因为这更方便。最后一个函数 shift_point_up() 就是一个例子。

不应由用户调用的内部函数,如果需要,可以接受非 Like 参数。

向量

向量与点有许多相似之处。然而,它们具有不同的含义。向量应该用来表示方向。例如,考虑这个稍微有点刻意的函数:

M = TypeVar("M", bound=Mobject)  # allow any mobject
def shift_mobject(mob: M, direction: Vector3D, scale_factor: float = 1) -> M:
    return mob.shift(direction * scale_factor)

这里我们看到了一个重要的区别示例。direction 不应该被标注为 Point3D,因为它表示的是一个用来移动 Mobject 的方向,而不是空间中的一个位置。

一般来说,如果一个参数被称为 directionaxis,它应该被类型提示为某种形式的 VectorND

警告

这并非总是如此。例如,从 Manim 0.18.0 版本开始,Vector Mobject 的 `direction` 参数应为 Point2DLike | Point3DLike,因为它也可以接受 tuple[float, float]tuple[float, float, float]

颜色

Manim 提供的用于处理颜色的接口是 ManimColor。Manim 支持的主要颜色类型是 RGB、RGBA 和 HSV。您需要根据函数使用的颜色类型添加类型提示。如果任何颜色都适用,您需要类似这样的标注:

if TYPE_CHECKING:
    from manim.utils.color import ParsableManimColor

# type hint stuff with ParsableManimColor

贝塞尔曲线

Manim 内部使用点集合来表示 Mobject。对于最常用的 Mobject 子类 VMobject 而言,这些点代表贝塞尔曲线,它是一种使用一系列点来表示曲线的方式。

注意

要了解更多关于贝塞尔曲线的信息,请查看 https://pomax.github.io/bezierinfo/

Manim 支持两种不同的渲染器,它们各自对贝塞尔曲线有不同的表示方式:Cairo 使用三次贝塞尔曲线,而 OpenGL 使用二次贝塞尔曲线。

类型提示如 BezierPoints 表示一条贝塞尔曲线,而 BezierPath 表示多条贝塞尔曲线。当 BezierPath 中的贝塞尔曲线形成一条单一的连续曲线时,它被称为 Spline。Manim 还提供了更具体的类型别名,用于处理二次或三次曲线,它们以各自的类型作为前缀(例如,CubicBezierPoints 是一个由恰好 4 个点组成的 BezierPoints,代表一条三次贝塞尔曲线)。

函数

在整个代码库中,使用了许多不同类型的函数。最明显的例子是速率函数,它接受一个浮点数并输出一个浮点数(Callable[[float], float])。另一个例子是用于覆盖动画。通常需要将一个 Mobject 映射到一个被覆盖的 Animation,为此我们有 FunctionOverride 类型提示。

PathFuncTypeMappingFunction 更具专业性,但与沿路径移动对象或应用函数有关。如果您需要使用它们,您就会明白。

图像

Manim 中有几种图像表示方式。最常见的是以表示图像像素的浮点数 NumPy 数组形式。这在 OpenGL 渲染器中尤为常见。

这是 PixelArray 类型提示的用例。有时,Manim 可能会使用 PIL.Image.Image,它与 PixelArray 不同。在这种情况下,请使用 PIL.Image.Image 类型提示。当然,如果需要更具体的图像类型,也可以进行相应的标注。