You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

853 lines
36 KiB

5 months ago
from sympy.core.numbers import (Float, Rational, oo, pi)
from sympy.core.relational import Eq
from sympy.core.singleton import S
from sympy.core.symbol import (Symbol, symbols)
from sympy.functions.elementary.miscellaneous import sqrt
from sympy.functions.elementary.trigonometric import (acos, cos, sin)
from sympy.sets import EmptySet
from sympy.simplify.simplify import simplify
from sympy.functions.elementary.trigonometric import tan
from sympy.geometry import (Circle, GeometryError, Line, Point, Ray,
Segment, Triangle, intersection, Point3D, Line3D, Ray3D, Segment3D,
Point2D, Line2D)
from sympy.geometry.line import Undecidable
from sympy.geometry.polygon import _asa as asa
from sympy.utilities.iterables import cartes
from sympy.testing.pytest import raises, warns
x = Symbol('x', real=True)
y = Symbol('y', real=True)
z = Symbol('z', real=True)
k = Symbol('k', real=True)
x1 = Symbol('x1', real=True)
y1 = Symbol('y1', real=True)
t = Symbol('t', real=True)
a, b = symbols('a,b', real=True)
m = symbols('m', real=True)
def test_object_from_equation():
from sympy.abc import x, y, a, b
assert Line(3*x + y + 18) == Line2D(Point2D(0, -18), Point2D(1, -21))
assert Line(3*x + 5 * y + 1) == Line2D(
Point2D(0, Rational(-1, 5)), Point2D(1, Rational(-4, 5)))
assert Line(3*a + b + 18, x="a", y="b") == Line2D(
Point2D(0, -18), Point2D(1, -21))
assert Line(3*x + y) == Line2D(Point2D(0, 0), Point2D(1, -3))
assert Line(x + y) == Line2D(Point2D(0, 0), Point2D(1, -1))
assert Line(Eq(3*a + b, -18), x="a", y=b) == Line2D(
Point2D(0, -18), Point2D(1, -21))
# issue 22361
assert Line(x - 1) == Line2D(Point2D(1, 0), Point2D(1, 1))
assert Line(2*x - 2, y=x) == Line2D(Point2D(0, 1), Point2D(1, 1))
assert Line(y) == Line2D(Point2D(0, 0), Point2D(1, 0))
assert Line(2*y, x=y) == Line2D(Point2D(0, 0), Point2D(0, 1))
assert Line(y, x=y) == Line2D(Point2D(0, 0), Point2D(0, 1))
raises(ValueError, lambda: Line(x / y))
raises(ValueError, lambda: Line(a / b, x='a', y='b'))
raises(ValueError, lambda: Line(y / x))
raises(ValueError, lambda: Line(b / a, x='a', y='b'))
raises(ValueError, lambda: Line((x + 1)**2 + y))
def feq(a, b):
"""Test if two floating point values are 'equal'."""
t_float = Float("1.0E-10")
return -t_float < a - b < t_float
def test_angle_between():
a = Point(1, 2, 3, 4)
b = a.orthogonal_direction
o = a.origin
assert feq(Line.angle_between(Line(Point(0, 0), Point(1, 1)),
Line(Point(0, 0), Point(5, 0))).evalf(), pi.evalf() / 4)
assert Line(a, o).angle_between(Line(b, o)) == pi / 2
z = Point3D(0, 0, 0)
assert Line3D.angle_between(Line3D(z, Point3D(1, 1, 1)),
Line3D(z, Point3D(5, 0, 0))) == acos(sqrt(3) / 3)
# direction of points is used to determine angle
assert Line3D.angle_between(Line3D(z, Point3D(1, 1, 1)),
Line3D(Point3D(5, 0, 0), z)) == acos(-sqrt(3) / 3)
def test_closing_angle():
a = Ray((0, 0), angle=0)
b = Ray((1, 2), angle=pi/2)
assert a.closing_angle(b) == -pi/2
assert b.closing_angle(a) == pi/2
assert a.closing_angle(a) == 0
def test_smallest_angle():
a = Line(Point(1, 1), Point(1, 2))
b = Line(Point(1, 1),Point(2, 3))
assert a.smallest_angle_between(b) == acos(2*sqrt(5)/5)
def test_svg():
a = Line(Point(1, 1),Point(1, 2))
assert a._svg() == '<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" stroke-width="2.0" opacity="0.6" d="M 1.00000000000000,1.00000000000000 L 1.00000000000000,2.00000000000000" marker-start="url(#markerReverseArrow)" marker-end="url(#markerArrow)"/>'
a = Segment(Point(1, 0),Point(1, 1))
assert a._svg() == '<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" stroke-width="2.0" opacity="0.6" d="M 1.00000000000000,0 L 1.00000000000000,1.00000000000000" />'
a = Ray(Point(2, 3), Point(3, 5))
assert a._svg() == '<path fill-rule="evenodd" fill="#66cc99" stroke="#555555" stroke-width="2.0" opacity="0.6" d="M 2.00000000000000,3.00000000000000 L 3.00000000000000,5.00000000000000" marker-start="url(#markerCircle)" marker-end="url(#markerArrow)"/>'
def test_arbitrary_point():
l1 = Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1))
l2 = Line(Point(x1, x1), Point(y1, y1))
assert l2.arbitrary_point() in l2
assert Ray((1, 1), angle=pi / 4).arbitrary_point() == \
Point(t + 1, t + 1)
assert Segment((1, 1), (2, 3)).arbitrary_point() == Point(1 + t, 1 + 2 * t)
assert l1.perpendicular_segment(l1.arbitrary_point()) == l1.arbitrary_point()
assert Ray3D((1, 1, 1), direction_ratio=[1, 2, 3]).arbitrary_point() == \
Point3D(t + 1, 2 * t + 1, 3 * t + 1)
assert Segment3D(Point3D(0, 0, 0), Point3D(1, 1, 1)).midpoint == \
Point3D(S.Half, S.Half, S.Half)
assert Segment3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1)).length == sqrt(3) * sqrt((x1 - y1) ** 2)
assert Segment3D((1, 1, 1), (2, 3, 4)).arbitrary_point() == \
Point3D(t + 1, 2 * t + 1, 3 * t + 1)
raises(ValueError, (lambda: Line((x, 1), (2, 3)).arbitrary_point(x)))
def test_are_concurrent_2d():
l1 = Line(Point(0, 0), Point(1, 1))
l2 = Line(Point(x1, x1), Point(x1, 1 + x1))
assert Line.are_concurrent(l1) is False
assert Line.are_concurrent(l1, l2)
assert Line.are_concurrent(l1, l1, l1, l2)
assert Line.are_concurrent(l1, l2, Line(Point(5, x1), Point(Rational(-3, 5), x1)))
assert Line.are_concurrent(l1, Line(Point(0, 0), Point(-x1, x1)), l2) is False
def test_are_concurrent_3d():
p1 = Point3D(0, 0, 0)
l1 = Line(p1, Point3D(1, 1, 1))
parallel_1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))
parallel_2 = Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))
assert Line3D.are_concurrent(l1) is False
assert Line3D.are_concurrent(l1, Line(Point3D(x1, x1, x1), Point3D(y1, y1, y1))) is False
assert Line3D.are_concurrent(l1, Line3D(p1, Point3D(x1, x1, x1)),
Line(Point3D(x1, x1, x1), Point3D(x1, 1 + x1, 1))) is True
assert Line3D.are_concurrent(parallel_1, parallel_2) is False
def test_arguments():
"""Functions accepting `Point` objects in `geometry`
should also accept tuples, lists, and generators and
automatically convert them to points."""
from sympy.utilities.iterables import subsets
singles2d = ((1, 2), [1, 3], Point(1, 5))
doubles2d = subsets(singles2d, 2)
l2d = Line(Point2D(1, 2), Point2D(2, 3))
singles3d = ((1, 2, 3), [1, 2, 4], Point(1, 2, 6))
doubles3d = subsets(singles3d, 2)
l3d = Line(Point3D(1, 2, 3), Point3D(1, 1, 2))
singles4d = ((1, 2, 3, 4), [1, 2, 3, 5], Point(1, 2, 3, 7))
doubles4d = subsets(singles4d, 2)
l4d = Line(Point(1, 2, 3, 4), Point(2, 2, 2, 2))
# test 2D
test_single = ['contains', 'distance', 'equals', 'parallel_line', 'perpendicular_line', 'perpendicular_segment',
'projection', 'intersection']
for p in doubles2d:
Line2D(*p)
for func in test_single:
for p in singles2d:
getattr(l2d, func)(p)
# test 3D
for p in doubles3d:
Line3D(*p)
for func in test_single:
for p in singles3d:
getattr(l3d, func)(p)
# test 4D
for p in doubles4d:
Line(*p)
for func in test_single:
for p in singles4d:
getattr(l4d, func)(p)
def test_basic_properties_2d():
p1 = Point(0, 0)
p2 = Point(1, 1)
p10 = Point(2000, 2000)
p_r3 = Ray(p1, p2).random_point()
p_r4 = Ray(p2, p1).random_point()
l1 = Line(p1, p2)
l3 = Line(Point(x1, x1), Point(x1, 1 + x1))
l4 = Line(p1, Point(1, 0))
r1 = Ray(p1, Point(0, 1))
r2 = Ray(Point(0, 1), p1)
s1 = Segment(p1, p10)
p_s1 = s1.random_point()
assert Line((1, 1), slope=1) == Line((1, 1), (2, 2))
assert Line((1, 1), slope=oo) == Line((1, 1), (1, 2))
assert Line((1, 1), slope=oo).bounds == (1, 1, 1, 2)
assert Line((1, 1), slope=-oo) == Line((1, 1), (1, 2))
assert Line(p1, p2).scale(2, 1) == Line(p1, Point(2, 1))
assert Line(p1, p2) == Line(p1, p2)
assert Line(p1, p2) != Line(p2, p1)
assert l1 != Line(Point(x1, x1), Point(y1, y1))
assert l1 != l3
assert Line(p1, p10) != Line(p10, p1)
assert Line(p1, p10) != p1
assert p1 in l1 # is p1 on the line l1?
assert p1 not in l3
assert s1 in Line(p1, p10)
assert Ray(Point(0, 0), Point(0, 1)) in Ray(Point(0, 0), Point(0, 2))
assert Ray(Point(0, 0), Point(0, 2)) in Ray(Point(0, 0), Point(0, 1))
assert Ray(Point(0, 0), Point(0, 2)).xdirection == S.Zero
assert Ray(Point(0, 0), Point(1, 2)).xdirection == S.Infinity
assert Ray(Point(0, 0), Point(-1, 2)).xdirection == S.NegativeInfinity
assert Ray(Point(0, 0), Point(2, 0)).ydirection == S.Zero
assert Ray(Point(0, 0), Point(2, 2)).ydirection == S.Infinity
assert Ray(Point(0, 0), Point(2, -2)).ydirection == S.NegativeInfinity
assert (r1 in s1) is False
assert Segment(p1, p2) in s1
assert Ray(Point(x1, x1), Point(x1, 1 + x1)) != Ray(p1, Point(-1, 5))
assert Segment(p1, p2).midpoint == Point(S.Half, S.Half)
assert Segment(p1, Point(-x1, x1)).length == sqrt(2 * (x1 ** 2))
assert l1.slope == 1
assert l3.slope is oo
assert l4.slope == 0
assert Line(p1, Point(0, 1)).slope is oo
assert Line(r1.source, r1.random_point()).slope == r1.slope
assert Line(r2.source, r2.random_point()).slope == r2.slope
assert Segment(Point(0, -1), Segment(p1, Point(0, 1)).random_point()).slope == Segment(p1, Point(0, 1)).slope
assert l4.coefficients == (0, 1, 0)
assert Line((-x, x), (-x + 1, x - 1)).coefficients == (1, 1, 0)
assert Line(p1, Point(0, 1)).coefficients == (1, 0, 0)
# issue 7963
r = Ray((0, 0), angle=x)
assert r.subs(x, 3 * pi / 4) == Ray((0, 0), (-1, 1))
assert r.subs(x, 5 * pi / 4) == Ray((0, 0), (-1, -1))
assert r.subs(x, -pi / 4) == Ray((0, 0), (1, -1))
assert r.subs(x, pi / 2) == Ray((0, 0), (0, 1))
assert r.subs(x, -pi / 2) == Ray((0, 0), (0, -1))
for ind in range(0, 5):
assert l3.random_point() in l3
assert p_r3.x >= p1.x and p_r3.y >= p1.y
assert p_r4.x <= p2.x and p_r4.y <= p2.y
assert p1.x <= p_s1.x <= p10.x and p1.y <= p_s1.y <= p10.y
assert hash(s1) != hash(Segment(p10, p1))
assert s1.plot_interval() == [t, 0, 1]
assert Line(p1, p10).plot_interval() == [t, -5, 5]
assert Ray((0, 0), angle=pi / 4).plot_interval() == [t, 0, 10]
def test_basic_properties_3d():
p1 = Point3D(0, 0, 0)
p2 = Point3D(1, 1, 1)
p3 = Point3D(x1, x1, x1)
p5 = Point3D(x1, 1 + x1, 1)
l1 = Line3D(p1, p2)
l3 = Line3D(p3, p5)
r1 = Ray3D(p1, Point3D(-1, 5, 0))
r3 = Ray3D(p1, p2)
s1 = Segment3D(p1, p2)
assert Line3D((1, 1, 1), direction_ratio=[2, 3, 4]) == Line3D(Point3D(1, 1, 1), Point3D(3, 4, 5))
assert Line3D((1, 1, 1), direction_ratio=[1, 5, 7]) == Line3D(Point3D(1, 1, 1), Point3D(2, 6, 8))
assert Line3D((1, 1, 1), direction_ratio=[1, 2, 3]) == Line3D(Point3D(1, 1, 1), Point3D(2, 3, 4))
assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).direction_cosine == [1, 0, 0]
assert Line3D(Line3D(p1, Point3D(0, 1, 0))) == Line3D(p1, Point3D(0, 1, 0))
assert Ray3D(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))) == Ray3D(p1, Point3D(1, 0, 0))
assert Line3D(p1, p2) != Line3D(p2, p1)
assert l1 != l3
assert l1 != Line3D(p3, Point3D(y1, y1, y1))
assert r3 != r1
assert Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 1)) in Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2))
assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)) in Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 1))
assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).xdirection == S.Infinity
assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).ydirection == S.Infinity
assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).zdirection == S.Infinity
assert Ray3D(Point3D(0, 0, 0), Point3D(-2, 2, 2)).xdirection == S.NegativeInfinity
assert Ray3D(Point3D(0, 0, 0), Point3D(2, -2, 2)).ydirection == S.NegativeInfinity
assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, -2)).zdirection == S.NegativeInfinity
assert Ray3D(Point3D(0, 0, 0), Point3D(0, 2, 2)).xdirection == S.Zero
assert Ray3D(Point3D(0, 0, 0), Point3D(2, 0, 2)).ydirection == S.Zero
assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 0)).zdirection == S.Zero
assert p1 in l1
assert p1 not in l3
assert l1.direction_ratio == [1, 1, 1]
assert s1.midpoint == Point3D(S.Half, S.Half, S.Half)
# Test zdirection
assert Ray3D(p1, Point3D(0, 0, -1)).zdirection is S.NegativeInfinity
def test_contains():
p1 = Point(0, 0)
r = Ray(p1, Point(4, 4))
r1 = Ray3D(p1, Point3D(0, 0, -1))
r2 = Ray3D(p1, Point3D(0, 1, 0))
r3 = Ray3D(p1, Point3D(0, 0, 1))
l = Line(Point(0, 1), Point(3, 4))
# Segment contains
assert Point(0, (a + b) / 2) in Segment((0, a), (0, b))
assert Point((a + b) / 2, 0) in Segment((a, 0), (b, 0))
assert Point3D(0, 1, 0) in Segment3D((0, 1, 0), (0, 1, 0))
assert Point3D(1, 0, 0) in Segment3D((1, 0, 0), (1, 0, 0))
assert Segment3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).contains([]) is True
assert Segment3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).contains(
Segment3D(Point3D(2, 2, 2), Point3D(3, 2, 2))) is False
# Line contains
assert l.contains(Point(0, 1)) is True
assert l.contains((0, 1)) is True
assert l.contains((0, 0)) is False
# Ray contains
assert r.contains(p1) is True
assert r.contains((1, 1)) is True
assert r.contains((1, 3)) is False
assert r.contains(Segment((1, 1), (2, 2))) is True
assert r.contains(Segment((1, 2), (2, 5))) is False
assert r.contains(Ray((2, 2), (3, 3))) is True
assert r.contains(Ray((2, 2), (3, 5))) is False
assert r1.contains(Segment3D(p1, Point3D(0, 0, -10))) is True
assert r1.contains(Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))) is False
assert r2.contains(Point3D(0, 0, 0)) is True
assert r3.contains(Point3D(0, 0, 0)) is True
assert Ray3D(Point3D(1, 1, 1), Point3D(1, 0, 0)).contains([]) is False
assert Line3D((0, 0, 0), (x, y, z)).contains((2 * x, 2 * y, 2 * z))
with warns(UserWarning, test_stacklevel=False):
assert Line3D(p1, Point3D(0, 1, 0)).contains(Point(1.0, 1.0)) is False
with warns(UserWarning, test_stacklevel=False):
assert r3.contains(Point(1.0, 1.0)) is False
def test_contains_nonreal_symbols():
u, v, w, z = symbols('u, v, w, z')
l = Segment(Point(u, w), Point(v, z))
p = Point(u*Rational(2, 3) + v/3, w*Rational(2, 3) + z/3)
assert l.contains(p)
def test_distance_2d():
p1 = Point(0, 0)
p2 = Point(1, 1)
half = S.Half
s1 = Segment(Point(0, 0), Point(1, 1))
s2 = Segment(Point(half, half), Point(1, 0))
r = Ray(p1, p2)
assert s1.distance(Point(0, 0)) == 0
assert s1.distance((0, 0)) == 0
assert s2.distance(Point(0, 0)) == 2 ** half / 2
assert s2.distance(Point(Rational(3) / 2, Rational(3) / 2)) == 2 ** half
assert Line(p1, p2).distance(Point(-1, 1)) == sqrt(2)
assert Line(p1, p2).distance(Point(1, -1)) == sqrt(2)
assert Line(p1, p2).distance(Point(2, 2)) == 0
assert Line(p1, p2).distance((-1, 1)) == sqrt(2)
assert Line((0, 0), (0, 1)).distance(p1) == 0
assert Line((0, 0), (0, 1)).distance(p2) == 1
assert Line((0, 0), (1, 0)).distance(p1) == 0
assert Line((0, 0), (1, 0)).distance(p2) == 1
assert r.distance(Point(-1, -1)) == sqrt(2)
assert r.distance(Point(1, 1)) == 0
assert r.distance(Point(-1, 1)) == sqrt(2)
assert Ray((1, 1), (2, 2)).distance(Point(1.5, 3)) == 3 * sqrt(2) / 4
assert r.distance((1, 1)) == 0
def test_dimension_normalization():
with warns(UserWarning, test_stacklevel=False):
assert Ray((1, 1), (2, 1, 2)) == Ray((1, 1, 0), (2, 1, 2))
def test_distance_3d():
p1, p2 = Point3D(0, 0, 0), Point3D(1, 1, 1)
p3 = Point3D(Rational(3) / 2, Rational(3) / 2, Rational(3) / 2)
s1 = Segment3D(Point3D(0, 0, 0), Point3D(1, 1, 1))
s2 = Segment3D(Point3D(S.Half, S.Half, S.Half), Point3D(1, 0, 1))
r = Ray3D(p1, p2)
assert s1.distance(p1) == 0
assert s2.distance(p1) == sqrt(3) / 2
assert s2.distance(p3) == 2 * sqrt(6) / 3
assert s1.distance((0, 0, 0)) == 0
assert s2.distance((0, 0, 0)) == sqrt(3) / 2
assert s1.distance(p1) == 0
assert s2.distance(p1) == sqrt(3) / 2
assert s2.distance(p3) == 2 * sqrt(6) / 3
assert s1.distance((0, 0, 0)) == 0
assert s2.distance((0, 0, 0)) == sqrt(3) / 2
# Line to point
assert Line3D(p1, p2).distance(Point3D(-1, 1, 1)) == 2 * sqrt(6) / 3
assert Line3D(p1, p2).distance(Point3D(1, -1, 1)) == 2 * sqrt(6) / 3
assert Line3D(p1, p2).distance(Point3D(2, 2, 2)) == 0
assert Line3D(p1, p2).distance((2, 2, 2)) == 0
assert Line3D(p1, p2).distance((1, -1, 1)) == 2 * sqrt(6) / 3
assert Line3D((0, 0, 0), (0, 1, 0)).distance(p1) == 0
assert Line3D((0, 0, 0), (0, 1, 0)).distance(p2) == sqrt(2)
assert Line3D((0, 0, 0), (1, 0, 0)).distance(p1) == 0
assert Line3D((0, 0, 0), (1, 0, 0)).distance(p2) == sqrt(2)
# Ray to point
assert r.distance(Point3D(-1, -1, -1)) == sqrt(3)
assert r.distance(Point3D(1, 1, 1)) == 0
assert r.distance((-1, -1, -1)) == sqrt(3)
assert r.distance((1, 1, 1)) == 0
assert Ray3D((0, 0, 0), (1, 1, 2)).distance((-1, -1, 2)) == 4 * sqrt(3) / 3
assert Ray3D((1, 1, 1), (2, 2, 2)).distance(Point3D(1.5, -3, -1)) == Rational(9) / 2
assert Ray3D((1, 1, 1), (2, 2, 2)).distance(Point3D(1.5, 3, 1)) == sqrt(78) / 6
def test_equals():
p1 = Point(0, 0)
p2 = Point(1, 1)
l1 = Line(p1, p2)
l2 = Line((0, 5), slope=m)
l3 = Line(Point(x1, x1), Point(x1, 1 + x1))
assert l1.perpendicular_line(p1.args).equals(Line(Point(0, 0), Point(1, -1)))
assert l1.perpendicular_line(p1).equals(Line(Point(0, 0), Point(1, -1)))
assert Line(Point(x1, x1), Point(y1, y1)).parallel_line(Point(-x1, x1)). \
equals(Line(Point(-x1, x1), Point(-y1, 2 * x1 - y1)))
assert l3.parallel_line(p1.args).equals(Line(Point(0, 0), Point(0, -1)))
assert l3.parallel_line(p1).equals(Line(Point(0, 0), Point(0, -1)))
assert (l2.distance(Point(2, 3)) - 2 * abs(m + 1) / sqrt(m ** 2 + 1)).equals(0)
assert Line3D(p1, Point3D(0, 1, 0)).equals(Point(1.0, 1.0)) is False
assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).equals(Line3D(Point3D(-5, 0, 0), Point3D(-1, 0, 0))) is True
assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).equals(Line3D(p1, Point3D(0, 1, 0))) is False
assert Ray3D(p1, Point3D(0, 0, -1)).equals(Point(1.0, 1.0)) is False
assert Ray3D(p1, Point3D(0, 0, -1)).equals(Ray3D(p1, Point3D(0, 0, -1))) is True
assert Line3D((0, 0), (t, t)).perpendicular_line(Point(0, 1, 0)).equals(
Line3D(Point3D(0, 1, 0), Point3D(S.Half, S.Half, 0)))
assert Line3D((0, 0), (t, t)).perpendicular_segment(Point(0, 1, 0)).equals(Segment3D((0, 1), (S.Half, S.Half)))
assert Line3D(p1, Point3D(0, 1, 0)).equals(Point(1.0, 1.0)) is False
def test_equation():
p1 = Point(0, 0)
p2 = Point(1, 1)
l1 = Line(p1, p2)
l3 = Line(Point(x1, x1), Point(x1, 1 + x1))
assert simplify(l1.equation()) in (x - y, y - x)
assert simplify(l3.equation()) in (x - x1, x1 - x)
assert simplify(l1.equation()) in (x - y, y - x)
assert simplify(l3.equation()) in (x - x1, x1 - x)
assert Line(p1, Point(1, 0)).equation(x=x, y=y) == y
assert Line(p1, Point(0, 1)).equation() == x
assert Line(Point(2, 0), Point(2, 1)).equation() == x - 2
assert Line(p2, Point(2, 1)).equation() == y - 1
assert Line3D(Point(x1, x1, x1), Point(y1, y1, y1)
).equation() == (-x + y, -x + z)
assert Line3D(Point(1, 2, 3), Point(2, 3, 4)
).equation() == (-x + y - 1, -x + z - 2)
assert Line3D(Point(1, 2, 3), Point(1, 3, 4)
).equation() == (x - 1, -y + z - 1)
assert Line3D(Point(1, 2, 3), Point(2, 2, 4)
).equation() == (y - 2, -x + z - 2)
assert Line3D(Point(1, 2, 3), Point(2, 3, 3)
).equation() == (-x + y - 1, z - 3)
assert Line3D(Point(1, 2, 3), Point(1, 2, 4)
).equation() == (x - 1, y - 2)
assert Line3D(Point(1, 2, 3), Point(1, 3, 3)
).equation() == (x - 1, z - 3)
assert Line3D(Point(1, 2, 3), Point(2, 2, 3)
).equation() == (y - 2, z - 3)
def test_intersection_2d():
p1 = Point(0, 0)
p2 = Point(1, 1)
p3 = Point(x1, x1)
p4 = Point(y1, y1)
l1 = Line(p1, p2)
l3 = Line(Point(0, 0), Point(3, 4))
r1 = Ray(Point(1, 1), Point(2, 2))
r2 = Ray(Point(0, 0), Point(3, 4))
r4 = Ray(p1, p2)
r6 = Ray(Point(0, 1), Point(1, 2))
r7 = Ray(Point(0.5, 0.5), Point(1, 1))
s1 = Segment(p1, p2)
s2 = Segment(Point(0.25, 0.25), Point(0.5, 0.5))
s3 = Segment(Point(0, 0), Point(3, 4))
assert intersection(l1, p1) == [p1]
assert intersection(l1, Point(x1, 1 + x1)) == []
assert intersection(l1, Line(p3, p4)) in [[l1], [Line(p3, p4)]]
assert intersection(l1, l1.parallel_line(Point(x1, 1 + x1))) == []
assert intersection(l3, l3) == [l3]
assert intersection(l3, r2) == [r2]
assert intersection(l3, s3) == [s3]
assert intersection(s3, l3) == [s3]
assert intersection(Segment(Point(-10, 10), Point(10, 10)), Segment(Point(-5, -5), Point(-5, 5))) == []
assert intersection(r2, l3) == [r2]
assert intersection(r1, Ray(Point(2, 2), Point(0, 0))) == [Segment(Point(1, 1), Point(2, 2))]
assert intersection(r1, Ray(Point(1, 1), Point(-1, -1))) == [Point(1, 1)]
assert intersection(r1, Segment(Point(0, 0), Point(2, 2))) == [Segment(Point(1, 1), Point(2, 2))]
assert r4.intersection(s2) == [s2]
assert r4.intersection(Segment(Point(2, 3), Point(3, 4))) == []
assert r4.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))]
assert r4.intersection(Ray(p2, p1)) == [s1]
assert Ray(p2, p1).intersection(r6) == []
assert r4.intersection(r7) == r7.intersection(r4) == [r7]
assert Ray3D((0, 0), (3, 0)).intersection(Ray3D((1, 0), (3, 0))) == [Ray3D((1, 0), (3, 0))]
assert Ray3D((1, 0), (3, 0)).intersection(Ray3D((0, 0), (3, 0))) == [Ray3D((1, 0), (3, 0))]
assert Ray(Point(0, 0), Point(0, 4)).intersection(Ray(Point(0, 1), Point(0, -1))) == \
[Segment(Point(0, 0), Point(0, 1))]
assert Segment3D((0, 0), (3, 0)).intersection(
Segment3D((1, 0), (2, 0))) == [Segment3D((1, 0), (2, 0))]
assert Segment3D((1, 0), (2, 0)).intersection(
Segment3D((0, 0), (3, 0))) == [Segment3D((1, 0), (2, 0))]
assert Segment3D((0, 0), (3, 0)).intersection(
Segment3D((3, 0), (4, 0))) == [Point3D((3, 0))]
assert Segment3D((0, 0), (3, 0)).intersection(
Segment3D((2, 0), (5, 0))) == [Segment3D((2, 0), (3, 0))]
assert Segment3D((0, 0), (3, 0)).intersection(
Segment3D((-2, 0), (1, 0))) == [Segment3D((0, 0), (1, 0))]
assert Segment3D((0, 0), (3, 0)).intersection(
Segment3D((-2, 0), (0, 0))) == [Point3D(0, 0)]
assert s1.intersection(Segment(Point(1, 1), Point(2, 2))) == [Point(1, 1)]
assert s1.intersection(Segment(Point(0.5, 0.5), Point(1.5, 1.5))) == [Segment(Point(0.5, 0.5), p2)]
assert s1.intersection(Segment(Point(4, 4), Point(5, 5))) == []
assert s1.intersection(Segment(Point(-1, -1), p1)) == [p1]
assert s1.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))]
assert s1.intersection(Line(Point(1, 0), Point(2, 1))) == []
assert s1.intersection(s2) == [s2]
assert s2.intersection(s1) == [s2]
assert asa(120, 8, 52) == \
Triangle(
Point(0, 0),
Point(8, 0),
Point(-4 * cos(19 * pi / 90) / sin(2 * pi / 45),
4 * sqrt(3) * cos(19 * pi / 90) / sin(2 * pi / 45)))
assert Line((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == [Point(1, 1)]
assert Line((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == [Point(1, 1)]
assert Ray((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == [Point(1, 1)]
assert Ray((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == [Point(1, 1)]
assert Ray((0, 0), (10, 10)).contains(Segment((1, 1), (2, 2))) is True
assert Segment((1, 1), (2, 2)) in Line((0, 0), (10, 10))
assert s1.intersection(Ray((1, 1), (4, 4))) == [Point(1, 1)]
# This test is disabled because it hangs after rref changes which simplify
# intermediate results and return a different representation from when the
# test was written.
# # 16628 - this should be fast
# p0 = Point2D(Rational(249, 5), Rational(497999, 10000))
# p1 = Point2D((-58977084786*sqrt(405639795226) + 2030690077184193 +
# 20112207807*sqrt(630547164901) + 99600*sqrt(255775022850776494562626))
# /(2000*sqrt(255775022850776494562626) + 1991998000*sqrt(405639795226)
# + 1991998000*sqrt(630547164901) + 1622561172902000),
# (-498000*sqrt(255775022850776494562626) - 995999*sqrt(630547164901) +
# 90004251917891999 +
# 496005510002*sqrt(405639795226))/(10000*sqrt(255775022850776494562626)
# + 9959990000*sqrt(405639795226) + 9959990000*sqrt(630547164901) +
# 8112805864510000))
# p2 = Point2D(Rational(497, 10), Rational(-497, 10))
# p3 = Point2D(Rational(-497, 10), Rational(-497, 10))
# l = Line(p0, p1)
# s = Segment(p2, p3)
# n = (-52673223862*sqrt(405639795226) - 15764156209307469 -
# 9803028531*sqrt(630547164901) +
# 33200*sqrt(255775022850776494562626))
# d = sqrt(405639795226) + 315274080450 + 498000*sqrt(
# 630547164901) + sqrt(255775022850776494562626)
# assert intersection(l, s) == [
# Point2D(n/d*Rational(3, 2000), Rational(-497, 10))]
def test_line_intersection():
# see also test_issue_11238 in test_matrices.py
x0 = tan(pi*Rational(13, 45))
x1 = sqrt(3)
x2 = x0**2
x, y = [8*x0/(x0 + x1), (24*x0 - 8*x1*x2)/(x2 - 3)]
assert Line(Point(0, 0), Point(1, -sqrt(3))).contains(Point(x, y)) is True
def test_intersection_3d():
p1 = Point3D(0, 0, 0)
p2 = Point3D(1, 1, 1)
l1 = Line3D(p1, p2)
l2 = Line3D(Point3D(0, 0, 0), Point3D(3, 4, 0))
r1 = Ray3D(Point3D(1, 1, 1), Point3D(2, 2, 2))
r2 = Ray3D(Point3D(0, 0, 0), Point3D(3, 4, 0))
s1 = Segment3D(Point3D(0, 0, 0), Point3D(3, 4, 0))
assert intersection(l1, p1) == [p1]
assert intersection(l1, Point3D(x1, 1 + x1, 1)) == []
assert intersection(l1, l1.parallel_line(p1)) == [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1))]
assert intersection(l2, r2) == [r2]
assert intersection(l2, s1) == [s1]
assert intersection(r2, l2) == [r2]
assert intersection(r1, Ray3D(Point3D(1, 1, 1), Point3D(-1, -1, -1))) == [Point3D(1, 1, 1)]
assert intersection(r1, Segment3D(Point3D(0, 0, 0), Point3D(2, 2, 2))) == [
Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))]
assert intersection(Ray3D(Point3D(1, 0, 0), Point3D(-1, 0, 0)), Ray3D(Point3D(0, 1, 0), Point3D(0, -1, 0))) \
== [Point3D(0, 0, 0)]
assert intersection(r1, Ray3D(Point3D(2, 2, 2), Point3D(0, 0, 0))) == \
[Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))]
assert intersection(s1, r2) == [s1]
assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).intersection(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) == \
[Point3D(2, 2, 1)]
assert Line3D((0, 1, 2), (0, 2, 3)).intersection(Line3D((0, 1, 2), (0, 1, 1))) == [Point3D(0, 1, 2)]
assert Line3D((0, 0), (t, t)).intersection(Line3D((0, 1), (t, t))) == \
[Point3D(t, t)]
assert Ray3D(Point3D(0, 0, 0), Point3D(0, 4, 0)).intersection(Ray3D(Point3D(0, 1, 1), Point3D(0, -1, 1))) == []
def test_is_parallel():
p1 = Point3D(0, 0, 0)
p2 = Point3D(1, 1, 1)
p3 = Point3D(x1, x1, x1)
l2 = Line(Point(x1, x1), Point(y1, y1))
l2_1 = Line(Point(x1, x1), Point(x1, 1 + x1))
assert Line.is_parallel(Line(Point(0, 0), Point(1, 1)), l2)
assert Line.is_parallel(l2, Line(Point(x1, x1), Point(x1, 1 + x1))) is False
assert Line.is_parallel(l2, l2.parallel_line(Point(-x1, x1)))
assert Line.is_parallel(l2_1, l2_1.parallel_line(Point(0, 0)))
assert Line3D(p1, p2).is_parallel(Line3D(p1, p2)) # same as in 2D
assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).is_parallel(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) is False
assert Line3D(p1, p2).parallel_line(p3) == Line3D(Point3D(x1, x1, x1),
Point3D(x1 + 1, x1 + 1, x1 + 1))
assert Line3D(p1, p2).parallel_line(p3.args) == \
Line3D(Point3D(x1, x1, x1), Point3D(x1 + 1, x1 + 1, x1 + 1))
assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).is_parallel(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) is False
def test_is_perpendicular():
p1 = Point(0, 0)
p2 = Point(1, 1)
l1 = Line(p1, p2)
l2 = Line(Point(x1, x1), Point(y1, y1))
l1_1 = Line(p1, Point(-x1, x1))
# 2D
assert Line.is_perpendicular(l1, l1_1)
assert Line.is_perpendicular(l1, l2) is False
p = l1.random_point()
assert l1.perpendicular_segment(p) == p
# 3D
assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)),
Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))) is True
assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)),
Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))) is False
assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)),
Line3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1))) is False
def test_is_similar():
p1 = Point(2000, 2000)
p2 = p1.scale(2, 2)
r1 = Ray3D(Point3D(1, 1, 1), Point3D(1, 0, 0))
r2 = Ray(Point(0, 0), Point(0, 1))
s1 = Segment(Point(0, 0), p1)
assert s1.is_similar(Segment(p1, p2))
assert s1.is_similar(r2) is False
assert r1.is_similar(Line3D(Point3D(1, 1, 1), Point3D(1, 0, 0))) is True
assert r1.is_similar(Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))) is False
def test_length():
s2 = Segment3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1))
assert Line(Point(0, 0), Point(1, 1)).length is oo
assert s2.length == sqrt(3) * sqrt((x1 - y1) ** 2)
assert Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)).length is oo
def test_projection():
p1 = Point(0, 0)
p2 = Point3D(0, 0, 0)
p3 = Point(-x1, x1)
l1 = Line(p1, Point(1, 1))
l2 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))
l3 = Line3D(p2, Point3D(1, 1, 1))
r1 = Ray(Point(1, 1), Point(2, 2))
s1 = Segment(Point2D(0, 0), Point2D(0, 1))
s2 = Segment(Point2D(1, 0), Point2D(2, 1/2))
assert Line(Point(x1, x1), Point(y1, y1)).projection(Point(y1, y1)) == Point(y1, y1)
assert Line(Point(x1, x1), Point(x1, 1 + x1)).projection(Point(1, 1)) == Point(x1, 1)
assert Segment(Point(-2, 2), Point(0, 4)).projection(r1) == Segment(Point(-1, 3), Point(0, 4))
assert Segment(Point(0, 4), Point(-2, 2)).projection(r1) == Segment(Point(0, 4), Point(-1, 3))
assert s2.projection(s1) == EmptySet
assert l1.projection(p3) == p1
assert l1.projection(Ray(p1, Point(-1, 5))) == Ray(Point(0, 0), Point(2, 2))
assert l1.projection(Ray(p1, Point(-1, 1))) == p1
assert r1.projection(Ray(Point(1, 1), Point(-1, -1))) == Point(1, 1)
assert r1.projection(Ray(Point(0, 4), Point(-1, -5))) == Segment(Point(1, 1), Point(2, 2))
assert r1.projection(Segment(Point(-1, 5), Point(-5, -10))) == Segment(Point(1, 1), Point(2, 2))
assert r1.projection(Ray(Point(1, 1), Point(-1, -1))) == Point(1, 1)
assert r1.projection(Ray(Point(0, 4), Point(-1, -5))) == Segment(Point(1, 1), Point(2, 2))
assert r1.projection(Segment(Point(-1, 5), Point(-5, -10))) == Segment(Point(1, 1), Point(2, 2))
assert l3.projection(Ray3D(p2, Point3D(-1, 5, 0))) == Ray3D(Point3D(0, 0, 0), Point3D(Rational(4, 3), Rational(4, 3), Rational(4, 3)))
assert l3.projection(Ray3D(p2, Point3D(-1, 1, 1))) == Ray3D(Point3D(0, 0, 0), Point3D(Rational(1, 3), Rational(1, 3), Rational(1, 3)))
assert l2.projection(Point3D(5, 5, 0)) == Point3D(5, 0)
assert l2.projection(Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))).equals(l2)
def test_perpendicular_line():
# 3d - requires a particular orthogonal to be selected
p1, p2, p3 = Point(0, 0, 0), Point(2, 3, 4), Point(-2, 2, 0)
l = Line(p1, p2)
p = l.perpendicular_line(p3)
assert p.p1 == p3
assert p.p2 in l
# 2d - does not require special selection
p1, p2, p3 = Point(0, 0), Point(2, 3), Point(-2, 2)
l = Line(p1, p2)
p = l.perpendicular_line(p3)
assert p.p1 == p3
# p is directed from l to p3
assert p.direction.unit == (p3 - l.projection(p3)).unit
def test_perpendicular_bisector():
s1 = Segment(Point(0, 0), Point(1, 1))
aline = Line(Point(S.Half, S.Half), Point(Rational(3, 2), Rational(-1, 2)))
on_line = Segment(Point(S.Half, S.Half), Point(Rational(3, 2), Rational(-1, 2))).midpoint
assert s1.perpendicular_bisector().equals(aline)
assert s1.perpendicular_bisector(on_line).equals(Segment(s1.midpoint, on_line))
assert s1.perpendicular_bisector(on_line + (1, 0)).equals(aline)
def test_raises():
d, e = symbols('a,b', real=True)
s = Segment((d, 0), (e, 0))
raises(TypeError, lambda: Line((1, 1), 1))
raises(ValueError, lambda: Line(Point(0, 0), Point(0, 0)))
raises(Undecidable, lambda: Point(2 * d, 0) in s)
raises(ValueError, lambda: Ray3D(Point(1.0, 1.0)))
raises(ValueError, lambda: Line3D(Point3D(0, 0, 0), Point3D(0, 0, 0)))
raises(TypeError, lambda: Line3D((1, 1), 1))
raises(ValueError, lambda: Line3D(Point3D(0, 0, 0)))
raises(TypeError, lambda: Ray((1, 1), 1))
raises(GeometryError, lambda: Line(Point(0, 0), Point(1, 0))
.projection(Circle(Point(0, 0), 1)))
def test_ray_generation():
assert Ray((1, 1), angle=pi / 4) == Ray((1, 1), (2, 2))
assert Ray((1, 1), angle=pi / 2) == Ray((1, 1), (1, 2))
assert Ray((1, 1), angle=-pi / 2) == Ray((1, 1), (1, 0))
assert Ray((1, 1), angle=-3 * pi / 2) == Ray((1, 1), (1, 2))
assert Ray((1, 1), angle=5 * pi / 2) == Ray((1, 1), (1, 2))
assert Ray((1, 1), angle=5.0 * pi / 2) == Ray((1, 1), (1, 2))
assert Ray((1, 1), angle=pi) == Ray((1, 1), (0, 1))
assert Ray((1, 1), angle=3.0 * pi) == Ray((1, 1), (0, 1))
assert Ray((1, 1), angle=4.0 * pi) == Ray((1, 1), (2, 1))
assert Ray((1, 1), angle=0) == Ray((1, 1), (2, 1))
assert Ray((1, 1), angle=4.05 * pi) == Ray(Point(1, 1),
Point(2, -sqrt(5) * sqrt(2 * sqrt(5) + 10) / 4 - sqrt(
2 * sqrt(5) + 10) / 4 + 2 + sqrt(5)))
assert Ray((1, 1), angle=4.02 * pi) == Ray(Point(1, 1),
Point(2, 1 + tan(4.02 * pi)))
assert Ray((1, 1), angle=5) == Ray((1, 1), (2, 1 + tan(5)))
assert Ray3D((1, 1, 1), direction_ratio=[4, 4, 4]) == Ray3D(Point3D(1, 1, 1), Point3D(5, 5, 5))
assert Ray3D((1, 1, 1), direction_ratio=[1, 2, 3]) == Ray3D(Point3D(1, 1, 1), Point3D(2, 3, 4))
assert Ray3D((1, 1, 1), direction_ratio=[1, 1, 1]) == Ray3D(Point3D(1, 1, 1), Point3D(2, 2, 2))
def test_issue_7814():
circle = Circle(Point(x, 0), y)
line = Line(Point(k, z), slope=0)
_s = sqrt((y - z)*(y + z))
assert line.intersection(circle) == [Point2D(x + _s, z), Point2D(x - _s, z)]
def test_issue_2941():
def _check():
for f, g in cartes(*[(Line, Ray, Segment)] * 2):
l1 = f(a, b)
l2 = g(c, d)
assert l1.intersection(l2) == l2.intersection(l1)
# intersect at end point
c, d = (-2, -2), (-2, 0)
a, b = (0, 0), (1, 1)
_check()
# midline intersection
c, d = (-2, -3), (-2, 0)
_check()
def test_parameter_value():
t = Symbol('t')
p1, p2 = Point(0, 1), Point(5, 6)
l = Line(p1, p2)
assert l.parameter_value((5, 6), t) == {t: 1}
raises(ValueError, lambda: l.parameter_value((0, 0), t))
def test_bisectors():
r1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))
r2 = Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))
bisections = r1.bisectors(r2)
assert bisections == [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 0)),
Line3D(Point3D(0, 0, 0), Point3D(1, -1, 0))]
ans = [Line3D(Point3D(0, 0, 0), Point3D(1, 0, 1)),
Line3D(Point3D(0, 0, 0), Point3D(-1, 0, 1))]
l1 = (0, 0, 0), (0, 0, 1)
l2 = (0, 0), (1, 0)
for a, b in cartes((Line, Segment, Ray), repeat=2):
assert a(*l1).bisectors(b(*l2)) == ans
def test_issue_8615():
a = Line3D(Point3D(6, 5, 0), Point3D(6, -6, 0))
b = Line3D(Point3D(6, -1, 19/10), Point3D(6, -1, 0))
assert a.intersection(b) == [Point3D(6, -1, 0)]
def test_issue_12598():
r1 = Ray(Point(0, 1), Point(0.98, 0.79).n(2))
r2 = Ray(Point(0, 0), Point(0.71, 0.71).n(2))
assert str(r1.intersection(r2)[0]) == 'Point2D(0.82, 0.82)'
l1 = Line((0, 0), (1, 1))
l2 = Segment((-1, 1), (0, -1)).n(2)
assert str(l1.intersection(l2)[0]) == 'Point2D(-0.33, -0.33)'
l2 = Segment((-1, 1), (-1/2, 1/2)).n(2)
assert not l1.intersection(l2)