Source code for manim.utils.paths

"""Functions determining transformation paths between sets of points."""

from __future__ import annotations

__all__ = [
    "straight_path",
    "path_along_arc",
    "clockwise_path",
    "counterclockwise_path",
]


from typing import TYPE_CHECKING

import numpy as np

from ..constants import OUT
from ..utils.bezier import interpolate
from ..utils.space_ops import rotation_matrix

if TYPE_CHECKING:
    from manim.typing import PathFuncType, Vector3D


STRAIGHT_PATH_THRESHOLD = 0.01


[docs] def straight_path(): """Simplest path function. Each point in a set goes in a straight path toward its destination. Examples -------- .. manim :: StraightPathExample class StraightPathExample(Scene): def construct(self): colors = [RED, GREEN, BLUE] starting_points = VGroup( *[ Dot(LEFT + pos, color=color) for pos, color in zip([UP, DOWN, LEFT], colors) ] ) finish_points = VGroup( *[ Dot(RIGHT + pos, color=color) for pos, color in zip([ORIGIN, UP, DOWN], colors) ] ) self.add(starting_points) self.add(finish_points) for dot in starting_points: self.add(TracedPath(dot.get_center, stroke_color=dot.get_color())) self.wait() self.play( Transform( starting_points, finish_points, path_func=utils.paths.straight_path(), run_time=2, ) ) self.wait() """ return interpolate
[docs] def path_along_circles( arc_angle: float, circles_centers: np.ndarray, axis: Vector3D = OUT ) -> PathFuncType: """This function transforms each point by moving it roughly along a circle, each with its own specified center. The path may be seen as each point smoothly changing its orbit from its starting position to its destination. Parameters ---------- arc_angle The angle each point traverses around the quasicircle. circles_centers The centers of each point's quasicircle to rotate around. axis The axis of rotation. Examples -------- .. manim :: PathAlongCirclesExample class PathAlongCirclesExample(Scene): def construct(self): colors = [RED, GREEN, BLUE] starting_points = VGroup( *[ Dot(LEFT + pos, color=color) for pos, color in zip([UP, DOWN, LEFT], colors) ] ) finish_points = VGroup( *[ Dot(RIGHT + pos, color=color) for pos, color in zip([ORIGIN, UP, DOWN], colors) ] ) self.add(starting_points) self.add(finish_points) for dot in starting_points: self.add(TracedPath(dot.get_center, stroke_color=dot.get_color())) circle_center = Dot(3 * LEFT) self.add(circle_center) self.wait() self.play( Transform( starting_points, finish_points, path_func=utils.paths.path_along_circles( 2 * PI, circle_center.get_center() ), run_time=3, ) ) self.wait() """ if np.linalg.norm(axis) == 0: axis = OUT unit_axis = axis / np.linalg.norm(axis) def path(start_points: np.ndarray, end_points: np.ndarray, alpha: float): detransformed_end_points = circles_centers + np.dot( end_points - circles_centers, rotation_matrix(-arc_angle, unit_axis).T ) rot_matrix = rotation_matrix(alpha * arc_angle, unit_axis) return circles_centers + np.dot( interpolate(start_points, detransformed_end_points, alpha) - circles_centers, rot_matrix.T, ) return path
[docs] def path_along_arc(arc_angle: float, axis: Vector3D = OUT) -> PathFuncType: """This function transforms each point by moving it along a circular arc. Parameters ---------- arc_angle The angle each point traverses around a circular arc. axis The axis of rotation. Examples -------- .. manim :: PathAlongArcExample class PathAlongArcExample(Scene): def construct(self): colors = [RED, GREEN, BLUE] starting_points = VGroup( *[ Dot(LEFT + pos, color=color) for pos, color in zip([UP, DOWN, LEFT], colors) ] ) finish_points = VGroup( *[ Dot(RIGHT + pos, color=color) for pos, color in zip([ORIGIN, UP, DOWN], colors) ] ) self.add(starting_points) self.add(finish_points) for dot in starting_points: self.add(TracedPath(dot.get_center, stroke_color=dot.get_color())) self.wait() self.play( Transform( starting_points, finish_points, path_func=utils.paths.path_along_arc(TAU * 2 / 3), run_time=3, ) ) self.wait() """ if abs(arc_angle) < STRAIGHT_PATH_THRESHOLD: return straight_path() if np.linalg.norm(axis) == 0: axis = OUT unit_axis = axis / np.linalg.norm(axis) def path(start_points: np.ndarray, end_points: np.ndarray, alpha: float): vects = end_points - start_points centers = start_points + 0.5 * vects if arc_angle != np.pi: centers += np.cross(unit_axis, vects / 2.0) / np.tan(arc_angle / 2) rot_matrix = rotation_matrix(alpha * arc_angle, unit_axis) return centers + np.dot(start_points - centers, rot_matrix.T) return path
[docs] def clockwise_path() -> PathFuncType: """This function transforms each point by moving clockwise around a half circle. Examples -------- .. manim :: ClockwisePathExample class ClockwisePathExample(Scene): def construct(self): colors = [RED, GREEN, BLUE] starting_points = VGroup( *[ Dot(LEFT + pos, color=color) for pos, color in zip([UP, DOWN, LEFT], colors) ] ) finish_points = VGroup( *[ Dot(RIGHT + pos, color=color) for pos, color in zip([ORIGIN, UP, DOWN], colors) ] ) self.add(starting_points) self.add(finish_points) for dot in starting_points: self.add(TracedPath(dot.get_center, stroke_color=dot.get_color())) self.wait() self.play( Transform( starting_points, finish_points, path_func=utils.paths.clockwise_path(), run_time=2, ) ) self.wait() """ return path_along_arc(-np.pi)
[docs] def counterclockwise_path() -> PathFuncType: """This function transforms each point by moving counterclockwise around a half circle. Examples -------- .. manim :: CounterclockwisePathExample class CounterclockwisePathExample(Scene): def construct(self): colors = [RED, GREEN, BLUE] starting_points = VGroup( *[ Dot(LEFT + pos, color=color) for pos, color in zip([UP, DOWN, LEFT], colors) ] ) finish_points = VGroup( *[ Dot(RIGHT + pos, color=color) for pos, color in zip([ORIGIN, UP, DOWN], colors) ] ) self.add(starting_points) self.add(finish_points) for dot in starting_points: self.add(TracedPath(dot.get_center, stroke_color=dot.get_color())) self.wait() self.play( Transform( starting_points, finish_points, path_func=utils.paths.counterclockwise_path(), run_time=2, ) ) self.wait() """ return path_along_arc(np.pi)
[docs] def spiral_path(angle: float, axis: Vector3D = OUT) -> PathFuncType: """This function transforms each point by moving along a spiral to its destination. Parameters ---------- angle The angle each point traverses around a spiral. axis The axis of rotation. Examples -------- .. manim :: SpiralPathExample class SpiralPathExample(Scene): def construct(self): colors = [RED, GREEN, BLUE] starting_points = VGroup( *[ Dot(LEFT + pos, color=color) for pos, color in zip([UP, DOWN, LEFT], colors) ] ) finish_points = VGroup( *[ Dot(RIGHT + pos, color=color) for pos, color in zip([ORIGIN, UP, DOWN], colors) ] ) self.add(starting_points) self.add(finish_points) for dot in starting_points: self.add(TracedPath(dot.get_center, stroke_color=dot.get_color())) self.wait() self.play( Transform( starting_points, finish_points, path_func=utils.paths.spiral_path(2 * TAU), run_time=5, ) ) self.wait() """ if abs(angle) < STRAIGHT_PATH_THRESHOLD: return straight_path() if np.linalg.norm(axis) == 0: axis = OUT unit_axis = axis / np.linalg.norm(axis) def path(start_points: np.ndarray, end_points: np.ndarray, alpha: float): rot_matrix = rotation_matrix((alpha - 1) * angle, unit_axis) return start_points + alpha * np.dot(end_points - start_points, rot_matrix.T) return path