manim 0.18.1__py3-none-any.whl → 0.19.0__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/__main__.py +45 -12
- manim/_config/__init__.py +2 -2
- manim/_config/cli_colors.py +8 -4
- manim/_config/default.cfg +0 -2
- manim/_config/logger_utils.py +5 -0
- manim/_config/utils.py +29 -38
- manim/animation/animation.py +148 -8
- manim/animation/composition.py +16 -13
- manim/animation/creation.py +184 -8
- manim/animation/fading.py +5 -8
- manim/animation/indication.py +93 -26
- manim/animation/movement.py +21 -3
- manim/animation/rotation.py +2 -1
- manim/animation/specialized.py +3 -5
- manim/animation/speedmodifier.py +3 -3
- manim/animation/transform.py +4 -5
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +2 -2
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +52 -36
- manim/cli/checkhealth/checks.py +92 -76
- manim/cli/checkhealth/commands.py +12 -5
- manim/cli/default_group.py +148 -24
- manim/cli/init/commands.py +28 -23
- manim/cli/plugins/commands.py +13 -3
- manim/cli/render/commands.py +47 -42
- manim/cli/render/global_options.py +43 -9
- manim/cli/render/render_options.py +84 -19
- manim/constants.py +11 -4
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +109 -75
- manim/mobject/geometry/boolean_ops.py +20 -17
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +120 -60
- manim/mobject/geometry/polygram.py +109 -25
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +36 -27
- manim/mobject/graph.py +48 -40
- manim/mobject/graphing/coordinate_systems.py +110 -45
- manim/mobject/graphing/functions.py +16 -10
- manim/mobject/graphing/number_line.py +23 -9
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +149 -103
- manim/mobject/opengl/opengl_geometry.py +4 -8
- manim/mobject/opengl/opengl_mobject.py +506 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
- manim/mobject/opengl/opengl_surface.py +1 -2
- manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
- manim/mobject/svg/brace.py +61 -13
- manim/mobject/svg/svg_mobject.py +2 -1
- manim/mobject/table.py +11 -12
- manim/mobject/text/code_mobject.py +186 -550
- manim/mobject/text/numbers.py +7 -7
- manim/mobject/text/tex_mobject.py +22 -13
- manim/mobject/text/text_mobject.py +29 -20
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_dimensions.py +59 -31
- manim/mobject/types/image_mobject.py +37 -23
- manim/mobject/types/point_cloud_mobject.py +103 -67
- manim/mobject/types/vectorized_mobject.py +387 -214
- manim/mobject/value_tracker.py +2 -1
- manim/mobject/vector_field.py +2 -4
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +2 -3
- manim/plugins/plugins_flags.py +3 -3
- manim/renderer/cairo_renderer.py +11 -11
- manim/renderer/opengl_renderer.py +19 -20
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +3 -2
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +72 -41
- manim/scene/scene_file_writer.py +313 -164
- manim/scene/section.py +15 -15
- manim/scene/three_d_scene.py +8 -15
- manim/scene/vector_space_scene.py +3 -6
- manim/typing.py +326 -66
- manim/utils/bezier.py +1658 -381
- manim/utils/caching.py +11 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +2 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +3 -0
- manim/utils/color/XKCD.py +2 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +818 -301
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +40 -19
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -6
- manim/utils/deprecation.py +92 -43
- manim/utils/docbuild/autoaliasattr_directive.py +45 -8
- manim/utils/docbuild/autocolor_directive.py +12 -13
- manim/utils/docbuild/manim_directive.py +35 -29
- manim/utils/docbuild/module_parsing.py +74 -27
- manim/utils/family.py +3 -3
- manim/utils/family_ops.py +12 -4
- manim/utils/file_ops.py +22 -16
- manim/utils/hashing.py +7 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +12 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +55 -19
- manim/utils/opengl.py +68 -23
- manim/utils/parameter_parsing.py +3 -2
- manim/utils/paths.py +11 -5
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +69 -32
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +48 -37
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +33 -18
- manim/utils/testing/frames_comparison.py +20 -14
- manim/utils/tex.py +4 -2
- manim/utils/tex_file_writing.py +45 -45
- manim/utils/tex_templates.py +1 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim-0.18.1.dist-info/RECORD +0 -217
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
|
@@ -5,9 +5,11 @@ import inspect
|
|
|
5
5
|
import itertools as it
|
|
6
6
|
import random
|
|
7
7
|
import sys
|
|
8
|
+
import types
|
|
9
|
+
from collections.abc import Iterable, Iterator, Sequence
|
|
8
10
|
from functools import partialmethod, wraps
|
|
9
11
|
from math import ceil
|
|
10
|
-
from typing import
|
|
12
|
+
from typing import TYPE_CHECKING, Any, Callable, TypeVar
|
|
11
13
|
|
|
12
14
|
import moderngl
|
|
13
15
|
import numpy as np
|
|
@@ -44,10 +46,36 @@ from manim.utils.space_ops import (
|
|
|
44
46
|
rotation_matrix_transpose,
|
|
45
47
|
)
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
if TYPE_CHECKING:
|
|
50
|
+
import numpy.typing as npt
|
|
51
|
+
from typing_extensions import Self, TypeAlias
|
|
52
|
+
|
|
53
|
+
from manim.renderer.shader_wrapper import ShaderWrapper
|
|
54
|
+
from manim.typing import (
|
|
55
|
+
ManimFloat,
|
|
56
|
+
MappingFunction,
|
|
57
|
+
MatrixMN,
|
|
58
|
+
MultiMappingFunction,
|
|
59
|
+
PathFuncType,
|
|
60
|
+
Point3D,
|
|
61
|
+
Point3D_Array,
|
|
62
|
+
Point3DLike,
|
|
63
|
+
Point3DLike_Array,
|
|
64
|
+
Vector3D,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
TimeBasedUpdater: TypeAlias = Callable[["Mobject", float], object]
|
|
68
|
+
NonTimeBasedUpdater: TypeAlias = Callable[["Mobject"], object]
|
|
69
|
+
Updater: TypeAlias = NonTimeBasedUpdater | TimeBasedUpdater
|
|
70
|
+
|
|
71
|
+
T = TypeVar("T")
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def affects_shader_info_id(
|
|
75
|
+
func: Callable[[OpenGLMobject], OpenGLMobject],
|
|
76
|
+
) -> Callable[[OpenGLMobject], OpenGLMobject]:
|
|
49
77
|
@wraps(func)
|
|
50
|
-
def wrapper(self):
|
|
78
|
+
def wrapper(self: OpenGLMobject) -> OpenGLMobject:
|
|
51
79
|
for mob in self.get_family():
|
|
52
80
|
func(mob)
|
|
53
81
|
mob.refresh_shader_wrapper_id()
|
|
@@ -93,26 +121,26 @@ class OpenGLMobject:
|
|
|
93
121
|
|
|
94
122
|
def __init__(
|
|
95
123
|
self,
|
|
96
|
-
color=WHITE,
|
|
97
|
-
opacity=1,
|
|
98
|
-
dim=3, # TODO, get rid of this
|
|
124
|
+
color: ParsableManimColor | Iterable[ParsableManimColor] = WHITE,
|
|
125
|
+
opacity: float = 1,
|
|
126
|
+
dim: int = 3, # TODO, get rid of this
|
|
99
127
|
# Lighting parameters
|
|
100
128
|
# Positive gloss up to 1 makes it reflect the light.
|
|
101
|
-
gloss=0.0,
|
|
129
|
+
gloss: float = 0.0,
|
|
102
130
|
# Positive shadow up to 1 makes a side opposite the light darker
|
|
103
|
-
shadow=0.0,
|
|
131
|
+
shadow: float = 0.0,
|
|
104
132
|
# For shaders
|
|
105
|
-
render_primitive=moderngl.TRIANGLES,
|
|
106
|
-
texture_paths=None,
|
|
107
|
-
depth_test=False,
|
|
133
|
+
render_primitive: int = moderngl.TRIANGLES,
|
|
134
|
+
texture_paths: dict[str, str] | None = None,
|
|
135
|
+
depth_test: bool = False,
|
|
108
136
|
# If true, the mobject will not get rotated according to camera position
|
|
109
|
-
is_fixed_in_frame=False,
|
|
110
|
-
is_fixed_orientation=False,
|
|
137
|
+
is_fixed_in_frame: bool = False,
|
|
138
|
+
is_fixed_orientation: bool = False,
|
|
111
139
|
# Must match in attributes of vert shader
|
|
112
140
|
# Event listener
|
|
113
|
-
listen_to_events=False,
|
|
114
|
-
model_matrix=None,
|
|
115
|
-
should_render=True,
|
|
141
|
+
listen_to_events: bool = False,
|
|
142
|
+
model_matrix: MatrixMN | None = None,
|
|
143
|
+
should_render: bool = True,
|
|
116
144
|
name: str | None = None,
|
|
117
145
|
**kwargs,
|
|
118
146
|
):
|
|
@@ -165,15 +193,73 @@ class OpenGLMobject:
|
|
|
165
193
|
|
|
166
194
|
self.should_render = should_render
|
|
167
195
|
|
|
196
|
+
def _assert_valid_submobjects(self, submobjects: Iterable[OpenGLMobject]) -> Self:
|
|
197
|
+
"""Check that all submobjects are actually instances of
|
|
198
|
+
:class:`OpenGLMobject`, and that none of them is
|
|
199
|
+
``self`` (an :class:`OpenGLMobject` cannot contain itself).
|
|
200
|
+
|
|
201
|
+
This is an auxiliary function called when adding OpenGLMobjects to the
|
|
202
|
+
:attr:`submobjects` list.
|
|
203
|
+
|
|
204
|
+
This function is intended to be overridden by subclasses such as
|
|
205
|
+
:class:`OpenGLVMobject`, which should assert that only other
|
|
206
|
+
OpenGLVMobjects may be added into it.
|
|
207
|
+
|
|
208
|
+
Parameters
|
|
209
|
+
----------
|
|
210
|
+
submobjects
|
|
211
|
+
The list containing values to validate.
|
|
212
|
+
|
|
213
|
+
Returns
|
|
214
|
+
-------
|
|
215
|
+
:class:`OpenGLMobject`
|
|
216
|
+
The OpenGLMobject itself.
|
|
217
|
+
|
|
218
|
+
Raises
|
|
219
|
+
------
|
|
220
|
+
TypeError
|
|
221
|
+
If any of the values in `submobjects` is not an
|
|
222
|
+
:class:`OpenGLMobject`.
|
|
223
|
+
ValueError
|
|
224
|
+
If there was an attempt to add an :class:`OpenGLMobject` as its own
|
|
225
|
+
submobject.
|
|
226
|
+
"""
|
|
227
|
+
return self._assert_valid_submobjects_internal(submobjects, OpenGLMobject)
|
|
228
|
+
|
|
229
|
+
def _assert_valid_submobjects_internal(
|
|
230
|
+
self, submobjects: Iterable[OpenGLMobject], mob_class: type[OpenGLMobject]
|
|
231
|
+
) -> Self:
|
|
232
|
+
for i, submob in enumerate(submobjects):
|
|
233
|
+
if not isinstance(submob, mob_class):
|
|
234
|
+
error_message = (
|
|
235
|
+
f"Only values of type {mob_class.__name__} can be added "
|
|
236
|
+
f"as submobjects of {type(self).__name__}, but the value "
|
|
237
|
+
f"{submob} (at index {i}) is of type "
|
|
238
|
+
f"{type(submob).__name__}."
|
|
239
|
+
)
|
|
240
|
+
# Intended for subclasses such as OpenGLVMobject, which
|
|
241
|
+
# cannot have regular OpenGLMobjects as submobjects
|
|
242
|
+
if isinstance(submob, OpenGLMobject):
|
|
243
|
+
error_message += (
|
|
244
|
+
" You can try adding this value into a Group instead."
|
|
245
|
+
)
|
|
246
|
+
raise TypeError(error_message)
|
|
247
|
+
if submob is self:
|
|
248
|
+
raise ValueError(
|
|
249
|
+
f"Cannot add {type(self).__name__} as a submobject of "
|
|
250
|
+
f"itself (at index {i})."
|
|
251
|
+
)
|
|
252
|
+
return self
|
|
253
|
+
|
|
168
254
|
@classmethod
|
|
169
|
-
def __init_subclass__(cls, **kwargs):
|
|
255
|
+
def __init_subclass__(cls, **kwargs) -> None:
|
|
170
256
|
super().__init_subclass__(**kwargs)
|
|
171
257
|
cls._original__init__ = cls.__init__
|
|
172
258
|
|
|
173
|
-
def __str__(self):
|
|
259
|
+
def __str__(self) -> str:
|
|
174
260
|
return self.__class__.__name__
|
|
175
261
|
|
|
176
|
-
def __repr__(self):
|
|
262
|
+
def __repr__(self) -> str:
|
|
177
263
|
return str(self.name)
|
|
178
264
|
|
|
179
265
|
def __sub__(self, other):
|
|
@@ -189,7 +275,7 @@ class OpenGLMobject:
|
|
|
189
275
|
return NotImplemented
|
|
190
276
|
|
|
191
277
|
@classmethod
|
|
192
|
-
def set_default(cls, **kwargs):
|
|
278
|
+
def set_default(cls, **kwargs) -> None:
|
|
193
279
|
"""Sets the default values of keyword arguments.
|
|
194
280
|
|
|
195
281
|
If this method is called without any additional keyword
|
|
@@ -236,28 +322,31 @@ class OpenGLMobject:
|
|
|
236
322
|
else:
|
|
237
323
|
cls.__init__ = cls._original__init__
|
|
238
324
|
|
|
239
|
-
def init_data(self):
|
|
325
|
+
def init_data(self) -> None:
|
|
240
326
|
"""Initializes the ``points``, ``bounding_box`` and ``rgbas`` attributes and groups them into self.data.
|
|
241
|
-
Subclasses can inherit and overwrite this method to extend `self.data`.
|
|
327
|
+
Subclasses can inherit and overwrite this method to extend `self.data`.
|
|
328
|
+
"""
|
|
242
329
|
self.points = np.zeros((0, 3))
|
|
243
330
|
self.bounding_box = np.zeros((3, 3))
|
|
244
331
|
self.rgbas = np.zeros((1, 4))
|
|
245
332
|
|
|
246
|
-
def init_colors(self):
|
|
333
|
+
def init_colors(self) -> object:
|
|
247
334
|
"""Initializes the colors.
|
|
248
335
|
|
|
249
|
-
Gets called upon creation
|
|
336
|
+
Gets called upon creation
|
|
337
|
+
"""
|
|
250
338
|
self.set_color(self.color, self.opacity)
|
|
251
339
|
|
|
252
|
-
def init_points(self):
|
|
340
|
+
def init_points(self) -> object:
|
|
253
341
|
"""Initializes :attr:`points` and therefore the shape.
|
|
254
342
|
|
|
255
343
|
Gets called upon creation. This is an empty method that can be implemented by
|
|
256
|
-
subclasses.
|
|
344
|
+
subclasses.
|
|
345
|
+
"""
|
|
257
346
|
# Typically implemented in subclass, unless purposefully left blank
|
|
258
347
|
pass
|
|
259
348
|
|
|
260
|
-
def set(self, **kwargs) ->
|
|
349
|
+
def set(self, **kwargs) -> Self:
|
|
261
350
|
"""Sets attributes.
|
|
262
351
|
|
|
263
352
|
Mainly to be used along with :attr:`animate` to
|
|
@@ -285,24 +374,23 @@ class OpenGLMobject:
|
|
|
285
374
|
|
|
286
375
|
|
|
287
376
|
"""
|
|
288
|
-
|
|
289
377
|
for attr, value in kwargs.items():
|
|
290
378
|
setattr(self, attr, value)
|
|
291
379
|
|
|
292
380
|
return self
|
|
293
381
|
|
|
294
|
-
def set_data(self, data):
|
|
382
|
+
def set_data(self, data: dict[str, Any]) -> Self:
|
|
295
383
|
for key in data:
|
|
296
384
|
self.data[key] = data[key].copy()
|
|
297
385
|
return self
|
|
298
386
|
|
|
299
|
-
def set_uniforms(self, uniforms):
|
|
387
|
+
def set_uniforms(self, uniforms: dict[str, Any]) -> Self:
|
|
300
388
|
for key in uniforms:
|
|
301
389
|
self.uniforms[key] = uniforms[key] # Copy?
|
|
302
390
|
return self
|
|
303
391
|
|
|
304
392
|
@property
|
|
305
|
-
def animate(self):
|
|
393
|
+
def animate(self) -> _AnimationBuilder | Self:
|
|
306
394
|
"""Used to animate the application of a method.
|
|
307
395
|
|
|
308
396
|
.. warning::
|
|
@@ -313,7 +401,9 @@ class OpenGLMobject:
|
|
|
313
401
|
|
|
314
402
|
::
|
|
315
403
|
|
|
316
|
-
self.play(
|
|
404
|
+
self.play(
|
|
405
|
+
my_mobject.animate.shift(RIGHT), my_mobject.animate.rotate(PI)
|
|
406
|
+
)
|
|
317
407
|
|
|
318
408
|
make use of method chaining for ``animate``, meaning::
|
|
319
409
|
|
|
@@ -390,7 +480,7 @@ class OpenGLMobject:
|
|
|
390
480
|
return _AnimationBuilder(self)
|
|
391
481
|
|
|
392
482
|
@property
|
|
393
|
-
def width(self):
|
|
483
|
+
def width(self) -> float:
|
|
394
484
|
"""The width of the mobject.
|
|
395
485
|
|
|
396
486
|
Returns
|
|
@@ -418,17 +508,16 @@ class OpenGLMobject:
|
|
|
418
508
|
:meth:`length_over_dim`
|
|
419
509
|
|
|
420
510
|
"""
|
|
421
|
-
|
|
422
511
|
# Get the length across the X dimension
|
|
423
512
|
return self.length_over_dim(0)
|
|
424
513
|
|
|
425
514
|
# Only these methods should directly affect points
|
|
426
515
|
@width.setter
|
|
427
|
-
def width(self, value):
|
|
516
|
+
def width(self, value: float) -> None:
|
|
428
517
|
self.rescale_to_fit(value, 0, stretch=False)
|
|
429
518
|
|
|
430
519
|
@property
|
|
431
|
-
def height(self):
|
|
520
|
+
def height(self) -> float:
|
|
432
521
|
"""The height of the mobject.
|
|
433
522
|
|
|
434
523
|
Returns
|
|
@@ -456,16 +545,15 @@ class OpenGLMobject:
|
|
|
456
545
|
:meth:`length_over_dim`
|
|
457
546
|
|
|
458
547
|
"""
|
|
459
|
-
|
|
460
548
|
# Get the length across the Y dimension
|
|
461
549
|
return self.length_over_dim(1)
|
|
462
550
|
|
|
463
551
|
@height.setter
|
|
464
|
-
def height(self, value):
|
|
552
|
+
def height(self, value: float) -> None:
|
|
465
553
|
self.rescale_to_fit(value, 1, stretch=False)
|
|
466
554
|
|
|
467
555
|
@property
|
|
468
|
-
def depth(self):
|
|
556
|
+
def depth(self) -> float:
|
|
469
557
|
"""The depth of the mobject.
|
|
470
558
|
|
|
471
559
|
Returns
|
|
@@ -477,12 +565,11 @@ class OpenGLMobject:
|
|
|
477
565
|
:meth:`length_over_dim`
|
|
478
566
|
|
|
479
567
|
"""
|
|
480
|
-
|
|
481
568
|
# Get the length across the Z dimension
|
|
482
569
|
return self.length_over_dim(2)
|
|
483
570
|
|
|
484
571
|
@depth.setter
|
|
485
|
-
def depth(self, value):
|
|
572
|
+
def depth(self, value: float) -> None:
|
|
486
573
|
self.rescale_to_fit(value, 2, stretch=False)
|
|
487
574
|
|
|
488
575
|
def resize_points(self, new_length, resize_func=resize_array):
|
|
@@ -491,7 +578,7 @@ class OpenGLMobject:
|
|
|
491
578
|
self.refresh_bounding_box()
|
|
492
579
|
return self
|
|
493
580
|
|
|
494
|
-
def set_points(self, points):
|
|
581
|
+
def set_points(self, points: Point3DLike_Array) -> Self:
|
|
495
582
|
if len(points) == len(self.points):
|
|
496
583
|
self.points[:] = points
|
|
497
584
|
elif isinstance(points, np.ndarray):
|
|
@@ -501,23 +588,26 @@ class OpenGLMobject:
|
|
|
501
588
|
self.refresh_bounding_box()
|
|
502
589
|
return self
|
|
503
590
|
|
|
504
|
-
def apply_over_attr_arrays(
|
|
591
|
+
def apply_over_attr_arrays(
|
|
592
|
+
self, func: Callable[[npt.NDArray[T]], npt.NDArray[T]]
|
|
593
|
+
) -> Self:
|
|
594
|
+
# TODO: OpenGLMobject.get_array_attrs() doesn't even exist!
|
|
505
595
|
for attr in self.get_array_attrs():
|
|
506
596
|
setattr(self, attr, func(getattr(self, attr)))
|
|
507
597
|
return self
|
|
508
598
|
|
|
509
|
-
def append_points(self, new_points):
|
|
599
|
+
def append_points(self, new_points: Point3DLike_Array) -> Self:
|
|
510
600
|
self.points = np.vstack([self.points, new_points])
|
|
511
601
|
self.refresh_bounding_box()
|
|
512
602
|
return self
|
|
513
603
|
|
|
514
|
-
def reverse_points(self):
|
|
604
|
+
def reverse_points(self) -> Self:
|
|
515
605
|
for mob in self.get_family():
|
|
516
606
|
for key in mob.data:
|
|
517
607
|
mob.data[key] = mob.data[key][::-1]
|
|
518
608
|
return self
|
|
519
609
|
|
|
520
|
-
def get_midpoint(self) ->
|
|
610
|
+
def get_midpoint(self) -> Point3D:
|
|
521
611
|
"""Get coordinates of the middle of the path that forms the :class:`~.OpenGLMobject`.
|
|
522
612
|
|
|
523
613
|
Examples
|
|
@@ -540,13 +630,14 @@ class OpenGLMobject:
|
|
|
540
630
|
"""
|
|
541
631
|
return self.point_from_proportion(0.5)
|
|
542
632
|
|
|
633
|
+
# TODO: name is inconsistent with Mobject.apply_points_function_about_point()
|
|
543
634
|
def apply_points_function(
|
|
544
635
|
self,
|
|
545
|
-
func,
|
|
546
|
-
about_point=None,
|
|
547
|
-
about_edge=ORIGIN,
|
|
548
|
-
works_on_bounding_box=False,
|
|
549
|
-
):
|
|
636
|
+
func: MultiMappingFunction,
|
|
637
|
+
about_point: Point3DLike | None = None,
|
|
638
|
+
about_edge: Vector3D | None = ORIGIN,
|
|
639
|
+
works_on_bounding_box: bool = False,
|
|
640
|
+
) -> Self:
|
|
550
641
|
if about_point is None and about_edge is not None:
|
|
551
642
|
about_point = self.get_bounding_box_point(about_edge)
|
|
552
643
|
|
|
@@ -572,7 +663,7 @@ class OpenGLMobject:
|
|
|
572
663
|
|
|
573
664
|
# Others related to points
|
|
574
665
|
|
|
575
|
-
def match_points(self, mobject):
|
|
666
|
+
def match_points(self, mobject: OpenGLMobject) -> Self:
|
|
576
667
|
"""Edit points, positions, and submobjects to be identical
|
|
577
668
|
to another :class:`~.OpenGLMobject`, while keeping the style unchanged.
|
|
578
669
|
|
|
@@ -590,29 +681,31 @@ class OpenGLMobject:
|
|
|
590
681
|
self.wait(0.5)
|
|
591
682
|
"""
|
|
592
683
|
self.set_points(mobject.points)
|
|
684
|
+
return self
|
|
593
685
|
|
|
594
|
-
def clear_points(self):
|
|
686
|
+
def clear_points(self) -> Self:
|
|
595
687
|
self.points = np.empty((0, 3))
|
|
688
|
+
return self
|
|
596
689
|
|
|
597
|
-
def get_num_points(self):
|
|
690
|
+
def get_num_points(self) -> int:
|
|
598
691
|
return len(self.points)
|
|
599
692
|
|
|
600
|
-
def get_all_points(self):
|
|
693
|
+
def get_all_points(self) -> Point3D_Array:
|
|
601
694
|
if self.submobjects:
|
|
602
695
|
return np.vstack([sm.points for sm in self.get_family()])
|
|
603
696
|
else:
|
|
604
697
|
return self.points
|
|
605
698
|
|
|
606
|
-
def has_points(self):
|
|
699
|
+
def has_points(self) -> bool:
|
|
607
700
|
return self.get_num_points() > 0
|
|
608
701
|
|
|
609
|
-
def get_bounding_box(self):
|
|
702
|
+
def get_bounding_box(self) -> npt.NDArray[float]:
|
|
610
703
|
if self.needs_new_bounding_box:
|
|
611
704
|
self.bounding_box = self.compute_bounding_box()
|
|
612
705
|
self.needs_new_bounding_box = False
|
|
613
706
|
return self.bounding_box
|
|
614
707
|
|
|
615
|
-
def compute_bounding_box(self):
|
|
708
|
+
def compute_bounding_box(self) -> npt.NDArray[float]:
|
|
616
709
|
all_points = np.vstack(
|
|
617
710
|
[
|
|
618
711
|
self.points,
|
|
@@ -632,7 +725,9 @@ class OpenGLMobject:
|
|
|
632
725
|
mids = (mins + maxs) / 2
|
|
633
726
|
return np.array([mins, mids, maxs])
|
|
634
727
|
|
|
635
|
-
def refresh_bounding_box(
|
|
728
|
+
def refresh_bounding_box(
|
|
729
|
+
self, recurse_down: bool = False, recurse_up: bool = True
|
|
730
|
+
) -> Self:
|
|
636
731
|
for mob in self.get_family(recurse_down):
|
|
637
732
|
mob.needs_new_bounding_box = True
|
|
638
733
|
if recurse_up:
|
|
@@ -640,7 +735,9 @@ class OpenGLMobject:
|
|
|
640
735
|
parent.refresh_bounding_box()
|
|
641
736
|
return self
|
|
642
737
|
|
|
643
|
-
def is_point_touching(
|
|
738
|
+
def is_point_touching(
|
|
739
|
+
self, point: Point3DLike, buff: float = MED_SMALL_BUFF
|
|
740
|
+
) -> bool:
|
|
644
741
|
bb = self.get_bounding_box()
|
|
645
742
|
mins = bb[0] - buff
|
|
646
743
|
maxs = bb[2] + buff
|
|
@@ -648,22 +745,22 @@ class OpenGLMobject:
|
|
|
648
745
|
|
|
649
746
|
# Family matters
|
|
650
747
|
|
|
651
|
-
def __getitem__(self, value):
|
|
748
|
+
def __getitem__(self, value: int | slice) -> OpenGLMobject:
|
|
652
749
|
if isinstance(value, slice):
|
|
653
750
|
GroupClass = self.get_group_class()
|
|
654
751
|
return GroupClass(*self.split().__getitem__(value))
|
|
655
752
|
return self.split().__getitem__(value)
|
|
656
753
|
|
|
657
|
-
def __iter__(self):
|
|
754
|
+
def __iter__(self) -> Iterator[OpenGLMobject]:
|
|
658
755
|
return iter(self.split())
|
|
659
756
|
|
|
660
|
-
def __len__(self):
|
|
757
|
+
def __len__(self) -> int:
|
|
661
758
|
return len(self.split())
|
|
662
759
|
|
|
663
|
-
def split(self):
|
|
760
|
+
def split(self) -> Sequence[OpenGLMobject]:
|
|
664
761
|
return self.submobjects
|
|
665
762
|
|
|
666
|
-
def assemble_family(self):
|
|
763
|
+
def assemble_family(self) -> Self:
|
|
667
764
|
sub_families = (sm.get_family() for sm in self.submobjects)
|
|
668
765
|
self.family = [self, *uniq_chain(*sub_families)]
|
|
669
766
|
self.refresh_has_updater_status()
|
|
@@ -672,18 +769,16 @@ class OpenGLMobject:
|
|
|
672
769
|
parent.assemble_family()
|
|
673
770
|
return self
|
|
674
771
|
|
|
675
|
-
def get_family(self, recurse=True):
|
|
772
|
+
def get_family(self, recurse: bool = True) -> Sequence[OpenGLMobject]:
|
|
676
773
|
if recurse and hasattr(self, "family"):
|
|
677
774
|
return self.family
|
|
678
775
|
else:
|
|
679
776
|
return [self]
|
|
680
777
|
|
|
681
|
-
def family_members_with_points(self):
|
|
778
|
+
def family_members_with_points(self) -> Sequence[OpenGLMobject]:
|
|
682
779
|
return [m for m in self.get_family() if m.has_points()]
|
|
683
780
|
|
|
684
|
-
def add(
|
|
685
|
-
self, *mobjects: OpenGLMobject, update_parent: bool = False
|
|
686
|
-
) -> OpenGLMobject:
|
|
781
|
+
def add(self, *mobjects: OpenGLMobject, update_parent: bool = False) -> Self:
|
|
687
782
|
"""Add mobjects as submobjects.
|
|
688
783
|
|
|
689
784
|
The mobjects are added to :attr:`submobjects`.
|
|
@@ -734,28 +829,33 @@ class OpenGLMobject:
|
|
|
734
829
|
>>> len(outer.submobjects)
|
|
735
830
|
1
|
|
736
831
|
|
|
832
|
+
Only OpenGLMobjects can be added::
|
|
833
|
+
|
|
834
|
+
>>> outer.add(3)
|
|
835
|
+
Traceback (most recent call last):
|
|
836
|
+
...
|
|
837
|
+
TypeError: Only values of type OpenGLMobject can be added as submobjects of OpenGLMobject, but the value 3 (at index 0) is of type int.
|
|
838
|
+
|
|
737
839
|
Adding an object to itself raises an error::
|
|
738
840
|
|
|
739
841
|
>>> outer.add(outer)
|
|
740
842
|
Traceback (most recent call last):
|
|
741
843
|
...
|
|
742
|
-
ValueError: OpenGLMobject
|
|
844
|
+
ValueError: Cannot add OpenGLMobject as a submobject of itself (at index 0).
|
|
743
845
|
|
|
744
846
|
"""
|
|
745
847
|
if update_parent:
|
|
746
848
|
assert len(mobjects) == 1, "Can't set multiple parents."
|
|
747
849
|
mobjects[0].parent = self
|
|
748
850
|
|
|
749
|
-
|
|
750
|
-
|
|
851
|
+
self._assert_valid_submobjects(mobjects)
|
|
852
|
+
|
|
751
853
|
if any(mobjects.count(elem) > 1 for elem in mobjects):
|
|
752
854
|
logger.warning(
|
|
753
855
|
"Attempted adding some Mobject as a child more than once, "
|
|
754
856
|
"this is not possible. Repetitions are ignored.",
|
|
755
857
|
)
|
|
756
858
|
for mobject in mobjects:
|
|
757
|
-
if not isinstance(mobject, OpenGLMobject):
|
|
758
|
-
raise TypeError("All submobjects must be of type OpenGLMobject")
|
|
759
859
|
if mobject not in self.submobjects:
|
|
760
860
|
self.submobjects.append(mobject)
|
|
761
861
|
if self not in mobject.parents:
|
|
@@ -763,7 +863,9 @@ class OpenGLMobject:
|
|
|
763
863
|
self.assemble_family()
|
|
764
864
|
return self
|
|
765
865
|
|
|
766
|
-
def insert(
|
|
866
|
+
def insert(
|
|
867
|
+
self, index: int, mobject: OpenGLMobject, update_parent: bool = False
|
|
868
|
+
) -> Self:
|
|
767
869
|
"""Inserts a mobject at a specific position into self.submobjects
|
|
768
870
|
|
|
769
871
|
Effectively just calls ``self.submobjects.insert(index, mobject)``,
|
|
@@ -780,15 +882,10 @@ class OpenGLMobject:
|
|
|
780
882
|
update_parent
|
|
781
883
|
Whether or not to set ``mobject.parent`` to ``self``.
|
|
782
884
|
"""
|
|
783
|
-
|
|
784
885
|
if update_parent:
|
|
785
886
|
mobject.parent = self
|
|
786
887
|
|
|
787
|
-
|
|
788
|
-
raise ValueError("OpenGLMobject cannot contain self")
|
|
789
|
-
|
|
790
|
-
if not isinstance(mobject, OpenGLMobject):
|
|
791
|
-
raise TypeError("All submobjects must be of type OpenGLMobject")
|
|
888
|
+
self._assert_valid_submobjects([mobject])
|
|
792
889
|
|
|
793
890
|
if mobject not in self.submobjects:
|
|
794
891
|
self.submobjects.insert(index, mobject)
|
|
@@ -799,9 +896,7 @@ class OpenGLMobject:
|
|
|
799
896
|
self.assemble_family()
|
|
800
897
|
return self
|
|
801
898
|
|
|
802
|
-
def remove(
|
|
803
|
-
self, *mobjects: OpenGLMobject, update_parent: bool = False
|
|
804
|
-
) -> OpenGLMobject:
|
|
899
|
+
def remove(self, *mobjects: OpenGLMobject, update_parent: bool = False) -> Self:
|
|
805
900
|
"""Remove :attr:`submobjects`.
|
|
806
901
|
|
|
807
902
|
The mobjects are removed from :attr:`submobjects`, if they exist.
|
|
@@ -835,7 +930,7 @@ class OpenGLMobject:
|
|
|
835
930
|
self.assemble_family()
|
|
836
931
|
return self
|
|
837
932
|
|
|
838
|
-
def add_to_back(self, *mobjects: OpenGLMobject) ->
|
|
933
|
+
def add_to_back(self, *mobjects: OpenGLMobject) -> Self:
|
|
839
934
|
# NOTE: is the note true OpenGLMobjects?
|
|
840
935
|
"""Add all passed mobjects to the back of the submobjects.
|
|
841
936
|
|
|
@@ -880,10 +975,12 @@ class OpenGLMobject:
|
|
|
880
975
|
:meth:`add`
|
|
881
976
|
|
|
882
977
|
"""
|
|
978
|
+
self._assert_valid_submobjects(mobjects)
|
|
883
979
|
self.submobjects = list_update(mobjects, self.submobjects)
|
|
884
980
|
return self
|
|
885
981
|
|
|
886
|
-
def replace_submobject(self, index, new_submob):
|
|
982
|
+
def replace_submobject(self, index: int, new_submob: OpenGLMobject) -> Self:
|
|
983
|
+
self._assert_valid_submobjects([new_submob])
|
|
887
984
|
old_submob = self.submobjects[index]
|
|
888
985
|
if self in old_submob.parents:
|
|
889
986
|
old_submob.parents.remove(self)
|
|
@@ -891,36 +988,11 @@ class OpenGLMobject:
|
|
|
891
988
|
self.assemble_family()
|
|
892
989
|
return self
|
|
893
990
|
|
|
894
|
-
def invert(self, recursive=False):
|
|
895
|
-
"""Inverts the list of :attr:`submobjects`.
|
|
896
|
-
|
|
897
|
-
Parameters
|
|
898
|
-
----------
|
|
899
|
-
recursive
|
|
900
|
-
If ``True``, all submobject lists of this mobject's family are inverted.
|
|
901
|
-
|
|
902
|
-
Examples
|
|
903
|
-
--------
|
|
904
|
-
|
|
905
|
-
.. manim:: InvertSumobjectsExample
|
|
906
|
-
|
|
907
|
-
class InvertSumobjectsExample(Scene):
|
|
908
|
-
def construct(self):
|
|
909
|
-
s = VGroup(*[Dot().shift(i*0.1*RIGHT) for i in range(-20,20)])
|
|
910
|
-
s2 = s.copy()
|
|
911
|
-
s2.invert()
|
|
912
|
-
s2.shift(DOWN)
|
|
913
|
-
self.play(Write(s), Write(s2))
|
|
914
|
-
"""
|
|
915
|
-
if recursive:
|
|
916
|
-
for submob in self.submobjects:
|
|
917
|
-
submob.invert(recursive=True)
|
|
918
|
-
list.reverse(self.submobjects)
|
|
919
|
-
self.assemble_family()
|
|
920
|
-
|
|
921
991
|
# Submobject organization
|
|
922
992
|
|
|
923
|
-
def arrange(
|
|
993
|
+
def arrange(
|
|
994
|
+
self, direction: Vector3D = RIGHT, center: bool = True, **kwargs
|
|
995
|
+
) -> Self:
|
|
924
996
|
"""Sorts :class:`~.OpenGLMobject` next to each other on screen.
|
|
925
997
|
|
|
926
998
|
Examples
|
|
@@ -949,14 +1021,14 @@ class OpenGLMobject:
|
|
|
949
1021
|
rows: int | None = None,
|
|
950
1022
|
cols: int | None = None,
|
|
951
1023
|
buff: float | tuple[float, float] = MED_SMALL_BUFF,
|
|
952
|
-
cell_alignment:
|
|
1024
|
+
cell_alignment: Vector3D = ORIGIN,
|
|
953
1025
|
row_alignments: str | None = None, # "ucd"
|
|
954
1026
|
col_alignments: str | None = None, # "lcr"
|
|
955
|
-
row_heights:
|
|
956
|
-
col_widths:
|
|
1027
|
+
row_heights: Sequence[float | None] | None = None,
|
|
1028
|
+
col_widths: Sequence[float | None] | None = None,
|
|
957
1029
|
flow_order: str = "rd",
|
|
958
1030
|
**kwargs,
|
|
959
|
-
) ->
|
|
1031
|
+
) -> Self:
|
|
960
1032
|
"""Arrange submobjects in a grid.
|
|
961
1033
|
|
|
962
1034
|
Parameters
|
|
@@ -1052,16 +1124,27 @@ class OpenGLMobject:
|
|
|
1052
1124
|
start_pos = self.get_center()
|
|
1053
1125
|
|
|
1054
1126
|
# get cols / rows values if given (implicitly)
|
|
1055
|
-
def init_size(
|
|
1127
|
+
def init_size(
|
|
1128
|
+
num: int | None,
|
|
1129
|
+
alignments: str | None,
|
|
1130
|
+
sizes: Sequence[float | None] | None,
|
|
1131
|
+
name: str,
|
|
1132
|
+
) -> int:
|
|
1056
1133
|
if num is not None:
|
|
1057
1134
|
return num
|
|
1058
1135
|
if alignments is not None:
|
|
1059
1136
|
return len(alignments)
|
|
1060
1137
|
if sizes is not None:
|
|
1061
1138
|
return len(sizes)
|
|
1139
|
+
raise ValueError(
|
|
1140
|
+
f"At least one of the following parameters: '{name}s', "
|
|
1141
|
+
f"'{name}_alignments' or "
|
|
1142
|
+
f"'{name}_{'widths' if name == 'col' else 'heights'}', "
|
|
1143
|
+
"must not be None"
|
|
1144
|
+
)
|
|
1062
1145
|
|
|
1063
|
-
cols = init_size(cols, col_alignments, col_widths)
|
|
1064
|
-
rows = init_size(rows, row_alignments, row_heights)
|
|
1146
|
+
cols = init_size(cols, col_alignments, col_widths, "col")
|
|
1147
|
+
rows = init_size(rows, row_alignments, row_heights, "row")
|
|
1065
1148
|
|
|
1066
1149
|
# calculate rows cols
|
|
1067
1150
|
if rows is None and cols is None:
|
|
@@ -1085,16 +1168,19 @@ class OpenGLMobject:
|
|
|
1085
1168
|
buff_x = buff_y = buff
|
|
1086
1169
|
|
|
1087
1170
|
# Initialize alignments correctly
|
|
1088
|
-
def init_alignments(
|
|
1089
|
-
|
|
1171
|
+
def init_alignments(
|
|
1172
|
+
str_alignments: str | None,
|
|
1173
|
+
num: int,
|
|
1174
|
+
mapping: dict[str, Vector3D],
|
|
1175
|
+
name: str,
|
|
1176
|
+
direction: Vector3D,
|
|
1177
|
+
) -> Sequence[Vector3D]:
|
|
1178
|
+
if str_alignments is None:
|
|
1090
1179
|
# Use cell_alignment as fallback
|
|
1091
|
-
return [cell_alignment *
|
|
1092
|
-
if len(
|
|
1180
|
+
return [cell_alignment * direction] * num
|
|
1181
|
+
if len(str_alignments) != num:
|
|
1093
1182
|
raise ValueError(f"{name}_alignments has a mismatching size.")
|
|
1094
|
-
|
|
1095
|
-
for i in range(num):
|
|
1096
|
-
alignments[i] = mapping[alignments[i]]
|
|
1097
|
-
return alignments
|
|
1183
|
+
return [mapping[letter] for letter in str_alignments]
|
|
1098
1184
|
|
|
1099
1185
|
row_alignments = init_alignments(
|
|
1100
1186
|
row_alignments,
|
|
@@ -1130,11 +1216,12 @@ class OpenGLMobject:
|
|
|
1130
1216
|
|
|
1131
1217
|
# Reverse row_alignments and row_heights. Necessary since the
|
|
1132
1218
|
# grid filling is handled bottom up for simplicity reasons.
|
|
1133
|
-
def reverse(maybe_list):
|
|
1219
|
+
def reverse(maybe_list: Sequence[Any] | None) -> Sequence[Any] | None:
|
|
1134
1220
|
if maybe_list is not None:
|
|
1135
1221
|
maybe_list = list(maybe_list)
|
|
1136
1222
|
maybe_list.reverse()
|
|
1137
1223
|
return maybe_list
|
|
1224
|
+
return None
|
|
1138
1225
|
|
|
1139
1226
|
row_alignments = reverse(row_alignments)
|
|
1140
1227
|
row_heights = reverse(row_heights)
|
|
@@ -1155,7 +1242,12 @@ class OpenGLMobject:
|
|
|
1155
1242
|
]
|
|
1156
1243
|
|
|
1157
1244
|
# Initialize row_heights / col_widths correctly using measurements as fallback
|
|
1158
|
-
def init_sizes(
|
|
1245
|
+
def init_sizes(
|
|
1246
|
+
sizes: Sequence[float | None] | None,
|
|
1247
|
+
num: int,
|
|
1248
|
+
measures: Sequence[float],
|
|
1249
|
+
name: str,
|
|
1250
|
+
) -> Sequence[float]:
|
|
1159
1251
|
if sizes is None:
|
|
1160
1252
|
sizes = [None] * num
|
|
1161
1253
|
if len(sizes) != num:
|
|
@@ -1188,7 +1280,9 @@ class OpenGLMobject:
|
|
|
1188
1280
|
self.move_to(start_pos)
|
|
1189
1281
|
return self
|
|
1190
1282
|
|
|
1191
|
-
def get_grid(
|
|
1283
|
+
def get_grid(
|
|
1284
|
+
self, n_rows: int, n_cols: int, height: float | None = None, **kwargs
|
|
1285
|
+
) -> OpenGLGroup:
|
|
1192
1286
|
"""
|
|
1193
1287
|
Returns a new mobject containing multiple copies of this one
|
|
1194
1288
|
arranged in a grid
|
|
@@ -1199,11 +1293,15 @@ class OpenGLMobject:
|
|
|
1199
1293
|
grid.set_height(height)
|
|
1200
1294
|
return grid
|
|
1201
1295
|
|
|
1202
|
-
def duplicate(self, n: int):
|
|
1203
|
-
"""Returns an :class:`~.
|
|
1296
|
+
def duplicate(self, n: int) -> OpenGLGroup:
|
|
1297
|
+
"""Returns an :class:`~.OpenGLGroup` containing ``n`` copies of the mobject."""
|
|
1204
1298
|
return self.get_group_class()(*[self.copy() for _ in range(n)])
|
|
1205
1299
|
|
|
1206
|
-
def sort(
|
|
1300
|
+
def sort(
|
|
1301
|
+
self,
|
|
1302
|
+
point_to_num_func: Callable[[Point3DLike], float] = lambda p: p[0],
|
|
1303
|
+
submob_func: Callable[[OpenGLMobject], Any] | None = None,
|
|
1304
|
+
) -> Self:
|
|
1207
1305
|
"""Sorts the list of :attr:`submobjects` by a function defined by ``submob_func``."""
|
|
1208
1306
|
if submob_func is not None:
|
|
1209
1307
|
self.submobjects.sort(key=submob_func)
|
|
@@ -1211,7 +1309,7 @@ class OpenGLMobject:
|
|
|
1211
1309
|
self.submobjects.sort(key=lambda m: point_to_num_func(m.get_center()))
|
|
1212
1310
|
return self
|
|
1213
1311
|
|
|
1214
|
-
def shuffle(self, recurse=False):
|
|
1312
|
+
def shuffle(self, recurse: bool = False) -> Self:
|
|
1215
1313
|
"""Shuffles the order of :attr:`submobjects`
|
|
1216
1314
|
|
|
1217
1315
|
Examples
|
|
@@ -1234,7 +1332,7 @@ class OpenGLMobject:
|
|
|
1234
1332
|
self.assemble_family()
|
|
1235
1333
|
return self
|
|
1236
1334
|
|
|
1237
|
-
def invert(self, recursive=False):
|
|
1335
|
+
def invert(self, recursive: bool = False) -> Self:
|
|
1238
1336
|
"""Inverts the list of :attr:`submobjects`.
|
|
1239
1337
|
|
|
1240
1338
|
Parameters
|
|
@@ -1258,11 +1356,13 @@ class OpenGLMobject:
|
|
|
1258
1356
|
if recursive:
|
|
1259
1357
|
for submob in self.submobjects:
|
|
1260
1358
|
submob.invert(recursive=True)
|
|
1261
|
-
|
|
1359
|
+
self.submobjects.reverse()
|
|
1360
|
+
self.assemble_family()
|
|
1361
|
+
return self
|
|
1262
1362
|
|
|
1263
1363
|
# Copying
|
|
1264
1364
|
|
|
1265
|
-
def copy(self, shallow: bool = False):
|
|
1365
|
+
def copy(self, shallow: bool = False) -> OpenGLMobject:
|
|
1266
1366
|
"""Create and return an identical copy of the :class:`OpenGLMobject` including all
|
|
1267
1367
|
:attr:`submobjects`.
|
|
1268
1368
|
|
|
@@ -1320,14 +1420,14 @@ class OpenGLMobject:
|
|
|
1320
1420
|
# setattr(copy_mobject, attr, value.copy())
|
|
1321
1421
|
return copy_mobject
|
|
1322
1422
|
|
|
1323
|
-
def deepcopy(self):
|
|
1423
|
+
def deepcopy(self) -> OpenGLMobject:
|
|
1324
1424
|
parents = self.parents
|
|
1325
1425
|
self.parents = []
|
|
1326
1426
|
result = copy.deepcopy(self)
|
|
1327
1427
|
self.parents = parents
|
|
1328
1428
|
return result
|
|
1329
1429
|
|
|
1330
|
-
def generate_target(self, use_deepcopy: bool = False):
|
|
1430
|
+
def generate_target(self, use_deepcopy: bool = False) -> OpenGLMobject:
|
|
1331
1431
|
self.target = None # Prevent exponential explosion
|
|
1332
1432
|
if use_deepcopy:
|
|
1333
1433
|
self.target = self.deepcopy()
|
|
@@ -1335,7 +1435,7 @@ class OpenGLMobject:
|
|
|
1335
1435
|
self.target = self.copy()
|
|
1336
1436
|
return self.target
|
|
1337
1437
|
|
|
1338
|
-
def save_state(self, use_deepcopy: bool = False):
|
|
1438
|
+
def save_state(self, use_deepcopy: bool = False) -> Self:
|
|
1339
1439
|
"""Save the current state (position, color & size). Can be restored with :meth:`~.OpenGLMobject.restore`."""
|
|
1340
1440
|
if hasattr(self, "saved_state"):
|
|
1341
1441
|
# Prevent exponential growth of data
|
|
@@ -1346,7 +1446,7 @@ class OpenGLMobject:
|
|
|
1346
1446
|
self.saved_state = self.copy()
|
|
1347
1447
|
return self
|
|
1348
1448
|
|
|
1349
|
-
def restore(self):
|
|
1449
|
+
def restore(self) -> Self:
|
|
1350
1450
|
"""Restores the state that was previously saved with :meth:`~.OpenGLMobject.save_state`."""
|
|
1351
1451
|
if not hasattr(self, "saved_state") or self.save_state is None:
|
|
1352
1452
|
raise Exception("Trying to restore without having saved")
|
|
@@ -1355,13 +1455,13 @@ class OpenGLMobject:
|
|
|
1355
1455
|
|
|
1356
1456
|
# Updating
|
|
1357
1457
|
|
|
1358
|
-
def init_updaters(self):
|
|
1458
|
+
def init_updaters(self) -> None:
|
|
1359
1459
|
self.time_based_updaters = []
|
|
1360
1460
|
self.non_time_updaters = []
|
|
1361
1461
|
self.has_updaters = False
|
|
1362
1462
|
self.updating_suspended = False
|
|
1363
1463
|
|
|
1364
|
-
def update(self, dt=0, recurse=True):
|
|
1464
|
+
def update(self, dt: float = 0, recurse: bool = True) -> Self:
|
|
1365
1465
|
if not self.has_updaters or self.updating_suspended:
|
|
1366
1466
|
return self
|
|
1367
1467
|
for updater in self.time_based_updaters:
|
|
@@ -1373,19 +1473,24 @@ class OpenGLMobject:
|
|
|
1373
1473
|
submob.update(dt, recurse)
|
|
1374
1474
|
return self
|
|
1375
1475
|
|
|
1376
|
-
def get_time_based_updaters(self):
|
|
1476
|
+
def get_time_based_updaters(self) -> Sequence[TimeBasedUpdater]:
|
|
1377
1477
|
return self.time_based_updaters
|
|
1378
1478
|
|
|
1379
|
-
def has_time_based_updater(self):
|
|
1479
|
+
def has_time_based_updater(self) -> bool:
|
|
1380
1480
|
return len(self.time_based_updaters) > 0
|
|
1381
1481
|
|
|
1382
|
-
def get_updaters(self):
|
|
1482
|
+
def get_updaters(self) -> Sequence[Updater]:
|
|
1383
1483
|
return self.time_based_updaters + self.non_time_updaters
|
|
1384
1484
|
|
|
1385
|
-
def get_family_updaters(self):
|
|
1485
|
+
def get_family_updaters(self) -> Sequence[Updater]:
|
|
1386
1486
|
return list(it.chain(*(sm.get_updaters() for sm in self.get_family())))
|
|
1387
1487
|
|
|
1388
|
-
def add_updater(
|
|
1488
|
+
def add_updater(
|
|
1489
|
+
self,
|
|
1490
|
+
update_function: Updater,
|
|
1491
|
+
index: int | None = None,
|
|
1492
|
+
call_updater: bool = False,
|
|
1493
|
+
) -> Self:
|
|
1389
1494
|
if "dt" in inspect.signature(update_function).parameters:
|
|
1390
1495
|
updater_list = self.time_based_updaters
|
|
1391
1496
|
else:
|
|
@@ -1401,14 +1506,14 @@ class OpenGLMobject:
|
|
|
1401
1506
|
self.update()
|
|
1402
1507
|
return self
|
|
1403
1508
|
|
|
1404
|
-
def remove_updater(self, update_function):
|
|
1509
|
+
def remove_updater(self, update_function: Updater) -> Self:
|
|
1405
1510
|
for updater_list in [self.time_based_updaters, self.non_time_updaters]:
|
|
1406
1511
|
while update_function in updater_list:
|
|
1407
1512
|
updater_list.remove(update_function)
|
|
1408
1513
|
self.refresh_has_updater_status()
|
|
1409
1514
|
return self
|
|
1410
1515
|
|
|
1411
|
-
def clear_updaters(self, recurse=True):
|
|
1516
|
+
def clear_updaters(self, recurse: bool = True) -> Self:
|
|
1412
1517
|
self.time_based_updaters = []
|
|
1413
1518
|
self.non_time_updaters = []
|
|
1414
1519
|
self.refresh_has_updater_status()
|
|
@@ -1417,20 +1522,20 @@ class OpenGLMobject:
|
|
|
1417
1522
|
submob.clear_updaters()
|
|
1418
1523
|
return self
|
|
1419
1524
|
|
|
1420
|
-
def match_updaters(self, mobject):
|
|
1525
|
+
def match_updaters(self, mobject: OpenGLMobject) -> Self:
|
|
1421
1526
|
self.clear_updaters()
|
|
1422
1527
|
for updater in mobject.get_updaters():
|
|
1423
1528
|
self.add_updater(updater)
|
|
1424
1529
|
return self
|
|
1425
1530
|
|
|
1426
|
-
def suspend_updating(self, recurse=True):
|
|
1531
|
+
def suspend_updating(self, recurse: bool = True) -> Self:
|
|
1427
1532
|
self.updating_suspended = True
|
|
1428
1533
|
if recurse:
|
|
1429
1534
|
for submob in self.submobjects:
|
|
1430
1535
|
submob.suspend_updating(recurse)
|
|
1431
1536
|
return self
|
|
1432
1537
|
|
|
1433
|
-
def resume_updating(self, recurse=True, call_updater=True):
|
|
1538
|
+
def resume_updating(self, recurse: bool = True, call_updater: bool = True) -> Self:
|
|
1434
1539
|
self.updating_suspended = False
|
|
1435
1540
|
if recurse:
|
|
1436
1541
|
for submob in self.submobjects:
|
|
@@ -1441,13 +1546,13 @@ class OpenGLMobject:
|
|
|
1441
1546
|
self.update(dt=0, recurse=recurse)
|
|
1442
1547
|
return self
|
|
1443
1548
|
|
|
1444
|
-
def refresh_has_updater_status(self):
|
|
1549
|
+
def refresh_has_updater_status(self) -> Self:
|
|
1445
1550
|
self.has_updaters = any(mob.get_updaters() for mob in self.get_family())
|
|
1446
1551
|
return self
|
|
1447
1552
|
|
|
1448
1553
|
# Transforming operations
|
|
1449
1554
|
|
|
1450
|
-
def shift(self, vector):
|
|
1555
|
+
def shift(self, vector: Vector3D) -> Self:
|
|
1451
1556
|
self.apply_points_function(
|
|
1452
1557
|
lambda points: points + vector,
|
|
1453
1558
|
about_edge=None,
|
|
@@ -1461,7 +1566,7 @@ class OpenGLMobject:
|
|
|
1461
1566
|
about_point: Sequence[float] | None = None,
|
|
1462
1567
|
about_edge: Sequence[float] = ORIGIN,
|
|
1463
1568
|
**kwargs,
|
|
1464
|
-
) ->
|
|
1569
|
+
) -> Self:
|
|
1465
1570
|
r"""Scale the size by a factor.
|
|
1466
1571
|
|
|
1467
1572
|
Default behavior is to scale about the center of the mobject.
|
|
@@ -1480,7 +1585,7 @@ class OpenGLMobject:
|
|
|
1480
1585
|
if :math:`\alpha < 0`, the mobject is also flipped.
|
|
1481
1586
|
kwargs
|
|
1482
1587
|
Additional keyword arguments passed to
|
|
1483
|
-
:meth:`
|
|
1588
|
+
:meth:`apply_points_function`.
|
|
1484
1589
|
|
|
1485
1590
|
Returns
|
|
1486
1591
|
-------
|
|
@@ -1517,24 +1622,24 @@ class OpenGLMobject:
|
|
|
1517
1622
|
)
|
|
1518
1623
|
return self
|
|
1519
1624
|
|
|
1520
|
-
def stretch(self, factor, dim, **kwargs):
|
|
1521
|
-
def func(points):
|
|
1625
|
+
def stretch(self, factor: float, dim: int, **kwargs) -> Self:
|
|
1626
|
+
def func(points: Point3D_Array) -> Point3D_Array:
|
|
1522
1627
|
points[:, dim] *= factor
|
|
1523
1628
|
return points
|
|
1524
1629
|
|
|
1525
1630
|
self.apply_points_function(func, works_on_bounding_box=True, **kwargs)
|
|
1526
1631
|
return self
|
|
1527
1632
|
|
|
1528
|
-
def rotate_about_origin(self, angle, axis=OUT):
|
|
1633
|
+
def rotate_about_origin(self, angle: float, axis: Vector3D = OUT) -> Self:
|
|
1529
1634
|
return self.rotate(angle, axis, about_point=ORIGIN)
|
|
1530
1635
|
|
|
1531
1636
|
def rotate(
|
|
1532
1637
|
self,
|
|
1533
|
-
angle,
|
|
1534
|
-
axis=OUT,
|
|
1638
|
+
angle: float,
|
|
1639
|
+
axis: Vector3D = OUT,
|
|
1535
1640
|
about_point: Sequence[float] | None = None,
|
|
1536
1641
|
**kwargs,
|
|
1537
|
-
):
|
|
1642
|
+
) -> Self:
|
|
1538
1643
|
"""Rotates the :class:`~.OpenGLMobject` about a certain point."""
|
|
1539
1644
|
rot_matrix_T = rotation_matrix_transpose(angle, axis)
|
|
1540
1645
|
self.apply_points_function(
|
|
@@ -1544,7 +1649,7 @@ class OpenGLMobject:
|
|
|
1544
1649
|
)
|
|
1545
1650
|
return self
|
|
1546
1651
|
|
|
1547
|
-
def flip(self, axis=UP, **kwargs):
|
|
1652
|
+
def flip(self, axis: Vector3D = UP, **kwargs) -> Self:
|
|
1548
1653
|
"""Flips/Mirrors an mobject about its center.
|
|
1549
1654
|
|
|
1550
1655
|
Examples
|
|
@@ -1563,25 +1668,28 @@ class OpenGLMobject:
|
|
|
1563
1668
|
"""
|
|
1564
1669
|
return self.rotate(TAU / 2, axis, **kwargs)
|
|
1565
1670
|
|
|
1566
|
-
def apply_function(self, function, **kwargs):
|
|
1671
|
+
def apply_function(self, function: MappingFunction, **kwargs) -> Self:
|
|
1567
1672
|
# Default to applying matrix about the origin, not mobjects center
|
|
1568
1673
|
if len(kwargs) == 0:
|
|
1569
1674
|
kwargs["about_point"] = ORIGIN
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1675
|
+
|
|
1676
|
+
def multi_mapping_function(points: Point3D_Array) -> Point3D_Array:
|
|
1677
|
+
result: Point3D_Array = np.apply_along_axis(function, 1, points)
|
|
1678
|
+
return result
|
|
1679
|
+
|
|
1680
|
+
self.apply_points_function(multi_mapping_function, **kwargs)
|
|
1573
1681
|
return self
|
|
1574
1682
|
|
|
1575
|
-
def apply_function_to_position(self, function):
|
|
1683
|
+
def apply_function_to_position(self, function: MappingFunction) -> Self:
|
|
1576
1684
|
self.move_to(function(self.get_center()))
|
|
1577
1685
|
return self
|
|
1578
1686
|
|
|
1579
|
-
def apply_function_to_submobject_positions(self, function):
|
|
1687
|
+
def apply_function_to_submobject_positions(self, function: MappingFunction) -> Self:
|
|
1580
1688
|
for submob in self.submobjects:
|
|
1581
1689
|
submob.apply_function_to_position(function)
|
|
1582
1690
|
return self
|
|
1583
1691
|
|
|
1584
|
-
def apply_matrix(self, matrix, **kwargs):
|
|
1692
|
+
def apply_matrix(self, matrix: MatrixMN, **kwargs) -> Self:
|
|
1585
1693
|
# Default to applying matrix about the origin, not mobjects center
|
|
1586
1694
|
if ("about_point" not in kwargs) and ("about_edge" not in kwargs):
|
|
1587
1695
|
kwargs["about_point"] = ORIGIN
|
|
@@ -1593,7 +1701,9 @@ class OpenGLMobject:
|
|
|
1593
1701
|
)
|
|
1594
1702
|
return self
|
|
1595
1703
|
|
|
1596
|
-
def apply_complex_function(
|
|
1704
|
+
def apply_complex_function(
|
|
1705
|
+
self, function: Callable[[complex], complex], **kwargs
|
|
1706
|
+
) -> Self:
|
|
1597
1707
|
"""Applies a complex function to a :class:`OpenGLMobject`.
|
|
1598
1708
|
The x and y coordinates correspond to the real and imaginary parts respectively.
|
|
1599
1709
|
|
|
@@ -1627,7 +1737,7 @@ class OpenGLMobject:
|
|
|
1627
1737
|
|
|
1628
1738
|
return self.apply_function(R3_func)
|
|
1629
1739
|
|
|
1630
|
-
def hierarchical_model_matrix(self):
|
|
1740
|
+
def hierarchical_model_matrix(self) -> MatrixMN:
|
|
1631
1741
|
if self.parent is None:
|
|
1632
1742
|
return self.model_matrix
|
|
1633
1743
|
|
|
@@ -1638,7 +1748,12 @@ class OpenGLMobject:
|
|
|
1638
1748
|
current_object = current_object.parent
|
|
1639
1749
|
return np.linalg.multi_dot(list(reversed(model_matrices)))
|
|
1640
1750
|
|
|
1641
|
-
def wag(
|
|
1751
|
+
def wag(
|
|
1752
|
+
self,
|
|
1753
|
+
direction: Vector3D = RIGHT,
|
|
1754
|
+
axis: Vector3D = DOWN,
|
|
1755
|
+
wag_factor: float = 1.0,
|
|
1756
|
+
) -> Self:
|
|
1642
1757
|
for mob in self.family_members_with_points():
|
|
1643
1758
|
alphas = np.dot(mob.points, np.transpose(axis))
|
|
1644
1759
|
alphas -= min(alphas)
|
|
@@ -1655,12 +1770,16 @@ class OpenGLMobject:
|
|
|
1655
1770
|
|
|
1656
1771
|
# Positioning methods
|
|
1657
1772
|
|
|
1658
|
-
def center(self):
|
|
1773
|
+
def center(self) -> Self:
|
|
1659
1774
|
"""Moves the mobject to the center of the Scene."""
|
|
1660
1775
|
self.shift(-self.get_center())
|
|
1661
1776
|
return self
|
|
1662
1777
|
|
|
1663
|
-
def align_on_border(
|
|
1778
|
+
def align_on_border(
|
|
1779
|
+
self,
|
|
1780
|
+
direction: Vector3D,
|
|
1781
|
+
buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER,
|
|
1782
|
+
) -> Self:
|
|
1664
1783
|
"""
|
|
1665
1784
|
Direction just needs to be a vector pointing towards side or
|
|
1666
1785
|
corner in the 2d plane.
|
|
@@ -1676,22 +1795,30 @@ class OpenGLMobject:
|
|
|
1676
1795
|
self.shift(shift_val)
|
|
1677
1796
|
return self
|
|
1678
1797
|
|
|
1679
|
-
def to_corner(
|
|
1798
|
+
def to_corner(
|
|
1799
|
+
self,
|
|
1800
|
+
corner: Vector3D = LEFT + DOWN,
|
|
1801
|
+
buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER,
|
|
1802
|
+
) -> Self:
|
|
1680
1803
|
return self.align_on_border(corner, buff)
|
|
1681
1804
|
|
|
1682
|
-
def to_edge(
|
|
1805
|
+
def to_edge(
|
|
1806
|
+
self,
|
|
1807
|
+
edge: Vector3D = LEFT,
|
|
1808
|
+
buff: float = DEFAULT_MOBJECT_TO_EDGE_BUFFER,
|
|
1809
|
+
) -> Self:
|
|
1683
1810
|
return self.align_on_border(edge, buff)
|
|
1684
1811
|
|
|
1685
1812
|
def next_to(
|
|
1686
1813
|
self,
|
|
1687
|
-
mobject_or_point,
|
|
1688
|
-
direction=RIGHT,
|
|
1689
|
-
buff=DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
1690
|
-
aligned_edge=ORIGIN,
|
|
1691
|
-
submobject_to_align=None,
|
|
1692
|
-
index_of_submobject_to_align=None,
|
|
1693
|
-
coor_mask=np.array([1, 1, 1]),
|
|
1694
|
-
):
|
|
1814
|
+
mobject_or_point: OpenGLMobject | Point3DLike,
|
|
1815
|
+
direction: Vector3D = RIGHT,
|
|
1816
|
+
buff: float = DEFAULT_MOBJECT_TO_MOBJECT_BUFFER,
|
|
1817
|
+
aligned_edge: Vector3D = ORIGIN,
|
|
1818
|
+
submobject_to_align: OpenGLMobject | None = None,
|
|
1819
|
+
index_of_submobject_to_align: int | None = None,
|
|
1820
|
+
coor_mask: Point3DLike = np.array([1, 1, 1]),
|
|
1821
|
+
) -> Self:
|
|
1695
1822
|
"""Move this :class:`~.OpenGLMobject` next to another's :class:`~.OpenGLMobject` or coordinate.
|
|
1696
1823
|
|
|
1697
1824
|
Examples
|
|
@@ -1733,7 +1860,7 @@ class OpenGLMobject:
|
|
|
1733
1860
|
self.shift((target_point - point_to_align + buff * direction) * coor_mask)
|
|
1734
1861
|
return self
|
|
1735
1862
|
|
|
1736
|
-
def shift_onto_screen(self, **kwargs):
|
|
1863
|
+
def shift_onto_screen(self, **kwargs) -> Self:
|
|
1737
1864
|
space_lengths = [config["frame_x_radius"], config["frame_y_radius"]]
|
|
1738
1865
|
for vect in UP, DOWN, LEFT, RIGHT:
|
|
1739
1866
|
dim = np.argmax(np.abs(vect))
|
|
@@ -1744,21 +1871,21 @@ class OpenGLMobject:
|
|
|
1744
1871
|
self.to_edge(vect, **kwargs)
|
|
1745
1872
|
return self
|
|
1746
1873
|
|
|
1747
|
-
def is_off_screen(self):
|
|
1874
|
+
def is_off_screen(self) -> bool:
|
|
1748
1875
|
if self.get_left()[0] > config.frame_x_radius:
|
|
1749
1876
|
return True
|
|
1750
1877
|
if self.get_right()[0] < config.frame_x_radius:
|
|
1751
1878
|
return True
|
|
1752
1879
|
if self.get_bottom()[1] > config.frame_y_radius:
|
|
1753
1880
|
return True
|
|
1754
|
-
|
|
1755
|
-
return True
|
|
1756
|
-
return False
|
|
1881
|
+
return self.get_top()[1] < -config.frame_y_radius
|
|
1757
1882
|
|
|
1758
|
-
def stretch_about_point(self, factor, dim, point):
|
|
1883
|
+
def stretch_about_point(self, factor: float, dim: int, point: Point3DLike) -> Self:
|
|
1759
1884
|
return self.stretch(factor, dim, about_point=point)
|
|
1760
1885
|
|
|
1761
|
-
def rescale_to_fit(
|
|
1886
|
+
def rescale_to_fit(
|
|
1887
|
+
self, length: float, dim: int, stretch: bool = False, **kwargs
|
|
1888
|
+
) -> Self:
|
|
1762
1889
|
old_length = self.length_over_dim(dim)
|
|
1763
1890
|
if old_length == 0:
|
|
1764
1891
|
return self
|
|
@@ -1768,7 +1895,7 @@ class OpenGLMobject:
|
|
|
1768
1895
|
self.scale(length / old_length, **kwargs)
|
|
1769
1896
|
return self
|
|
1770
1897
|
|
|
1771
|
-
def stretch_to_fit_width(self, width, **kwargs):
|
|
1898
|
+
def stretch_to_fit_width(self, width: float, **kwargs) -> Self:
|
|
1772
1899
|
"""Stretches the :class:`~.OpenGLMobject` to fit a width, not keeping height/depth proportional.
|
|
1773
1900
|
|
|
1774
1901
|
Returns
|
|
@@ -1793,15 +1920,15 @@ class OpenGLMobject:
|
|
|
1793
1920
|
"""
|
|
1794
1921
|
return self.rescale_to_fit(width, 0, stretch=True, **kwargs)
|
|
1795
1922
|
|
|
1796
|
-
def stretch_to_fit_height(self, height, **kwargs):
|
|
1923
|
+
def stretch_to_fit_height(self, height: float, **kwargs) -> Self:
|
|
1797
1924
|
"""Stretches the :class:`~.OpenGLMobject` to fit a height, not keeping width/height proportional."""
|
|
1798
1925
|
return self.rescale_to_fit(height, 1, stretch=True, **kwargs)
|
|
1799
1926
|
|
|
1800
|
-
def stretch_to_fit_depth(self, depth, **kwargs):
|
|
1927
|
+
def stretch_to_fit_depth(self, depth: float, **kwargs) -> Self:
|
|
1801
1928
|
"""Stretches the :class:`~.OpenGLMobject` to fit a depth, not keeping width/height proportional."""
|
|
1802
1929
|
return self.rescale_to_fit(depth, 1, stretch=True, **kwargs)
|
|
1803
1930
|
|
|
1804
|
-
def set_width(self, width, stretch=False, **kwargs):
|
|
1931
|
+
def set_width(self, width: float, stretch: bool = False, **kwargs) -> Self:
|
|
1805
1932
|
"""Scales the :class:`~.OpenGLMobject` to fit a width while keeping height/depth proportional.
|
|
1806
1933
|
|
|
1807
1934
|
Returns
|
|
@@ -1828,38 +1955,38 @@ class OpenGLMobject:
|
|
|
1828
1955
|
|
|
1829
1956
|
scale_to_fit_width = set_width
|
|
1830
1957
|
|
|
1831
|
-
def set_height(self, height, stretch=False, **kwargs):
|
|
1958
|
+
def set_height(self, height: float, stretch: bool = False, **kwargs) -> Self:
|
|
1832
1959
|
"""Scales the :class:`~.OpenGLMobject` to fit a height while keeping width/depth proportional."""
|
|
1833
1960
|
return self.rescale_to_fit(height, 1, stretch=stretch, **kwargs)
|
|
1834
1961
|
|
|
1835
1962
|
scale_to_fit_height = set_height
|
|
1836
1963
|
|
|
1837
|
-
def set_depth(self, depth, stretch=False, **kwargs):
|
|
1964
|
+
def set_depth(self, depth: float, stretch: bool = False, **kwargs):
|
|
1838
1965
|
"""Scales the :class:`~.OpenGLMobject` to fit a depth while keeping width/height proportional."""
|
|
1839
1966
|
return self.rescale_to_fit(depth, 2, stretch=stretch, **kwargs)
|
|
1840
1967
|
|
|
1841
1968
|
scale_to_fit_depth = set_depth
|
|
1842
1969
|
|
|
1843
|
-
def set_coord(self, value, dim, direction=ORIGIN):
|
|
1970
|
+
def set_coord(self, value: float, dim: int, direction: Vector3D = ORIGIN) -> Self:
|
|
1844
1971
|
curr = self.get_coord(dim, direction)
|
|
1845
1972
|
shift_vect = np.zeros(self.dim)
|
|
1846
1973
|
shift_vect[dim] = value - curr
|
|
1847
1974
|
self.shift(shift_vect)
|
|
1848
1975
|
return self
|
|
1849
1976
|
|
|
1850
|
-
def set_x(self, x, direction=ORIGIN):
|
|
1977
|
+
def set_x(self, x: float, direction: Vector3D = ORIGIN) -> Self:
|
|
1851
1978
|
"""Set x value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)"""
|
|
1852
1979
|
return self.set_coord(x, 0, direction)
|
|
1853
1980
|
|
|
1854
|
-
def set_y(self, y, direction=ORIGIN):
|
|
1981
|
+
def set_y(self, y: float, direction: Vector3D = ORIGIN) -> Self:
|
|
1855
1982
|
"""Set y value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)"""
|
|
1856
1983
|
return self.set_coord(y, 1, direction)
|
|
1857
1984
|
|
|
1858
|
-
def set_z(self, z, direction=ORIGIN):
|
|
1985
|
+
def set_z(self, z: float, direction: Vector3D = ORIGIN) -> Self:
|
|
1859
1986
|
"""Set z value of the center of the :class:`~.OpenGLMobject` (``int`` or ``float``)"""
|
|
1860
1987
|
return self.set_coord(z, 2, direction)
|
|
1861
1988
|
|
|
1862
|
-
def space_out_submobjects(self, factor=1.5, **kwargs):
|
|
1989
|
+
def space_out_submobjects(self, factor: float = 1.5, **kwargs) -> Self:
|
|
1863
1990
|
self.scale(factor, **kwargs)
|
|
1864
1991
|
for submob in self.submobjects:
|
|
1865
1992
|
submob.scale(1.0 / factor)
|
|
@@ -1867,10 +1994,10 @@ class OpenGLMobject:
|
|
|
1867
1994
|
|
|
1868
1995
|
def move_to(
|
|
1869
1996
|
self,
|
|
1870
|
-
point_or_mobject,
|
|
1871
|
-
aligned_edge=ORIGIN,
|
|
1872
|
-
coor_mask=np.array([1, 1, 1]),
|
|
1873
|
-
):
|
|
1997
|
+
point_or_mobject: Point3DLike | OpenGLMobject,
|
|
1998
|
+
aligned_edge: Vector3D = ORIGIN,
|
|
1999
|
+
coor_mask: Point3DLike = np.array([1, 1, 1]),
|
|
2000
|
+
) -> Self:
|
|
1874
2001
|
"""Move center of the :class:`~.OpenGLMobject` to certain coordinate."""
|
|
1875
2002
|
if isinstance(point_or_mobject, OpenGLMobject):
|
|
1876
2003
|
target = point_or_mobject.get_bounding_box_point(aligned_edge)
|
|
@@ -1880,7 +2007,12 @@ class OpenGLMobject:
|
|
|
1880
2007
|
self.shift((target - point_to_align) * coor_mask)
|
|
1881
2008
|
return self
|
|
1882
2009
|
|
|
1883
|
-
def replace(
|
|
2010
|
+
def replace(
|
|
2011
|
+
self,
|
|
2012
|
+
mobject: OpenGLMobject,
|
|
2013
|
+
dim_to_match: int = 0,
|
|
2014
|
+
stretch: bool = False,
|
|
2015
|
+
) -> Self:
|
|
1884
2016
|
if not mobject.get_num_points() and not mobject.submobjects:
|
|
1885
2017
|
self.scale(0)
|
|
1886
2018
|
return self
|
|
@@ -1902,13 +2034,13 @@ class OpenGLMobject:
|
|
|
1902
2034
|
dim_to_match: int = 0,
|
|
1903
2035
|
stretch: bool = False,
|
|
1904
2036
|
buff: float = MED_SMALL_BUFF,
|
|
1905
|
-
):
|
|
2037
|
+
) -> Self:
|
|
1906
2038
|
self.replace(mobject, dim_to_match, stretch)
|
|
1907
2039
|
length = mobject.length_over_dim(dim_to_match)
|
|
1908
2040
|
self.scale((length + buff) / length)
|
|
1909
2041
|
return self
|
|
1910
2042
|
|
|
1911
|
-
def put_start_and_end_on(self, start, end):
|
|
2043
|
+
def put_start_and_end_on(self, start: Point3DLike, end: Point3DLike) -> Self:
|
|
1912
2044
|
curr_start, curr_end = self.get_start_and_end()
|
|
1913
2045
|
curr_vect = curr_end - curr_start
|
|
1914
2046
|
if np.all(curr_vect == 0):
|
|
@@ -1933,7 +2065,13 @@ class OpenGLMobject:
|
|
|
1933
2065
|
|
|
1934
2066
|
# Color functions
|
|
1935
2067
|
|
|
1936
|
-
def set_rgba_array(
|
|
2068
|
+
def set_rgba_array(
|
|
2069
|
+
self,
|
|
2070
|
+
color: ParsableManimColor | Iterable[ParsableManimColor] | None = None,
|
|
2071
|
+
opacity: float | Iterable[float] | None = None,
|
|
2072
|
+
name: str = "rgbas",
|
|
2073
|
+
recurse: bool = True,
|
|
2074
|
+
) -> Self:
|
|
1937
2075
|
if color is not None:
|
|
1938
2076
|
rgbs = np.array([color_to_rgb(c) for c in listify(color)])
|
|
1939
2077
|
if opacity is not None:
|
|
@@ -1963,7 +2101,12 @@ class OpenGLMobject:
|
|
|
1963
2101
|
mob.data[name] = rgbas.copy()
|
|
1964
2102
|
return self
|
|
1965
2103
|
|
|
1966
|
-
def set_rgba_array_direct(
|
|
2104
|
+
def set_rgba_array_direct(
|
|
2105
|
+
self,
|
|
2106
|
+
rgbas: npt.NDArray[RGBA_Array_Float],
|
|
2107
|
+
name: str = "rgbas",
|
|
2108
|
+
recurse: bool = True,
|
|
2109
|
+
) -> Self:
|
|
1967
2110
|
"""Directly set rgba data from `rgbas` and optionally do the same recursively
|
|
1968
2111
|
with submobjects. This can be used if the `rgbas` have already been generated
|
|
1969
2112
|
with the correct shape and simply need to be set.
|
|
@@ -1980,7 +2123,12 @@ class OpenGLMobject:
|
|
|
1980
2123
|
for mob in self.get_family(recurse):
|
|
1981
2124
|
mob.data[name] = rgbas.copy()
|
|
1982
2125
|
|
|
1983
|
-
def set_color(
|
|
2126
|
+
def set_color(
|
|
2127
|
+
self,
|
|
2128
|
+
color: ParsableManimColor | Iterable[ParsableManimColor] | None,
|
|
2129
|
+
opacity: float | Iterable[float] | None = None,
|
|
2130
|
+
recurse: bool = True,
|
|
2131
|
+
) -> Self:
|
|
1984
2132
|
self.set_rgba_array(color, opacity, recurse=False)
|
|
1985
2133
|
# Recurse to submobjects differently from how set_rgba_array
|
|
1986
2134
|
# in case they implement set_color differently
|
|
@@ -1993,24 +2141,25 @@ class OpenGLMobject:
|
|
|
1993
2141
|
submob.set_color(color, recurse=True)
|
|
1994
2142
|
return self
|
|
1995
2143
|
|
|
1996
|
-
def set_opacity(
|
|
2144
|
+
def set_opacity(
|
|
2145
|
+
self, opacity: float | Iterable[float] | None, recurse: bool = True
|
|
2146
|
+
) -> Self:
|
|
1997
2147
|
self.set_rgba_array(color=None, opacity=opacity, recurse=False)
|
|
1998
2148
|
if recurse:
|
|
1999
2149
|
for submob in self.submobjects:
|
|
2000
2150
|
submob.set_opacity(opacity, recurse=True)
|
|
2001
2151
|
return self
|
|
2002
2152
|
|
|
2003
|
-
def get_color(self):
|
|
2153
|
+
def get_color(self) -> str:
|
|
2004
2154
|
return rgb_to_hex(self.rgbas[0, :3])
|
|
2005
2155
|
|
|
2006
|
-
def get_opacity(self):
|
|
2156
|
+
def get_opacity(self) -> float:
|
|
2007
2157
|
return self.rgbas[0, 3]
|
|
2008
2158
|
|
|
2009
|
-
def set_color_by_gradient(self, *colors):
|
|
2010
|
-
self.set_submobject_colors_by_gradient(*colors)
|
|
2011
|
-
return self
|
|
2159
|
+
def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self:
|
|
2160
|
+
return self.set_submobject_colors_by_gradient(*colors)
|
|
2012
2161
|
|
|
2013
|
-
def set_submobject_colors_by_gradient(self, *colors):
|
|
2162
|
+
def set_submobject_colors_by_gradient(self, *colors: ParsableManimColor) -> Self:
|
|
2014
2163
|
if len(colors) == 0:
|
|
2015
2164
|
raise Exception("Need at least one color")
|
|
2016
2165
|
elif len(colors) == 1:
|
|
@@ -2024,21 +2173,21 @@ class OpenGLMobject:
|
|
|
2024
2173
|
mob.set_color(color)
|
|
2025
2174
|
return self
|
|
2026
2175
|
|
|
2027
|
-
def fade(self, darkness=0.5, recurse=True):
|
|
2028
|
-
self.set_opacity(1.0 - darkness, recurse=recurse)
|
|
2176
|
+
def fade(self, darkness: float = 0.5, recurse: bool = True) -> Self:
|
|
2177
|
+
return self.set_opacity(1.0 - darkness, recurse=recurse)
|
|
2029
2178
|
|
|
2030
|
-
def get_gloss(self):
|
|
2179
|
+
def get_gloss(self) -> float:
|
|
2031
2180
|
return self.gloss
|
|
2032
2181
|
|
|
2033
|
-
def set_gloss(self, gloss, recurse=True):
|
|
2182
|
+
def set_gloss(self, gloss: float, recurse: bool = True) -> Self:
|
|
2034
2183
|
for mob in self.get_family(recurse):
|
|
2035
2184
|
mob.gloss = gloss
|
|
2036
2185
|
return self
|
|
2037
2186
|
|
|
2038
|
-
def get_shadow(self):
|
|
2187
|
+
def get_shadow(self) -> float:
|
|
2039
2188
|
return self.shadow
|
|
2040
2189
|
|
|
2041
|
-
def set_shadow(self, shadow, recurse=True):
|
|
2190
|
+
def set_shadow(self, shadow: float, recurse: bool = True) -> Self:
|
|
2042
2191
|
for mob in self.get_family(recurse):
|
|
2043
2192
|
mob.shadow = shadow
|
|
2044
2193
|
return self
|
|
@@ -2046,8 +2195,11 @@ class OpenGLMobject:
|
|
|
2046
2195
|
# Background rectangle
|
|
2047
2196
|
|
|
2048
2197
|
def add_background_rectangle(
|
|
2049
|
-
self,
|
|
2050
|
-
|
|
2198
|
+
self,
|
|
2199
|
+
color: ParsableManimColor | None = None,
|
|
2200
|
+
opacity: float = 0.75,
|
|
2201
|
+
**kwargs,
|
|
2202
|
+
) -> Self:
|
|
2051
2203
|
# TODO, this does not behave well when the mobject has points,
|
|
2052
2204
|
# since it gets displayed on top
|
|
2053
2205
|
"""Add a BackgroundRectangle as submobject.
|
|
@@ -2085,39 +2237,39 @@ class OpenGLMobject:
|
|
|
2085
2237
|
self.add_to_back(self.background_rectangle)
|
|
2086
2238
|
return self
|
|
2087
2239
|
|
|
2088
|
-
def add_background_rectangle_to_submobjects(self, **kwargs):
|
|
2240
|
+
def add_background_rectangle_to_submobjects(self, **kwargs) -> Self:
|
|
2089
2241
|
for submobject in self.submobjects:
|
|
2090
2242
|
submobject.add_background_rectangle(**kwargs)
|
|
2091
2243
|
return self
|
|
2092
2244
|
|
|
2093
|
-
def add_background_rectangle_to_family_members_with_points(self, **kwargs):
|
|
2245
|
+
def add_background_rectangle_to_family_members_with_points(self, **kwargs) -> Self:
|
|
2094
2246
|
for mob in self.family_members_with_points():
|
|
2095
2247
|
mob.add_background_rectangle(**kwargs)
|
|
2096
2248
|
return self
|
|
2097
2249
|
|
|
2098
2250
|
# Getters
|
|
2099
2251
|
|
|
2100
|
-
def get_bounding_box_point(self, direction):
|
|
2252
|
+
def get_bounding_box_point(self, direction: Vector3D) -> Point3D:
|
|
2101
2253
|
bb = self.get_bounding_box()
|
|
2102
2254
|
indices = (np.sign(direction) + 1).astype(int)
|
|
2103
2255
|
return np.array([bb[indices[i]][i] for i in range(3)])
|
|
2104
2256
|
|
|
2105
|
-
def get_edge_center(self, direction) ->
|
|
2257
|
+
def get_edge_center(self, direction: Vector3D) -> Point3D:
|
|
2106
2258
|
"""Get edge coordinates for certain direction."""
|
|
2107
2259
|
return self.get_bounding_box_point(direction)
|
|
2108
2260
|
|
|
2109
|
-
def get_corner(self, direction) ->
|
|
2261
|
+
def get_corner(self, direction: Vector3D) -> Point3D:
|
|
2110
2262
|
"""Get corner coordinates for certain direction."""
|
|
2111
2263
|
return self.get_bounding_box_point(direction)
|
|
2112
2264
|
|
|
2113
|
-
def get_center(self) ->
|
|
2265
|
+
def get_center(self) -> Point3D:
|
|
2114
2266
|
"""Get center coordinates."""
|
|
2115
2267
|
return self.get_bounding_box()[1]
|
|
2116
2268
|
|
|
2117
|
-
def get_center_of_mass(self):
|
|
2269
|
+
def get_center_of_mass(self) -> Point3D:
|
|
2118
2270
|
return self.get_all_points().mean(0)
|
|
2119
2271
|
|
|
2120
|
-
def get_boundary_point(self, direction):
|
|
2272
|
+
def get_boundary_point(self, direction: Vector3D) -> Point3D:
|
|
2121
2273
|
all_points = self.get_all_points()
|
|
2122
2274
|
boundary_directions = all_points - self.get_center()
|
|
2123
2275
|
norms = np.linalg.norm(boundary_directions, axis=1)
|
|
@@ -2125,7 +2277,7 @@ class OpenGLMobject:
|
|
|
2125
2277
|
index = np.argmax(np.dot(boundary_directions, np.array(direction).T))
|
|
2126
2278
|
return all_points[index]
|
|
2127
2279
|
|
|
2128
|
-
def get_continuous_bounding_box_point(self, direction):
|
|
2280
|
+
def get_continuous_bounding_box_point(self, direction: Vector3D) -> Point3D:
|
|
2129
2281
|
dl, center, ur = self.get_bounding_box()
|
|
2130
2282
|
corner_vect = ur - center
|
|
2131
2283
|
return center + direction / np.max(
|
|
@@ -2139,86 +2291,86 @@ class OpenGLMobject:
|
|
|
2139
2291
|
),
|
|
2140
2292
|
)
|
|
2141
2293
|
|
|
2142
|
-
def get_top(self) ->
|
|
2294
|
+
def get_top(self) -> Point3D:
|
|
2143
2295
|
"""Get top coordinates of a box bounding the :class:`~.OpenGLMobject`"""
|
|
2144
2296
|
return self.get_edge_center(UP)
|
|
2145
2297
|
|
|
2146
|
-
def get_bottom(self) ->
|
|
2298
|
+
def get_bottom(self) -> Point3D:
|
|
2147
2299
|
"""Get bottom coordinates of a box bounding the :class:`~.OpenGLMobject`"""
|
|
2148
2300
|
return self.get_edge_center(DOWN)
|
|
2149
2301
|
|
|
2150
|
-
def get_right(self) ->
|
|
2302
|
+
def get_right(self) -> Point3D:
|
|
2151
2303
|
"""Get right coordinates of a box bounding the :class:`~.OpenGLMobject`"""
|
|
2152
2304
|
return self.get_edge_center(RIGHT)
|
|
2153
2305
|
|
|
2154
|
-
def get_left(self) ->
|
|
2306
|
+
def get_left(self) -> Point3D:
|
|
2155
2307
|
"""Get left coordinates of a box bounding the :class:`~.OpenGLMobject`"""
|
|
2156
2308
|
return self.get_edge_center(LEFT)
|
|
2157
2309
|
|
|
2158
|
-
def get_zenith(self) ->
|
|
2310
|
+
def get_zenith(self) -> Point3D:
|
|
2159
2311
|
"""Get zenith coordinates of a box bounding a 3D :class:`~.OpenGLMobject`."""
|
|
2160
2312
|
return self.get_edge_center(OUT)
|
|
2161
2313
|
|
|
2162
|
-
def get_nadir(self) ->
|
|
2314
|
+
def get_nadir(self) -> Point3D:
|
|
2163
2315
|
"""Get nadir (opposite the zenith) coordinates of a box bounding a 3D :class:`~.OpenGLMobject`."""
|
|
2164
2316
|
return self.get_edge_center(IN)
|
|
2165
2317
|
|
|
2166
|
-
def length_over_dim(self, dim):
|
|
2318
|
+
def length_over_dim(self, dim: int) -> float:
|
|
2167
2319
|
bb = self.get_bounding_box()
|
|
2168
2320
|
return abs((bb[2] - bb[0])[dim])
|
|
2169
2321
|
|
|
2170
|
-
def get_width(self):
|
|
2322
|
+
def get_width(self) -> float:
|
|
2171
2323
|
"""Returns the width of the mobject."""
|
|
2172
2324
|
return self.length_over_dim(0)
|
|
2173
2325
|
|
|
2174
|
-
def get_height(self):
|
|
2326
|
+
def get_height(self) -> float:
|
|
2175
2327
|
"""Returns the height of the mobject."""
|
|
2176
2328
|
return self.length_over_dim(1)
|
|
2177
2329
|
|
|
2178
|
-
def get_depth(self):
|
|
2330
|
+
def get_depth(self) -> float:
|
|
2179
2331
|
"""Returns the depth of the mobject."""
|
|
2180
2332
|
return self.length_over_dim(2)
|
|
2181
2333
|
|
|
2182
|
-
def get_coord(self, dim: int, direction=ORIGIN):
|
|
2334
|
+
def get_coord(self, dim: int, direction: Vector3D = ORIGIN) -> ManimFloat:
|
|
2183
2335
|
"""Meant to generalize ``get_x``, ``get_y`` and ``get_z``"""
|
|
2184
2336
|
return self.get_bounding_box_point(direction)[dim]
|
|
2185
2337
|
|
|
2186
|
-
def get_x(self, direction=ORIGIN) ->
|
|
2338
|
+
def get_x(self, direction: Vector3D = ORIGIN) -> ManimFloat:
|
|
2187
2339
|
"""Returns x coordinate of the center of the :class:`~.OpenGLMobject` as ``float``"""
|
|
2188
2340
|
return self.get_coord(0, direction)
|
|
2189
2341
|
|
|
2190
|
-
def get_y(self, direction=ORIGIN) ->
|
|
2342
|
+
def get_y(self, direction: Vector3D = ORIGIN) -> ManimFloat:
|
|
2191
2343
|
"""Returns y coordinate of the center of the :class:`~.OpenGLMobject` as ``float``"""
|
|
2192
2344
|
return self.get_coord(1, direction)
|
|
2193
2345
|
|
|
2194
|
-
def get_z(self, direction=ORIGIN) ->
|
|
2346
|
+
def get_z(self, direction: Vector3D = ORIGIN) -> ManimFloat:
|
|
2195
2347
|
"""Returns z coordinate of the center of the :class:`~.OpenGLMobject` as ``float``"""
|
|
2196
2348
|
return self.get_coord(2, direction)
|
|
2197
2349
|
|
|
2198
|
-
def get_start(self):
|
|
2350
|
+
def get_start(self) -> Point3D:
|
|
2199
2351
|
"""Returns the point, where the stroke that surrounds the :class:`~.OpenGLMobject` starts."""
|
|
2200
2352
|
self.throw_error_if_no_points()
|
|
2201
2353
|
return np.array(self.points[0])
|
|
2202
2354
|
|
|
2203
|
-
def get_end(self):
|
|
2355
|
+
def get_end(self) -> Point3D:
|
|
2204
2356
|
"""Returns the point, where the stroke that surrounds the :class:`~.OpenGLMobject` ends."""
|
|
2205
2357
|
self.throw_error_if_no_points()
|
|
2206
2358
|
return np.array(self.points[-1])
|
|
2207
2359
|
|
|
2208
|
-
def get_start_and_end(self):
|
|
2360
|
+
def get_start_and_end(self) -> tuple[Point3D, Point3D]:
|
|
2209
2361
|
"""Returns starting and ending point of a stroke as a ``tuple``."""
|
|
2210
2362
|
return self.get_start(), self.get_end()
|
|
2211
2363
|
|
|
2212
|
-
def point_from_proportion(self, alpha):
|
|
2364
|
+
def point_from_proportion(self, alpha: float) -> Point3D:
|
|
2213
2365
|
points = self.points
|
|
2214
2366
|
i, subalpha = integer_interpolate(0, len(points) - 1, alpha)
|
|
2215
2367
|
return interpolate(points[i], points[i + 1], subalpha)
|
|
2216
2368
|
|
|
2217
|
-
def pfp(self, alpha):
|
|
2369
|
+
def pfp(self, alpha: float) -> Point3D:
|
|
2218
2370
|
"""Abbreviation for point_from_proportion"""
|
|
2219
2371
|
return self.point_from_proportion(alpha)
|
|
2220
2372
|
|
|
2221
|
-
def get_pieces(self, n_pieces):
|
|
2373
|
+
def get_pieces(self, n_pieces: int) -> OpenGLMobject:
|
|
2222
2374
|
template = self.copy()
|
|
2223
2375
|
template.submobjects = []
|
|
2224
2376
|
alphas = np.linspace(0, 1, n_pieces + 1)
|
|
@@ -2229,34 +2381,36 @@ class OpenGLMobject:
|
|
|
2229
2381
|
)
|
|
2230
2382
|
)
|
|
2231
2383
|
|
|
2232
|
-
def get_z_index_reference_point(self):
|
|
2384
|
+
def get_z_index_reference_point(self) -> Point3D:
|
|
2233
2385
|
# TODO, better place to define default z_index_group?
|
|
2234
2386
|
z_index_group = getattr(self, "z_index_group", self)
|
|
2235
2387
|
return z_index_group.get_center()
|
|
2236
2388
|
|
|
2237
2389
|
# Match other mobject properties
|
|
2238
2390
|
|
|
2239
|
-
def match_color(self, mobject: OpenGLMobject):
|
|
2391
|
+
def match_color(self, mobject: OpenGLMobject) -> Self:
|
|
2240
2392
|
"""Match the color with the color of another :class:`~.OpenGLMobject`."""
|
|
2241
2393
|
return self.set_color(mobject.get_color())
|
|
2242
2394
|
|
|
2243
|
-
def match_dim_size(self, mobject: OpenGLMobject, dim, **kwargs):
|
|
2395
|
+
def match_dim_size(self, mobject: OpenGLMobject, dim: int, **kwargs) -> Self:
|
|
2244
2396
|
"""Match the specified dimension with the dimension of another :class:`~.OpenGLMobject`."""
|
|
2245
2397
|
return self.rescale_to_fit(mobject.length_over_dim(dim), dim, **kwargs)
|
|
2246
2398
|
|
|
2247
|
-
def match_width(self, mobject: OpenGLMobject, **kwargs):
|
|
2399
|
+
def match_width(self, mobject: OpenGLMobject, **kwargs) -> Self:
|
|
2248
2400
|
"""Match the width with the width of another :class:`~.OpenGLMobject`."""
|
|
2249
2401
|
return self.match_dim_size(mobject, 0, **kwargs)
|
|
2250
2402
|
|
|
2251
|
-
def match_height(self, mobject: OpenGLMobject, **kwargs):
|
|
2403
|
+
def match_height(self, mobject: OpenGLMobject, **kwargs) -> Self:
|
|
2252
2404
|
"""Match the height with the height of another :class:`~.OpenGLMobject`."""
|
|
2253
2405
|
return self.match_dim_size(mobject, 1, **kwargs)
|
|
2254
2406
|
|
|
2255
|
-
def match_depth(self, mobject: OpenGLMobject, **kwargs):
|
|
2407
|
+
def match_depth(self, mobject: OpenGLMobject, **kwargs) -> Self:
|
|
2256
2408
|
"""Match the depth with the depth of another :class:`~.OpenGLMobject`."""
|
|
2257
2409
|
return self.match_dim_size(mobject, 2, **kwargs)
|
|
2258
2410
|
|
|
2259
|
-
def match_coord(
|
|
2411
|
+
def match_coord(
|
|
2412
|
+
self, mobject: OpenGLMobject, dim: int, direction: Vector3D = ORIGIN
|
|
2413
|
+
) -> Self:
|
|
2260
2414
|
"""Match the coordinates with the coordinates of another :class:`~.OpenGLMobject`."""
|
|
2261
2415
|
return self.set_coord(
|
|
2262
2416
|
mobject.get_coord(dim, direction),
|
|
@@ -2264,23 +2418,23 @@ class OpenGLMobject:
|
|
|
2264
2418
|
direction=direction,
|
|
2265
2419
|
)
|
|
2266
2420
|
|
|
2267
|
-
def match_x(self, mobject, direction=ORIGIN):
|
|
2421
|
+
def match_x(self, mobject: OpenGLMobject, direction: Vector3D = ORIGIN) -> Self:
|
|
2268
2422
|
"""Match x coord. to the x coord. of another :class:`~.OpenGLMobject`."""
|
|
2269
2423
|
return self.match_coord(mobject, 0, direction)
|
|
2270
2424
|
|
|
2271
|
-
def match_y(self, mobject, direction=ORIGIN):
|
|
2425
|
+
def match_y(self, mobject: OpenGLMobject, direction: Vector3D = ORIGIN) -> Self:
|
|
2272
2426
|
"""Match y coord. to the x coord. of another :class:`~.OpenGLMobject`."""
|
|
2273
2427
|
return self.match_coord(mobject, 1, direction)
|
|
2274
2428
|
|
|
2275
|
-
def match_z(self, mobject, direction=ORIGIN):
|
|
2429
|
+
def match_z(self, mobject: OpenGLMobject, direction: Vector3D = ORIGIN) -> Self:
|
|
2276
2430
|
"""Match z coord. to the x coord. of another :class:`~.OpenGLMobject`."""
|
|
2277
2431
|
return self.match_coord(mobject, 2, direction)
|
|
2278
2432
|
|
|
2279
2433
|
def align_to(
|
|
2280
2434
|
self,
|
|
2281
|
-
mobject_or_point: OpenGLMobject |
|
|
2282
|
-
direction=ORIGIN,
|
|
2283
|
-
):
|
|
2435
|
+
mobject_or_point: OpenGLMobject | Point3DLike,
|
|
2436
|
+
direction: Vector3D = ORIGIN,
|
|
2437
|
+
) -> Self:
|
|
2284
2438
|
"""
|
|
2285
2439
|
Examples:
|
|
2286
2440
|
mob1.align_to(mob2, UP) moves mob1 vertically so that its
|
|
@@ -2300,21 +2454,22 @@ class OpenGLMobject:
|
|
|
2300
2454
|
self.set_coord(point[dim], dim, direction)
|
|
2301
2455
|
return self
|
|
2302
2456
|
|
|
2303
|
-
def get_group_class(self):
|
|
2457
|
+
def get_group_class(self) -> type[OpenGLGroup]:
|
|
2304
2458
|
return OpenGLGroup
|
|
2305
2459
|
|
|
2306
2460
|
@staticmethod
|
|
2307
|
-
def get_mobject_type_class():
|
|
2461
|
+
def get_mobject_type_class() -> type[OpenGLMobject]:
|
|
2308
2462
|
"""Return the base class of this mobject type."""
|
|
2309
2463
|
return OpenGLMobject
|
|
2310
2464
|
|
|
2311
2465
|
# Alignment
|
|
2312
2466
|
|
|
2313
|
-
def align_data_and_family(self, mobject):
|
|
2467
|
+
def align_data_and_family(self, mobject: OpenGLMobject) -> Self:
|
|
2314
2468
|
self.align_family(mobject)
|
|
2315
2469
|
self.align_data(mobject)
|
|
2470
|
+
return self
|
|
2316
2471
|
|
|
2317
|
-
def align_data(self, mobject):
|
|
2472
|
+
def align_data(self, mobject: OpenGLMobject) -> Self:
|
|
2318
2473
|
# In case any data arrays get resized when aligned to shader data
|
|
2319
2474
|
# self.refresh_shader_data()
|
|
2320
2475
|
for mob1, mob2 in zip(self.get_family(), mobject.get_family()):
|
|
@@ -2330,14 +2485,15 @@ class OpenGLMobject:
|
|
|
2330
2485
|
mob1.data[key] = resize_preserving_order(arr1, len(arr2))
|
|
2331
2486
|
elif len(arr1) > len(arr2):
|
|
2332
2487
|
mob2.data[key] = resize_preserving_order(arr2, len(arr1))
|
|
2488
|
+
return self
|
|
2333
2489
|
|
|
2334
|
-
def align_points(self, mobject):
|
|
2490
|
+
def align_points(self, mobject: OpenGLMobject) -> Self:
|
|
2335
2491
|
max_len = max(self.get_num_points(), mobject.get_num_points())
|
|
2336
2492
|
for mob in (self, mobject):
|
|
2337
2493
|
mob.resize_points(max_len, resize_func=resize_preserving_order)
|
|
2338
2494
|
return self
|
|
2339
2495
|
|
|
2340
|
-
def align_family(self, mobject):
|
|
2496
|
+
def align_family(self, mobject: OpenGLMobject) -> Self:
|
|
2341
2497
|
mob1 = self
|
|
2342
2498
|
mob2 = mobject
|
|
2343
2499
|
n1 = len(mob1)
|
|
@@ -2350,14 +2506,14 @@ class OpenGLMobject:
|
|
|
2350
2506
|
sm1.align_family(sm2)
|
|
2351
2507
|
return self
|
|
2352
2508
|
|
|
2353
|
-
def push_self_into_submobjects(self):
|
|
2509
|
+
def push_self_into_submobjects(self) -> Self:
|
|
2354
2510
|
copy = self.deepcopy()
|
|
2355
2511
|
copy.submobjects = []
|
|
2356
2512
|
self.resize_points(0)
|
|
2357
2513
|
self.add(copy)
|
|
2358
2514
|
return self
|
|
2359
2515
|
|
|
2360
|
-
def add_n_more_submobjects(self, n):
|
|
2516
|
+
def add_n_more_submobjects(self, n: int) -> Self:
|
|
2361
2517
|
if n == 0:
|
|
2362
2518
|
return self
|
|
2363
2519
|
|
|
@@ -2386,7 +2542,13 @@ class OpenGLMobject:
|
|
|
2386
2542
|
|
|
2387
2543
|
# Interpolate
|
|
2388
2544
|
|
|
2389
|
-
def interpolate(
|
|
2545
|
+
def interpolate(
|
|
2546
|
+
self,
|
|
2547
|
+
mobject1: OpenGLMobject,
|
|
2548
|
+
mobject2: OpenGLMobject,
|
|
2549
|
+
alpha: float,
|
|
2550
|
+
path_func: PathFuncType = straight_path(),
|
|
2551
|
+
) -> Self:
|
|
2390
2552
|
"""Turns this :class:`~.OpenGLMobject` into an interpolation between ``mobject1``
|
|
2391
2553
|
and ``mobject2``.
|
|
2392
2554
|
|
|
@@ -2415,10 +2577,7 @@ class OpenGLMobject:
|
|
|
2415
2577
|
if key not in mobject1.data or key not in mobject2.data:
|
|
2416
2578
|
continue
|
|
2417
2579
|
|
|
2418
|
-
if key in ("points", "bounding_box")
|
|
2419
|
-
func = path_func
|
|
2420
|
-
else:
|
|
2421
|
-
func = interpolate
|
|
2580
|
+
func = path_func if key in ("points", "bounding_box") else interpolate
|
|
2422
2581
|
|
|
2423
2582
|
self.data[key][:] = func(mobject1.data[key], mobject2.data[key], alpha)
|
|
2424
2583
|
|
|
@@ -2439,7 +2598,9 @@ class OpenGLMobject:
|
|
|
2439
2598
|
)
|
|
2440
2599
|
return self
|
|
2441
2600
|
|
|
2442
|
-
def pointwise_become_partial(
|
|
2601
|
+
def pointwise_become_partial(
|
|
2602
|
+
self, mobject: OpenGLMobject, a: float, b: float
|
|
2603
|
+
) -> None:
|
|
2443
2604
|
"""
|
|
2444
2605
|
Set points in such a way as to become only
|
|
2445
2606
|
part of mobject.
|
|
@@ -2456,7 +2617,7 @@ class OpenGLMobject:
|
|
|
2456
2617
|
match_depth: bool = False,
|
|
2457
2618
|
match_center: bool = False,
|
|
2458
2619
|
stretch: bool = False,
|
|
2459
|
-
):
|
|
2620
|
+
) -> Self:
|
|
2460
2621
|
"""Edit all data and submobjects to be identical
|
|
2461
2622
|
to another :class:`~.OpenGLMobject`
|
|
2462
2623
|
|
|
@@ -2491,7 +2652,6 @@ class OpenGLMobject:
|
|
|
2491
2652
|
circ.become(square)
|
|
2492
2653
|
self.wait(0.5)
|
|
2493
2654
|
"""
|
|
2494
|
-
|
|
2495
2655
|
if stretch:
|
|
2496
2656
|
mobject.stretch_to_fit_height(self.height)
|
|
2497
2657
|
mobject.stretch_to_fit_width(self.width)
|
|
@@ -2516,7 +2676,7 @@ class OpenGLMobject:
|
|
|
2516
2676
|
|
|
2517
2677
|
# Locking data
|
|
2518
2678
|
|
|
2519
|
-
def lock_data(self, keys):
|
|
2679
|
+
def lock_data(self, keys: Iterable[str]) -> None:
|
|
2520
2680
|
"""
|
|
2521
2681
|
To speed up some animations, particularly transformations,
|
|
2522
2682
|
it can be handy to acknowledge which pieces of data
|
|
@@ -2530,7 +2690,9 @@ class OpenGLMobject:
|
|
|
2530
2690
|
self.refresh_shader_data()
|
|
2531
2691
|
self.locked_data_keys = set(keys)
|
|
2532
2692
|
|
|
2533
|
-
def lock_matching_data(
|
|
2693
|
+
def lock_matching_data(
|
|
2694
|
+
self, mobject1: OpenGLMobject, mobject2: OpenGLMobject
|
|
2695
|
+
) -> Self:
|
|
2534
2696
|
for sm, sm1, sm2 in zip(
|
|
2535
2697
|
self.get_family(),
|
|
2536
2698
|
mobject1.get_family(),
|
|
@@ -2547,57 +2709,57 @@ class OpenGLMobject:
|
|
|
2547
2709
|
)
|
|
2548
2710
|
return self
|
|
2549
2711
|
|
|
2550
|
-
def unlock_data(self):
|
|
2712
|
+
def unlock_data(self) -> None:
|
|
2551
2713
|
for mob in self.get_family():
|
|
2552
2714
|
mob.locked_data_keys = set()
|
|
2553
2715
|
|
|
2554
2716
|
# Operations touching shader uniforms
|
|
2555
2717
|
|
|
2556
2718
|
@affects_shader_info_id
|
|
2557
|
-
def fix_in_frame(self):
|
|
2719
|
+
def fix_in_frame(self) -> Self:
|
|
2558
2720
|
self.is_fixed_in_frame = 1.0
|
|
2559
2721
|
return self
|
|
2560
2722
|
|
|
2561
2723
|
@affects_shader_info_id
|
|
2562
|
-
def fix_orientation(self):
|
|
2724
|
+
def fix_orientation(self) -> Self:
|
|
2563
2725
|
self.is_fixed_orientation = 1.0
|
|
2564
2726
|
self.fixed_orientation_center = tuple(self.get_center())
|
|
2565
2727
|
self.depth_test = True
|
|
2566
2728
|
return self
|
|
2567
2729
|
|
|
2568
2730
|
@affects_shader_info_id
|
|
2569
|
-
def unfix_from_frame(self):
|
|
2731
|
+
def unfix_from_frame(self) -> Self:
|
|
2570
2732
|
self.is_fixed_in_frame = 0.0
|
|
2571
2733
|
return self
|
|
2572
2734
|
|
|
2573
2735
|
@affects_shader_info_id
|
|
2574
|
-
def unfix_orientation(self):
|
|
2736
|
+
def unfix_orientation(self) -> Self:
|
|
2575
2737
|
self.is_fixed_orientation = 0.0
|
|
2576
2738
|
self.fixed_orientation_center = (0, 0, 0)
|
|
2577
2739
|
self.depth_test = False
|
|
2578
2740
|
return self
|
|
2579
2741
|
|
|
2580
2742
|
@affects_shader_info_id
|
|
2581
|
-
def apply_depth_test(self):
|
|
2743
|
+
def apply_depth_test(self) -> Self:
|
|
2582
2744
|
self.depth_test = True
|
|
2583
2745
|
return self
|
|
2584
2746
|
|
|
2585
2747
|
@affects_shader_info_id
|
|
2586
|
-
def deactivate_depth_test(self):
|
|
2748
|
+
def deactivate_depth_test(self) -> Self:
|
|
2587
2749
|
self.depth_test = False
|
|
2588
2750
|
return self
|
|
2589
2751
|
|
|
2590
2752
|
# Shader code manipulation
|
|
2591
2753
|
|
|
2592
|
-
def replace_shader_code(self,
|
|
2754
|
+
def replace_shader_code(self, old_code: str, new_code: str) -> Self:
|
|
2593
2755
|
# TODO, will this work with VMobject structure, given
|
|
2594
2756
|
# that it does not simpler return shader_wrappers of
|
|
2595
2757
|
# family?
|
|
2596
2758
|
for wrapper in self.get_shader_wrapper_list():
|
|
2597
|
-
wrapper.replace_code(
|
|
2759
|
+
wrapper.replace_code(old_code, new_code)
|
|
2598
2760
|
return self
|
|
2599
2761
|
|
|
2600
|
-
def set_color_by_code(self, glsl_code):
|
|
2762
|
+
def set_color_by_code(self, glsl_code: str) -> Self:
|
|
2601
2763
|
"""
|
|
2602
2764
|
Takes a snippet of code and inserts it into a
|
|
2603
2765
|
context which has the following variables:
|
|
@@ -2609,11 +2771,11 @@ class OpenGLMobject:
|
|
|
2609
2771
|
|
|
2610
2772
|
def set_color_by_xyz_func(
|
|
2611
2773
|
self,
|
|
2612
|
-
glsl_snippet,
|
|
2613
|
-
min_value
|
|
2614
|
-
max_value=5.0,
|
|
2615
|
-
colormap="viridis",
|
|
2616
|
-
):
|
|
2774
|
+
glsl_snippet: str,
|
|
2775
|
+
min_value: float = -5.0,
|
|
2776
|
+
max_value: float = 5.0,
|
|
2777
|
+
colormap: str = "viridis",
|
|
2778
|
+
) -> Self:
|
|
2617
2779
|
"""
|
|
2618
2780
|
Pass in a glsl expression in terms of x, y and z which returns
|
|
2619
2781
|
a float.
|
|
@@ -2624,22 +2786,17 @@ class OpenGLMobject:
|
|
|
2624
2786
|
glsl_snippet = glsl_snippet.replace(char, "point." + char)
|
|
2625
2787
|
rgb_list = get_colormap_list(colormap)
|
|
2626
2788
|
self.set_color_by_code(
|
|
2627
|
-
"color.rgb = float_to_color({}, {}, {}, {});"
|
|
2628
|
-
glsl_snippet,
|
|
2629
|
-
float(min_value),
|
|
2630
|
-
float(max_value),
|
|
2631
|
-
get_colormap_code(rgb_list),
|
|
2632
|
-
),
|
|
2789
|
+
f"color.rgb = float_to_color({glsl_snippet}, {float(min_value)}, {float(max_value)}, {get_colormap_code(rgb_list)});",
|
|
2633
2790
|
)
|
|
2634
2791
|
return self
|
|
2635
2792
|
|
|
2636
2793
|
# For shader data
|
|
2637
2794
|
|
|
2638
|
-
def refresh_shader_wrapper_id(self):
|
|
2795
|
+
def refresh_shader_wrapper_id(self) -> Self:
|
|
2639
2796
|
self.get_shader_wrapper().refresh_id()
|
|
2640
2797
|
return self
|
|
2641
2798
|
|
|
2642
|
-
def get_shader_wrapper(self):
|
|
2799
|
+
def get_shader_wrapper(self) -> ShaderWrapper:
|
|
2643
2800
|
from manim.renderer.shader_wrapper import ShaderWrapper
|
|
2644
2801
|
|
|
2645
2802
|
# if hasattr(self, "__shader_wrapper"):
|
|
@@ -2656,7 +2813,7 @@ class OpenGLMobject:
|
|
|
2656
2813
|
)
|
|
2657
2814
|
return self.shader_wrapper
|
|
2658
2815
|
|
|
2659
|
-
def get_shader_wrapper_list(self):
|
|
2816
|
+
def get_shader_wrapper_list(self) -> Sequence[ShaderWrapper]:
|
|
2660
2817
|
shader_wrappers = it.chain(
|
|
2661
2818
|
[self.get_shader_wrapper()],
|
|
2662
2819
|
*(sm.get_shader_wrapper_list() for sm in self.submobjects),
|
|
@@ -2673,7 +2830,7 @@ class OpenGLMobject:
|
|
|
2673
2830
|
result.append(shader_wrapper)
|
|
2674
2831
|
return result
|
|
2675
2832
|
|
|
2676
|
-
def check_data_alignment(self, array, data_key):
|
|
2833
|
+
def check_data_alignment(self, array: npt.NDArray, data_key: str) -> Self:
|
|
2677
2834
|
# Makes sure that self.data[key] can be broadcast into
|
|
2678
2835
|
# the given array, meaning its length has to be either 1
|
|
2679
2836
|
# or the length of the array
|
|
@@ -2685,45 +2842,50 @@ class OpenGLMobject:
|
|
|
2685
2842
|
)
|
|
2686
2843
|
return self
|
|
2687
2844
|
|
|
2688
|
-
def get_resized_shader_data_array(self, length):
|
|
2845
|
+
def get_resized_shader_data_array(self, length: float) -> npt.NDArray:
|
|
2689
2846
|
# If possible, try to populate an existing array, rather
|
|
2690
2847
|
# than recreating it each frame
|
|
2691
2848
|
points = self.points
|
|
2692
2849
|
shader_data = np.zeros(len(points), dtype=self.shader_dtype)
|
|
2693
2850
|
return shader_data
|
|
2694
2851
|
|
|
2695
|
-
def read_data_to_shader(
|
|
2852
|
+
def read_data_to_shader(
|
|
2853
|
+
self,
|
|
2854
|
+
shader_data: npt.NDArray, # has structured data type, ex. ("point", np.float32, (3,))
|
|
2855
|
+
shader_data_key: str,
|
|
2856
|
+
data_key: str,
|
|
2857
|
+
) -> None:
|
|
2696
2858
|
if data_key in self.locked_data_keys:
|
|
2697
2859
|
return
|
|
2698
2860
|
self.check_data_alignment(shader_data, data_key)
|
|
2699
2861
|
shader_data[shader_data_key] = self.data[data_key]
|
|
2700
2862
|
|
|
2701
|
-
def get_shader_data(self):
|
|
2863
|
+
def get_shader_data(self) -> npt.NDArray:
|
|
2702
2864
|
shader_data = self.get_resized_shader_data_array(self.get_num_points())
|
|
2703
2865
|
self.read_data_to_shader(shader_data, "point", "points")
|
|
2704
2866
|
return shader_data
|
|
2705
2867
|
|
|
2706
|
-
def refresh_shader_data(self):
|
|
2868
|
+
def refresh_shader_data(self) -> None:
|
|
2707
2869
|
self.get_shader_data()
|
|
2708
2870
|
|
|
2709
|
-
def get_shader_uniforms(self):
|
|
2871
|
+
def get_shader_uniforms(self) -> dict[str, Any]:
|
|
2710
2872
|
return self.uniforms
|
|
2711
2873
|
|
|
2712
|
-
def get_shader_vert_indices(self):
|
|
2874
|
+
def get_shader_vert_indices(self) -> Sequence[int]:
|
|
2713
2875
|
return self.shader_indices
|
|
2714
2876
|
|
|
2715
2877
|
@property
|
|
2716
|
-
def submobjects(self):
|
|
2878
|
+
def submobjects(self) -> Sequence[OpenGLMobject]:
|
|
2717
2879
|
return self._submobjects if hasattr(self, "_submobjects") else []
|
|
2718
2880
|
|
|
2719
2881
|
@submobjects.setter
|
|
2720
|
-
def submobjects(self, submobject_list):
|
|
2882
|
+
def submobjects(self, submobject_list: Iterable[OpenGLMobject]) -> None:
|
|
2721
2883
|
self.remove(*self.submobjects)
|
|
2722
2884
|
self.add(*submobject_list)
|
|
2723
2885
|
|
|
2724
2886
|
# Errors
|
|
2725
2887
|
|
|
2726
|
-
def throw_error_if_no_points(self):
|
|
2888
|
+
def throw_error_if_no_points(self) -> None:
|
|
2727
2889
|
if not self.has_points():
|
|
2728
2890
|
message = (
|
|
2729
2891
|
"Cannot call OpenGLMobject.{} " + "for a OpenGLMobject with no points"
|
|
@@ -2733,40 +2895,42 @@ class OpenGLMobject:
|
|
|
2733
2895
|
|
|
2734
2896
|
|
|
2735
2897
|
class OpenGLGroup(OpenGLMobject):
|
|
2736
|
-
def __init__(self, *mobjects, **kwargs):
|
|
2737
|
-
if not all(isinstance(m, OpenGLMobject) for m in mobjects):
|
|
2738
|
-
raise Exception("All submobjects must be of type OpenGLMobject")
|
|
2898
|
+
def __init__(self, *mobjects: OpenGLMobject, **kwargs):
|
|
2739
2899
|
super().__init__(**kwargs)
|
|
2740
2900
|
self.add(*mobjects)
|
|
2741
2901
|
|
|
2742
2902
|
|
|
2743
2903
|
class OpenGLPoint(OpenGLMobject):
|
|
2744
2904
|
def __init__(
|
|
2745
|
-
self,
|
|
2905
|
+
self,
|
|
2906
|
+
location: Point3DLike = ORIGIN,
|
|
2907
|
+
artificial_width: float = 1e-6,
|
|
2908
|
+
artificial_height: float = 1e-6,
|
|
2909
|
+
**kwargs,
|
|
2746
2910
|
):
|
|
2747
2911
|
self.artificial_width = artificial_width
|
|
2748
2912
|
self.artificial_height = artificial_height
|
|
2749
2913
|
super().__init__(**kwargs)
|
|
2750
2914
|
self.set_location(location)
|
|
2751
2915
|
|
|
2752
|
-
def get_width(self):
|
|
2916
|
+
def get_width(self) -> float:
|
|
2753
2917
|
return self.artificial_width
|
|
2754
2918
|
|
|
2755
|
-
def get_height(self):
|
|
2919
|
+
def get_height(self) -> float:
|
|
2756
2920
|
return self.artificial_height
|
|
2757
2921
|
|
|
2758
|
-
def get_location(self):
|
|
2922
|
+
def get_location(self) -> Point3D:
|
|
2759
2923
|
return self.points[0].copy()
|
|
2760
2924
|
|
|
2761
|
-
def get_bounding_box_point(self, *args, **kwargs):
|
|
2925
|
+
def get_bounding_box_point(self, *args, **kwargs) -> Point3D:
|
|
2762
2926
|
return self.get_location()
|
|
2763
2927
|
|
|
2764
|
-
def set_location(self, new_loc):
|
|
2928
|
+
def set_location(self, new_loc: Point3D) -> None:
|
|
2765
2929
|
self.set_points(np.array(new_loc, ndmin=2, dtype=float))
|
|
2766
2930
|
|
|
2767
2931
|
|
|
2768
2932
|
class _AnimationBuilder:
|
|
2769
|
-
def __init__(self, mobject):
|
|
2933
|
+
def __init__(self, mobject: OpenGLMobject):
|
|
2770
2934
|
self.mobject = mobject
|
|
2771
2935
|
self.mobject.generate_target()
|
|
2772
2936
|
|
|
@@ -2778,7 +2942,7 @@ class _AnimationBuilder:
|
|
|
2778
2942
|
self.cannot_pass_args = False
|
|
2779
2943
|
self.anim_args = {}
|
|
2780
2944
|
|
|
2781
|
-
def __call__(self, **kwargs):
|
|
2945
|
+
def __call__(self, **kwargs) -> Self:
|
|
2782
2946
|
if self.cannot_pass_args:
|
|
2783
2947
|
raise ValueError(
|
|
2784
2948
|
"Animation arguments must be passed before accessing methods and can only be passed once",
|
|
@@ -2789,14 +2953,13 @@ class _AnimationBuilder:
|
|
|
2789
2953
|
|
|
2790
2954
|
return self
|
|
2791
2955
|
|
|
2792
|
-
def __getattr__(self, method_name):
|
|
2956
|
+
def __getattr__(self, method_name: str) -> Callable[..., Self]:
|
|
2793
2957
|
method = getattr(self.mobject.target, method_name)
|
|
2794
2958
|
has_overridden_animation = hasattr(method, "_override_animate")
|
|
2795
2959
|
|
|
2796
2960
|
if (self.is_chaining and has_overridden_animation) or self.overridden_animation:
|
|
2797
2961
|
raise NotImplementedError(
|
|
2798
|
-
"Method chaining is currently not supported for "
|
|
2799
|
-
"overridden animations",
|
|
2962
|
+
"Method chaining is currently not supported for overridden animations",
|
|
2800
2963
|
)
|
|
2801
2964
|
|
|
2802
2965
|
def update_target(*method_args, **method_kwargs):
|
|
@@ -2817,7 +2980,7 @@ class _AnimationBuilder:
|
|
|
2817
2980
|
|
|
2818
2981
|
return update_target
|
|
2819
2982
|
|
|
2820
|
-
def build(self):
|
|
2983
|
+
def build(self) -> _MethodAnimation:
|
|
2821
2984
|
from manim.animation.transform import _MethodAnimation
|
|
2822
2985
|
|
|
2823
2986
|
if self.overridden_animation:
|
|
@@ -2831,7 +2994,7 @@ class _AnimationBuilder:
|
|
|
2831
2994
|
return anim
|
|
2832
2995
|
|
|
2833
2996
|
|
|
2834
|
-
def override_animate(method):
|
|
2997
|
+
def override_animate(method: types.FunctionType) -> types.FunctionType:
|
|
2835
2998
|
r"""Decorator for overriding method animations.
|
|
2836
2999
|
|
|
2837
3000
|
This allows to specify a method (returning an :class:`~.Animation`)
|