Skip to content

Commit 7760675

Browse files
PhotonSpheresjsonvillanuevaWampyCakesfriedkeenan
authored
Added new classes Angle, RightAngle for two intersecting lines (#1085)
* test * test2 * Added two angle functions * bug-fix * bug_fix * bug-fix * angle changes * Added Docstrings * Run tests * Update manim/mobject/geometry.py Co-authored-by: Jason Villanueva <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: Jason Villanueva <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: Jason Villanueva <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: Jason Villanueva <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: KingWampy <[email protected]> * Changed examples * Added tab * Changed docstring * Updated Docstrings * Updated Docstrings * Ideas from MrMallIronmaker implemented * Update manim/mobject/geometry.py Co-authored-by: Jason Villanueva <[email protected]> * Change inheritance for Angle * Added inheritance in Angle * Black Test * Update manim/mobject/geometry.py Co-authored-by: Jason Villanueva <[email protected]> * Fixed multiple inheritance * Added Tests * Black test * retrigger checks * Updated docstrings * updated Docstrings * Update manim/mobject/geometry.py Co-authored-by: friedkeenan <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: friedkeenan <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: friedkeenan <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: friedkeenan <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: friedkeenan <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: friedkeenan <[email protected]> * Update manim/mobject/geometry.py Co-authored-by: friedkeenan <[email protected]> Co-authored-by: Pseudodifferent <[email protected]> Co-authored-by: Jason Villanueva <[email protected]> Co-authored-by: KingWampy <[email protected]> Co-authored-by: friedkeenan <[email protected]>
1 parent 783bdde commit 7760675

File tree

4 files changed

+258
-0
lines changed

4 files changed

+258
-0
lines changed

manim/mobject/geometry.py

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ def construct(self):
5454
"Square",
5555
"RoundedRectangle",
5656
"Cutout",
57+
"Angle",
58+
"RightAngle",
5759
]
5860

5961
import warnings
@@ -1557,3 +1559,243 @@ def __init__(self, main_shape, *mobjects, **kwargs):
15571559
sub_direction = "CW"
15581560
for mobject in mobjects:
15591561
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)
Binary file not shown.
Binary file not shown.

tests/test_graphical_units/test_geometry.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,22 @@ def construct(self):
150150
self.wait(1)
151151

152152

153+
class AngleTest(Scene):
154+
def construct(self):
155+
l1 = Line(ORIGIN, RIGHT)
156+
l2 = Line(ORIGIN, UP)
157+
a = Angle(l1, l2)
158+
self.play(Animation(a))
159+
160+
161+
class RightAngleTest(Scene):
162+
def construct(self):
163+
l1 = Line(ORIGIN, RIGHT)
164+
l2 = Line(ORIGIN, UP)
165+
a = RightAngle(l1, l2)
166+
self.play(Animation(a))
167+
168+
153169
MODULE_NAME = "geometry"
154170

155171

0 commit comments

Comments
 (0)