|
"""Parabolic geometrical entity. |
|
|
|
Contains |
|
* Parabola |
|
|
|
""" |
|
|
|
from sympy.core import S |
|
from sympy.core.sorting import ordered |
|
from sympy.core.symbol import _symbol, symbols |
|
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 |
|
from sympy.simplify.simplify import simplify |
|
from sympy.solvers.solvers import solve |
|
|
|
|
|
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.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 2 |
|
|
|
@property |
|
def axis_of_symmetry(self): |
|
"""Return the axis of symmetry of the parabola: a line |
|
perpendicular to the directrix passing through the focus. |
|
|
|
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) |
|
|
|
m = self.directrix.slope |
|
if m is S.Infinity: |
|
t1 = 4 * (self.p_parameter) * (x - self.vertex.x) |
|
t2 = (y - self.vertex.y)**2 |
|
elif m == 0: |
|
t1 = 4 * (self.p_parameter) * (y - self.vertex.y) |
|
t2 = (x - self.vertex.x)**2 |
|
else: |
|
a, b = self.focus |
|
c, d = self.directrix.coefficients[:2] |
|
t1 = (x - a)**2 + (y - b)**2 |
|
t2 = self.directrix.equation(x, y)**2/(c**2 + d**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], set=True)[1]])) |
|
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], set=True)[1] |
|
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], set=True)[1]])) |
|
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 |
|
======== |
|
|
|
https://www.sparknotes.com/math/precalc/conicsections/section2/ |
|
|
|
Examples |
|
======== |
|
|
|
>>> from sympy import Parabola, Point, Line |
|
>>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) |
|
>>> p1.p_parameter |
|
-4 |
|
|
|
""" |
|
m = self.directrix.slope |
|
if m is S.Infinity: |
|
x = self.directrix.coefficients[2] |
|
p = sign(self.focus.args[0] + x) |
|
elif m == 0: |
|
y = self.directrix.coefficients[2] |
|
p = sign(self.focus.args[1] + y) |
|
else: |
|
d = self.directrix.projection(self.focus) |
|
p = sign(self.focus.x - d.x) |
|
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 |
|
m = self.directrix.slope |
|
if m is S.Infinity: |
|
vertex = Point(focus.args[0] - self.p_parameter, focus.args[1]) |
|
elif m == 0: |
|
vertex = Point(focus.args[0], focus.args[1] - self.p_parameter) |
|
else: |
|
vertex = self.axis_of_symmetry.intersection(self)[0] |
|
return vertex |
|
|