@@ -54,6 +54,8 @@ def construct(self):
54
54
"Square" ,
55
55
"RoundedRectangle" ,
56
56
"Cutout" ,
57
+ "Angle" ,
58
+ "RightAngle" ,
57
59
]
58
60
59
61
import warnings
@@ -1557,3 +1559,243 @@ def __init__(self, main_shape, *mobjects, **kwargs):
1557
1559
sub_direction = "CW"
1558
1560
for mobject in mobjects :
1559
1561
self .append_points (mobject .force_direction (sub_direction ).get_points ())
1562
+
1563
+
1564
+ class Angle (Arc , Elbow ):
1565
+ """A circular arc or elbow-type mobject representing an angle of two lines.
1566
+
1567
+ Parameters
1568
+ ----------
1569
+ line1 : :class:`Line`
1570
+ The first line.
1571
+ line2 : :class:`Line`
1572
+ The second line.
1573
+ radius : :class:`float`
1574
+ The radius of the :class:`Arc`.
1575
+ quadrant : Sequence[:class:`int`]
1576
+ A sequence of two :class:`int` numbers determining which of the 4 quadrants should be used.
1577
+ The first value indicates whether to anchor the arc on the first line closer to the end point (1)
1578
+ or start point (-1), and the second value functions similarly for the end (1) or start (-1) of the second line.
1579
+ Possibilities: (1,1), (-1,1), (1,-1), (-1,-1).
1580
+ other_angle : :class:`bool`
1581
+ Toggles between the two possible angles defined by two points and an arc center. If set to
1582
+ False (default), the arc will always go counterclockwise from the point on line1 until
1583
+ the point on line2 is reached. If set to True, the angle will go clockwise from line1 to line2.
1584
+ dot : :class:`bool`
1585
+ Allows for a :class:`Dot` in the arc. Mainly used as an convention to indicate a right angle.
1586
+ The dot can be customized in the next three parameters.
1587
+ dot_radius : :class:`float`
1588
+ The radius of the :class:`Dot`. If not specified otherwise, this radius will be 1/10 of the arc radius.
1589
+ dot_distance : :class:`float`
1590
+ Relative distance from the center to the arc: 0 puts the dot in the center and 1 on the arc itself.
1591
+ dot_color : :class:`~.Colors`
1592
+ The color of the :class:`Dot`.
1593
+ elbow : :class:`bool`
1594
+ Produces an elbow-type mobject indicating a right angle, see :class:`RightAngle` for more information
1595
+ and a shorthand.
1596
+ **kwargs
1597
+ Further keyword arguments that are passed to the constructor of :class:`Arc` or :class:`Elbow`.
1598
+
1599
+ Examples
1600
+ --------
1601
+ The first example shows some right angles with a dot in the middle while the second example shows
1602
+ all 8 possible angles defined by two lines.
1603
+
1604
+ .. manim:: RightArcAngleExample
1605
+ :save_last_frame:
1606
+
1607
+ class RightArcAngleExample(Scene):
1608
+ def construct(self):
1609
+ line1 = Line( LEFT, RIGHT )
1610
+ line2 = Line( DOWN, UP )
1611
+ rightarcangles = [
1612
+ Angle(line1, line2, dot=True),
1613
+ Angle(line1, line2, radius=0.4, quadrant=(1,-1), dot=True, other_angle=True),
1614
+ Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8, dot=True, dot_color=YELLOW, dot_radius=0.04, other_angle=True),
1615
+ Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, dot=True, dot_color=GREEN, dot_radius=0.08),
1616
+ ]
1617
+ line_list = VGroup( *[VGroup() for k in range(4)] )
1618
+ for k in range(4):
1619
+ linea = line1.copy()
1620
+ lineb = line2.copy()
1621
+ line_list[k].add( linea )
1622
+ line_list[k].add( lineb )
1623
+ line_list[k].add( rightarcangles[k] )
1624
+ line_list.arrange_in_grid(buff=1.5)
1625
+ self.add(
1626
+ line_list
1627
+ )
1628
+
1629
+ .. manim:: AngleExample
1630
+ :save_last_frame:
1631
+
1632
+ class AngleExample(Scene):
1633
+ def construct(self):
1634
+ line1 = Line( LEFT + (1/3) * UP, RIGHT + (1/3) * DOWN )
1635
+ line2 = Line( DOWN + (1/3) * RIGHT, UP + (1/3) * LEFT )
1636
+ angles = [
1637
+ Angle(line1, line2),
1638
+ Angle(line1, line2, radius=0.4, quadrant=(1,-1), other_angle=True),
1639
+ Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8, other_angle=True),
1640
+ Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED),
1641
+ Angle(line1, line2, other_angle=True),
1642
+ Angle(line1, line2, radius=0.4, quadrant=(1,-1)),
1643
+ Angle(line1, line2, radius=0.5, quadrant=(-1,1), stroke_width=8),
1644
+ Angle(line1, line2, radius=0.7, quadrant=(-1,-1), color=RED, other_angle=True),
1645
+ ]
1646
+ line_list = VGroup( *[VGroup() for k in range(8)] )
1647
+ for k in range(8):
1648
+ linea = line1.copy()
1649
+ lineb = line2.copy()
1650
+ line_list[k].add( linea )
1651
+ line_list[k].add( lineb )
1652
+ line_list[k].add( angles[k] )
1653
+ line_list.arrange_in_grid(n_rows=2, n_cols=4, buff=1.5)
1654
+ self.add(
1655
+ line_list
1656
+ )
1657
+
1658
+ """
1659
+
1660
+ def __init__ (
1661
+ self ,
1662
+ line1 ,
1663
+ line2 ,
1664
+ radius = None ,
1665
+ quadrant = (1 , 1 ),
1666
+ other_angle = False ,
1667
+ dot = False ,
1668
+ dot_radius = None ,
1669
+ dot_distance = 0.55 ,
1670
+ dot_color = WHITE ,
1671
+ elbow = False ,
1672
+ ** kwargs
1673
+ ):
1674
+ self .quadrant = quadrant
1675
+ self .dot_distance = dot_distance
1676
+ self .elbow = elbow
1677
+ inter = line_intersection (
1678
+ [line1 .get_start (), line1 .get_end ()], [line2 .get_start (), line2 .get_end ()]
1679
+ )
1680
+
1681
+ if radius is None :
1682
+ if quadrant [0 ] == 1 :
1683
+ dist_1 = np .linalg .norm (line1 .get_end () - inter )
1684
+ else :
1685
+ dist_1 = np .linalg .norm (line1 .get_start () - inter )
1686
+ if quadrant [1 ] == 1 :
1687
+ dist_2 = np .linalg .norm (line2 .get_end () - inter )
1688
+ else :
1689
+ dist_2 = np .linalg .norm (line2 .get_start () - inter )
1690
+ if np .minimum (dist_1 , dist_2 ) < 0.6 :
1691
+ radius = (2 / 3 ) * np .minimum (dist_1 , dist_2 )
1692
+ else :
1693
+ radius = 0.4
1694
+ else :
1695
+ self .radius = radius
1696
+
1697
+ anchor_angle_1 = inter + quadrant [0 ] * radius * line1 .get_unit_vector ()
1698
+ anchor_angle_2 = inter + quadrant [1 ] * radius * line2 .get_unit_vector ()
1699
+
1700
+ if elbow :
1701
+ anchor_middle = (
1702
+ inter
1703
+ + quadrant [0 ] * radius * line1 .get_unit_vector ()
1704
+ + quadrant [1 ] * radius * line2 .get_unit_vector ()
1705
+ )
1706
+ Elbow .__init__ (self , ** kwargs )
1707
+ self .set_points_as_corners ([anchor_angle_1 , anchor_middle , anchor_angle_2 ])
1708
+ else :
1709
+ angle_1 = angle_of_vector (anchor_angle_1 - inter )
1710
+ angle_2 = angle_of_vector (anchor_angle_2 - inter )
1711
+
1712
+ if not other_angle :
1713
+ start_angle = angle_1
1714
+ if angle_2 > angle_1 :
1715
+ angle_fin = angle_2 - angle_1
1716
+ else :
1717
+ angle_fin = 2 * np .pi - (angle_1 - angle_2 )
1718
+ else :
1719
+ start_angle = angle_1
1720
+ if angle_2 < angle_1 :
1721
+ angle_fin = - angle_1 + angle_2
1722
+ else :
1723
+ angle_fin = - 2 * np .pi + (angle_2 - angle_1 )
1724
+
1725
+ Arc .__init__ (
1726
+ self ,
1727
+ radius = radius ,
1728
+ angle = angle_fin ,
1729
+ start_angle = start_angle ,
1730
+ arc_center = inter ,
1731
+ ** kwargs
1732
+ )
1733
+ if dot :
1734
+ if dot_radius is None :
1735
+ dot_radius = radius / 10
1736
+ else :
1737
+ self .dot_radius = dot_radius
1738
+ right_dot = Dot (ORIGIN , radius = dot_radius , color = dot_color )
1739
+ dot_anchor = (
1740
+ inter
1741
+ + (self .get_center () - inter )
1742
+ / np .linalg .norm (self .get_center () - inter )
1743
+ * radius
1744
+ * dot_distance
1745
+ )
1746
+ right_dot .move_to (dot_anchor )
1747
+ self .add (right_dot )
1748
+
1749
+ def generate_points (self ):
1750
+ if self .elbow :
1751
+ Elbow .generate_points (self )
1752
+ else :
1753
+ Arc .generate_points (self )
1754
+
1755
+
1756
+ class RightAngle (Angle ):
1757
+ """An elbow-type mobject representing a right angle between two lines.
1758
+
1759
+ Parameters
1760
+ ----------
1761
+ line1 : :class:`Line`
1762
+ The first line.
1763
+ line2 : :class:`Line`
1764
+ The second line.
1765
+ length : :class:`float`
1766
+ The length of the arms.
1767
+ **kwargs
1768
+ Further keyword arguments that are passed to the constructor of :class:`Angle`.
1769
+
1770
+ Examples
1771
+ --------
1772
+
1773
+ .. manim:: RightAngleExample
1774
+ :save_last_frame:
1775
+
1776
+ class RightAngleExample(Scene):
1777
+ def construct(self):
1778
+ line1 = Line( LEFT, RIGHT )
1779
+ line2 = Line( DOWN, UP )
1780
+ rightangles = [
1781
+ RightAngle(line1, line2),
1782
+ RightAngle(line1, line2, length=0.4, quadrant=(1,-1)),
1783
+ RightAngle(line1, line2, length=0.5, quadrant=(-1,1), stroke_width=8),
1784
+ RightAngle(line1, line2, length=0.7, quadrant=(-1,-1), color=RED),
1785
+ ]
1786
+ line_list = VGroup( *[VGroup() for k in range(4)] )
1787
+ for k in range(4):
1788
+ linea = line1.copy()
1789
+ lineb = line2.copy()
1790
+ line_list[k].add( linea )
1791
+ line_list[k].add( lineb )
1792
+ line_list[k].add( rightangles[k] )
1793
+ line_list.arrange_in_grid(buff=1.5)
1794
+ self.add(
1795
+ line_list
1796
+ )
1797
+
1798
+ """
1799
+
1800
+ def __init__ (self , line1 , line2 , length = None , ** kwargs ):
1801
+ Angle .__init__ (self , line1 , line2 , radius = length , elbow = True , ** kwargs )
0 commit comments