Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 93 additions & 21 deletions manim/mobject/geometry/labeled.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

__all__ = ["Label", "LabeledLine", "LabeledArrow", "LabeledPolygram"]

from typing import TYPE_CHECKING, Any
from typing import TYPE_CHECKING, Any, Self

import numpy as np

Expand All @@ -20,6 +20,7 @@
from manim.mobject.types.vectorized_mobject import VGroup
from manim.utils.color import WHITE
from manim.utils.polylabel import polylabel
from manim.utils.space_ops import rotate_vector

if TYPE_CHECKING:
from manim.typing import Point3DLike_Array
Expand Down Expand Up @@ -102,13 +103,8 @@ def __init__(
else:
raise TypeError("Unsupported label type. Must be MathTex, Tex, or Text.")

# Add a background box
self.background_rect = BackgroundRectangle(self.rendered_label, **box_config)

# Add a frame around the label
self.frame = SurroundingRectangle(self.rendered_label, **frame_config)

# Add components to the VGroup
self.add(self.background_rect, self.rendered_label, self.frame)


Expand All @@ -128,8 +124,20 @@ class LabeledLine(Line):
A dictionary containing the configuration for the background box.
frame_config
A dictionary containing the configuration for the frame.

.. seealso::
align_label_with_line
If set to `True`, the label is aligned with the line.
label_above_line
If set to `True`, the label is above the line. For this to work,
the parameter `align_label_with_line` must also be set to True.
label_below_line
If set to `True`, the label is below the line. For this to work,
the parameter `align_label_with_line` must also be set to True.
The parameters `label_above_line` and `label_below_line` cannot both be
`True` at the same time.
buff
Buffer space between label and line.

.. seealso::
:class:`LabeledArrow`

Examples
Expand All @@ -141,15 +149,21 @@ class LabeledLine(Line):
class LabeledLineExample(Scene):
def construct(self):
line = LabeledLine(
color= BLUE,
label = '0.5',
label_position = 0.8,
label_position = 0.5,
label_config = {
"font_size" : 20
"font_size" : 45,
"stroke_color" : RED
},
start=LEFT+DOWN,
end=RIGHT+UP)
end=RIGHT+UP,
align_label_with_line=True,
label_above_line=False,
label_below_line=True,
)

line.set_length(line.get_length() * 2)
line.set_length(line.get_length()*2)
self.add(line)
"""

Expand All @@ -160,26 +174,63 @@ def __init__(
label_config: dict[str, Any] | None = None,
box_config: dict[str, Any] | None = None,
frame_config: dict[str, Any] | None = None,
align_label_with_line: bool = False,
label_above_line: bool = False,
label_below_line: bool = False,
buff: float = MED_SMALL_BUFF,
*args: Any,
**kwargs: Any,
) -> None:
if label_above_line and label_below_line:
raise ValueError(
"label_above_line and label_below_line cannot both be True."
)

super().__init__(*args, **kwargs)
self.label_position = label_position
self.align_label_with_line = align_label_with_line
self.label_above_line = label_above_line
self.label_below_line = label_below_line
self.buff = buff
self.label_angle: float = 0

# Create Label
self.label = Label(
label=label,
label_config=label_config,
box_config=box_config,
frame_config=frame_config,
)
self.position_label()
self.add(self.label)

# Compute Label Position
line_start, line_end = self.get_start_and_end()
new_vec = (line_end - line_start) * label_position
label_coords = line_start + new_vec
def position_label(self) -> None:
normal_unit_vector = rotate_vector(self.get_unit_vector(), TAU / 4)
label_position = np.clip(self.label_position, 0, 1)
label_position_on_line = self.point_from_proportion(label_position)

self.label.move_to(label_coords)
self.add(self.label)
if self.align_label_with_line:
current_angle = self.get_angle()
delta = current_angle - self.label_angle
self.label.rotate(delta, about_point=ORIGIN)
self.label_angle = current_angle

if self.label_above_line:
label_position_on_line += normal_unit_vector * self.buff
elif self.label_below_line:
label_position_on_line -= normal_unit_vector * self.buff
self.label.move_to(label_position_on_line)

def scale(
self,
scale_factor: float = 1,
*args: Any,
**kwargs: Any,
) -> Self:
super().scale(scale_factor, *args, **kwargs)
if hasattr(self, "label"):
self.label.scale(1 / scale_factor)
self.position_label()
return self


class LabeledArrow(LabeledLine, Arrow):
Expand Down Expand Up @@ -211,8 +262,21 @@ class LabeledArrow(LabeledLine, Arrow):

class LabeledArrowExample(Scene):
def construct(self):
l_arrow = LabeledArrow("0.5", start=LEFT*3, end=RIGHT*3 + UP*2, label_position=0.5)

l_arrow = LabeledArrow(
"0.5",
color = YELLOW,
start=LEFT*1.5+ 1.5*DOWN,
end=RIGHT*1.5 + UP*1.5,
label_config = {
#"font_size" : 20,
"stroke_color" : RED
},
label_position=0.5,
align_label_with_line=True,
label_above_line=False,
label_below_line = True,
)
l_arrow.set_length(l_arrow.get_length() * 1.2)
self.add(l_arrow)
"""

Expand All @@ -223,6 +287,14 @@ def __init__(
) -> None:
super().__init__(*args, **kwargs)

def scale( # type: ignore[override]
self,
scale_factor: float = 1,
*args: Any,
**kwargs: Any,
) -> Self:
return super().scale(scale_factor, *args, **kwargs)


class LabeledPolygram(Polygram):
"""Constructs a polygram containing a label box at its pole of inaccessibility.
Expand Down
Binary file not shown.
Loading