parabola.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. """Parabolic geometrical entity.
  2. Contains
  3. * Parabola
  4. """
  5. from sympy.core import S
  6. from sympy.core.sorting import ordered
  7. from sympy.core.symbol import _symbol, symbols
  8. from sympy.geometry.entity import GeometryEntity, GeometrySet
  9. from sympy.geometry.point import Point, Point2D
  10. from sympy.geometry.line import Line, Line2D, Ray2D, Segment2D, LinearEntity3D
  11. from sympy.geometry.ellipse import Ellipse
  12. from sympy.functions import sign
  13. from sympy.simplify import simplify
  14. from sympy.solvers.solvers import solve
  15. class Parabola(GeometrySet):
  16. """A parabolic GeometryEntity.
  17. A parabola is declared with a point, that is called 'focus', and
  18. a line, that is called 'directrix'.
  19. Only vertical or horizontal parabolas are currently supported.
  20. Parameters
  21. ==========
  22. focus : Point
  23. Default value is Point(0, 0)
  24. directrix : Line
  25. Attributes
  26. ==========
  27. focus
  28. directrix
  29. axis of symmetry
  30. focal length
  31. p parameter
  32. vertex
  33. eccentricity
  34. Raises
  35. ======
  36. ValueError
  37. When `focus` is not a two dimensional point.
  38. When `focus` is a point of directrix.
  39. NotImplementedError
  40. When `directrix` is neither horizontal nor vertical.
  41. Examples
  42. ========
  43. >>> from sympy import Parabola, Point, Line
  44. >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7,8)))
  45. >>> p1.focus
  46. Point2D(0, 0)
  47. >>> p1.directrix
  48. Line2D(Point2D(5, 8), Point2D(7, 8))
  49. """
  50. def __new__(cls, focus=None, directrix=None, **kwargs):
  51. if focus:
  52. focus = Point(focus, dim=2)
  53. else:
  54. focus = Point(0, 0)
  55. directrix = Line(directrix)
  56. if directrix.contains(focus):
  57. raise ValueError('The focus must not be a point of directrix')
  58. return GeometryEntity.__new__(cls, focus, directrix, **kwargs)
  59. @property
  60. def ambient_dimension(self):
  61. """Returns the ambient dimension of parabola.
  62. Returns
  63. =======
  64. ambient_dimension : integer
  65. Examples
  66. ========
  67. >>> from sympy import Parabola, Point, Line
  68. >>> f1 = Point(0, 0)
  69. >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8)))
  70. >>> p1.ambient_dimension
  71. 2
  72. """
  73. return 2
  74. @property
  75. def axis_of_symmetry(self):
  76. """Return the axis of symmetry of the parabola: a line
  77. perpendicular to the directrix passing through the focus.
  78. Returns
  79. =======
  80. axis_of_symmetry : Line
  81. See Also
  82. ========
  83. sympy.geometry.line.Line
  84. Examples
  85. ========
  86. >>> from sympy import Parabola, Point, Line
  87. >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8)))
  88. >>> p1.axis_of_symmetry
  89. Line2D(Point2D(0, 0), Point2D(0, 1))
  90. """
  91. return self.directrix.perpendicular_line(self.focus)
  92. @property
  93. def directrix(self):
  94. """The directrix of the parabola.
  95. Returns
  96. =======
  97. directrix : Line
  98. See Also
  99. ========
  100. sympy.geometry.line.Line
  101. Examples
  102. ========
  103. >>> from sympy import Parabola, Point, Line
  104. >>> l1 = Line(Point(5, 8), Point(7, 8))
  105. >>> p1 = Parabola(Point(0, 0), l1)
  106. >>> p1.directrix
  107. Line2D(Point2D(5, 8), Point2D(7, 8))
  108. """
  109. return self.args[1]
  110. @property
  111. def eccentricity(self):
  112. """The eccentricity of the parabola.
  113. Returns
  114. =======
  115. eccentricity : number
  116. A parabola may also be characterized as a conic section with an
  117. eccentricity of 1. As a consequence of this, all parabolas are
  118. similar, meaning that while they can be different sizes,
  119. they are all the same shape.
  120. See Also
  121. ========
  122. https://en.wikipedia.org/wiki/Parabola
  123. Examples
  124. ========
  125. >>> from sympy import Parabola, Point, Line
  126. >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8)))
  127. >>> p1.eccentricity
  128. 1
  129. Notes
  130. -----
  131. The eccentricity for every Parabola is 1 by definition.
  132. """
  133. return S.One
  134. def equation(self, x='x', y='y'):
  135. """The equation of the parabola.
  136. Parameters
  137. ==========
  138. x : str, optional
  139. Label for the x-axis. Default value is 'x'.
  140. y : str, optional
  141. Label for the y-axis. Default value is 'y'.
  142. Returns
  143. =======
  144. equation : SymPy expression
  145. Examples
  146. ========
  147. >>> from sympy import Parabola, Point, Line
  148. >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8)))
  149. >>> p1.equation()
  150. -x**2 - 16*y + 64
  151. >>> p1.equation('f')
  152. -f**2 - 16*y + 64
  153. >>> p1.equation(y='z')
  154. -x**2 - 16*z + 64
  155. """
  156. x = _symbol(x, real=True)
  157. y = _symbol(y, real=True)
  158. m = self.directrix.slope
  159. if m is S.Infinity:
  160. t1 = 4 * (self.p_parameter) * (x - self.vertex.x)
  161. t2 = (y - self.vertex.y)**2
  162. elif m == 0:
  163. t1 = 4 * (self.p_parameter) * (y - self.vertex.y)
  164. t2 = (x - self.vertex.x)**2
  165. else:
  166. a, b = self.focus
  167. c, d = self.directrix.coefficients[:2]
  168. t1 = (x - a)**2 + (y - b)**2
  169. t2 = self.directrix.equation(x, y)**2/(c**2 + d**2)
  170. return t1 - t2
  171. @property
  172. def focal_length(self):
  173. """The focal length of the parabola.
  174. Returns
  175. =======
  176. focal_lenght : number or symbolic expression
  177. Notes
  178. =====
  179. The distance between the vertex and the focus
  180. (or the vertex and directrix), measured along the axis
  181. of symmetry, is the "focal length".
  182. See Also
  183. ========
  184. https://en.wikipedia.org/wiki/Parabola
  185. Examples
  186. ========
  187. >>> from sympy import Parabola, Point, Line
  188. >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8)))
  189. >>> p1.focal_length
  190. 4
  191. """
  192. distance = self.directrix.distance(self.focus)
  193. focal_length = distance/2
  194. return focal_length
  195. @property
  196. def focus(self):
  197. """The focus of the parabola.
  198. Returns
  199. =======
  200. focus : Point
  201. See Also
  202. ========
  203. sympy.geometry.point.Point
  204. Examples
  205. ========
  206. >>> from sympy import Parabola, Point, Line
  207. >>> f1 = Point(0, 0)
  208. >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8)))
  209. >>> p1.focus
  210. Point2D(0, 0)
  211. """
  212. return self.args[0]
  213. def intersection(self, o):
  214. """The intersection of the parabola and another geometrical entity `o`.
  215. Parameters
  216. ==========
  217. o : GeometryEntity, LinearEntity
  218. Returns
  219. =======
  220. intersection : list of GeometryEntity objects
  221. Examples
  222. ========
  223. >>> from sympy import Parabola, Point, Ellipse, Line, Segment
  224. >>> p1 = Point(0,0)
  225. >>> l1 = Line(Point(1, -2), Point(-1,-2))
  226. >>> parabola1 = Parabola(p1, l1)
  227. >>> parabola1.intersection(Ellipse(Point(0, 0), 2, 5))
  228. [Point2D(-2, 0), Point2D(2, 0)]
  229. >>> parabola1.intersection(Line(Point(-7, 3), Point(12, 3)))
  230. [Point2D(-4, 3), Point2D(4, 3)]
  231. >>> parabola1.intersection(Segment((-12, -65), (14, -68)))
  232. []
  233. """
  234. x, y = symbols('x y', real=True)
  235. parabola_eq = self.equation()
  236. if isinstance(o, Parabola):
  237. if o in self:
  238. return [o]
  239. else:
  240. return list(ordered([Point(i) for i in solve(
  241. [parabola_eq, o.equation()], [x, y], set=True)[1]]))
  242. elif isinstance(o, Point2D):
  243. if simplify(parabola_eq.subs([(x, o._args[0]), (y, o._args[1])])) == 0:
  244. return [o]
  245. else:
  246. return []
  247. elif isinstance(o, (Segment2D, Ray2D)):
  248. result = solve([parabola_eq,
  249. Line2D(o.points[0], o.points[1]).equation()],
  250. [x, y], set=True)[1]
  251. return list(ordered([Point2D(i) for i in result if i in o]))
  252. elif isinstance(o, (Line2D, Ellipse)):
  253. return list(ordered([Point2D(i) for i in solve(
  254. [parabola_eq, o.equation()], [x, y], set=True)[1]]))
  255. elif isinstance(o, LinearEntity3D):
  256. raise TypeError('Entity must be two dimensional, not three dimensional')
  257. else:
  258. raise TypeError('Wrong type of argument were put')
  259. @property
  260. def p_parameter(self):
  261. """P is a parameter of parabola.
  262. Returns
  263. =======
  264. p : number or symbolic expression
  265. Notes
  266. =====
  267. The absolute value of p is the focal length. The sign on p tells
  268. which way the parabola faces. Vertical parabolas that open up
  269. and horizontal that open right, give a positive value for p.
  270. Vertical parabolas that open down and horizontal that open left,
  271. give a negative value for p.
  272. See Also
  273. ========
  274. https://www.sparknotes.com/math/precalc/conicsections/section2/
  275. Examples
  276. ========
  277. >>> from sympy import Parabola, Point, Line
  278. >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8)))
  279. >>> p1.p_parameter
  280. -4
  281. """
  282. m = self.directrix.slope
  283. if m is S.Infinity:
  284. x = self.directrix.coefficients[2]
  285. p = sign(self.focus.args[0] + x)
  286. elif m == 0:
  287. y = self.directrix.coefficients[2]
  288. p = sign(self.focus.args[1] + y)
  289. else:
  290. d = self.directrix.projection(self.focus)
  291. p = sign(self.focus.x - d.x)
  292. return p * self.focal_length
  293. @property
  294. def vertex(self):
  295. """The vertex of the parabola.
  296. Returns
  297. =======
  298. vertex : Point
  299. See Also
  300. ========
  301. sympy.geometry.point.Point
  302. Examples
  303. ========
  304. >>> from sympy import Parabola, Point, Line
  305. >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8)))
  306. >>> p1.vertex
  307. Point2D(0, 4)
  308. """
  309. focus = self.focus
  310. m = self.directrix.slope
  311. if m is S.Infinity:
  312. vertex = Point(focus.args[0] - self.p_parameter, focus.args[1])
  313. elif m == 0:
  314. vertex = Point(focus.args[0], focus.args[1] - self.p_parameter)
  315. else:
  316. vertex = self.axis_of_symmetry.intersection(self)[0]
  317. return vertex