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
|
@@ -16,11 +16,11 @@ __all__ = [
|
|
|
16
16
|
"Torus",
|
|
17
17
|
]
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
from typing import
|
|
19
|
+
from collections.abc import Callable, Iterable, Sequence
|
|
20
|
+
from typing import TYPE_CHECKING, Any
|
|
21
21
|
|
|
22
22
|
import numpy as np
|
|
23
|
-
from
|
|
23
|
+
from typing_extensions import Self
|
|
24
24
|
|
|
25
25
|
from manim import config, logger
|
|
26
26
|
from manim.constants import *
|
|
@@ -29,16 +29,26 @@ from manim.mobject.geometry.polygram import Square
|
|
|
29
29
|
from manim.mobject.mobject import *
|
|
30
30
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
31
31
|
from manim.mobject.opengl.opengl_mobject import OpenGLMobject
|
|
32
|
-
from manim.mobject.types.vectorized_mobject import VGroup, VMobject
|
|
33
|
-
from manim.utils.color import
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
from manim.mobject.types.vectorized_mobject import VectorizedPoint, VGroup, VMobject
|
|
33
|
+
from manim.utils.color import (
|
|
34
|
+
BLUE,
|
|
35
|
+
BLUE_D,
|
|
36
|
+
BLUE_E,
|
|
37
|
+
LIGHT_GREY,
|
|
38
|
+
WHITE,
|
|
39
|
+
ManimColor,
|
|
40
|
+
ParsableManimColor,
|
|
41
|
+
interpolate_color,
|
|
42
|
+
)
|
|
36
43
|
from manim.utils.iterables import tuplify
|
|
37
44
|
from manim.utils.space_ops import normalize, perpendicular_bisector, z_to_vector
|
|
38
45
|
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from manim.typing import Point3D, Point3DLike, Vector3DLike
|
|
48
|
+
|
|
39
49
|
|
|
40
50
|
class ThreeDVMobject(VMobject, metaclass=ConvertToOpenGL):
|
|
41
|
-
def __init__(self, shade_in_3d=True, **kwargs):
|
|
51
|
+
def __init__(self, shade_in_3d: bool = True, **kwargs):
|
|
42
52
|
super().__init__(shade_in_3d=shade_in_3d, **kwargs)
|
|
43
53
|
|
|
44
54
|
|
|
@@ -63,7 +73,7 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
|
|
|
63
73
|
The opacity of the :class:`Surface`, from 0 being fully transparent
|
|
64
74
|
to 1 being fully opaque. Defaults to 1.
|
|
65
75
|
checkerboard_colors
|
|
66
|
-
|
|
76
|
+
ng individual faces alternating colors. Overrides ``fill_color``.
|
|
67
77
|
stroke_color
|
|
68
78
|
Color of the stroke surrounding each face of :class:`Surface`.
|
|
69
79
|
stroke_width
|
|
@@ -101,36 +111,46 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
|
|
|
101
111
|
v_range: Sequence[float] = [0, 1],
|
|
102
112
|
resolution: Sequence[int] = 32,
|
|
103
113
|
surface_piece_config: dict = {},
|
|
104
|
-
fill_color:
|
|
114
|
+
fill_color: ParsableManimColor = BLUE_D,
|
|
105
115
|
fill_opacity: float = 1.0,
|
|
106
|
-
checkerboard_colors: Sequence[
|
|
107
|
-
stroke_color:
|
|
116
|
+
checkerboard_colors: Sequence[ParsableManimColor] | bool = [BLUE_D, BLUE_E],
|
|
117
|
+
stroke_color: ParsableManimColor = LIGHT_GREY,
|
|
108
118
|
stroke_width: float = 0.5,
|
|
109
119
|
should_make_jagged: bool = False,
|
|
110
120
|
pre_function_handle_to_anchor_scale_factor: float = 0.00001,
|
|
111
|
-
**kwargs,
|
|
121
|
+
**kwargs: Any,
|
|
112
122
|
) -> None:
|
|
113
123
|
self.u_range = u_range
|
|
114
124
|
self.v_range = v_range
|
|
115
|
-
super().__init__(
|
|
125
|
+
super().__init__(
|
|
126
|
+
fill_color=fill_color,
|
|
127
|
+
fill_opacity=fill_opacity,
|
|
128
|
+
stroke_color=stroke_color,
|
|
129
|
+
stroke_width=stroke_width,
|
|
130
|
+
**kwargs,
|
|
131
|
+
)
|
|
116
132
|
self.resolution = resolution
|
|
117
133
|
self.surface_piece_config = surface_piece_config
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
134
|
+
if checkerboard_colors:
|
|
135
|
+
self.checkerboard_colors: list[ManimColor] = [
|
|
136
|
+
ManimColor(x) for x in checkerboard_colors
|
|
137
|
+
]
|
|
138
|
+
else:
|
|
139
|
+
self.checkerboard_colors = checkerboard_colors
|
|
123
140
|
self.should_make_jagged = should_make_jagged
|
|
124
141
|
self.pre_function_handle_to_anchor_scale_factor = (
|
|
125
142
|
pre_function_handle_to_anchor_scale_factor
|
|
126
143
|
)
|
|
127
|
-
self.
|
|
144
|
+
self._func = func
|
|
128
145
|
self._setup_in_uv_space()
|
|
129
146
|
self.apply_function(lambda p: func(p[0], p[1]))
|
|
130
147
|
if self.should_make_jagged:
|
|
131
148
|
self.make_jagged()
|
|
132
149
|
|
|
133
|
-
def
|
|
150
|
+
def func(self, u: float, v: float) -> np.ndarray:
|
|
151
|
+
return self._func(u, v)
|
|
152
|
+
|
|
153
|
+
def _get_u_values_and_v_values(self) -> tuple[np.ndarray, np.ndarray]:
|
|
134
154
|
res = tuplify(self.resolution)
|
|
135
155
|
if len(res) == 1:
|
|
136
156
|
u_res = v_res = res[0]
|
|
@@ -142,7 +162,7 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
|
|
|
142
162
|
|
|
143
163
|
return u_values, v_values
|
|
144
164
|
|
|
145
|
-
def _setup_in_uv_space(self):
|
|
165
|
+
def _setup_in_uv_space(self) -> None:
|
|
146
166
|
u_values, v_values = self._get_u_values_and_v_values()
|
|
147
167
|
faces = VGroup()
|
|
148
168
|
for i in range(len(u_values) - 1):
|
|
@@ -176,7 +196,9 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
|
|
|
176
196
|
if self.checkerboard_colors:
|
|
177
197
|
self.set_fill_by_checkerboard(*self.checkerboard_colors)
|
|
178
198
|
|
|
179
|
-
def set_fill_by_checkerboard(
|
|
199
|
+
def set_fill_by_checkerboard(
|
|
200
|
+
self, *colors: Iterable[ParsableManimColor], opacity: float | None = None
|
|
201
|
+
) -> Self:
|
|
180
202
|
"""Sets the fill_color of each face of :class:`Surface` in
|
|
181
203
|
an alternating pattern.
|
|
182
204
|
|
|
@@ -199,14 +221,13 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
|
|
|
199
221
|
face.set_fill(colors[c_index], opacity=opacity)
|
|
200
222
|
return self
|
|
201
223
|
|
|
202
|
-
@deprecated_params("colors", since="v0.16.0")
|
|
203
224
|
def set_fill_by_value(
|
|
204
225
|
self,
|
|
205
226
|
axes: Mobject,
|
|
206
|
-
colorscale:
|
|
227
|
+
colorscale: list[ParsableManimColor] | ParsableManimColor | None = None,
|
|
207
228
|
axis: int = 2,
|
|
208
229
|
**kwargs,
|
|
209
|
-
):
|
|
230
|
+
) -> Self:
|
|
210
231
|
"""Sets the color of each mobject of a parametric surface to a color
|
|
211
232
|
relative to its axis-value.
|
|
212
233
|
|
|
@@ -316,7 +337,7 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
|
|
|
316
337
|
|
|
317
338
|
|
|
318
339
|
class Sphere(Surface):
|
|
319
|
-
"""
|
|
340
|
+
"""A three-dimensional sphere.
|
|
320
341
|
|
|
321
342
|
Parameters
|
|
322
343
|
----------
|
|
@@ -360,17 +381,19 @@ class Sphere(Surface):
|
|
|
360
381
|
|
|
361
382
|
def __init__(
|
|
362
383
|
self,
|
|
363
|
-
center=ORIGIN,
|
|
364
|
-
radius=1,
|
|
365
|
-
resolution=None,
|
|
366
|
-
u_range=(0, TAU),
|
|
367
|
-
v_range=(0, PI),
|
|
384
|
+
center: Point3DLike = ORIGIN,
|
|
385
|
+
radius: float = 1,
|
|
386
|
+
resolution: Sequence[int] | None = None,
|
|
387
|
+
u_range: Sequence[float] = (0, TAU),
|
|
388
|
+
v_range: Sequence[float] = (0, PI),
|
|
368
389
|
**kwargs,
|
|
369
|
-
):
|
|
390
|
+
) -> None:
|
|
370
391
|
if config.renderer == RendererType.OPENGL:
|
|
371
392
|
res_value = (101, 51)
|
|
372
393
|
elif config.renderer == RendererType.CAIRO:
|
|
373
394
|
res_value = (24, 12)
|
|
395
|
+
else:
|
|
396
|
+
raise Exception("Unknown renderer")
|
|
374
397
|
|
|
375
398
|
resolution = resolution if resolution is not None else res_value
|
|
376
399
|
|
|
@@ -386,7 +409,14 @@ class Sphere(Surface):
|
|
|
386
409
|
|
|
387
410
|
self.shift(center)
|
|
388
411
|
|
|
389
|
-
def func(self, u, v):
|
|
412
|
+
def func(self, u: float, v: float) -> np.ndarray:
|
|
413
|
+
"""The z values defining the :class:`Sphere` being plotted.
|
|
414
|
+
|
|
415
|
+
Returns
|
|
416
|
+
-------
|
|
417
|
+
:class:`numpy.array`
|
|
418
|
+
The z values defining the :class:`Sphere`.
|
|
419
|
+
"""
|
|
390
420
|
return self.radius * np.array(
|
|
391
421
|
[np.cos(u) * np.sin(v), np.sin(u) * np.sin(v), -np.cos(v)],
|
|
392
422
|
)
|
|
@@ -428,10 +458,10 @@ class Dot3D(Sphere):
|
|
|
428
458
|
self,
|
|
429
459
|
point: list | np.ndarray = ORIGIN,
|
|
430
460
|
radius: float = DEFAULT_DOT_RADIUS,
|
|
431
|
-
color:
|
|
432
|
-
resolution=(8, 8),
|
|
461
|
+
color: ParsableManimColor = WHITE,
|
|
462
|
+
resolution: tuple[int, int] = (8, 8),
|
|
433
463
|
**kwargs,
|
|
434
|
-
):
|
|
464
|
+
) -> None:
|
|
435
465
|
super().__init__(center=point, radius=radius, resolution=resolution, **kwargs)
|
|
436
466
|
self.set_color(color)
|
|
437
467
|
|
|
@@ -468,12 +498,12 @@ class Cube(VGroup):
|
|
|
468
498
|
|
|
469
499
|
def __init__(
|
|
470
500
|
self,
|
|
471
|
-
side_length=2,
|
|
472
|
-
fill_opacity=0.75,
|
|
473
|
-
fill_color=BLUE,
|
|
474
|
-
stroke_width=0,
|
|
501
|
+
side_length: float = 2,
|
|
502
|
+
fill_opacity: float = 0.75,
|
|
503
|
+
fill_color: ParsableManimColor = BLUE,
|
|
504
|
+
stroke_width: float = 0,
|
|
475
505
|
**kwargs,
|
|
476
|
-
):
|
|
506
|
+
) -> None:
|
|
477
507
|
self.side_length = side_length
|
|
478
508
|
super().__init__(
|
|
479
509
|
fill_color=fill_color,
|
|
@@ -482,11 +512,13 @@ class Cube(VGroup):
|
|
|
482
512
|
**kwargs,
|
|
483
513
|
)
|
|
484
514
|
|
|
485
|
-
def generate_points(self):
|
|
515
|
+
def generate_points(self) -> None:
|
|
516
|
+
"""Creates the sides of the :class:`Cube`."""
|
|
486
517
|
for vect in IN, OUT, LEFT, RIGHT, UP, DOWN:
|
|
487
518
|
face = Square(
|
|
488
519
|
side_length=self.side_length,
|
|
489
520
|
shade_in_3d=True,
|
|
521
|
+
joint_type=LineJointType.BEVEL,
|
|
490
522
|
)
|
|
491
523
|
face.flip()
|
|
492
524
|
face.shift(self.side_length * OUT / 2.0)
|
|
@@ -494,7 +526,8 @@ class Cube(VGroup):
|
|
|
494
526
|
|
|
495
527
|
self.add(face)
|
|
496
528
|
|
|
497
|
-
init_points
|
|
529
|
+
def init_points(self) -> None:
|
|
530
|
+
self.generate_points()
|
|
498
531
|
|
|
499
532
|
|
|
500
533
|
class Prism(Cube):
|
|
@@ -520,11 +553,14 @@ class Prism(Cube):
|
|
|
520
553
|
self.add(prismSmall, prismLarge)
|
|
521
554
|
"""
|
|
522
555
|
|
|
523
|
-
def __init__(
|
|
556
|
+
def __init__(
|
|
557
|
+
self, dimensions: tuple[float, float, float] | np.ndarray = [3, 2, 1], **kwargs
|
|
558
|
+
) -> None:
|
|
524
559
|
self.dimensions = dimensions
|
|
525
560
|
super().__init__(**kwargs)
|
|
526
561
|
|
|
527
|
-
def generate_points(self):
|
|
562
|
+
def generate_points(self) -> None:
|
|
563
|
+
"""Creates the sides of the :class:`Prism`."""
|
|
528
564
|
super().generate_points()
|
|
529
565
|
for dim, value in enumerate(self.dimensions):
|
|
530
566
|
self.rescale_to_fit(value, dim, stretch=True)
|
|
@@ -577,8 +613,8 @@ class Cone(Surface):
|
|
|
577
613
|
v_range: Sequence[float] = [0, TAU],
|
|
578
614
|
u_min: float = 0,
|
|
579
615
|
checkerboard_colors: bool = False,
|
|
580
|
-
**kwargs,
|
|
581
|
-
):
|
|
616
|
+
**kwargs: Any,
|
|
617
|
+
) -> None:
|
|
582
618
|
self.direction = direction
|
|
583
619
|
self.theta = PI - np.arctan(base_radius / height)
|
|
584
620
|
|
|
@@ -590,22 +626,23 @@ class Cone(Surface):
|
|
|
590
626
|
**kwargs,
|
|
591
627
|
)
|
|
592
628
|
# used for rotations
|
|
629
|
+
self.new_height = height
|
|
593
630
|
self._current_theta = 0
|
|
594
631
|
self._current_phi = 0
|
|
595
|
-
|
|
632
|
+
self.base_circle = Circle(
|
|
633
|
+
radius=base_radius,
|
|
634
|
+
color=self.fill_color,
|
|
635
|
+
fill_opacity=self.fill_opacity,
|
|
636
|
+
stroke_width=0,
|
|
637
|
+
)
|
|
638
|
+
self.base_circle.shift(height * IN)
|
|
639
|
+
self._set_start_and_end_attributes(direction)
|
|
596
640
|
if show_base:
|
|
597
|
-
self.base_circle = Circle(
|
|
598
|
-
radius=base_radius,
|
|
599
|
-
color=self.fill_color,
|
|
600
|
-
fill_opacity=self.fill_opacity,
|
|
601
|
-
stroke_width=0,
|
|
602
|
-
)
|
|
603
|
-
self.base_circle.shift(height * IN)
|
|
604
641
|
self.add(self.base_circle)
|
|
605
642
|
|
|
606
643
|
self._rotate_to_direction()
|
|
607
644
|
|
|
608
|
-
def func(self, u: float, v: float):
|
|
645
|
+
def func(self, u: float, v: float) -> np.ndarray:
|
|
609
646
|
"""Converts from spherical coordinates to cartesian.
|
|
610
647
|
|
|
611
648
|
Parameters
|
|
@@ -614,6 +651,11 @@ class Cone(Surface):
|
|
|
614
651
|
The radius.
|
|
615
652
|
v
|
|
616
653
|
The azimuthal angle.
|
|
654
|
+
|
|
655
|
+
Returns
|
|
656
|
+
-------
|
|
657
|
+
:class:`numpy.array`
|
|
658
|
+
Points defining the :class:`Cone`.
|
|
617
659
|
"""
|
|
618
660
|
r = u
|
|
619
661
|
phi = v
|
|
@@ -625,14 +667,17 @@ class Cone(Surface):
|
|
|
625
667
|
],
|
|
626
668
|
)
|
|
627
669
|
|
|
628
|
-
def
|
|
670
|
+
def get_start(self) -> np.ndarray:
|
|
671
|
+
return self.start_point.get_center()
|
|
672
|
+
|
|
673
|
+
def get_end(self) -> np.ndarray:
|
|
674
|
+
return self.end_point.get_center()
|
|
675
|
+
|
|
676
|
+
def _rotate_to_direction(self) -> None:
|
|
629
677
|
x, y, z = self.direction
|
|
630
678
|
|
|
631
679
|
r = np.sqrt(x**2 + y**2 + z**2)
|
|
632
|
-
if r > 0
|
|
633
|
-
theta = np.arccos(z / r)
|
|
634
|
-
else:
|
|
635
|
-
theta = 0
|
|
680
|
+
theta = np.arccos(z / r) if r > 0 else 0
|
|
636
681
|
|
|
637
682
|
if x == 0:
|
|
638
683
|
if y == 0: # along the z axis
|
|
@@ -658,18 +703,18 @@ class Cone(Surface):
|
|
|
658
703
|
self._current_theta = theta
|
|
659
704
|
self._current_phi = phi
|
|
660
705
|
|
|
661
|
-
def set_direction(self, direction):
|
|
706
|
+
def set_direction(self, direction: np.ndarray) -> None:
|
|
662
707
|
"""Changes the direction of the apex of the :class:`Cone`.
|
|
663
708
|
|
|
664
709
|
Parameters
|
|
665
710
|
----------
|
|
666
|
-
direction
|
|
711
|
+
direction
|
|
667
712
|
The direction of the apex.
|
|
668
713
|
"""
|
|
669
714
|
self.direction = direction
|
|
670
715
|
self._rotate_to_direction()
|
|
671
716
|
|
|
672
|
-
def get_direction(self):
|
|
717
|
+
def get_direction(self) -> np.ndarray:
|
|
673
718
|
"""Returns the current direction of the apex of the :class:`Cone`.
|
|
674
719
|
|
|
675
720
|
Returns
|
|
@@ -679,6 +724,15 @@ class Cone(Surface):
|
|
|
679
724
|
"""
|
|
680
725
|
return self.direction
|
|
681
726
|
|
|
727
|
+
def _set_start_and_end_attributes(self, direction):
|
|
728
|
+
normalized_direction = direction * np.linalg.norm(direction)
|
|
729
|
+
|
|
730
|
+
start = self.base_circle.get_center()
|
|
731
|
+
end = start + normalized_direction * self.new_height
|
|
732
|
+
self.start_point = VectorizedPoint(start)
|
|
733
|
+
self.end_point = VectorizedPoint(end)
|
|
734
|
+
self.add(self.start_point, self.end_point)
|
|
735
|
+
|
|
682
736
|
|
|
683
737
|
class Cylinder(Surface):
|
|
684
738
|
"""A cylinder, defined by its height, radius and direction,
|
|
@@ -719,9 +773,9 @@ class Cylinder(Surface):
|
|
|
719
773
|
direction: np.ndarray = Z_AXIS,
|
|
720
774
|
v_range: Sequence[float] = [0, TAU],
|
|
721
775
|
show_ends: bool = True,
|
|
722
|
-
resolution=(24, 24),
|
|
776
|
+
resolution: Sequence[int] = (24, 24),
|
|
723
777
|
**kwargs,
|
|
724
|
-
):
|
|
778
|
+
) -> None:
|
|
725
779
|
self._height = height
|
|
726
780
|
self.radius = radius
|
|
727
781
|
super().__init__(
|
|
@@ -737,7 +791,7 @@ class Cylinder(Surface):
|
|
|
737
791
|
self._current_theta = 0
|
|
738
792
|
self.set_direction(direction)
|
|
739
793
|
|
|
740
|
-
def func(self, u: float, v: float):
|
|
794
|
+
def func(self, u: float, v: float) -> np.ndarray:
|
|
741
795
|
"""Converts from cylindrical coordinates to cartesian.
|
|
742
796
|
|
|
743
797
|
Parameters
|
|
@@ -746,13 +800,18 @@ class Cylinder(Surface):
|
|
|
746
800
|
The height.
|
|
747
801
|
v
|
|
748
802
|
The azimuthal angle.
|
|
803
|
+
|
|
804
|
+
Returns
|
|
805
|
+
-------
|
|
806
|
+
:class:`numpy.ndarray`
|
|
807
|
+
Points defining the :class:`Cylinder`.
|
|
749
808
|
"""
|
|
750
809
|
height = u
|
|
751
810
|
phi = v
|
|
752
811
|
r = self.radius
|
|
753
812
|
return np.array([r * np.cos(phi), r * np.sin(phi), height])
|
|
754
813
|
|
|
755
|
-
def add_bases(self):
|
|
814
|
+
def add_bases(self) -> None:
|
|
756
815
|
"""Adds the end caps of the cylinder."""
|
|
757
816
|
if config.renderer == RendererType.OPENGL:
|
|
758
817
|
color = self.color
|
|
@@ -779,14 +838,11 @@ class Cylinder(Surface):
|
|
|
779
838
|
self.base_bottom.shift(self.u_range[0] * IN)
|
|
780
839
|
self.add(self.base_top, self.base_bottom)
|
|
781
840
|
|
|
782
|
-
def _rotate_to_direction(self):
|
|
841
|
+
def _rotate_to_direction(self) -> None:
|
|
783
842
|
x, y, z = self.direction
|
|
784
843
|
|
|
785
844
|
r = np.sqrt(x**2 + y**2 + z**2)
|
|
786
|
-
if r > 0
|
|
787
|
-
theta = np.arccos(z / r)
|
|
788
|
-
else:
|
|
789
|
-
theta = 0
|
|
845
|
+
theta = np.arccos(z / r) if r > 0 else 0
|
|
790
846
|
|
|
791
847
|
if x == 0:
|
|
792
848
|
if y == 0: # along the z axis
|
|
@@ -812,12 +868,12 @@ class Cylinder(Surface):
|
|
|
812
868
|
self._current_theta = theta
|
|
813
869
|
self._current_phi = phi
|
|
814
870
|
|
|
815
|
-
def set_direction(self, direction):
|
|
871
|
+
def set_direction(self, direction: np.ndarray) -> None:
|
|
816
872
|
"""Sets the direction of the central axis of the :class:`Cylinder`.
|
|
817
873
|
|
|
818
874
|
Parameters
|
|
819
875
|
----------
|
|
820
|
-
direction
|
|
876
|
+
direction : :class:`numpy.array`
|
|
821
877
|
The direction of the central axis of the :class:`Cylinder`.
|
|
822
878
|
"""
|
|
823
879
|
# if get_norm(direction) is get_norm(self.direction):
|
|
@@ -825,12 +881,12 @@ class Cylinder(Surface):
|
|
|
825
881
|
self.direction = direction
|
|
826
882
|
self._rotate_to_direction()
|
|
827
883
|
|
|
828
|
-
def get_direction(self):
|
|
884
|
+
def get_direction(self) -> np.ndarray:
|
|
829
885
|
"""Returns the direction of the central axis of the :class:`Cylinder`.
|
|
830
886
|
|
|
831
887
|
Returns
|
|
832
888
|
-------
|
|
833
|
-
direction
|
|
889
|
+
direction : :class:`numpy.array`
|
|
834
890
|
The direction of the central axis of the :class:`Cylinder`.
|
|
835
891
|
"""
|
|
836
892
|
return self.direction
|
|
@@ -849,6 +905,12 @@ class Line3D(Cylinder):
|
|
|
849
905
|
The thickness of the line.
|
|
850
906
|
color
|
|
851
907
|
The color of the line.
|
|
908
|
+
resolution
|
|
909
|
+
The resolution of the line.
|
|
910
|
+
By default this value is the number of points the line will sampled at.
|
|
911
|
+
If you want the line to also come out checkered, use a tuple.
|
|
912
|
+
For example, for a line made of 24 points with 4 checker points on each
|
|
913
|
+
cylinder, pass the tuple (4, 24).
|
|
852
914
|
|
|
853
915
|
Examples
|
|
854
916
|
--------
|
|
@@ -868,15 +930,23 @@ class Line3D(Cylinder):
|
|
|
868
930
|
start: np.ndarray = LEFT,
|
|
869
931
|
end: np.ndarray = RIGHT,
|
|
870
932
|
thickness: float = 0.02,
|
|
871
|
-
color=None,
|
|
933
|
+
color: ParsableManimColor | None = None,
|
|
934
|
+
resolution: int | Sequence[int] = 24,
|
|
872
935
|
**kwargs,
|
|
873
936
|
):
|
|
874
937
|
self.thickness = thickness
|
|
938
|
+
self.resolution = (2, resolution) if isinstance(resolution, int) else resolution
|
|
939
|
+
|
|
940
|
+
start = np.array(start, dtype=np.float64)
|
|
941
|
+
end = np.array(end, dtype=np.float64)
|
|
942
|
+
|
|
875
943
|
self.set_start_and_end_attrs(start, end, **kwargs)
|
|
876
944
|
if color is not None:
|
|
877
945
|
self.set_color(color)
|
|
878
946
|
|
|
879
|
-
def set_start_and_end_attrs(
|
|
947
|
+
def set_start_and_end_attrs(
|
|
948
|
+
self, start: np.ndarray, end: np.ndarray, **kwargs
|
|
949
|
+
) -> None:
|
|
880
950
|
"""Sets the start and end points of the line.
|
|
881
951
|
|
|
882
952
|
If either ``start`` or ``end`` are :class:`Mobjects <.Mobject>`,
|
|
@@ -903,11 +973,30 @@ class Line3D(Cylinder):
|
|
|
903
973
|
height=np.linalg.norm(self.vect),
|
|
904
974
|
radius=self.thickness,
|
|
905
975
|
direction=self.direction,
|
|
976
|
+
resolution=self.resolution,
|
|
906
977
|
**kwargs,
|
|
907
978
|
)
|
|
908
979
|
self.shift((self.start + self.end) / 2)
|
|
909
980
|
|
|
910
|
-
def pointify(
|
|
981
|
+
def pointify(
|
|
982
|
+
self,
|
|
983
|
+
mob_or_point: Mobject | Point3DLike,
|
|
984
|
+
direction: Vector3DLike | None = None,
|
|
985
|
+
) -> Point3D:
|
|
986
|
+
"""Gets a point representing the center of the :class:`Mobjects <.Mobject>`.
|
|
987
|
+
|
|
988
|
+
Parameters
|
|
989
|
+
----------
|
|
990
|
+
mob_or_point
|
|
991
|
+
:class:`Mobjects <.Mobject>` or point whose center should be returned.
|
|
992
|
+
direction
|
|
993
|
+
If an edge of a :class:`Mobjects <.Mobject>` should be returned, the direction of the edge.
|
|
994
|
+
|
|
995
|
+
Returns
|
|
996
|
+
-------
|
|
997
|
+
:class:`numpy.array`
|
|
998
|
+
Center of the :class:`Mobjects <.Mobject>` or point, or edge if direction is given.
|
|
999
|
+
"""
|
|
911
1000
|
if isinstance(mob_or_point, (Mobject, OpenGLMobject)):
|
|
912
1001
|
mob = mob_or_point
|
|
913
1002
|
if direction is None:
|
|
@@ -916,7 +1005,7 @@ class Line3D(Cylinder):
|
|
|
916
1005
|
return mob.get_boundary_point(direction)
|
|
917
1006
|
return np.array(mob_or_point)
|
|
918
1007
|
|
|
919
|
-
def get_start(self):
|
|
1008
|
+
def get_start(self) -> np.ndarray:
|
|
920
1009
|
"""Returns the starting point of the :class:`Line3D`.
|
|
921
1010
|
|
|
922
1011
|
Returns
|
|
@@ -926,7 +1015,7 @@ class Line3D(Cylinder):
|
|
|
926
1015
|
"""
|
|
927
1016
|
return self.start
|
|
928
1017
|
|
|
929
|
-
def get_end(self):
|
|
1018
|
+
def get_end(self) -> np.ndarray:
|
|
930
1019
|
"""Returns the ending point of the :class:`Line3D`.
|
|
931
1020
|
|
|
932
1021
|
Returns
|
|
@@ -938,8 +1027,12 @@ class Line3D(Cylinder):
|
|
|
938
1027
|
|
|
939
1028
|
@classmethod
|
|
940
1029
|
def parallel_to(
|
|
941
|
-
cls,
|
|
942
|
-
|
|
1030
|
+
cls,
|
|
1031
|
+
line: Line3D,
|
|
1032
|
+
point: Point3DLike = ORIGIN,
|
|
1033
|
+
length: float = 5,
|
|
1034
|
+
**kwargs,
|
|
1035
|
+
) -> Line3D:
|
|
943
1036
|
"""Returns a line parallel to another line going through
|
|
944
1037
|
a given point.
|
|
945
1038
|
|
|
@@ -949,9 +1042,16 @@ class Line3D(Cylinder):
|
|
|
949
1042
|
The line to be parallel to.
|
|
950
1043
|
point
|
|
951
1044
|
The point to pass through.
|
|
1045
|
+
length
|
|
1046
|
+
Length of the parallel line.
|
|
952
1047
|
kwargs
|
|
953
1048
|
Additional parameters to be passed to the class.
|
|
954
1049
|
|
|
1050
|
+
Returns
|
|
1051
|
+
-------
|
|
1052
|
+
:class:`Line3D`
|
|
1053
|
+
Line parallel to ``line``.
|
|
1054
|
+
|
|
955
1055
|
Examples
|
|
956
1056
|
--------
|
|
957
1057
|
.. manim:: ParallelLineExample
|
|
@@ -965,18 +1065,22 @@ class Line3D(Cylinder):
|
|
|
965
1065
|
line2 = Line3D.parallel_to(line1, color=YELLOW)
|
|
966
1066
|
self.add(ax, line1, line2)
|
|
967
1067
|
"""
|
|
968
|
-
|
|
1068
|
+
np_point = np.asarray(point)
|
|
969
1069
|
vect = normalize(line.vect)
|
|
970
1070
|
return cls(
|
|
971
|
-
|
|
972
|
-
|
|
1071
|
+
np_point + vect * length / 2,
|
|
1072
|
+
np_point - vect * length / 2,
|
|
973
1073
|
**kwargs,
|
|
974
1074
|
)
|
|
975
1075
|
|
|
976
1076
|
@classmethod
|
|
977
1077
|
def perpendicular_to(
|
|
978
|
-
cls,
|
|
979
|
-
|
|
1078
|
+
cls,
|
|
1079
|
+
line: Line3D,
|
|
1080
|
+
point: Vector3DLike = ORIGIN,
|
|
1081
|
+
length: float = 5,
|
|
1082
|
+
**kwargs,
|
|
1083
|
+
) -> Line3D:
|
|
980
1084
|
"""Returns a line perpendicular to another line going through
|
|
981
1085
|
a given point.
|
|
982
1086
|
|
|
@@ -986,9 +1090,16 @@ class Line3D(Cylinder):
|
|
|
986
1090
|
The line to be perpendicular to.
|
|
987
1091
|
point
|
|
988
1092
|
The point to pass through.
|
|
1093
|
+
length
|
|
1094
|
+
Length of the perpendicular line.
|
|
989
1095
|
kwargs
|
|
990
1096
|
Additional parameters to be passed to the class.
|
|
991
1097
|
|
|
1098
|
+
Returns
|
|
1099
|
+
-------
|
|
1100
|
+
:class:`Line3D`
|
|
1101
|
+
Line perpendicular to ``line``.
|
|
1102
|
+
|
|
992
1103
|
Examples
|
|
993
1104
|
--------
|
|
994
1105
|
.. manim:: PerpLineExample
|
|
@@ -1002,17 +1113,17 @@ class Line3D(Cylinder):
|
|
|
1002
1113
|
line2 = Line3D.perpendicular_to(line1, color=BLUE)
|
|
1003
1114
|
self.add(ax, line1, line2)
|
|
1004
1115
|
"""
|
|
1005
|
-
|
|
1116
|
+
np_point = np.asarray(point)
|
|
1006
1117
|
|
|
1007
|
-
norm = np.cross(line.vect,
|
|
1118
|
+
norm = np.cross(line.vect, np_point - line.start)
|
|
1008
1119
|
if all(np.linalg.norm(norm) == np.zeros(3)):
|
|
1009
1120
|
raise ValueError("Could not find the perpendicular.")
|
|
1010
1121
|
|
|
1011
1122
|
start, end = perpendicular_bisector([line.start, line.end], norm)
|
|
1012
1123
|
vect = normalize(end - start)
|
|
1013
1124
|
return cls(
|
|
1014
|
-
|
|
1015
|
-
|
|
1125
|
+
np_point + vect * length / 2,
|
|
1126
|
+
np_point - vect * length / 2,
|
|
1016
1127
|
**kwargs,
|
|
1017
1128
|
)
|
|
1018
1129
|
|
|
@@ -1034,6 +1145,8 @@ class Arrow3D(Line3D):
|
|
|
1034
1145
|
The base radius of the conical tip.
|
|
1035
1146
|
color
|
|
1036
1147
|
The color of the arrow.
|
|
1148
|
+
resolution
|
|
1149
|
+
The resolution of the arrow line.
|
|
1037
1150
|
|
|
1038
1151
|
Examples
|
|
1039
1152
|
--------
|
|
@@ -1059,11 +1172,17 @@ class Arrow3D(Line3D):
|
|
|
1059
1172
|
thickness: float = 0.02,
|
|
1060
1173
|
height: float = 0.3,
|
|
1061
1174
|
base_radius: float = 0.08,
|
|
1062
|
-
color=WHITE,
|
|
1175
|
+
color: ParsableManimColor = WHITE,
|
|
1176
|
+
resolution: int | Sequence[int] = 24,
|
|
1063
1177
|
**kwargs,
|
|
1064
|
-
):
|
|
1178
|
+
) -> None:
|
|
1065
1179
|
super().__init__(
|
|
1066
|
-
start=start,
|
|
1180
|
+
start=start,
|
|
1181
|
+
end=end,
|
|
1182
|
+
thickness=thickness,
|
|
1183
|
+
color=color,
|
|
1184
|
+
resolution=resolution,
|
|
1185
|
+
**kwargs,
|
|
1067
1186
|
)
|
|
1068
1187
|
|
|
1069
1188
|
self.length = np.linalg.norm(self.vect)
|
|
@@ -1072,14 +1191,21 @@ class Arrow3D(Line3D):
|
|
|
1072
1191
|
self.end - height * self.direction,
|
|
1073
1192
|
**kwargs,
|
|
1074
1193
|
)
|
|
1075
|
-
|
|
1076
1194
|
self.cone = Cone(
|
|
1077
|
-
direction=self.direction,
|
|
1195
|
+
direction=self.direction,
|
|
1196
|
+
base_radius=base_radius,
|
|
1197
|
+
height=height,
|
|
1198
|
+
**kwargs,
|
|
1078
1199
|
)
|
|
1079
|
-
|
|
1080
|
-
self.
|
|
1200
|
+
np_end = np.asarray(end, dtype=np.float64)
|
|
1201
|
+
self.cone.shift(np_end)
|
|
1202
|
+
self.end_point = VectorizedPoint(np_end)
|
|
1203
|
+
self.add(self.end_point, self.cone)
|
|
1081
1204
|
self.set_color(color)
|
|
1082
1205
|
|
|
1206
|
+
def get_end(self) -> np.ndarray:
|
|
1207
|
+
return self.end_point.get_center()
|
|
1208
|
+
|
|
1083
1209
|
|
|
1084
1210
|
class Torus(Surface):
|
|
1085
1211
|
"""A torus.
|
|
@@ -1115,11 +1241,11 @@ class Torus(Surface):
|
|
|
1115
1241
|
self,
|
|
1116
1242
|
major_radius: float = 3,
|
|
1117
1243
|
minor_radius: float = 1,
|
|
1118
|
-
u_range=(0, TAU),
|
|
1119
|
-
v_range=(0, TAU),
|
|
1120
|
-
resolution=None,
|
|
1244
|
+
u_range: Sequence[float] = (0, TAU),
|
|
1245
|
+
v_range: Sequence[float] = (0, TAU),
|
|
1246
|
+
resolution: tuple[int, int] | None = None,
|
|
1121
1247
|
**kwargs,
|
|
1122
|
-
):
|
|
1248
|
+
) -> None:
|
|
1123
1249
|
if config.renderer == RendererType.OPENGL:
|
|
1124
1250
|
res_value = (101, 101)
|
|
1125
1251
|
elif config.renderer == RendererType.CAIRO:
|
|
@@ -1137,6 +1263,13 @@ class Torus(Surface):
|
|
|
1137
1263
|
**kwargs,
|
|
1138
1264
|
)
|
|
1139
1265
|
|
|
1140
|
-
def func(self, u, v):
|
|
1266
|
+
def func(self, u: float, v: float) -> np.ndarray:
|
|
1267
|
+
"""The z values defining the :class:`Torus` being plotted.
|
|
1268
|
+
|
|
1269
|
+
Returns
|
|
1270
|
+
-------
|
|
1271
|
+
:class:`numpy.ndarray`
|
|
1272
|
+
The z values defining the :class:`Torus`.
|
|
1273
|
+
"""
|
|
1141
1274
|
P = np.array([np.cos(u), np.sin(u), 0])
|
|
1142
1275
|
return (self.R - self.r * np.cos(v)) * P - self.r * np.sin(v) * OUT
|