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 \}
This commit is contained in:
Grant Sanderson 2024-12-26 11:35:34 -06:00 committed by GitHub
parent 39fbb677dc
commit 96d44bd560
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 49 additions and 11 deletions

View file

@ -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:

View file

@ -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):

View file

@ -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
)

View file

@ -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

View file

@ -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

View file

@ -11,7 +11,8 @@ def num_tex_symbols(tex: str) -> int:
tex = remove_tex_environments(tex)
commands_pattern = r"""
(?P<sqrt>\\sqrt\[[0-9]+\])| # Special sqrt with number
(?P<cmd>\\[a-zA-Z!,-/:;<>]+) # Regular commands
(?P<escaped_brace>\\[{}])| # Escaped braces
(?P<cmd>\\[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()

View file

@ -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]