mirror of
https://github.com/3b1b/manim.git
synced 2026-04-26 03:00:23 -04:00
Allow path_along_arc to take in multiple arc_angle values
This commit is contained in:
@@ -28,7 +28,7 @@ class Transform(Animation):
|
||||
self,
|
||||
mobject: Mobject,
|
||||
target_mobject: Mobject | None = None,
|
||||
path_arc: float = 0.0,
|
||||
path_arc: float | Tuple[float, float] = 0.0,
|
||||
path_arc_axis: np.ndarray = OUT,
|
||||
path_func: Callable | None = None,
|
||||
**kwargs
|
||||
@@ -43,7 +43,7 @@ class Transform(Animation):
|
||||
def init_path_func(self) -> None:
|
||||
if self.path_func is not None:
|
||||
return
|
||||
elif self.path_arc == 0:
|
||||
elif isinstance(self.path_arc, float) and self.path_arc == 0:
|
||||
self.path_func = straight_path
|
||||
else:
|
||||
self.path_func = path_along_arc(
|
||||
|
||||
@@ -34,26 +34,43 @@ def straight_path(
|
||||
|
||||
|
||||
def path_along_arc(
|
||||
arc_angle: float,
|
||||
arc_angle: float | Tuple[float, float] | np.ndarray,
|
||||
axis: Vect3 = OUT
|
||||
) -> Callable[[Vect3Array, Vect3Array, float], Vect3Array]:
|
||||
"""
|
||||
arc_angle can be a single angle, or a pair of angles, in which case
|
||||
the range of all angles between that pair will be used.
|
||||
|
||||
If vect is vector from start to end, [vect[:,1], -vect[:,0]] is
|
||||
perpendicular to vect in the left direction.
|
||||
"""
|
||||
if abs(arc_angle) < STRAIGHT_PATH_THRESHOLD:
|
||||
if isinstance(arc_angle, float | int) and abs(arc_angle) < STRAIGHT_PATH_THRESHOLD:
|
||||
return straight_path
|
||||
if get_norm(axis) == 0:
|
||||
axis = OUT
|
||||
unit_axis = axis / get_norm(axis)
|
||||
|
||||
def path(start_points, end_points, alpha):
|
||||
vects = end_points - start_points
|
||||
centers = start_points + 0.5 * vects
|
||||
if arc_angle != np.pi:
|
||||
centers += np.cross(unit_axis, vects / 2.0) / math.tan(arc_angle / 2)
|
||||
rot_matrix_T = rotation_matrix_transpose(alpha * arc_angle, unit_axis)
|
||||
return centers + np.dot(start_points - centers, rot_matrix_T)
|
||||
if isinstance(arc_angle, float | int):
|
||||
theta = arc_angle
|
||||
else:
|
||||
if isinstance(arc_angle, np.ndarray) and len(arc_angle) == len(start_points):
|
||||
theta_range = arc_angle
|
||||
else:
|
||||
theta_range = np.linspace(arc_angle[0], arc_angle[-1], len(start_points))
|
||||
# Avoid zero, mildly hacky
|
||||
theta_range[np.abs(theta_range) < STRAIGHT_PATH_THRESHOLD] = STRAIGHT_PATH_THRESHOLD
|
||||
# Get shape to match
|
||||
theta = theta_range[:, np.newaxis] * np.ones(start_points.shape[1])
|
||||
start_to_end = end_points - start_points
|
||||
|
||||
with np.errstate(divide='ignore', invalid='ignore'):
|
||||
adjustments = np.nan_to_num(np.cross(unit_axis, start_to_end / 2.0) / np.tan(theta / 2))
|
||||
arc_centers = start_points + 0.5 * start_to_end + adjustments
|
||||
|
||||
c_to_start = start_points - arc_centers
|
||||
c_to_perp = np.cross(unit_axis, c_to_start)
|
||||
return arc_centers + np.cos(alpha * theta) * c_to_start + np.sin(alpha * theta) * c_to_perp
|
||||
|
||||
return path
|
||||
|
||||
|
||||
Reference in New Issue
Block a user