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
|
@@ -13,21 +13,36 @@ __all__ = [
|
|
|
13
13
|
"Square",
|
|
14
14
|
"RoundedRectangle",
|
|
15
15
|
"Cutout",
|
|
16
|
+
"ConvexHull",
|
|
16
17
|
]
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
from math import ceil
|
|
21
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
19
22
|
|
|
20
23
|
import numpy as np
|
|
21
|
-
from colour import Color
|
|
22
24
|
|
|
23
25
|
from manim.constants import *
|
|
24
26
|
from manim.mobject.geometry.arc import ArcBetweenPoints
|
|
25
27
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
26
28
|
from manim.mobject.types.vectorized_mobject import VGroup, VMobject
|
|
27
|
-
from manim.utils.color import
|
|
29
|
+
from manim.utils.color import BLUE, WHITE, ParsableManimColor
|
|
28
30
|
from manim.utils.iterables import adjacent_n_tuples, adjacent_pairs
|
|
31
|
+
from manim.utils.qhull import QuickHull
|
|
29
32
|
from manim.utils.space_ops import angle_between_vectors, normalize, regular_vertices
|
|
30
33
|
|
|
34
|
+
if TYPE_CHECKING:
|
|
35
|
+
import numpy.typing as npt
|
|
36
|
+
from typing_extensions import Self
|
|
37
|
+
|
|
38
|
+
from manim.typing import (
|
|
39
|
+
Point3D,
|
|
40
|
+
Point3D_Array,
|
|
41
|
+
Point3DLike,
|
|
42
|
+
Point3DLike_Array,
|
|
43
|
+
)
|
|
44
|
+
from manim.utils.color import ParsableManimColor
|
|
45
|
+
|
|
31
46
|
|
|
32
47
|
class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
33
48
|
"""A generalized :class:`Polygon`, allowing for disconnected sets of edges.
|
|
@@ -64,10 +79,17 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
|
64
79
|
self.wait()
|
|
65
80
|
"""
|
|
66
81
|
|
|
67
|
-
def __init__(
|
|
82
|
+
def __init__(
|
|
83
|
+
self,
|
|
84
|
+
*vertex_groups: Point3DLike_Array,
|
|
85
|
+
color: ParsableManimColor = BLUE,
|
|
86
|
+
**kwargs: Any,
|
|
87
|
+
):
|
|
68
88
|
super().__init__(color=color, **kwargs)
|
|
69
89
|
|
|
70
90
|
for vertices in vertex_groups:
|
|
91
|
+
# The inferred type for *vertices is Any, but it should be
|
|
92
|
+
# Point3D_Array
|
|
71
93
|
first_vertex, *vertices = vertices
|
|
72
94
|
first_vertex = np.array(first_vertex)
|
|
73
95
|
|
|
@@ -76,7 +98,7 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
|
76
98
|
[*(np.array(vertex) for vertex in vertices), first_vertex],
|
|
77
99
|
)
|
|
78
100
|
|
|
79
|
-
def get_vertices(self) ->
|
|
101
|
+
def get_vertices(self) -> Point3D_Array:
|
|
80
102
|
"""Gets the vertices of the :class:`Polygram`.
|
|
81
103
|
|
|
82
104
|
Returns
|
|
@@ -95,56 +117,94 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
|
95
117
|
[-1., -1., 0.],
|
|
96
118
|
[ 1., -1., 0.]])
|
|
97
119
|
"""
|
|
98
|
-
|
|
99
120
|
return self.get_start_anchors()
|
|
100
121
|
|
|
101
|
-
def get_vertex_groups(self) ->
|
|
122
|
+
def get_vertex_groups(self) -> list[Point3D_Array]:
|
|
102
123
|
"""Gets the vertex groups of the :class:`Polygram`.
|
|
103
124
|
|
|
104
125
|
Returns
|
|
105
126
|
-------
|
|
106
|
-
|
|
107
|
-
The vertex groups of the :class:`Polygram`.
|
|
127
|
+
list[Point3D_Array]
|
|
128
|
+
The list of vertex groups of the :class:`Polygram`.
|
|
108
129
|
|
|
109
130
|
Examples
|
|
110
131
|
--------
|
|
111
132
|
::
|
|
112
133
|
|
|
113
|
-
>>> poly = Polygram([ORIGIN, RIGHT, UP], [LEFT, LEFT + UP, 2 * LEFT])
|
|
114
|
-
>>> poly.get_vertex_groups()
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
[
|
|
120
|
-
|
|
121
|
-
|
|
134
|
+
>>> poly = Polygram([ORIGIN, RIGHT, UP, LEFT + UP], [LEFT, LEFT + UP, 2 * LEFT])
|
|
135
|
+
>>> groups = poly.get_vertex_groups()
|
|
136
|
+
>>> len(groups)
|
|
137
|
+
2
|
|
138
|
+
>>> groups[0]
|
|
139
|
+
array([[ 0., 0., 0.],
|
|
140
|
+
[ 1., 0., 0.],
|
|
141
|
+
[ 0., 1., 0.],
|
|
142
|
+
[-1., 1., 0.]])
|
|
143
|
+
>>> groups[1]
|
|
144
|
+
array([[-1., 0., 0.],
|
|
145
|
+
[-1., 1., 0.],
|
|
146
|
+
[-2., 0., 0.]])
|
|
122
147
|
"""
|
|
123
|
-
|
|
124
148
|
vertex_groups = []
|
|
125
149
|
|
|
150
|
+
# TODO: If any of the original vertex groups contained the starting vertex N
|
|
151
|
+
# times, then .get_vertex_groups() splits it into N vertex groups.
|
|
126
152
|
group = []
|
|
127
153
|
for start, end in zip(self.get_start_anchors(), self.get_end_anchors()):
|
|
128
154
|
group.append(start)
|
|
129
155
|
|
|
130
156
|
if self.consider_points_equals(end, group[0]):
|
|
131
|
-
vertex_groups.append(group)
|
|
157
|
+
vertex_groups.append(np.array(group))
|
|
132
158
|
group = []
|
|
133
159
|
|
|
134
|
-
return
|
|
160
|
+
return vertex_groups
|
|
135
161
|
|
|
136
|
-
def round_corners(
|
|
162
|
+
def round_corners(
|
|
163
|
+
self,
|
|
164
|
+
radius: float | list[float] = 0.5,
|
|
165
|
+
evenly_distribute_anchors: bool = False,
|
|
166
|
+
components_per_rounded_corner: int = 2,
|
|
167
|
+
) -> Self:
|
|
137
168
|
"""Rounds off the corners of the :class:`Polygram`.
|
|
138
169
|
|
|
139
170
|
Parameters
|
|
140
171
|
----------
|
|
141
172
|
radius
|
|
142
173
|
The curvature of the corners of the :class:`Polygram`.
|
|
174
|
+
evenly_distribute_anchors
|
|
175
|
+
Break long line segments into proportionally-sized segments.
|
|
176
|
+
components_per_rounded_corner
|
|
177
|
+
The number of points used to represent the rounded corner curve.
|
|
143
178
|
|
|
144
179
|
|
|
145
180
|
.. seealso::
|
|
146
181
|
:class:`.~RoundedRectangle`
|
|
147
182
|
|
|
183
|
+
.. note::
|
|
184
|
+
If `radius` is supplied as a single value, then the same radius
|
|
185
|
+
will be applied to all corners. If `radius` is a list, then the
|
|
186
|
+
individual values will be applied sequentially, with the first
|
|
187
|
+
corner receiving `radius[0]`, the second corner receiving
|
|
188
|
+
`radius[1]`, etc. The radius list will be repeated as necessary.
|
|
189
|
+
|
|
190
|
+
The `components_per_rounded_corner` value is provided so that the
|
|
191
|
+
fidelity of the rounded corner may be fine-tuned as needed. 2 is
|
|
192
|
+
an appropriate value for most shapes, however a larger value may be
|
|
193
|
+
need if the rounded corner is particularly large. 2 is the minimum
|
|
194
|
+
number allowed, representing the start and end of the curve. 3 will
|
|
195
|
+
result in a start, middle, and end point, meaning 2 curves will be
|
|
196
|
+
generated.
|
|
197
|
+
|
|
198
|
+
The option to `evenly_distribute_anchors` is provided so that the
|
|
199
|
+
line segments (the part part of each line remaining after rounding
|
|
200
|
+
off the corners) can be subdivided to a density similar to that of
|
|
201
|
+
the average density of the rounded corners. This may be desirable
|
|
202
|
+
in situations in which an even distribution of curves is desired
|
|
203
|
+
for use in later transformation animations. Be aware, though, that
|
|
204
|
+
enabling this option can result in an an object containing
|
|
205
|
+
significantly more points than the original, especially when the
|
|
206
|
+
rounded corner curves are small.
|
|
207
|
+
|
|
148
208
|
Examples
|
|
149
209
|
--------
|
|
150
210
|
.. manim:: PolygramRoundCorners
|
|
@@ -161,15 +221,24 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
|
161
221
|
shapes.arrange(RIGHT)
|
|
162
222
|
self.add(shapes)
|
|
163
223
|
"""
|
|
164
|
-
|
|
165
224
|
if radius == 0:
|
|
166
225
|
return self
|
|
167
226
|
|
|
168
|
-
new_points = []
|
|
227
|
+
new_points: list[Point3D] = []
|
|
169
228
|
|
|
170
|
-
for
|
|
229
|
+
for vertex_group in self.get_vertex_groups():
|
|
171
230
|
arcs = []
|
|
172
|
-
|
|
231
|
+
|
|
232
|
+
# Repeat the radius list as necessary in order to provide a radius
|
|
233
|
+
# for each vertex.
|
|
234
|
+
if isinstance(radius, (int, float)):
|
|
235
|
+
radius_list = [radius] * len(vertex_group)
|
|
236
|
+
else:
|
|
237
|
+
radius_list = radius * ceil(len(vertex_group) / len(radius))
|
|
238
|
+
|
|
239
|
+
for current_radius, (v1, v2, v3) in zip(
|
|
240
|
+
radius_list, adjacent_n_tuples(vertex_group, 3)
|
|
241
|
+
):
|
|
173
242
|
vect1 = v2 - v1
|
|
174
243
|
vect2 = v3 - v2
|
|
175
244
|
unit_vect1 = normalize(vect1)
|
|
@@ -177,10 +246,10 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
|
177
246
|
|
|
178
247
|
angle = angle_between_vectors(vect1, vect2)
|
|
179
248
|
# Negative radius gives concave curves
|
|
180
|
-
angle *= np.sign(
|
|
249
|
+
angle *= np.sign(current_radius)
|
|
181
250
|
|
|
182
251
|
# Distance between vertex and start of the arc
|
|
183
|
-
cut_off_length =
|
|
252
|
+
cut_off_length = current_radius * np.tan(angle / 2)
|
|
184
253
|
|
|
185
254
|
# Determines counterclockwise vs. clockwise
|
|
186
255
|
sign = np.sign(np.cross(vect1, vect2)[2])
|
|
@@ -189,9 +258,24 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
|
189
258
|
v2 - unit_vect1 * cut_off_length,
|
|
190
259
|
v2 + unit_vect2 * cut_off_length,
|
|
191
260
|
angle=sign * angle,
|
|
261
|
+
num_components=components_per_rounded_corner,
|
|
192
262
|
)
|
|
193
263
|
arcs.append(arc)
|
|
194
264
|
|
|
265
|
+
if evenly_distribute_anchors:
|
|
266
|
+
# Determine the average length of each curve
|
|
267
|
+
nonzero_length_arcs = [arc for arc in arcs if len(arc.points) > 4]
|
|
268
|
+
if len(nonzero_length_arcs) > 0:
|
|
269
|
+
total_arc_length = sum(
|
|
270
|
+
[arc.get_arc_length() for arc in nonzero_length_arcs]
|
|
271
|
+
)
|
|
272
|
+
num_curves = (
|
|
273
|
+
sum([len(arc.points) for arc in nonzero_length_arcs]) / 4
|
|
274
|
+
)
|
|
275
|
+
average_arc_length = total_arc_length / num_curves
|
|
276
|
+
else:
|
|
277
|
+
average_arc_length = 1.0
|
|
278
|
+
|
|
195
279
|
# To ensure that we loop through starting with last
|
|
196
280
|
arcs = [arcs[-1], *arcs[:-1]]
|
|
197
281
|
from manim.mobject.geometry.line import Line
|
|
@@ -201,14 +285,13 @@ class Polygram(VMobject, metaclass=ConvertToOpenGL):
|
|
|
201
285
|
|
|
202
286
|
line = Line(arc1.get_end(), arc2.get_start())
|
|
203
287
|
|
|
204
|
-
# Make sure anchors are evenly distributed
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
line.insert_n_curves(int(arc1.get_num_curves() * len_ratio))
|
|
288
|
+
# Make sure anchors are evenly distributed, if necessary
|
|
289
|
+
if evenly_distribute_anchors:
|
|
290
|
+
line.insert_n_curves(ceil(line.get_length() / average_arc_length))
|
|
208
291
|
|
|
209
292
|
new_points.extend(line.points)
|
|
210
293
|
|
|
211
|
-
self.set_points(new_points)
|
|
294
|
+
self.set_points(np.array(new_points))
|
|
212
295
|
|
|
213
296
|
return self
|
|
214
297
|
|
|
@@ -243,7 +326,7 @@ class Polygon(Polygram):
|
|
|
243
326
|
self.add(isosceles, square_and_triangles)
|
|
244
327
|
"""
|
|
245
328
|
|
|
246
|
-
def __init__(self, *vertices:
|
|
329
|
+
def __init__(self, *vertices: Point3DLike, **kwargs: Any) -> None:
|
|
247
330
|
super().__init__(vertices, **kwargs)
|
|
248
331
|
|
|
249
332
|
|
|
@@ -286,8 +369,8 @@ class RegularPolygram(Polygram):
|
|
|
286
369
|
density: int = 2,
|
|
287
370
|
radius: float = 1,
|
|
288
371
|
start_angle: float | None = None,
|
|
289
|
-
**kwargs,
|
|
290
|
-
):
|
|
372
|
+
**kwargs: Any,
|
|
373
|
+
) -> None:
|
|
291
374
|
# Regular polygrams can be expressed by the number of their vertices
|
|
292
375
|
# and their density. This relation can be expressed as its Schläfli
|
|
293
376
|
# symbol: {num_vertices/density}.
|
|
@@ -307,7 +390,7 @@ class RegularPolygram(Polygram):
|
|
|
307
390
|
|
|
308
391
|
# Utility function for generating the individual
|
|
309
392
|
# polygon vertices.
|
|
310
|
-
def gen_polygon_vertices(start_angle):
|
|
393
|
+
def gen_polygon_vertices(start_angle: float | None) -> tuple[list[Any], float]:
|
|
311
394
|
reg_vertices, start_angle = regular_vertices(
|
|
312
395
|
num_vertices,
|
|
313
396
|
radius=radius,
|
|
@@ -363,7 +446,7 @@ class RegularPolygon(RegularPolygram):
|
|
|
363
446
|
self.add(poly_group)
|
|
364
447
|
"""
|
|
365
448
|
|
|
366
|
-
def __init__(self, n: int = 6, **kwargs):
|
|
449
|
+
def __init__(self, n: int = 6, **kwargs: Any) -> None:
|
|
367
450
|
super().__init__(n, density=1, **kwargs)
|
|
368
451
|
|
|
369
452
|
|
|
@@ -403,7 +486,6 @@ class Star(Polygon):
|
|
|
403
486
|
Examples
|
|
404
487
|
--------
|
|
405
488
|
.. manim:: StarExample
|
|
406
|
-
:save_as_gif:
|
|
407
489
|
|
|
408
490
|
class StarExample(Scene):
|
|
409
491
|
def construct(self):
|
|
@@ -434,8 +516,8 @@ class Star(Polygon):
|
|
|
434
516
|
inner_radius: float | None = None,
|
|
435
517
|
density: int = 2,
|
|
436
518
|
start_angle: float | None = TAU / 4,
|
|
437
|
-
**kwargs,
|
|
438
|
-
):
|
|
519
|
+
**kwargs: Any,
|
|
520
|
+
) -> None:
|
|
439
521
|
inner_angle = TAU / (2 * n)
|
|
440
522
|
|
|
441
523
|
if inner_radius is None:
|
|
@@ -466,7 +548,7 @@ class Star(Polygon):
|
|
|
466
548
|
start_angle=self.start_angle + inner_angle,
|
|
467
549
|
)
|
|
468
550
|
|
|
469
|
-
vertices = []
|
|
551
|
+
vertices: list[npt.NDArray] = []
|
|
470
552
|
for pair in zip(outer_vertices, inner_vertices):
|
|
471
553
|
vertices.extend(pair)
|
|
472
554
|
|
|
@@ -494,7 +576,7 @@ class Triangle(RegularPolygon):
|
|
|
494
576
|
self.add(tri_group)
|
|
495
577
|
"""
|
|
496
578
|
|
|
497
|
-
def __init__(self, **kwargs):
|
|
579
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
498
580
|
super().__init__(n=3, **kwargs)
|
|
499
581
|
|
|
500
582
|
|
|
@@ -529,29 +611,37 @@ class Rectangle(Polygon):
|
|
|
529
611
|
def construct(self):
|
|
530
612
|
rect1 = Rectangle(width=4.0, height=2.0, grid_xstep=1.0, grid_ystep=0.5)
|
|
531
613
|
rect2 = Rectangle(width=1.0, height=4.0)
|
|
614
|
+
rect3 = Rectangle(width=2.0, height=2.0, grid_xstep=1.0, grid_ystep=1.0)
|
|
615
|
+
rect3.grid_lines.set_stroke(width=1)
|
|
532
616
|
|
|
533
|
-
rects = Group(rect1,rect2).arrange(buff=1)
|
|
617
|
+
rects = Group(rect1, rect2, rect3).arrange(buff=1)
|
|
534
618
|
self.add(rects)
|
|
535
619
|
"""
|
|
536
620
|
|
|
537
621
|
def __init__(
|
|
538
622
|
self,
|
|
539
|
-
color:
|
|
623
|
+
color: ParsableManimColor = WHITE,
|
|
540
624
|
height: float = 2.0,
|
|
541
625
|
width: float = 4.0,
|
|
542
626
|
grid_xstep: float | None = None,
|
|
543
627
|
grid_ystep: float | None = None,
|
|
544
628
|
mark_paths_closed: bool = True,
|
|
545
629
|
close_new_points: bool = True,
|
|
546
|
-
**kwargs,
|
|
630
|
+
**kwargs: Any,
|
|
547
631
|
):
|
|
548
632
|
super().__init__(UR, UL, DL, DR, color=color, **kwargs)
|
|
549
633
|
self.stretch_to_fit_width(width)
|
|
550
634
|
self.stretch_to_fit_height(height)
|
|
635
|
+
|
|
551
636
|
v = self.get_vertices()
|
|
552
|
-
|
|
637
|
+
self.grid_lines = VGroup()
|
|
638
|
+
|
|
639
|
+
if grid_xstep or grid_ystep:
|
|
553
640
|
from manim.mobject.geometry.line import Line
|
|
554
641
|
|
|
642
|
+
v = self.get_vertices()
|
|
643
|
+
|
|
644
|
+
if grid_xstep:
|
|
555
645
|
grid_xstep = abs(grid_xstep)
|
|
556
646
|
count = int(width / grid_xstep)
|
|
557
647
|
grid = VGroup(
|
|
@@ -564,8 +654,9 @@ class Rectangle(Polygon):
|
|
|
564
654
|
for i in range(1, count)
|
|
565
655
|
)
|
|
566
656
|
)
|
|
567
|
-
self.add(grid)
|
|
568
|
-
|
|
657
|
+
self.grid_lines.add(grid)
|
|
658
|
+
|
|
659
|
+
if grid_ystep:
|
|
569
660
|
grid_ystep = abs(grid_ystep)
|
|
570
661
|
count = int(height / grid_ystep)
|
|
571
662
|
grid = VGroup(
|
|
@@ -578,7 +669,10 @@ class Rectangle(Polygon):
|
|
|
578
669
|
for i in range(1, count)
|
|
579
670
|
)
|
|
580
671
|
)
|
|
581
|
-
self.add(grid)
|
|
672
|
+
self.grid_lines.add(grid)
|
|
673
|
+
|
|
674
|
+
if self.grid_lines:
|
|
675
|
+
self.add(self.grid_lines)
|
|
582
676
|
|
|
583
677
|
|
|
584
678
|
class Square(Rectangle):
|
|
@@ -604,10 +698,17 @@ class Square(Rectangle):
|
|
|
604
698
|
self.add(square_1, square_2, square_3)
|
|
605
699
|
"""
|
|
606
700
|
|
|
607
|
-
def __init__(self, side_length: float = 2.0, **kwargs):
|
|
608
|
-
self.side_length = side_length
|
|
701
|
+
def __init__(self, side_length: float = 2.0, **kwargs: Any) -> None:
|
|
609
702
|
super().__init__(height=side_length, width=side_length, **kwargs)
|
|
610
703
|
|
|
704
|
+
@property
|
|
705
|
+
def side_length(self) -> float:
|
|
706
|
+
return float(np.linalg.norm(self.get_vertices()[0] - self.get_vertices()[1]))
|
|
707
|
+
|
|
708
|
+
@side_length.setter
|
|
709
|
+
def side_length(self, value: float) -> None:
|
|
710
|
+
self.scale(value / self.side_length)
|
|
711
|
+
|
|
611
712
|
|
|
612
713
|
class RoundedRectangle(Rectangle):
|
|
613
714
|
"""A rectangle with rounded corners.
|
|
@@ -633,7 +734,7 @@ class RoundedRectangle(Rectangle):
|
|
|
633
734
|
self.add(rect_group)
|
|
634
735
|
"""
|
|
635
736
|
|
|
636
|
-
def __init__(self, corner_radius: float = 0.5, **kwargs):
|
|
737
|
+
def __init__(self, corner_radius: float | list[float] = 0.5, **kwargs: Any):
|
|
637
738
|
super().__init__(**kwargs)
|
|
638
739
|
self.corner_radius = corner_radius
|
|
639
740
|
self.round_corners(self.corner_radius)
|
|
@@ -674,12 +775,77 @@ class Cutout(VMobject, metaclass=ConvertToOpenGL):
|
|
|
674
775
|
self.wait()
|
|
675
776
|
"""
|
|
676
777
|
|
|
677
|
-
def __init__(
|
|
778
|
+
def __init__(
|
|
779
|
+
self, main_shape: VMobject, *mobjects: VMobject, **kwargs: Any
|
|
780
|
+
) -> None:
|
|
678
781
|
super().__init__(**kwargs)
|
|
679
782
|
self.append_points(main_shape.points)
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
sub_direction = "CW"
|
|
783
|
+
sub_direction: Literal["CCW", "CW"] = (
|
|
784
|
+
"CCW" if main_shape.get_direction() == "CW" else "CW"
|
|
785
|
+
)
|
|
684
786
|
for mobject in mobjects:
|
|
685
787
|
self.append_points(mobject.force_direction(sub_direction).points)
|
|
788
|
+
|
|
789
|
+
|
|
790
|
+
class ConvexHull(Polygram):
|
|
791
|
+
"""Constructs a convex hull for a set of points in no particular order.
|
|
792
|
+
|
|
793
|
+
Parameters
|
|
794
|
+
----------
|
|
795
|
+
points
|
|
796
|
+
The points to consider.
|
|
797
|
+
tolerance
|
|
798
|
+
The tolerance used by quickhull.
|
|
799
|
+
kwargs
|
|
800
|
+
Forwarded to the parent constructor.
|
|
801
|
+
|
|
802
|
+
Examples
|
|
803
|
+
--------
|
|
804
|
+
.. manim:: ConvexHullExample
|
|
805
|
+
:save_last_frame:
|
|
806
|
+
:quality: high
|
|
807
|
+
|
|
808
|
+
class ConvexHullExample(Scene):
|
|
809
|
+
def construct(self):
|
|
810
|
+
points = [
|
|
811
|
+
[-2.35, -2.25, 0],
|
|
812
|
+
[1.65, -2.25, 0],
|
|
813
|
+
[2.65, -0.25, 0],
|
|
814
|
+
[1.65, 1.75, 0],
|
|
815
|
+
[-0.35, 2.75, 0],
|
|
816
|
+
[-2.35, 0.75, 0],
|
|
817
|
+
[-0.35, -1.25, 0],
|
|
818
|
+
[0.65, -0.25, 0],
|
|
819
|
+
[-1.35, 0.25, 0],
|
|
820
|
+
[0.15, 0.75, 0]
|
|
821
|
+
]
|
|
822
|
+
hull = ConvexHull(*points, color=BLUE)
|
|
823
|
+
dots = VGroup(*[Dot(point) for point in points])
|
|
824
|
+
self.add(hull)
|
|
825
|
+
self.add(dots)
|
|
826
|
+
"""
|
|
827
|
+
|
|
828
|
+
def __init__(
|
|
829
|
+
self, *points: Point3DLike, tolerance: float = 1e-5, **kwargs: Any
|
|
830
|
+
) -> None:
|
|
831
|
+
# Build Convex Hull
|
|
832
|
+
array = np.array(points)[:, :2]
|
|
833
|
+
hull = QuickHull(tolerance)
|
|
834
|
+
hull.build(array)
|
|
835
|
+
|
|
836
|
+
# Extract Vertices
|
|
837
|
+
facets = set(hull.facets) - hull.removed
|
|
838
|
+
facet = facets.pop()
|
|
839
|
+
subfacets = list(facet.subfacets)
|
|
840
|
+
while len(subfacets) <= len(facets):
|
|
841
|
+
sf = subfacets[-1]
|
|
842
|
+
(facet,) = hull.neighbors[sf] - {facet}
|
|
843
|
+
(sf,) = facet.subfacets - {sf}
|
|
844
|
+
subfacets.append(sf)
|
|
845
|
+
|
|
846
|
+
# Setup Vertices as Point3D
|
|
847
|
+
coordinates = np.vstack([sf.coordinates for sf in subfacets])
|
|
848
|
+
vertices = np.hstack((coordinates, np.zeros((len(coordinates), 1))))
|
|
849
|
+
|
|
850
|
+
# Call Polygram
|
|
851
|
+
super().__init__(vertices, **kwargs)
|
|
@@ -4,13 +4,25 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
__all__ = ["SurroundingRectangle", "BackgroundRectangle", "Cross", "Underline"]
|
|
6
6
|
|
|
7
|
-
from
|
|
8
|
-
|
|
7
|
+
from typing import Any
|
|
8
|
+
|
|
9
|
+
from typing_extensions import Self
|
|
10
|
+
|
|
11
|
+
from manim import logger
|
|
12
|
+
from manim._config import config
|
|
13
|
+
from manim.constants import (
|
|
14
|
+
DOWN,
|
|
15
|
+
LEFT,
|
|
16
|
+
RIGHT,
|
|
17
|
+
SMALL_BUFF,
|
|
18
|
+
UP,
|
|
19
|
+
)
|
|
9
20
|
from manim.mobject.geometry.line import Line
|
|
10
21
|
from manim.mobject.geometry.polygram import RoundedRectangle
|
|
11
22
|
from manim.mobject.mobject import Mobject
|
|
23
|
+
from manim.mobject.opengl.opengl_mobject import OpenGLMobject
|
|
12
24
|
from manim.mobject.types.vectorized_mobject import VGroup
|
|
13
|
-
from manim.utils.color import BLACK, RED, YELLOW,
|
|
25
|
+
from manim.utils.color import BLACK, RED, YELLOW, ManimColor, ParsableManimColor
|
|
14
26
|
|
|
15
27
|
|
|
16
28
|
class SurroundingRectangle(RoundedRectangle):
|
|
@@ -38,17 +50,36 @@ class SurroundingRectangle(RoundedRectangle):
|
|
|
38
50
|
"""
|
|
39
51
|
|
|
40
52
|
def __init__(
|
|
41
|
-
self,
|
|
42
|
-
|
|
53
|
+
self,
|
|
54
|
+
*mobjects: Mobject,
|
|
55
|
+
color: ParsableManimColor = YELLOW,
|
|
56
|
+
buff: float | tuple[float, float] = SMALL_BUFF,
|
|
57
|
+
corner_radius: float = 0.0,
|
|
58
|
+
**kwargs: Any,
|
|
59
|
+
) -> None:
|
|
60
|
+
from manim.mobject.mobject import Group
|
|
61
|
+
|
|
62
|
+
if not all(isinstance(mob, (Mobject, OpenGLMobject)) for mob in mobjects):
|
|
63
|
+
raise TypeError(
|
|
64
|
+
"Expected all inputs for parameter mobjects to be a Mobjects"
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if isinstance(buff, tuple):
|
|
68
|
+
buff_x = buff[0]
|
|
69
|
+
buff_y = buff[1]
|
|
70
|
+
else:
|
|
71
|
+
buff_x = buff_y = buff
|
|
72
|
+
|
|
73
|
+
group = Group(*mobjects)
|
|
43
74
|
super().__init__(
|
|
44
75
|
color=color,
|
|
45
|
-
width=
|
|
46
|
-
height=
|
|
76
|
+
width=group.width + 2 * buff_x,
|
|
77
|
+
height=group.height + 2 * buff_y,
|
|
47
78
|
corner_radius=corner_radius,
|
|
48
79
|
**kwargs,
|
|
49
80
|
)
|
|
50
81
|
self.buff = buff
|
|
51
|
-
self.move_to(
|
|
82
|
+
self.move_to(group)
|
|
52
83
|
|
|
53
84
|
|
|
54
85
|
class BackgroundRectangle(SurroundingRectangle):
|
|
@@ -78,19 +109,19 @@ class BackgroundRectangle(SurroundingRectangle):
|
|
|
78
109
|
|
|
79
110
|
def __init__(
|
|
80
111
|
self,
|
|
81
|
-
|
|
82
|
-
color:
|
|
112
|
+
*mobjects: Mobject,
|
|
113
|
+
color: ParsableManimColor | None = None,
|
|
83
114
|
stroke_width: float = 0,
|
|
84
115
|
stroke_opacity: float = 0,
|
|
85
116
|
fill_opacity: float = 0.75,
|
|
86
|
-
buff: float = 0,
|
|
87
|
-
**kwargs,
|
|
88
|
-
):
|
|
117
|
+
buff: float | tuple[float, float] = 0,
|
|
118
|
+
**kwargs: Any,
|
|
119
|
+
) -> None:
|
|
89
120
|
if color is None:
|
|
90
121
|
color = config.background_color
|
|
91
122
|
|
|
92
123
|
super().__init__(
|
|
93
|
-
|
|
124
|
+
*mobjects,
|
|
94
125
|
color=color,
|
|
95
126
|
stroke_width=stroke_width,
|
|
96
127
|
stroke_opacity=stroke_opacity,
|
|
@@ -98,13 +129,13 @@ class BackgroundRectangle(SurroundingRectangle):
|
|
|
98
129
|
buff=buff,
|
|
99
130
|
**kwargs,
|
|
100
131
|
)
|
|
101
|
-
self.original_fill_opacity = self.fill_opacity
|
|
132
|
+
self.original_fill_opacity: float = self.fill_opacity
|
|
102
133
|
|
|
103
|
-
def pointwise_become_partial(self, mobject, a, b):
|
|
134
|
+
def pointwise_become_partial(self, mobject: Mobject, a: Any, b: float) -> Self:
|
|
104
135
|
self.set_fill(opacity=b * self.original_fill_opacity)
|
|
105
136
|
return self
|
|
106
137
|
|
|
107
|
-
def set_style(self, fill_opacity, **kwargs):
|
|
138
|
+
def set_style(self, fill_opacity: float, **kwargs: Any) -> Self: # type: ignore[override]
|
|
108
139
|
# Unchangeable style, except for fill_opacity
|
|
109
140
|
# All other style arguments are ignored
|
|
110
141
|
super().set_style(
|
|
@@ -120,8 +151,11 @@ class BackgroundRectangle(SurroundingRectangle):
|
|
|
120
151
|
)
|
|
121
152
|
return self
|
|
122
153
|
|
|
123
|
-
def get_fill_color(self):
|
|
124
|
-
|
|
154
|
+
def get_fill_color(self) -> ManimColor:
|
|
155
|
+
# The type of the color property is set to Any using the property decorator
|
|
156
|
+
# vectorized_mobject.py#L571
|
|
157
|
+
temp_color: ManimColor = self.color
|
|
158
|
+
return temp_color
|
|
125
159
|
|
|
126
160
|
|
|
127
161
|
class Cross(VGroup):
|
|
@@ -152,11 +186,11 @@ class Cross(VGroup):
|
|
|
152
186
|
def __init__(
|
|
153
187
|
self,
|
|
154
188
|
mobject: Mobject | None = None,
|
|
155
|
-
stroke_color:
|
|
156
|
-
stroke_width: float = 6,
|
|
157
|
-
scale_factor: float = 1,
|
|
158
|
-
**kwargs,
|
|
159
|
-
):
|
|
189
|
+
stroke_color: ParsableManimColor = RED,
|
|
190
|
+
stroke_width: float = 6.0,
|
|
191
|
+
scale_factor: float = 1.0,
|
|
192
|
+
**kwargs: Any,
|
|
193
|
+
) -> None:
|
|
160
194
|
super().__init__(
|
|
161
195
|
Line(UP + LEFT, DOWN + RIGHT), Line(UP + RIGHT, DOWN + LEFT), **kwargs
|
|
162
196
|
)
|
|
@@ -181,7 +215,9 @@ class Underline(Line):
|
|
|
181
215
|
self.add(man, ul)
|
|
182
216
|
"""
|
|
183
217
|
|
|
184
|
-
def __init__(
|
|
218
|
+
def __init__(
|
|
219
|
+
self, mobject: Mobject, buff: float = SMALL_BUFF, **kwargs: Any
|
|
220
|
+
) -> None:
|
|
185
221
|
super().__init__(LEFT, RIGHT, buff=buff, **kwargs)
|
|
186
222
|
self.match_width(mobject)
|
|
187
223
|
self.next_to(mobject, DOWN, buff=self.buff)
|