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