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
manim/camera/mapping_camera.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""A camera that
|
|
1
|
+
"""A camera module that supports spatial mapping between objects for distortion effects."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -17,8 +17,16 @@ from ..utils.config_ops import DictAsObject
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class MappingCamera(Camera):
|
|
20
|
-
"""
|
|
21
|
-
|
|
20
|
+
"""Parameters
|
|
21
|
+
----------
|
|
22
|
+
mapping_func : callable
|
|
23
|
+
Function to map 3D points to new 3D points (identity by default).
|
|
24
|
+
min_num_curves : int
|
|
25
|
+
Minimum number of curves for VMobjects to avoid visual glitches.
|
|
26
|
+
allow_object_intrusion : bool
|
|
27
|
+
If True, modifies original mobjects; else works on copies.
|
|
28
|
+
kwargs : dict
|
|
29
|
+
Additional arguments passed to Camera base class.
|
|
22
30
|
"""
|
|
23
31
|
|
|
24
32
|
def __init__(
|
|
@@ -34,12 +42,18 @@ class MappingCamera(Camera):
|
|
|
34
42
|
super().__init__(**kwargs)
|
|
35
43
|
|
|
36
44
|
def points_to_pixel_coords(self, mobject, points):
|
|
45
|
+
# Map points with custom function before converting to pixels
|
|
37
46
|
return super().points_to_pixel_coords(
|
|
38
47
|
mobject,
|
|
39
48
|
np.apply_along_axis(self.mapping_func, 1, points),
|
|
40
49
|
)
|
|
41
50
|
|
|
42
51
|
def capture_mobjects(self, mobjects, **kwargs):
|
|
52
|
+
"""Capture mobjects for rendering after applying the spatial mapping.
|
|
53
|
+
|
|
54
|
+
Copies mobjects unless intrusion is allowed, and ensures
|
|
55
|
+
vector objects have enough curves for smooth distortion.
|
|
56
|
+
"""
|
|
43
57
|
mobjects = self.get_mobjects_to_display(mobjects, **kwargs)
|
|
44
58
|
if self.allow_object_intrusion:
|
|
45
59
|
mobject_copies = mobjects
|
|
@@ -64,8 +78,16 @@ class MappingCamera(Camera):
|
|
|
64
78
|
# TODO: Add optional separator borders between cameras (or perhaps peel this off into a
|
|
65
79
|
# CameraPlusOverlay class)
|
|
66
80
|
|
|
81
|
+
|
|
67
82
|
# TODO, the classes below should likely be deleted
|
|
68
83
|
class OldMultiCamera(Camera):
|
|
84
|
+
"""Parameters
|
|
85
|
+
----------
|
|
86
|
+
cameras_with_start_positions : tuple
|
|
87
|
+
Tuples of (Camera, (start_y, start_x)) indicating camera and
|
|
88
|
+
its pixel offset on the final frame.
|
|
89
|
+
"""
|
|
90
|
+
|
|
69
91
|
def __init__(self, *cameras_with_start_positions, **kwargs):
|
|
70
92
|
self.shifted_cameras = [
|
|
71
93
|
DictAsObject(
|
|
@@ -124,6 +146,15 @@ class OldMultiCamera(Camera):
|
|
|
124
146
|
|
|
125
147
|
|
|
126
148
|
class SplitScreenCamera(OldMultiCamera):
|
|
149
|
+
"""Initializes a split screen camera setup with two side-by-side cameras.
|
|
150
|
+
|
|
151
|
+
Parameters
|
|
152
|
+
----------
|
|
153
|
+
left_camera : Camera
|
|
154
|
+
right_camera : Camera
|
|
155
|
+
kwargs : dict
|
|
156
|
+
"""
|
|
157
|
+
|
|
127
158
|
def __init__(self, left_camera, right_camera, **kwargs):
|
|
128
159
|
Camera.__init__(self, **kwargs) # to set attributes such as pixel_width
|
|
129
160
|
self.left_camera = left_camera
|
manim/camera/moving_camera.py
CHANGED
|
@@ -1,45 +1,48 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Defines the MovingCamera class, a camera that can pan and zoom through a scene.
|
|
2
2
|
|
|
3
3
|
.. SEEALSO::
|
|
4
4
|
|
|
5
5
|
:mod:`.moving_camera_scene`
|
|
6
|
-
|
|
7
6
|
"""
|
|
8
7
|
|
|
9
8
|
from __future__ import annotations
|
|
10
9
|
|
|
11
10
|
__all__ = ["MovingCamera"]
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
from collections.abc import Iterable
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
from cairo import Context
|
|
16
|
+
|
|
17
|
+
from manim.typing import PixelArray, Point3D, Point3DLike
|
|
14
18
|
|
|
15
19
|
from .. import config
|
|
16
20
|
from ..camera.camera import Camera
|
|
17
21
|
from ..constants import DOWN, LEFT, RIGHT, UP
|
|
18
22
|
from ..mobject.frame import ScreenRectangle
|
|
19
23
|
from ..mobject.mobject import Mobject
|
|
20
|
-
from ..utils.color import WHITE
|
|
24
|
+
from ..utils.color import WHITE, ManimColor
|
|
21
25
|
|
|
22
26
|
|
|
23
27
|
class MovingCamera(Camera):
|
|
24
|
-
"""
|
|
25
|
-
|
|
28
|
+
"""A camera that follows and matches the size and position of its 'frame', a Rectangle (or similar Mobject).
|
|
29
|
+
|
|
30
|
+
The frame defines the region of space the camera displays and can move or resize dynamically.
|
|
26
31
|
|
|
27
32
|
.. SEEALSO::
|
|
28
33
|
|
|
29
34
|
:class:`.MovingCameraScene`
|
|
30
|
-
|
|
31
35
|
"""
|
|
32
36
|
|
|
33
37
|
def __init__(
|
|
34
38
|
self,
|
|
35
|
-
frame=None,
|
|
36
|
-
fixed_dimension=0, # width
|
|
37
|
-
default_frame_stroke_color=WHITE,
|
|
38
|
-
default_frame_stroke_width=0,
|
|
39
|
-
**kwargs,
|
|
39
|
+
frame: Mobject | None = None,
|
|
40
|
+
fixed_dimension: int = 0, # width
|
|
41
|
+
default_frame_stroke_color: ManimColor = WHITE,
|
|
42
|
+
default_frame_stroke_width: int = 0,
|
|
43
|
+
**kwargs: Any,
|
|
40
44
|
):
|
|
41
|
-
"""
|
|
42
|
-
Frame is a Mobject, (should almost certainly be a rectangle)
|
|
45
|
+
"""Frame is a Mobject, (should almost certainly be a rectangle)
|
|
43
46
|
determining which region of space the camera displays
|
|
44
47
|
"""
|
|
45
48
|
self.fixed_dimension = fixed_dimension
|
|
@@ -56,7 +59,7 @@ class MovingCamera(Camera):
|
|
|
56
59
|
|
|
57
60
|
# TODO, make these work for a rotated frame
|
|
58
61
|
@property
|
|
59
|
-
def frame_height(self):
|
|
62
|
+
def frame_height(self) -> float:
|
|
60
63
|
"""Returns the height of the frame.
|
|
61
64
|
|
|
62
65
|
Returns
|
|
@@ -66,30 +69,8 @@ class MovingCamera(Camera):
|
|
|
66
69
|
"""
|
|
67
70
|
return self.frame.height
|
|
68
71
|
|
|
69
|
-
@property
|
|
70
|
-
def frame_width(self):
|
|
71
|
-
"""Returns the width of the frame
|
|
72
|
-
|
|
73
|
-
Returns
|
|
74
|
-
-------
|
|
75
|
-
float
|
|
76
|
-
The width of the frame.
|
|
77
|
-
"""
|
|
78
|
-
return self.frame.width
|
|
79
|
-
|
|
80
|
-
@property
|
|
81
|
-
def frame_center(self):
|
|
82
|
-
"""Returns the centerpoint of the frame in cartesian coordinates.
|
|
83
|
-
|
|
84
|
-
Returns
|
|
85
|
-
-------
|
|
86
|
-
np.array
|
|
87
|
-
The cartesian coordinates of the center of the frame.
|
|
88
|
-
"""
|
|
89
|
-
return self.frame.get_center()
|
|
90
|
-
|
|
91
72
|
@frame_height.setter
|
|
92
|
-
def frame_height(self, frame_height: float):
|
|
73
|
+
def frame_height(self, frame_height: float) -> None:
|
|
93
74
|
"""Sets the height of the frame in MUnits.
|
|
94
75
|
|
|
95
76
|
Parameters
|
|
@@ -99,8 +80,19 @@ class MovingCamera(Camera):
|
|
|
99
80
|
"""
|
|
100
81
|
self.frame.stretch_to_fit_height(frame_height)
|
|
101
82
|
|
|
83
|
+
@property
|
|
84
|
+
def frame_width(self) -> float:
|
|
85
|
+
"""Returns the width of the frame
|
|
86
|
+
|
|
87
|
+
Returns
|
|
88
|
+
-------
|
|
89
|
+
float
|
|
90
|
+
The width of the frame.
|
|
91
|
+
"""
|
|
92
|
+
return self.frame.width
|
|
93
|
+
|
|
102
94
|
@frame_width.setter
|
|
103
|
-
def frame_width(self, frame_width: float):
|
|
95
|
+
def frame_width(self, frame_width: float) -> None:
|
|
104
96
|
"""Sets the width of the frame in MUnits.
|
|
105
97
|
|
|
106
98
|
Parameters
|
|
@@ -110,8 +102,19 @@ class MovingCamera(Camera):
|
|
|
110
102
|
"""
|
|
111
103
|
self.frame.stretch_to_fit_width(frame_width)
|
|
112
104
|
|
|
105
|
+
@property
|
|
106
|
+
def frame_center(self) -> Point3D:
|
|
107
|
+
"""Returns the centerpoint of the frame in cartesian coordinates.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
np.array
|
|
112
|
+
The cartesian coordinates of the center of the frame.
|
|
113
|
+
"""
|
|
114
|
+
return self.frame.get_center()
|
|
115
|
+
|
|
113
116
|
@frame_center.setter
|
|
114
|
-
def frame_center(self, frame_center:
|
|
117
|
+
def frame_center(self, frame_center: Point3DLike | Mobject) -> None:
|
|
115
118
|
"""Sets the centerpoint of the frame.
|
|
116
119
|
|
|
117
120
|
Parameters
|
|
@@ -123,25 +126,20 @@ class MovingCamera(Camera):
|
|
|
123
126
|
"""
|
|
124
127
|
self.frame.move_to(frame_center)
|
|
125
128
|
|
|
126
|
-
def capture_mobjects(self, mobjects, **kwargs):
|
|
129
|
+
def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None:
|
|
127
130
|
# self.reset_frame_center()
|
|
128
131
|
# self.realign_frame_shape()
|
|
129
132
|
super().capture_mobjects(mobjects, **kwargs)
|
|
130
133
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
# at each frame. So no caching.
|
|
134
|
-
def get_cached_cairo_context(self, pixel_array):
|
|
135
|
-
"""
|
|
136
|
-
Since the frame can be moving around, the cairo
|
|
134
|
+
def get_cached_cairo_context(self, pixel_array: PixelArray) -> None:
|
|
135
|
+
"""Since the frame can be moving around, the cairo
|
|
137
136
|
context used for updating should be regenerated
|
|
138
137
|
at each frame. So no caching.
|
|
139
138
|
"""
|
|
140
139
|
return None
|
|
141
140
|
|
|
142
|
-
def cache_cairo_context(self, pixel_array, ctx):
|
|
143
|
-
"""
|
|
144
|
-
Since the frame can be moving around, the cairo
|
|
141
|
+
def cache_cairo_context(self, pixel_array: PixelArray, ctx: Context) -> None:
|
|
142
|
+
"""Since the frame can be moving around, the cairo
|
|
145
143
|
context used for updating should be regenerated
|
|
146
144
|
at each frame. So no caching.
|
|
147
145
|
"""
|
|
@@ -158,24 +156,23 @@ class MovingCamera(Camera):
|
|
|
158
156
|
# self.frame_shape = (self.frame.height, width)
|
|
159
157
|
# self.resize_frame_shape(fixed_dimension=self.fixed_dimension)
|
|
160
158
|
|
|
161
|
-
def get_mobjects_indicating_movement(self):
|
|
162
|
-
"""
|
|
163
|
-
Returns all mobjects whose movement implies that the camera
|
|
159
|
+
def get_mobjects_indicating_movement(self) -> list[Mobject]:
|
|
160
|
+
"""Returns all mobjects whose movement implies that the camera
|
|
164
161
|
should think of all other mobjects on the screen as moving
|
|
165
162
|
|
|
166
163
|
Returns
|
|
167
164
|
-------
|
|
168
|
-
list
|
|
165
|
+
list[Mobject]
|
|
169
166
|
"""
|
|
170
167
|
return [self.frame]
|
|
171
168
|
|
|
172
169
|
def auto_zoom(
|
|
173
170
|
self,
|
|
174
|
-
mobjects:
|
|
171
|
+
mobjects: Iterable[Mobject],
|
|
175
172
|
margin: float = 0,
|
|
176
173
|
only_mobjects_in_frame: bool = False,
|
|
177
174
|
animate: bool = True,
|
|
178
|
-
):
|
|
175
|
+
) -> Mobject:
|
|
179
176
|
"""Zooms on to a given array of mobjects (or a singular mobject)
|
|
180
177
|
and automatically resizes to frame all the mobjects.
|
|
181
178
|
|
|
@@ -205,10 +202,36 @@ class MovingCamera(Camera):
|
|
|
205
202
|
or ScreenRectangle with position and size updated to zoomed position.
|
|
206
203
|
|
|
207
204
|
"""
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
205
|
+
(
|
|
206
|
+
scene_critical_x_left,
|
|
207
|
+
scene_critical_x_right,
|
|
208
|
+
scene_critical_y_up,
|
|
209
|
+
scene_critical_y_down,
|
|
210
|
+
) = self._get_bounding_box(mobjects, only_mobjects_in_frame)
|
|
211
|
+
|
|
212
|
+
# calculate center x and y
|
|
213
|
+
x = (scene_critical_x_left + scene_critical_x_right) / 2
|
|
214
|
+
y = (scene_critical_y_up + scene_critical_y_down) / 2
|
|
215
|
+
|
|
216
|
+
# calculate proposed width and height of zoomed scene
|
|
217
|
+
new_width = abs(scene_critical_x_left - scene_critical_x_right)
|
|
218
|
+
new_height = abs(scene_critical_y_up - scene_critical_y_down)
|
|
219
|
+
|
|
220
|
+
m_target = self.frame.animate if animate else self.frame
|
|
221
|
+
# zoom to fit all mobjects along the side that has the largest size
|
|
222
|
+
if new_width / self.frame.width > new_height / self.frame.height:
|
|
223
|
+
return m_target.set_x(x).set_y(y).set(width=new_width + margin)
|
|
224
|
+
else:
|
|
225
|
+
return m_target.set_x(x).set_y(y).set(height=new_height + margin)
|
|
226
|
+
|
|
227
|
+
def _get_bounding_box(
|
|
228
|
+
self, mobjects: Iterable[Mobject], only_mobjects_in_frame: bool
|
|
229
|
+
) -> tuple[float, float, float, float]:
|
|
230
|
+
bounding_box_located = False
|
|
231
|
+
scene_critical_x_left: float = 0
|
|
232
|
+
scene_critical_x_right: float = 1
|
|
233
|
+
scene_critical_y_up: float = 1
|
|
234
|
+
scene_critical_y_down: float = 0
|
|
212
235
|
|
|
213
236
|
for m in mobjects:
|
|
214
237
|
if (m == self.frame) or (
|
|
@@ -218,11 +241,12 @@ class MovingCamera(Camera):
|
|
|
218
241
|
continue
|
|
219
242
|
|
|
220
243
|
# initialize scene critical points with first mobjects critical points
|
|
221
|
-
if
|
|
244
|
+
if not bounding_box_located:
|
|
222
245
|
scene_critical_x_left = m.get_critical_point(LEFT)[0]
|
|
223
246
|
scene_critical_x_right = m.get_critical_point(RIGHT)[0]
|
|
224
247
|
scene_critical_y_up = m.get_critical_point(UP)[1]
|
|
225
248
|
scene_critical_y_down = m.get_critical_point(DOWN)[1]
|
|
249
|
+
bounding_box_located = True
|
|
226
250
|
|
|
227
251
|
else:
|
|
228
252
|
if m.get_critical_point(LEFT)[0] < scene_critical_x_left:
|
|
@@ -237,17 +261,14 @@ class MovingCamera(Camera):
|
|
|
237
261
|
if m.get_critical_point(DOWN)[1] < scene_critical_y_down:
|
|
238
262
|
scene_critical_y_down = m.get_critical_point(DOWN)[1]
|
|
239
263
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
# calculate proposed width and height of zoomed scene
|
|
245
|
-
new_width = abs(scene_critical_x_left - scene_critical_x_right)
|
|
246
|
-
new_height = abs(scene_critical_y_up - scene_critical_y_down)
|
|
264
|
+
if not bounding_box_located:
|
|
265
|
+
raise Exception(
|
|
266
|
+
"Could not determine bounding box of the mobjects given to 'auto_zoom'."
|
|
267
|
+
)
|
|
247
268
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
269
|
+
return (
|
|
270
|
+
scene_critical_x_left,
|
|
271
|
+
scene_critical_x_right,
|
|
272
|
+
scene_critical_y_up,
|
|
273
|
+
scene_critical_y_down,
|
|
274
|
+
)
|
manim/camera/multi_camera.py
CHANGED
|
@@ -5,7 +5,13 @@ from __future__ import annotations
|
|
|
5
5
|
__all__ = ["MultiCamera"]
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
from
|
|
8
|
+
from collections.abc import Iterable
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
from typing_extensions import Self
|
|
12
|
+
|
|
13
|
+
from manim.mobject.mobject import Mobject
|
|
14
|
+
from manim.mobject.types.image_mobject import ImageMobjectFromCamera
|
|
9
15
|
|
|
10
16
|
from ..camera.moving_camera import MovingCamera
|
|
11
17
|
from ..utils.iterables import list_difference_update
|
|
@@ -16,10 +22,10 @@ class MultiCamera(MovingCamera):
|
|
|
16
22
|
|
|
17
23
|
def __init__(
|
|
18
24
|
self,
|
|
19
|
-
image_mobjects_from_cameras:
|
|
20
|
-
allow_cameras_to_capture_their_own_display=False,
|
|
21
|
-
**kwargs,
|
|
22
|
-
):
|
|
25
|
+
image_mobjects_from_cameras: Iterable[ImageMobjectFromCamera] | None = None,
|
|
26
|
+
allow_cameras_to_capture_their_own_display: bool = False,
|
|
27
|
+
**kwargs: Any,
|
|
28
|
+
) -> None:
|
|
23
29
|
"""Initialises the MultiCamera
|
|
24
30
|
|
|
25
31
|
Parameters
|
|
@@ -29,7 +35,7 @@ class MultiCamera(MovingCamera):
|
|
|
29
35
|
kwargs
|
|
30
36
|
Any valid keyword arguments of MovingCamera.
|
|
31
37
|
"""
|
|
32
|
-
self.image_mobjects_from_cameras = []
|
|
38
|
+
self.image_mobjects_from_cameras: list[ImageMobjectFromCamera] = []
|
|
33
39
|
if image_mobjects_from_cameras is not None:
|
|
34
40
|
for imfc in image_mobjects_from_cameras:
|
|
35
41
|
self.add_image_mobject_from_camera(imfc)
|
|
@@ -38,7 +44,9 @@ class MultiCamera(MovingCamera):
|
|
|
38
44
|
)
|
|
39
45
|
super().__init__(**kwargs)
|
|
40
46
|
|
|
41
|
-
def add_image_mobject_from_camera(
|
|
47
|
+
def add_image_mobject_from_camera(
|
|
48
|
+
self, image_mobject_from_camera: ImageMobjectFromCamera
|
|
49
|
+
) -> None:
|
|
42
50
|
"""Adds an ImageMobject that's been obtained from the camera
|
|
43
51
|
into the list ``self.image_mobject_from_cameras``
|
|
44
52
|
|
|
@@ -53,20 +61,20 @@ class MultiCamera(MovingCamera):
|
|
|
53
61
|
assert isinstance(imfc.camera, MovingCamera)
|
|
54
62
|
self.image_mobjects_from_cameras.append(imfc)
|
|
55
63
|
|
|
56
|
-
def update_sub_cameras(self):
|
|
64
|
+
def update_sub_cameras(self) -> None:
|
|
57
65
|
"""Reshape sub_camera pixel_arrays"""
|
|
58
66
|
for imfc in self.image_mobjects_from_cameras:
|
|
59
67
|
pixel_height, pixel_width = self.pixel_array.shape[:2]
|
|
60
|
-
imfc.camera.frame_shape = (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
)
|
|
68
|
+
# imfc.camera.frame_shape = (
|
|
69
|
+
# imfc.camera.frame.height,
|
|
70
|
+
# imfc.camera.frame.width,
|
|
71
|
+
# )
|
|
64
72
|
imfc.camera.reset_pixel_shape(
|
|
65
73
|
int(pixel_height * imfc.height / self.frame_height),
|
|
66
74
|
int(pixel_width * imfc.width / self.frame_width),
|
|
67
75
|
)
|
|
68
76
|
|
|
69
|
-
def reset(self):
|
|
77
|
+
def reset(self) -> Self:
|
|
70
78
|
"""Resets the MultiCamera.
|
|
71
79
|
|
|
72
80
|
Returns
|
|
@@ -79,7 +87,7 @@ class MultiCamera(MovingCamera):
|
|
|
79
87
|
super().reset()
|
|
80
88
|
return self
|
|
81
89
|
|
|
82
|
-
def capture_mobjects(self, mobjects, **kwargs):
|
|
90
|
+
def capture_mobjects(self, mobjects: Iterable[Mobject], **kwargs: Any) -> None:
|
|
83
91
|
self.update_sub_cameras()
|
|
84
92
|
for imfc in self.image_mobjects_from_cameras:
|
|
85
93
|
to_add = list(mobjects)
|
|
@@ -88,7 +96,7 @@ class MultiCamera(MovingCamera):
|
|
|
88
96
|
imfc.camera.capture_mobjects(to_add, **kwargs)
|
|
89
97
|
super().capture_mobjects(mobjects, **kwargs)
|
|
90
98
|
|
|
91
|
-
def get_mobjects_indicating_movement(self):
|
|
99
|
+
def get_mobjects_indicating_movement(self) -> list[Mobject]:
|
|
92
100
|
"""Returns all mobjects whose movement implies that the camera
|
|
93
101
|
should think of all other mobjects on the screen as moving
|
|
94
102
|
|