Skip to content

Commit 0902eef

Browse files
Enables Use of input_to_graph_point() by CurvesAsSubmobjects Instances (#3190)
* CurvesAsSubmobjects preserve points. * Override point_from_proportion() instead * fixed typo * added test * added underscore for helper method --------- Co-authored-by: Benjamin Hackl <[email protected]>
1 parent 524b27a commit 0902eef

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

manim/mobject/types/vectorized_mobject.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,6 +2345,69 @@ def __init__(self, vmobject, **kwargs):
23452345
part.match_style(vmobject)
23462346
self.add(part)
23472347

2348+
def point_from_proportion(self, alpha: float) -> np.ndarray:
2349+
"""Gets the point at a proportion along the path of the :class:`CurvesAsSubmobjects`.
2350+
2351+
Parameters
2352+
----------
2353+
alpha
2354+
The proportion along the the path of the :class:`CurvesAsSubmobjects`.
2355+
2356+
Returns
2357+
-------
2358+
:class:`numpy.ndarray`
2359+
The point on the :class:`CurvesAsSubmobjects`.
2360+
2361+
Raises
2362+
------
2363+
:exc:`ValueError`
2364+
If ``alpha`` is not between 0 and 1.
2365+
:exc:`Exception`
2366+
If the :class:`CurvesAsSubmobjects` has no submobjects, or no submobject has points.
2367+
"""
2368+
if alpha < 0 or alpha > 1:
2369+
raise ValueError(f"Alpha {alpha} not between 0 and 1.")
2370+
2371+
self._throw_error_if_no_submobjects()
2372+
submobjs_with_pts = self._get_submobjects_with_points()
2373+
2374+
if alpha == 1:
2375+
return submobjs_with_pts[-1].points[-1]
2376+
2377+
submobjs_arc_lengths = tuple(
2378+
part.get_arc_length() for part in submobjs_with_pts
2379+
)
2380+
2381+
total_length = sum(submobjs_arc_lengths)
2382+
target_length = alpha * total_length
2383+
current_length = 0
2384+
2385+
for i, part in enumerate(submobjs_with_pts):
2386+
part_length = submobjs_arc_lengths[i]
2387+
if current_length + part_length >= target_length:
2388+
residue = (target_length - current_length) / part_length
2389+
return part.point_from_proportion(residue)
2390+
2391+
current_length += part_length
2392+
2393+
def _throw_error_if_no_submobjects(self):
2394+
if len(self.submobjects) == 0:
2395+
caller_name = sys._getframe(1).f_code.co_name
2396+
raise Exception(
2397+
f"Cannot call CurvesAsSubmobjects.{caller_name} for a CurvesAsSubmobject with no submobjects"
2398+
)
2399+
2400+
def _get_submobjects_with_points(self):
2401+
submobjs_with_pts = tuple(
2402+
part for part in self.submobjects if len(part.points) > 0
2403+
)
2404+
if len(submobjs_with_pts) == 0:
2405+
caller_name = sys._getframe(1).f_code.co_name
2406+
raise Exception(
2407+
f"Cannot call CurvesAsSubmobjects.{caller_name} for a CurvesAsSubmobject whose submobjects have no points"
2408+
)
2409+
return submobjs_with_pts
2410+
23482411

23492412
class DashedVMobject(VMobject, metaclass=ConvertToOpenGL):
23502413
"""A :class:`VMobject` composed of dashes instead of lines.

tests/module/mobject/types/vectorized_mobject/test_vectorized_mobject.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from manim import (
77
Circle,
8+
CurvesAsSubmobjects,
89
Line,
910
Mobject,
1011
Polygon,
@@ -41,6 +42,38 @@ def test_vmobject_point_from_propotion():
4142
obj.point_from_proportion(0)
4243

4344

45+
def test_curves_as_submobjects_point_from_proportion():
46+
obj = CurvesAsSubmobjects(VGroup())
47+
48+
with pytest.raises(ValueError, match="between 0 and 1"):
49+
obj.point_from_proportion(2)
50+
with pytest.raises(Exception, match="with no submobjects"):
51+
obj.point_from_proportion(0)
52+
53+
obj.add(VMobject())
54+
with pytest.raises(Exception, match="have no points"):
55+
obj.point_from_proportion(0)
56+
57+
# submobject[0] is a line of length 4
58+
obj.submobjects[0].set_points_as_corners(
59+
[
60+
np.array([0, 0, 0]),
61+
np.array([4, 0, 0]),
62+
],
63+
)
64+
obj.add(VMobject())
65+
# submobject[1] is a line of length 2
66+
obj.submobjects[1].set_points_as_corners(
67+
[
68+
np.array([4, 0, 0]),
69+
np.array([4, 2, 0]),
70+
],
71+
)
72+
73+
# point at proportion 0.5 should be at length 3, point [3, 0, 0]
74+
np.testing.assert_array_equal(obj.point_from_proportion(0.5), np.array([3, 0, 0]))
75+
76+
4477
def test_vgroup_init():
4578
"""Test the VGroup instantiation."""
4679
VGroup()

0 commit comments

Comments
 (0)