From 96d44bd560564882ddc6f0d81b92ca2a00b5954b Mon Sep 17 00:00:00 2001 From: Grant Sanderson Date: Thu, 26 Dec 2024 11:35:34 -0600 Subject: [PATCH] Video work (#2284) * Comment tweak * Directly print traceback Since the shell.showtraceback is giving some issues * Make InteracrtiveSceneEmbed into a class This way it can keep track of it's internal shell; use of get_ipython has a finicky relationship with reloading. * Move remaining checkpoint_paste logic into scene_embed.py This involved making a few context managers for Scene: temp_record, temp_skip, temp_progress_bar, which seem useful in and of themselves. * Change null key to be the empty string * Ensure temporary svg paths for Text are deleted * Remove unused dict_ops.py functions * Remove break_into_partial_movies from file_writer configuration * Rewrite guarantee_existence using Path * Clean up SceneFileWriter It had a number of vestigial functions no longer used, and some setup that could be made more organized. * Remove --save_pngs CLI arg (which did nothing) * Add --subdivide CLI arg * Remove add_extension_if_not_present * Remove get_sorted_integer_files * Have find_file return Path * Minor clean up * Clean up num_tex_symbols * Fix find_file * Minor cleanup for extract_scene.py * Add preview_frame_while_skipping option to scene config * Use shell.showtraceback function * Move keybindings to config, instead of in-place constants * Replace DEGREES -> DEG * Add arg to clear the cache * Separate out full_tex_to_svg from tex_to_svg And only cache to disk the results of full_tex_to_svg. Otherwise, making edits to the tex_templates would not show up without clearing the cache. * Bug fix in handling BlankScene * Make checkpoint_states an instance variable of CheckpointManager As per https://github.com/3b1b/manim/issues/2272 * Move resizing out of Window.focus, and into Window.init_for_scene * Make default output directory "." instead of "" To address https://github.com/3b1b/manim/issues/2261 * Remove input_file_path arg from SceneFileWriter * Use Dict syntax in place of dict for config more consistently across config.py * Simplify get_output_directory * Swap order of preamble and additional preamble * Minor stylistic tweak * Have UnitInterval pass on kwargs to NumberLine * Add simple get_dist function * Have TracedPath always update to the stroke configuration passed in * Have Mobject.match_points apply to all parts of data in pointlike_data_key * Always call Mobject.update upon adding an updater * Add Surface.uv_to_point * Make sure Surface.set_opacity takes in a recurse option * Update num_tex_symbols to account for \{ and \} --- manimlib/mobject/changing.py | 2 +- manimlib/mobject/mobject.py | 10 +++++++--- manimlib/mobject/number_line.py | 4 +++- manimlib/mobject/types/surface.py | 30 +++++++++++++++++++++++++++++- manimlib/utils/space_ops.py | 4 ++++ manimlib/utils/tex.py | 5 ++++- manimlib/utils/tex_file_writing.py | 5 +---- 7 files changed, 49 insertions(+), 11 deletions(-) diff --git a/manimlib/mobject/changing.py b/manimlib/mobject/changing.py index 01a73560..0c3c17f6 100644 --- a/manimlib/mobject/changing.py +++ b/manimlib/mobject/changing.py @@ -112,7 +112,7 @@ class TracedPath(VMobject): self.time: float = 0 self.traced_points: list[np.ndarray] = [] self.add_updater(lambda m, dt: m.update_path(dt)) - self.set_stroke(stroke_color, stroke_width) + self.always.set_stroke(stroke_color, stroke_width) def update_path(self, dt: float) -> Self: if dt == 0: diff --git a/manimlib/mobject/mobject.py b/manimlib/mobject/mobject.py index 36cd5c64..7cd027d1 100644 --- a/manimlib/mobject/mobject.py +++ b/manimlib/mobject/mobject.py @@ -307,12 +307,15 @@ class Mobject(object): parent.refresh_bounding_box() return self - # Others related to points - + @affects_data def match_points(self, mobject: Mobject) -> Self: - self.set_points(mobject.get_points()) + self.resize_points(len(mobject.data), resize_func=resize_preserving_order) + for key in self.pointlike_data_keys: + self.data[key][:] = mobject.data[key] return self + # Others related to points + def get_points(self) -> Vect3Array: return self.data["point"] @@ -842,6 +845,7 @@ class Mobject(object): if call: self.update(dt=0) self.refresh_has_updater_status() + self.update() return self def insert_updater(self, update_func: Updater, index=0): diff --git a/manimlib/mobject/number_line.py b/manimlib/mobject/number_line.py index c2f49e88..f98b0a0e 100644 --- a/manimlib/mobject/number_line.py +++ b/manimlib/mobject/number_line.py @@ -221,11 +221,13 @@ class UnitInterval(NumberLine): big_tick_numbers: list[float] = [0, 1], decimal_number_config: dict = dict( num_decimal_places=1, - ) + ), + **kwargs ): super().__init__( x_range=x_range, unit_size=unit_size, big_tick_numbers=big_tick_numbers, decimal_number_config=decimal_number_config, + **kwargs ) diff --git a/manimlib/mobject/types/surface.py b/manimlib/mobject/types/surface.py index 1a0eabb4..127851b6 100644 --- a/manimlib/mobject/types/surface.py +++ b/manimlib/mobject/types/surface.py @@ -8,9 +8,11 @@ from manimlib.constants import OUT from manimlib.mobject.mobject import Mobject from manimlib.utils.bezier import integer_interpolate from manimlib.utils.bezier import interpolate +from manimlib.utils.bezier import inverse_interpolate from manimlib.utils.images import get_full_raster_image_path from manimlib.utils.iterables import listify from manimlib.utils.iterables import resize_with_interpolation +from manimlib.utils.simple_functions import clip from manimlib.utils.space_ops import normalize_along_axis from manimlib.utils.space_ops import cross @@ -96,6 +98,32 @@ class Surface(Mobject): self.data['du_point'][:] = du_points self.data['dv_point'][:] = dv_points + def uv_to_point(self, u, v): + nu, nv = self.resolution + uv_grid = np.reshape(self.get_points(), (nu, nv, self.dim)) + + alpha1 = clip(inverse_interpolate(*self.u_range[:2], u), 0, 1) + alpha2 = clip(inverse_interpolate(*self.v_range[:2], v), 0, 1) + scaled_u = alpha1 * (nu - 1) + scaled_v = alpha2 * (nv - 1) + u_int = int(scaled_u) + v_int = int(scaled_v) + u_int_plus = min(u_int + 1, nu - 1) + v_int_plus = min(v_int + 1, nv - 1) + + a = uv_grid[u_int, v_int, :] + b = uv_grid[u_int, v_int_plus, :] + c = uv_grid[u_int_plus, v_int, :] + d = uv_grid[u_int_plus, v_int_plus, :] + + u_res = scaled_u % 1 + v_res = scaled_v % 1 + return interpolate( + interpolate(a, b, v_res), + interpolate(c, d, v_res), + u_res + ) + def apply_points_function(self, *args, **kwargs) -> Self: super().apply_points_function(*args, **kwargs) self.get_unit_normals() @@ -307,7 +335,7 @@ class TexturedSurface(Surface): self.uniforms["num_textures"] = self.num_textures @Mobject.affects_data - def set_opacity(self, opacity: float | Iterable[float]) -> Self: + def set_opacity(self, opacity: float | Iterable[float], recurse=True) -> Self: op_arr = np.array(listify(opacity)) self.data["opacity"][:, 0] = resize_with_interpolation(op_arr, len(self.data)) return self diff --git a/manimlib/utils/space_ops.py b/manimlib/utils/space_ops.py index e89c1dfe..74a52225 100644 --- a/manimlib/utils/space_ops.py +++ b/manimlib/utils/space_ops.py @@ -48,6 +48,10 @@ def get_norm(vect: VectN | List[float]) -> float: return sum((x**2 for x in vect))**0.5 +def get_dist(vect1: VectN, vect2: VectN): + return get_norm(vect2 - vect1) + + def normalize( vect: VectN | List[float], fall_back: VectN | List[float] | None = None diff --git a/manimlib/utils/tex.py b/manimlib/utils/tex.py index 7c2d7ecc..88b7a8e4 100644 --- a/manimlib/utils/tex.py +++ b/manimlib/utils/tex.py @@ -11,7 +11,8 @@ def num_tex_symbols(tex: str) -> int: tex = remove_tex_environments(tex) commands_pattern = r""" (?P\\sqrt\[[0-9]+\])| # Special sqrt with number - (?P\\[a-zA-Z!,-/:;<>]+) # Regular commands + (?P\\[{}])| # Escaped braces + (?P\\[a-zA-Z!,-/:;<>]+) # Regular commands """ total = 0 pos = 0 @@ -21,6 +22,8 @@ def num_tex_symbols(tex: str) -> int: if match.group("sqrt"): total += len(match.group()) - 5 + elif match.group("escaped_brace"): + total += 1 # Count escaped brace as one symbol else: total += TEX_TO_SYMBOL_COUNT.get(match.group(), 1) pos = match.end() diff --git a/manimlib/utils/tex_file_writing.py b/manimlib/utils/tex_file_writing.py index 71872ce0..2778a0dc 100644 --- a/manimlib/utils/tex_file_writing.py +++ b/manimlib/utils/tex_file_writing.py @@ -22,10 +22,7 @@ def get_tex_template_config(template_name: str) -> dict[str, str]: with open(template_path, encoding="utf-8") as tex_templates_file: templates_dict = yaml.safe_load(tex_templates_file) if name not in templates_dict: - log.warning( - "Cannot recognize template '%s', falling back to 'default'.", - name - ) + log.warning(f"Cannot recognize template {name}, falling back to 'default'.") name = "default" return templates_dict[name]