shape_matchers.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. from __future__ import annotations
  2. from colour import Color
  3. from manimlib.constants import BLACK, RED, YELLOW, WHITE
  4. from manimlib.constants import DL, DOWN, DR, LEFT, RIGHT, UL, UR
  5. from manimlib.constants import SMALL_BUFF
  6. from manimlib.mobject.geometry import Line
  7. from manimlib.mobject.geometry import Rectangle
  8. from manimlib.mobject.types.vectorized_mobject import VGroup
  9. from manimlib.mobject.types.vectorized_mobject import VMobject
  10. from manimlib.utils.customization import get_customization
  11. from typing import TYPE_CHECKING
  12. if TYPE_CHECKING:
  13. from typing import Sequence
  14. from manimlib.mobject.mobject import Mobject
  15. from manimlib.typing import ManimColor, Self
  16. class SurroundingRectangle(Rectangle):
  17. def __init__(
  18. self,
  19. mobject: Mobject,
  20. buff: float = SMALL_BUFF,
  21. color: ManimColor = YELLOW,
  22. **kwargs
  23. ):
  24. super().__init__(color=color, **kwargs)
  25. self.buff = buff
  26. self.surround(mobject)
  27. if mobject.is_fixed_in_frame():
  28. self.fix_in_frame()
  29. def surround(self, mobject, buff=None) -> Self:
  30. self.mobject = mobject
  31. self.buff = buff if buff is not None else self.buff
  32. super().surround(mobject, self.buff)
  33. return self
  34. def set_buff(self, buff) -> Self:
  35. self.buff = buff
  36. self.surround(self.mobject)
  37. return self
  38. class BackgroundRectangle(SurroundingRectangle):
  39. def __init__(
  40. self,
  41. mobject: Mobject,
  42. color: ManimColor = None,
  43. stroke_width: float = 0,
  44. stroke_opacity: float = 0,
  45. fill_opacity: float = 0.75,
  46. buff: float = 0,
  47. **kwargs
  48. ):
  49. if color is None:
  50. color = get_customization()['style']['background_color']
  51. super().__init__(
  52. mobject,
  53. color=color,
  54. stroke_width=stroke_width,
  55. stroke_opacity=stroke_opacity,
  56. fill_opacity=fill_opacity,
  57. buff=buff,
  58. **kwargs
  59. )
  60. self.original_fill_opacity = fill_opacity
  61. def pointwise_become_partial(self, mobject: Mobject, a: float, b: float) -> Self:
  62. self.set_fill(opacity=b * self.original_fill_opacity)
  63. return self
  64. def set_style(
  65. self,
  66. stroke_color: ManimColor | None = None,
  67. stroke_width: float | None = None,
  68. fill_color: ManimColor | None = None,
  69. fill_opacity: float | None = None,
  70. family: bool = True
  71. ) -> Self:
  72. # Unchangeable style, except for fill_opacity
  73. VMobject.set_style(
  74. self,
  75. stroke_color=BLACK,
  76. stroke_width=0,
  77. fill_color=BLACK,
  78. fill_opacity=fill_opacity
  79. )
  80. return self
  81. def get_fill_color(self) -> Color:
  82. return Color(self.color)
  83. class Cross(VGroup):
  84. def __init__(
  85. self,
  86. mobject: Mobject,
  87. stroke_color: ManimColor = RED,
  88. stroke_width: float | Sequence[float] = [0, 6, 0],
  89. **kwargs
  90. ):
  91. super().__init__(
  92. Line(UL, DR),
  93. Line(UR, DL),
  94. )
  95. self.insert_n_curves(20)
  96. self.replace(mobject, stretch=True)
  97. self.set_stroke(stroke_color, width=stroke_width)
  98. class Underline(Line):
  99. def __init__(
  100. self,
  101. mobject: Mobject,
  102. buff: float = SMALL_BUFF,
  103. stroke_color=WHITE,
  104. stroke_width: float | Sequence[float] = [0, 3, 3, 0],
  105. stretch_factor=1.2,
  106. **kwargs
  107. ):
  108. super().__init__(LEFT, RIGHT, **kwargs)
  109. if not isinstance(stroke_width, (float, int)):
  110. self.insert_n_curves(len(stroke_width) - 2)
  111. self.set_stroke(stroke_color, stroke_width)
  112. self.set_width(mobject.get_width() * stretch_factor)
  113. self.next_to(mobject, DOWN, buff=buff)