Skip to content
Open
211 changes: 208 additions & 3 deletions manim/mobject/geometry/tips.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,14 @@
"ArrowTriangleTip",
"ArrowTriangleFilledTip",
"StealthTip",
"CurvedTip1",
"CurvedTip2",
"CurvedTip3",
"TriangleTip1",
"TriangleTip2",
]

import warnings
from typing import TYPE_CHECKING, Any

import numpy as np
Expand Down Expand Up @@ -217,7 +223,16 @@ def __init__(
start_angle: float = PI,
**kwargs: Any,
):
self.start_angle = start_angle
if start_angle != PI:
warnings.warn(
(
"start_angle is deprecated for StealthTip "
"and has no effect. It will be removed in "
"a future version of Manim Community ."
),
DeprecationWarning,
stacklevel=2,
)
VMobject.__init__(
self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
)
Expand Down Expand Up @@ -293,7 +308,16 @@ def __init__(
start_angle: float = PI,
**kwargs: Any,
) -> None:
self.start_angle = start_angle
if start_angle != PI:
warnings.warn(
(
"start_angle is deprecated for ArrowCircleTip "
"and has no effect. It will be removed in "
"a future version of Manim Community ."
),
DeprecationWarning,
stacklevel=2,
)
Circle.__init__(
self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
)
Expand Down Expand Up @@ -321,7 +345,16 @@ def __init__(
start_angle: float = PI,
**kwargs: Any,
) -> None:
self.start_angle = start_angle
if start_angle != PI:
warnings.warn(
(
"start_angle is deprecated for ArrowSquareTip "
"and has no effect. It will be removed in "
"a future version of Manim Community ."
),
DeprecationWarning,
stacklevel=2,
)
Square.__init__(
self,
fill_opacity=fill_opacity,
Expand All @@ -340,3 +373,175 @@ def __init__(
self, fill_opacity: float = 1, stroke_width: float = 0, **kwargs: Any
) -> None:
super().__init__(fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs)


class CurvedTip1(ArrowTip):
"""Inward curved arrow shape."""

def __init__(
self,
fill_opacity: float = 1,
stroke_width: float = 3,
length: float = DEFAULT_ARROW_TIP_LENGTH / 2,
**kwargs: Any,
):
VMobject.__init__(
self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
)
tip = np.array([1.5, 0, 0])
top = np.array([0, 0.7, 0])
bottom = np.array([0, -0.7, 0])
sag = 0.1

self.start_new_path(tip)

self.add_cubic_bezier_curve_to(
tip + (top - tip) / 3 + np.array([0, -sag, 0]),
tip + (top - tip) * 2 / 3 + np.array([0, -sag, 0]),
top,
)

self.add_line_to(bottom)

self.add_cubic_bezier_curve_to(
bottom + (tip - bottom) / 3 + np.array([0, sag, 0]),
bottom + (tip - bottom) * 2 / 3 + np.array([0, sag, 0]),
tip,
)

self.scale(length / (1.3 * self.length))


class CurvedTip2(ArrowTip):
"""Outward curved arrow shape."""

def __init__(
self,
fill_opacity: float = 1,
stroke_width: float = 3,
length: float = DEFAULT_ARROW_TIP_LENGTH / 2,
**kwargs: Any,
):
VMobject.__init__(
self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
)
tip = np.array([1.5, 0, 0])
top = np.array([0, 0.7, 0])
bottom = np.array([0, -0.7, 0])
sag = 0.1

self.start_new_path(tip)

self.add_cubic_bezier_curve_to(
tip + (top - tip) / 3 + np.array([0, sag, 0]),
tip + (top - tip) * 2 / 3 + np.array([0, sag, 0]),
top,
)

self.add_line_to(bottom)

self.add_cubic_bezier_curve_to(
bottom + (tip - bottom) / 3 + np.array([0, -sag, 0]),
bottom + (tip - bottom) * 2 / 3 + np.array([0, -sag, 0]),
tip,
)

self.scale(length / (1.3 * self.length))


class CurvedTip3(ArrowTip):
"""Curved arrow shape."""

def __init__(
self,
fill_opacity: float = 1,
stroke_width: float = 3,
length: float = DEFAULT_ARROW_TIP_LENGTH / 2,
**kwargs: Any,
):
VMobject.__init__(
self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
)
tip = np.array([2.0, 0.00, 0])

self.start_new_path(tip)

self.add_cubic_bezier_curve_to(
np.array([1, 0.75, 0]),
np.array([0, 0.95, 0]),
np.array([-1.0, 1.0, 0]),
)

self.add_cubic_bezier_curve_to(
np.array([-0.65, 0.77, 0]),
np.array([-0.25, 0.4, 0]),
[0, 0, 0],
)

self.add_cubic_bezier_curve_to(
np.array([-0.25, -0.4, 0]),
np.array([-0.65, -0.77, 0]),
np.array([-1.0, -1.0, 0]),
)
self.add_cubic_bezier_curve_to(
np.array([0, -0.95, 0]),
np.array([1, -0.75, 0]),
tip,
)
self.scale(length / (1.5 * self.length))


class TriangleTip1(ArrowTip):
"""Elongated triangle arrow shape."""

def __init__(
self,
fill_opacity: float = 1,
stroke_width: float = 3,
length: float = DEFAULT_ARROW_TIP_LENGTH / 2,
**kwargs: Any,
):
VMobject.__init__(
self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
)
tip = np.array([2.0, 0, 0])

self.start_new_path(tip)

self.add_points_as_corners(
[
np.array([0, 0.6, 0]),
np.array([0, -0.6, 0]),
np.array([2.0, 0.0, 0]),
]
)
self.scale(length / self.length)


class TriangleTip2(ArrowTip):
"""Modified triangle arrow shape."""

def __init__(
self,
fill_opacity: float = 1,
stroke_width: float = 3,
length: float = DEFAULT_ARROW_TIP_LENGTH / 2,
**kwargs: Any,
):
VMobject.__init__(
self, fill_opacity=fill_opacity, stroke_width=stroke_width, **kwargs
)
tip = np.array([3.0, 0.0, 0])

self.start_new_path(tip)

self.add_points_as_corners(
[
np.array([0.5, 1, 0]),
np.array([0, 0.25, 0]),
np.array([0, -0.25, 0]),
np.array([0.5, -1, 0]),
np.array([3.0, 0.0, 0]),
]
)
self.scale(length / self.length)
Loading