Skip to main content

Handle points, lines and conics by using algebraic geometry.

Project description

pyConics

pyConics handles points, lines and conics by using algebraic geometry and homogeneous coordinates (projective geometry).

Installation

From a local directory clones this project:

git clone https://github.com/osowsky/pyConics.git (by using http)
or
git clone git@github.com:osowsky/pyConics.git (by using ssh)

You can install this package, as well:

pip install pyConics

Usage

pyConics can be used to handle points, lines and conics by using algebraic geometry and homogeneous coordinates.

Working with points

The representation in homogeneous coordinates of a Cartesian point $p = (\enspace\alpha,\enspace\beta\enspace)$, where $\alpha,\enspace\beta\enspace\in\enspace\mathcal{R}$, is given by the following vector in $\mathcal{R}^3$:

$$ p=\left[\begin{array}{cc} \enspace\alpha & \beta & 1.0\enspace \end{array}\right]^{T} $$

If you want to represent a point $p$ at infinity, you must define a vector as follows:

$$ p=\left[\begin{array}{cc} \enspace\alpha & \beta & 0.0\enspace \end{array}\right]^{T}, $$

where $\enspace\alpha,\enspace\beta\enspace\in\enspace\mathcal{R}$

How to work with points in pyConics.

    from pyConics import Point

    p1 = Point( ( 0.0, 1.0 ), 'p1' ) # p1 = ( 0.0, 1.0 ).
    p2 = Point( ( 1.0, 1.0 ), 'p2' ) # p2 = ( 1.0, 1.0 ).

    print( p1 ) # -> p1: [0.0000e+00 1.0000e+00 1.0000e+00].
    print( p2 ) # -> p2: [1.0000e+00 1.0000e+00 1.0000e+00].
    print()

    print( f'Are p1 and p2 the same? {p1 == p2}\n' ) # -> False.

    d12 = p1.distance( p2 )
    print( f'Distance from {p1}\nto {p2} is {d12:.4f}.\n' ) # -> d12 = 1.0.

    p3 = Point( ( 1, 1, 0 ), 'p3' ) # Point at the infinity.
    print( p3 ) # -> p3: [1.0000e+00 1.0000e+00 0.0000e+00] -> point at the infinity.
    print()

    print( f'Is p3 a point at infinity? {p3.at_infinity()}.\n' ) # -> True.

    d13 = p1.distance( p3 )
    print( f'Distance from {p1} to\n{p3} is {d13:.4f}.\n' ) # -> d13 = Inf.

Working with lines

The representation in homogeneous coordinates of a Cartesian line $l:\beta y=\alpha x + \gamma$, where $\alpha,\enspace\beta,\enspace\gamma\in\enspace\mathcal{R}$, is given by the following vector in $\mathcal{R}^3$:

$$ l=\left[\begin{array}{cc} \enspace\alpha & -\beta & \gamma\enspace \end{array}\right]^{T} $$

The vector above satisfies the following homogeneous expression for straight lines in projective geometry:

$$ l:\left\lbrace\enspace (\enspace x,\enspace y\enspace)\enspace|\enspace \left[\begin{array}{cc} \enspace\alpha & -\beta & \gamma\enspace \end{array}\right]\times \left[\begin{array}{c} \enspace\ x \enspace\ \enspace\ y \enspace\ \enspace\ 1 \enspace\ \end{array}\right]\enspace=\enspace 0 \enspace\right\rbrace $$

If you want to represent a line $l$ at infinity, you must define a vector as follows:

$$ l\enspace=\left[\begin{array}{cc} \enspace 0.0 & 0.0 & \gamma\enspace \end{array}\right]^{T}, $$

where $\enspace\gamma\enspace\in\enspace\mathcal{R}$

How to work with lines in pyConics.

    from pyConics import Line

    l1 = Line( ( 1, -1, 1 ), 'l1' )         # l1: y = x + 1
    l2 = Line( ( 1.5, -1.5, -1.5 ), 'l2' )  # l2: 1.5y = 1.5x - 1.5
    l3 = Line( ( -1, -1, 1 ), 'l3' )        # l3: y = -x + 1
    l4 = Line( ( 2, 2, -2 ), 'l4' )         # l4: 2y = -2x + 2

    print( l1 ) # -> l1: ( x, y ) | [1.0000e+00 -1.0000e+00 1.0000e+00] * [ x y 1 ]' = 0.
    print( l2 ) # -> l2: ( x, y ) | [1.5000e+00 -1.5000e+00 -1.5000e+00] * [ x y 1 ]' = 0.
    print( l3 ) # -> l3: ( x, y ) | [-1.0000e+00 -1.0000e+00 1.0000e+00] * [ x y 1 ]' = 0.
    print( l4 ) # -> l4: ( x, y ) | [2.0000e+00 2.0000e+00 -2.0000e+00] * [ x y 1 ]' = 0.
    print()

    # The relationships between two lines lx and ly can be:
    # 1) coincident lines: lx == ly or lx.are_coincident( ly ).
    #    Notice that l4 = -2 * l3. From the projective geometry both lines are
    #    coincident because they satisfy the same equation. 
    print( f'Is l1 == l1? {l1 == l1}.' )
    print( f'Is l3 == l4? {l3 == l4}.' )
    print( f'Is l1 == l2? {l1 == l2}.\n' )

    # 2) parallel lines: lx // ly or lx.are_parallel( ly ).
    #    Notice that coincident lines are parallel ones, as well.
    print( f'Is l1 // l2? {l1 // l2}.' )
    print( f'Is l2 // l3? {l2 // l3}.' )
    print( f'Is l3 // l4? {l3 // l4}.\n' )

    # 3) concurrent lines: lx.are_concurrent( ly )
    print( f'Are l1 and l2 concurrent lines? {l1.are_concurrent( l2 )}.' )
    print( f'Are l2 and l3 concurrent lines? {l2.are_concurrent( l3 )}.' )
    print( f'Are l3 and l4 concurrent lines? {l3.are_concurrent( l4 )}.\n' )

    # 4) perpendicular lines: lx + ly or lx.are_perpendicular( ly ).
    print( f'Is l1 + l3? {l1 + l3}.' )
    print( f'Is l2 + l4? {l2 + l4}.' )
    print( f'Is l3 + l4? {l3 + l4}.\n' )

    # Euclidean distance between lines.
    # Notice that, from the theory the distance between two concurrent
    # lines is equal to zero. 
    print( f'Distance from l1 to l2 is {l1.distance( l2 ):.4f}.' )
    print( f'Distance from l2 to l3 is {l2.distance( l3 ):.4f}.' )
    print( f'Distance from l3 to l4 is {l3.distance( l4 ):.4f}.\n' )

    # Lines at infinity.
    l5 = Line( ( 0, 0, 2 ), 'l5' )
    l6 = Line( ( 1, -1, 1 ), 'l6' )
    print( l5 )
    print( l6 )
    print( f'Is l5 a line at infinity? {l5.at_infinity()}.' )
    print( f'Is l6 a line at infinity? {l6.at_infinity()}.\n' )

    # Distance from l5 at infinity and l6.
    d56 = l5.distance( l6 )
    print( f'Distance from {l5} to {l6} is {d56}.\n' )

Working with points and lines

Now that I have introduced you to the concepts of points and lines in projective geometry and how you should work with them. The next step is to know how to use both geometric shapes together.

However, before we start this step I must answer a question that you may be wondering. If points and lines have the same vector representation, i.e., they are both vectors in $\mathcal{R}^3$, how will I know if I am using a point or a line?

A generic answer would be: The context will tell you whether the vectors in $\mathcal{R}^3$ are points or lines. For instance, the cross product operation can be used with the following operands:

  1. two points: The result is a straight line $l$ that passes through both points.
  2. two lines: The result is the point of intersection $p$ between both lines.
  3. a point $p$ and a line $l$: The result is a line that is perpendicular to the straight line $l$ and passes through the point $p$.

Finally, the Table below shows six interesting interpretations about vector representation of points and lines, four of which are not well-posed in two-dimensional Euclidean Geometry, namely point and line at infinity.

$$ % \def\arraystretch{2.5} \begin{array}{ccc} \text{vector in }\mathcal{R}^3 & \text{point} & \text{line}\newline \hline\hline [\begin{array}{ccc} \alpha & \beta & 0.0 \end{array}]^{T} & \text{point at infinity} & \text{line passing through the origin}\newline \hline [\begin{array}{ccc} 0.0 & 0.0 & \gamma \end{array}]^{T} & \text{point at origin with }\gamma=1.0 & \text{line at infinity}\newline \hline [\begin{array}{ccc} 0.0 & 0.0 & 0.0 \end{array}]^{T} & \text{point at infinity} & \text{line at infinity}\newline \hline \end{array} $$

How to work with points and lines in pyConics.

    from pyConics import Point, Line

    # Points.
    p1 = Point( ( 1, 3 ), 'p1' )   # p1 = ( 1, 3 )
    p2 = Point( ( 0, 4 ), 'p2' )   # p2 = ( 0, 4 )
    p3 = Point( ( -2, 0 ), 'p3' )  # p3 = ( -2, 0 )
    p4 = Point( ( 2, 0 ), 'p4' )   # p4 = ( 2, 0 )
    p5 = Point( ( 0, -4 ), 'p5' )  # p5 = ( 0, -4 )

    # Lines.
    l1 = Line( ( 2, -1, 4 ), 'l1' )   #l1: y = 2x + 4
    l2 = Line( ( 2, -1, -4 ), 'l2' )  #l2: y = 2x - 4
    l3 = Line( ( 2, 1, 0 ), 'l3' )    #l3: y = -2x
    l4 = Line( ( 1, 0, -2 ), 'l4' )   #l4: x = 2
    l5 = Line( ( 0, 1, -4 ), 'l5' )   #l5: y = 4
    l6 = Line( ( 3, -1, 0 ), 'l6' )   #l6: y = 3x

    # Test whether a point is in or is not in a Line.
    print( l1, p1, p2, p3, sep='\n' )
    print( f'Is p1 in l1? {p1 in l1}.' )    # p1 belongs to l1: False
    print( f'Is p2 in l1? {p2 in l1}.' )    # p2 belongs to l1: True
    print( f'Is p3 in l1? {p3 in l1}.\n' )  # p3 belongs to l1: True
    print( l6, p1, p4, sep='\n' )
    print( f'Is p1 in l6? {p1 in l6}.' )    # p1 belongs to l6: True
    print( f'Is p4 in l6? {p4 in l6}.\n' )  # p4 belongs to l6: False
    print( l4, p4, sep='\n' )
    print( f'Is p4 in l4? {p4 in l4}.\n' )  # p4 belongs to l4: True
    print( l5, p2, sep='\n' )
    print( f'Is p2 in l5? {p2 in l5}.\n' )  # p2 belongs to l5: True

    # Use the cross product to handle points and lines.
    # 1) the cross product between two points gives us a line that
    #    passes through these points.
    l: Line = p2 * p3
    l.name = 'l'
    print( l1, l, sep='\n' )
    print( f'Are l and l1 coincident? {l==l1}.\n' )
    l: Line = p4 * p5
    l.name = 'l'
    print( l2, l, sep='\n' )
    print( f'Are l and l2 coincident? {l==l2}.\n' )

    # 2) the cross product between two lines gives us their point
    #    of intersection.
    p: Point = l1 * l3
    p.name = 'p'
    print( l1, l3, p, sep='\n' )
    print( f'Is p in l1? {p in l1}.' )
    print( f'Is p in l3? {p in l3}.\n' )
    p: Point = l2 * l4
    p.name = 'p'
    print( l2, l4, p4, p, sep='\n' )
    print( f'Is p in l2? {p in l2}.' )
    print( f'Is p in l4? {p in l4}.' )
    print( f'Are p and p4 coincident? {p==p4}.\n' )

    # Two parallel lines have their point of intersection at infinity.
    # So, ...
    p: Point = l1 * l2
    p.name = 'p'
    print( l1, l2, p, sep='\n' )
    print( f'Is p in l1? {p in l1}.' )
    print( f'Is p in l2? {p in l2}.' )
    print( f'Is p in l4? {p in l4}.' )
    print( f'Is p at infinity? {p.at_infinity()}.\n' )

    # 3) the cross product between a point and a line gives us a
    #    line which is perpendicular to that line and passes
    #    through that point.
    l: Line = l2 * p2
    l.name = 'l'
    print( p2, l2, l, sep='\n' )
    print( f'Is p2 in l? {p2 in l}.' )
    print( f'Are l2 and l perpendicular? {l2 + l}.\n' )
    p: Point = l2 * l
    p.name = 'p'
    print( l2, l, p, sep='\n' )
    print( f'Is p in l? {p in l}.' )
    print( f'Is p in l2? {p in l2}.' )

    # Getting the distance between p2 and l2.
    print( f'Distance from p2 to l2 = {p2.distance( l2 ):.4f}.' )
    print( f'Distance from p2 to p  = {p2.distance( p ):.4f}.\n' )

Contributing

Interested in contributing? Check out the contributing guidelines. Please note that this project is released with a Code of Conduct. By contributing to this project, you agree to abide by its terms.

License

pyConics was created by Jefferson Osowsky. It is licensed under the terms of the GNU General Public License v3.0 license.

Credits

pyConics was created with cookiecutter and the py-pkgs-cookiecutter template.

pyConics has used the following Python packages since its first release:

  • numpy
  • pytest

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyconics-0.2.6.tar.gz (26.5 kB view hashes)

Uploaded Source

Built Distribution

pyconics-0.2.6-py3-none-any.whl (29.5 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page