manim 0.18.0.post0__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 +2 -2
- 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.post0.dist-info → manim-0.18.1.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/METADATA +29 -35
- manim-0.18.1.dist-info/RECORD +217 -0
- manim/cli/new/__init__.py +0 -0
- manim/cli/new/group.py +0 -189
- manim/plugins/import_plugins.py +0 -43
- manim-0.18.0.post0.dist-info/RECORD +0 -217
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/LICENSE +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/WHEEL +0 -0
- {manim-0.18.0.post0.dist-info → manim-0.18.1.dist-info}/entry_points.txt +0 -0
manim/animation/animation.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Animate mobjects."""
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
from __future__ import annotations
|
|
5
4
|
|
|
6
5
|
from manim.mobject.opengl.opengl_mobject import OpenGLMobject
|
|
@@ -18,6 +17,8 @@ __all__ = ["Animation", "Wait", "override_animation"]
|
|
|
18
17
|
from copy import deepcopy
|
|
19
18
|
from typing import TYPE_CHECKING, Callable, Iterable, Sequence
|
|
20
19
|
|
|
20
|
+
from typing_extensions import Self
|
|
21
|
+
|
|
21
22
|
if TYPE_CHECKING:
|
|
22
23
|
from manim.scene.scene import Scene
|
|
23
24
|
|
|
@@ -112,7 +113,7 @@ class Animation:
|
|
|
112
113
|
*args,
|
|
113
114
|
use_override=True,
|
|
114
115
|
**kwargs,
|
|
115
|
-
):
|
|
116
|
+
) -> Self:
|
|
116
117
|
if isinstance(mobject, Mobject) and use_override:
|
|
117
118
|
func = mobject.animation_override_for(cls)
|
|
118
119
|
if func is not None:
|
|
@@ -191,6 +192,11 @@ class Animation:
|
|
|
191
192
|
method.
|
|
192
193
|
|
|
193
194
|
"""
|
|
195
|
+
if self.run_time <= 0:
|
|
196
|
+
raise ValueError(
|
|
197
|
+
f"{self} has a run_time of <= 0 seconds, this cannot be rendered correctly. "
|
|
198
|
+
"Please set the run_time to be positive"
|
|
199
|
+
)
|
|
194
200
|
self.starting_mobject = self.create_starting_mobject()
|
|
195
201
|
if self.suspend_mobject_updating:
|
|
196
202
|
# All calls to self.mobject's internal updaters
|
|
@@ -398,6 +404,7 @@ class Animation:
|
|
|
398
404
|
self.run_time = run_time
|
|
399
405
|
return self
|
|
400
406
|
|
|
407
|
+
# TODO: is this getter even necessary?
|
|
401
408
|
def get_run_time(self) -> float:
|
|
402
409
|
"""Get the run time of the animation.
|
|
403
410
|
|
manim/animation/composition.py
CHANGED
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
"""Tools for displaying multiple animations at once."""
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
from __future__ import annotations
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
import types
|
|
6
|
+
from typing import TYPE_CHECKING, Callable, Iterable, Sequence
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
|
|
10
|
+
from manim._config import config
|
|
11
|
+
from manim.animation.animation import Animation, prepare_animation
|
|
12
|
+
from manim.constants import RendererType
|
|
13
|
+
from manim.mobject.mobject import Group, Mobject
|
|
10
14
|
from manim.mobject.opengl.opengl_mobject import OpenGLGroup
|
|
11
|
-
|
|
12
|
-
from
|
|
13
|
-
from
|
|
14
|
-
from
|
|
15
|
-
from ..mobject.mobject import Group, Mobject
|
|
16
|
-
from ..scene.scene import Scene
|
|
17
|
-
from ..utils.iterables import remove_list_redundancies
|
|
18
|
-
from ..utils.rate_functions import linear
|
|
15
|
+
from manim.scene.scene import Scene
|
|
16
|
+
from manim.utils.iterables import remove_list_redundancies
|
|
17
|
+
from manim.utils.parameter_parsing import flatten_iterable_parameters
|
|
18
|
+
from manim.utils.rate_functions import linear
|
|
19
19
|
|
|
20
20
|
if TYPE_CHECKING:
|
|
21
21
|
from manim.mobject.opengl.opengl_vectorized_mobject import OpenGLVGroup
|
|
22
|
-
|
|
23
|
-
from ..mobject.types.vectorized_mobject import VGroup
|
|
22
|
+
from manim.mobject.types.vectorized_mobject import VGroup
|
|
24
23
|
|
|
25
24
|
__all__ = ["AnimationGroup", "Succession", "LaggedStart", "LaggedStartMap"]
|
|
26
25
|
|
|
@@ -54,14 +53,15 @@ class AnimationGroup(Animation):
|
|
|
54
53
|
|
|
55
54
|
def __init__(
|
|
56
55
|
self,
|
|
57
|
-
*animations: Animation,
|
|
56
|
+
*animations: Animation | Iterable[Animation] | types.GeneratorType[Animation],
|
|
58
57
|
group: Group | VGroup | OpenGLGroup | OpenGLVGroup = None,
|
|
59
58
|
run_time: float | None = None,
|
|
60
59
|
rate_func: Callable[[float], float] = linear,
|
|
61
60
|
lag_ratio: float = 0,
|
|
62
61
|
**kwargs,
|
|
63
62
|
) -> None:
|
|
64
|
-
|
|
63
|
+
arg_anim = flatten_iterable_parameters(animations)
|
|
64
|
+
self.animations = [prepare_animation(anim) for anim in arg_anim]
|
|
65
65
|
self.rate_func = rate_func
|
|
66
66
|
self.group = group
|
|
67
67
|
if self.group is None:
|
|
@@ -81,6 +81,17 @@ class AnimationGroup(Animation):
|
|
|
81
81
|
return list(self.group)
|
|
82
82
|
|
|
83
83
|
def begin(self) -> None:
|
|
84
|
+
if self.run_time <= 0:
|
|
85
|
+
tmp = (
|
|
86
|
+
"Please set the run_time to be positive"
|
|
87
|
+
if len(self.animations) != 0
|
|
88
|
+
else "Please add at least one Animation with positive run_time"
|
|
89
|
+
)
|
|
90
|
+
raise ValueError(
|
|
91
|
+
f"{self} has a run_time of 0 seconds, this cannot be "
|
|
92
|
+
f"rendered correctly. {tmp}."
|
|
93
|
+
)
|
|
94
|
+
self.anim_group_time = 0.0
|
|
84
95
|
if self.suspend_mobject_updating:
|
|
85
96
|
self.group.suspend_updating()
|
|
86
97
|
for anim in self.animations:
|
|
@@ -91,8 +102,9 @@ class AnimationGroup(Animation):
|
|
|
91
102
|
anim._setup_scene(scene)
|
|
92
103
|
|
|
93
104
|
def finish(self) -> None:
|
|
94
|
-
|
|
95
|
-
|
|
105
|
+
self.interpolate(1)
|
|
106
|
+
self.anims_begun[:] = True
|
|
107
|
+
self.anims_finished[:] = True
|
|
96
108
|
if self.suspend_mobject_updating:
|
|
97
109
|
self.group.resume_updating()
|
|
98
110
|
|
|
@@ -104,7 +116,9 @@ class AnimationGroup(Animation):
|
|
|
104
116
|
anim.clean_up_from_scene(scene)
|
|
105
117
|
|
|
106
118
|
def update_mobjects(self, dt: float) -> None:
|
|
107
|
-
for anim in self.
|
|
119
|
+
for anim in self.anims_with_timings["anim"][
|
|
120
|
+
self.anims_begun & ~self.anims_finished
|
|
121
|
+
]:
|
|
108
122
|
anim.update_mobjects(dt)
|
|
109
123
|
|
|
110
124
|
def init_run_time(self, run_time) -> float:
|
|
@@ -121,22 +135,30 @@ class AnimationGroup(Animation):
|
|
|
121
135
|
The duration of the animation in seconds.
|
|
122
136
|
"""
|
|
123
137
|
self.build_animations_with_timings()
|
|
124
|
-
if
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
138
|
+
# Note: if lag_ratio < 1, then not necessarily the final animation's
|
|
139
|
+
# end time will be the max end time! Therefore we must calculate the
|
|
140
|
+
# maximum over all the end times, and not just take the last one.
|
|
141
|
+
# Example: if you want to play 2 animations of 10s and 1s with a
|
|
142
|
+
# lag_ratio of 0.1, the 1st one will end at t=10 and the 2nd one will
|
|
143
|
+
# end at t=2, so the AnimationGroup will end at t=10.
|
|
144
|
+
self.max_end_time = max(self.anims_with_timings["end"], default=0)
|
|
128
145
|
return self.max_end_time if run_time is None else run_time
|
|
129
146
|
|
|
130
147
|
def build_animations_with_timings(self) -> None:
|
|
131
148
|
"""Creates a list of triplets of the form (anim, start_time, end_time)."""
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
149
|
+
run_times = np.array([anim.run_time for anim in self.animations])
|
|
150
|
+
num_animations = run_times.shape[0]
|
|
151
|
+
dtype = [("anim", "O"), ("start", "f8"), ("end", "f8")]
|
|
152
|
+
self.anims_with_timings = np.zeros(num_animations, dtype=dtype)
|
|
153
|
+
self.anims_begun = np.zeros(num_animations, dtype=bool)
|
|
154
|
+
self.anims_finished = np.zeros(num_animations, dtype=bool)
|
|
155
|
+
if num_animations == 0:
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
lags = run_times[:-1] * self.lag_ratio
|
|
159
|
+
self.anims_with_timings["anim"] = self.animations
|
|
160
|
+
self.anims_with_timings["start"][1:] = np.add.accumulate(lags)
|
|
161
|
+
self.anims_with_timings["end"] = self.anims_with_timings["start"] + run_times
|
|
140
162
|
|
|
141
163
|
def interpolate(self, alpha: float) -> None:
|
|
142
164
|
# Note, if the run_time of AnimationGroup has been
|
|
@@ -144,14 +166,30 @@ class AnimationGroup(Animation):
|
|
|
144
166
|
# times might not correspond to actual times,
|
|
145
167
|
# e.g. of the surrounding scene. Instead they'd
|
|
146
168
|
# be a rescaled version. But that's okay!
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
169
|
+
anim_group_time = self.rate_func(alpha) * self.max_end_time
|
|
170
|
+
time_goes_back = anim_group_time < self.anim_group_time
|
|
171
|
+
|
|
172
|
+
# Only update ongoing animations
|
|
173
|
+
awt = self.anims_with_timings
|
|
174
|
+
new_begun = anim_group_time >= awt["start"]
|
|
175
|
+
new_finished = anim_group_time > awt["end"]
|
|
176
|
+
to_update = awt[
|
|
177
|
+
(self.anims_begun | new_begun) & (~self.anims_finished | ~new_finished)
|
|
178
|
+
]
|
|
179
|
+
|
|
180
|
+
run_times = to_update["end"] - to_update["start"]
|
|
181
|
+
sub_alphas = (anim_group_time - to_update["start"]) / run_times
|
|
182
|
+
if time_goes_back:
|
|
183
|
+
sub_alphas[sub_alphas < 0] = 0
|
|
184
|
+
else:
|
|
185
|
+
sub_alphas[sub_alphas > 1] = 1
|
|
186
|
+
|
|
187
|
+
for anim_to_update, sub_alpha in zip(to_update["anim"], sub_alphas):
|
|
188
|
+
anim_to_update.interpolate(sub_alpha)
|
|
189
|
+
|
|
190
|
+
self.anim_group_time = anim_group_time
|
|
191
|
+
self.anims_begun = new_begun
|
|
192
|
+
self.anims_finished = new_finished
|
|
155
193
|
|
|
156
194
|
|
|
157
195
|
class Succession(AnimationGroup):
|
|
@@ -226,8 +264,8 @@ class Succession(AnimationGroup):
|
|
|
226
264
|
self.active_animation = self.animations[index]
|
|
227
265
|
self.active_animation._setup_scene(self.scene)
|
|
228
266
|
self.active_animation.begin()
|
|
229
|
-
self.active_start_time = self.anims_with_timings[index][
|
|
230
|
-
self.active_end_time = self.anims_with_timings[index][
|
|
267
|
+
self.active_start_time = self.anims_with_timings[index]["start"]
|
|
268
|
+
self.active_end_time = self.anims_with_timings[index]["end"]
|
|
231
269
|
|
|
232
270
|
def next_animation(self) -> None:
|
|
233
271
|
"""Proceeds to the next animation.
|
|
@@ -244,7 +282,7 @@ class Succession(AnimationGroup):
|
|
|
244
282
|
self.next_animation()
|
|
245
283
|
if self.active_animation is not None and self.active_start_time is not None:
|
|
246
284
|
elapsed = current_time - self.active_start_time
|
|
247
|
-
active_run_time = self.active_animation.
|
|
285
|
+
active_run_time = self.active_animation.run_time
|
|
248
286
|
subalpha = elapsed / active_run_time if active_run_time != 0.0 else 1.0
|
|
249
287
|
self.active_animation.interpolate(subalpha)
|
|
250
288
|
|
manim/animation/creation.py
CHANGED
|
@@ -456,7 +456,7 @@ class SpiralIn(Animation):
|
|
|
456
456
|
fade_in_fraction=0.3,
|
|
457
457
|
**kwargs,
|
|
458
458
|
) -> None:
|
|
459
|
-
self.shapes = shapes
|
|
459
|
+
self.shapes = shapes.copy()
|
|
460
460
|
self.scale_factor = scale_factor
|
|
461
461
|
self.shape_center = shapes.get_center()
|
|
462
462
|
self.fade_in_fraction = fade_in_fraction
|
|
@@ -473,15 +473,21 @@ class SpiralIn(Animation):
|
|
|
473
473
|
|
|
474
474
|
def interpolate_mobject(self, alpha: float) -> None:
|
|
475
475
|
alpha = self.rate_func(alpha)
|
|
476
|
-
for shape in self.shapes:
|
|
476
|
+
for original_shape, shape in zip(self.shapes, self.mobject):
|
|
477
477
|
shape.restore()
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
478
|
+
fill_opacity = original_shape.get_fill_opacity()
|
|
479
|
+
stroke_opacity = original_shape.get_stroke_opacity()
|
|
480
|
+
new_fill_opacity = min(
|
|
481
|
+
fill_opacity, alpha * fill_opacity / self.fade_in_fraction
|
|
482
|
+
)
|
|
483
|
+
new_stroke_opacity = min(
|
|
484
|
+
stroke_opacity, alpha * stroke_opacity / self.fade_in_fraction
|
|
485
|
+
)
|
|
481
486
|
shape.shift((shape.final_position - shape.initial_position) * alpha)
|
|
482
487
|
shape.rotate(TAU * alpha, about_point=self.shape_center)
|
|
483
488
|
shape.rotate(-TAU * alpha, about_point=shape.get_center_of_mass())
|
|
484
|
-
shape.
|
|
489
|
+
shape.set_fill(opacity=new_fill_opacity)
|
|
490
|
+
shape.set_stroke(opacity=new_stroke_opacity)
|
|
485
491
|
|
|
486
492
|
|
|
487
493
|
class ShowIncreasingSubsets(Animation):
|
manim/animation/fading.py
CHANGED
manim/animation/indication.py
CHANGED
|
@@ -31,7 +31,6 @@ __all__ = [
|
|
|
31
31
|
"Flash",
|
|
32
32
|
"ShowPassingFlash",
|
|
33
33
|
"ShowPassingFlashWithThinningStrokeWidth",
|
|
34
|
-
"ShowCreationThenFadeOut",
|
|
35
34
|
"ApplyWave",
|
|
36
35
|
"Circumscribe",
|
|
37
36
|
"Wiggle",
|
|
@@ -131,7 +130,7 @@ class Indicate(Transform):
|
|
|
131
130
|
color
|
|
132
131
|
The color the mobject temporally takes.
|
|
133
132
|
rate_func
|
|
134
|
-
The function
|
|
133
|
+
The function defining the animation progress at every point in time.
|
|
135
134
|
kwargs
|
|
136
135
|
Additional arguments to be passed to the :class:`~.Succession` constructor
|
|
137
136
|
|
|
@@ -148,7 +147,7 @@ class Indicate(Transform):
|
|
|
148
147
|
|
|
149
148
|
def __init__(
|
|
150
149
|
self,
|
|
151
|
-
mobject:
|
|
150
|
+
mobject: Mobject,
|
|
152
151
|
scale_factor: float = 1.2,
|
|
153
152
|
color: str = YELLOW,
|
|
154
153
|
rate_func: Callable[[float, Optional[float]], np.ndarray] = there_and_back,
|
|
@@ -158,7 +157,7 @@ class Indicate(Transform):
|
|
|
158
157
|
self.scale_factor = scale_factor
|
|
159
158
|
super().__init__(mobject, rate_func=rate_func, **kwargs)
|
|
160
159
|
|
|
161
|
-
def create_target(self) ->
|
|
160
|
+
def create_target(self) -> Mobject:
|
|
162
161
|
target = self.mobject.copy()
|
|
163
162
|
target.scale(self.scale_factor)
|
|
164
163
|
target.set_color(self.color)
|
|
@@ -342,16 +341,6 @@ class ShowPassingFlashWithThinningStrokeWidth(AnimationGroup):
|
|
|
342
341
|
)
|
|
343
342
|
|
|
344
343
|
|
|
345
|
-
@deprecated(
|
|
346
|
-
since="v0.15.0",
|
|
347
|
-
until="v0.16.0",
|
|
348
|
-
message="Use Create then FadeOut to achieve this effect.",
|
|
349
|
-
)
|
|
350
|
-
class ShowCreationThenFadeOut(Succession):
|
|
351
|
-
def __init__(self, mobject: "Mobject", remover: bool = True, **kwargs) -> None:
|
|
352
|
-
super().__init__(Create(mobject), FadeOut(mobject), remover=remover, **kwargs)
|
|
353
|
-
|
|
354
|
-
|
|
355
344
|
class ApplyWave(Homotopy):
|
|
356
345
|
"""Send a wave through the Mobject distorting it temporarily.
|
|
357
346
|
|
|
@@ -397,7 +386,7 @@ class ApplyWave(Homotopy):
|
|
|
397
386
|
|
|
398
387
|
def __init__(
|
|
399
388
|
self,
|
|
400
|
-
mobject:
|
|
389
|
+
mobject: Mobject,
|
|
401
390
|
direction: np.ndarray = UP,
|
|
402
391
|
amplitude: float = 0.2,
|
|
403
392
|
wave_func: Callable[[float], float] = smooth,
|
|
@@ -415,7 +404,7 @@ class ApplyWave(Homotopy):
|
|
|
415
404
|
# This wave is build up as follows:
|
|
416
405
|
# The time is split into 2*ripples phases. In every phase the amplitude
|
|
417
406
|
# either rises to one or goes down to zero. Consecutive ripples will have
|
|
418
|
-
# their amplitudes in
|
|
407
|
+
# their amplitudes in opposing directions (first ripple from 0 to 1 to 0,
|
|
419
408
|
# second from 0 to -1 to 0 and so on). This is how two ripples would be
|
|
420
409
|
# divided into phases:
|
|
421
410
|
|
|
@@ -454,7 +443,7 @@ class ApplyWave(Homotopy):
|
|
|
454
443
|
return wave_func(t * phases)
|
|
455
444
|
elif phase == phases - 1:
|
|
456
445
|
# last ripple. Rising or falling depending on the number of ripples
|
|
457
|
-
# The (ripples % 2)-term is used to make this
|
|
446
|
+
# The (ripples % 2)-term is used to make this distinction.
|
|
458
447
|
t -= phase / phases # Time relative to the phase
|
|
459
448
|
return (1 - wave_func(t * phases)) * (2 * (ripples % 2) - 1)
|
|
460
449
|
else:
|
|
@@ -516,7 +505,7 @@ class Wiggle(Animation):
|
|
|
516
505
|
|
|
517
506
|
def __init__(
|
|
518
507
|
self,
|
|
519
|
-
mobject:
|
|
508
|
+
mobject: Mobject,
|
|
520
509
|
scale_value: float = 1.1,
|
|
521
510
|
rotation_angle: float = 0.01 * TAU,
|
|
522
511
|
n_wiggles: int = 6,
|
|
@@ -544,8 +533,8 @@ class Wiggle(Animation):
|
|
|
544
533
|
|
|
545
534
|
def interpolate_submobject(
|
|
546
535
|
self,
|
|
547
|
-
submobject:
|
|
548
|
-
starting_submobject:
|
|
536
|
+
submobject: Mobject,
|
|
537
|
+
starting_submobject: Mobject,
|
|
549
538
|
alpha: float,
|
|
550
539
|
) -> None:
|
|
551
540
|
submobject.points[:, :] = starting_submobject.points
|
|
@@ -567,7 +556,7 @@ class Circumscribe(Succession):
|
|
|
567
556
|
mobject
|
|
568
557
|
The mobject to be circumscribed.
|
|
569
558
|
shape
|
|
570
|
-
The shape with which to
|
|
559
|
+
The shape with which to surround the given mobject. Should be either
|
|
571
560
|
:class:`~.Rectangle` or :class:`~.Circle`
|
|
572
561
|
fade_in
|
|
573
562
|
Whether to make the surrounding shape to fade in. It will be drawn otherwise.
|
manim/animation/movement.py
CHANGED
manim/animation/rotation.py
CHANGED
|
@@ -59,7 +59,7 @@ class Rotate(Transform):
|
|
|
59
59
|
about_point
|
|
60
60
|
The rotation center.
|
|
61
61
|
about_edge
|
|
62
|
-
If ``about_point``is ``None``, this argument specifies
|
|
62
|
+
If ``about_point`` is ``None``, this argument specifies
|
|
63
63
|
the direction of the bounding box point to be taken as
|
|
64
64
|
the rotation center.
|
|
65
65
|
|
manim/animation/specialized.py
CHANGED
manim/animation/speedmodifier.py
CHANGED
|
@@ -4,15 +4,20 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import inspect
|
|
6
6
|
import types
|
|
7
|
-
from typing import Callable
|
|
7
|
+
from typing import TYPE_CHECKING, Callable
|
|
8
8
|
|
|
9
9
|
from numpy import piecewise
|
|
10
10
|
|
|
11
11
|
from ..animation.animation import Animation, Wait, prepare_animation
|
|
12
12
|
from ..animation.composition import AnimationGroup
|
|
13
|
-
from ..mobject.mobject import Mobject,
|
|
13
|
+
from ..mobject.mobject import Mobject, _AnimationBuilder
|
|
14
14
|
from ..scene.scene import Scene
|
|
15
15
|
|
|
16
|
+
if TYPE_CHECKING:
|
|
17
|
+
from ..mobject.mobject import Updater
|
|
18
|
+
|
|
19
|
+
__all__ = ["ChangeSpeed"]
|
|
20
|
+
|
|
16
21
|
|
|
17
22
|
class ChangeSpeed(Animation):
|
|
18
23
|
"""Modifies the speed of passed animation.
|
|
@@ -225,7 +225,7 @@ class TransformMatchingShapes(TransformMatchingAbstractBase):
|
|
|
225
225
|
def get_mobject_key(mobject: Mobject) -> int:
|
|
226
226
|
mobject.save_state()
|
|
227
227
|
mobject.center()
|
|
228
|
-
mobject.
|
|
228
|
+
mobject.set(height=1)
|
|
229
229
|
result = hash(np.round(mobject.points, 3).tobytes())
|
|
230
230
|
mobject.restore()
|
|
231
231
|
return result
|
manim/camera/camera.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""A camera converts the mobjects contained in a Scene into an array of pixels."""
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
from __future__ import annotations
|
|
5
4
|
|
|
6
5
|
__all__ = ["Camera", "BackgroundColoredVMobjectDisplayer"]
|
|
@@ -37,6 +36,14 @@ LINE_JOIN_MAP = {
|
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
|
|
39
|
+
CAP_STYLE_MAP = {
|
|
40
|
+
CapStyleType.AUTO: None, # TODO: this could be improved
|
|
41
|
+
CapStyleType.ROUND: cairo.LineCap.ROUND,
|
|
42
|
+
CapStyleType.BUTT: cairo.LineCap.BUTT,
|
|
43
|
+
CapStyleType.SQUARE: cairo.LineCap.SQUARE,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
40
47
|
class Camera:
|
|
41
48
|
"""Base camera class.
|
|
42
49
|
|
|
@@ -778,11 +785,13 @@ class Camera:
|
|
|
778
785
|
ctx.set_line_width(
|
|
779
786
|
width
|
|
780
787
|
* self.cairo_line_width_multiple
|
|
781
|
-
# This ensures lines have constant width as you zoom in on them.
|
|
782
788
|
* (self.frame_width / self.frame_width),
|
|
789
|
+
# This ensures lines have constant width as you zoom in on them.
|
|
783
790
|
)
|
|
784
791
|
if vmobject.joint_type != LineJointType.AUTO:
|
|
785
792
|
ctx.set_line_join(LINE_JOIN_MAP[vmobject.joint_type])
|
|
793
|
+
if vmobject.cap_style != CapStyleType.AUTO:
|
|
794
|
+
ctx.set_line_cap(CAP_STYLE_MAP[vmobject.cap_style])
|
|
786
795
|
ctx.stroke_preserve()
|
|
787
796
|
return self
|
|
788
797
|
|
|
@@ -973,8 +982,8 @@ class Camera:
|
|
|
973
982
|
sub_image = Image.fromarray(image_mobject.get_pixel_array(), mode="RGBA")
|
|
974
983
|
|
|
975
984
|
# Reshape
|
|
976
|
-
pixel_width = max(int(pdist([ul_coords, ur_coords])), 1)
|
|
977
|
-
pixel_height = max(int(pdist([ul_coords, dl_coords])), 1)
|
|
985
|
+
pixel_width = max(int(pdist([ul_coords, ur_coords]).item()), 1)
|
|
986
|
+
pixel_height = max(int(pdist([ul_coords, dl_coords]).item()), 1)
|
|
978
987
|
sub_image = sub_image.resize(
|
|
979
988
|
(pixel_width, pixel_height),
|
|
980
989
|
resample=image_mobject.resampling_algorithm,
|
manim/cli/cfg/group.py
CHANGED
|
@@ -5,13 +5,12 @@ cfg``. Here you can specify options, subcommands, and subgroups for the cfg
|
|
|
5
5
|
group.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
10
|
-
import os
|
|
11
11
|
from ast import literal_eval
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
|
|
14
|
-
import click
|
|
15
14
|
import cloup
|
|
16
15
|
from rich.errors import StyleSyntaxError
|
|
17
16
|
from rich.style import Style
|
|
@@ -28,6 +27,17 @@ If left empty, the default colour will be used.[/red]
|
|
|
28
27
|
"""
|
|
29
28
|
RICH_NON_STYLE_ENTRIES: str = ["log.width", "log.height", "log.timestamps"]
|
|
30
29
|
|
|
30
|
+
__all__ = [
|
|
31
|
+
"value_from_string",
|
|
32
|
+
"value_from_string",
|
|
33
|
+
"is_valid_style",
|
|
34
|
+
"replace_keys",
|
|
35
|
+
"cfg",
|
|
36
|
+
"write",
|
|
37
|
+
"show",
|
|
38
|
+
"export",
|
|
39
|
+
]
|
|
40
|
+
|
|
31
41
|
|
|
32
42
|
def value_from_string(value: str) -> str | int | bool:
|
|
33
43
|
"""Extracts the literal of proper datatype from a string.
|
|
@@ -123,21 +133,21 @@ def replace_keys(default: dict) -> dict:
|
|
|
123
133
|
epilog=EPILOG,
|
|
124
134
|
help="Manages Manim configuration files.",
|
|
125
135
|
)
|
|
126
|
-
@
|
|
136
|
+
@cloup.pass_context
|
|
127
137
|
def cfg(ctx):
|
|
128
138
|
"""Responsible for the cfg subcommand."""
|
|
129
139
|
pass
|
|
130
140
|
|
|
131
141
|
|
|
132
142
|
@cfg.command(context_settings=cli_ctx_settings, no_args_is_help=True)
|
|
133
|
-
@
|
|
143
|
+
@cloup.option(
|
|
134
144
|
"-l",
|
|
135
145
|
"--level",
|
|
136
|
-
type=
|
|
146
|
+
type=cloup.Choice(["user", "cwd"], case_sensitive=False),
|
|
137
147
|
default="cwd",
|
|
138
148
|
help="Specify if this config is for user or the working directory.",
|
|
139
149
|
)
|
|
140
|
-
@
|
|
150
|
+
@cloup.option("-o", "--open", "openfile", is_flag=True)
|
|
141
151
|
def write(level: str = None, openfile: bool = False) -> None:
|
|
142
152
|
config_paths = config_file_paths()
|
|
143
153
|
console.print(
|
|
@@ -258,8 +268,8 @@ def show():
|
|
|
258
268
|
|
|
259
269
|
|
|
260
270
|
@cfg.command(context_settings=cli_ctx_settings)
|
|
261
|
-
@
|
|
262
|
-
@
|
|
271
|
+
@cloup.option("-d", "--directory", default=Path.cwd())
|
|
272
|
+
@cloup.pass_context
|
|
263
273
|
def export(ctx, directory):
|
|
264
274
|
directory_path = Path(directory)
|
|
265
275
|
if directory_path.absolute == Path.cwd().absolute:
|
manim/cli/checkhealth/checks.py
CHANGED
manim/cli/default_group.py
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
|
-
"""DefaultGroup allows a subcommand to act as the main command
|
|
1
|
+
"""``DefaultGroup`` allows a subcommand to act as the main command.
|
|
2
2
|
|
|
3
3
|
In particular, this class is what allows ``manim`` to act as ``manim render``.
|
|
4
|
+
|
|
5
|
+
.. note::
|
|
6
|
+
This is a vendored version of https://github.com/click-contrib/click-default-group/
|
|
7
|
+
under the BSD 3-Clause "New" or "Revised" License.
|
|
8
|
+
|
|
9
|
+
This library isn't used as a dependency as we need to inherit from ``cloup.Group`` instead
|
|
10
|
+
of ``click.Group``.
|
|
4
11
|
"""
|
|
5
|
-
import cloup
|
|
6
12
|
|
|
7
|
-
|
|
13
|
+
import warnings
|
|
14
|
+
|
|
15
|
+
import cloup
|
|
8
16
|
|
|
9
17
|
__all__ = ["DefaultGroup"]
|
|
10
18
|
|
|
@@ -54,8 +62,8 @@ class DefaultGroup(cloup.Group):
|
|
|
54
62
|
decorator = super().command(*args, **kwargs)
|
|
55
63
|
if not default:
|
|
56
64
|
return decorator
|
|
57
|
-
|
|
58
|
-
"Use default param of DefaultGroup or
|
|
65
|
+
warnings.warn(
|
|
66
|
+
"Use default param of DefaultGroup or set_default_command() instead",
|
|
59
67
|
DeprecationWarning,
|
|
60
68
|
)
|
|
61
69
|
|
manim/cli/init/commands.py
CHANGED
|
@@ -5,6 +5,7 @@ init``. Here you can specify options, subcommands, and subgroups for the init
|
|
|
5
5
|
group.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
10
11
|
import configparser
|
|
@@ -30,6 +31,8 @@ CFG_DEFAULTS = {
|
|
|
30
31
|
"resolution": (854, 480),
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
__all__ = ["select_resolution", "update_cfg", "project", "scene"]
|
|
35
|
+
|
|
33
36
|
|
|
34
37
|
def select_resolution():
|
|
35
38
|
"""Prompts input of type click.Choice from user. Presents options from QUALITIES constant.
|
|
@@ -47,7 +50,7 @@ def select_resolution():
|
|
|
47
50
|
resolution_options.pop()
|
|
48
51
|
choice = click.prompt(
|
|
49
52
|
"\nSelect resolution:\n",
|
|
50
|
-
type=
|
|
53
|
+
type=cloup.Choice([f"{i[0]}p" for i in resolution_options]),
|
|
51
54
|
show_default=False,
|
|
52
55
|
default="480p",
|
|
53
56
|
)
|
manim/cli/plugins/commands.py
CHANGED
|
@@ -5,6 +5,7 @@ plugin``. Here you can specify options, subcommands, and subgroups for the plugi
|
|
|
5
5
|
group.
|
|
6
6
|
|
|
7
7
|
"""
|
|
8
|
+
|
|
8
9
|
from __future__ import annotations
|
|
9
10
|
|
|
10
11
|
import cloup
|
|
@@ -12,6 +13,8 @@ import cloup
|
|
|
12
13
|
from ...constants import CONTEXT_SETTINGS, EPILOG
|
|
13
14
|
from ...plugins.plugins_flags import list_plugins
|
|
14
15
|
|
|
16
|
+
__all__ = ["plugins"]
|
|
17
|
+
|
|
15
18
|
|
|
16
19
|
@cloup.command(
|
|
17
20
|
context_settings=CONTEXT_SETTINGS,
|