manim 0.18.0.post0__py3-none-any.whl → 0.18.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__init__.py +3 -6
- manim/__main__.py +18 -10
- manim/_config/__init__.py +5 -2
- manim/_config/cli_colors.py +12 -8
- manim/_config/default.cfg +1 -1
- manim/_config/logger_utils.py +9 -8
- manim/_config/utils.py +637 -449
- manim/animation/animation.py +9 -2
- manim/animation/composition.py +78 -40
- manim/animation/creation.py +12 -6
- manim/animation/fading.py +0 -1
- manim/animation/indication.py +10 -21
- manim/animation/movement.py +1 -2
- manim/animation/rotation.py +1 -1
- manim/animation/specialized.py +1 -1
- manim/animation/speedmodifier.py +7 -2
- manim/animation/transform_matching_parts.py +1 -1
- manim/camera/camera.py +13 -4
- manim/cli/cfg/group.py +18 -8
- manim/cli/checkhealth/checks.py +2 -0
- manim/cli/checkhealth/commands.py +2 -0
- manim/cli/default_group.py +13 -5
- manim/cli/init/commands.py +4 -1
- manim/cli/plugins/commands.py +3 -0
- manim/cli/render/commands.py +27 -20
- manim/cli/render/ease_of_access_options.py +4 -3
- manim/cli/render/global_options.py +9 -7
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +13 -13
- manim/constants.py +54 -15
- manim/gui/gui.py +2 -0
- manim/mobject/geometry/arc.py +4 -4
- manim/mobject/geometry/boolean_ops.py +13 -9
- manim/mobject/geometry/line.py +16 -8
- manim/mobject/geometry/polygram.py +17 -5
- manim/mobject/geometry/tips.py +2 -2
- manim/mobject/graph.py +379 -106
- manim/mobject/graphing/coordinate_systems.py +17 -20
- manim/mobject/graphing/functions.py +14 -10
- manim/mobject/graphing/number_line.py +1 -1
- manim/mobject/mobject.py +175 -72
- manim/mobject/opengl/opengl_compatibility.py +2 -0
- manim/mobject/opengl/opengl_geometry.py +26 -1
- manim/mobject/opengl/opengl_image_mobject.py +2 -0
- manim/mobject/opengl/opengl_mobject.py +3 -0
- manim/mobject/opengl/opengl_point_cloud_mobject.py +2 -0
- manim/mobject/opengl/opengl_surface.py +2 -0
- manim/mobject/opengl/opengl_three_dimensions.py +2 -0
- manim/mobject/opengl/opengl_vectorized_mobject.py +19 -14
- manim/mobject/svg/brace.py +2 -0
- manim/mobject/svg/svg_mobject.py +2 -2
- manim/mobject/table.py +0 -1
- manim/mobject/text/code_mobject.py +2 -0
- manim/mobject/text/numbers.py +2 -0
- manim/mobject/text/tex_mobject.py +1 -1
- manim/mobject/text/text_mobject.py +43 -6
- manim/mobject/three_d/three_d_utils.py +4 -4
- manim/mobject/three_d/three_dimensions.py +4 -4
- manim/mobject/types/image_mobject.py +5 -1
- manim/mobject/types/point_cloud_mobject.py +2 -0
- manim/mobject/types/vectorized_mobject.py +124 -29
- manim/mobject/value_tracker.py +3 -3
- manim/mobject/vector_field.py +3 -1
- manim/plugins/__init__.py +15 -1
- manim/plugins/plugins_flags.py +11 -5
- manim/renderer/cairo_renderer.py +12 -2
- manim/renderer/opengl_renderer.py +2 -3
- manim/renderer/opengl_renderer_window.py +2 -0
- manim/renderer/shader_wrapper.py +2 -0
- manim/renderer/vectorized_mobject_rendering.py +5 -0
- manim/scene/scene.py +22 -6
- manim/scene/scene_file_writer.py +3 -1
- manim/scene/section.py +2 -0
- manim/scene/three_d_scene.py +5 -6
- manim/scene/vector_space_scene.py +21 -5
- manim/typing.py +567 -67
- manim/utils/bezier.py +9 -18
- manim/utils/caching.py +2 -0
- manim/utils/color/BS381.py +1 -0
- manim/utils/color/XKCD.py +1 -0
- manim/utils/color/core.py +31 -13
- manim/utils/commands.py +8 -1
- manim/utils/debug.py +0 -1
- manim/utils/deprecation.py +3 -2
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +197 -0
- manim/utils/docbuild/autocolor_directive.py +9 -4
- manim/utils/docbuild/manim_directive.py +18 -9
- manim/utils/docbuild/module_parsing.py +198 -0
- manim/utils/exceptions.py +6 -0
- manim/utils/family.py +2 -0
- manim/utils/family_ops.py +5 -0
- manim/utils/file_ops.py +6 -2
- manim/utils/hashing.py +2 -0
- manim/utils/ipython_magic.py +2 -0
- manim/utils/module_ops.py +2 -0
- manim/utils/opengl.py +14 -0
- manim/utils/parameter_parsing.py +31 -0
- manim/utils/paths.py +12 -20
- manim/utils/rate_functions.py +6 -8
- manim/utils/space_ops.py +81 -36
- manim/utils/testing/__init__.py +17 -0
- manim/utils/testing/frames_comparison.py +7 -5
- manim/utils/tex.py +124 -196
- manim/utils/tex_file_writing.py +2 -0
- manim/utils/tex_templates.py +1 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/METADATA +29 -35
- manim-0.18.1.dist-info/RECORD +217 -0
- manim/cli/new/__init__.py +0 -0
- manim/cli/new/group.py +0 -189
- manim/plugins/import_plugins.py +0 -43
- manim-0.18.0.post0.dist-info/RECORD +0 -217
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/LICENSE +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/WHEEL +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/entry_points.txt +0 -0
manim/mobject/mobject.py
CHANGED
|
@@ -16,10 +16,9 @@ import types
|
|
|
16
16
|
import warnings
|
|
17
17
|
from functools import partialmethod, reduce
|
|
18
18
|
from pathlib import Path
|
|
19
|
-
from typing import TYPE_CHECKING, Callable, Iterable, Literal
|
|
19
|
+
from typing import TYPE_CHECKING, Callable, Iterable, Literal
|
|
20
20
|
|
|
21
21
|
import numpy as np
|
|
22
|
-
from typing_extensions import Self, TypeAlias
|
|
23
22
|
|
|
24
23
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
25
24
|
|
|
@@ -39,14 +38,9 @@ from ..utils.iterables import list_update, remove_list_redundancies
|
|
|
39
38
|
from ..utils.paths import straight_path
|
|
40
39
|
from ..utils.space_ops import angle_between_vectors, normalize, rotation_matrix
|
|
41
40
|
|
|
42
|
-
# TODO: Explain array_attrs
|
|
43
|
-
|
|
44
|
-
TimeBasedUpdater: TypeAlias = Callable[["Mobject", float], None]
|
|
45
|
-
NonTimeBasedUpdater: TypeAlias = Callable[["Mobject"], None]
|
|
46
|
-
Updater: TypeAlias = Union[NonTimeBasedUpdater, TimeBasedUpdater]
|
|
47
|
-
T = TypeVar("T", bound="Mobject")
|
|
48
|
-
|
|
49
41
|
if TYPE_CHECKING:
|
|
42
|
+
from typing_extensions import Self, TypeAlias
|
|
43
|
+
|
|
50
44
|
from manim.typing import (
|
|
51
45
|
FunctionOverride,
|
|
52
46
|
Image,
|
|
@@ -56,12 +50,15 @@ if TYPE_CHECKING:
|
|
|
56
50
|
PathFuncType,
|
|
57
51
|
Point3D,
|
|
58
52
|
Point3D_Array,
|
|
59
|
-
|
|
60
|
-
Vector3,
|
|
53
|
+
Vector3D,
|
|
61
54
|
)
|
|
62
55
|
|
|
63
56
|
from ..animation.animation import Animation
|
|
64
57
|
|
|
58
|
+
TimeBasedUpdater: TypeAlias = Callable[["Mobject", float], object]
|
|
59
|
+
NonTimeBasedUpdater: TypeAlias = Callable[["Mobject"], object]
|
|
60
|
+
Updater: TypeAlias = NonTimeBasedUpdater | TimeBasedUpdater
|
|
61
|
+
|
|
65
62
|
|
|
66
63
|
class Mobject:
|
|
67
64
|
"""Mathematical Object: base class for objects that can be displayed on screen.
|
|
@@ -238,7 +235,7 @@ class Mobject:
|
|
|
238
235
|
cls.__init__ = cls._original__init__
|
|
239
236
|
|
|
240
237
|
@property
|
|
241
|
-
def animate(self) -> _AnimationBuilder |
|
|
238
|
+
def animate(self) -> _AnimationBuilder | Self:
|
|
242
239
|
"""Used to animate the application of any method of :code:`self`.
|
|
243
240
|
|
|
244
241
|
Any method called on :code:`animate` is converted to an animation of applying
|
|
@@ -883,7 +880,7 @@ class Mobject:
|
|
|
883
880
|
|
|
884
881
|
Returns
|
|
885
882
|
-------
|
|
886
|
-
class:`bool`
|
|
883
|
+
:class:`bool`
|
|
887
884
|
``True`` if at least one updater uses the ``dt`` parameter, ``False``
|
|
888
885
|
otherwise.
|
|
889
886
|
|
|
@@ -968,11 +965,11 @@ class Mobject:
|
|
|
968
965
|
|
|
969
966
|
class DtUpdater(Scene):
|
|
970
967
|
def construct(self):
|
|
971
|
-
|
|
968
|
+
square = Square()
|
|
972
969
|
|
|
973
|
-
#Let the
|
|
974
|
-
|
|
975
|
-
self.add(
|
|
970
|
+
#Let the square rotate 90° per second
|
|
971
|
+
square.add_updater(lambda mobject, dt: mobject.rotate(dt*90*DEGREES))
|
|
972
|
+
self.add(square)
|
|
976
973
|
self.wait(2)
|
|
977
974
|
|
|
978
975
|
See also
|
|
@@ -1154,7 +1151,7 @@ class Mobject:
|
|
|
1154
1151
|
for mob in self.family_members_with_points():
|
|
1155
1152
|
func(mob)
|
|
1156
1153
|
|
|
1157
|
-
def shift(self, *vectors:
|
|
1154
|
+
def shift(self, *vectors: Vector3D) -> Self:
|
|
1158
1155
|
"""Shift by the given vectors.
|
|
1159
1156
|
|
|
1160
1157
|
Parameters
|
|
@@ -1226,14 +1223,14 @@ class Mobject:
|
|
|
1226
1223
|
)
|
|
1227
1224
|
return self
|
|
1228
1225
|
|
|
1229
|
-
def rotate_about_origin(self, angle: float, axis:
|
|
1226
|
+
def rotate_about_origin(self, angle: float, axis: Vector3D = OUT, axes=[]) -> Self:
|
|
1230
1227
|
"""Rotates the :class:`~.Mobject` about the ORIGIN, which is at [0,0,0]."""
|
|
1231
1228
|
return self.rotate(angle, axis, about_point=ORIGIN)
|
|
1232
1229
|
|
|
1233
1230
|
def rotate(
|
|
1234
1231
|
self,
|
|
1235
1232
|
angle: float,
|
|
1236
|
-
axis:
|
|
1233
|
+
axis: Vector3D = OUT,
|
|
1237
1234
|
about_point: Point3D | None = None,
|
|
1238
1235
|
**kwargs,
|
|
1239
1236
|
) -> Self:
|
|
@@ -1244,7 +1241,7 @@ class Mobject:
|
|
|
1244
1241
|
)
|
|
1245
1242
|
return self
|
|
1246
1243
|
|
|
1247
|
-
def flip(self, axis:
|
|
1244
|
+
def flip(self, axis: Vector3D = UP, **kwargs) -> Self:
|
|
1248
1245
|
"""Flips/Mirrors an mobject about its center.
|
|
1249
1246
|
|
|
1250
1247
|
Examples
|
|
@@ -1337,20 +1334,6 @@ class Mobject:
|
|
|
1337
1334
|
|
|
1338
1335
|
return self.apply_function(R3_func)
|
|
1339
1336
|
|
|
1340
|
-
def wag(
|
|
1341
|
-
self, direction: Vector3 = RIGHT, axis: Vector3 = DOWN, wag_factor: float = 1.0
|
|
1342
|
-
) -> Self:
|
|
1343
|
-
for mob in self.family_members_with_points():
|
|
1344
|
-
alphas = np.dot(mob.points, np.transpose(axis))
|
|
1345
|
-
alphas -= min(alphas)
|
|
1346
|
-
alphas /= max(alphas)
|
|
1347
|
-
alphas = alphas**wag_factor
|
|
1348
|
-
mob.points += np.dot(
|
|
1349
|
-
alphas.reshape((len(alphas), 1)),
|
|
1350
|
-
np.array(direction).reshape((1, mob.dim)),
|
|
1351
|
-
)
|
|
1352
|
-
return self
|
|
1353
|
-
|
|
1354
1337
|
def reverse_points(self) -> Self:
|
|
1355
1338
|
for mob in self.family_members_with_points():
|
|
1356
1339
|
mob.apply_over_attr_arrays(lambda arr: np.array(list(reversed(arr))))
|
|
@@ -1404,7 +1387,7 @@ class Mobject:
|
|
|
1404
1387
|
return self
|
|
1405
1388
|
|
|
1406
1389
|
def align_on_border(
|
|
1407
|
-
self, direction:
|
|
1390
|
+
self, direction: Vector3D, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
|
|
1408
1391
|
) -> Self:
|
|
1409
1392
|
"""Direction just needs to be a vector pointing towards side or
|
|
1410
1393
|
corner in the 2d plane.
|
|
@@ -1421,24 +1404,72 @@ class Mobject:
|
|
|
1421
1404
|
return self
|
|
1422
1405
|
|
|
1423
1406
|
def to_corner(
|
|
1424
|
-
self, corner:
|
|
1407
|
+
self, corner: Vector3D = DL, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
|
|
1425
1408
|
) -> Self:
|
|
1409
|
+
"""Moves this :class:`~.Mobject` to the given corner of the screen.
|
|
1410
|
+
|
|
1411
|
+
Returns
|
|
1412
|
+
-------
|
|
1413
|
+
:class:`.Mobject`
|
|
1414
|
+
The newly positioned mobject.
|
|
1415
|
+
|
|
1416
|
+
Examples
|
|
1417
|
+
--------
|
|
1418
|
+
|
|
1419
|
+
.. manim:: ToCornerExample
|
|
1420
|
+
:save_last_frame:
|
|
1421
|
+
|
|
1422
|
+
class ToCornerExample(Scene):
|
|
1423
|
+
def construct(self):
|
|
1424
|
+
c = Circle()
|
|
1425
|
+
c.to_corner(UR)
|
|
1426
|
+
t = Tex("To the corner!")
|
|
1427
|
+
t2 = MathTex("x^3").shift(DOWN)
|
|
1428
|
+
self.add(c,t,t2)
|
|
1429
|
+
t.to_corner(DL, buff=0)
|
|
1430
|
+
t2.to_corner(UL, buff=1.5)
|
|
1431
|
+
"""
|
|
1426
1432
|
return self.align_on_border(corner, buff)
|
|
1427
1433
|
|
|
1428
1434
|
def to_edge(
|
|
1429
|
-
self, edge:
|
|
1435
|
+
self, edge: Vector3D = LEFT, buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER
|
|
1430
1436
|
) -> Self:
|
|
1437
|
+
"""Moves this :class:`~.Mobject` to the given edge of the screen,
|
|
1438
|
+
without affecting its position in the other dimension.
|
|
1439
|
+
|
|
1440
|
+
Returns
|
|
1441
|
+
-------
|
|
1442
|
+
:class:`.Mobject`
|
|
1443
|
+
The newly positioned mobject.
|
|
1444
|
+
|
|
1445
|
+
Examples
|
|
1446
|
+
--------
|
|
1447
|
+
|
|
1448
|
+
.. manim:: ToEdgeExample
|
|
1449
|
+
:save_last_frame:
|
|
1450
|
+
|
|
1451
|
+
class ToEdgeExample(Scene):
|
|
1452
|
+
def construct(self):
|
|
1453
|
+
tex_top = Tex("I am at the top!")
|
|
1454
|
+
tex_top.to_edge(UP)
|
|
1455
|
+
tex_side = Tex("I am moving to the side!")
|
|
1456
|
+
c = Circle().shift(2*DOWN)
|
|
1457
|
+
self.add(tex_top, tex_side)
|
|
1458
|
+
tex_side.to_edge(LEFT)
|
|
1459
|
+
c.to_edge(RIGHT, buff=0)
|
|
1460
|
+
|
|
1461
|
+
"""
|
|
1431
1462
|
return self.align_on_border(edge, buff)
|
|
1432
1463
|
|
|
1433
1464
|
def next_to(
|
|
1434
1465
|
self,
|
|
1435
1466
|
mobject_or_point: Mobject | Point3D,
|
|
1436
|
-
direction:
|
|
1467
|
+
direction: Vector3D = RIGHT,
|
|
1437
1468
|
buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
1438
|
-
aligned_edge:
|
|
1469
|
+
aligned_edge: Vector3D = ORIGIN,
|
|
1439
1470
|
submobject_to_align: Mobject | None = None,
|
|
1440
1471
|
index_of_submobject_to_align: int | None = None,
|
|
1441
|
-
coor_mask:
|
|
1472
|
+
coor_mask: Vector3D = np.array([1, 1, 1]),
|
|
1442
1473
|
) -> Self:
|
|
1443
1474
|
"""Move this :class:`~.Mobject` next to another's :class:`~.Mobject` or Point3D.
|
|
1444
1475
|
|
|
@@ -1630,22 +1661,22 @@ class Mobject:
|
|
|
1630
1661
|
|
|
1631
1662
|
return self.rescale_to_fit(depth, 2, stretch=True, **kwargs)
|
|
1632
1663
|
|
|
1633
|
-
def set_coord(self, value, dim: int, direction:
|
|
1664
|
+
def set_coord(self, value, dim: int, direction: Vector3D = ORIGIN) -> Self:
|
|
1634
1665
|
curr = self.get_coord(dim, direction)
|
|
1635
1666
|
shift_vect = np.zeros(self.dim)
|
|
1636
1667
|
shift_vect[dim] = value - curr
|
|
1637
1668
|
self.shift(shift_vect)
|
|
1638
1669
|
return self
|
|
1639
1670
|
|
|
1640
|
-
def set_x(self, x: float, direction:
|
|
1671
|
+
def set_x(self, x: float, direction: Vector3D = ORIGIN) -> Self:
|
|
1641
1672
|
"""Set x value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
|
|
1642
1673
|
return self.set_coord(x, 0, direction)
|
|
1643
1674
|
|
|
1644
|
-
def set_y(self, y: float, direction:
|
|
1675
|
+
def set_y(self, y: float, direction: Vector3D = ORIGIN) -> Self:
|
|
1645
1676
|
"""Set y value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
|
|
1646
1677
|
return self.set_coord(y, 1, direction)
|
|
1647
1678
|
|
|
1648
|
-
def set_z(self, z: float, direction:
|
|
1679
|
+
def set_z(self, z: float, direction: Vector3D = ORIGIN) -> Self:
|
|
1649
1680
|
"""Set z value of the center of the :class:`~.Mobject` (``int`` or ``float``)"""
|
|
1650
1681
|
return self.set_coord(z, 2, direction)
|
|
1651
1682
|
|
|
@@ -1658,8 +1689,8 @@ class Mobject:
|
|
|
1658
1689
|
def move_to(
|
|
1659
1690
|
self,
|
|
1660
1691
|
point_or_mobject: Point3D | Mobject,
|
|
1661
|
-
aligned_edge:
|
|
1662
|
-
coor_mask:
|
|
1692
|
+
aligned_edge: Vector3D = ORIGIN,
|
|
1693
|
+
coor_mask: Vector3D = np.array([1, 1, 1]),
|
|
1663
1694
|
) -> Self:
|
|
1664
1695
|
"""Move center of the :class:`~.Mobject` to certain Point3D."""
|
|
1665
1696
|
if isinstance(point_or_mobject, Mobject):
|
|
@@ -1703,7 +1734,8 @@ class Mobject:
|
|
|
1703
1734
|
curr_start, curr_end = self.get_start_and_end()
|
|
1704
1735
|
curr_vect = curr_end - curr_start
|
|
1705
1736
|
if np.all(curr_vect == 0):
|
|
1706
|
-
|
|
1737
|
+
self.points = start
|
|
1738
|
+
return self
|
|
1707
1739
|
target_vect = np.array(end) - np.array(start)
|
|
1708
1740
|
axis = (
|
|
1709
1741
|
normalize(np.cross(curr_vect, target_vect))
|
|
@@ -1872,7 +1904,17 @@ class Mobject:
|
|
|
1872
1904
|
return self
|
|
1873
1905
|
|
|
1874
1906
|
def get_color(self) -> ManimColor:
|
|
1875
|
-
"""Returns the color of the :class:`~.Mobject`
|
|
1907
|
+
"""Returns the color of the :class:`~.Mobject`
|
|
1908
|
+
|
|
1909
|
+
Examples
|
|
1910
|
+
--------
|
|
1911
|
+
::
|
|
1912
|
+
|
|
1913
|
+
>>> from manim import Square, RED
|
|
1914
|
+
>>> Square(color=RED).get_color() == RED
|
|
1915
|
+
True
|
|
1916
|
+
|
|
1917
|
+
"""
|
|
1876
1918
|
return self.color
|
|
1877
1919
|
|
|
1878
1920
|
##
|
|
@@ -1964,7 +2006,7 @@ class Mobject:
|
|
|
1964
2006
|
else:
|
|
1965
2007
|
return np.max(values)
|
|
1966
2008
|
|
|
1967
|
-
def get_critical_point(self, direction:
|
|
2009
|
+
def get_critical_point(self, direction: Vector3D) -> Point3D:
|
|
1968
2010
|
"""Picture a box bounding the :class:`~.Mobject`. Such a box has
|
|
1969
2011
|
9 'critical points': 4 corners, 4 edge center, the
|
|
1970
2012
|
center. This returns one of them, along the given direction.
|
|
@@ -1993,11 +2035,11 @@ class Mobject:
|
|
|
1993
2035
|
|
|
1994
2036
|
# Pseudonyms for more general get_critical_point method
|
|
1995
2037
|
|
|
1996
|
-
def get_edge_center(self, direction:
|
|
2038
|
+
def get_edge_center(self, direction: Vector3D) -> Point3D:
|
|
1997
2039
|
"""Get edge Point3Ds for certain direction."""
|
|
1998
2040
|
return self.get_critical_point(direction)
|
|
1999
2041
|
|
|
2000
|
-
def get_corner(self, direction:
|
|
2042
|
+
def get_corner(self, direction: Vector3D) -> Point3D:
|
|
2001
2043
|
"""Get corner Point3Ds for certain direction."""
|
|
2002
2044
|
return self.get_critical_point(direction)
|
|
2003
2045
|
|
|
@@ -2008,7 +2050,7 @@ class Mobject:
|
|
|
2008
2050
|
def get_center_of_mass(self) -> Point3D:
|
|
2009
2051
|
return np.apply_along_axis(np.mean, 0, self.get_all_points())
|
|
2010
2052
|
|
|
2011
|
-
def get_boundary_point(self, direction:
|
|
2053
|
+
def get_boundary_point(self, direction: Vector3D) -> Point3D:
|
|
2012
2054
|
all_points = self.get_points_defining_boundary()
|
|
2013
2055
|
index = np.argmax(np.dot(all_points, np.array(direction).T))
|
|
2014
2056
|
return all_points[index]
|
|
@@ -2067,19 +2109,19 @@ class Mobject:
|
|
|
2067
2109
|
dim,
|
|
2068
2110
|
) - self.reduce_across_dimension(min, dim)
|
|
2069
2111
|
|
|
2070
|
-
def get_coord(self, dim: int, direction:
|
|
2112
|
+
def get_coord(self, dim: int, direction: Vector3D = ORIGIN):
|
|
2071
2113
|
"""Meant to generalize ``get_x``, ``get_y`` and ``get_z``"""
|
|
2072
2114
|
return self.get_extremum_along_dim(dim=dim, key=direction[dim])
|
|
2073
2115
|
|
|
2074
|
-
def get_x(self, direction:
|
|
2116
|
+
def get_x(self, direction: Vector3D = ORIGIN) -> ManimFloat:
|
|
2075
2117
|
"""Returns x Point3D of the center of the :class:`~.Mobject` as ``float``"""
|
|
2076
2118
|
return self.get_coord(0, direction)
|
|
2077
2119
|
|
|
2078
|
-
def get_y(self, direction:
|
|
2120
|
+
def get_y(self, direction: Vector3D = ORIGIN) -> ManimFloat:
|
|
2079
2121
|
"""Returns y Point3D of the center of the :class:`~.Mobject` as ``float``"""
|
|
2080
2122
|
return self.get_coord(1, direction)
|
|
2081
2123
|
|
|
2082
|
-
def get_z(self, direction:
|
|
2124
|
+
def get_z(self, direction: Vector3D = ORIGIN) -> ManimFloat:
|
|
2083
2125
|
"""Returns z Point3D of the center of the :class:`~.Mobject` as ``float``"""
|
|
2084
2126
|
return self.get_coord(2, direction)
|
|
2085
2127
|
|
|
@@ -2150,7 +2192,7 @@ class Mobject:
|
|
|
2150
2192
|
return self.match_dim_size(mobject, 2, **kwargs)
|
|
2151
2193
|
|
|
2152
2194
|
def match_coord(
|
|
2153
|
-
self, mobject: Mobject, dim: int, direction:
|
|
2195
|
+
self, mobject: Mobject, dim: int, direction: Vector3D = ORIGIN
|
|
2154
2196
|
) -> Self:
|
|
2155
2197
|
"""Match the Point3Ds with the Point3Ds of another :class:`~.Mobject`."""
|
|
2156
2198
|
return self.set_coord(
|
|
@@ -2174,7 +2216,7 @@ class Mobject:
|
|
|
2174
2216
|
def align_to(
|
|
2175
2217
|
self,
|
|
2176
2218
|
mobject_or_point: Mobject | Point3D,
|
|
2177
|
-
direction:
|
|
2219
|
+
direction: Vector3D = ORIGIN,
|
|
2178
2220
|
) -> Self:
|
|
2179
2221
|
"""Aligns mobject to another :class:`~.Mobject` in a certain direction.
|
|
2180
2222
|
|
|
@@ -2229,7 +2271,7 @@ class Mobject:
|
|
|
2229
2271
|
|
|
2230
2272
|
def arrange(
|
|
2231
2273
|
self,
|
|
2232
|
-
direction:
|
|
2274
|
+
direction: Vector3D = RIGHT,
|
|
2233
2275
|
buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
2234
2276
|
center: bool = True,
|
|
2235
2277
|
**kwargs,
|
|
@@ -2262,7 +2304,7 @@ class Mobject:
|
|
|
2262
2304
|
rows: int | None = None,
|
|
2263
2305
|
cols: int | None = None,
|
|
2264
2306
|
buff: float | tuple[float, float] = MED_SMALL_BUFF,
|
|
2265
|
-
cell_alignment:
|
|
2307
|
+
cell_alignment: Vector3D = ORIGIN,
|
|
2266
2308
|
row_alignments: str | None = None, # "ucd"
|
|
2267
2309
|
col_alignments: str | None = None, # "lcr"
|
|
2268
2310
|
row_heights: Iterable[float | None] | None = None,
|
|
@@ -2667,13 +2709,13 @@ class Mobject:
|
|
|
2667
2709
|
|
|
2668
2710
|
def add_n_more_submobjects(self, n: int) -> Self | None:
|
|
2669
2711
|
if n == 0:
|
|
2670
|
-
return
|
|
2712
|
+
return None
|
|
2671
2713
|
|
|
2672
2714
|
curr = len(self.submobjects)
|
|
2673
2715
|
if curr == 0:
|
|
2674
2716
|
# If empty, simply add n point mobjects
|
|
2675
2717
|
self.submobjects = [self.get_point_mobject() for k in range(n)]
|
|
2676
|
-
return
|
|
2718
|
+
return None
|
|
2677
2719
|
|
|
2678
2720
|
target = curr + n
|
|
2679
2721
|
# TODO, factor this out to utils so as to reuse
|
|
@@ -2728,7 +2770,6 @@ class Mobject:
|
|
|
2728
2770
|
def become(
|
|
2729
2771
|
self,
|
|
2730
2772
|
mobject: Mobject,
|
|
2731
|
-
copy_submobjects: bool = True,
|
|
2732
2773
|
match_height: bool = False,
|
|
2733
2774
|
match_width: bool = False,
|
|
2734
2775
|
match_depth: bool = False,
|
|
@@ -2741,20 +2782,25 @@ class Mobject:
|
|
|
2741
2782
|
.. note::
|
|
2742
2783
|
|
|
2743
2784
|
If both match_height and match_width are ``True`` then the transformed :class:`~.Mobject`
|
|
2744
|
-
will match the height first and then the width
|
|
2785
|
+
will match the height first and then the width.
|
|
2745
2786
|
|
|
2746
2787
|
Parameters
|
|
2747
2788
|
----------
|
|
2748
2789
|
match_height
|
|
2749
|
-
|
|
2790
|
+
Whether or not to preserve the height of the original
|
|
2791
|
+
:class:`~.Mobject`.
|
|
2750
2792
|
match_width
|
|
2751
|
-
|
|
2793
|
+
Whether or not to preserve the width of the original
|
|
2794
|
+
:class:`~.Mobject`.
|
|
2752
2795
|
match_depth
|
|
2753
|
-
|
|
2796
|
+
Whether or not to preserve the depth of the original
|
|
2797
|
+
:class:`~.Mobject`.
|
|
2754
2798
|
match_center
|
|
2755
|
-
|
|
2799
|
+
Whether or not to preserve the center of the original
|
|
2800
|
+
:class:`~.Mobject`.
|
|
2756
2801
|
stretch
|
|
2757
|
-
|
|
2802
|
+
Whether or not to stretch the target mobject to match the
|
|
2803
|
+
the proportions of the original :class:`~.Mobject`.
|
|
2758
2804
|
|
|
2759
2805
|
Examples
|
|
2760
2806
|
--------
|
|
@@ -2768,8 +2814,65 @@ class Mobject:
|
|
|
2768
2814
|
self.wait(0.5)
|
|
2769
2815
|
circ.become(square)
|
|
2770
2816
|
self.wait(0.5)
|
|
2771
|
-
"""
|
|
2772
2817
|
|
|
2818
|
+
|
|
2819
|
+
The following examples illustrate how mobject measurements
|
|
2820
|
+
change when using the ``match_...`` and ``stretch`` arguments.
|
|
2821
|
+
We start with a rectangle that is 2 units high and 4 units wide,
|
|
2822
|
+
which we want to turn into a circle of radius 3::
|
|
2823
|
+
|
|
2824
|
+
>>> from manim import Rectangle, Circle
|
|
2825
|
+
>>> import numpy as np
|
|
2826
|
+
>>> rect = Rectangle(height=2, width=4)
|
|
2827
|
+
>>> circ = Circle(radius=3)
|
|
2828
|
+
|
|
2829
|
+
With ``stretch=True``, the target circle is deformed to match
|
|
2830
|
+
the proportions of the rectangle, which results in the target
|
|
2831
|
+
mobject being an ellipse with height 2 and width 4. We can
|
|
2832
|
+
check that the resulting points satisfy the ellipse equation
|
|
2833
|
+
:math:`x^2/a^2 + y^2/b^2 = 1` with :math:`a = 4/2` and :math:`b = 2/2`
|
|
2834
|
+
being the semi-axes::
|
|
2835
|
+
|
|
2836
|
+
>>> result = rect.copy().become(circ, stretch=True)
|
|
2837
|
+
>>> result.height, result.width
|
|
2838
|
+
(2.0, 4.0)
|
|
2839
|
+
>>> ellipse_points = np.array(result.get_anchors())
|
|
2840
|
+
>>> ellipse_eq = np.sum(ellipse_points**2 * [1/4, 1, 0], axis=1)
|
|
2841
|
+
>>> np.allclose(ellipse_eq, 1)
|
|
2842
|
+
True
|
|
2843
|
+
|
|
2844
|
+
With ``match_height=True`` and ``match_width=True`` the circle is
|
|
2845
|
+
scaled such that the height or the width of the rectangle will
|
|
2846
|
+
be preserved, respectively.
|
|
2847
|
+
The points of the resulting mobject satisfy the circle equation
|
|
2848
|
+
:math:`x^2 + y^2 = r^2` for the corresponding radius :math:`r`::
|
|
2849
|
+
|
|
2850
|
+
>>> result = rect.copy().become(circ, match_height=True)
|
|
2851
|
+
>>> result.height, result.width
|
|
2852
|
+
(2.0, 2.0)
|
|
2853
|
+
>>> circle_points = np.array(result.get_anchors())
|
|
2854
|
+
>>> circle_eq = np.sum(circle_points**2, axis=1)
|
|
2855
|
+
>>> np.allclose(circle_eq, 1)
|
|
2856
|
+
True
|
|
2857
|
+
>>> result = rect.copy().become(circ, match_width=True)
|
|
2858
|
+
>>> result.height, result.width
|
|
2859
|
+
(4.0, 4.0)
|
|
2860
|
+
>>> circle_points = np.array(result.get_anchors())
|
|
2861
|
+
>>> circle_eq = np.sum(circle_points**2, axis=1)
|
|
2862
|
+
>>> np.allclose(circle_eq, 2**2)
|
|
2863
|
+
True
|
|
2864
|
+
|
|
2865
|
+
With ``match_center=True``, the resulting mobject is moved such that
|
|
2866
|
+
its center is the same as the center of the original mobject::
|
|
2867
|
+
|
|
2868
|
+
>>> rect = rect.shift(np.array([0, 1, 0]))
|
|
2869
|
+
>>> np.allclose(rect.get_center(), circ.get_center())
|
|
2870
|
+
False
|
|
2871
|
+
>>> result = rect.copy().become(circ, match_center=True)
|
|
2872
|
+
>>> np.allclose(rect.get_center(), result.get_center())
|
|
2873
|
+
True
|
|
2874
|
+
"""
|
|
2875
|
+
mobject = mobject.copy()
|
|
2773
2876
|
if stretch:
|
|
2774
2877
|
mobject.stretch_to_fit_height(self.height)
|
|
2775
2878
|
mobject.stretch_to_fit_width(self.width)
|
|
@@ -2825,7 +2928,7 @@ class Mobject:
|
|
|
2825
2928
|
self,
|
|
2826
2929
|
z_index_value: float,
|
|
2827
2930
|
family: bool = True,
|
|
2828
|
-
) ->
|
|
2931
|
+
) -> Self:
|
|
2829
2932
|
"""Sets the :class:`~.Mobject`'s :attr:`z_index` to the value specified in `z_index_value`.
|
|
2830
2933
|
|
|
2831
2934
|
Parameters
|
|
@@ -10,6 +10,8 @@ from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
|
|
|
10
10
|
|
|
11
11
|
from ...constants import RendererType
|
|
12
12
|
|
|
13
|
+
__all__ = ["ConvertToOpenGL"]
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
class ConvertToOpenGL(ABCMeta):
|
|
15
17
|
"""Metaclass for swapping (V)Mobject with its OpenGL counterpart at runtime
|
|
@@ -23,11 +23,36 @@ from manim.utils.space_ops import (
|
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
DEFAULT_DOT_RADIUS = 0.08
|
|
26
|
-
DEFAULT_SMALL_DOT_RADIUS = 0.04
|
|
27
26
|
DEFAULT_DASH_LENGTH = 0.05
|
|
28
27
|
DEFAULT_ARROW_TIP_LENGTH = 0.35
|
|
29
28
|
DEFAULT_ARROW_TIP_WIDTH = 0.35
|
|
30
29
|
|
|
30
|
+
__all__ = [
|
|
31
|
+
"OpenGLTipableVMobject",
|
|
32
|
+
"OpenGLArc",
|
|
33
|
+
"OpenGLArcBetweenPoints",
|
|
34
|
+
"OpenGLCurvedArrow",
|
|
35
|
+
"OpenGLCurvedDoubleArrow",
|
|
36
|
+
"OpenGLCircle",
|
|
37
|
+
"OpenGLDot",
|
|
38
|
+
"OpenGLEllipse",
|
|
39
|
+
"OpenGLAnnularSector",
|
|
40
|
+
"OpenGLSector",
|
|
41
|
+
"OpenGLAnnulus",
|
|
42
|
+
"OpenGLLine",
|
|
43
|
+
"OpenGLDashedLine",
|
|
44
|
+
"OpenGLTangentLine",
|
|
45
|
+
"OpenGLElbow",
|
|
46
|
+
"OpenGLArrow",
|
|
47
|
+
"OpenGLVector",
|
|
48
|
+
"OpenGLDoubleArrow",
|
|
49
|
+
"OpenGLCubicBezier",
|
|
50
|
+
"OpenGLPolygon",
|
|
51
|
+
"OpenGLRegularPolygon",
|
|
52
|
+
"OpenGLTriangle",
|
|
53
|
+
"OpenGLArrowTip",
|
|
54
|
+
]
|
|
55
|
+
|
|
31
56
|
|
|
32
57
|
class OpenGLTipableVMobject(OpenGLVMobject):
|
|
33
58
|
"""
|
|
@@ -13,6 +13,8 @@ from PIL.Image import Resampling
|
|
|
13
13
|
from manim.mobject.opengl.opengl_surface import OpenGLSurface, OpenGLTexturedSurface
|
|
14
14
|
from manim.utils.images import get_full_raster_image_path
|
|
15
15
|
|
|
16
|
+
__all__ = ["OpenGLImageMobject"]
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
class OpenGLImageMobject(OpenGLTexturedSurface):
|
|
18
20
|
def __init__(
|
|
@@ -12,6 +12,8 @@ from manim.utils.color import BLACK, WHITE, YELLOW, color_gradient, color_to_rgb
|
|
|
12
12
|
from manim.utils.config_ops import _Uniforms
|
|
13
13
|
from manim.utils.iterables import resize_with_interpolation
|
|
14
14
|
|
|
15
|
+
__all__ = ["OpenGLPMobject", "OpenGLPGroup", "OpenGLPMPoint"]
|
|
16
|
+
|
|
15
17
|
|
|
16
18
|
class OpenGLPMobject(OpenGLMobject):
|
|
17
19
|
shader_folder = "true_dot"
|
|
@@ -17,6 +17,8 @@ from manim.utils.images import change_to_rgba_array, get_full_raster_image_path
|
|
|
17
17
|
from manim.utils.iterables import listify
|
|
18
18
|
from manim.utils.space_ops import normalize_along_axis
|
|
19
19
|
|
|
20
|
+
__all__ = ["OpenGLSurface", "OpenGLTexturedSurface"]
|
|
21
|
+
|
|
20
22
|
|
|
21
23
|
class OpenGLSurface(OpenGLMobject):
|
|
22
24
|
r"""Creates a Surface.
|
|
@@ -5,6 +5,8 @@ import numpy as np
|
|
|
5
5
|
from manim.mobject.opengl.opengl_surface import OpenGLSurface
|
|
6
6
|
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup, OpenGLVMobject
|
|
7
7
|
|
|
8
|
+
__all__ = ["OpenGLSurfaceMesh"]
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
class OpenGLSurfaceMesh(OpenGLVGroup):
|
|
10
12
|
def __init__(
|
|
@@ -34,6 +34,15 @@ from manim.utils.space_ops import (
|
|
|
34
34
|
z_to_vector,
|
|
35
35
|
)
|
|
36
36
|
|
|
37
|
+
__all__ = [
|
|
38
|
+
"triggers_refreshed_triangulation",
|
|
39
|
+
"OpenGLVMobject",
|
|
40
|
+
"OpenGLVGroup",
|
|
41
|
+
"OpenGLVectorizedPoint",
|
|
42
|
+
"OpenGLCurvesAsSubmobjects",
|
|
43
|
+
"OpenGLDashedVMobject",
|
|
44
|
+
]
|
|
45
|
+
|
|
37
46
|
|
|
38
47
|
def triggers_refreshed_triangulation(func):
|
|
39
48
|
@wraps(func)
|
|
@@ -944,7 +953,9 @@ class OpenGLVMobject(OpenGLMobject):
|
|
|
944
953
|
|
|
945
954
|
curves_and_lengths = tuple(self.get_curve_functions_with_lengths())
|
|
946
955
|
|
|
947
|
-
target_length = alpha * np.sum(
|
|
956
|
+
target_length = alpha * np.sum(
|
|
957
|
+
np.fromiter((length for _, length in curves_and_lengths), dtype=np.float64)
|
|
958
|
+
)
|
|
948
959
|
current_length = 0
|
|
949
960
|
|
|
950
961
|
for curve, length in curves_and_lengths:
|
|
@@ -1014,7 +1025,7 @@ class OpenGLVMobject(OpenGLMobject):
|
|
|
1014
1025
|
|
|
1015
1026
|
return alpha
|
|
1016
1027
|
|
|
1017
|
-
def get_anchors_and_handles(self):
|
|
1028
|
+
def get_anchors_and_handles(self) -> Iterable[np.ndarray]:
|
|
1018
1029
|
"""
|
|
1019
1030
|
Returns anchors1, handles, anchors2,
|
|
1020
1031
|
where (anchors1[i], handles[i], anchors2[i])
|
|
@@ -1046,27 +1057,21 @@ class OpenGLVMobject(OpenGLMobject):
|
|
|
1046
1057
|
nppc = self.n_points_per_curve
|
|
1047
1058
|
return self.points[nppc - 1 :: nppc]
|
|
1048
1059
|
|
|
1049
|
-
def get_anchors(self) -> np.ndarray:
|
|
1060
|
+
def get_anchors(self) -> Iterable[np.ndarray]:
|
|
1050
1061
|
"""Returns the anchors of the curves forming the OpenGLVMobject.
|
|
1051
1062
|
|
|
1052
1063
|
Returns
|
|
1053
1064
|
-------
|
|
1054
|
-
np.ndarray
|
|
1065
|
+
Iterable[np.ndarray]
|
|
1055
1066
|
The anchors.
|
|
1056
1067
|
"""
|
|
1057
1068
|
points = self.points
|
|
1058
1069
|
if len(points) == 1:
|
|
1059
1070
|
return points
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
self.get_start_anchors(),
|
|
1065
|
-
self.get_end_anchors(),
|
|
1066
|
-
)
|
|
1067
|
-
),
|
|
1068
|
-
),
|
|
1069
|
-
)
|
|
1071
|
+
|
|
1072
|
+
s = self.get_start_anchors()
|
|
1073
|
+
e = self.get_end_anchors()
|
|
1074
|
+
return list(it.chain.from_iterable(zip(s, e)))
|
|
1070
1075
|
|
|
1071
1076
|
def get_points_without_null_curves(self, atol=1e-9):
|
|
1072
1077
|
nppc = self.n_points_per_curve
|
manim/mobject/svg/brace.py
CHANGED
|
@@ -24,6 +24,8 @@ from ...mobject.types.vectorized_mobject import VMobject
|
|
|
24
24
|
from ...utils.color import BLACK
|
|
25
25
|
from ..svg.svg_mobject import VMobjectFromSVGPath
|
|
26
26
|
|
|
27
|
+
__all__ = ["Brace", "BraceBetweenPoints", "BraceLabel", "ArcBrace"]
|
|
28
|
+
|
|
27
29
|
|
|
28
30
|
class Brace(VMobjectFromSVGPath):
|
|
29
31
|
"""Takes a mobject and draws a brace adjacent to it.
|