""" 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()