test_line.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. from sympy.core.numbers import (Float, Rational, oo, pi)
  2. from sympy.core.relational import Eq
  3. from sympy.core.singleton import S
  4. from sympy.core.symbol import (Symbol, symbols)
  5. from sympy.functions.elementary.miscellaneous import sqrt
  6. from sympy.functions.elementary.trigonometric import (acos, cos, sin)
  7. from sympy.sets import EmptySet
  8. from sympy.simplify.simplify import simplify
  9. from sympy.functions.elementary.trigonometric import tan
  10. from sympy.geometry import (Circle, GeometryError, Line, Point, Ray,
  11. Segment, Triangle, intersection, Point3D, Line3D, Ray3D, Segment3D,
  12. Point2D, Line2D, Plane)
  13. from sympy.geometry.line import Undecidable
  14. from sympy.geometry.polygon import _asa as asa
  15. from sympy.utilities.iterables import cartes
  16. from sympy.testing.pytest import raises, warns
  17. x = Symbol('x', real=True)
  18. y = Symbol('y', real=True)
  19. z = Symbol('z', real=True)
  20. k = Symbol('k', real=True)
  21. x1 = Symbol('x1', real=True)
  22. y1 = Symbol('y1', real=True)
  23. t = Symbol('t', real=True)
  24. a, b = symbols('a,b', real=True)
  25. m = symbols('m', real=True)
  26. def test_object_from_equation():
  27. from sympy.abc import x, y, a, b
  28. assert Line(3*x + y + 18) == Line2D(Point2D(0, -18), Point2D(1, -21))
  29. assert Line(3*x + 5 * y + 1) == Line2D(
  30. Point2D(0, Rational(-1, 5)), Point2D(1, Rational(-4, 5)))
  31. assert Line(3*a + b + 18, x="a", y="b") == Line2D(
  32. Point2D(0, -18), Point2D(1, -21))
  33. assert Line(3*x + y) == Line2D(Point2D(0, 0), Point2D(1, -3))
  34. assert Line(x + y) == Line2D(Point2D(0, 0), Point2D(1, -1))
  35. assert Line(Eq(3*a + b, -18), x="a", y=b) == Line2D(
  36. Point2D(0, -18), Point2D(1, -21))
  37. # issue 22361
  38. assert Line(x - 1) == Line2D(Point2D(1, 0), Point2D(1, 1))
  39. assert Line(2*x - 2, y=x) == Line2D(Point2D(0, 1), Point2D(1, 1))
  40. assert Line(y) == Line2D(Point2D(0, 0), Point2D(1, 0))
  41. assert Line(2*y, x=y) == Line2D(Point2D(0, 0), Point2D(0, 1))
  42. assert Line(y, x=y) == Line2D(Point2D(0, 0), Point2D(0, 1))
  43. raises(ValueError, lambda: Line(x / y))
  44. raises(ValueError, lambda: Line(a / b, x='a', y='b'))
  45. raises(ValueError, lambda: Line(y / x))
  46. raises(ValueError, lambda: Line(b / a, x='a', y='b'))
  47. raises(ValueError, lambda: Line((x + 1)**2 + y))
  48. def feq(a, b):
  49. """Test if two floating point values are 'equal'."""
  50. t_float = Float("1.0E-10")
  51. return -t_float < a - b < t_float
  52. def test_angle_between():
  53. a = Point(1, 2, 3, 4)
  54. b = a.orthogonal_direction
  55. o = a.origin
  56. assert feq(Line.angle_between(Line(Point(0, 0), Point(1, 1)),
  57. Line(Point(0, 0), Point(5, 0))).evalf(), pi.evalf() / 4)
  58. assert Line(a, o).angle_between(Line(b, o)) == pi / 2
  59. z = Point3D(0, 0, 0)
  60. assert Line3D.angle_between(Line3D(z, Point3D(1, 1, 1)),
  61. Line3D(z, Point3D(5, 0, 0))) == acos(sqrt(3) / 3)
  62. # direction of points is used to determine angle
  63. assert Line3D.angle_between(Line3D(z, Point3D(1, 1, 1)),
  64. Line3D(Point3D(5, 0, 0), z)) == acos(-sqrt(3) / 3)
  65. def test_closing_angle():
  66. a = Ray((0, 0), angle=0)
  67. b = Ray((1, 2), angle=pi/2)
  68. assert a.closing_angle(b) == -pi/2
  69. assert b.closing_angle(a) == pi/2
  70. assert a.closing_angle(a) == 0
  71. def test_smallest_angle():
  72. a = Line(Point(1, 1), Point(1, 2))
  73. b = Line(Point(1, 1),Point(2, 3))
  74. assert a.smallest_angle_between(b) == acos(2*sqrt(5)/5)
  75. def test_svg():
  76. a = Line(Point(1, 1),Point(1, 2))
  77. 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)"/>'
  78. a = Segment(Point(1, 0),Point(1, 1))
  79. 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" />'
  80. a = Ray(Point(2, 3), Point(3, 5))
  81. 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)"/>'
  82. def test_arbitrary_point():
  83. l1 = Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1))
  84. l2 = Line(Point(x1, x1), Point(y1, y1))
  85. assert l2.arbitrary_point() in l2
  86. assert Ray((1, 1), angle=pi / 4).arbitrary_point() == \
  87. Point(t + 1, t + 1)
  88. assert Segment((1, 1), (2, 3)).arbitrary_point() == Point(1 + t, 1 + 2 * t)
  89. assert l1.perpendicular_segment(l1.arbitrary_point()) == l1.arbitrary_point()
  90. assert Ray3D((1, 1, 1), direction_ratio=[1, 2, 3]).arbitrary_point() == \
  91. Point3D(t + 1, 2 * t + 1, 3 * t + 1)
  92. assert Segment3D(Point3D(0, 0, 0), Point3D(1, 1, 1)).midpoint == \
  93. Point3D(S.Half, S.Half, S.Half)
  94. assert Segment3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1)).length == sqrt(3) * sqrt((x1 - y1) ** 2)
  95. assert Segment3D((1, 1, 1), (2, 3, 4)).arbitrary_point() == \
  96. Point3D(t + 1, 2 * t + 1, 3 * t + 1)
  97. raises(ValueError, (lambda: Line((x, 1), (2, 3)).arbitrary_point(x)))
  98. def test_are_concurrent_2d():
  99. l1 = Line(Point(0, 0), Point(1, 1))
  100. l2 = Line(Point(x1, x1), Point(x1, 1 + x1))
  101. assert Line.are_concurrent(l1) is False
  102. assert Line.are_concurrent(l1, l2)
  103. assert Line.are_concurrent(l1, l1, l1, l2)
  104. assert Line.are_concurrent(l1, l2, Line(Point(5, x1), Point(Rational(-3, 5), x1)))
  105. assert Line.are_concurrent(l1, Line(Point(0, 0), Point(-x1, x1)), l2) is False
  106. def test_are_concurrent_3d():
  107. p1 = Point3D(0, 0, 0)
  108. l1 = Line(p1, Point3D(1, 1, 1))
  109. parallel_1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))
  110. parallel_2 = Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))
  111. assert Line3D.are_concurrent(l1) is False
  112. assert Line3D.are_concurrent(l1, Line(Point3D(x1, x1, x1), Point3D(y1, y1, y1))) is False
  113. assert Line3D.are_concurrent(l1, Line3D(p1, Point3D(x1, x1, x1)),
  114. Line(Point3D(x1, x1, x1), Point3D(x1, 1 + x1, 1))) is True
  115. assert Line3D.are_concurrent(parallel_1, parallel_2) is False
  116. def test_arguments():
  117. """Functions accepting `Point` objects in `geometry`
  118. should also accept tuples, lists, and generators and
  119. automatically convert them to points."""
  120. from sympy.utilities.iterables import subsets
  121. singles2d = ((1, 2), [1, 3], Point(1, 5))
  122. doubles2d = subsets(singles2d, 2)
  123. l2d = Line(Point2D(1, 2), Point2D(2, 3))
  124. singles3d = ((1, 2, 3), [1, 2, 4], Point(1, 2, 6))
  125. doubles3d = subsets(singles3d, 2)
  126. l3d = Line(Point3D(1, 2, 3), Point3D(1, 1, 2))
  127. singles4d = ((1, 2, 3, 4), [1, 2, 3, 5], Point(1, 2, 3, 7))
  128. doubles4d = subsets(singles4d, 2)
  129. l4d = Line(Point(1, 2, 3, 4), Point(2, 2, 2, 2))
  130. # test 2D
  131. test_single = ['contains', 'distance', 'equals', 'parallel_line', 'perpendicular_line', 'perpendicular_segment',
  132. 'projection', 'intersection']
  133. for p in doubles2d:
  134. Line2D(*p)
  135. for func in test_single:
  136. for p in singles2d:
  137. getattr(l2d, func)(p)
  138. # test 3D
  139. for p in doubles3d:
  140. Line3D(*p)
  141. for func in test_single:
  142. for p in singles3d:
  143. getattr(l3d, func)(p)
  144. # test 4D
  145. for p in doubles4d:
  146. Line(*p)
  147. for func in test_single:
  148. for p in singles4d:
  149. getattr(l4d, func)(p)
  150. def test_basic_properties_2d():
  151. p1 = Point(0, 0)
  152. p2 = Point(1, 1)
  153. p10 = Point(2000, 2000)
  154. p_r3 = Ray(p1, p2).random_point()
  155. p_r4 = Ray(p2, p1).random_point()
  156. l1 = Line(p1, p2)
  157. l3 = Line(Point(x1, x1), Point(x1, 1 + x1))
  158. l4 = Line(p1, Point(1, 0))
  159. r1 = Ray(p1, Point(0, 1))
  160. r2 = Ray(Point(0, 1), p1)
  161. s1 = Segment(p1, p10)
  162. p_s1 = s1.random_point()
  163. assert Line((1, 1), slope=1) == Line((1, 1), (2, 2))
  164. assert Line((1, 1), slope=oo) == Line((1, 1), (1, 2))
  165. assert Line((1, 1), slope=oo).bounds == (1, 1, 1, 2)
  166. assert Line((1, 1), slope=-oo) == Line((1, 1), (1, 2))
  167. assert Line(p1, p2).scale(2, 1) == Line(p1, Point(2, 1))
  168. assert Line(p1, p2) == Line(p1, p2)
  169. assert Line(p1, p2) != Line(p2, p1)
  170. assert l1 != Line(Point(x1, x1), Point(y1, y1))
  171. assert l1 != l3
  172. assert Line(p1, p10) != Line(p10, p1)
  173. assert Line(p1, p10) != p1
  174. assert p1 in l1 # is p1 on the line l1?
  175. assert p1 not in l3
  176. assert s1 in Line(p1, p10)
  177. assert Ray(Point(0, 0), Point(0, 1)) in Ray(Point(0, 0), Point(0, 2))
  178. assert Ray(Point(0, 0), Point(0, 2)) in Ray(Point(0, 0), Point(0, 1))
  179. assert Ray(Point(0, 0), Point(0, 2)).xdirection == S.Zero
  180. assert Ray(Point(0, 0), Point(1, 2)).xdirection == S.Infinity
  181. assert Ray(Point(0, 0), Point(-1, 2)).xdirection == S.NegativeInfinity
  182. assert Ray(Point(0, 0), Point(2, 0)).ydirection == S.Zero
  183. assert Ray(Point(0, 0), Point(2, 2)).ydirection == S.Infinity
  184. assert Ray(Point(0, 0), Point(2, -2)).ydirection == S.NegativeInfinity
  185. assert (r1 in s1) is False
  186. assert Segment(p1, p2) in s1
  187. assert Ray(Point(x1, x1), Point(x1, 1 + x1)) != Ray(p1, Point(-1, 5))
  188. assert Segment(p1, p2).midpoint == Point(S.Half, S.Half)
  189. assert Segment(p1, Point(-x1, x1)).length == sqrt(2 * (x1 ** 2))
  190. assert l1.slope == 1
  191. assert l3.slope is oo
  192. assert l4.slope == 0
  193. assert Line(p1, Point(0, 1)).slope is oo
  194. assert Line(r1.source, r1.random_point()).slope == r1.slope
  195. assert Line(r2.source, r2.random_point()).slope == r2.slope
  196. assert Segment(Point(0, -1), Segment(p1, Point(0, 1)).random_point()).slope == Segment(p1, Point(0, 1)).slope
  197. assert l4.coefficients == (0, 1, 0)
  198. assert Line((-x, x), (-x + 1, x - 1)).coefficients == (1, 1, 0)
  199. assert Line(p1, Point(0, 1)).coefficients == (1, 0, 0)
  200. # issue 7963
  201. r = Ray((0, 0), angle=x)
  202. assert r.subs(x, 3 * pi / 4) == Ray((0, 0), (-1, 1))
  203. assert r.subs(x, 5 * pi / 4) == Ray((0, 0), (-1, -1))
  204. assert r.subs(x, -pi / 4) == Ray((0, 0), (1, -1))
  205. assert r.subs(x, pi / 2) == Ray((0, 0), (0, 1))
  206. assert r.subs(x, -pi / 2) == Ray((0, 0), (0, -1))
  207. for ind in range(0, 5):
  208. assert l3.random_point() in l3
  209. assert p_r3.x >= p1.x and p_r3.y >= p1.y
  210. assert p_r4.x <= p2.x and p_r4.y <= p2.y
  211. assert p1.x <= p_s1.x <= p10.x and p1.y <= p_s1.y <= p10.y
  212. assert hash(s1) != hash(Segment(p10, p1))
  213. assert s1.plot_interval() == [t, 0, 1]
  214. assert Line(p1, p10).plot_interval() == [t, -5, 5]
  215. assert Ray((0, 0), angle=pi / 4).plot_interval() == [t, 0, 10]
  216. def test_basic_properties_3d():
  217. p1 = Point3D(0, 0, 0)
  218. p2 = Point3D(1, 1, 1)
  219. p3 = Point3D(x1, x1, x1)
  220. p5 = Point3D(x1, 1 + x1, 1)
  221. l1 = Line3D(p1, p2)
  222. l3 = Line3D(p3, p5)
  223. r1 = Ray3D(p1, Point3D(-1, 5, 0))
  224. r3 = Ray3D(p1, p2)
  225. s1 = Segment3D(p1, p2)
  226. assert Line3D((1, 1, 1), direction_ratio=[2, 3, 4]) == Line3D(Point3D(1, 1, 1), Point3D(3, 4, 5))
  227. assert Line3D((1, 1, 1), direction_ratio=[1, 5, 7]) == Line3D(Point3D(1, 1, 1), Point3D(2, 6, 8))
  228. assert Line3D((1, 1, 1), direction_ratio=[1, 2, 3]) == Line3D(Point3D(1, 1, 1), Point3D(2, 3, 4))
  229. assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).direction_cosine == [1, 0, 0]
  230. assert Line3D(Line3D(p1, Point3D(0, 1, 0))) == Line3D(p1, Point3D(0, 1, 0))
  231. assert Ray3D(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))) == Ray3D(p1, Point3D(1, 0, 0))
  232. assert Line3D(p1, p2) != Line3D(p2, p1)
  233. assert l1 != l3
  234. assert l1 != Line3D(p3, Point3D(y1, y1, y1))
  235. assert r3 != r1
  236. assert Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 1)) in Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2))
  237. assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)) in Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 1))
  238. assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).xdirection == S.Infinity
  239. assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).ydirection == S.Infinity
  240. assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).zdirection == S.Infinity
  241. assert Ray3D(Point3D(0, 0, 0), Point3D(-2, 2, 2)).xdirection == S.NegativeInfinity
  242. assert Ray3D(Point3D(0, 0, 0), Point3D(2, -2, 2)).ydirection == S.NegativeInfinity
  243. assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, -2)).zdirection == S.NegativeInfinity
  244. assert Ray3D(Point3D(0, 0, 0), Point3D(0, 2, 2)).xdirection == S.Zero
  245. assert Ray3D(Point3D(0, 0, 0), Point3D(2, 0, 2)).ydirection == S.Zero
  246. assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 0)).zdirection == S.Zero
  247. assert p1 in l1
  248. assert p1 not in l3
  249. assert l1.direction_ratio == [1, 1, 1]
  250. assert s1.midpoint == Point3D(S.Half, S.Half, S.Half)
  251. # Test zdirection
  252. assert Ray3D(p1, Point3D(0, 0, -1)).zdirection is S.NegativeInfinity
  253. def test_contains():
  254. p1 = Point(0, 0)
  255. r = Ray(p1, Point(4, 4))
  256. r1 = Ray3D(p1, Point3D(0, 0, -1))
  257. r2 = Ray3D(p1, Point3D(0, 1, 0))
  258. r3 = Ray3D(p1, Point3D(0, 0, 1))
  259. l = Line(Point(0, 1), Point(3, 4))
  260. # Segment contains
  261. assert Point(0, (a + b) / 2) in Segment((0, a), (0, b))
  262. assert Point((a + b) / 2, 0) in Segment((a, 0), (b, 0))
  263. assert Point3D(0, 1, 0) in Segment3D((0, 1, 0), (0, 1, 0))
  264. assert Point3D(1, 0, 0) in Segment3D((1, 0, 0), (1, 0, 0))
  265. assert Segment3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).contains([]) is True
  266. assert Segment3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).contains(
  267. Segment3D(Point3D(2, 2, 2), Point3D(3, 2, 2))) is False
  268. # Line contains
  269. assert l.contains(Point(0, 1)) is True
  270. assert l.contains((0, 1)) is True
  271. assert l.contains((0, 0)) is False
  272. # Ray contains
  273. assert r.contains(p1) is True
  274. assert r.contains((1, 1)) is True
  275. assert r.contains((1, 3)) is False
  276. assert r.contains(Segment((1, 1), (2, 2))) is True
  277. assert r.contains(Segment((1, 2), (2, 5))) is False
  278. assert r.contains(Ray((2, 2), (3, 3))) is True
  279. assert r.contains(Ray((2, 2), (3, 5))) is False
  280. assert r1.contains(Segment3D(p1, Point3D(0, 0, -10))) is True
  281. assert r1.contains(Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))) is False
  282. assert r2.contains(Point3D(0, 0, 0)) is True
  283. assert r3.contains(Point3D(0, 0, 0)) is True
  284. assert Ray3D(Point3D(1, 1, 1), Point3D(1, 0, 0)).contains([]) is False
  285. assert Line3D((0, 0, 0), (x, y, z)).contains((2 * x, 2 * y, 2 * z))
  286. with warns(UserWarning, test_stacklevel=False):
  287. assert Line3D(p1, Point3D(0, 1, 0)).contains(Point(1.0, 1.0)) is False
  288. with warns(UserWarning, test_stacklevel=False):
  289. assert r3.contains(Point(1.0, 1.0)) is False
  290. def test_contains_nonreal_symbols():
  291. u, v, w, z = symbols('u, v, w, z')
  292. l = Segment(Point(u, w), Point(v, z))
  293. p = Point(u*Rational(2, 3) + v/3, w*Rational(2, 3) + z/3)
  294. assert l.contains(p)
  295. def test_distance_2d():
  296. p1 = Point(0, 0)
  297. p2 = Point(1, 1)
  298. half = S.Half
  299. s1 = Segment(Point(0, 0), Point(1, 1))
  300. s2 = Segment(Point(half, half), Point(1, 0))
  301. r = Ray(p1, p2)
  302. assert s1.distance(Point(0, 0)) == 0
  303. assert s1.distance((0, 0)) == 0
  304. assert s2.distance(Point(0, 0)) == 2 ** half / 2
  305. assert s2.distance(Point(Rational(3) / 2, Rational(3) / 2)) == 2 ** half
  306. assert Line(p1, p2).distance(Point(-1, 1)) == sqrt(2)
  307. assert Line(p1, p2).distance(Point(1, -1)) == sqrt(2)
  308. assert Line(p1, p2).distance(Point(2, 2)) == 0
  309. assert Line(p1, p2).distance((-1, 1)) == sqrt(2)
  310. assert Line((0, 0), (0, 1)).distance(p1) == 0
  311. assert Line((0, 0), (0, 1)).distance(p2) == 1
  312. assert Line((0, 0), (1, 0)).distance(p1) == 0
  313. assert Line((0, 0), (1, 0)).distance(p2) == 1
  314. assert r.distance(Point(-1, -1)) == sqrt(2)
  315. assert r.distance(Point(1, 1)) == 0
  316. assert r.distance(Point(-1, 1)) == sqrt(2)
  317. assert Ray((1, 1), (2, 2)).distance(Point(1.5, 3)) == 3 * sqrt(2) / 4
  318. assert r.distance((1, 1)) == 0
  319. def test_dimension_normalization():
  320. with warns(UserWarning, test_stacklevel=False):
  321. assert Ray((1, 1), (2, 1, 2)) == Ray((1, 1, 0), (2, 1, 2))
  322. def test_distance_3d():
  323. p1, p2 = Point3D(0, 0, 0), Point3D(1, 1, 1)
  324. p3 = Point3D(Rational(3) / 2, Rational(3) / 2, Rational(3) / 2)
  325. s1 = Segment3D(Point3D(0, 0, 0), Point3D(1, 1, 1))
  326. s2 = Segment3D(Point3D(S.Half, S.Half, S.Half), Point3D(1, 0, 1))
  327. r = Ray3D(p1, p2)
  328. assert s1.distance(p1) == 0
  329. assert s2.distance(p1) == sqrt(3) / 2
  330. assert s2.distance(p3) == 2 * sqrt(6) / 3
  331. assert s1.distance((0, 0, 0)) == 0
  332. assert s2.distance((0, 0, 0)) == sqrt(3) / 2
  333. assert s1.distance(p1) == 0
  334. assert s2.distance(p1) == sqrt(3) / 2
  335. assert s2.distance(p3) == 2 * sqrt(6) / 3
  336. assert s1.distance((0, 0, 0)) == 0
  337. assert s2.distance((0, 0, 0)) == sqrt(3) / 2
  338. # Line to point
  339. assert Line3D(p1, p2).distance(Point3D(-1, 1, 1)) == 2 * sqrt(6) / 3
  340. assert Line3D(p1, p2).distance(Point3D(1, -1, 1)) == 2 * sqrt(6) / 3
  341. assert Line3D(p1, p2).distance(Point3D(2, 2, 2)) == 0
  342. assert Line3D(p1, p2).distance((2, 2, 2)) == 0
  343. assert Line3D(p1, p2).distance((1, -1, 1)) == 2 * sqrt(6) / 3
  344. assert Line3D((0, 0, 0), (0, 1, 0)).distance(p1) == 0
  345. assert Line3D((0, 0, 0), (0, 1, 0)).distance(p2) == sqrt(2)
  346. assert Line3D((0, 0, 0), (1, 0, 0)).distance(p1) == 0
  347. assert Line3D((0, 0, 0), (1, 0, 0)).distance(p2) == sqrt(2)
  348. # Line to line
  349. assert Line3D((0, 0, 0), (1, 0, 0)).distance(Line3D((0, 0, 0), (0, 1, 2))) == 0
  350. assert Line3D((0, 0, 0), (1, 0, 0)).distance(Line3D((0, 0, 0), (1, 0, 0))) == 0
  351. assert Line3D((0, 0, 0), (1, 0, 0)).distance(Line3D((10, 0, 0), (10, 1, 2))) == 0
  352. assert Line3D((0, 0, 0), (1, 0, 0)).distance(Line3D((0, 1, 0), (0, 1, 1))) == 1
  353. # Line to plane
  354. assert Line3D((0, 0, 0), (1, 0, 0)).distance(Plane((2, 0, 0), (0, 0, 1))) == 0
  355. assert Line3D((0, 0, 0), (1, 0, 0)).distance(Plane((0, 1, 0), (0, 1, 0))) == 1
  356. assert Line3D((0, 0, 0), (1, 0, 0)).distance(Plane((1, 1, 3), (1, 0, 0))) == 0
  357. # Ray to point
  358. assert r.distance(Point3D(-1, -1, -1)) == sqrt(3)
  359. assert r.distance(Point3D(1, 1, 1)) == 0
  360. assert r.distance((-1, -1, -1)) == sqrt(3)
  361. assert r.distance((1, 1, 1)) == 0
  362. assert Ray3D((0, 0, 0), (1, 1, 2)).distance((-1, -1, 2)) == 4 * sqrt(3) / 3
  363. assert Ray3D((1, 1, 1), (2, 2, 2)).distance(Point3D(1.5, -3, -1)) == Rational(9) / 2
  364. assert Ray3D((1, 1, 1), (2, 2, 2)).distance(Point3D(1.5, 3, 1)) == sqrt(78) / 6
  365. def test_equals():
  366. p1 = Point(0, 0)
  367. p2 = Point(1, 1)
  368. l1 = Line(p1, p2)
  369. l2 = Line((0, 5), slope=m)
  370. l3 = Line(Point(x1, x1), Point(x1, 1 + x1))
  371. assert l1.perpendicular_line(p1.args).equals(Line(Point(0, 0), Point(1, -1)))
  372. assert l1.perpendicular_line(p1).equals(Line(Point(0, 0), Point(1, -1)))
  373. assert Line(Point(x1, x1), Point(y1, y1)).parallel_line(Point(-x1, x1)). \
  374. equals(Line(Point(-x1, x1), Point(-y1, 2 * x1 - y1)))
  375. assert l3.parallel_line(p1.args).equals(Line(Point(0, 0), Point(0, -1)))
  376. assert l3.parallel_line(p1).equals(Line(Point(0, 0), Point(0, -1)))
  377. assert (l2.distance(Point(2, 3)) - 2 * abs(m + 1) / sqrt(m ** 2 + 1)).equals(0)
  378. assert Line3D(p1, Point3D(0, 1, 0)).equals(Point(1.0, 1.0)) is False
  379. assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).equals(Line3D(Point3D(-5, 0, 0), Point3D(-1, 0, 0))) is True
  380. assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).equals(Line3D(p1, Point3D(0, 1, 0))) is False
  381. assert Ray3D(p1, Point3D(0, 0, -1)).equals(Point(1.0, 1.0)) is False
  382. assert Ray3D(p1, Point3D(0, 0, -1)).equals(Ray3D(p1, Point3D(0, 0, -1))) is True
  383. assert Line3D((0, 0), (t, t)).perpendicular_line(Point(0, 1, 0)).equals(
  384. Line3D(Point3D(0, 1, 0), Point3D(S.Half, S.Half, 0)))
  385. assert Line3D((0, 0), (t, t)).perpendicular_segment(Point(0, 1, 0)).equals(Segment3D((0, 1), (S.Half, S.Half)))
  386. assert Line3D(p1, Point3D(0, 1, 0)).equals(Point(1.0, 1.0)) is False
  387. def test_equation():
  388. p1 = Point(0, 0)
  389. p2 = Point(1, 1)
  390. l1 = Line(p1, p2)
  391. l3 = Line(Point(x1, x1), Point(x1, 1 + x1))
  392. assert simplify(l1.equation()) in (x - y, y - x)
  393. assert simplify(l3.equation()) in (x - x1, x1 - x)
  394. assert simplify(l1.equation()) in (x - y, y - x)
  395. assert simplify(l3.equation()) in (x - x1, x1 - x)
  396. assert Line(p1, Point(1, 0)).equation(x=x, y=y) == y
  397. assert Line(p1, Point(0, 1)).equation() == x
  398. assert Line(Point(2, 0), Point(2, 1)).equation() == x - 2
  399. assert Line(p2, Point(2, 1)).equation() == y - 1
  400. assert Line3D(Point(x1, x1, x1), Point(y1, y1, y1)
  401. ).equation() == (-x + y, -x + z)
  402. assert Line3D(Point(1, 2, 3), Point(2, 3, 4)
  403. ).equation() == (-x + y - 1, -x + z - 2)
  404. assert Line3D(Point(1, 2, 3), Point(1, 3, 4)
  405. ).equation() == (x - 1, -y + z - 1)
  406. assert Line3D(Point(1, 2, 3), Point(2, 2, 4)
  407. ).equation() == (y - 2, -x + z - 2)
  408. assert Line3D(Point(1, 2, 3), Point(2, 3, 3)
  409. ).equation() == (-x + y - 1, z - 3)
  410. assert Line3D(Point(1, 2, 3), Point(1, 2, 4)
  411. ).equation() == (x - 1, y - 2)
  412. assert Line3D(Point(1, 2, 3), Point(1, 3, 3)
  413. ).equation() == (x - 1, z - 3)
  414. assert Line3D(Point(1, 2, 3), Point(2, 2, 3)
  415. ).equation() == (y - 2, z - 3)
  416. def test_intersection_2d():
  417. p1 = Point(0, 0)
  418. p2 = Point(1, 1)
  419. p3 = Point(x1, x1)
  420. p4 = Point(y1, y1)
  421. l1 = Line(p1, p2)
  422. l3 = Line(Point(0, 0), Point(3, 4))
  423. r1 = Ray(Point(1, 1), Point(2, 2))
  424. r2 = Ray(Point(0, 0), Point(3, 4))
  425. r4 = Ray(p1, p2)
  426. r6 = Ray(Point(0, 1), Point(1, 2))
  427. r7 = Ray(Point(0.5, 0.5), Point(1, 1))
  428. s1 = Segment(p1, p2)
  429. s2 = Segment(Point(0.25, 0.25), Point(0.5, 0.5))
  430. s3 = Segment(Point(0, 0), Point(3, 4))
  431. assert intersection(l1, p1) == [p1]
  432. assert intersection(l1, Point(x1, 1 + x1)) == []
  433. assert intersection(l1, Line(p3, p4)) in [[l1], [Line(p3, p4)]]
  434. assert intersection(l1, l1.parallel_line(Point(x1, 1 + x1))) == []
  435. assert intersection(l3, l3) == [l3]
  436. assert intersection(l3, r2) == [r2]
  437. assert intersection(l3, s3) == [s3]
  438. assert intersection(s3, l3) == [s3]
  439. assert intersection(Segment(Point(-10, 10), Point(10, 10)), Segment(Point(-5, -5), Point(-5, 5))) == []
  440. assert intersection(r2, l3) == [r2]
  441. assert intersection(r1, Ray(Point(2, 2), Point(0, 0))) == [Segment(Point(1, 1), Point(2, 2))]
  442. assert intersection(r1, Ray(Point(1, 1), Point(-1, -1))) == [Point(1, 1)]
  443. assert intersection(r1, Segment(Point(0, 0), Point(2, 2))) == [Segment(Point(1, 1), Point(2, 2))]
  444. assert r4.intersection(s2) == [s2]
  445. assert r4.intersection(Segment(Point(2, 3), Point(3, 4))) == []
  446. assert r4.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))]
  447. assert r4.intersection(Ray(p2, p1)) == [s1]
  448. assert Ray(p2, p1).intersection(r6) == []
  449. assert r4.intersection(r7) == r7.intersection(r4) == [r7]
  450. assert Ray3D((0, 0), (3, 0)).intersection(Ray3D((1, 0), (3, 0))) == [Ray3D((1, 0), (3, 0))]
  451. assert Ray3D((1, 0), (3, 0)).intersection(Ray3D((0, 0), (3, 0))) == [Ray3D((1, 0), (3, 0))]
  452. assert Ray(Point(0, 0), Point(0, 4)).intersection(Ray(Point(0, 1), Point(0, -1))) == \
  453. [Segment(Point(0, 0), Point(0, 1))]
  454. assert Segment3D((0, 0), (3, 0)).intersection(
  455. Segment3D((1, 0), (2, 0))) == [Segment3D((1, 0), (2, 0))]
  456. assert Segment3D((1, 0), (2, 0)).intersection(
  457. Segment3D((0, 0), (3, 0))) == [Segment3D((1, 0), (2, 0))]
  458. assert Segment3D((0, 0), (3, 0)).intersection(
  459. Segment3D((3, 0), (4, 0))) == [Point3D((3, 0))]
  460. assert Segment3D((0, 0), (3, 0)).intersection(
  461. Segment3D((2, 0), (5, 0))) == [Segment3D((2, 0), (3, 0))]
  462. assert Segment3D((0, 0), (3, 0)).intersection(
  463. Segment3D((-2, 0), (1, 0))) == [Segment3D((0, 0), (1, 0))]
  464. assert Segment3D((0, 0), (3, 0)).intersection(
  465. Segment3D((-2, 0), (0, 0))) == [Point3D(0, 0)]
  466. assert s1.intersection(Segment(Point(1, 1), Point(2, 2))) == [Point(1, 1)]
  467. assert s1.intersection(Segment(Point(0.5, 0.5), Point(1.5, 1.5))) == [Segment(Point(0.5, 0.5), p2)]
  468. assert s1.intersection(Segment(Point(4, 4), Point(5, 5))) == []
  469. assert s1.intersection(Segment(Point(-1, -1), p1)) == [p1]
  470. assert s1.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))]
  471. assert s1.intersection(Line(Point(1, 0), Point(2, 1))) == []
  472. assert s1.intersection(s2) == [s2]
  473. assert s2.intersection(s1) == [s2]
  474. assert asa(120, 8, 52) == \
  475. Triangle(
  476. Point(0, 0),
  477. Point(8, 0),
  478. Point(-4 * cos(19 * pi / 90) / sin(2 * pi / 45),
  479. 4 * sqrt(3) * cos(19 * pi / 90) / sin(2 * pi / 45)))
  480. assert Line((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == [Point(1, 1)]
  481. assert Line((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == [Point(1, 1)]
  482. assert Ray((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == [Point(1, 1)]
  483. assert Ray((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == [Point(1, 1)]
  484. assert Ray((0, 0), (10, 10)).contains(Segment((1, 1), (2, 2))) is True
  485. assert Segment((1, 1), (2, 2)) in Line((0, 0), (10, 10))
  486. assert s1.intersection(Ray((1, 1), (4, 4))) == [Point(1, 1)]
  487. # This test is disabled because it hangs after rref changes which simplify
  488. # intermediate results and return a different representation from when the
  489. # test was written.
  490. # # 16628 - this should be fast
  491. # p0 = Point2D(Rational(249, 5), Rational(497999, 10000))
  492. # p1 = Point2D((-58977084786*sqrt(405639795226) + 2030690077184193 +
  493. # 20112207807*sqrt(630547164901) + 99600*sqrt(255775022850776494562626))
  494. # /(2000*sqrt(255775022850776494562626) + 1991998000*sqrt(405639795226)
  495. # + 1991998000*sqrt(630547164901) + 1622561172902000),
  496. # (-498000*sqrt(255775022850776494562626) - 995999*sqrt(630547164901) +
  497. # 90004251917891999 +
  498. # 496005510002*sqrt(405639795226))/(10000*sqrt(255775022850776494562626)
  499. # + 9959990000*sqrt(405639795226) + 9959990000*sqrt(630547164901) +
  500. # 8112805864510000))
  501. # p2 = Point2D(Rational(497, 10), Rational(-497, 10))
  502. # p3 = Point2D(Rational(-497, 10), Rational(-497, 10))
  503. # l = Line(p0, p1)
  504. # s = Segment(p2, p3)
  505. # n = (-52673223862*sqrt(405639795226) - 15764156209307469 -
  506. # 9803028531*sqrt(630547164901) +
  507. # 33200*sqrt(255775022850776494562626))
  508. # d = sqrt(405639795226) + 315274080450 + 498000*sqrt(
  509. # 630547164901) + sqrt(255775022850776494562626)
  510. # assert intersection(l, s) == [
  511. # Point2D(n/d*Rational(3, 2000), Rational(-497, 10))]
  512. def test_line_intersection():
  513. # see also test_issue_11238 in test_matrices.py
  514. x0 = tan(pi*Rational(13, 45))
  515. x1 = sqrt(3)
  516. x2 = x0**2
  517. x, y = [8*x0/(x0 + x1), (24*x0 - 8*x1*x2)/(x2 - 3)]
  518. assert Line(Point(0, 0), Point(1, -sqrt(3))).contains(Point(x, y)) is True
  519. def test_intersection_3d():
  520. p1 = Point3D(0, 0, 0)
  521. p2 = Point3D(1, 1, 1)
  522. l1 = Line3D(p1, p2)
  523. l2 = Line3D(Point3D(0, 0, 0), Point3D(3, 4, 0))
  524. r1 = Ray3D(Point3D(1, 1, 1), Point3D(2, 2, 2))
  525. r2 = Ray3D(Point3D(0, 0, 0), Point3D(3, 4, 0))
  526. s1 = Segment3D(Point3D(0, 0, 0), Point3D(3, 4, 0))
  527. assert intersection(l1, p1) == [p1]
  528. assert intersection(l1, Point3D(x1, 1 + x1, 1)) == []
  529. assert intersection(l1, l1.parallel_line(p1)) == [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1))]
  530. assert intersection(l2, r2) == [r2]
  531. assert intersection(l2, s1) == [s1]
  532. assert intersection(r2, l2) == [r2]
  533. assert intersection(r1, Ray3D(Point3D(1, 1, 1), Point3D(-1, -1, -1))) == [Point3D(1, 1, 1)]
  534. assert intersection(r1, Segment3D(Point3D(0, 0, 0), Point3D(2, 2, 2))) == [
  535. Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))]
  536. assert intersection(Ray3D(Point3D(1, 0, 0), Point3D(-1, 0, 0)), Ray3D(Point3D(0, 1, 0), Point3D(0, -1, 0))) \
  537. == [Point3D(0, 0, 0)]
  538. assert intersection(r1, Ray3D(Point3D(2, 2, 2), Point3D(0, 0, 0))) == \
  539. [Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))]
  540. assert intersection(s1, r2) == [s1]
  541. assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).intersection(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) == \
  542. [Point3D(2, 2, 1)]
  543. assert Line3D((0, 1, 2), (0, 2, 3)).intersection(Line3D((0, 1, 2), (0, 1, 1))) == [Point3D(0, 1, 2)]
  544. assert Line3D((0, 0), (t, t)).intersection(Line3D((0, 1), (t, t))) == \
  545. [Point3D(t, t)]
  546. assert Ray3D(Point3D(0, 0, 0), Point3D(0, 4, 0)).intersection(Ray3D(Point3D(0, 1, 1), Point3D(0, -1, 1))) == []
  547. def test_is_parallel():
  548. p1 = Point3D(0, 0, 0)
  549. p2 = Point3D(1, 1, 1)
  550. p3 = Point3D(x1, x1, x1)
  551. l2 = Line(Point(x1, x1), Point(y1, y1))
  552. l2_1 = Line(Point(x1, x1), Point(x1, 1 + x1))
  553. assert Line.is_parallel(Line(Point(0, 0), Point(1, 1)), l2)
  554. assert Line.is_parallel(l2, Line(Point(x1, x1), Point(x1, 1 + x1))) is False
  555. assert Line.is_parallel(l2, l2.parallel_line(Point(-x1, x1)))
  556. assert Line.is_parallel(l2_1, l2_1.parallel_line(Point(0, 0)))
  557. assert Line3D(p1, p2).is_parallel(Line3D(p1, p2)) # same as in 2D
  558. assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).is_parallel(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) is False
  559. assert Line3D(p1, p2).parallel_line(p3) == Line3D(Point3D(x1, x1, x1),
  560. Point3D(x1 + 1, x1 + 1, x1 + 1))
  561. assert Line3D(p1, p2).parallel_line(p3.args) == \
  562. Line3D(Point3D(x1, x1, x1), Point3D(x1 + 1, x1 + 1, x1 + 1))
  563. assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).is_parallel(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) is False
  564. def test_is_perpendicular():
  565. p1 = Point(0, 0)
  566. p2 = Point(1, 1)
  567. l1 = Line(p1, p2)
  568. l2 = Line(Point(x1, x1), Point(y1, y1))
  569. l1_1 = Line(p1, Point(-x1, x1))
  570. # 2D
  571. assert Line.is_perpendicular(l1, l1_1)
  572. assert Line.is_perpendicular(l1, l2) is False
  573. p = l1.random_point()
  574. assert l1.perpendicular_segment(p) == p
  575. # 3D
  576. assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)),
  577. Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))) is True
  578. assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)),
  579. Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))) is False
  580. assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)),
  581. Line3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1))) is False
  582. def test_is_similar():
  583. p1 = Point(2000, 2000)
  584. p2 = p1.scale(2, 2)
  585. r1 = Ray3D(Point3D(1, 1, 1), Point3D(1, 0, 0))
  586. r2 = Ray(Point(0, 0), Point(0, 1))
  587. s1 = Segment(Point(0, 0), p1)
  588. assert s1.is_similar(Segment(p1, p2))
  589. assert s1.is_similar(r2) is False
  590. assert r1.is_similar(Line3D(Point3D(1, 1, 1), Point3D(1, 0, 0))) is True
  591. assert r1.is_similar(Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))) is False
  592. def test_length():
  593. s2 = Segment3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1))
  594. assert Line(Point(0, 0), Point(1, 1)).length is oo
  595. assert s2.length == sqrt(3) * sqrt((x1 - y1) ** 2)
  596. assert Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)).length is oo
  597. def test_projection():
  598. p1 = Point(0, 0)
  599. p2 = Point3D(0, 0, 0)
  600. p3 = Point(-x1, x1)
  601. l1 = Line(p1, Point(1, 1))
  602. l2 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))
  603. l3 = Line3D(p2, Point3D(1, 1, 1))
  604. r1 = Ray(Point(1, 1), Point(2, 2))
  605. s1 = Segment(Point2D(0, 0), Point2D(0, 1))
  606. s2 = Segment(Point2D(1, 0), Point2D(2, 1/2))
  607. assert Line(Point(x1, x1), Point(y1, y1)).projection(Point(y1, y1)) == Point(y1, y1)
  608. assert Line(Point(x1, x1), Point(x1, 1 + x1)).projection(Point(1, 1)) == Point(x1, 1)
  609. assert Segment(Point(-2, 2), Point(0, 4)).projection(r1) == Segment(Point(-1, 3), Point(0, 4))
  610. assert Segment(Point(0, 4), Point(-2, 2)).projection(r1) == Segment(Point(0, 4), Point(-1, 3))
  611. assert s2.projection(s1) == EmptySet
  612. assert l1.projection(p3) == p1
  613. assert l1.projection(Ray(p1, Point(-1, 5))) == Ray(Point(0, 0), Point(2, 2))
  614. assert l1.projection(Ray(p1, Point(-1, 1))) == p1
  615. assert r1.projection(Ray(Point(1, 1), Point(-1, -1))) == Point(1, 1)
  616. assert r1.projection(Ray(Point(0, 4), Point(-1, -5))) == Segment(Point(1, 1), Point(2, 2))
  617. assert r1.projection(Segment(Point(-1, 5), Point(-5, -10))) == Segment(Point(1, 1), Point(2, 2))
  618. assert r1.projection(Ray(Point(1, 1), Point(-1, -1))) == Point(1, 1)
  619. assert r1.projection(Ray(Point(0, 4), Point(-1, -5))) == Segment(Point(1, 1), Point(2, 2))
  620. assert r1.projection(Segment(Point(-1, 5), Point(-5, -10))) == Segment(Point(1, 1), Point(2, 2))
  621. assert l3.projection(Ray3D(p2, Point3D(-1, 5, 0))) == Ray3D(Point3D(0, 0, 0), Point3D(Rational(4, 3), Rational(4, 3), Rational(4, 3)))
  622. assert l3.projection(Ray3D(p2, Point3D(-1, 1, 1))) == Ray3D(Point3D(0, 0, 0), Point3D(Rational(1, 3), Rational(1, 3), Rational(1, 3)))
  623. assert l2.projection(Point3D(5, 5, 0)) == Point3D(5, 0)
  624. assert l2.projection(Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))).equals(l2)
  625. def test_perpendicular_line():
  626. # 3d - requires a particular orthogonal to be selected
  627. p1, p2, p3 = Point(0, 0, 0), Point(2, 3, 4), Point(-2, 2, 0)
  628. l = Line(p1, p2)
  629. p = l.perpendicular_line(p3)
  630. assert p.p1 == p3
  631. assert p.p2 in l
  632. # 2d - does not require special selection
  633. p1, p2, p3 = Point(0, 0), Point(2, 3), Point(-2, 2)
  634. l = Line(p1, p2)
  635. p = l.perpendicular_line(p3)
  636. assert p.p1 == p3
  637. # p is directed from l to p3
  638. assert p.direction.unit == (p3 - l.projection(p3)).unit
  639. def test_perpendicular_bisector():
  640. s1 = Segment(Point(0, 0), Point(1, 1))
  641. aline = Line(Point(S.Half, S.Half), Point(Rational(3, 2), Rational(-1, 2)))
  642. on_line = Segment(Point(S.Half, S.Half), Point(Rational(3, 2), Rational(-1, 2))).midpoint
  643. assert s1.perpendicular_bisector().equals(aline)
  644. assert s1.perpendicular_bisector(on_line).equals(Segment(s1.midpoint, on_line))
  645. assert s1.perpendicular_bisector(on_line + (1, 0)).equals(aline)
  646. def test_raises():
  647. d, e = symbols('a,b', real=True)
  648. s = Segment((d, 0), (e, 0))
  649. raises(TypeError, lambda: Line((1, 1), 1))
  650. raises(ValueError, lambda: Line(Point(0, 0), Point(0, 0)))
  651. raises(Undecidable, lambda: Point(2 * d, 0) in s)
  652. raises(ValueError, lambda: Ray3D(Point(1.0, 1.0)))
  653. raises(ValueError, lambda: Line3D(Point3D(0, 0, 0), Point3D(0, 0, 0)))
  654. raises(TypeError, lambda: Line3D((1, 1), 1))
  655. raises(ValueError, lambda: Line3D(Point3D(0, 0, 0)))
  656. raises(TypeError, lambda: Ray((1, 1), 1))
  657. raises(GeometryError, lambda: Line(Point(0, 0), Point(1, 0))
  658. .projection(Circle(Point(0, 0), 1)))
  659. def test_ray_generation():
  660. assert Ray((1, 1), angle=pi / 4) == Ray((1, 1), (2, 2))
  661. assert Ray((1, 1), angle=pi / 2) == Ray((1, 1), (1, 2))
  662. assert Ray((1, 1), angle=-pi / 2) == Ray((1, 1), (1, 0))
  663. assert Ray((1, 1), angle=-3 * pi / 2) == Ray((1, 1), (1, 2))
  664. assert Ray((1, 1), angle=5 * pi / 2) == Ray((1, 1), (1, 2))
  665. assert Ray((1, 1), angle=5.0 * pi / 2) == Ray((1, 1), (1, 2))
  666. assert Ray((1, 1), angle=pi) == Ray((1, 1), (0, 1))
  667. assert Ray((1, 1), angle=3.0 * pi) == Ray((1, 1), (0, 1))
  668. assert Ray((1, 1), angle=4.0 * pi) == Ray((1, 1), (2, 1))
  669. assert Ray((1, 1), angle=0) == Ray((1, 1), (2, 1))
  670. assert Ray((1, 1), angle=4.05 * pi) == Ray(Point(1, 1),
  671. Point(2, -sqrt(5) * sqrt(2 * sqrt(5) + 10) / 4 - sqrt(
  672. 2 * sqrt(5) + 10) / 4 + 2 + sqrt(5)))
  673. assert Ray((1, 1), angle=4.02 * pi) == Ray(Point(1, 1),
  674. Point(2, 1 + tan(4.02 * pi)))
  675. assert Ray((1, 1), angle=5) == Ray((1, 1), (2, 1 + tan(5)))
  676. assert Ray3D((1, 1, 1), direction_ratio=[4, 4, 4]) == Ray3D(Point3D(1, 1, 1), Point3D(5, 5, 5))
  677. assert Ray3D((1, 1, 1), direction_ratio=[1, 2, 3]) == Ray3D(Point3D(1, 1, 1), Point3D(2, 3, 4))
  678. assert Ray3D((1, 1, 1), direction_ratio=[1, 1, 1]) == Ray3D(Point3D(1, 1, 1), Point3D(2, 2, 2))
  679. def test_issue_7814():
  680. circle = Circle(Point(x, 0), y)
  681. line = Line(Point(k, z), slope=0)
  682. _s = sqrt((y - z)*(y + z))
  683. assert line.intersection(circle) == [Point2D(x + _s, z), Point2D(x - _s, z)]
  684. def test_issue_2941():
  685. def _check():
  686. for f, g in cartes(*[(Line, Ray, Segment)] * 2):
  687. l1 = f(a, b)
  688. l2 = g(c, d)
  689. assert l1.intersection(l2) == l2.intersection(l1)
  690. # intersect at end point
  691. c, d = (-2, -2), (-2, 0)
  692. a, b = (0, 0), (1, 1)
  693. _check()
  694. # midline intersection
  695. c, d = (-2, -3), (-2, 0)
  696. _check()
  697. def test_parameter_value():
  698. t = Symbol('t')
  699. p1, p2 = Point(0, 1), Point(5, 6)
  700. l = Line(p1, p2)
  701. assert l.parameter_value((5, 6), t) == {t: 1}
  702. raises(ValueError, lambda: l.parameter_value((0, 0), t))
  703. def test_bisectors():
  704. r1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))
  705. r2 = Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))
  706. bisections = r1.bisectors(r2)
  707. assert bisections == [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 0)),
  708. Line3D(Point3D(0, 0, 0), Point3D(1, -1, 0))]
  709. ans = [Line3D(Point3D(0, 0, 0), Point3D(1, 0, 1)),
  710. Line3D(Point3D(0, 0, 0), Point3D(-1, 0, 1))]
  711. l1 = (0, 0, 0), (0, 0, 1)
  712. l2 = (0, 0), (1, 0)
  713. for a, b in cartes((Line, Segment, Ray), repeat=2):
  714. assert a(*l1).bisectors(b(*l2)) == ans
  715. def test_issue_8615():
  716. a = Line3D(Point3D(6, 5, 0), Point3D(6, -6, 0))
  717. b = Line3D(Point3D(6, -1, 19/10), Point3D(6, -1, 0))
  718. assert a.intersection(b) == [Point3D(6, -1, 0)]
  719. def test_issue_12598():
  720. r1 = Ray(Point(0, 1), Point(0.98, 0.79).n(2))
  721. r2 = Ray(Point(0, 0), Point(0.71, 0.71).n(2))
  722. assert str(r1.intersection(r2)[0]) == 'Point2D(0.82, 0.82)'
  723. l1 = Line((0, 0), (1, 1))
  724. l2 = Segment((-1, 1), (0, -1)).n(2)
  725. assert str(l1.intersection(l2)[0]) == 'Point2D(-0.33, -0.33)'
  726. l2 = Segment((-1, 1), (-1/2, 1/2)).n(2)
  727. assert not l1.intersection(l2)