@@ -40,6 +40,7 @@ def construct(self):
4040 "CubicBezier" ,
4141 "ArcPolygon" ,
4242 "ArcPolygonFromArcs" ,
43+ "TangentialArc" ,
4344]
4445
4546import itertools
@@ -55,6 +56,7 @@ def construct(self):
5556from manim .utils .color import BLACK , BLUE , RED , WHITE , ParsableManimColor
5657from manim .utils .iterables import adjacent_pairs
5758from 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+
499567class CurvedArrow (ArcBetweenPoints ):
500568 def __init__ (
501569 self , start_point : Point3DLike , end_point : Point3DLike , ** kwargs : Any
0 commit comments