"""Parabolic geometrical entity. Contains * Parabola """ from sympy.core import S from sympy.core.compatibility import ordered from sympy.core.symbol import _symbol from sympy import symbols, simplify, solve # type:ignore from sympy.geometry.entity import GeometryEntity, GeometrySet from sympy.geometry.point import Point, Point2D from sympy.geometry.line import Line, Line2D, Ray2D, Segment2D, LinearEntity3D from sympy.geometry.ellipse import Ellipse from sympy.functions import sign class Parabola(GeometrySet): """A parabolic GeometryEntity. A parabola is declared with a point, that is called 'focus', and a line, that is called 'directrix'. Only vertical or horizontal parabolas are currently supported. Parameters ========== focus : Point Default value is Point(0, 0) directrix : Line Attributes ========== focus directrix axis of symmetry focal length p parameter vertex eccentricity Raises ====== ValueError When `focus` is not a two dimensional point. When `focus` is a point of directrix. NotImplementedError When `directrix` is neither horizontal nor vertical. Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7,8))) >>> p1.focus Point2D(0, 0) >>> p1.directrix Line2D(Point2D(5, 8), Point2D(7, 8)) """ def __new__(cls, focus=None, directrix=None, **kwargs): if focus: focus = Point(focus, dim=2) else: focus = Point(0, 0) directrix = Line(directrix) if (directrix.slope != 0 and directrix.slope != S.Infinity): raise NotImplementedError('The directrix must be a horizontal' ' or vertical line') if directrix.contains(focus): raise ValueError('The focus must not be a point of directrix') return GeometryEntity.__new__(cls, focus, directrix, **kwargs) @property def ambient_dimension(self): """Returns the ambient dimension of parabola. Returns ======= ambient_dimension : integer Examples ======== >>> from sympy import Parabola, Point, Line >>> f1 = Point(0, 0) >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8))) >>> p1.ambient_dimension 2 """ return S(2) @property def axis_of_symmetry(self): """The axis of symmetry of the parabola. Returns ======= axis_of_symmetry : Line See Also ======== sympy.geometry.line.Line Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.axis_of_symmetry Line2D(Point2D(0, 0), Point2D(0, 1)) """ return self.directrix.perpendicular_line(self.focus) @property def directrix(self): """The directrix of the parabola. Returns ======= directrix : Line See Also ======== sympy.geometry.line.Line Examples ======== >>> from sympy import Parabola, Point, Line >>> l1 = Line(Point(5, 8), Point(7, 8)) >>> p1 = Parabola(Point(0, 0), l1) >>> p1.directrix Line2D(Point2D(5, 8), Point2D(7, 8)) """ return self.args[1] @property def eccentricity(self): """The eccentricity of the parabola. Returns ======= eccentricity : number A parabola may also be characterized as a conic section with an eccentricity of 1. As a consequence of this, all parabolas are similar, meaning that while they can be different sizes, they are all the same shape. See Also ======== https://en.wikipedia.org/wiki/Parabola Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.eccentricity 1 Notes ----- The eccentricity for every Parabola is 1 by definition. """ return S.One def equation(self, x='x', y='y'): """The equation of the parabola. Parameters ========== x : str, optional Label for the x-axis. Default value is 'x'. y : str, optional Label for the y-axis. Default value is 'y'. Returns ======= equation : sympy expression Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.equation() -x**2 - 16*y + 64 >>> p1.equation('f') -f**2 - 16*y + 64 >>> p1.equation(y='z') -x**2 - 16*z + 64 """ x = _symbol(x, real=True) y = _symbol(y, real=True) if (self.axis_of_symmetry.slope == 0): t1 = 4 * (self.p_parameter) * (x - self.vertex.x) t2 = (y - self.vertex.y)**2 else: t1 = 4 * (self.p_parameter) * (y - self.vertex.y) t2 = (x - self.vertex.x)**2 return t1 - t2 @property def focal_length(self): """The focal length of the parabola. Returns ======= focal_lenght : number or symbolic expression Notes ===== The distance between the vertex and the focus (or the vertex and directrix), measured along the axis of symmetry, is the "focal length". See Also ======== https://en.wikipedia.org/wiki/Parabola Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.focal_length 4 """ distance = self.directrix.distance(self.focus) focal_length = distance/2 return focal_length @property def focus(self): """The focus of the parabola. Returns ======= focus : Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Parabola, Point, Line >>> f1 = Point(0, 0) >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8))) >>> p1.focus Point2D(0, 0) """ return self.args[0] def intersection(self, o): """The intersection of the parabola and another geometrical entity `o`. Parameters ========== o : GeometryEntity, LinearEntity Returns ======= intersection : list of GeometryEntity objects Examples ======== >>> from sympy import Parabola, Point, Ellipse, Line, Segment >>> p1 = Point(0,0) >>> l1 = Line(Point(1, -2), Point(-1,-2)) >>> parabola1 = Parabola(p1, l1) >>> parabola1.intersection(Ellipse(Point(0, 0), 2, 5)) [Point2D(-2, 0), Point2D(2, 0)] >>> parabola1.intersection(Line(Point(-7, 3), Point(12, 3))) [Point2D(-4, 3), Point2D(4, 3)] >>> parabola1.intersection(Segment((-12, -65), (14, -68))) [] """ x, y = symbols('x y', real=True) parabola_eq = self.equation() if isinstance(o, Parabola): if o in self: return [o] else: return list(ordered([Point(i) for i in solve([parabola_eq, o.equation()], [x, y])])) elif isinstance(o, Point2D): if simplify(parabola_eq.subs([(x, o._args[0]), (y, o._args[1])])) == 0: return [o] else: return [] elif isinstance(o, (Segment2D, Ray2D)): result = solve([parabola_eq, Line2D(o.points[0], o.points[1]).equation()], [x, y]) return list(ordered([Point2D(i) for i in result if i in o])) elif isinstance(o, (Line2D, Ellipse)): return list(ordered([Point2D(i) for i in solve([parabola_eq, o.equation()], [x, y])])) elif isinstance(o, LinearEntity3D): raise TypeError('Entity must be two dimensional, not three dimensional') else: raise TypeError('Wrong type of argument were put') @property def p_parameter(self): """P is a parameter of parabola. Returns ======= p : number or symbolic expression Notes ===== The absolute value of p is the focal length. The sign on p tells which way the parabola faces. Vertical parabolas that open up and horizontal that open right, give a positive value for p. Vertical parabolas that open down and horizontal that open left, give a negative value for p. See Also ======== http://www.sparknotes.com/math/precalc/conicsections/section2.rhtml Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.p_parameter -4 """ if self.axis_of_symmetry.slope == 0: x = self.directrix.coefficients[2] p = sign(self.focus.args[0] + x) else: y = self.directrix.coefficients[2] p = sign(self.focus.args[1] + y) return p * self.focal_length @property def vertex(self): """The vertex of the parabola. Returns ======= vertex : Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.vertex Point2D(0, 4) """ focus = self.focus if (self.axis_of_symmetry.slope == 0): vertex = Point(focus.args[0] - self.p_parameter, focus.args[1]) else: vertex = Point(focus.args[0], focus.args[1] - self.p_parameter) return vertex