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.
Files changed (163) hide show
  1. manim/__init__.py +11 -6
  2. manim/__main__.py +62 -19
  3. manim/_config/__init__.py +10 -9
  4. manim/_config/cli_colors.py +26 -9
  5. manim/_config/default.cfg +1 -3
  6. manim/_config/logger_utils.py +23 -13
  7. manim/_config/utils.py +662 -468
  8. manim/animation/animation.py +164 -18
  9. manim/animation/changing.py +34 -23
  10. manim/animation/composition.py +265 -67
  11. manim/animation/creation.py +208 -26
  12. manim/animation/fading.py +16 -18
  13. manim/animation/growing.py +35 -15
  14. manim/animation/indication.py +150 -76
  15. manim/animation/movement.py +56 -22
  16. manim/animation/numbers.py +64 -6
  17. manim/animation/rotation.py +78 -7
  18. manim/animation/specialized.py +6 -7
  19. manim/animation/speedmodifier.py +13 -10
  20. manim/animation/transform.py +14 -11
  21. manim/animation/transform_matching_parts.py +3 -4
  22. manim/animation/updaters/mobject_update_utils.py +152 -30
  23. manim/animation/updaters/update.py +10 -7
  24. manim/camera/camera.py +182 -118
  25. manim/camera/mapping_camera.py +34 -3
  26. manim/camera/moving_camera.py +95 -74
  27. manim/camera/multi_camera.py +23 -15
  28. manim/camera/three_d_camera.py +70 -52
  29. manim/cli/__init__.py +17 -0
  30. manim/cli/cfg/group.py +76 -44
  31. manim/cli/checkhealth/checks.py +192 -0
  32. manim/cli/checkhealth/commands.py +90 -0
  33. manim/cli/default_group.py +158 -25
  34. manim/cli/init/commands.py +33 -25
  35. manim/cli/plugins/commands.py +16 -3
  36. manim/cli/render/commands.py +72 -60
  37. manim/cli/render/ease_of_access_options.py +4 -3
  38. manim/cli/render/global_options.py +59 -17
  39. manim/cli/render/output_options.py +6 -5
  40. manim/cli/render/render_options.py +98 -33
  41. manim/constants.py +109 -59
  42. manim/data_structures.py +31 -0
  43. manim/mobject/frame.py +8 -5
  44. manim/mobject/geometry/__init__.py +1 -0
  45. manim/mobject/geometry/arc.py +277 -135
  46. manim/mobject/geometry/boolean_ops.py +32 -31
  47. manim/mobject/geometry/labeled.py +376 -0
  48. manim/mobject/geometry/line.py +192 -87
  49. manim/mobject/geometry/polygram.py +224 -58
  50. manim/mobject/geometry/shape_matchers.py +61 -25
  51. manim/mobject/geometry/tips.py +122 -48
  52. manim/mobject/graph.py +1027 -419
  53. manim/mobject/graphing/coordinate_systems.py +533 -278
  54. manim/mobject/graphing/functions.py +53 -32
  55. manim/mobject/graphing/number_line.py +123 -65
  56. manim/mobject/graphing/probability.py +88 -62
  57. manim/mobject/graphing/scale.py +33 -19
  58. manim/mobject/logo.py +118 -28
  59. manim/mobject/matrix.py +87 -83
  60. manim/mobject/mobject.py +912 -442
  61. manim/mobject/opengl/dot_cloud.py +16 -5
  62. manim/mobject/opengl/opengl_compatibility.py +4 -2
  63. manim/mobject/opengl/opengl_geometry.py +254 -153
  64. manim/mobject/opengl/opengl_image_mobject.py +3 -1
  65. manim/mobject/opengl/opengl_mobject.py +779 -482
  66. manim/mobject/opengl/opengl_point_cloud_mobject.py +41 -14
  67. manim/mobject/opengl/opengl_surface.py +14 -92
  68. manim/mobject/opengl/opengl_three_dimensions.py +12 -8
  69. manim/mobject/opengl/opengl_vectorized_mobject.py +98 -100
  70. manim/mobject/svg/brace.py +173 -41
  71. manim/mobject/svg/svg_mobject.py +139 -53
  72. manim/mobject/table.py +61 -68
  73. manim/mobject/text/code_mobject.py +193 -539
  74. manim/mobject/text/numbers.py +81 -34
  75. manim/mobject/text/tex_mobject.py +130 -78
  76. manim/mobject/text/text_mobject.py +288 -164
  77. manim/mobject/three_d/polyhedra.py +111 -13
  78. manim/mobject/three_d/three_d_utils.py +17 -8
  79. manim/mobject/three_d/three_dimensions.py +239 -106
  80. manim/mobject/types/image_mobject.py +50 -30
  81. manim/mobject/types/point_cloud_mobject.py +120 -75
  82. manim/mobject/types/vectorized_mobject.py +841 -408
  83. manim/mobject/value_tracker.py +105 -38
  84. manim/mobject/vector_field.py +50 -31
  85. manim/opengl/__init__.py +3 -3
  86. manim/plugins/__init__.py +14 -1
  87. manim/plugins/plugins_flags.py +10 -14
  88. manim/renderer/cairo_renderer.py +65 -50
  89. manim/renderer/opengl_renderer.py +89 -69
  90. manim/renderer/opengl_renderer_window.py +39 -18
  91. manim/renderer/shader.py +123 -87
  92. manim/renderer/shader_wrapper.py +44 -28
  93. manim/renderer/vectorized_mobject_rendering.py +38 -10
  94. manim/scene/moving_camera_scene.py +32 -3
  95. manim/scene/scene.py +507 -242
  96. manim/scene/scene_file_writer.py +371 -220
  97. manim/scene/section.py +20 -16
  98. manim/scene/three_d_scene.py +14 -22
  99. manim/scene/vector_space_scene.py +223 -129
  100. manim/scene/zoomed_scene.py +46 -41
  101. manim/typing.py +990 -0
  102. manim/utils/bezier.py +1823 -371
  103. manim/utils/caching.py +12 -5
  104. manim/utils/color/AS2700.py +236 -0
  105. manim/utils/color/BS381.py +318 -0
  106. manim/utils/color/DVIPSNAMES.py +96 -0
  107. manim/utils/color/SVGNAMES.py +179 -0
  108. manim/utils/color/X11.py +533 -0
  109. manim/utils/color/XKCD.py +952 -0
  110. manim/utils/color/__init__.py +61 -0
  111. manim/utils/color/core.py +1667 -0
  112. manim/utils/color/manim_colors.py +218 -0
  113. manim/utils/commands.py +48 -20
  114. manim/utils/config_ops.py +39 -19
  115. manim/utils/debug.py +8 -7
  116. manim/utils/deprecation.py +86 -39
  117. manim/utils/docbuild/__init__.py +17 -0
  118. manim/utils/docbuild/autoaliasattr_directive.py +236 -0
  119. manim/utils/docbuild/autocolor_directive.py +99 -0
  120. manim/utils/docbuild/manim_directive.py +94 -41
  121. manim/utils/docbuild/module_parsing.py +245 -0
  122. manim/utils/exceptions.py +6 -0
  123. manim/utils/family.py +5 -3
  124. manim/utils/family_ops.py +17 -4
  125. manim/utils/file_ops.py +27 -17
  126. manim/utils/hashing.py +55 -45
  127. manim/utils/images.py +13 -7
  128. manim/utils/ipython_magic.py +13 -7
  129. manim/utils/iterables.py +163 -120
  130. manim/utils/module_ops.py +66 -24
  131. manim/utils/opengl.py +77 -24
  132. manim/utils/parameter_parsing.py +32 -0
  133. manim/utils/paths.py +30 -33
  134. manim/utils/polylabel.py +235 -0
  135. manim/utils/qhull.py +218 -0
  136. manim/utils/rate_functions.py +98 -32
  137. manim/utils/simple_functions.py +25 -33
  138. manim/utils/sounds.py +7 -1
  139. manim/utils/space_ops.py +188 -115
  140. manim/utils/testing/__init__.py +17 -0
  141. manim/utils/testing/_frames_testers.py +13 -8
  142. manim/utils/testing/_show_diff.py +5 -3
  143. manim/utils/testing/_test_class_makers.py +34 -18
  144. manim/utils/testing/frames_comparison.py +37 -19
  145. manim/utils/tex.py +130 -198
  146. manim/utils/tex_file_writing.py +77 -47
  147. manim/utils/tex_templates.py +2 -1
  148. manim/utils/unit.py +6 -5
  149. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/METADATA +64 -65
  150. manim-0.19.1.dist-info/RECORD +220 -0
  151. {manim-0.17.0.dist-info → manim-0.19.1.dist-info}/WHEEL +1 -1
  152. manim-0.19.1.dist-info/entry_points.txt +3 -0
  153. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE.community +1 -1
  154. manim/cli/new/group.py +0 -189
  155. manim/communitycolors.py +0 -9
  156. manim/gui/__init__.py +0 -0
  157. manim/gui/gui.py +0 -82
  158. manim/plugins/import_plugins.py +0 -43
  159. manim/utils/color.py +0 -552
  160. manim-0.17.0.dist-info/RECORD +0 -206
  161. manim-0.17.0.dist-info/entry_points.txt +0 -4
  162. /manim/cli/{new → checkhealth}/__init__.py +0 -0
  163. {manim-0.17.0.dist-info → manim-0.19.1.dist-info/licenses}/LICENSE +0 -0
@@ -16,11 +16,11 @@ __all__ = [
16
16
  "Torus",
17
17
  ]
18
18
 
19
-
20
- from typing import *
19
+ from collections.abc import Callable, Iterable, Sequence
20
+ from typing import TYPE_CHECKING, Any
21
21
 
22
22
  import numpy as np
23
- from colour import Color
23
+ from typing_extensions import Self
24
24
 
25
25
  from manim import config, logger
26
26
  from manim.constants import *
@@ -29,16 +29,26 @@ from manim.mobject.geometry.polygram import Square
29
29
  from manim.mobject.mobject import *
30
30
  from manim.mobject.opengl.opengl_compatibility import ConvertToOpenGL
31
31
  from manim.mobject.opengl.opengl_mobject import OpenGLMobject
32
- from manim.mobject.types.vectorized_mobject import VGroup, VMobject
33
- from manim.utils.color import *
34
- from manim.utils.color import Colors
35
- from manim.utils.deprecation import deprecated_params
32
+ from manim.mobject.types.vectorized_mobject import VectorizedPoint, VGroup, VMobject
33
+ from manim.utils.color import (
34
+ BLUE,
35
+ BLUE_D,
36
+ BLUE_E,
37
+ LIGHT_GREY,
38
+ WHITE,
39
+ ManimColor,
40
+ ParsableManimColor,
41
+ interpolate_color,
42
+ )
36
43
  from manim.utils.iterables import tuplify
37
44
  from manim.utils.space_ops import normalize, perpendicular_bisector, z_to_vector
38
45
 
46
+ if TYPE_CHECKING:
47
+ from manim.typing import Point3D, Point3DLike, Vector3DLike
48
+
39
49
 
40
50
  class ThreeDVMobject(VMobject, metaclass=ConvertToOpenGL):
41
- def __init__(self, shade_in_3d=True, **kwargs):
51
+ def __init__(self, shade_in_3d: bool = True, **kwargs):
42
52
  super().__init__(shade_in_3d=shade_in_3d, **kwargs)
43
53
 
44
54
 
@@ -63,7 +73,7 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
63
73
  The opacity of the :class:`Surface`, from 0 being fully transparent
64
74
  to 1 being fully opaque. Defaults to 1.
65
75
  checkerboard_colors
66
- Colors individual faces alternating colors. Overrides ``fill_color``.
76
+ ng individual faces alternating colors. Overrides ``fill_color``.
67
77
  stroke_color
68
78
  Color of the stroke surrounding each face of :class:`Surface`.
69
79
  stroke_width
@@ -101,36 +111,46 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
101
111
  v_range: Sequence[float] = [0, 1],
102
112
  resolution: Sequence[int] = 32,
103
113
  surface_piece_config: dict = {},
104
- fill_color: Color = BLUE_D,
114
+ fill_color: ParsableManimColor = BLUE_D,
105
115
  fill_opacity: float = 1.0,
106
- checkerboard_colors: Sequence[Color] = [BLUE_D, BLUE_E],
107
- stroke_color: Color = LIGHT_GREY,
116
+ checkerboard_colors: Sequence[ParsableManimColor] | bool = [BLUE_D, BLUE_E],
117
+ stroke_color: ParsableManimColor = LIGHT_GREY,
108
118
  stroke_width: float = 0.5,
109
119
  should_make_jagged: bool = False,
110
120
  pre_function_handle_to_anchor_scale_factor: float = 0.00001,
111
- **kwargs,
121
+ **kwargs: Any,
112
122
  ) -> None:
113
123
  self.u_range = u_range
114
124
  self.v_range = v_range
115
- super().__init__(**kwargs)
125
+ super().__init__(
126
+ fill_color=fill_color,
127
+ fill_opacity=fill_opacity,
128
+ stroke_color=stroke_color,
129
+ stroke_width=stroke_width,
130
+ **kwargs,
131
+ )
116
132
  self.resolution = resolution
117
133
  self.surface_piece_config = surface_piece_config
118
- self.fill_color = fill_color
119
- self.fill_opacity = fill_opacity
120
- self.checkerboard_colors = checkerboard_colors
121
- self.stroke_color = stroke_color
122
- self.stroke_width = stroke_width
134
+ if checkerboard_colors:
135
+ self.checkerboard_colors: list[ManimColor] = [
136
+ ManimColor(x) for x in checkerboard_colors
137
+ ]
138
+ else:
139
+ self.checkerboard_colors = checkerboard_colors
123
140
  self.should_make_jagged = should_make_jagged
124
141
  self.pre_function_handle_to_anchor_scale_factor = (
125
142
  pre_function_handle_to_anchor_scale_factor
126
143
  )
127
- self.func = func
144
+ self._func = func
128
145
  self._setup_in_uv_space()
129
146
  self.apply_function(lambda p: func(p[0], p[1]))
130
147
  if self.should_make_jagged:
131
148
  self.make_jagged()
132
149
 
133
- def _get_u_values_and_v_values(self):
150
+ def func(self, u: float, v: float) -> np.ndarray:
151
+ return self._func(u, v)
152
+
153
+ def _get_u_values_and_v_values(self) -> tuple[np.ndarray, np.ndarray]:
134
154
  res = tuplify(self.resolution)
135
155
  if len(res) == 1:
136
156
  u_res = v_res = res[0]
@@ -142,7 +162,7 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
142
162
 
143
163
  return u_values, v_values
144
164
 
145
- def _setup_in_uv_space(self):
165
+ def _setup_in_uv_space(self) -> None:
146
166
  u_values, v_values = self._get_u_values_and_v_values()
147
167
  faces = VGroup()
148
168
  for i in range(len(u_values) - 1):
@@ -176,7 +196,9 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
176
196
  if self.checkerboard_colors:
177
197
  self.set_fill_by_checkerboard(*self.checkerboard_colors)
178
198
 
179
- def set_fill_by_checkerboard(self, *colors, opacity=None):
199
+ def set_fill_by_checkerboard(
200
+ self, *colors: Iterable[ParsableManimColor], opacity: float | None = None
201
+ ) -> Self:
180
202
  """Sets the fill_color of each face of :class:`Surface` in
181
203
  an alternating pattern.
182
204
 
@@ -199,14 +221,13 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
199
221
  face.set_fill(colors[c_index], opacity=opacity)
200
222
  return self
201
223
 
202
- @deprecated_params("colors", since="v0.16.0")
203
224
  def set_fill_by_value(
204
225
  self,
205
226
  axes: Mobject,
206
- colorscale: Union[Iterable[Color], Color] | None = None,
227
+ colorscale: list[ParsableManimColor] | ParsableManimColor | None = None,
207
228
  axis: int = 2,
208
229
  **kwargs,
209
- ):
230
+ ) -> Self:
210
231
  """Sets the color of each mobject of a parametric surface to a color
211
232
  relative to its axis-value.
212
233
 
@@ -316,7 +337,7 @@ class Surface(VGroup, metaclass=ConvertToOpenGL):
316
337
 
317
338
 
318
339
  class Sphere(Surface):
319
- """An three-dimensional sphere.
340
+ """A three-dimensional sphere.
320
341
 
321
342
  Parameters
322
343
  ----------
@@ -360,17 +381,19 @@ class Sphere(Surface):
360
381
 
361
382
  def __init__(
362
383
  self,
363
- center=ORIGIN,
364
- radius=1,
365
- resolution=None,
366
- u_range=(0, TAU),
367
- v_range=(0, PI),
384
+ center: Point3DLike = ORIGIN,
385
+ radius: float = 1,
386
+ resolution: Sequence[int] | None = None,
387
+ u_range: Sequence[float] = (0, TAU),
388
+ v_range: Sequence[float] = (0, PI),
368
389
  **kwargs,
369
- ):
390
+ ) -> None:
370
391
  if config.renderer == RendererType.OPENGL:
371
392
  res_value = (101, 51)
372
393
  elif config.renderer == RendererType.CAIRO:
373
394
  res_value = (24, 12)
395
+ else:
396
+ raise Exception("Unknown renderer")
374
397
 
375
398
  resolution = resolution if resolution is not None else res_value
376
399
 
@@ -386,7 +409,14 @@ class Sphere(Surface):
386
409
 
387
410
  self.shift(center)
388
411
 
389
- def func(self, u, v):
412
+ def func(self, u: float, v: float) -> np.ndarray:
413
+ """The z values defining the :class:`Sphere` being plotted.
414
+
415
+ Returns
416
+ -------
417
+ :class:`numpy.array`
418
+ The z values defining the :class:`Sphere`.
419
+ """
390
420
  return self.radius * np.array(
391
421
  [np.cos(u) * np.sin(v), np.sin(u) * np.sin(v), -np.cos(v)],
392
422
  )
@@ -428,10 +458,10 @@ class Dot3D(Sphere):
428
458
  self,
429
459
  point: list | np.ndarray = ORIGIN,
430
460
  radius: float = DEFAULT_DOT_RADIUS,
431
- color: Colors = WHITE,
432
- resolution=(8, 8),
461
+ color: ParsableManimColor = WHITE,
462
+ resolution: tuple[int, int] = (8, 8),
433
463
  **kwargs,
434
- ):
464
+ ) -> None:
435
465
  super().__init__(center=point, radius=radius, resolution=resolution, **kwargs)
436
466
  self.set_color(color)
437
467
 
@@ -468,12 +498,12 @@ class Cube(VGroup):
468
498
 
469
499
  def __init__(
470
500
  self,
471
- side_length=2,
472
- fill_opacity=0.75,
473
- fill_color=BLUE,
474
- stroke_width=0,
501
+ side_length: float = 2,
502
+ fill_opacity: float = 0.75,
503
+ fill_color: ParsableManimColor = BLUE,
504
+ stroke_width: float = 0,
475
505
  **kwargs,
476
- ):
506
+ ) -> None:
477
507
  self.side_length = side_length
478
508
  super().__init__(
479
509
  fill_color=fill_color,
@@ -482,11 +512,13 @@ class Cube(VGroup):
482
512
  **kwargs,
483
513
  )
484
514
 
485
- def generate_points(self):
515
+ def generate_points(self) -> None:
516
+ """Creates the sides of the :class:`Cube`."""
486
517
  for vect in IN, OUT, LEFT, RIGHT, UP, DOWN:
487
518
  face = Square(
488
519
  side_length=self.side_length,
489
520
  shade_in_3d=True,
521
+ joint_type=LineJointType.BEVEL,
490
522
  )
491
523
  face.flip()
492
524
  face.shift(self.side_length * OUT / 2.0)
@@ -494,7 +526,8 @@ class Cube(VGroup):
494
526
 
495
527
  self.add(face)
496
528
 
497
- init_points = generate_points
529
+ def init_points(self) -> None:
530
+ self.generate_points()
498
531
 
499
532
 
500
533
  class Prism(Cube):
@@ -520,11 +553,14 @@ class Prism(Cube):
520
553
  self.add(prismSmall, prismLarge)
521
554
  """
522
555
 
523
- def __init__(self, dimensions=[3, 2, 1], **kwargs):
556
+ def __init__(
557
+ self, dimensions: tuple[float, float, float] | np.ndarray = [3, 2, 1], **kwargs
558
+ ) -> None:
524
559
  self.dimensions = dimensions
525
560
  super().__init__(**kwargs)
526
561
 
527
- def generate_points(self):
562
+ def generate_points(self) -> None:
563
+ """Creates the sides of the :class:`Prism`."""
528
564
  super().generate_points()
529
565
  for dim, value in enumerate(self.dimensions):
530
566
  self.rescale_to_fit(value, dim, stretch=True)
@@ -577,8 +613,8 @@ class Cone(Surface):
577
613
  v_range: Sequence[float] = [0, TAU],
578
614
  u_min: float = 0,
579
615
  checkerboard_colors: bool = False,
580
- **kwargs,
581
- ):
616
+ **kwargs: Any,
617
+ ) -> None:
582
618
  self.direction = direction
583
619
  self.theta = PI - np.arctan(base_radius / height)
584
620
 
@@ -590,22 +626,23 @@ class Cone(Surface):
590
626
  **kwargs,
591
627
  )
592
628
  # used for rotations
629
+ self.new_height = height
593
630
  self._current_theta = 0
594
631
  self._current_phi = 0
595
-
632
+ self.base_circle = Circle(
633
+ radius=base_radius,
634
+ color=self.fill_color,
635
+ fill_opacity=self.fill_opacity,
636
+ stroke_width=0,
637
+ )
638
+ self.base_circle.shift(height * IN)
639
+ self._set_start_and_end_attributes(direction)
596
640
  if show_base:
597
- self.base_circle = Circle(
598
- radius=base_radius,
599
- color=self.fill_color,
600
- fill_opacity=self.fill_opacity,
601
- stroke_width=0,
602
- )
603
- self.base_circle.shift(height * IN)
604
641
  self.add(self.base_circle)
605
642
 
606
643
  self._rotate_to_direction()
607
644
 
608
- def func(self, u: float, v: float):
645
+ def func(self, u: float, v: float) -> np.ndarray:
609
646
  """Converts from spherical coordinates to cartesian.
610
647
 
611
648
  Parameters
@@ -614,6 +651,11 @@ class Cone(Surface):
614
651
  The radius.
615
652
  v
616
653
  The azimuthal angle.
654
+
655
+ Returns
656
+ -------
657
+ :class:`numpy.array`
658
+ Points defining the :class:`Cone`.
617
659
  """
618
660
  r = u
619
661
  phi = v
@@ -625,14 +667,17 @@ class Cone(Surface):
625
667
  ],
626
668
  )
627
669
 
628
- def _rotate_to_direction(self):
670
+ def get_start(self) -> np.ndarray:
671
+ return self.start_point.get_center()
672
+
673
+ def get_end(self) -> np.ndarray:
674
+ return self.end_point.get_center()
675
+
676
+ def _rotate_to_direction(self) -> None:
629
677
  x, y, z = self.direction
630
678
 
631
679
  r = np.sqrt(x**2 + y**2 + z**2)
632
- if r > 0:
633
- theta = np.arccos(z / r)
634
- else:
635
- theta = 0
680
+ theta = np.arccos(z / r) if r > 0 else 0
636
681
 
637
682
  if x == 0:
638
683
  if y == 0: # along the z axis
@@ -658,18 +703,18 @@ class Cone(Surface):
658
703
  self._current_theta = theta
659
704
  self._current_phi = phi
660
705
 
661
- def set_direction(self, direction):
706
+ def set_direction(self, direction: np.ndarray) -> None:
662
707
  """Changes the direction of the apex of the :class:`Cone`.
663
708
 
664
709
  Parameters
665
710
  ----------
666
- direction : :class:`numpy.array`
711
+ direction
667
712
  The direction of the apex.
668
713
  """
669
714
  self.direction = direction
670
715
  self._rotate_to_direction()
671
716
 
672
- def get_direction(self):
717
+ def get_direction(self) -> np.ndarray:
673
718
  """Returns the current direction of the apex of the :class:`Cone`.
674
719
 
675
720
  Returns
@@ -679,6 +724,15 @@ class Cone(Surface):
679
724
  """
680
725
  return self.direction
681
726
 
727
+ def _set_start_and_end_attributes(self, direction):
728
+ normalized_direction = direction * np.linalg.norm(direction)
729
+
730
+ start = self.base_circle.get_center()
731
+ end = start + normalized_direction * self.new_height
732
+ self.start_point = VectorizedPoint(start)
733
+ self.end_point = VectorizedPoint(end)
734
+ self.add(self.start_point, self.end_point)
735
+
682
736
 
683
737
  class Cylinder(Surface):
684
738
  """A cylinder, defined by its height, radius and direction,
@@ -719,9 +773,9 @@ class Cylinder(Surface):
719
773
  direction: np.ndarray = Z_AXIS,
720
774
  v_range: Sequence[float] = [0, TAU],
721
775
  show_ends: bool = True,
722
- resolution=(24, 24),
776
+ resolution: Sequence[int] = (24, 24),
723
777
  **kwargs,
724
- ):
778
+ ) -> None:
725
779
  self._height = height
726
780
  self.radius = radius
727
781
  super().__init__(
@@ -737,7 +791,7 @@ class Cylinder(Surface):
737
791
  self._current_theta = 0
738
792
  self.set_direction(direction)
739
793
 
740
- def func(self, u: float, v: float):
794
+ def func(self, u: float, v: float) -> np.ndarray:
741
795
  """Converts from cylindrical coordinates to cartesian.
742
796
 
743
797
  Parameters
@@ -746,13 +800,18 @@ class Cylinder(Surface):
746
800
  The height.
747
801
  v
748
802
  The azimuthal angle.
803
+
804
+ Returns
805
+ -------
806
+ :class:`numpy.ndarray`
807
+ Points defining the :class:`Cylinder`.
749
808
  """
750
809
  height = u
751
810
  phi = v
752
811
  r = self.radius
753
812
  return np.array([r * np.cos(phi), r * np.sin(phi), height])
754
813
 
755
- def add_bases(self):
814
+ def add_bases(self) -> None:
756
815
  """Adds the end caps of the cylinder."""
757
816
  if config.renderer == RendererType.OPENGL:
758
817
  color = self.color
@@ -779,14 +838,11 @@ class Cylinder(Surface):
779
838
  self.base_bottom.shift(self.u_range[0] * IN)
780
839
  self.add(self.base_top, self.base_bottom)
781
840
 
782
- def _rotate_to_direction(self):
841
+ def _rotate_to_direction(self) -> None:
783
842
  x, y, z = self.direction
784
843
 
785
844
  r = np.sqrt(x**2 + y**2 + z**2)
786
- if r > 0:
787
- theta = np.arccos(z / r)
788
- else:
789
- theta = 0
845
+ theta = np.arccos(z / r) if r > 0 else 0
790
846
 
791
847
  if x == 0:
792
848
  if y == 0: # along the z axis
@@ -812,12 +868,12 @@ class Cylinder(Surface):
812
868
  self._current_theta = theta
813
869
  self._current_phi = phi
814
870
 
815
- def set_direction(self, direction):
871
+ def set_direction(self, direction: np.ndarray) -> None:
816
872
  """Sets the direction of the central axis of the :class:`Cylinder`.
817
873
 
818
874
  Parameters
819
875
  ----------
820
- direction
876
+ direction : :class:`numpy.array`
821
877
  The direction of the central axis of the :class:`Cylinder`.
822
878
  """
823
879
  # if get_norm(direction) is get_norm(self.direction):
@@ -825,12 +881,12 @@ class Cylinder(Surface):
825
881
  self.direction = direction
826
882
  self._rotate_to_direction()
827
883
 
828
- def get_direction(self):
884
+ def get_direction(self) -> np.ndarray:
829
885
  """Returns the direction of the central axis of the :class:`Cylinder`.
830
886
 
831
887
  Returns
832
888
  -------
833
- direction
889
+ direction : :class:`numpy.array`
834
890
  The direction of the central axis of the :class:`Cylinder`.
835
891
  """
836
892
  return self.direction
@@ -849,6 +905,12 @@ class Line3D(Cylinder):
849
905
  The thickness of the line.
850
906
  color
851
907
  The color of the line.
908
+ resolution
909
+ The resolution of the line.
910
+ By default this value is the number of points the line will sampled at.
911
+ If you want the line to also come out checkered, use a tuple.
912
+ For example, for a line made of 24 points with 4 checker points on each
913
+ cylinder, pass the tuple (4, 24).
852
914
 
853
915
  Examples
854
916
  --------
@@ -868,15 +930,23 @@ class Line3D(Cylinder):
868
930
  start: np.ndarray = LEFT,
869
931
  end: np.ndarray = RIGHT,
870
932
  thickness: float = 0.02,
871
- color=None,
933
+ color: ParsableManimColor | None = None,
934
+ resolution: int | Sequence[int] = 24,
872
935
  **kwargs,
873
936
  ):
874
937
  self.thickness = thickness
938
+ self.resolution = (2, resolution) if isinstance(resolution, int) else resolution
939
+
940
+ start = np.array(start, dtype=np.float64)
941
+ end = np.array(end, dtype=np.float64)
942
+
875
943
  self.set_start_and_end_attrs(start, end, **kwargs)
876
944
  if color is not None:
877
945
  self.set_color(color)
878
946
 
879
- def set_start_and_end_attrs(self, start, end, **kwargs):
947
+ def set_start_and_end_attrs(
948
+ self, start: np.ndarray, end: np.ndarray, **kwargs
949
+ ) -> None:
880
950
  """Sets the start and end points of the line.
881
951
 
882
952
  If either ``start`` or ``end`` are :class:`Mobjects <.Mobject>`,
@@ -903,11 +973,30 @@ class Line3D(Cylinder):
903
973
  height=np.linalg.norm(self.vect),
904
974
  radius=self.thickness,
905
975
  direction=self.direction,
976
+ resolution=self.resolution,
906
977
  **kwargs,
907
978
  )
908
979
  self.shift((self.start + self.end) / 2)
909
980
 
910
- def pointify(self, mob_or_point, direction=None):
981
+ def pointify(
982
+ self,
983
+ mob_or_point: Mobject | Point3DLike,
984
+ direction: Vector3DLike | None = None,
985
+ ) -> Point3D:
986
+ """Gets a point representing the center of the :class:`Mobjects <.Mobject>`.
987
+
988
+ Parameters
989
+ ----------
990
+ mob_or_point
991
+ :class:`Mobjects <.Mobject>` or point whose center should be returned.
992
+ direction
993
+ If an edge of a :class:`Mobjects <.Mobject>` should be returned, the direction of the edge.
994
+
995
+ Returns
996
+ -------
997
+ :class:`numpy.array`
998
+ Center of the :class:`Mobjects <.Mobject>` or point, or edge if direction is given.
999
+ """
911
1000
  if isinstance(mob_or_point, (Mobject, OpenGLMobject)):
912
1001
  mob = mob_or_point
913
1002
  if direction is None:
@@ -916,7 +1005,7 @@ class Line3D(Cylinder):
916
1005
  return mob.get_boundary_point(direction)
917
1006
  return np.array(mob_or_point)
918
1007
 
919
- def get_start(self):
1008
+ def get_start(self) -> np.ndarray:
920
1009
  """Returns the starting point of the :class:`Line3D`.
921
1010
 
922
1011
  Returns
@@ -926,7 +1015,7 @@ class Line3D(Cylinder):
926
1015
  """
927
1016
  return self.start
928
1017
 
929
- def get_end(self):
1018
+ def get_end(self) -> np.ndarray:
930
1019
  """Returns the ending point of the :class:`Line3D`.
931
1020
 
932
1021
  Returns
@@ -938,8 +1027,12 @@ class Line3D(Cylinder):
938
1027
 
939
1028
  @classmethod
940
1029
  def parallel_to(
941
- cls, line: Line3D, point: Sequence[float] = ORIGIN, length: float = 5, **kwargs
942
- ):
1030
+ cls,
1031
+ line: Line3D,
1032
+ point: Point3DLike = ORIGIN,
1033
+ length: float = 5,
1034
+ **kwargs,
1035
+ ) -> Line3D:
943
1036
  """Returns a line parallel to another line going through
944
1037
  a given point.
945
1038
 
@@ -949,9 +1042,16 @@ class Line3D(Cylinder):
949
1042
  The line to be parallel to.
950
1043
  point
951
1044
  The point to pass through.
1045
+ length
1046
+ Length of the parallel line.
952
1047
  kwargs
953
1048
  Additional parameters to be passed to the class.
954
1049
 
1050
+ Returns
1051
+ -------
1052
+ :class:`Line3D`
1053
+ Line parallel to ``line``.
1054
+
955
1055
  Examples
956
1056
  --------
957
1057
  .. manim:: ParallelLineExample
@@ -965,18 +1065,22 @@ class Line3D(Cylinder):
965
1065
  line2 = Line3D.parallel_to(line1, color=YELLOW)
966
1066
  self.add(ax, line1, line2)
967
1067
  """
968
- point = np.array(point)
1068
+ np_point = np.asarray(point)
969
1069
  vect = normalize(line.vect)
970
1070
  return cls(
971
- point + vect * length / 2,
972
- point - vect * length / 2,
1071
+ np_point + vect * length / 2,
1072
+ np_point - vect * length / 2,
973
1073
  **kwargs,
974
1074
  )
975
1075
 
976
1076
  @classmethod
977
1077
  def perpendicular_to(
978
- cls, line: Line3D, point: Sequence[float] = ORIGIN, length: float = 5, **kwargs
979
- ):
1078
+ cls,
1079
+ line: Line3D,
1080
+ point: Vector3DLike = ORIGIN,
1081
+ length: float = 5,
1082
+ **kwargs,
1083
+ ) -> Line3D:
980
1084
  """Returns a line perpendicular to another line going through
981
1085
  a given point.
982
1086
 
@@ -986,9 +1090,16 @@ class Line3D(Cylinder):
986
1090
  The line to be perpendicular to.
987
1091
  point
988
1092
  The point to pass through.
1093
+ length
1094
+ Length of the perpendicular line.
989
1095
  kwargs
990
1096
  Additional parameters to be passed to the class.
991
1097
 
1098
+ Returns
1099
+ -------
1100
+ :class:`Line3D`
1101
+ Line perpendicular to ``line``.
1102
+
992
1103
  Examples
993
1104
  --------
994
1105
  .. manim:: PerpLineExample
@@ -1002,17 +1113,17 @@ class Line3D(Cylinder):
1002
1113
  line2 = Line3D.perpendicular_to(line1, color=BLUE)
1003
1114
  self.add(ax, line1, line2)
1004
1115
  """
1005
- point = np.array(point)
1116
+ np_point = np.asarray(point)
1006
1117
 
1007
- norm = np.cross(line.vect, point - line.start)
1118
+ norm = np.cross(line.vect, np_point - line.start)
1008
1119
  if all(np.linalg.norm(norm) == np.zeros(3)):
1009
1120
  raise ValueError("Could not find the perpendicular.")
1010
1121
 
1011
1122
  start, end = perpendicular_bisector([line.start, line.end], norm)
1012
1123
  vect = normalize(end - start)
1013
1124
  return cls(
1014
- point + vect * length / 2,
1015
- point - vect * length / 2,
1125
+ np_point + vect * length / 2,
1126
+ np_point - vect * length / 2,
1016
1127
  **kwargs,
1017
1128
  )
1018
1129
 
@@ -1034,6 +1145,8 @@ class Arrow3D(Line3D):
1034
1145
  The base radius of the conical tip.
1035
1146
  color
1036
1147
  The color of the arrow.
1148
+ resolution
1149
+ The resolution of the arrow line.
1037
1150
 
1038
1151
  Examples
1039
1152
  --------
@@ -1059,11 +1172,17 @@ class Arrow3D(Line3D):
1059
1172
  thickness: float = 0.02,
1060
1173
  height: float = 0.3,
1061
1174
  base_radius: float = 0.08,
1062
- color=WHITE,
1175
+ color: ParsableManimColor = WHITE,
1176
+ resolution: int | Sequence[int] = 24,
1063
1177
  **kwargs,
1064
- ):
1178
+ ) -> None:
1065
1179
  super().__init__(
1066
- start=start, end=end, thickness=thickness, color=color, **kwargs
1180
+ start=start,
1181
+ end=end,
1182
+ thickness=thickness,
1183
+ color=color,
1184
+ resolution=resolution,
1185
+ **kwargs,
1067
1186
  )
1068
1187
 
1069
1188
  self.length = np.linalg.norm(self.vect)
@@ -1072,14 +1191,21 @@ class Arrow3D(Line3D):
1072
1191
  self.end - height * self.direction,
1073
1192
  **kwargs,
1074
1193
  )
1075
-
1076
1194
  self.cone = Cone(
1077
- direction=self.direction, base_radius=base_radius, height=height, **kwargs
1195
+ direction=self.direction,
1196
+ base_radius=base_radius,
1197
+ height=height,
1198
+ **kwargs,
1078
1199
  )
1079
- self.cone.shift(end)
1080
- self.add(self.cone)
1200
+ np_end = np.asarray(end, dtype=np.float64)
1201
+ self.cone.shift(np_end)
1202
+ self.end_point = VectorizedPoint(np_end)
1203
+ self.add(self.end_point, self.cone)
1081
1204
  self.set_color(color)
1082
1205
 
1206
+ def get_end(self) -> np.ndarray:
1207
+ return self.end_point.get_center()
1208
+
1083
1209
 
1084
1210
  class Torus(Surface):
1085
1211
  """A torus.
@@ -1115,11 +1241,11 @@ class Torus(Surface):
1115
1241
  self,
1116
1242
  major_radius: float = 3,
1117
1243
  minor_radius: float = 1,
1118
- u_range=(0, TAU),
1119
- v_range=(0, TAU),
1120
- resolution=None,
1244
+ u_range: Sequence[float] = (0, TAU),
1245
+ v_range: Sequence[float] = (0, TAU),
1246
+ resolution: tuple[int, int] | None = None,
1121
1247
  **kwargs,
1122
- ):
1248
+ ) -> None:
1123
1249
  if config.renderer == RendererType.OPENGL:
1124
1250
  res_value = (101, 101)
1125
1251
  elif config.renderer == RendererType.CAIRO:
@@ -1137,6 +1263,13 @@ class Torus(Surface):
1137
1263
  **kwargs,
1138
1264
  )
1139
1265
 
1140
- def func(self, u, v):
1266
+ def func(self, u: float, v: float) -> np.ndarray:
1267
+ """The z values defining the :class:`Torus` being plotted.
1268
+
1269
+ Returns
1270
+ -------
1271
+ :class:`numpy.ndarray`
1272
+ The z values defining the :class:`Torus`.
1273
+ """
1141
1274
  P = np.array([np.cos(u), np.sin(u), 0])
1142
1275
  return (self.R - self.r * np.cos(v)) * P - self.r * np.sin(v) * OUT