diff --git a/manimlib/mobject/changing.py b/manimlib/mobject/changing.py index 69e9302b..cd4a2481 100644 --- a/manimlib/mobject/changing.py +++ b/manimlib/mobject/changing.py @@ -1,4 +1,10 @@ -from manimlib.constants import * +import numpy as np +from manimlib.constants import BLUE_D +from manimlib.constants import BLUE_B +from manimlib.constants import BLUE_E +from manimlib.constants import GREY_BROWN +from manimlib.constants import WHITE +from manimlib.mobject.mobject import Mobject from manimlib.mobject.types.vectorized_mobject import VMobject from manimlib.mobject.types.vectorized_mobject import VGroup from manimlib.utils.rate_functions import smooth @@ -75,24 +81,52 @@ class TracedPath(VMobject): "stroke_width": 2, "stroke_color": WHITE, "min_distance_to_new_point": 0.1, + "time_traced": np.inf, + "fill_opacity": 0, + "sparseness": 1, } def __init__(self, traced_point_func, **kwargs): super().__init__(**kwargs) self.traced_point_func = traced_point_func - self.add_updater(lambda m: m.update_path()) + self.time = 0 + self.times = [] + self.traced_points = [] + self.add_updater(lambda m, dt: m.update_path(dt)) - def update_path(self): - new_point = self.traced_point_func() - if not self.has_points(): - self.start_new_path(new_point) - self.add_line_to(new_point) + def update_path(self, dt): + point = np.array(self.traced_point_func()) + tps = self.traced_points + times = self.times + + if len(tps) == 0: + tps.append(point) + times.append(self.time) + if get_norm(point - tps[-1]) >= self.min_distance_to_new_point: + times.append(self.time) + tps.append(point) + # Cut off tail + while times and times[0] < self.time - self.time_traced: + times = times[1:] + tps = tps[1:] + if tps: + self.set_points_as_corners(tps[::self.sparseness]) + self.time += dt + + +class TracingTail(TracedPath): + CONFIG = { + "stroke_width": (0, 3), + "stroke_opacity": (0, 1), + "stroke_color": WHITE, + "time_traced": 1.0, + "min_distance_to_new_point": 0, + "sparseness": 3, + } + + def __init__(self, mobject_or_func, **kwargs): + if isinstance(mobject_or_func, Mobject): + func = mobject_or_func.get_center else: - # Set the end to be the new point - self.get_points()[-1] = new_point - - # Second to last point - nppcc = self.n_points_per_curve - dist = get_norm(new_point - self.get_points()[-nppcc]) - if dist >= self.min_distance_to_new_point: - self.add_line_to(new_point) + func = mobject_or_func + super().__init__(func, **kwargs)