manim 0.18.1__py3-none-any.whl → 0.19.0__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/__main__.py +45 -12
- manim/_config/__init__.py +2 -2
- manim/_config/cli_colors.py +8 -4
- manim/_config/default.cfg +0 -2
- manim/_config/logger_utils.py +5 -0
- manim/_config/utils.py +29 -38
- manim/animation/animation.py +148 -8
- manim/animation/composition.py +16 -13
- manim/animation/creation.py +184 -8
- manim/animation/fading.py +5 -8
- manim/animation/indication.py +93 -26
- manim/animation/movement.py +21 -3
- manim/animation/rotation.py +2 -1
- manim/animation/specialized.py +3 -5
- manim/animation/speedmodifier.py +3 -3
- manim/animation/transform.py +4 -5
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +2 -2
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +52 -36
- manim/cli/checkhealth/checks.py +92 -76
- manim/cli/checkhealth/commands.py +12 -5
- manim/cli/default_group.py +148 -24
- manim/cli/init/commands.py +28 -23
- manim/cli/plugins/commands.py +13 -3
- manim/cli/render/commands.py +47 -42
- manim/cli/render/global_options.py +43 -9
- manim/cli/render/render_options.py +84 -19
- manim/constants.py +11 -4
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +109 -75
- manim/mobject/geometry/boolean_ops.py +20 -17
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +120 -60
- manim/mobject/geometry/polygram.py +109 -25
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +36 -27
- manim/mobject/graph.py +48 -40
- manim/mobject/graphing/coordinate_systems.py +110 -45
- manim/mobject/graphing/functions.py +16 -10
- manim/mobject/graphing/number_line.py +23 -9
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +149 -103
- manim/mobject/opengl/opengl_geometry.py +4 -8
- manim/mobject/opengl/opengl_mobject.py +506 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
- manim/mobject/opengl/opengl_surface.py +1 -2
- manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
- manim/mobject/svg/brace.py +61 -13
- manim/mobject/svg/svg_mobject.py +2 -1
- manim/mobject/table.py +11 -12
- manim/mobject/text/code_mobject.py +186 -550
- manim/mobject/text/numbers.py +7 -7
- manim/mobject/text/tex_mobject.py +22 -13
- manim/mobject/text/text_mobject.py +29 -20
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_dimensions.py +59 -31
- manim/mobject/types/image_mobject.py +37 -23
- manim/mobject/types/point_cloud_mobject.py +103 -67
- manim/mobject/types/vectorized_mobject.py +387 -214
- manim/mobject/value_tracker.py +2 -1
- manim/mobject/vector_field.py +2 -4
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +2 -3
- manim/plugins/plugins_flags.py +3 -3
- manim/renderer/cairo_renderer.py +11 -11
- manim/renderer/opengl_renderer.py +19 -20
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +3 -2
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +72 -41
- manim/scene/scene_file_writer.py +313 -164
- manim/scene/section.py +15 -15
- manim/scene/three_d_scene.py +8 -15
- manim/scene/vector_space_scene.py +3 -6
- manim/typing.py +326 -66
- manim/utils/bezier.py +1658 -381
- manim/utils/caching.py +11 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +2 -0
- manim/utils/color/DVIPSNAMES.py +96 -0
- manim/utils/color/SVGNAMES.py +179 -0
- manim/utils/color/X11.py +3 -0
- manim/utils/color/XKCD.py +2 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +818 -301
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +40 -19
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -6
- manim/utils/deprecation.py +92 -43
- manim/utils/docbuild/autoaliasattr_directive.py +45 -8
- manim/utils/docbuild/autocolor_directive.py +12 -13
- manim/utils/docbuild/manim_directive.py +35 -29
- manim/utils/docbuild/module_parsing.py +74 -27
- manim/utils/family.py +3 -3
- manim/utils/family_ops.py +12 -4
- manim/utils/file_ops.py +22 -16
- manim/utils/hashing.py +7 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +12 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +55 -19
- manim/utils/opengl.py +68 -23
- manim/utils/parameter_parsing.py +3 -2
- manim/utils/paths.py +11 -5
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +69 -32
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +48 -37
- manim/utils/testing/_frames_testers.py +13 -8
- manim/utils/testing/_show_diff.py +5 -3
- manim/utils/testing/_test_class_makers.py +33 -18
- manim/utils/testing/frames_comparison.py +20 -14
- manim/utils/tex.py +4 -2
- manim/utils/tex_file_writing.py +45 -45
- manim/utils/tex_templates.py +1 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim-0.18.1.dist-info/RECORD +0 -217
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
- {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
manim/mobject/text/numbers.py
CHANGED
|
@@ -4,7 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
__all__ = ["DecimalNumber", "Integer", "Variable"]
|
|
6
6
|
|
|
7
|
-
from
|
|
7
|
+
from collections.abc import Sequence
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
10
|
import numpy as np
|
|
10
11
|
|
|
@@ -22,7 +23,7 @@ __all__ = ["DecimalNumber", "Integer", "Variable"]
|
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|
25
|
-
"""An mobject representing a decimal number.
|
|
26
|
+
r"""An mobject representing a decimal number.
|
|
26
27
|
|
|
27
28
|
Parameters
|
|
28
29
|
----------
|
|
@@ -210,10 +211,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|
|
210
211
|
|
|
211
212
|
rounded_num = np.round(number, self.num_decimal_places)
|
|
212
213
|
if num_string.startswith("-") and rounded_num == 0:
|
|
213
|
-
if self.include_sign:
|
|
214
|
-
num_string = "+" + num_string[1:]
|
|
215
|
-
else:
|
|
216
|
-
num_string = num_string[1:]
|
|
214
|
+
num_string = "+" + num_string[1:] if self.include_sign else num_string[1:]
|
|
217
215
|
|
|
218
216
|
return num_string
|
|
219
217
|
|
|
@@ -330,7 +328,9 @@ class Integer(DecimalNumber):
|
|
|
330
328
|
self.add(Integer(number=6.28).set_x(-1.5).set_y(-2).set_color(YELLOW).scale(1.4))
|
|
331
329
|
"""
|
|
332
330
|
|
|
333
|
-
def __init__(
|
|
331
|
+
def __init__(
|
|
332
|
+
self, number: float = 0, num_decimal_places: int = 0, **kwargs: Any
|
|
333
|
+
) -> None:
|
|
334
334
|
super().__init__(number=number, num_decimal_places=num_decimal_places, **kwargs)
|
|
335
335
|
|
|
336
336
|
def get_value(self):
|
|
@@ -12,7 +12,7 @@ r"""Mobjects representing text rendered using LaTeX.
|
|
|
12
12
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
|
-
from manim.utils.color import ManimColor
|
|
15
|
+
from manim.utils.color import BLACK, ManimColor, ParsableManimColor
|
|
16
16
|
|
|
17
17
|
__all__ = [
|
|
18
18
|
"SingleStringMathTex",
|
|
@@ -26,9 +26,9 @@ __all__ = [
|
|
|
26
26
|
import itertools as it
|
|
27
27
|
import operator as op
|
|
28
28
|
import re
|
|
29
|
+
from collections.abc import Iterable
|
|
29
30
|
from functools import reduce
|
|
30
31
|
from textwrap import dedent
|
|
31
|
-
from typing import Iterable
|
|
32
32
|
|
|
33
33
|
from manim import config, logger
|
|
34
34
|
from manim.constants import *
|
|
@@ -62,12 +62,11 @@ class SingleStringMathTex(SVGMobject):
|
|
|
62
62
|
tex_environment: str = "align*",
|
|
63
63
|
tex_template: TexTemplate | None = None,
|
|
64
64
|
font_size: float = DEFAULT_FONT_SIZE,
|
|
65
|
+
color: ParsableManimColor | None = None,
|
|
65
66
|
**kwargs,
|
|
66
67
|
):
|
|
67
|
-
if
|
|
68
|
-
|
|
69
|
-
# and can instead inherit from the parent
|
|
70
|
-
kwargs["color"] = VMobject().color
|
|
68
|
+
if color is None:
|
|
69
|
+
color = VMobject().color
|
|
71
70
|
|
|
72
71
|
self._font_size = font_size
|
|
73
72
|
self.organize_left_to_right = organize_left_to_right
|
|
@@ -88,6 +87,7 @@ class SingleStringMathTex(SVGMobject):
|
|
|
88
87
|
should_center=should_center,
|
|
89
88
|
stroke_width=stroke_width,
|
|
90
89
|
height=height,
|
|
90
|
+
color=color,
|
|
91
91
|
path_string_config={
|
|
92
92
|
"should_subdivide_sharp_curves": True,
|
|
93
93
|
"should_remove_null_curves": True,
|
|
@@ -175,8 +175,8 @@ class SingleStringMathTex(SVGMobject):
|
|
|
175
175
|
tex = self._remove_stray_braces(tex)
|
|
176
176
|
|
|
177
177
|
for context in ["array"]:
|
|
178
|
-
begin_in = ("\\begin{%s}" % context) in tex
|
|
179
|
-
end_in = ("\\end{%s}" % context) in tex
|
|
178
|
+
begin_in = ("\\begin{%s}" % context) in tex # noqa: UP031
|
|
179
|
+
end_in = ("\\end{%s}" % context) in tex # noqa: UP031
|
|
180
180
|
if begin_in ^ end_in:
|
|
181
181
|
# Just turn this into a blank string,
|
|
182
182
|
# which means caller should leave a
|
|
@@ -191,7 +191,6 @@ class SingleStringMathTex(SVGMobject):
|
|
|
191
191
|
This is important when the braces in the TeX code are spread over
|
|
192
192
|
multiple arguments as in, e.g., ``MathTex(r"e^{i", r"\tau} = 1")``.
|
|
193
193
|
"""
|
|
194
|
-
|
|
195
194
|
# "\{" does not count (it's a brace literal), but "\\{" counts (it's a new line and then brace)
|
|
196
195
|
num_lefts = tex.count("{") - tex.count("\\{") + tex.count("\\\\{")
|
|
197
196
|
num_rights = tex.count("}") - tex.count("\\}") + tex.count("\\\\}")
|
|
@@ -211,10 +210,16 @@ class SingleStringMathTex(SVGMobject):
|
|
|
211
210
|
return self.tex_string
|
|
212
211
|
|
|
213
212
|
def init_colors(self, propagate_colors=True):
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
213
|
+
for submobject in self.submobjects:
|
|
214
|
+
# needed to preserve original (non-black)
|
|
215
|
+
# TeX colors of individual submobjects
|
|
216
|
+
if submobject.color != BLACK:
|
|
217
|
+
continue
|
|
218
|
+
submobject.color = self.color
|
|
219
|
+
if config.renderer == RendererType.OPENGL:
|
|
220
|
+
submobject.init_colors()
|
|
221
|
+
elif config.renderer == RendererType.CAIRO:
|
|
222
|
+
submobject.init_colors(propagate_colors=propagate_colors)
|
|
218
223
|
|
|
219
224
|
|
|
220
225
|
class MathTex(SingleStringMathTex):
|
|
@@ -427,6 +432,10 @@ class MathTex(SingleStringMathTex):
|
|
|
427
432
|
class Tex(MathTex):
|
|
428
433
|
r"""A string compiled with LaTeX in normal mode.
|
|
429
434
|
|
|
435
|
+
The color can be set using
|
|
436
|
+
the ``color`` argument. Any parts of the ``tex_string`` that are colored by the
|
|
437
|
+
TeX commands ``\color`` or ``\textcolor`` will retain their original color.
|
|
438
|
+
|
|
430
439
|
Tests
|
|
431
440
|
-----
|
|
432
441
|
|
|
@@ -56,12 +56,11 @@ __all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
|
|
|
56
56
|
|
|
57
57
|
import copy
|
|
58
58
|
import hashlib
|
|
59
|
-
import os
|
|
60
59
|
import re
|
|
60
|
+
from collections.abc import Iterable, Sequence
|
|
61
61
|
from contextlib import contextmanager
|
|
62
62
|
from itertools import chain
|
|
63
63
|
from pathlib import Path
|
|
64
|
-
from typing import Iterable, Sequence
|
|
65
64
|
|
|
66
65
|
import manimpango
|
|
67
66
|
import numpy as np
|
|
@@ -135,10 +134,17 @@ class Paragraph(VGroup):
|
|
|
135
134
|
--------
|
|
136
135
|
Normal usage::
|
|
137
136
|
|
|
138
|
-
paragraph = Paragraph(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
137
|
+
paragraph = Paragraph(
|
|
138
|
+
"this is a awesome",
|
|
139
|
+
"paragraph",
|
|
140
|
+
"With \nNewlines",
|
|
141
|
+
"\tWith Tabs",
|
|
142
|
+
" With Spaces",
|
|
143
|
+
"With Alignments",
|
|
144
|
+
"center",
|
|
145
|
+
"left",
|
|
146
|
+
"right",
|
|
147
|
+
)
|
|
142
148
|
|
|
143
149
|
Remove unwanted invisible characters::
|
|
144
150
|
|
|
@@ -412,7 +418,7 @@ class Text(SVGMobject):
|
|
|
412
418
|
"""
|
|
413
419
|
|
|
414
420
|
@staticmethod
|
|
415
|
-
@functools.
|
|
421
|
+
@functools.cache
|
|
416
422
|
def font_list() -> list[str]:
|
|
417
423
|
return manimpango.list_fonts()
|
|
418
424
|
|
|
@@ -657,7 +663,8 @@ class Text(SVGMobject):
|
|
|
657
663
|
)
|
|
658
664
|
def _set_color_by_t2g(self, t2g=None):
|
|
659
665
|
"""Sets gradient colors for specified
|
|
660
|
-
strings. Behaves similarly to ``set_color_by_t2c``.
|
|
666
|
+
strings. Behaves similarly to ``set_color_by_t2c``.
|
|
667
|
+
"""
|
|
661
668
|
t2g = t2g if t2g else self.t2g
|
|
662
669
|
for word, gradient in list(t2g.items()):
|
|
663
670
|
for start, end in self._find_indexes(word, self.text):
|
|
@@ -696,7 +703,7 @@ class Text(SVGMobject):
|
|
|
696
703
|
default = default_args[arg]
|
|
697
704
|
if left != default and getattr(right_setting, arg) != default:
|
|
698
705
|
raise ValueError(
|
|
699
|
-
f"Ambiguous style for text '{self.text[right_setting.start:right_setting.end]}':"
|
|
706
|
+
f"Ambiguous style for text '{self.text[right_setting.start : right_setting.end]}':"
|
|
700
707
|
+ f"'{arg}' cannot be both '{left}' and '{right}'."
|
|
701
708
|
)
|
|
702
709
|
setattr(right_setting, arg, left if left != default else right)
|
|
@@ -907,7 +914,7 @@ class MarkupText(SVGMobject):
|
|
|
907
914
|
Here is a list of supported tags:
|
|
908
915
|
|
|
909
916
|
- ``<b>bold</b>``, ``<i>italic</i>`` and ``<b><i>bold+italic</i></b>``
|
|
910
|
-
- ``<
|
|
917
|
+
- ``<u>underline</u>`` and ``<s>strike through</s>``
|
|
911
918
|
- ``<tt>typewriter font</tt>``
|
|
912
919
|
- ``<big>bigger font</big>`` and ``<small>smaller font</small>``
|
|
913
920
|
- ``<sup>superscript</sup>`` and ``<sub>subscript</sub>``
|
|
@@ -1155,7 +1162,7 @@ class MarkupText(SVGMobject):
|
|
|
1155
1162
|
"""
|
|
1156
1163
|
|
|
1157
1164
|
@staticmethod
|
|
1158
|
-
@functools.
|
|
1165
|
+
@functools.cache
|
|
1159
1166
|
def font_list() -> list[str]:
|
|
1160
1167
|
return manimpango.list_fonts()
|
|
1161
1168
|
|
|
@@ -1305,15 +1312,13 @@ class MarkupText(SVGMobject):
|
|
|
1305
1312
|
self.set_color_by_gradient(*self.gradient)
|
|
1306
1313
|
for col in colormap:
|
|
1307
1314
|
self.chars[
|
|
1308
|
-
col["start"]
|
|
1309
|
-
- col["start_offset"] : col["end"]
|
|
1315
|
+
col["start"] - col["start_offset"] : col["end"]
|
|
1310
1316
|
- col["start_offset"]
|
|
1311
1317
|
- col["end_offset"]
|
|
1312
1318
|
].set_color(self._parse_color(col["color"]))
|
|
1313
1319
|
for grad in gradientmap:
|
|
1314
1320
|
self.chars[
|
|
1315
|
-
grad["start"]
|
|
1316
|
-
- grad["start_offset"] : grad["end"]
|
|
1321
|
+
grad["start"] - grad["start_offset"] : grad["end"]
|
|
1317
1322
|
- grad["start_offset"]
|
|
1318
1323
|
- grad["end_offset"]
|
|
1319
1324
|
].set_color_by_gradient(
|
|
@@ -1406,7 +1411,8 @@ class MarkupText(SVGMobject):
|
|
|
1406
1411
|
"""Counts characters that will be displayed.
|
|
1407
1412
|
|
|
1408
1413
|
This is needed for partial coloring or gradients, because space
|
|
1409
|
-
counts to the text's `len`, but has no corresponding character.
|
|
1414
|
+
counts to the text's `len`, but has no corresponding character.
|
|
1415
|
+
"""
|
|
1410
1416
|
count = 0
|
|
1411
1417
|
level = 0
|
|
1412
1418
|
# temporarily replace HTML entities by single char
|
|
@@ -1449,7 +1455,9 @@ class MarkupText(SVGMobject):
|
|
|
1449
1455
|
"end_offset": end_offset,
|
|
1450
1456
|
},
|
|
1451
1457
|
)
|
|
1452
|
-
self.text = re.sub(
|
|
1458
|
+
self.text = re.sub(
|
|
1459
|
+
"<gradient[^>]+>(.+?)</gradient>", r"\1", self.text, count=0, flags=re.S
|
|
1460
|
+
)
|
|
1453
1461
|
return gradientmap
|
|
1454
1462
|
|
|
1455
1463
|
def _parse_color(self, col):
|
|
@@ -1491,7 +1499,9 @@ class MarkupText(SVGMobject):
|
|
|
1491
1499
|
"end_offset": end_offset,
|
|
1492
1500
|
},
|
|
1493
1501
|
)
|
|
1494
|
-
self.text = re.sub(
|
|
1502
|
+
self.text = re.sub(
|
|
1503
|
+
"<color[^>]+>(.+?)</color>", r"\1", self.text, count=0, flags=re.S
|
|
1504
|
+
)
|
|
1495
1505
|
return colormap
|
|
1496
1506
|
|
|
1497
1507
|
def __repr__(self):
|
|
@@ -1537,7 +1547,6 @@ def register_font(font_file: str | Path):
|
|
|
1537
1547
|
This method is available for macOS for ``ManimPango>=v0.2.3``. Using this
|
|
1538
1548
|
method with previous releases will raise an :class:`AttributeError` on macOS.
|
|
1539
1549
|
"""
|
|
1540
|
-
|
|
1541
1550
|
input_folder = Path(config.input_file).parent.resolve()
|
|
1542
1551
|
possible_paths = [
|
|
1543
1552
|
Path(font_file),
|
|
@@ -1552,7 +1561,7 @@ def register_font(font_file: str | Path):
|
|
|
1552
1561
|
logger.debug("Found file at %s", file_path.absolute())
|
|
1553
1562
|
break
|
|
1554
1563
|
else:
|
|
1555
|
-
error = f"Can't find {font_file}.
|
|
1564
|
+
error = f"Can't find {font_file}.Tried these : {possible_paths}"
|
|
1556
1565
|
raise FileNotFoundError(error)
|
|
1557
1566
|
|
|
1558
1567
|
try:
|
|
@@ -10,11 +10,20 @@ from manim.mobject.geometry.polygram import Polygon
|
|
|
10
10
|
from manim.mobject.graph import Graph
|
|
11
11
|
from manim.mobject.three_d.three_dimensions import Dot3D
|
|
12
12
|
from manim.mobject.types.vectorized_mobject import VGroup
|
|
13
|
+
from manim.utils.qhull import QuickHull
|
|
13
14
|
|
|
14
15
|
if TYPE_CHECKING:
|
|
15
16
|
from manim.mobject.mobject import Mobject
|
|
17
|
+
from manim.typing import Point3D
|
|
16
18
|
|
|
17
|
-
__all__ = [
|
|
19
|
+
__all__ = [
|
|
20
|
+
"Polyhedron",
|
|
21
|
+
"Tetrahedron",
|
|
22
|
+
"Octahedron",
|
|
23
|
+
"Icosahedron",
|
|
24
|
+
"Dodecahedron",
|
|
25
|
+
"ConvexHull3D",
|
|
26
|
+
]
|
|
18
27
|
|
|
19
28
|
|
|
20
29
|
class Polyhedron(VGroup):
|
|
@@ -361,3 +370,91 @@ class Dodecahedron(Polyhedron):
|
|
|
361
370
|
],
|
|
362
371
|
**kwargs,
|
|
363
372
|
)
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
class ConvexHull3D(Polyhedron):
|
|
376
|
+
"""A convex hull for a set of points
|
|
377
|
+
|
|
378
|
+
Parameters
|
|
379
|
+
----------
|
|
380
|
+
points
|
|
381
|
+
The points to consider.
|
|
382
|
+
tolerance
|
|
383
|
+
The tolerance used for quickhull.
|
|
384
|
+
kwargs
|
|
385
|
+
Forwarded to the parent constructor.
|
|
386
|
+
|
|
387
|
+
Examples
|
|
388
|
+
--------
|
|
389
|
+
.. manim:: ConvexHull3DExample
|
|
390
|
+
:save_last_frame:
|
|
391
|
+
:quality: high
|
|
392
|
+
|
|
393
|
+
class ConvexHull3DExample(ThreeDScene):
|
|
394
|
+
def construct(self):
|
|
395
|
+
self.set_camera_orientation(phi=75 * DEGREES, theta=30 * DEGREES)
|
|
396
|
+
points = [
|
|
397
|
+
[ 1.93192757, 0.44134585, -1.52407061],
|
|
398
|
+
[-0.93302521, 1.23206983, 0.64117067],
|
|
399
|
+
[-0.44350918, -0.61043677, 0.21723705],
|
|
400
|
+
[-0.42640268, -1.05260843, 1.61266094],
|
|
401
|
+
[-1.84449637, 0.91238739, -1.85172623],
|
|
402
|
+
[ 1.72068132, -0.11880457, 0.51881751],
|
|
403
|
+
[ 0.41904805, 0.44938012, -1.86440686],
|
|
404
|
+
[ 0.83864666, 1.66653337, 1.88960123],
|
|
405
|
+
[ 0.22240514, -0.80986286, 1.34249326],
|
|
406
|
+
[-1.29585759, 1.01516189, 0.46187522],
|
|
407
|
+
[ 1.7776499, -1.59550796, -1.70240747],
|
|
408
|
+
[ 0.80065226, -0.12530398, 1.70063977],
|
|
409
|
+
[ 1.28960948, -1.44158255, 1.39938582],
|
|
410
|
+
[-0.93538943, 1.33617705, -0.24852643],
|
|
411
|
+
[-1.54868271, 1.7444399, -0.46170734]
|
|
412
|
+
]
|
|
413
|
+
hull = ConvexHull3D(
|
|
414
|
+
*points,
|
|
415
|
+
faces_config = {"stroke_opacity": 0},
|
|
416
|
+
graph_config = {
|
|
417
|
+
"vertex_type": Dot3D,
|
|
418
|
+
"edge_config": {
|
|
419
|
+
"stroke_color": BLUE,
|
|
420
|
+
"stroke_width": 2,
|
|
421
|
+
"stroke_opacity": 0.05,
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
)
|
|
425
|
+
dots = VGroup(*[Dot3D(point) for point in points])
|
|
426
|
+
self.add(hull)
|
|
427
|
+
self.add(dots)
|
|
428
|
+
"""
|
|
429
|
+
|
|
430
|
+
def __init__(self, *points: Point3D, tolerance: float = 1e-5, **kwargs):
|
|
431
|
+
# Build Convex Hull
|
|
432
|
+
array = np.array(points)
|
|
433
|
+
hull = QuickHull(tolerance)
|
|
434
|
+
hull.build(array)
|
|
435
|
+
|
|
436
|
+
# Setup Lists
|
|
437
|
+
vertices = []
|
|
438
|
+
faces = []
|
|
439
|
+
|
|
440
|
+
# Extract Faces
|
|
441
|
+
c = 0
|
|
442
|
+
d = {}
|
|
443
|
+
facets = set(hull.facets) - hull.removed
|
|
444
|
+
for facet in facets:
|
|
445
|
+
tmp = set()
|
|
446
|
+
for subfacet in facet.subfacets:
|
|
447
|
+
for point in subfacet.points:
|
|
448
|
+
if point not in d:
|
|
449
|
+
vertices.append(point.coordinates)
|
|
450
|
+
d[point] = c
|
|
451
|
+
c += 1
|
|
452
|
+
tmp.add(point)
|
|
453
|
+
faces.append([d[point] for point in tmp])
|
|
454
|
+
|
|
455
|
+
# Call Polyhedron
|
|
456
|
+
super().__init__(
|
|
457
|
+
vertex_coords=vertices,
|
|
458
|
+
faces_list=faces,
|
|
459
|
+
**kwargs,
|
|
460
|
+
)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from manim.typing import
|
|
5
|
+
from manim.typing import Point3DLike, Vector3D
|
|
6
6
|
from manim.utils.color import BLUE, BLUE_D, BLUE_E, LIGHT_GREY, WHITE, interpolate_color
|
|
7
7
|
|
|
8
8
|
__all__ = [
|
|
@@ -19,7 +19,8 @@ __all__ = [
|
|
|
19
19
|
"Torus",
|
|
20
20
|
]
|
|
21
21
|
|
|
22
|
-
from
|
|
22
|
+
from collections.abc import Iterable, Sequence
|
|
23
|
+
from typing import Any, Callable
|
|
23
24
|
|
|
24
25
|
import numpy as np
|
|
25
26
|
from typing_extensions import Self
|
|
@@ -31,16 +32,10 @@ from manim.mobject.geometry.polygram import Square
|
|
|
31
32
|
from manim.mobject.mobject import *
|
|
32
33
|
from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
|
|
33
34
|
from manim.mobject.opengl.opengl_mobject import OpenGLMobject
|
|
34
|
-
from manim.mobject.types.vectorized_mobject import VGroup, VMobject
|
|
35
|
+
from manim.mobject.types.vectorized_mobject import VectorizedPoint, VGroup, VMobject
|
|
35
36
|
from manim.utils.color import (
|
|
36
|
-
BLUE,
|
|
37
|
-
BLUE_D,
|
|
38
|
-
BLUE_E,
|
|
39
|
-
LIGHT_GREY,
|
|
40
|
-
WHITE,
|
|
41
37
|
ManimColor,
|
|
42
38
|
ParsableManimColor,
|
|
43
|
-
interpolate_color,
|
|
44
39
|
)
|
|
45
40
|
from manim.utils.iterables import tuplify
|
|
46
41
|
from manim.utils.space_ops import normalize, perpendicular_bisector, z_to_vector
|
|
@@ -378,7 +373,7 @@ class Sphere(Surface):
|
|
|
378
373
|
|
|
379
374
|
def __init__(
|
|
380
375
|
self,
|
|
381
|
-
center:
|
|
376
|
+
center: Point3DLike = ORIGIN,
|
|
382
377
|
radius: float = 1,
|
|
383
378
|
resolution: Sequence[int] | None = None,
|
|
384
379
|
u_range: Sequence[float] = (0, TAU),
|
|
@@ -621,17 +616,18 @@ class Cone(Surface):
|
|
|
621
616
|
**kwargs,
|
|
622
617
|
)
|
|
623
618
|
# used for rotations
|
|
619
|
+
self.new_height = height
|
|
624
620
|
self._current_theta = 0
|
|
625
621
|
self._current_phi = 0
|
|
626
|
-
|
|
622
|
+
self.base_circle = Circle(
|
|
623
|
+
radius=base_radius,
|
|
624
|
+
color=self.fill_color,
|
|
625
|
+
fill_opacity=self.fill_opacity,
|
|
626
|
+
stroke_width=0,
|
|
627
|
+
)
|
|
628
|
+
self.base_circle.shift(height * IN)
|
|
629
|
+
self._set_start_and_end_attributes(direction)
|
|
627
630
|
if show_base:
|
|
628
|
-
self.base_circle = Circle(
|
|
629
|
-
radius=base_radius,
|
|
630
|
-
color=self.fill_color,
|
|
631
|
-
fill_opacity=self.fill_opacity,
|
|
632
|
-
stroke_width=0,
|
|
633
|
-
)
|
|
634
|
-
self.base_circle.shift(height * IN)
|
|
635
631
|
self.add(self.base_circle)
|
|
636
632
|
|
|
637
633
|
self._rotate_to_direction()
|
|
@@ -661,14 +657,17 @@ class Cone(Surface):
|
|
|
661
657
|
],
|
|
662
658
|
)
|
|
663
659
|
|
|
660
|
+
def get_start(self) -> np.ndarray:
|
|
661
|
+
return self.start_point.get_center()
|
|
662
|
+
|
|
663
|
+
def get_end(self) -> np.ndarray:
|
|
664
|
+
return self.end_point.get_center()
|
|
665
|
+
|
|
664
666
|
def _rotate_to_direction(self) -> None:
|
|
665
667
|
x, y, z = self.direction
|
|
666
668
|
|
|
667
669
|
r = np.sqrt(x**2 + y**2 + z**2)
|
|
668
|
-
if r > 0
|
|
669
|
-
theta = np.arccos(z / r)
|
|
670
|
-
else:
|
|
671
|
-
theta = 0
|
|
670
|
+
theta = np.arccos(z / r) if r > 0 else 0
|
|
672
671
|
|
|
673
672
|
if x == 0:
|
|
674
673
|
if y == 0: # along the z axis
|
|
@@ -715,6 +714,15 @@ class Cone(Surface):
|
|
|
715
714
|
"""
|
|
716
715
|
return self.direction
|
|
717
716
|
|
|
717
|
+
def _set_start_and_end_attributes(self, direction):
|
|
718
|
+
normalized_direction = direction * np.linalg.norm(direction)
|
|
719
|
+
|
|
720
|
+
start = self.base_circle.get_center()
|
|
721
|
+
end = start + normalized_direction * self.new_height
|
|
722
|
+
self.start_point = VectorizedPoint(start)
|
|
723
|
+
self.end_point = VectorizedPoint(end)
|
|
724
|
+
self.add(self.start_point, self.end_point)
|
|
725
|
+
|
|
718
726
|
|
|
719
727
|
class Cylinder(Surface):
|
|
720
728
|
"""A cylinder, defined by its height, radius and direction,
|
|
@@ -824,10 +832,7 @@ class Cylinder(Surface):
|
|
|
824
832
|
x, y, z = self.direction
|
|
825
833
|
|
|
826
834
|
r = np.sqrt(x**2 + y**2 + z**2)
|
|
827
|
-
if r > 0
|
|
828
|
-
theta = np.arccos(z / r)
|
|
829
|
-
else:
|
|
830
|
-
theta = 0
|
|
835
|
+
theta = np.arccos(z / r) if r > 0 else 0
|
|
831
836
|
|
|
832
837
|
if x == 0:
|
|
833
838
|
if y == 0: # along the z axis
|
|
@@ -890,6 +895,12 @@ class Line3D(Cylinder):
|
|
|
890
895
|
The thickness of the line.
|
|
891
896
|
color
|
|
892
897
|
The color of the line.
|
|
898
|
+
resolution
|
|
899
|
+
The resolution of the line.
|
|
900
|
+
By default this value is the number of points the line will sampled at.
|
|
901
|
+
If you want the line to also come out checkered, use a tuple.
|
|
902
|
+
For example, for a line made of 24 points with 4 checker points on each
|
|
903
|
+
cylinder, pass the tuple (4, 24).
|
|
893
904
|
|
|
894
905
|
Examples
|
|
895
906
|
--------
|
|
@@ -910,9 +921,11 @@ class Line3D(Cylinder):
|
|
|
910
921
|
end: np.ndarray = RIGHT,
|
|
911
922
|
thickness: float = 0.02,
|
|
912
923
|
color: ParsableManimColor | None = None,
|
|
924
|
+
resolution: int | Sequence[int] = 24,
|
|
913
925
|
**kwargs,
|
|
914
926
|
):
|
|
915
927
|
self.thickness = thickness
|
|
928
|
+
self.resolution = (2, resolution) if isinstance(resolution, int) else resolution
|
|
916
929
|
self.set_start_and_end_attrs(start, end, **kwargs)
|
|
917
930
|
if color is not None:
|
|
918
931
|
self.set_color(color)
|
|
@@ -946,13 +959,14 @@ class Line3D(Cylinder):
|
|
|
946
959
|
height=np.linalg.norm(self.vect),
|
|
947
960
|
radius=self.thickness,
|
|
948
961
|
direction=self.direction,
|
|
962
|
+
resolution=self.resolution,
|
|
949
963
|
**kwargs,
|
|
950
964
|
)
|
|
951
965
|
self.shift((self.start + self.end) / 2)
|
|
952
966
|
|
|
953
967
|
def pointify(
|
|
954
968
|
self,
|
|
955
|
-
mob_or_point: Mobject |
|
|
969
|
+
mob_or_point: Mobject | Point3DLike,
|
|
956
970
|
direction: Vector3D = None,
|
|
957
971
|
) -> np.ndarray:
|
|
958
972
|
"""Gets a point representing the center of the :class:`Mobjects <.Mobject>`.
|
|
@@ -1117,6 +1131,8 @@ class Arrow3D(Line3D):
|
|
|
1117
1131
|
The base radius of the conical tip.
|
|
1118
1132
|
color
|
|
1119
1133
|
The color of the arrow.
|
|
1134
|
+
resolution
|
|
1135
|
+
The resolution of the arrow line.
|
|
1120
1136
|
|
|
1121
1137
|
Examples
|
|
1122
1138
|
--------
|
|
@@ -1143,10 +1159,16 @@ class Arrow3D(Line3D):
|
|
|
1143
1159
|
height: float = 0.3,
|
|
1144
1160
|
base_radius: float = 0.08,
|
|
1145
1161
|
color: ParsableManimColor = WHITE,
|
|
1162
|
+
resolution: int | Sequence[int] = 24,
|
|
1146
1163
|
**kwargs,
|
|
1147
1164
|
) -> None:
|
|
1148
1165
|
super().__init__(
|
|
1149
|
-
start=start,
|
|
1166
|
+
start=start,
|
|
1167
|
+
end=end,
|
|
1168
|
+
thickness=thickness,
|
|
1169
|
+
color=color,
|
|
1170
|
+
resolution=resolution,
|
|
1171
|
+
**kwargs,
|
|
1150
1172
|
)
|
|
1151
1173
|
|
|
1152
1174
|
self.length = np.linalg.norm(self.vect)
|
|
@@ -1155,14 +1177,20 @@ class Arrow3D(Line3D):
|
|
|
1155
1177
|
self.end - height * self.direction,
|
|
1156
1178
|
**kwargs,
|
|
1157
1179
|
)
|
|
1158
|
-
|
|
1159
1180
|
self.cone = Cone(
|
|
1160
|
-
direction=self.direction,
|
|
1181
|
+
direction=self.direction,
|
|
1182
|
+
base_radius=base_radius,
|
|
1183
|
+
height=height,
|
|
1184
|
+
**kwargs,
|
|
1161
1185
|
)
|
|
1162
1186
|
self.cone.shift(end)
|
|
1163
|
-
self.
|
|
1187
|
+
self.end_point = VectorizedPoint(end)
|
|
1188
|
+
self.add(self.end_point, self.cone)
|
|
1164
1189
|
self.set_color(color)
|
|
1165
1190
|
|
|
1191
|
+
def get_end(self) -> np.ndarray:
|
|
1192
|
+
return self.end_point.get_center()
|
|
1193
|
+
|
|
1166
1194
|
|
|
1167
1195
|
class Torus(Surface):
|
|
1168
1196
|
"""A torus.
|