manim 0.18.0__py3-none-any.whl → 0.18.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of manim might be problematic. Click here for more details.
- manim/__init__.py +3 -6
- manim/__main__.py +18 -10
- manim/_config/__init__.py +5 -2
- manim/_config/cli_colors.py +12 -8
- manim/_config/default.cfg +1 -1
- manim/_config/logger_utils.py +9 -8
- manim/_config/utils.py +637 -449
- manim/animation/animation.py +9 -2
- manim/animation/composition.py +78 -40
- manim/animation/creation.py +12 -6
- manim/animation/fading.py +0 -1
- manim/animation/indication.py +10 -21
- manim/animation/movement.py +1 -2
- manim/animation/rotation.py +1 -1
- manim/animation/specialized.py +1 -1
- manim/animation/speedmodifier.py +7 -2
- manim/animation/transform_matching_parts.py +1 -1
- manim/camera/camera.py +13 -4
- manim/cli/cfg/group.py +18 -8
- manim/cli/checkhealth/checks.py +2 -0
- manim/cli/checkhealth/commands.py +2 -0
- manim/cli/default_group.py +13 -5
- manim/cli/init/commands.py +4 -1
- manim/cli/plugins/commands.py +3 -0
- manim/cli/render/commands.py +27 -20
- manim/cli/render/ease_of_access_options.py +4 -3
- manim/cli/render/global_options.py +9 -7
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +13 -13
- manim/constants.py +54 -15
- manim/gui/gui.py +2 -0
- manim/mobject/geometry/arc.py +4 -4
- manim/mobject/geometry/boolean_ops.py +13 -9
- manim/mobject/geometry/line.py +16 -8
- manim/mobject/geometry/polygram.py +17 -5
- manim/mobject/geometry/tips.py +2 -2
- manim/mobject/graph.py +379 -106
- manim/mobject/graphing/coordinate_systems.py +17 -20
- manim/mobject/graphing/functions.py +14 -10
- manim/mobject/graphing/number_line.py +1 -1
- manim/mobject/mobject.py +175 -72
- manim/mobject/opengl/opengl_compatibility.py +2 -0
- manim/mobject/opengl/opengl_geometry.py +26 -1
- manim/mobject/opengl/opengl_image_mobject.py +2 -0
- manim/mobject/opengl/opengl_mobject.py +3 -0
- manim/mobject/opengl/opengl_point_cloud_mobject.py +2 -0
- manim/mobject/opengl/opengl_surface.py +2 -0
- manim/mobject/opengl/opengl_three_dimensions.py +2 -0
- manim/mobject/opengl/opengl_vectorized_mobject.py +19 -14
- manim/mobject/svg/brace.py +2 -0
- manim/mobject/svg/svg_mobject.py +10 -12
- manim/mobject/table.py +0 -1
- manim/mobject/text/code_mobject.py +2 -0
- manim/mobject/text/numbers.py +2 -0
- manim/mobject/text/tex_mobject.py +1 -1
- manim/mobject/text/text_mobject.py +43 -6
- manim/mobject/three_d/three_d_utils.py +4 -4
- manim/mobject/three_d/three_dimensions.py +4 -4
- manim/mobject/types/image_mobject.py +5 -1
- manim/mobject/types/point_cloud_mobject.py +2 -0
- manim/mobject/types/vectorized_mobject.py +124 -29
- manim/mobject/value_tracker.py +3 -3
- manim/mobject/vector_field.py +3 -1
- manim/plugins/__init__.py +15 -1
- manim/plugins/plugins_flags.py +11 -5
- manim/renderer/cairo_renderer.py +12 -2
- manim/renderer/opengl_renderer.py +2 -3
- manim/renderer/opengl_renderer_window.py +2 -0
- manim/renderer/shader_wrapper.py +2 -0
- manim/renderer/vectorized_mobject_rendering.py +5 -0
- manim/scene/scene.py +22 -6
- manim/scene/scene_file_writer.py +3 -1
- manim/scene/section.py +2 -0
- manim/scene/three_d_scene.py +5 -6
- manim/scene/vector_space_scene.py +21 -5
- manim/typing.py +567 -67
- manim/utils/bezier.py +9 -18
- manim/utils/caching.py +2 -0
- manim/utils/color/BS381.py +1 -0
- manim/utils/color/XKCD.py +1 -0
- manim/utils/color/core.py +31 -13
- manim/utils/commands.py +8 -1
- manim/utils/debug.py +0 -1
- manim/utils/deprecation.py +3 -2
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +197 -0
- manim/utils/docbuild/autocolor_directive.py +9 -4
- manim/utils/docbuild/manim_directive.py +18 -9
- manim/utils/docbuild/module_parsing.py +198 -0
- manim/utils/exceptions.py +6 -0
- manim/utils/family.py +2 -0
- manim/utils/family_ops.py +5 -0
- manim/utils/file_ops.py +6 -2
- manim/utils/hashing.py +2 -0
- manim/utils/ipython_magic.py +2 -0
- manim/utils/module_ops.py +2 -0
- manim/utils/opengl.py +14 -0
- manim/utils/parameter_parsing.py +31 -0
- manim/utils/paths.py +12 -20
- manim/utils/rate_functions.py +6 -8
- manim/utils/space_ops.py +81 -36
- manim/utils/testing/__init__.py +17 -0
- manim/utils/testing/frames_comparison.py +7 -5
- manim/utils/tex.py +124 -196
- manim/utils/tex_file_writing.py +2 -0
- manim/utils/tex_templates.py +1 -0
- {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/METADATA +29 -35
- {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/RECORD +112 -112
- {manim-0.18.0.dist-info → manim-0.18.1.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.dist-info → manim-0.18.1.dist-info}/LICENSE +0 -0
- {manim-0.18.0.dist-info → manim-0.18.1.dist-info}/entry_points.txt +0 -0
manim/mobject/svg/svg_mobject.py
CHANGED
|
@@ -441,9 +441,9 @@ class SVGMobject(VMobject, metaclass=ConvertToOpenGL):
|
|
|
441
441
|
if self.should_center:
|
|
442
442
|
self.center()
|
|
443
443
|
if self.svg_height is not None:
|
|
444
|
-
self.
|
|
444
|
+
self.set(height=self.svg_height)
|
|
445
445
|
if self.svg_width is not None:
|
|
446
|
-
self.
|
|
446
|
+
self.set(width=self.svg_width)
|
|
447
447
|
|
|
448
448
|
|
|
449
449
|
class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
|
|
@@ -510,17 +510,15 @@ class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
|
|
|
510
510
|
all_points: list[np.ndarray] = []
|
|
511
511
|
last_move = None
|
|
512
512
|
curve_start = None
|
|
513
|
+
last_true_move = None
|
|
513
514
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
# of updating this Mobject's numpy array of points. This way,
|
|
517
|
-
# we don't observe O(n^2) behavior for complex paths due to
|
|
518
|
-
# numpy's need to re-allocate memory on every append.
|
|
519
|
-
def move_pen(pt):
|
|
520
|
-
nonlocal last_move, curve_start
|
|
515
|
+
def move_pen(pt, *, true_move: bool = False):
|
|
516
|
+
nonlocal last_move, curve_start, last_true_move
|
|
521
517
|
last_move = pt
|
|
522
518
|
if curve_start is None:
|
|
523
519
|
curve_start = last_move
|
|
520
|
+
if true_move:
|
|
521
|
+
last_true_move = last_move
|
|
524
522
|
|
|
525
523
|
if self.n_points_per_curve == 4:
|
|
526
524
|
|
|
@@ -568,7 +566,7 @@ class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
|
|
|
568
566
|
for segment in self.path_obj:
|
|
569
567
|
segment_class = segment.__class__
|
|
570
568
|
if segment_class == se.Move:
|
|
571
|
-
move_pen(_convert_point_to_3d(*segment.end))
|
|
569
|
+
move_pen(_convert_point_to_3d(*segment.end), true_move=True)
|
|
572
570
|
elif segment_class == se.Line:
|
|
573
571
|
add_line(last_move, _convert_point_to_3d(*segment.end))
|
|
574
572
|
elif segment_class == se.QuadraticBezier:
|
|
@@ -588,8 +586,8 @@ class VMobjectFromSVGPath(VMobject, metaclass=ConvertToOpenGL):
|
|
|
588
586
|
# If the SVG path naturally ends at the beginning of the curve,
|
|
589
587
|
# we do *not* need to draw a closing line. To account for floating
|
|
590
588
|
# point precision, we use a small value to compare the two points.
|
|
591
|
-
if abs(np.linalg.norm(last_move -
|
|
592
|
-
add_line(last_move,
|
|
589
|
+
if abs(np.linalg.norm(last_move - last_true_move)) > 0.0001:
|
|
590
|
+
add_line(last_move, last_true_move)
|
|
593
591
|
curve_start = None
|
|
594
592
|
else:
|
|
595
593
|
raise AssertionError(f"Not implemented: {segment_class}")
|
manim/mobject/table.py
CHANGED
|
@@ -74,7 +74,6 @@ from manim.mobject.text.numbers import DecimalNumber, Integer
|
|
|
74
74
|
from manim.mobject.text.tex_mobject import MathTex
|
|
75
75
|
from manim.mobject.text.text_mobject import Paragraph
|
|
76
76
|
|
|
77
|
-
from .. import config
|
|
78
77
|
from ..animation.animation import Animation
|
|
79
78
|
from ..animation.composition import AnimationGroup
|
|
80
79
|
from ..animation.creation import Create, Write
|
manim/mobject/text/numbers.py
CHANGED
|
@@ -34,7 +34,7 @@ from manim import config, logger
|
|
|
34
34
|
from manim.constants import *
|
|
35
35
|
from manim.mobject.geometry.line import Line
|
|
36
36
|
from manim.mobject.svg.svg_mobject import SVGMobject
|
|
37
|
-
from manim.mobject.types.vectorized_mobject import
|
|
37
|
+
from manim.mobject.types.vectorized_mobject import VGroup, VMobject
|
|
38
38
|
from manim.utils.tex import TexTemplate
|
|
39
39
|
from manim.utils.tex_file_writing import tex_to_svg_file
|
|
40
40
|
|
|
@@ -49,6 +49,8 @@ Examples
|
|
|
49
49
|
|
|
50
50
|
from __future__ import annotations
|
|
51
51
|
|
|
52
|
+
import functools
|
|
53
|
+
|
|
52
54
|
__all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
|
|
53
55
|
|
|
54
56
|
|
|
@@ -77,6 +79,8 @@ TEXT_MOB_SCALE_FACTOR = 0.05
|
|
|
77
79
|
DEFAULT_LINE_SPACING_SCALE = 0.3
|
|
78
80
|
TEXT2SVG_ADJUSTMENT_FACTOR = 4.8
|
|
79
81
|
|
|
82
|
+
__all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
|
|
83
|
+
|
|
80
84
|
|
|
81
85
|
def remove_invisible_chars(mobject: SVGMobject) -> SVGMobject:
|
|
82
86
|
"""Function to remove unwanted invisible characters from some mobjects.
|
|
@@ -350,7 +354,7 @@ class Text(SVGMobject):
|
|
|
350
354
|
)
|
|
351
355
|
text6.scale(1.3).shift(DOWN)
|
|
352
356
|
self.add(text1, text2, text3, text4, text5 , text6)
|
|
353
|
-
Group(*self.mobjects).arrange(DOWN, buff=.8).
|
|
357
|
+
Group(*self.mobjects).arrange(DOWN, buff=.8).set(height=config.frame_height-LARGE_BUFF)
|
|
354
358
|
|
|
355
359
|
.. manim:: TextMoreCustomization
|
|
356
360
|
:save_last_frame:
|
|
@@ -407,6 +411,11 @@ class Text(SVGMobject):
|
|
|
407
411
|
|
|
408
412
|
"""
|
|
409
413
|
|
|
414
|
+
@staticmethod
|
|
415
|
+
@functools.lru_cache(maxsize=None)
|
|
416
|
+
def font_list() -> list[str]:
|
|
417
|
+
return manimpango.list_fonts()
|
|
418
|
+
|
|
410
419
|
def __init__(
|
|
411
420
|
self,
|
|
412
421
|
text: str,
|
|
@@ -431,13 +440,25 @@ class Text(SVGMobject):
|
|
|
431
440
|
width: float = None,
|
|
432
441
|
should_center: bool = True,
|
|
433
442
|
disable_ligatures: bool = False,
|
|
443
|
+
use_svg_cache: bool = False,
|
|
434
444
|
**kwargs,
|
|
435
445
|
) -> None:
|
|
436
446
|
self.line_spacing = line_spacing
|
|
437
447
|
if font and warn_missing_font:
|
|
438
|
-
fonts_list =
|
|
448
|
+
fonts_list = Text.font_list()
|
|
449
|
+
# handle special case of sans/sans-serif
|
|
450
|
+
if font.lower() == "sans-serif":
|
|
451
|
+
font = "sans"
|
|
439
452
|
if font not in fonts_list:
|
|
440
|
-
|
|
453
|
+
# check if the capitalized version is in the supported fonts
|
|
454
|
+
if font.capitalize() in fonts_list:
|
|
455
|
+
font = font.capitalize()
|
|
456
|
+
elif font.lower() in fonts_list:
|
|
457
|
+
font = font.lower()
|
|
458
|
+
elif font.title() in fonts_list:
|
|
459
|
+
font = font.title()
|
|
460
|
+
else:
|
|
461
|
+
logger.warning(f"Font {font} not in {fonts_list}.")
|
|
441
462
|
self.font = font
|
|
442
463
|
self._font_size = float(font_size)
|
|
443
464
|
# needs to be a float or else size is inflated when font_size = 24
|
|
@@ -491,7 +512,7 @@ class Text(SVGMobject):
|
|
|
491
512
|
height=height,
|
|
492
513
|
width=width,
|
|
493
514
|
should_center=should_center,
|
|
494
|
-
use_svg_cache=
|
|
515
|
+
use_svg_cache=use_svg_cache,
|
|
495
516
|
**kwargs,
|
|
496
517
|
)
|
|
497
518
|
self.text = text
|
|
@@ -1133,6 +1154,11 @@ class MarkupText(SVGMobject):
|
|
|
1133
1154
|
|
|
1134
1155
|
"""
|
|
1135
1156
|
|
|
1157
|
+
@staticmethod
|
|
1158
|
+
@functools.lru_cache(maxsize=None)
|
|
1159
|
+
def font_list() -> list[str]:
|
|
1160
|
+
return manimpango.list_fonts()
|
|
1161
|
+
|
|
1136
1162
|
def __init__(
|
|
1137
1163
|
self,
|
|
1138
1164
|
text: str,
|
|
@@ -1157,9 +1183,20 @@ class MarkupText(SVGMobject):
|
|
|
1157
1183
|
self.text = text
|
|
1158
1184
|
self.line_spacing = line_spacing
|
|
1159
1185
|
if font and warn_missing_font:
|
|
1160
|
-
fonts_list =
|
|
1186
|
+
fonts_list = Text.font_list()
|
|
1187
|
+
# handle special case of sans/sans-serif
|
|
1188
|
+
if font.lower() == "sans-serif":
|
|
1189
|
+
font = "sans"
|
|
1161
1190
|
if font not in fonts_list:
|
|
1162
|
-
|
|
1191
|
+
# check if the capitalized version is in the supported fonts
|
|
1192
|
+
if font.capitalize() in fonts_list:
|
|
1193
|
+
font = font.capitalize()
|
|
1194
|
+
elif font.lower() in fonts_list:
|
|
1195
|
+
font = font.lower()
|
|
1196
|
+
elif font.title() in fonts_list:
|
|
1197
|
+
font = font.title()
|
|
1198
|
+
else:
|
|
1199
|
+
logger.warning(f"Font {font} not in {fonts_list}.")
|
|
1163
1200
|
self.font = font
|
|
1164
1201
|
self._font_size = float(font_size)
|
|
1165
1202
|
self.slant = slant
|
|
@@ -22,7 +22,7 @@ from manim.constants import ORIGIN, UP
|
|
|
22
22
|
from manim.utils.space_ops import get_unit_normal
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
|
-
from manim.typing import Point3D,
|
|
25
|
+
from manim.typing import Point3D, Vector3D
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def get_3d_vmob_gradient_start_and_end_points(vmob) -> tuple[Point3D, Point3D]:
|
|
@@ -52,7 +52,7 @@ def get_3d_vmob_end_corner(vmob) -> Point3D:
|
|
|
52
52
|
return vmob.points[get_3d_vmob_end_corner_index(vmob)]
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def get_3d_vmob_unit_normal(vmob, point_index: int) ->
|
|
55
|
+
def get_3d_vmob_unit_normal(vmob, point_index: int) -> Vector3D:
|
|
56
56
|
n_points = vmob.get_num_points()
|
|
57
57
|
if len(vmob.get_anchors()) <= 2:
|
|
58
58
|
return np.array(UP)
|
|
@@ -68,9 +68,9 @@ def get_3d_vmob_unit_normal(vmob, point_index: int) -> Vector:
|
|
|
68
68
|
return unit_normal
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def get_3d_vmob_start_corner_unit_normal(vmob) ->
|
|
71
|
+
def get_3d_vmob_start_corner_unit_normal(vmob) -> Vector3D:
|
|
72
72
|
return get_3d_vmob_unit_normal(vmob, get_3d_vmob_start_corner_index(vmob))
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def get_3d_vmob_end_corner_unit_normal(vmob) ->
|
|
75
|
+
def get_3d_vmob_end_corner_unit_normal(vmob) -> Vector3D:
|
|
76
76
|
return get_3d_vmob_unit_normal(vmob, get_3d_vmob_end_corner_index(vmob))
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from manim.typing import Point3D,
|
|
5
|
+
from manim.typing import Point3D, Vector3D
|
|
6
6
|
from manim.utils.color import BLUE, BLUE_D, BLUE_E, LIGHT_GREY, WHITE, interpolate_color
|
|
7
7
|
|
|
8
8
|
__all__ = [
|
|
@@ -953,7 +953,7 @@ class Line3D(Cylinder):
|
|
|
953
953
|
def pointify(
|
|
954
954
|
self,
|
|
955
955
|
mob_or_point: Mobject | Point3D,
|
|
956
|
-
direction:
|
|
956
|
+
direction: Vector3D = None,
|
|
957
957
|
) -> np.ndarray:
|
|
958
958
|
"""Gets a point representing the center of the :class:`Mobjects <.Mobject>`.
|
|
959
959
|
|
|
@@ -1001,7 +1001,7 @@ class Line3D(Cylinder):
|
|
|
1001
1001
|
def parallel_to(
|
|
1002
1002
|
cls,
|
|
1003
1003
|
line: Line3D,
|
|
1004
|
-
point:
|
|
1004
|
+
point: Vector3D = ORIGIN,
|
|
1005
1005
|
length: float = 5,
|
|
1006
1006
|
**kwargs,
|
|
1007
1007
|
) -> Line3D:
|
|
@@ -1049,7 +1049,7 @@ class Line3D(Cylinder):
|
|
|
1049
1049
|
def perpendicular_to(
|
|
1050
1050
|
cls,
|
|
1051
1051
|
line: Line3D,
|
|
1052
|
-
point:
|
|
1052
|
+
point: Vector3D = ORIGIN,
|
|
1053
1053
|
length: float = 5,
|
|
1054
1054
|
**kwargs,
|
|
1055
1055
|
) -> Line3D:
|
|
@@ -19,6 +19,8 @@ from ...utils.bezier import interpolate
|
|
|
19
19
|
from ...utils.color import WHITE, ManimColor, color_to_int_rgb
|
|
20
20
|
from ...utils.images import change_to_rgba_array, get_full_raster_image_path
|
|
21
21
|
|
|
22
|
+
__all__ = ["ImageMobject", "ImageMobjectFromCamera"]
|
|
23
|
+
|
|
22
24
|
|
|
23
25
|
class AbstractImageMobject(Mobject):
|
|
24
26
|
"""
|
|
@@ -191,7 +193,9 @@ class ImageMobject(AbstractImageMobject):
|
|
|
191
193
|
self.pixel_array, self.pixel_array_dtype
|
|
192
194
|
)
|
|
193
195
|
if self.invert:
|
|
194
|
-
self.pixel_array[:, :, :3] =
|
|
196
|
+
self.pixel_array[:, :, :3] = (
|
|
197
|
+
np.iinfo(self.pixel_array_dtype).max - self.pixel_array[:, :, :3]
|
|
198
|
+
)
|
|
195
199
|
super().__init__(scale_to_resolution, **kwargs)
|
|
196
200
|
|
|
197
201
|
def get_pixel_array(self):
|
|
@@ -23,6 +23,8 @@ from ...utils.color import (
|
|
|
23
23
|
)
|
|
24
24
|
from ...utils.iterables import stretch_array_to_length
|
|
25
25
|
|
|
26
|
+
__all__ = ["PMobject", "Mobject1D", "Mobject2D", "PGroup", "PointCloudDot", "Point"]
|
|
27
|
+
|
|
26
28
|
|
|
27
29
|
class PMobject(Mobject, metaclass=ConvertToOpenGL):
|
|
28
30
|
"""A disc made of a cloud of Dots
|
|
@@ -26,20 +26,17 @@ from typing import (
|
|
|
26
26
|
)
|
|
27
27
|
|
|
28
28
|
import numpy as np
|
|
29
|
-
import numpy.typing as npt
|
|
30
29
|
from PIL.Image import Image
|
|
31
|
-
from typing_extensions import Self
|
|
32
30
|
|
|
31
|
+
from manim import config
|
|
32
|
+
from manim.constants import *
|
|
33
|
+
from manim.mobject.mobject import Mobject
|
|
33
34
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
34
35
|
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVMobject
|
|
35
36
|
from manim.mobject.three_d.three_d_utils import (
|
|
36
37
|
get_3d_vmob_gradient_start_and_end_points,
|
|
37
38
|
)
|
|
38
|
-
|
|
39
|
-
from ... import config
|
|
40
|
-
from ...constants import *
|
|
41
|
-
from ...mobject.mobject import Mobject
|
|
42
|
-
from ...utils.bezier import (
|
|
39
|
+
from manim.utils.bezier import (
|
|
43
40
|
bezier,
|
|
44
41
|
get_smooth_handle_points,
|
|
45
42
|
integer_interpolate,
|
|
@@ -47,11 +44,19 @@ from ...utils.bezier import (
|
|
|
47
44
|
partial_bezier_points,
|
|
48
45
|
proportions_along_bezier_curve_for_point,
|
|
49
46
|
)
|
|
50
|
-
from
|
|
51
|
-
from
|
|
52
|
-
|
|
47
|
+
from manim.utils.color import BLACK, WHITE, ManimColor, ParsableManimColor
|
|
48
|
+
from manim.utils.iterables import (
|
|
49
|
+
make_even,
|
|
50
|
+
resize_array,
|
|
51
|
+
stretch_array_to_length,
|
|
52
|
+
tuplify,
|
|
53
|
+
)
|
|
54
|
+
from manim.utils.space_ops import rotate_vector, shoelace_direction
|
|
53
55
|
|
|
54
56
|
if TYPE_CHECKING:
|
|
57
|
+
import numpy.typing as npt
|
|
58
|
+
from typing_extensions import Self
|
|
59
|
+
|
|
55
60
|
from manim.typing import (
|
|
56
61
|
BezierPoints,
|
|
57
62
|
CubicBezierPoints,
|
|
@@ -62,7 +67,7 @@ if TYPE_CHECKING:
|
|
|
62
67
|
Point3D_Array,
|
|
63
68
|
QuadraticBezierPoints,
|
|
64
69
|
RGBA_Array_Float,
|
|
65
|
-
|
|
70
|
+
Vector3D,
|
|
66
71
|
Zeros,
|
|
67
72
|
)
|
|
68
73
|
|
|
@@ -74,6 +79,16 @@ if TYPE_CHECKING:
|
|
|
74
79
|
# - Think about length of self.points. Always 0 or 1 mod 4?
|
|
75
80
|
# That's kind of weird.
|
|
76
81
|
|
|
82
|
+
__all__ = [
|
|
83
|
+
"VMobject",
|
|
84
|
+
"VGroup",
|
|
85
|
+
"VDict",
|
|
86
|
+
"VectorizedPoint",
|
|
87
|
+
"CurvesAsSubmobjects",
|
|
88
|
+
"VectorizedPoint",
|
|
89
|
+
"DashedVMobject",
|
|
90
|
+
]
|
|
91
|
+
|
|
77
92
|
|
|
78
93
|
class VMobject(Mobject):
|
|
79
94
|
"""A vectorized mobject.
|
|
@@ -114,7 +129,7 @@ class VMobject(Mobject):
|
|
|
114
129
|
background_stroke_width: float = 0,
|
|
115
130
|
sheen_factor: float = 0.0,
|
|
116
131
|
joint_type: LineJointType | None = None,
|
|
117
|
-
sheen_direction:
|
|
132
|
+
sheen_direction: Vector3D = UL,
|
|
118
133
|
close_new_points: bool = False,
|
|
119
134
|
pre_function_handle_to_anchor_scale_factor: float = 0.01,
|
|
120
135
|
make_smooth_after_applying_functions: bool = False,
|
|
@@ -123,6 +138,7 @@ class VMobject(Mobject):
|
|
|
123
138
|
# TODO, do we care about accounting for varying zoom levels?
|
|
124
139
|
tolerance_for_point_equality: float = 1e-6,
|
|
125
140
|
n_points_per_cubic_curve: int = 4,
|
|
141
|
+
cap_style: CapStyleType = CapStyleType.AUTO,
|
|
126
142
|
**kwargs,
|
|
127
143
|
):
|
|
128
144
|
self.fill_opacity = fill_opacity
|
|
@@ -138,7 +154,7 @@ class VMobject(Mobject):
|
|
|
138
154
|
self.joint_type: LineJointType = (
|
|
139
155
|
LineJointType.AUTO if joint_type is None else joint_type
|
|
140
156
|
)
|
|
141
|
-
self.sheen_direction:
|
|
157
|
+
self.sheen_direction: Vector3D = sheen_direction
|
|
142
158
|
self.close_new_points: bool = close_new_points
|
|
143
159
|
self.pre_function_handle_to_anchor_scale_factor: float = (
|
|
144
160
|
pre_function_handle_to_anchor_scale_factor
|
|
@@ -150,6 +166,7 @@ class VMobject(Mobject):
|
|
|
150
166
|
self.shade_in_3d: bool = shade_in_3d
|
|
151
167
|
self.tolerance_for_point_equality: float = tolerance_for_point_equality
|
|
152
168
|
self.n_points_per_cubic_curve: int = n_points_per_cubic_curve
|
|
169
|
+
self.cap_style: CapStyleType = cap_style
|
|
153
170
|
super().__init__(**kwargs)
|
|
154
171
|
self.submobjects: list[VMobject]
|
|
155
172
|
|
|
@@ -335,11 +352,39 @@ class VMobject(Mobject):
|
|
|
335
352
|
setattr(self, opacity_name, opacity)
|
|
336
353
|
if color is not None and background:
|
|
337
354
|
if isinstance(color, (list, tuple)):
|
|
338
|
-
self.background_stroke_color = color
|
|
355
|
+
self.background_stroke_color = ManimColor.parse(color)
|
|
339
356
|
else:
|
|
340
357
|
self.background_stroke_color = ManimColor(color)
|
|
341
358
|
return self
|
|
342
359
|
|
|
360
|
+
def set_cap_style(self, cap_style: CapStyleType) -> Self:
|
|
361
|
+
"""
|
|
362
|
+
Sets the cap style of the :class:`VMobject`.
|
|
363
|
+
|
|
364
|
+
Parameters
|
|
365
|
+
----------
|
|
366
|
+
cap_style
|
|
367
|
+
The cap style to be set. See :class:`.CapStyleType` for options.
|
|
368
|
+
|
|
369
|
+
Returns
|
|
370
|
+
-------
|
|
371
|
+
:class:`VMobject`
|
|
372
|
+
``self``
|
|
373
|
+
|
|
374
|
+
Examples
|
|
375
|
+
--------
|
|
376
|
+
.. manim:: CapStyleExample
|
|
377
|
+
:save_last_frame:
|
|
378
|
+
|
|
379
|
+
class CapStyleExample(Scene):
|
|
380
|
+
def construct(self):
|
|
381
|
+
line = Line(LEFT, RIGHT, color=YELLOW, stroke_width=20)
|
|
382
|
+
line.set_cap_style(CapStyleType.ROUND)
|
|
383
|
+
self.add(line)
|
|
384
|
+
"""
|
|
385
|
+
self.cap_style = cap_style
|
|
386
|
+
return self
|
|
387
|
+
|
|
343
388
|
def set_background_stroke(self, **kwargs) -> Self:
|
|
344
389
|
kwargs["background"] = True
|
|
345
390
|
self.set_stroke(**kwargs)
|
|
@@ -356,7 +401,7 @@ class VMobject(Mobject):
|
|
|
356
401
|
background_stroke_width: float | None = None,
|
|
357
402
|
background_stroke_opacity: float | None = None,
|
|
358
403
|
sheen_factor: float | None = None,
|
|
359
|
-
sheen_direction:
|
|
404
|
+
sheen_direction: Vector3D | None = None,
|
|
360
405
|
background_image: Image | str | None = None,
|
|
361
406
|
family: bool = True,
|
|
362
407
|
) -> Self:
|
|
@@ -523,7 +568,7 @@ class VMobject(Mobject):
|
|
|
523
568
|
|
|
524
569
|
color = property(get_color, set_color)
|
|
525
570
|
|
|
526
|
-
def set_sheen_direction(self, direction:
|
|
571
|
+
def set_sheen_direction(self, direction: Vector3D, family: bool = True) -> Self:
|
|
527
572
|
"""Sets the direction of the applied sheen.
|
|
528
573
|
|
|
529
574
|
Parameters
|
|
@@ -548,11 +593,11 @@ class VMobject(Mobject):
|
|
|
548
593
|
for submob in self.get_family():
|
|
549
594
|
submob.sheen_direction = direction
|
|
550
595
|
else:
|
|
551
|
-
self.sheen_direction:
|
|
596
|
+
self.sheen_direction: Vector3D = direction
|
|
552
597
|
return self
|
|
553
598
|
|
|
554
599
|
def rotate_sheen_direction(
|
|
555
|
-
self, angle: float, axis:
|
|
600
|
+
self, angle: float, axis: Vector3D = OUT, family: bool = True
|
|
556
601
|
) -> Self:
|
|
557
602
|
"""Rotates the direction of the applied sheen.
|
|
558
603
|
|
|
@@ -585,7 +630,7 @@ class VMobject(Mobject):
|
|
|
585
630
|
return self
|
|
586
631
|
|
|
587
632
|
def set_sheen(
|
|
588
|
-
self, factor: float, direction:
|
|
633
|
+
self, factor: float, direction: Vector3D | None = None, family: bool = True
|
|
589
634
|
) -> Self:
|
|
590
635
|
"""Applies a color gradient from a direction.
|
|
591
636
|
|
|
@@ -623,7 +668,7 @@ class VMobject(Mobject):
|
|
|
623
668
|
self.set_fill(self.get_fill_color(), family=family)
|
|
624
669
|
return self
|
|
625
670
|
|
|
626
|
-
def get_sheen_direction(self) ->
|
|
671
|
+
def get_sheen_direction(self) -> Vector3D:
|
|
627
672
|
return np.array(self.sheen_direction)
|
|
628
673
|
|
|
629
674
|
def get_sheen_factor(self) -> float:
|
|
@@ -917,6 +962,27 @@ class VMobject(Mobject):
|
|
|
917
962
|
-------
|
|
918
963
|
:class:`VMobject`
|
|
919
964
|
``self``
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
Examples
|
|
968
|
+
--------
|
|
969
|
+
.. manim:: PointsAsCornersExample
|
|
970
|
+
:save_last_frame:
|
|
971
|
+
|
|
972
|
+
class PointsAsCornersExample(Scene):
|
|
973
|
+
def construct(self):
|
|
974
|
+
corners = (
|
|
975
|
+
# create square
|
|
976
|
+
UR, UL,
|
|
977
|
+
DL, DR,
|
|
978
|
+
UR,
|
|
979
|
+
# create crosses
|
|
980
|
+
DL, UL,
|
|
981
|
+
DR
|
|
982
|
+
)
|
|
983
|
+
vmob = VMobject(stroke_color=RED)
|
|
984
|
+
vmob.set_points_as_corners(corners).scale(2)
|
|
985
|
+
self.add(vmob)
|
|
920
986
|
"""
|
|
921
987
|
nppcc = self.n_points_per_cubic_curve
|
|
922
988
|
points = np.array(points)
|
|
@@ -998,7 +1064,7 @@ class VMobject(Mobject):
|
|
|
998
1064
|
def rotate(
|
|
999
1065
|
self,
|
|
1000
1066
|
angle: float,
|
|
1001
|
-
axis:
|
|
1067
|
+
axis: Vector3D = OUT,
|
|
1002
1068
|
about_point: Point3D | None = None,
|
|
1003
1069
|
**kwargs,
|
|
1004
1070
|
) -> Self:
|
|
@@ -1342,6 +1408,22 @@ class VMobject(Mobject):
|
|
|
1342
1408
|
If ``alpha`` is not between 0 and 1.
|
|
1343
1409
|
:exc:`Exception`
|
|
1344
1410
|
If the :class:`VMobject` has no points.
|
|
1411
|
+
|
|
1412
|
+
Example
|
|
1413
|
+
-------
|
|
1414
|
+
.. manim:: PointFromProportion
|
|
1415
|
+
:save_last_frame:
|
|
1416
|
+
|
|
1417
|
+
class PointFromProportion(Scene):
|
|
1418
|
+
def construct(self):
|
|
1419
|
+
line = Line(2*DL, 2*UR)
|
|
1420
|
+
self.add(line)
|
|
1421
|
+
colors = (RED, BLUE, YELLOW)
|
|
1422
|
+
proportions = (1/4, 1/2, 3/4)
|
|
1423
|
+
for color, proportion in zip(colors, proportions):
|
|
1424
|
+
self.add(Dot(color=color).move_to(
|
|
1425
|
+
line.point_from_proportion(proportion)
|
|
1426
|
+
))
|
|
1345
1427
|
"""
|
|
1346
1428
|
|
|
1347
1429
|
if alpha < 0 or alpha > 1:
|
|
@@ -1366,6 +1448,9 @@ class VMobject(Mobject):
|
|
|
1366
1448
|
return curve(residue)
|
|
1367
1449
|
|
|
1368
1450
|
current_length += length
|
|
1451
|
+
raise Exception(
|
|
1452
|
+
"Not sure how you reached here, please file a bug report at https://github.com/ManimCommunity/manim/issues/new/choose"
|
|
1453
|
+
)
|
|
1369
1454
|
|
|
1370
1455
|
def proportion_from_point(
|
|
1371
1456
|
self,
|
|
@@ -1468,9 +1553,10 @@ class VMobject(Mobject):
|
|
|
1468
1553
|
"""
|
|
1469
1554
|
if self.points.shape[0] == 1:
|
|
1470
1555
|
return self.points
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
)
|
|
1556
|
+
|
|
1557
|
+
s = self.get_start_anchors()
|
|
1558
|
+
e = self.get_end_anchors()
|
|
1559
|
+
return list(it.chain.from_iterable(zip(s, e)))
|
|
1474
1560
|
|
|
1475
1561
|
def get_points_defining_boundary(self) -> Point3D_Array:
|
|
1476
1562
|
# Probably returns all anchors, but this is weird regarding the name of the method.
|
|
@@ -1690,7 +1776,10 @@ class VMobject(Mobject):
|
|
|
1690
1776
|
interpolate(getattr(mobject1, attr), getattr(mobject2, attr), alpha),
|
|
1691
1777
|
)
|
|
1692
1778
|
if alpha == 1.0:
|
|
1693
|
-
|
|
1779
|
+
val = getattr(mobject2, attr)
|
|
1780
|
+
if isinstance(val, np.ndarray):
|
|
1781
|
+
val = val.copy()
|
|
1782
|
+
setattr(self, attr, val)
|
|
1694
1783
|
|
|
1695
1784
|
def pointwise_become_partial(
|
|
1696
1785
|
self,
|
|
@@ -1963,8 +2052,14 @@ class VGroup(VMobject, metaclass=ConvertToOpenGL):
|
|
|
1963
2052
|
(gr-circle_red).animate.shift(RIGHT)
|
|
1964
2053
|
)
|
|
1965
2054
|
"""
|
|
1966
|
-
|
|
1967
|
-
|
|
2055
|
+
for m in vmobjects:
|
|
2056
|
+
if not isinstance(m, (VMobject, OpenGLVMobject)):
|
|
2057
|
+
raise TypeError(
|
|
2058
|
+
f"All submobjects of {self.__class__.__name__} must be of type VMobject. "
|
|
2059
|
+
f"Got {repr(m)} ({type(m).__name__}) instead. "
|
|
2060
|
+
"You can try using `Group` instead."
|
|
2061
|
+
)
|
|
2062
|
+
|
|
1968
2063
|
return super().add(*vmobjects)
|
|
1969
2064
|
|
|
1970
2065
|
def __add__(self, vmobject: VMobject) -> Self:
|
|
@@ -2458,7 +2553,7 @@ class CurvesAsSubmobjects(VGroup):
|
|
|
2458
2553
|
if len(self.submobjects) == 0:
|
|
2459
2554
|
caller_name = sys._getframe(1).f_code.co_name
|
|
2460
2555
|
raise Exception(
|
|
2461
|
-
f"Cannot call CurvesAsSubmobjects.{caller_name} for a CurvesAsSubmobject with no submobjects"
|
|
2556
|
+
f"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject with no submobjects"
|
|
2462
2557
|
)
|
|
2463
2558
|
|
|
2464
2559
|
def _get_submobjects_with_points(self):
|
|
@@ -2468,7 +2563,7 @@ class CurvesAsSubmobjects(VGroup):
|
|
|
2468
2563
|
if len(submobjs_with_pts) == 0:
|
|
2469
2564
|
caller_name = sys._getframe(1).f_code.co_name
|
|
2470
2565
|
raise Exception(
|
|
2471
|
-
f"Cannot call CurvesAsSubmobjects.{caller_name} for a CurvesAsSubmobject whose submobjects have no points"
|
|
2566
|
+
f"Cannot call CurvesAsSubmobjects. {caller_name} for a CurvesAsSubmobject whose submobjects have no points"
|
|
2472
2567
|
)
|
|
2473
2568
|
return submobjs_with_pts
|
|
2474
2569
|
|
manim/mobject/value_tracker.py
CHANGED
|
@@ -45,7 +45,7 @@ class ValueTracker(Mobject, metaclass=ConvertToOpenGL):
|
|
|
45
45
|
self.wait(1)
|
|
46
46
|
tracker -= 4
|
|
47
47
|
self.wait(0.5)
|
|
48
|
-
self.play(tracker.animate.set_value(5))
|
|
48
|
+
self.play(tracker.animate.set_value(5))
|
|
49
49
|
self.wait(0.5)
|
|
50
50
|
self.play(tracker.animate.set_value(3))
|
|
51
51
|
self.play(tracker.animate.increment_value(-2))
|
|
@@ -71,7 +71,7 @@ class ValueTracker(Mobject, metaclass=ConvertToOpenGL):
|
|
|
71
71
|
|
|
72
72
|
def __init__(self, value=0, **kwargs):
|
|
73
73
|
super().__init__(**kwargs)
|
|
74
|
-
self.
|
|
74
|
+
self.set(points=np.zeros((1, 3)))
|
|
75
75
|
self.set_value(value)
|
|
76
76
|
|
|
77
77
|
def get_value(self) -> float:
|
|
@@ -132,7 +132,7 @@ class ValueTracker(Mobject, metaclass=ConvertToOpenGL):
|
|
|
132
132
|
Turns self into an interpolation between mobject1
|
|
133
133
|
and mobject2.
|
|
134
134
|
"""
|
|
135
|
-
self.
|
|
135
|
+
self.set(points=path_func(mobject1.points, mobject2.points, alpha))
|
|
136
136
|
return self
|
|
137
137
|
|
|
138
138
|
|
manim/mobject/vector_field.py
CHANGED
|
@@ -829,7 +829,9 @@ class StreamLines(VectorField):
|
|
|
829
829
|
step = max(1, int(len(points) / self.max_anchors_per_line))
|
|
830
830
|
line.set_points_smoothly(points[::step])
|
|
831
831
|
if self.single_color:
|
|
832
|
-
line.set_stroke(
|
|
832
|
+
line.set_stroke(
|
|
833
|
+
color=self.color, width=self.stroke_width, opacity=opacity
|
|
834
|
+
)
|
|
833
835
|
else:
|
|
834
836
|
if config.renderer == RendererType.OPENGL:
|
|
835
837
|
# scaled for compatibility with cairo
|
manim/plugins/__init__.py
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from manim import config, logger
|
|
4
|
+
|
|
5
|
+
from .plugins_flags import get_plugins, list_plugins
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"get_plugins",
|
|
9
|
+
"list_plugins",
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
requested_plugins: set[str] = set(config["plugins"])
|
|
13
|
+
missing_plugins = requested_plugins - set(get_plugins().keys())
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
if missing_plugins:
|
|
17
|
+
logger.warning("Missing Plugins: %s", missing_plugins)
|