From 58fe0c79d8f9b12be4e75a7fe04cee4187b55ba5 Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Sat, 6 Jun 2020 11:43:59 -0700 Subject: [PATCH] Reconfigured ParametricCurve --- manimlib/mobject/coordinate_systems.py | 20 +++----- manimlib/mobject/functions.py | 66 +++++++++++++------------- 2 files changed, 41 insertions(+), 45 deletions(-) diff --git a/manimlib/mobject/coordinate_systems.py b/manimlib/mobject/coordinate_systems.py index 0f9d28d6..5a9ae287 100644 --- a/manimlib/mobject/coordinate_systems.py +++ b/manimlib/mobject/coordinate_systems.py @@ -84,16 +84,12 @@ class CoordinateSystem(): ) return self.axis_labels - def get_graph(self, function, x_min=None, x_max=None, **kwargs): - if x_min is None: - x_min = self.x_min - if x_max is None: - x_max = self.x_max - + def get_graph(self, function, x_range=None, **kwargs): + if x_range is None: + x_range = self.x_range graph = ParametricCurve( lambda t: self.coords_to_point(t, function(t)), - t_min=x_min, - t_max=x_max, + t_range=x_range, **kwargs ) graph.underlying_function = function @@ -102,9 +98,7 @@ class CoordinateSystem(): def get_parametric_curve(self, function, **kwargs): dim = self.dimension graph = ParametricCurve( - lambda t: self.coords_to_point( - *function(t)[:dim] - ), + lambda t: self.coords_to_point(*function(t)[:dim]), **kwargs ) graph.underlying_function = function @@ -119,8 +113,8 @@ class CoordinateSystem(): graph.point_from_proportion(a) )[0], target=x, - lower_bound=self.x_min, - upper_bound=self.x_max, + lower_bound=self.x_range[0], + upper_bound=self.x_range[1], ) if alpha is not None: return graph.point_from_proportion(alpha) diff --git a/manimlib/mobject/functions.py b/manimlib/mobject/functions.py index 31df3c9f..cbb08103 100644 --- a/manimlib/mobject/functions.py +++ b/manimlib/mobject/functions.py @@ -6,29 +6,33 @@ from manimlib.utils.space_ops import get_norm class ParametricCurve(VMobject): CONFIG = { - "t_min": 0, - "t_max": 1, - "step_size": 0.2, + "t_range": [0, 1, 0.1], "min_samples": 8, - "dt": 1e-8, + "epsilon": 1e-8, # TODO, automatically figure out discontinuities "discontinuities": [], } - def __init__(self, function=None, **kwargs): - # either get a function from __init__ or from CONFIG - self.function = function or self.function + def __init__(self, t_func, t_range=None, **kwargs): + digest_config(self, kwargs) + if t_range is not None: + self.t_range[:len(t_range)] = t_range + # To be backward compatible with all the scenes specifying t_min, t_max, step_size + self.t_range = [ + kwargs.get("t_min", self.t_range[0]), + kwargs.get("t_max", self.t_range[1]), + kwargs.get("step_size", self.t_range[2]), + ] + self.t_func = t_func VMobject.__init__(self, **kwargs) - def get_function(self): - return self.function - def get_point_from_function(self, t): - return self.function(t) + return self.t_func(t) def init_points(self): - t_min, t_max = self.t_min, self.t_max - dt = self.dt + # TODO, this seems like a mess. + t_min, t_max, step = self.t_range + epsilon = self.epsilon discontinuities = filter( lambda t: t_min <= t <= t_max, @@ -36,24 +40,24 @@ class ParametricCurve(VMobject): ) discontinuities = np.array(list(discontinuities)) boundary_times = [ - self.t_min, self.t_max, - *(discontinuities - dt), - *(discontinuities + dt), + t_min, t_max, + *(discontinuities - epsilon), + *(discontinuities + epsilon), ] boundary_times.sort() for t1, t2 in zip(boundary_times[0::2], boundary_times[1::2]): # Get an initial sample of points t_range = list(np.linspace(t1, t2, self.min_samples + 1)) - samples = [self.function(t) for t in t_range] + samples = np.array([self.t_func(t) for t in t_range]) # Take more samples based on the distances between them norms = [get_norm(p2 - p1) for p1, p2 in zip(samples, samples[1:])] full_t_range = [t1] for s1, s2, norm in zip(t_range, t_range[1:], norms): - n_inserts = int(norm / self.step_size) + n_inserts = int(norm / step) full_t_range += list(np.linspace(s1, s2, n_inserts + 1)[1:]) - points = np.array([self.function(t) for t in full_t_range]) + points = np.array([self.t_func(t) for t in full_t_range]) valid_indices = np.isfinite(points).all(1) points = points[valid_indices] if len(points) > 0: @@ -66,25 +70,23 @@ class ParametricCurve(VMobject): class FunctionGraph(ParametricCurve): CONFIG = { "color": YELLOW, - "x_min": -FRAME_X_RADIUS, - "x_max": FRAME_X_RADIUS, + "x_range": [-8, 8, 0.1], } - def __init__(self, function, **kwargs): + def __init__(self, function, x_range=None, **kwargs): digest_config(self, kwargs) - self.parametric_function = \ - lambda t: np.array([t, function(t), 0]) - ParametricCurve.__init__( - self, - self.parametric_function, - t_min=self.x_min, - t_max=self.x_max, - **kwargs - ) self.function = function + if x_range is not None: + self.x_range[:len(x_range)] = x_range + + def parametric_function(t): + return [t, function(t), 0] + + super().__init__(parametric_function, x_range, **kwargs) + def get_function(self): return self.function def get_point_from_function(self, x): - return self.parametric_function(x) + return self.t_func(x)