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.

Files changed (129) hide show
  1. manim/__main__.py +45 -12
  2. manim/_config/__init__.py +2 -2
  3. manim/_config/cli_colors.py +8 -4
  4. manim/_config/default.cfg +0 -2
  5. manim/_config/logger_utils.py +5 -0
  6. manim/_config/utils.py +29 -38
  7. manim/animation/animation.py +148 -8
  8. manim/animation/composition.py +16 -13
  9. manim/animation/creation.py +184 -8
  10. manim/animation/fading.py +5 -8
  11. manim/animation/indication.py +93 -26
  12. manim/animation/movement.py +21 -3
  13. manim/animation/rotation.py +2 -1
  14. manim/animation/specialized.py +3 -5
  15. manim/animation/speedmodifier.py +3 -3
  16. manim/animation/transform.py +4 -5
  17. manim/animation/updaters/mobject_update_utils.py +17 -14
  18. manim/camera/camera.py +2 -2
  19. manim/cli/__init__.py +17 -0
  20. manim/cli/cfg/group.py +52 -36
  21. manim/cli/checkhealth/checks.py +92 -76
  22. manim/cli/checkhealth/commands.py +12 -5
  23. manim/cli/default_group.py +148 -24
  24. manim/cli/init/commands.py +28 -23
  25. manim/cli/plugins/commands.py +13 -3
  26. manim/cli/render/commands.py +47 -42
  27. manim/cli/render/global_options.py +43 -9
  28. manim/cli/render/render_options.py +84 -19
  29. manim/constants.py +11 -4
  30. manim/mobject/frame.py +0 -1
  31. manim/mobject/geometry/arc.py +109 -75
  32. manim/mobject/geometry/boolean_ops.py +20 -17
  33. manim/mobject/geometry/labeled.py +300 -77
  34. manim/mobject/geometry/line.py +120 -60
  35. manim/mobject/geometry/polygram.py +109 -25
  36. manim/mobject/geometry/shape_matchers.py +35 -15
  37. manim/mobject/geometry/tips.py +36 -27
  38. manim/mobject/graph.py +48 -40
  39. manim/mobject/graphing/coordinate_systems.py +110 -45
  40. manim/mobject/graphing/functions.py +16 -10
  41. manim/mobject/graphing/number_line.py +23 -9
  42. manim/mobject/graphing/probability.py +2 -10
  43. manim/mobject/graphing/scale.py +6 -5
  44. manim/mobject/matrix.py +17 -19
  45. manim/mobject/mobject.py +149 -103
  46. manim/mobject/opengl/opengl_geometry.py +4 -8
  47. manim/mobject/opengl/opengl_mobject.py +506 -343
  48. manim/mobject/opengl/opengl_point_cloud_mobject.py +3 -7
  49. manim/mobject/opengl/opengl_surface.py +1 -2
  50. manim/mobject/opengl/opengl_vectorized_mobject.py +27 -65
  51. manim/mobject/svg/brace.py +61 -13
  52. manim/mobject/svg/svg_mobject.py +2 -1
  53. manim/mobject/table.py +11 -12
  54. manim/mobject/text/code_mobject.py +186 -550
  55. manim/mobject/text/numbers.py +7 -7
  56. manim/mobject/text/tex_mobject.py +22 -13
  57. manim/mobject/text/text_mobject.py +29 -20
  58. manim/mobject/three_d/polyhedra.py +98 -1
  59. manim/mobject/three_d/three_dimensions.py +59 -31
  60. manim/mobject/types/image_mobject.py +37 -23
  61. manim/mobject/types/point_cloud_mobject.py +103 -67
  62. manim/mobject/types/vectorized_mobject.py +387 -214
  63. manim/mobject/value_tracker.py +2 -1
  64. manim/mobject/vector_field.py +2 -4
  65. manim/opengl/__init__.py +3 -3
  66. manim/plugins/__init__.py +2 -3
  67. manim/plugins/plugins_flags.py +3 -3
  68. manim/renderer/cairo_renderer.py +11 -11
  69. manim/renderer/opengl_renderer.py +19 -20
  70. manim/renderer/shader.py +2 -3
  71. manim/renderer/shader_wrapper.py +3 -2
  72. manim/scene/moving_camera_scene.py +23 -0
  73. manim/scene/scene.py +72 -41
  74. manim/scene/scene_file_writer.py +313 -164
  75. manim/scene/section.py +15 -15
  76. manim/scene/three_d_scene.py +8 -15
  77. manim/scene/vector_space_scene.py +3 -6
  78. manim/typing.py +326 -66
  79. manim/utils/bezier.py +1658 -381
  80. manim/utils/caching.py +11 -5
  81. manim/utils/color/AS2700.py +2 -0
  82. manim/utils/color/BS381.py +2 -0
  83. manim/utils/color/DVIPSNAMES.py +96 -0
  84. manim/utils/color/SVGNAMES.py +179 -0
  85. manim/utils/color/X11.py +3 -0
  86. manim/utils/color/XKCD.py +2 -0
  87. manim/utils/color/__init__.py +8 -5
  88. manim/utils/color/core.py +818 -301
  89. manim/utils/color/manim_colors.py +7 -9
  90. manim/utils/commands.py +40 -19
  91. manim/utils/config_ops.py +18 -13
  92. manim/utils/debug.py +8 -6
  93. manim/utils/deprecation.py +92 -43
  94. manim/utils/docbuild/autoaliasattr_directive.py +45 -8
  95. manim/utils/docbuild/autocolor_directive.py +12 -13
  96. manim/utils/docbuild/manim_directive.py +35 -29
  97. manim/utils/docbuild/module_parsing.py +74 -27
  98. manim/utils/family.py +3 -3
  99. manim/utils/family_ops.py +12 -4
  100. manim/utils/file_ops.py +22 -16
  101. manim/utils/hashing.py +7 -7
  102. manim/utils/images.py +10 -4
  103. manim/utils/ipython_magic.py +12 -8
  104. manim/utils/iterables.py +161 -119
  105. manim/utils/module_ops.py +55 -19
  106. manim/utils/opengl.py +68 -23
  107. manim/utils/parameter_parsing.py +3 -2
  108. manim/utils/paths.py +11 -5
  109. manim/utils/polylabel.py +168 -0
  110. manim/utils/qhull.py +218 -0
  111. manim/utils/rate_functions.py +69 -32
  112. manim/utils/simple_functions.py +24 -15
  113. manim/utils/sounds.py +7 -1
  114. manim/utils/space_ops.py +48 -37
  115. manim/utils/testing/_frames_testers.py +13 -8
  116. manim/utils/testing/_show_diff.py +5 -3
  117. manim/utils/testing/_test_class_makers.py +33 -18
  118. manim/utils/testing/frames_comparison.py +20 -14
  119. manim/utils/tex.py +4 -2
  120. manim/utils/tex_file_writing.py +45 -45
  121. manim/utils/tex_templates.py +1 -1
  122. manim/utils/unit.py +6 -5
  123. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/METADATA +16 -9
  124. manim-0.19.0.dist-info/RECORD +221 -0
  125. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/WHEEL +1 -1
  126. manim-0.18.1.dist-info/RECORD +0 -217
  127. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE +0 -0
  128. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/LICENSE.community +0 -0
  129. {manim-0.18.1.dist-info → manim-0.19.0.dist-info}/entry_points.txt +0 -0
@@ -4,7 +4,8 @@ from __future__ import annotations
4
4
 
5
5
  __all__ = ["DecimalNumber", "Integer", "Variable"]
6
6
 
7
- from typing import Sequence
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__(self, number=0, num_decimal_places=0, **kwargs):
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 kwargs.get("color") is None:
68
- # makes it so that color isn't explicitly passed for these mobs,
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
- if config.renderer == RendererType.OPENGL:
215
- super().init_colors()
216
- elif config.renderer == RendererType.CAIRO:
217
- super().init_colors(propagate_colors=propagate_colors)
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('this is a awesome', 'paragraph',
139
- 'With \nNewlines', '\tWith Tabs',
140
- ' With Spaces', 'With Alignments',
141
- 'center', 'left', 'right')
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.lru_cache(maxsize=None)
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
- - ``<ul>underline</ul>`` and ``<s>strike through</s>``
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.lru_cache(maxsize=None)
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("<gradient[^>]+>(.+?)</gradient>", r"\1", self.text, 0, re.S)
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("<color[^>]+>(.+?)</color>", r"\1", self.text, 0, re.S)
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}." f"Tried these : {possible_paths}"
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__ = ["Polyhedron", "Tetrahedron", "Octahedron", "Icosahedron", "Dodecahedron"]
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 Point3D, Vector3D
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 typing import Any, Callable, Iterable, Sequence
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: Point3D = ORIGIN,
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 | Point3D,
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, end=end, thickness=thickness, color=color, **kwargs
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, base_radius=base_radius, height=height, **kwargs
1181
+ direction=self.direction,
1182
+ base_radius=base_radius,
1183
+ height=height,
1184
+ **kwargs,
1161
1185
  )
1162
1186
  self.cone.shift(end)
1163
- self.add(self.cone)
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.