manim 0.17.0__py3-none-any.whl → 0.19.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- manim/__init__.py +11 -6
- manim/__main__.py +62 -19
- manim/_config/__init__.py +10 -9
- manim/_config/cli_colors.py +26 -9
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +23 -13
- manim/_config/utils.py +662 -468
- manim/animation/animation.py +164 -18
- manim/animation/changing.py +34 -23
- manim/animation/composition.py +265 -67
- manim/animation/creation.py +208 -26
- manim/animation/fading.py +16 -18
- manim/animation/growing.py +35 -15
- manim/animation/indication.py +150 -76
- manim/animation/movement.py +56 -22
- manim/animation/numbers.py +64 -6
- manim/animation/rotation.py +78 -7
- manim/animation/specialized.py +6 -7
- manim/animation/speedmodifier.py +13 -10
- manim/animation/transform.py +14 -11
- manim/animation/transform_matching_parts.py +3 -4
- manim/animation/updaters/mobject_update_utils.py +152 -30
- manim/animation/updaters/update.py +10 -7
- manim/camera/camera.py +182 -118
- manim/camera/mapping_camera.py +34 -3
- manim/camera/moving_camera.py +95 -74
- manim/camera/multi_camera.py +23 -15
- manim/camera/three_d_camera.py +70 -52
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +76 -44
- manim/cli/checkhealth/checks.py +192 -0
- manim/cli/checkhealth/commands.py +90 -0
- manim/cli/default_group.py +158 -25
- manim/cli/init/commands.py +33 -25
- 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 +59 -17
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +98 -33
- manim/constants.py +109 -59
- manim/data_structures.py +31 -0
- manim/mobject/frame.py +8 -5
- manim/mobject/geometry/__init__.py +1 -0
- manim/mobject/geometry/arc.py +277 -135
- manim/mobject/geometry/boolean_ops.py +32 -31
- manim/mobject/geometry/labeled.py +376 -0
- manim/mobject/geometry/line.py +192 -87
- manim/mobject/geometry/polygram.py +224 -58
- manim/mobject/geometry/shape_matchers.py +61 -25
- manim/mobject/geometry/tips.py +122 -48
- manim/mobject/graph.py +1027 -419
- manim/mobject/graphing/coordinate_systems.py +533 -278
- manim/mobject/graphing/functions.py +53 -32
- manim/mobject/graphing/number_line.py +123 -65
- manim/mobject/graphing/probability.py +88 -62
- manim/mobject/graphing/scale.py +33 -19
- manim/mobject/logo.py +118 -28
- manim/mobject/matrix.py +87 -83
- manim/mobject/mobject.py +912 -442
- manim/mobject/opengl/dot_cloud.py +16 -5
- manim/mobject/opengl/opengl_compatibility.py +4 -2
- manim/mobject/opengl/opengl_geometry.py +254 -153
- manim/mobject/opengl/opengl_image_mobject.py +3 -1
- manim/mobject/opengl/opengl_mobject.py +779 -482
- manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
- manim/mobject/opengl/opengl_surface.py +14 -92
- manim/mobject/opengl/opengl_three_dimensions.py +12 -8
- manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
- manim/mobject/svg/brace.py +173 -41
- manim/mobject/svg/svg_mobject.py +139 -53
- manim/mobject/table.py +61 -68
- manim/mobject/text/code_mobject.py +193 -539
- manim/mobject/text/numbers.py +81 -34
- manim/mobject/text/tex_mobject.py +130 -78
- manim/mobject/text/text_mobject.py +288 -164
- manim/mobject/three_d/polyhedra.py +111 -13
- manim/mobject/three_d/three_d_utils.py +17 -8
- manim/mobject/three_d/three_dimensions.py +239 -106
- manim/mobject/types/image_mobject.py +50 -30
- manim/mobject/types/point_cloud_mobject.py +120 -75
- manim/mobject/types/vectorized_mobject.py +841 -408
- manim/mobject/value_tracker.py +105 -38
- manim/mobject/vector_field.py +50 -31
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +10 -14
- manim/renderer/cairo_renderer.py +65 -50
- manim/renderer/opengl_renderer.py +89 -69
- manim/renderer/opengl_renderer_window.py +39 -18
- manim/renderer/shader.py +123 -87
- manim/renderer/shader_wrapper.py +44 -28
- manim/renderer/vectorized_mobject_rendering.py +38 -10
- manim/scene/moving_camera_scene.py +32 -3
- manim/scene/scene.py +507 -242
- manim/scene/scene_file_writer.py +371 -220
- manim/scene/section.py +20 -16
- manim/scene/three_d_scene.py +14 -22
- manim/scene/vector_space_scene.py +223 -129
- manim/scene/zoomed_scene.py +46 -41
- manim/typing.py +990 -0
- manim/utils/bezier.py +1823 -371
- manim/utils/caching.py +12 -5
- manim/utils/color/AS2700.py +236 -0
- manim/utils/color/BS381.py +318 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +533 -0
- manim/utils/color/XKCD.py +952 -0
- manim/utils/color/__init__.py +61 -0
- manim/utils/color/core.py +1667 -0
- manim/utils/color/manim_colors.py +218 -0
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +39 -19
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +86 -39
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +236 -0
- manim/utils/docbuild/autocolor_directive.py +99 -0
- manim/utils/docbuild/manim_directive.py +94 -41
- 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 +27 -17
- manim/utils/hashing.py +55 -45
- manim/utils/images.py +13 -7
- manim/utils/ipython_magic.py +13 -7
- manim/utils/iterables.py +163 -120
- manim/utils/module_ops.py +66 -24
- manim/utils/opengl.py +77 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +30 -33
- manim/utils/polylabel.py +235 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +98 -32
- manim/utils/simple_functions.py +25 -33
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +188 -115
- 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 +34 -18
- manim/utils/testing/frames_comparison.py +37 -19
- manim/utils/tex.py +130 -198
- manim/utils/tex_file_writing.py +77 -47
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
- manim-0.19.1.dist-info/RECORD +220 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
- manim-0.19.1.dist-info/entry_points.txt +3 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
- manim/cli/new/group.py +0 -189
- manim/communitycolors.py +0 -9
- manim/gui/__init__.py +0 -0
- manim/gui/gui.py +0 -82
- manim/plugins/import_plugins.py +0 -43
- manim/utils/color.py +0 -552
- manim-0.17.0.dist-info/RECORD +0 -206
- manim-0.17.0.dist-info/entry_points.txt +0 -4
- /manim/cli/{new → checkhealth}/__init__.py +0 -0
- {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE +0 -0
|
@@ -5,8 +5,8 @@ from __future__ import annotations
|
|
|
5
5
|
__all__ = ["AbstractImageMobject", "ImageMobject", "ImageMobjectFromCamera"]
|
|
6
6
|
|
|
7
7
|
import pathlib
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
8
9
|
|
|
9
|
-
import colour
|
|
10
10
|
import numpy as np
|
|
11
11
|
from PIL import Image
|
|
12
12
|
from PIL.Image import Resampling
|
|
@@ -14,12 +14,23 @@ from PIL.Image import Resampling
|
|
|
14
14
|
from manim.mobject.geometry.shape_matchers import SurroundingRectangle
|
|
15
15
|
|
|
16
16
|
from ... import config
|
|
17
|
+
from ...camera.moving_camera import MovingCamera
|
|
17
18
|
from ...constants import *
|
|
18
19
|
from ...mobject.mobject import Mobject
|
|
19
20
|
from ...utils.bezier import interpolate
|
|
20
|
-
from ...utils.color import WHITE, color_to_int_rgb
|
|
21
|
+
from ...utils.color import WHITE, ManimColor, color_to_int_rgb
|
|
21
22
|
from ...utils.images import change_to_rgba_array, get_full_raster_image_path
|
|
22
23
|
|
|
24
|
+
__all__ = ["ImageMobject", "ImageMobjectFromCamera"]
|
|
25
|
+
|
|
26
|
+
if TYPE_CHECKING:
|
|
27
|
+
import numpy.typing as npt
|
|
28
|
+
from typing_extensions import Self
|
|
29
|
+
|
|
30
|
+
from manim.typing import PixelArray, StrPath
|
|
31
|
+
|
|
32
|
+
from ...camera.moving_camera import MovingCamera
|
|
33
|
+
|
|
23
34
|
|
|
24
35
|
class AbstractImageMobject(Mobject):
|
|
25
36
|
"""
|
|
@@ -38,23 +49,23 @@ class AbstractImageMobject(Mobject):
|
|
|
38
49
|
def __init__(
|
|
39
50
|
self,
|
|
40
51
|
scale_to_resolution: int,
|
|
41
|
-
pixel_array_dtype="uint8",
|
|
42
|
-
resampling_algorithm=Resampling.BICUBIC,
|
|
43
|
-
**kwargs,
|
|
44
|
-
):
|
|
52
|
+
pixel_array_dtype: str = "uint8",
|
|
53
|
+
resampling_algorithm: Resampling = Resampling.BICUBIC,
|
|
54
|
+
**kwargs: Any,
|
|
55
|
+
) -> None:
|
|
45
56
|
self.pixel_array_dtype = pixel_array_dtype
|
|
46
57
|
self.scale_to_resolution = scale_to_resolution
|
|
47
58
|
self.set_resampling_algorithm(resampling_algorithm)
|
|
48
59
|
super().__init__(**kwargs)
|
|
49
60
|
|
|
50
|
-
def get_pixel_array(self):
|
|
61
|
+
def get_pixel_array(self) -> PixelArray:
|
|
51
62
|
raise NotImplementedError()
|
|
52
63
|
|
|
53
64
|
def set_color(self, color, alpha=None, family=True):
|
|
54
65
|
# Likely to be implemented in subclasses, but no obligation
|
|
55
66
|
pass
|
|
56
67
|
|
|
57
|
-
def set_resampling_algorithm(self, resampling_algorithm: int):
|
|
68
|
+
def set_resampling_algorithm(self, resampling_algorithm: int) -> Self:
|
|
58
69
|
"""
|
|
59
70
|
Sets the interpolation method for upscaling the image. By default the image is
|
|
60
71
|
interpolated using bicubic algorithm. This method lets you change it.
|
|
@@ -84,14 +95,16 @@ class AbstractImageMobject(Mobject):
|
|
|
84
95
|
"Available algorithms: 'bicubic', 'nearest', 'box', 'bilinear', "
|
|
85
96
|
"'hamming', 'lanczos'.",
|
|
86
97
|
)
|
|
98
|
+
return self
|
|
87
99
|
|
|
88
|
-
def reset_points(self):
|
|
89
|
-
|
|
100
|
+
def reset_points(self) -> None:
|
|
101
|
+
"""Sets :attr:`points` to be the four image corners."""
|
|
90
102
|
self.points = np.array(
|
|
91
103
|
[
|
|
92
104
|
UP + LEFT,
|
|
93
105
|
UP + RIGHT,
|
|
94
106
|
DOWN + LEFT,
|
|
107
|
+
DOWN + RIGHT,
|
|
95
108
|
],
|
|
96
109
|
)
|
|
97
110
|
self.center()
|
|
@@ -168,15 +181,15 @@ class ImageMobject(AbstractImageMobject):
|
|
|
168
181
|
|
|
169
182
|
def __init__(
|
|
170
183
|
self,
|
|
171
|
-
filename_or_array,
|
|
184
|
+
filename_or_array: StrPath | npt.NDArray,
|
|
172
185
|
scale_to_resolution: int = QUALITIES[DEFAULT_QUALITY]["pixel_height"],
|
|
173
|
-
invert=False,
|
|
174
|
-
image_mode="RGBA",
|
|
175
|
-
**kwargs,
|
|
176
|
-
):
|
|
177
|
-
self.fill_opacity = 1
|
|
178
|
-
self.stroke_opacity = 1
|
|
179
|
-
self.
|
|
186
|
+
invert: bool = False,
|
|
187
|
+
image_mode: str = "RGBA",
|
|
188
|
+
**kwargs: Any,
|
|
189
|
+
) -> None:
|
|
190
|
+
self.fill_opacity: float = 1
|
|
191
|
+
self.stroke_opacity: float = 1
|
|
192
|
+
self.invert_image = invert
|
|
180
193
|
self.image_mode = image_mode
|
|
181
194
|
if isinstance(filename_or_array, (str, pathlib.PurePath)):
|
|
182
195
|
path = get_full_raster_image_path(filename_or_array)
|
|
@@ -189,8 +202,11 @@ class ImageMobject(AbstractImageMobject):
|
|
|
189
202
|
self.pixel_array = change_to_rgba_array(
|
|
190
203
|
self.pixel_array, self.pixel_array_dtype
|
|
191
204
|
)
|
|
192
|
-
if self.
|
|
193
|
-
self.pixel_array[:, :, :3] =
|
|
205
|
+
if self.invert_image:
|
|
206
|
+
self.pixel_array[:, :, :3] = (
|
|
207
|
+
np.iinfo(self.pixel_array_dtype).max - self.pixel_array[:, :, :3]
|
|
208
|
+
)
|
|
209
|
+
self.orig_alpha_pixel_array = self.pixel_array[:, :, 3].copy()
|
|
194
210
|
super().__init__(scale_to_resolution, **kwargs)
|
|
195
211
|
|
|
196
212
|
def get_pixel_array(self):
|
|
@@ -207,7 +223,7 @@ class ImageMobject(AbstractImageMobject):
|
|
|
207
223
|
self.color = color
|
|
208
224
|
return self
|
|
209
225
|
|
|
210
|
-
def set_opacity(self, alpha: float):
|
|
226
|
+
def set_opacity(self, alpha: float) -> Self:
|
|
211
227
|
"""Sets the image's opacity.
|
|
212
228
|
|
|
213
229
|
Parameters
|
|
@@ -216,12 +232,11 @@ class ImageMobject(AbstractImageMobject):
|
|
|
216
232
|
The alpha value of the object, 1 being opaque and 0 being
|
|
217
233
|
transparent.
|
|
218
234
|
"""
|
|
219
|
-
self.pixel_array[:, :, 3] =
|
|
220
|
-
self.fill_opacity = alpha
|
|
235
|
+
self.pixel_array[:, :, 3] = self.orig_alpha_pixel_array * alpha
|
|
221
236
|
self.stroke_opacity = alpha
|
|
222
237
|
return self
|
|
223
238
|
|
|
224
|
-
def fade(self, darkness: float = 0.5, family: bool = True):
|
|
239
|
+
def fade(self, darkness: float = 0.5, family: bool = True) -> Self:
|
|
225
240
|
"""Sets the image's opacity using a 1 - alpha relationship.
|
|
226
241
|
|
|
227
242
|
Parameters
|
|
@@ -238,7 +253,7 @@ class ImageMobject(AbstractImageMobject):
|
|
|
238
253
|
|
|
239
254
|
def interpolate_color(
|
|
240
255
|
self, mobject1: ImageMobject, mobject2: ImageMobject, alpha: float
|
|
241
|
-
):
|
|
256
|
+
) -> None:
|
|
242
257
|
"""Interpolates the array of pixel color values from one ImageMobject
|
|
243
258
|
into an array of equal size in the target ImageMobject.
|
|
244
259
|
|
|
@@ -274,9 +289,9 @@ class ImageMobject(AbstractImageMobject):
|
|
|
274
289
|
alpha,
|
|
275
290
|
).astype(self.pixel_array_dtype)
|
|
276
291
|
|
|
277
|
-
def get_style(self):
|
|
292
|
+
def get_style(self) -> dict[str, Any]:
|
|
278
293
|
return {
|
|
279
|
-
"fill_color":
|
|
294
|
+
"fill_color": ManimColor(self.color.get_rgb()).to_hex(),
|
|
280
295
|
"fill_opacity": self.fill_opacity,
|
|
281
296
|
}
|
|
282
297
|
|
|
@@ -287,7 +302,12 @@ class ImageMobject(AbstractImageMobject):
|
|
|
287
302
|
|
|
288
303
|
|
|
289
304
|
class ImageMobjectFromCamera(AbstractImageMobject):
|
|
290
|
-
def __init__(
|
|
305
|
+
def __init__(
|
|
306
|
+
self,
|
|
307
|
+
camera: MovingCamera,
|
|
308
|
+
default_display_frame_config: dict[str, Any] | None = None,
|
|
309
|
+
**kwargs: Any,
|
|
310
|
+
) -> None:
|
|
291
311
|
self.camera = camera
|
|
292
312
|
if default_display_frame_config is None:
|
|
293
313
|
default_display_frame_config = {
|
|
@@ -304,14 +324,14 @@ class ImageMobjectFromCamera(AbstractImageMobject):
|
|
|
304
324
|
self.pixel_array = self.camera.pixel_array
|
|
305
325
|
return self.pixel_array
|
|
306
326
|
|
|
307
|
-
def add_display_frame(self, **kwargs):
|
|
327
|
+
def add_display_frame(self, **kwargs: Any) -> Self:
|
|
308
328
|
config = dict(self.default_display_frame_config)
|
|
309
329
|
config.update(kwargs)
|
|
310
330
|
self.display_frame = SurroundingRectangle(self, **config)
|
|
311
331
|
self.add(self.display_frame)
|
|
312
332
|
return self
|
|
313
333
|
|
|
314
|
-
def interpolate_color(self, mobject1, mobject2, alpha):
|
|
334
|
+
def interpolate_color(self, mobject1, mobject2, alpha) -> None:
|
|
315
335
|
assert mobject1.pixel_array.shape == mobject2.pixel_array.shape, (
|
|
316
336
|
f"Mobject pixel array shapes incompatible for interpolation.\n"
|
|
317
337
|
f"Mobject 1 ({mobject1}) : {mobject1.pixel_array.shape}\n"
|
|
@@ -4,8 +4,10 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
__all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"]
|
|
6
6
|
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import TYPE_CHECKING, Any
|
|
9
|
+
|
|
7
10
|
import numpy as np
|
|
8
|
-
from colour import Color
|
|
9
11
|
|
|
10
12
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
11
13
|
from manim.mobject.opengl.opengl_point_cloud_mobject import OpenGLPMobject
|
|
@@ -17,12 +19,29 @@ from ...utils.color import (
|
|
|
17
19
|
BLACK,
|
|
18
20
|
WHITE,
|
|
19
21
|
YELLOW,
|
|
22
|
+
ManimColor,
|
|
23
|
+
ParsableManimColor,
|
|
20
24
|
color_gradient,
|
|
21
25
|
color_to_rgba,
|
|
22
26
|
rgba_to_color,
|
|
23
27
|
)
|
|
24
28
|
from ...utils.iterables import stretch_array_to_length
|
|
25
29
|
|
|
30
|
+
__all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"]
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
import numpy.typing as npt
|
|
34
|
+
from typing_extensions import Self
|
|
35
|
+
|
|
36
|
+
from manim.typing import (
|
|
37
|
+
FloatRGBA_Array,
|
|
38
|
+
FloatRGBALike_Array,
|
|
39
|
+
ManimFloat,
|
|
40
|
+
Point3D_Array,
|
|
41
|
+
Point3DLike,
|
|
42
|
+
Point3DLike_Array,
|
|
43
|
+
)
|
|
44
|
+
|
|
26
45
|
|
|
27
46
|
class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
28
47
|
"""A disc made of a cloud of Dots
|
|
@@ -53,19 +72,25 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
|
53
72
|
|
|
54
73
|
"""
|
|
55
74
|
|
|
56
|
-
def __init__(self, stroke_width=DEFAULT_STROKE_WIDTH, **kwargs):
|
|
75
|
+
def __init__(self, stroke_width: int = DEFAULT_STROKE_WIDTH, **kwargs: Any) -> None:
|
|
57
76
|
self.stroke_width = stroke_width
|
|
58
77
|
super().__init__(**kwargs)
|
|
59
78
|
|
|
60
|
-
def reset_points(self):
|
|
61
|
-
self.rgbas = np.zeros((0, 4))
|
|
62
|
-
self.points = np.zeros((0, 3))
|
|
79
|
+
def reset_points(self) -> Self:
|
|
80
|
+
self.rgbas: FloatRGBA_Array = np.zeros((0, 4))
|
|
81
|
+
self.points: Point3D_Array = np.zeros((0, 3))
|
|
63
82
|
return self
|
|
64
83
|
|
|
65
|
-
def get_array_attrs(self):
|
|
84
|
+
def get_array_attrs(self) -> list[str]:
|
|
66
85
|
return super().get_array_attrs() + ["rgbas"]
|
|
67
86
|
|
|
68
|
-
def add_points(
|
|
87
|
+
def add_points(
|
|
88
|
+
self,
|
|
89
|
+
points: Point3DLike_Array,
|
|
90
|
+
rgbas: FloatRGBALike_Array | None = None,
|
|
91
|
+
color: ParsableManimColor | None = None,
|
|
92
|
+
alpha: float = 1.0,
|
|
93
|
+
) -> Self:
|
|
69
94
|
"""Add points.
|
|
70
95
|
|
|
71
96
|
Points must be a Nx3 numpy array.
|
|
@@ -76,31 +101,33 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
|
76
101
|
num_new_points = len(points)
|
|
77
102
|
self.points = np.append(self.points, points, axis=0)
|
|
78
103
|
if rgbas is None:
|
|
79
|
-
color =
|
|
104
|
+
color = ManimColor(color) if color else self.color
|
|
80
105
|
rgbas = np.repeat([color_to_rgba(color, alpha)], num_new_points, axis=0)
|
|
81
106
|
elif len(rgbas) != len(points):
|
|
82
107
|
raise ValueError("points and rgbas must have same length")
|
|
83
108
|
self.rgbas = np.append(self.rgbas, rgbas, axis=0)
|
|
84
109
|
return self
|
|
85
110
|
|
|
86
|
-
def set_color(
|
|
111
|
+
def set_color(
|
|
112
|
+
self, color: ParsableManimColor = YELLOW, family: bool = True
|
|
113
|
+
) -> Self:
|
|
87
114
|
rgba = color_to_rgba(color)
|
|
88
115
|
mobs = self.family_members_with_points() if family else [self]
|
|
89
116
|
for mob in mobs:
|
|
90
117
|
mob.rgbas[:, :] = rgba
|
|
91
|
-
self.color = color
|
|
118
|
+
self.color = ManimColor.parse(color)
|
|
92
119
|
return self
|
|
93
120
|
|
|
94
|
-
def get_stroke_width(self):
|
|
121
|
+
def get_stroke_width(self) -> int:
|
|
95
122
|
return self.stroke_width
|
|
96
123
|
|
|
97
|
-
def set_stroke_width(self, width, family=True):
|
|
124
|
+
def set_stroke_width(self, width: int, family: bool = True) -> Self:
|
|
98
125
|
mobs = self.family_members_with_points() if family else [self]
|
|
99
126
|
for mob in mobs:
|
|
100
127
|
mob.stroke_width = width
|
|
101
128
|
return self
|
|
102
129
|
|
|
103
|
-
def set_color_by_gradient(self, *colors):
|
|
130
|
+
def set_color_by_gradient(self, *colors: ParsableManimColor) -> Self:
|
|
104
131
|
self.rgbas = np.array(
|
|
105
132
|
list(map(color_to_rgba, color_gradient(*colors, len(self.points)))),
|
|
106
133
|
)
|
|
@@ -108,11 +135,11 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
|
108
135
|
|
|
109
136
|
def set_colors_by_radial_gradient(
|
|
110
137
|
self,
|
|
111
|
-
center=None,
|
|
112
|
-
radius=1,
|
|
113
|
-
inner_color=WHITE,
|
|
114
|
-
outer_color=BLACK,
|
|
115
|
-
):
|
|
138
|
+
center: Point3DLike | None = None,
|
|
139
|
+
radius: float = 1,
|
|
140
|
+
inner_color: ParsableManimColor = WHITE,
|
|
141
|
+
outer_color: ParsableManimColor = BLACK,
|
|
142
|
+
) -> Self:
|
|
116
143
|
start_rgba, end_rgba = list(map(color_to_rgba, [inner_color, outer_color]))
|
|
117
144
|
if center is None:
|
|
118
145
|
center = self.get_center()
|
|
@@ -127,48 +154,48 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
|
127
154
|
)
|
|
128
155
|
return self
|
|
129
156
|
|
|
130
|
-
def match_colors(self, mobject):
|
|
157
|
+
def match_colors(self, mobject: Mobject) -> Self:
|
|
131
158
|
Mobject.align_data(self, mobject)
|
|
132
159
|
self.rgbas = np.array(mobject.rgbas)
|
|
133
160
|
return self
|
|
134
161
|
|
|
135
|
-
def filter_out(self, condition):
|
|
162
|
+
def filter_out(self, condition: npt.NDArray) -> Self:
|
|
136
163
|
for mob in self.family_members_with_points():
|
|
137
164
|
to_eliminate = ~np.apply_along_axis(condition, 1, mob.points)
|
|
138
165
|
mob.points = mob.points[to_eliminate]
|
|
139
166
|
mob.rgbas = mob.rgbas[to_eliminate]
|
|
140
167
|
return self
|
|
141
168
|
|
|
142
|
-
def thin_out(self, factor=5):
|
|
143
|
-
"""
|
|
144
|
-
Removes all but every nth point for n = factor
|
|
145
|
-
"""
|
|
169
|
+
def thin_out(self, factor: int = 5) -> Self:
|
|
170
|
+
"""Removes all but every nth point for n = factor"""
|
|
146
171
|
for mob in self.family_members_with_points():
|
|
147
172
|
num_points = self.get_num_points()
|
|
148
173
|
mob.apply_over_attr_arrays(
|
|
149
|
-
lambda arr: arr[np.arange(0,
|
|
174
|
+
lambda arr, n=num_points: arr[np.arange(0, n, factor)],
|
|
150
175
|
)
|
|
151
176
|
return self
|
|
152
177
|
|
|
153
|
-
def sort_points(
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
"""
|
|
178
|
+
def sort_points(
|
|
179
|
+
self, function: Callable[[npt.NDArray[ManimFloat]], float] = lambda p: p[0]
|
|
180
|
+
) -> Self:
|
|
181
|
+
"""Function is any map from R^3 to R"""
|
|
157
182
|
for mob in self.family_members_with_points():
|
|
158
183
|
indices = np.argsort(np.apply_along_axis(function, 1, mob.points))
|
|
159
|
-
mob.apply_over_attr_arrays(lambda arr: arr[
|
|
184
|
+
mob.apply_over_attr_arrays(lambda arr, idx=indices: arr[idx])
|
|
160
185
|
return self
|
|
161
186
|
|
|
162
|
-
def fade_to(
|
|
187
|
+
def fade_to(
|
|
188
|
+
self, color: ParsableManimColor, alpha: float, family: bool = True
|
|
189
|
+
) -> Self:
|
|
163
190
|
self.rgbas = interpolate(self.rgbas, color_to_rgba(color), alpha)
|
|
164
191
|
for mob in self.submobjects:
|
|
165
192
|
mob.fade_to(color, alpha, family)
|
|
166
193
|
return self
|
|
167
194
|
|
|
168
|
-
def get_all_rgbas(self):
|
|
195
|
+
def get_all_rgbas(self) -> npt.NDArray:
|
|
169
196
|
return self.get_merged_array("rgbas")
|
|
170
197
|
|
|
171
|
-
def ingest_submobjects(self):
|
|
198
|
+
def ingest_submobjects(self) -> Self:
|
|
172
199
|
attrs = self.get_array_attrs()
|
|
173
200
|
arrays = list(map(self.get_merged_array, attrs))
|
|
174
201
|
for attr, array in zip(attrs, arrays):
|
|
@@ -176,30 +203,32 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
|
176
203
|
self.submobjects = []
|
|
177
204
|
return self
|
|
178
205
|
|
|
179
|
-
def get_color(self):
|
|
206
|
+
def get_color(self) -> ManimColor:
|
|
180
207
|
return rgba_to_color(self.rgbas[0, :])
|
|
181
208
|
|
|
182
|
-
def point_from_proportion(self, alpha):
|
|
209
|
+
def point_from_proportion(self, alpha: float) -> Any:
|
|
183
210
|
index = alpha * (self.get_num_points() - 1)
|
|
184
|
-
return self.points[index]
|
|
211
|
+
return self.points[np.floor(index)]
|
|
185
212
|
|
|
186
213
|
@staticmethod
|
|
187
|
-
def get_mobject_type_class():
|
|
214
|
+
def get_mobject_type_class() -> type[PMobject]:
|
|
188
215
|
return PMobject
|
|
189
216
|
|
|
190
217
|
# Alignment
|
|
191
|
-
def align_points_with_larger(self, larger_mobject):
|
|
218
|
+
def align_points_with_larger(self, larger_mobject: Mobject) -> None:
|
|
192
219
|
assert isinstance(larger_mobject, PMobject)
|
|
193
220
|
self.apply_over_attr_arrays(
|
|
194
221
|
lambda a: stretch_array_to_length(a, larger_mobject.get_num_points()),
|
|
195
222
|
)
|
|
196
223
|
|
|
197
|
-
def get_point_mobject(self, center=None):
|
|
224
|
+
def get_point_mobject(self, center: Point3DLike | None = None) -> Point:
|
|
198
225
|
if center is None:
|
|
199
226
|
center = self.get_center()
|
|
200
227
|
return Point(center)
|
|
201
228
|
|
|
202
|
-
def interpolate_color(
|
|
229
|
+
def interpolate_color(
|
|
230
|
+
self, mobject1: Mobject, mobject2: Mobject, alpha: float
|
|
231
|
+
) -> Self:
|
|
203
232
|
self.rgbas = interpolate(mobject1.rgbas, mobject2.rgbas, alpha)
|
|
204
233
|
self.set_stroke_width(
|
|
205
234
|
interpolate(
|
|
@@ -210,7 +239,7 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
|
210
239
|
)
|
|
211
240
|
return self
|
|
212
241
|
|
|
213
|
-
def pointwise_become_partial(self, mobject, a, b):
|
|
242
|
+
def pointwise_become_partial(self, mobject: Mobject, a: float, b: float) -> None:
|
|
214
243
|
lower_index, upper_index = (int(x * mobject.get_num_points()) for x in (a, b))
|
|
215
244
|
for attr in self.get_array_attrs():
|
|
216
245
|
full_array = getattr(mobject, attr)
|
|
@@ -220,31 +249,39 @@ class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
|
220
249
|
|
|
221
250
|
# TODO, Make the two implementations below non-redundant
|
|
222
251
|
class Mobject1D(PMobject, metaclass=ConvertToOpenGL):
|
|
223
|
-
def __init__(self, density=DEFAULT_POINT_DENSITY_1D, **kwargs):
|
|
252
|
+
def __init__(self, density: int = DEFAULT_POINT_DENSITY_1D, **kwargs: Any) -> None:
|
|
224
253
|
self.density = density
|
|
225
254
|
self.epsilon = 1.0 / self.density
|
|
226
255
|
super().__init__(**kwargs)
|
|
227
256
|
|
|
228
|
-
def add_line(
|
|
257
|
+
def add_line(
|
|
258
|
+
self,
|
|
259
|
+
start: npt.NDArray,
|
|
260
|
+
end: npt.NDArray,
|
|
261
|
+
color: ParsableManimColor | None = None,
|
|
262
|
+
) -> None:
|
|
229
263
|
start, end = list(map(np.array, [start, end]))
|
|
230
264
|
length = np.linalg.norm(end - start)
|
|
231
265
|
if length == 0:
|
|
232
|
-
points = [start]
|
|
266
|
+
points = np.array([start])
|
|
233
267
|
else:
|
|
234
268
|
epsilon = self.epsilon / length
|
|
235
|
-
points =
|
|
269
|
+
points = np.array(
|
|
270
|
+
[interpolate(start, end, t) for t in np.arange(0, 1, epsilon)]
|
|
271
|
+
)
|
|
236
272
|
self.add_points(points, color=color)
|
|
237
273
|
|
|
238
274
|
|
|
239
275
|
class Mobject2D(PMobject, metaclass=ConvertToOpenGL):
|
|
240
|
-
def __init__(self, density=DEFAULT_POINT_DENSITY_2D, **kwargs):
|
|
276
|
+
def __init__(self, density: int = DEFAULT_POINT_DENSITY_2D, **kwargs: Any) -> None:
|
|
241
277
|
self.density = density
|
|
242
278
|
self.epsilon = 1.0 / self.density
|
|
243
279
|
super().__init__(**kwargs)
|
|
244
280
|
|
|
245
281
|
|
|
246
282
|
class PGroup(PMobject):
|
|
247
|
-
"""
|
|
283
|
+
"""A group for several point mobjects.
|
|
284
|
+
|
|
248
285
|
Examples
|
|
249
286
|
--------
|
|
250
287
|
|
|
@@ -265,8 +302,8 @@ class PGroup(PMobject):
|
|
|
265
302
|
|
|
266
303
|
"""
|
|
267
304
|
|
|
268
|
-
def __init__(self, *pmobs, **kwargs):
|
|
269
|
-
if not all(
|
|
305
|
+
def __init__(self, *pmobs: Any, **kwargs: Any) -> None:
|
|
306
|
+
if not all(isinstance(m, (PMobject, OpenGLPMobject)) for m in pmobs):
|
|
270
307
|
raise ValueError(
|
|
271
308
|
"All submobjects must be of type PMobject or OpenGLPMObject"
|
|
272
309
|
" if using the opengl renderer",
|
|
@@ -274,14 +311,18 @@ class PGroup(PMobject):
|
|
|
274
311
|
super().__init__(**kwargs)
|
|
275
312
|
self.add(*pmobs)
|
|
276
313
|
|
|
277
|
-
def fade_to(
|
|
314
|
+
def fade_to(
|
|
315
|
+
self, color: ParsableManimColor, alpha: float, family: bool = True
|
|
316
|
+
) -> Self:
|
|
278
317
|
if family:
|
|
279
318
|
for mob in self.submobjects:
|
|
280
319
|
mob.fade_to(color, alpha, family)
|
|
320
|
+
return self
|
|
281
321
|
|
|
282
322
|
|
|
283
323
|
class PointCloudDot(Mobject1D):
|
|
284
|
-
"""A disc made of a cloud of
|
|
324
|
+
"""A disc made of a cloud of dots.
|
|
325
|
+
|
|
285
326
|
Examples
|
|
286
327
|
--------
|
|
287
328
|
.. manim:: PointCloudDotExample
|
|
@@ -313,13 +354,13 @@ class PointCloudDot(Mobject1D):
|
|
|
313
354
|
|
|
314
355
|
def __init__(
|
|
315
356
|
self,
|
|
316
|
-
center=ORIGIN,
|
|
317
|
-
radius=2.0,
|
|
318
|
-
stroke_width=2,
|
|
319
|
-
density=DEFAULT_POINT_DENSITY_1D,
|
|
320
|
-
color=YELLOW,
|
|
321
|
-
**kwargs,
|
|
322
|
-
):
|
|
357
|
+
center: Point3DLike = ORIGIN,
|
|
358
|
+
radius: float = 2.0,
|
|
359
|
+
stroke_width: int = 2,
|
|
360
|
+
density: int = DEFAULT_POINT_DENSITY_1D,
|
|
361
|
+
color: ManimColor = YELLOW,
|
|
362
|
+
**kwargs: Any,
|
|
363
|
+
) -> None:
|
|
323
364
|
self.radius = radius
|
|
324
365
|
self.epsilon = 1.0 / density
|
|
325
366
|
super().__init__(
|
|
@@ -327,27 +368,29 @@ class PointCloudDot(Mobject1D):
|
|
|
327
368
|
)
|
|
328
369
|
self.shift(center)
|
|
329
370
|
|
|
330
|
-
def init_points(self):
|
|
371
|
+
def init_points(self) -> None:
|
|
331
372
|
self.reset_points()
|
|
332
373
|
self.generate_points()
|
|
333
374
|
|
|
334
|
-
def generate_points(self):
|
|
375
|
+
def generate_points(self) -> None:
|
|
335
376
|
self.add_points(
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
377
|
+
np.array(
|
|
378
|
+
[
|
|
379
|
+
r * (np.cos(theta) * RIGHT + np.sin(theta) * UP)
|
|
380
|
+
for r in np.arange(self.epsilon, self.radius, self.epsilon)
|
|
381
|
+
# Num is equal to int(stop - start)/ (step + 1) reformulated.
|
|
382
|
+
for theta in np.linspace(
|
|
383
|
+
0,
|
|
384
|
+
2 * np.pi,
|
|
385
|
+
num=int(2 * np.pi * (r + self.epsilon) / self.epsilon),
|
|
386
|
+
)
|
|
387
|
+
]
|
|
388
|
+
),
|
|
346
389
|
)
|
|
347
390
|
|
|
348
391
|
|
|
349
392
|
class Point(PMobject):
|
|
350
|
-
"""
|
|
393
|
+
"""A mobject representing a point.
|
|
351
394
|
|
|
352
395
|
Examples
|
|
353
396
|
--------
|
|
@@ -367,14 +410,16 @@ class Point(PMobject):
|
|
|
367
410
|
self.add(point)
|
|
368
411
|
"""
|
|
369
412
|
|
|
370
|
-
def __init__(
|
|
413
|
+
def __init__(
|
|
414
|
+
self, location: Point3DLike = ORIGIN, color: ManimColor = BLACK, **kwargs: Any
|
|
415
|
+
) -> None:
|
|
371
416
|
self.location = location
|
|
372
417
|
super().__init__(color=color, **kwargs)
|
|
373
418
|
|
|
374
|
-
def init_points(self):
|
|
419
|
+
def init_points(self) -> None:
|
|
375
420
|
self.reset_points()
|
|
376
421
|
self.generate_points()
|
|
377
422
|
self.set_points([self.location])
|
|
378
423
|
|
|
379
|
-
def generate_points(self):
|
|
380
|
-
self.add_points([self.location])
|
|
424
|
+
def generate_points(self) -> None:
|
|
425
|
+
self.add_points(np.array([self.location]))
|