Skip to content

Commit afa4692

Browse files
Add implementation for tangential arc (#4469)
* Add implementation for tangential arc * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add example * Improve doc slightly * Remove corner type * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add test for TangentialArc * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Import Line only if type checking * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add missing type hint * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add test for tangential arc * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 038d16b commit afa4692

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

manim/mobject/geometry/arc.py

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def construct(self):
4040
"CubicBezier",
4141
"ArcPolygon",
4242
"ArcPolygonFromArcs",
43+
"TangentialArc",
4344
]
4445

4546
import itertools
@@ -55,6 +56,7 @@ def construct(self):
5556
from manim.utils.color import BLACK, BLUE, RED, WHITE, ParsableManimColor
5657
from manim.utils.iterables import adjacent_pairs
5758
from manim.utils.space_ops import (
59+
angle_between_vectors,
5860
angle_of_vector,
5961
cartesian_to_spherical,
6062
line_intersection,
@@ -66,6 +68,7 @@ def construct(self):
6668
from collections.abc import Iterable
6769

6870
import manim.mobject.geometry.tips as tips
71+
from manim.mobject.geometry.line import Line
6972
from manim.mobject.mobject import Mobject
7073
from manim.mobject.text.tex_mobject import SingleStringMathTex, Tex
7174
from manim.mobject.text.text_mobject import Text
@@ -496,6 +499,71 @@ def __init__(
496499
self.radius = np.inf
497500

498501

502+
class TangentialArc(ArcBetweenPoints):
503+
"""
504+
Construct an arc that is tangent to two intersecting lines.
505+
You can choose any of the 4 possible corner arcs via the `corner` tuple.
506+
corner = (s1, s2) where each si is ±1 to control direction along each line.
507+
508+
Example
509+
-------
510+
.. manim:: TangentialArcExample
511+
512+
class TangentialArcExample(Scene):
513+
def construct(self):
514+
line1 = DashedLine(start=3 * LEFT, end=3 * RIGHT)
515+
line1.rotate(angle=31 * DEGREES, about_point=ORIGIN)
516+
line2 = DashedLine(start=3 * UP, end=3 * DOWN)
517+
line2.rotate(angle=12 * DEGREES, about_point=ORIGIN)
518+
519+
arc = TangentialArc(line1, line2, radius=2.25, corner=(1, 1), color=TEAL)
520+
self.add(arc, line1, line2)
521+
"""
522+
523+
def __init__(
524+
self,
525+
line1: Line,
526+
line2: Line,
527+
radius: float,
528+
corner: Any = (1, 1),
529+
**kwargs: Any,
530+
):
531+
self.line1 = line1
532+
self.line2 = line2
533+
534+
intersection_point = line_intersection(
535+
[line1.get_start(), line1.get_end()], [line2.get_start(), line2.get_end()]
536+
)
537+
538+
s1, s2 = corner
539+
# Get unit vector for specified directions
540+
unit_vector1 = s1 * line1.get_unit_vector()
541+
unit_vector2 = s2 * line2.get_unit_vector()
542+
543+
corner_angle = angle_between_vectors(unit_vector1, unit_vector2)
544+
tangent_point_distance = radius / np.tan(corner_angle / 2)
545+
546+
# tangent points
547+
tangent_point1 = intersection_point + tangent_point_distance * unit_vector1
548+
tangent_point2 = intersection_point + tangent_point_distance * unit_vector2
549+
550+
cross_product = (
551+
unit_vector1[0] * unit_vector2[1] - unit_vector1[1] * unit_vector2[0]
552+
)
553+
554+
# Determine start and end points based on orientation
555+
if cross_product < 0:
556+
# Counterclockwise orientation - standard order
557+
start_point = tangent_point1
558+
end_point = tangent_point2
559+
else:
560+
# Clockwise orientation - reverse the points
561+
start_point = tangent_point2
562+
end_point = tangent_point1
563+
564+
super().__init__(start=start_point, end=end_point, radius=radius, **kwargs)
565+
566+
499567
class CurvedArrow(ArcBetweenPoints):
500568
def __init__(
501569
self, start_point: Point3DLike, end_point: Point3DLike, **kwargs: Any

tests/module/mobject/geometry/test_unit_geometry.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,19 @@
66

77
from manim import (
88
DEGREES,
9+
DOWN,
910
LEFT,
11+
ORIGIN,
1012
RIGHT,
13+
UP,
1114
BackgroundRectangle,
1215
Circle,
1316
Line,
1417
Polygram,
1518
Sector,
1619
Square,
1720
SurroundingRectangle,
21+
TangentialArc,
1822
)
1923

2024
logger = logging.getLogger(__name__)
@@ -116,6 +120,14 @@ def test_SurroundingRectangle():
116120
assert sr.get_fill_opacity() == 0.42
117121

118122

123+
def test_TangentialArc():
124+
l1 = Line(start=LEFT, end=RIGHT)
125+
l2 = Line(start=DOWN, end=UP)
126+
l2.rotate(angle=45 * DEGREES, about_point=ORIGIN)
127+
arc = TangentialArc(l1, l2, radius=1.0)
128+
assert arc.radius == 1.0
129+
130+
119131
def test_SurroundingRectangle_buff():
120132
sq = Square()
121133
rect1 = SurroundingRectangle(sq, buff=1)

0 commit comments

Comments
 (0)