RedEnginePress logo
RedEnginePress
AlgorithmsLanguagesPlaygroundAbout

Braik Mac Construction

A
"""
braikenridge_maclaurin_construction
https://mathworld.wolfram.com/ConicSection.html
5 Points define a conic section on a 2D normal orthogonal plane using this technique.
"""

from __future__ import annotations

from dataclasses import dataclass, field

from numpy import array, linalg


@dataclass
class Point:
    """
    A point defined by 2 floats representing a length on a normalized
    orthogonal coordinate system
    default coordinate is the origin

    >>> Point(-1.0, 0.0)
    Point(x=-1.0, y=0.0)
    """

    x: float = 0.0
    y: float = 0.0

    def __post_init__(self) -> None:
        if not isinstance(self.x, (int, float)):
            raise TypeError("x must be an int or float numeric value")
        if not isinstance(self.y, (int, float)):
            raise TypeError("y must be an int or float numeric value")


@dataclass
class BraikMac:
    """
    Given a list of 5 points, determine the corresponding
    conic section equation and provide it to the user

    | x**2   xy  y**2  x  y  1 |
    | x1**2 x1y1 y1**2 x1 y1 1 |
    | x2**2 x2y2 y2**2 x2 y2 1 | = 0
    | x3**2 x3y3 y3**2 x3 y3 1 |
    | x4**2 x4y4 y4**2 x4 y4 1 |
    | x5**2 x5y5 y5**2 x5 y5 1 |

    >>> p1 = Point(0.0,0.0)
    >>> p2 = Point(5.0,0.0)
    >>> p3 = Point(2.0,3.0)
    >>> p4 = Point(1.0,10.0)
    >>> p5 = Point(6.0,7.0)
    >>> BraikMac([p1,p2,p3,p4,p5]) # doctest: +NORMALIZE_WHITESPACE
    BraikMac(p_list=[Point(x=0.0, y=0.0), Point(x=5.0, y=0.0),
    Point(x=2.0, y=3.0), Point(x=1.0, y=10.0), Point(x=6.0, y=7.0)])
    """

    p_list: list[Point] = field(default_factory=list)

    def __post_init__(self) -> None:
        n = 0
        for p in self.p_list:
            if not isinstance(p, Point):
                raise TypeError("Array must be point objects.")
            n += 1
        if n != 5:
            raise TypeError("Array must be 5 point objects.")

    @property
    def generate(self) -> str:
        x1 = self.p_list[0].x
        y1 = self.p_list[0].y
        x2 = self.p_list[1].x
        y2 = self.p_list[1].y
        x3 = self.p_list[2].x
        y3 = self.p_list[2].y
        x4 = self.p_list[3].x
        y4 = self.p_list[3].y
        x5 = self.p_list[4].x
        y5 = self.p_list[4].y

        x2_matrix = array(
            [
                [x1 * y1, y1**2, x1, y1, 1],
                [x2 * y2, y2**2, x2, y2, 1],
                [x3 * y3, y3**2, x3, y3, 1],
                [x4 * y4, y4**2, x4, y4, 1],
                [x5 * y5, y5**2, x5, y5, 1],
            ]
        )

        a = linalg.det(x2_matrix)

        xy_matrix = array(
            [
                [x1**2, y1**2, x1, y1, 1],
                [x2**2, y2**2, x2, y2, 1],
                [x3**2, y3**2, x3, y3, 1],
                [x4**2, y4**2, x4, y4, 1],
                [x5**2, y5**2, x5, y5, 1],
            ]
        )

        b = -linalg.det(xy_matrix)

        y2_matrix = array(
            [
                [x1**2, x1 * y1, x1, y1, 1],
                [x2**2, x2 * y2, x2, y2, 1],
                [x3**2, x3 * y3, x3, y3, 1],
                [x4**2, x4 * y4, x4, y4, 1],
                [x5**2, x5 * y5, x5, y5, 1],
            ]
        )

        c = linalg.det(y2_matrix)

        x_matrix = array(
            [
                [x1**2, x1 * y1, y1**2, y1, 1],
                [x2**2, x2 * y2, y2**2, y2, 1],
                [x3**2, x3 * y3, y3**2, y3, 1],
                [x4**2, x4 * y4, y4**2, y4, 1],
                [x5**2, x5 * y5, y5**2, y5, 1],
            ]
        )

        d = -linalg.det(x_matrix)

        y_matrix = array(
            [
                [x1**2, x1 * y1, y1**2, x1, 1],
                [x2**2, x2 * y2, y2**2, x2, 1],
                [x3**2, x3 * y3, y3**2, x3, 1],
                [x4**2, x4 * y4, y4**2, x4, 1],
                [x5**2, x5 * y5, y5**2, x5, 1],
            ]
        )

        e = linalg.det(y_matrix)

        const_matrix = array(
            [
                [x1**2, x1 * y1, y1**2, x1, y1],
                [x2**2, x2 * y2, y2**2, x2, y2],
                [x3**2, x3 * y3, y3**2, x3, y3],
                [x4**2, x4 * y4, y4**2, x4, y4],
                [x5**2, x5 * y5, y5**2, x5, y5],
            ]
        )

        f = -linalg.det(const_matrix)

        return f"0 = {a:+.2} X**2 {b:+.2} XY {c:+.2} Y**2 {d:+.2} X {e:+.2} Y {f:+.2}"


if __name__ == "__main__":
    from doctest import testmod

    testmod()