manim 0.18.0.post0__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/__init__.py +3 -6
- manim/__main__.py +61 -20
- manim/_config/__init__.py +6 -3
- manim/_config/cli_colors.py +16 -8
- manim/_config/default.cfg +1 -3
- manim/_config/logger_utils.py +14 -8
- manim/_config/utils.py +651 -472
- manim/animation/animation.py +152 -5
- manim/animation/composition.py +80 -39
- manim/animation/creation.py +196 -14
- manim/animation/fading.py +5 -9
- manim/animation/indication.py +103 -47
- manim/animation/movement.py +22 -5
- manim/animation/rotation.py +3 -2
- manim/animation/specialized.py +4 -6
- manim/animation/speedmodifier.py +10 -5
- manim/animation/transform.py +4 -5
- manim/animation/transform_matching_parts.py +1 -1
- manim/animation/updaters/mobject_update_utils.py +17 -14
- manim/camera/camera.py +15 -6
- manim/cli/__init__.py +17 -0
- manim/cli/cfg/group.py +70 -44
- manim/cli/checkhealth/checks.py +93 -75
- manim/cli/checkhealth/commands.py +14 -5
- manim/cli/default_group.py +157 -25
- manim/cli/init/commands.py +32 -24
- 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 +51 -15
- manim/cli/render/output_options.py +6 -5
- manim/cli/render/render_options.py +97 -32
- manim/constants.py +65 -19
- manim/gui/gui.py +2 -0
- manim/mobject/frame.py +0 -1
- manim/mobject/geometry/arc.py +112 -78
- manim/mobject/geometry/boolean_ops.py +32 -25
- manim/mobject/geometry/labeled.py +300 -77
- manim/mobject/geometry/line.py +132 -64
- manim/mobject/geometry/polygram.py +126 -30
- manim/mobject/geometry/shape_matchers.py +35 -15
- manim/mobject/geometry/tips.py +38 -29
- manim/mobject/graph.py +414 -133
- manim/mobject/graphing/coordinate_systems.py +126 -64
- manim/mobject/graphing/functions.py +25 -15
- manim/mobject/graphing/number_line.py +24 -10
- manim/mobject/graphing/probability.py +2 -10
- manim/mobject/graphing/scale.py +6 -5
- manim/mobject/matrix.py +17 -19
- manim/mobject/mobject.py +314 -165
- manim/mobject/opengl/opengl_compatibility.py +2 -0
- manim/mobject/opengl/opengl_geometry.py +30 -9
- manim/mobject/opengl/opengl_image_mobject.py +2 -0
- manim/mobject/opengl/opengl_mobject.py +509 -343
- manim/mobject/opengl/opengl_point_cloud_mobject.py +5 -7
- manim/mobject/opengl/opengl_surface.py +3 -2
- manim/mobject/opengl/opengl_three_dimensions.py +2 -0
- manim/mobject/opengl/opengl_vectorized_mobject.py +46 -79
- manim/mobject/svg/brace.py +63 -13
- manim/mobject/svg/svg_mobject.py +4 -3
- manim/mobject/table.py +11 -13
- manim/mobject/text/code_mobject.py +186 -548
- manim/mobject/text/numbers.py +9 -7
- manim/mobject/text/tex_mobject.py +23 -14
- manim/mobject/text/text_mobject.py +70 -24
- manim/mobject/three_d/polyhedra.py +98 -1
- manim/mobject/three_d/three_d_utils.py +4 -4
- manim/mobject/three_d/three_dimensions.py +62 -34
- manim/mobject/types/image_mobject.py +42 -24
- manim/mobject/types/point_cloud_mobject.py +105 -67
- manim/mobject/types/vectorized_mobject.py +496 -228
- manim/mobject/value_tracker.py +5 -4
- manim/mobject/vector_field.py +5 -5
- manim/opengl/__init__.py +3 -3
- manim/plugins/__init__.py +14 -1
- manim/plugins/plugins_flags.py +14 -8
- manim/renderer/cairo_renderer.py +20 -10
- manim/renderer/opengl_renderer.py +21 -23
- manim/renderer/opengl_renderer_window.py +2 -0
- manim/renderer/shader.py +2 -3
- manim/renderer/shader_wrapper.py +5 -2
- manim/renderer/vectorized_mobject_rendering.py +5 -0
- manim/scene/moving_camera_scene.py +23 -0
- manim/scene/scene.py +90 -43
- manim/scene/scene_file_writer.py +316 -165
- manim/scene/section.py +17 -15
- manim/scene/three_d_scene.py +13 -21
- manim/scene/vector_space_scene.py +22 -9
- manim/typing.py +830 -70
- manim/utils/bezier.py +1667 -399
- manim/utils/caching.py +13 -5
- manim/utils/color/AS2700.py +2 -0
- manim/utils/color/BS381.py +3 -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 +3 -0
- manim/utils/color/__init__.py +8 -5
- manim/utils/color/core.py +844 -309
- manim/utils/color/manim_colors.py +7 -9
- manim/utils/commands.py +48 -20
- manim/utils/config_ops.py +18 -13
- manim/utils/debug.py +8 -7
- manim/utils/deprecation.py +90 -40
- manim/utils/docbuild/__init__.py +17 -0
- manim/utils/docbuild/autoaliasattr_directive.py +234 -0
- manim/utils/docbuild/autocolor_directive.py +21 -17
- manim/utils/docbuild/manim_directive.py +50 -35
- 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 +26 -16
- manim/utils/hashing.py +9 -7
- manim/utils/images.py +10 -4
- manim/utils/ipython_magic.py +14 -8
- manim/utils/iterables.py +161 -119
- manim/utils/module_ops.py +57 -19
- manim/utils/opengl.py +83 -24
- manim/utils/parameter_parsing.py +32 -0
- manim/utils/paths.py +21 -23
- manim/utils/polylabel.py +168 -0
- manim/utils/qhull.py +218 -0
- manim/utils/rate_functions.py +74 -39
- manim/utils/simple_functions.py +24 -15
- manim/utils/sounds.py +7 -1
- manim/utils/space_ops.py +125 -69
- 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 +33 -18
- manim/utils/testing/frames_comparison.py +27 -19
- manim/utils/tex.py +127 -197
- manim/utils/tex_file_writing.py +47 -45
- manim/utils/tex_templates.py +2 -1
- manim/utils/unit.py +6 -5
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE.community +1 -1
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/METADATA +40 -39
- manim-0.19.0.dist-info/RECORD +221 -0
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
- manim/cli/new/__init__.py +0 -0
- manim/cli/new/group.py +0 -189
- manim/plugins/import_plugins.py +0 -43
- manim-0.18.0.post0.dist-info/RECORD +0 -217
- {manim-0.18.0.post0.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
- {manim-0.18.0.post0.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
|
|
|
@@ -18,9 +19,11 @@ from manim.mobject.value_tracker import ValueTracker
|
|
|
18
19
|
|
|
19
20
|
string_to_mob_map = {}
|
|
20
21
|
|
|
22
|
+
__all__ = ["DecimalNumber", "Integer", "Variable"]
|
|
23
|
+
|
|
21
24
|
|
|
22
25
|
class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|
23
|
-
"""An mobject representing a decimal number.
|
|
26
|
+
r"""An mobject representing a decimal number.
|
|
24
27
|
|
|
25
28
|
Parameters
|
|
26
29
|
----------
|
|
@@ -208,10 +211,7 @@ class DecimalNumber(VMobject, metaclass=ConvertToOpenGL):
|
|
|
208
211
|
|
|
209
212
|
rounded_num = np.round(number, self.num_decimal_places)
|
|
210
213
|
if num_string.startswith("-") and rounded_num == 0:
|
|
211
|
-
if self.include_sign:
|
|
212
|
-
num_string = "+" + num_string[1:]
|
|
213
|
-
else:
|
|
214
|
-
num_string = num_string[1:]
|
|
214
|
+
num_string = "+" + num_string[1:] if self.include_sign else num_string[1:]
|
|
215
215
|
|
|
216
216
|
return num_string
|
|
217
217
|
|
|
@@ -328,7 +328,9 @@ class Integer(DecimalNumber):
|
|
|
328
328
|
self.add(Integer(number=6.28).set_x(-1.5).set_y(-2).set_color(YELLOW).scale(1.4))
|
|
329
329
|
"""
|
|
330
330
|
|
|
331
|
-
def __init__(
|
|
331
|
+
def __init__(
|
|
332
|
+
self, number: float = 0, num_decimal_places: int = 0, **kwargs: Any
|
|
333
|
+
) -> None:
|
|
332
334
|
super().__init__(number=number, num_decimal_places=num_decimal_places, **kwargs)
|
|
333
335
|
|
|
334
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,15 +26,15 @@ __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 *
|
|
35
35
|
from manim.mobject.geometry.line import Line
|
|
36
36
|
from manim.mobject.svg.svg_mobject import SVGMobject
|
|
37
|
-
from manim.mobject.types.vectorized_mobject import
|
|
37
|
+
from manim.mobject.types.vectorized_mobject import VGroup, VMobject
|
|
38
38
|
from manim.utils.tex import TexTemplate
|
|
39
39
|
from manim.utils.tex_file_writing import tex_to_svg_file
|
|
40
40
|
|
|
@@ -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
|
|
|
@@ -49,17 +49,18 @@ Examples
|
|
|
49
49
|
|
|
50
50
|
from __future__ import annotations
|
|
51
51
|
|
|
52
|
+
import functools
|
|
53
|
+
|
|
52
54
|
__all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
|
|
53
55
|
|
|
54
56
|
|
|
55
57
|
import copy
|
|
56
58
|
import hashlib
|
|
57
|
-
import os
|
|
58
59
|
import re
|
|
60
|
+
from collections.abc import Iterable, Sequence
|
|
59
61
|
from contextlib import contextmanager
|
|
60
62
|
from itertools import chain
|
|
61
63
|
from pathlib import Path
|
|
62
|
-
from typing import Iterable, Sequence
|
|
63
64
|
|
|
64
65
|
import manimpango
|
|
65
66
|
import numpy as np
|
|
@@ -77,6 +78,8 @@ TEXT_MOB_SCALE_FACTOR = 0.05
|
|
|
77
78
|
DEFAULT_LINE_SPACING_SCALE = 0.3
|
|
78
79
|
TEXT2SVG_ADJUSTMENT_FACTOR = 4.8
|
|
79
80
|
|
|
81
|
+
__all__ = ["Text", "Paragraph", "MarkupText", "register_font"]
|
|
82
|
+
|
|
80
83
|
|
|
81
84
|
def remove_invisible_chars(mobject: SVGMobject) -> SVGMobject:
|
|
82
85
|
"""Function to remove unwanted invisible characters from some mobjects.
|
|
@@ -131,10 +134,17 @@ class Paragraph(VGroup):
|
|
|
131
134
|
--------
|
|
132
135
|
Normal usage::
|
|
133
136
|
|
|
134
|
-
paragraph = Paragraph(
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
+
)
|
|
138
148
|
|
|
139
149
|
Remove unwanted invisible characters::
|
|
140
150
|
|
|
@@ -350,7 +360,7 @@ class Text(SVGMobject):
|
|
|
350
360
|
)
|
|
351
361
|
text6.scale(1.3).shift(DOWN)
|
|
352
362
|
self.add(text1, text2, text3, text4, text5 , text6)
|
|
353
|
-
Group(*self.mobjects).arrange(DOWN, buff=.8).
|
|
363
|
+
Group(*self.mobjects).arrange(DOWN, buff=.8).set(height=config.frame_height-LARGE_BUFF)
|
|
354
364
|
|
|
355
365
|
.. manim:: TextMoreCustomization
|
|
356
366
|
:save_last_frame:
|
|
@@ -407,6 +417,11 @@ class Text(SVGMobject):
|
|
|
407
417
|
|
|
408
418
|
"""
|
|
409
419
|
|
|
420
|
+
@staticmethod
|
|
421
|
+
@functools.cache
|
|
422
|
+
def font_list() -> list[str]:
|
|
423
|
+
return manimpango.list_fonts()
|
|
424
|
+
|
|
410
425
|
def __init__(
|
|
411
426
|
self,
|
|
412
427
|
text: str,
|
|
@@ -431,13 +446,25 @@ class Text(SVGMobject):
|
|
|
431
446
|
width: float = None,
|
|
432
447
|
should_center: bool = True,
|
|
433
448
|
disable_ligatures: bool = False,
|
|
449
|
+
use_svg_cache: bool = False,
|
|
434
450
|
**kwargs,
|
|
435
451
|
) -> None:
|
|
436
452
|
self.line_spacing = line_spacing
|
|
437
453
|
if font and warn_missing_font:
|
|
438
|
-
fonts_list =
|
|
454
|
+
fonts_list = Text.font_list()
|
|
455
|
+
# handle special case of sans/sans-serif
|
|
456
|
+
if font.lower() == "sans-serif":
|
|
457
|
+
font = "sans"
|
|
439
458
|
if font not in fonts_list:
|
|
440
|
-
|
|
459
|
+
# check if the capitalized version is in the supported fonts
|
|
460
|
+
if font.capitalize() in fonts_list:
|
|
461
|
+
font = font.capitalize()
|
|
462
|
+
elif font.lower() in fonts_list:
|
|
463
|
+
font = font.lower()
|
|
464
|
+
elif font.title() in fonts_list:
|
|
465
|
+
font = font.title()
|
|
466
|
+
else:
|
|
467
|
+
logger.warning(f"Font {font} not in {fonts_list}.")
|
|
441
468
|
self.font = font
|
|
442
469
|
self._font_size = float(font_size)
|
|
443
470
|
# needs to be a float or else size is inflated when font_size = 24
|
|
@@ -491,7 +518,7 @@ class Text(SVGMobject):
|
|
|
491
518
|
height=height,
|
|
492
519
|
width=width,
|
|
493
520
|
should_center=should_center,
|
|
494
|
-
use_svg_cache=
|
|
521
|
+
use_svg_cache=use_svg_cache,
|
|
495
522
|
**kwargs,
|
|
496
523
|
)
|
|
497
524
|
self.text = text
|
|
@@ -636,7 +663,8 @@ class Text(SVGMobject):
|
|
|
636
663
|
)
|
|
637
664
|
def _set_color_by_t2g(self, t2g=None):
|
|
638
665
|
"""Sets gradient colors for specified
|
|
639
|
-
strings. Behaves similarly to ``set_color_by_t2c``.
|
|
666
|
+
strings. Behaves similarly to ``set_color_by_t2c``.
|
|
667
|
+
"""
|
|
640
668
|
t2g = t2g if t2g else self.t2g
|
|
641
669
|
for word, gradient in list(t2g.items()):
|
|
642
670
|
for start, end in self._find_indexes(word, self.text):
|
|
@@ -675,7 +703,7 @@ class Text(SVGMobject):
|
|
|
675
703
|
default = default_args[arg]
|
|
676
704
|
if left != default and getattr(right_setting, arg) != default:
|
|
677
705
|
raise ValueError(
|
|
678
|
-
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]}':"
|
|
679
707
|
+ f"'{arg}' cannot be both '{left}' and '{right}'."
|
|
680
708
|
)
|
|
681
709
|
setattr(right_setting, arg, left if left != default else right)
|
|
@@ -886,7 +914,7 @@ class MarkupText(SVGMobject):
|
|
|
886
914
|
Here is a list of supported tags:
|
|
887
915
|
|
|
888
916
|
- ``<b>bold</b>``, ``<i>italic</i>`` and ``<b><i>bold+italic</i></b>``
|
|
889
|
-
- ``<
|
|
917
|
+
- ``<u>underline</u>`` and ``<s>strike through</s>``
|
|
890
918
|
- ``<tt>typewriter font</tt>``
|
|
891
919
|
- ``<big>bigger font</big>`` and ``<small>smaller font</small>``
|
|
892
920
|
- ``<sup>superscript</sup>`` and ``<sub>subscript</sub>``
|
|
@@ -1133,6 +1161,11 @@ class MarkupText(SVGMobject):
|
|
|
1133
1161
|
|
|
1134
1162
|
"""
|
|
1135
1163
|
|
|
1164
|
+
@staticmethod
|
|
1165
|
+
@functools.cache
|
|
1166
|
+
def font_list() -> list[str]:
|
|
1167
|
+
return manimpango.list_fonts()
|
|
1168
|
+
|
|
1136
1169
|
def __init__(
|
|
1137
1170
|
self,
|
|
1138
1171
|
text: str,
|
|
@@ -1157,9 +1190,20 @@ class MarkupText(SVGMobject):
|
|
|
1157
1190
|
self.text = text
|
|
1158
1191
|
self.line_spacing = line_spacing
|
|
1159
1192
|
if font and warn_missing_font:
|
|
1160
|
-
fonts_list =
|
|
1193
|
+
fonts_list = Text.font_list()
|
|
1194
|
+
# handle special case of sans/sans-serif
|
|
1195
|
+
if font.lower() == "sans-serif":
|
|
1196
|
+
font = "sans"
|
|
1161
1197
|
if font not in fonts_list:
|
|
1162
|
-
|
|
1198
|
+
# check if the capitalized version is in the supported fonts
|
|
1199
|
+
if font.capitalize() in fonts_list:
|
|
1200
|
+
font = font.capitalize()
|
|
1201
|
+
elif font.lower() in fonts_list:
|
|
1202
|
+
font = font.lower()
|
|
1203
|
+
elif font.title() in fonts_list:
|
|
1204
|
+
font = font.title()
|
|
1205
|
+
else:
|
|
1206
|
+
logger.warning(f"Font {font} not in {fonts_list}.")
|
|
1163
1207
|
self.font = font
|
|
1164
1208
|
self._font_size = float(font_size)
|
|
1165
1209
|
self.slant = slant
|
|
@@ -1268,15 +1312,13 @@ class MarkupText(SVGMobject):
|
|
|
1268
1312
|
self.set_color_by_gradient(*self.gradient)
|
|
1269
1313
|
for col in colormap:
|
|
1270
1314
|
self.chars[
|
|
1271
|
-
col["start"]
|
|
1272
|
-
- col["start_offset"] : col["end"]
|
|
1315
|
+
col["start"] - col["start_offset"] : col["end"]
|
|
1273
1316
|
- col["start_offset"]
|
|
1274
1317
|
- col["end_offset"]
|
|
1275
1318
|
].set_color(self._parse_color(col["color"]))
|
|
1276
1319
|
for grad in gradientmap:
|
|
1277
1320
|
self.chars[
|
|
1278
|
-
grad["start"]
|
|
1279
|
-
- grad["start_offset"] : grad["end"]
|
|
1321
|
+
grad["start"] - grad["start_offset"] : grad["end"]
|
|
1280
1322
|
- grad["start_offset"]
|
|
1281
1323
|
- grad["end_offset"]
|
|
1282
1324
|
].set_color_by_gradient(
|
|
@@ -1369,7 +1411,8 @@ class MarkupText(SVGMobject):
|
|
|
1369
1411
|
"""Counts characters that will be displayed.
|
|
1370
1412
|
|
|
1371
1413
|
This is needed for partial coloring or gradients, because space
|
|
1372
|
-
counts to the text's `len`, but has no corresponding character.
|
|
1414
|
+
counts to the text's `len`, but has no corresponding character.
|
|
1415
|
+
"""
|
|
1373
1416
|
count = 0
|
|
1374
1417
|
level = 0
|
|
1375
1418
|
# temporarily replace HTML entities by single char
|
|
@@ -1412,7 +1455,9 @@ class MarkupText(SVGMobject):
|
|
|
1412
1455
|
"end_offset": end_offset,
|
|
1413
1456
|
},
|
|
1414
1457
|
)
|
|
1415
|
-
self.text = re.sub(
|
|
1458
|
+
self.text = re.sub(
|
|
1459
|
+
"<gradient[^>]+>(.+?)</gradient>", r"\1", self.text, count=0, flags=re.S
|
|
1460
|
+
)
|
|
1416
1461
|
return gradientmap
|
|
1417
1462
|
|
|
1418
1463
|
def _parse_color(self, col):
|
|
@@ -1454,7 +1499,9 @@ class MarkupText(SVGMobject):
|
|
|
1454
1499
|
"end_offset": end_offset,
|
|
1455
1500
|
},
|
|
1456
1501
|
)
|
|
1457
|
-
self.text = re.sub(
|
|
1502
|
+
self.text = re.sub(
|
|
1503
|
+
"<color[^>]+>(.+?)</color>", r"\1", self.text, count=0, flags=re.S
|
|
1504
|
+
)
|
|
1458
1505
|
return colormap
|
|
1459
1506
|
|
|
1460
1507
|
def __repr__(self):
|
|
@@ -1500,7 +1547,6 @@ def register_font(font_file: str | Path):
|
|
|
1500
1547
|
This method is available for macOS for ``ManimPango>=v0.2.3``. Using this
|
|
1501
1548
|
method with previous releases will raise an :class:`AttributeError` on macOS.
|
|
1502
1549
|
"""
|
|
1503
|
-
|
|
1504
1550
|
input_folder = Path(config.input_file).parent.resolve()
|
|
1505
1551
|
possible_paths = [
|
|
1506
1552
|
Path(font_file),
|
|
@@ -1515,7 +1561,7 @@ def register_font(font_file: str | Path):
|
|
|
1515
1561
|
logger.debug("Found file at %s", file_path.absolute())
|
|
1516
1562
|
break
|
|
1517
1563
|
else:
|
|
1518
|
-
error = f"Can't find {font_file}.
|
|
1564
|
+
error = f"Can't find {font_file}.Tried these : {possible_paths}"
|
|
1519
1565
|
raise FileNotFoundError(error)
|
|
1520
1566
|
|
|
1521
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
|
+
)
|
|
@@ -22,7 +22,7 @@ from manim.constants import ORIGIN, UP
|
|
|
22
22
|
from manim.utils.space_ops import get_unit_normal
|
|
23
23
|
|
|
24
24
|
if TYPE_CHECKING:
|
|
25
|
-
from manim.typing import Point3D,
|
|
25
|
+
from manim.typing import Point3D, Vector3D
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def get_3d_vmob_gradient_start_and_end_points(vmob) -> tuple[Point3D, Point3D]:
|
|
@@ -52,7 +52,7 @@ def get_3d_vmob_end_corner(vmob) -> Point3D:
|
|
|
52
52
|
return vmob.points[get_3d_vmob_end_corner_index(vmob)]
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def get_3d_vmob_unit_normal(vmob, point_index: int) ->
|
|
55
|
+
def get_3d_vmob_unit_normal(vmob, point_index: int) -> Vector3D:
|
|
56
56
|
n_points = vmob.get_num_points()
|
|
57
57
|
if len(vmob.get_anchors()) <= 2:
|
|
58
58
|
return np.array(UP)
|
|
@@ -68,9 +68,9 @@ def get_3d_vmob_unit_normal(vmob, point_index: int) -> Vector:
|
|
|
68
68
|
return unit_normal
|
|
69
69
|
|
|
70
70
|
|
|
71
|
-
def get_3d_vmob_start_corner_unit_normal(vmob) ->
|
|
71
|
+
def get_3d_vmob_start_corner_unit_normal(vmob) -> Vector3D:
|
|
72
72
|
return get_3d_vmob_unit_normal(vmob, get_3d_vmob_start_corner_index(vmob))
|
|
73
73
|
|
|
74
74
|
|
|
75
|
-
def get_3d_vmob_end_corner_unit_normal(vmob) ->
|
|
75
|
+
def get_3d_vmob_end_corner_unit_normal(vmob) -> Vector3D:
|
|
76
76
|
return get_3d_vmob_unit_normal(vmob, get_3d_vmob_end_corner_index(vmob))
|