在Manim中沿测量曲线移动Mobject的更优实现方案问询
问题描述
我想找一种更合理的方法,让Mobject沿由n维向量ts、xs、ys(可选zs)定义的路径移动。目前我用ParametricFunction加MoveAlongPath实现,还得定义速率函数来保证时序,但这个方法既繁琐又不够可靠。我觉得应该有内置函数,但一直没找到。
现有实现代码:
# This function takes a path defined by arrays and returns a function # ts is assumed to be strictly increasing def manim_curve(ts,xs,ys): ts,xs,ys = map(np.array,(ts,xs,ys)) # Calculate the total distance traveled over the curve dist = np.cumsum(np.abs(np.diff(xs+1j*ys,prepend=0))) # Normalize to a time range of [0,1] nts = ts / ts[-1] ndist = dist / dist[-1] # Create a function that can be passed `ParametricFunction` def f(t): n = np.abs(nts-t).argmin() # Find index from t return (xs[n],ys[n],0) # Create a rate function for `MoveAlongPath` def rate(t): n = np.abs(nts-t).argmin() # Find index from t return ndist[n] # Create manim curve curve = ParametricFunction(function=f) return curve,rate # Animation class to move along a discretely defined path class MoveAlongMeasuredPath(MoveAlongPath): def __init__(self,object,ts,xs,ys,**kwargs): ts,xs,ys = map(np.array,(ts,xs,ys)) curve,rate = manim_curve(ts,xs,ys) super().__init__(object,curve, run_time = ts[-1], rate_func = rate, **kwargs)
解决方案
Manim目前没有直接支持这种带时序离散点路径的内置动画,但可以通过更简洁可靠的方式实现,核心是用插值替代原方法的索引查找,同时优化路径构建逻辑:
优化后的实现
import numpy as np from scipy.interpolate import interp1d from manim import * class MoveAlongDiscretePath(MoveAlongPath): def __init__(self, mobject, ts, xs, ys, zs=None, **kwargs): ts, xs, ys = map(np.array, (ts, xs, ys)) # 处理3D路径的zs参数,默认全0 zs = np.zeros_like(xs) if zs is None else np.array(zs) # 用离散点构建Path对象,比ParametricFunction更高效 path_points = np.column_stack((xs, ys, zs)) path = Path() path.set_points_as_corners(path_points) # 计算路径各段距离及累积距离,用于时序映射 segment_distances = np.linalg.norm(np.diff(path_points, axis=0), axis=1) cumulative_dist = np.cumsum(np.insert(segment_distances, 0, 0)) total_dist = cumulative_dist[-1] # 构建时间到路径进度的线性插值函数,保证时序准确 time_to_progress = interp1d(ts, cumulative_dist / total_dist, kind='linear') # 定义速率函数:将动画时间[0,1]映射为路径进度[0,1] def rate_func(t): actual_time = np.clip(t * ts[-1], ts[0], ts[-1]) return time_to_progress(actual_time) super().__init__( mobject, path, run_time=ts[-1], rate_func=rate_func, **kwargs )
优化点说明
- 平滑移动:用线性插值替代原方法的
argmin索引查找,避免移动时的跳变,路径过渡更自然 - 3D支持:新增可选
zs参数,直接支持3D路径移动 - 高效路径构建:用
Path类直接通过离散点构建路径,比ParametricFunction更符合Manim的内部路径处理逻辑,性能更优 - 边界处理:通过
np.clip限制时间范围,避免越界问题
使用示例
class TestDiscretePathAnimation(Scene): def construct(self): dot = Dot(color=RED, radius=0.1) # 定义带时序的路径点 ts = np.array([0, 1.5, 3, 4.5, 6]) xs = np.array([0, 2, 0, -2, 0]) ys = np.array([0, 0, 2, 0, -2]) self.add(dot) # 播放路径动画 self.play(MoveAlongDiscretePath(dot, ts, xs, ys))
内容的提问来源于stack exchange,提问作者iHnR
相关产品推荐
相关产品推荐

