diff --git a/manim/mobject/mobject.py b/manim/mobject/mobject.py index 8557490ed9..b0991430a6 100644 --- a/manim/mobject/mobject.py +++ b/manim/mobject/mobject.py @@ -1979,13 +1979,13 @@ def restore(self) -> Self: self.become(self.saved_state) return self - def reduce_across_dimension(self, reduce_func: Callable, dim: int): + def reduce_across_dimension(self, reduce_func: Callable, dim: int) -> float | None: """Find the min or max value from a dimension across all points in this and submobjects.""" assert dim >= 0 assert dim <= 2 if len(self.submobjects) == 0 and len(self.points) == 0: - # If we have no points and no submobjects, return 0 (e.g. center) - return 0 + # If we have no points and no submobjects, return None + return None # If we do not have points (but do have submobjects) # use only the points from those. @@ -1998,7 +1998,11 @@ def reduce_across_dimension(self, reduce_func: Callable, dim: int): # smallest dimension they have and compare it to the return value. for mobj in self.submobjects: value = mobj.reduce_across_dimension(reduce_func, dim) - rv = value if rv is None else reduce_func([value, rv]) + if rv is None: + rv = value + else: + if value is not None: + rv = reduce_func([value, rv]) return rv def nonempty_submobjects(self) -> list[Self]: @@ -2149,10 +2153,11 @@ def get_nadir(self) -> Point3D: def length_over_dim(self, dim: int) -> float: """Measure the length of an :class:`~.Mobject` in a certain direction.""" - return self.reduce_across_dimension( - max, - dim, - ) - self.reduce_across_dimension(min, dim) + val_max = self.reduce_across_dimension(max, dim) + val_min = self.reduce_across_dimension(min, dim) + if val_max is None and val_min is None: + return 0 + return val_max - val_min def get_coord(self, dim: int, direction: Vector3D = ORIGIN): """Meant to generalize ``get_x``, ``get_y`` and ``get_z``""" diff --git a/tests/module/mobject/mobject/test_mobject.py b/tests/module/mobject/mobject/test_mobject.py index 89deea93c9..b00b4133c5 100644 --- a/tests/module/mobject/mobject/test_mobject.py +++ b/tests/module/mobject/mobject/test_mobject.py @@ -3,7 +3,7 @@ import numpy as np import pytest -from manim import DL, UR, Circle, Mobject, Rectangle, Square, VGroup +from manim import DL, DR, UL, UR, Circle, Mobject, Rectangle, Square, VGroup def test_mobject_add(): @@ -136,21 +136,19 @@ def test_mobject_dimensions_nested_mobjects(): def test_mobject_dimensions_mobjects_with_no_points_are_at_origin(): - rect = Rectangle(width=2, height=3) - rect.move_to([-4, -5, 0]) - outer_group = VGroup(rect) - - # This is as one would expect - assert outer_group.width == 2 - assert outer_group.height == 3 - - # Adding a mobject with no points has a quirk of adding a "point" - # to [0, 0, 0] (the origin). This changes the size of the outer - # group because now the bottom left corner is at [-5, -6.5, 0] - # but the upper right corner is [0, 0, 0] instead of [-3, -3.5, 0] - outer_group.add(VGroup()) - assert outer_group.width == 5 - assert outer_group.height == 6.5 + for direction in [DL, DR, UL, UR]: + rect = Rectangle(width=2, height=3) + rect.move_to(direction * 10) + outer_group = VGroup(rect) + + # This is as one would expect + assert outer_group.width == 2 + assert outer_group.height == 3 + + # Adding a mobject with no points does not change its size + outer_group.add(VGroup()) + assert outer_group.width == 2 + assert outer_group.height == 3 def test_mobject_dimensions_has_points_and_children():