Skip to content

Instantly share code, notes, and snippets.

@carlos-adir
Created August 29, 2023 20:19
Show Gist options
  • Save carlos-adir/d5f413512571784f097f7852a85a3b79 to your computer and use it in GitHub Desktop.
Save carlos-adir/d5f413512571784f097f7852a85a3b79 to your computer and use it in GitHub Desktop.
Basic class to operate conic sections
import numpy as np
from matplotlib import pyplot as plt
from typing import Tuple
class Conic:
def __init__(self, coefs: Tuple[float]):
self.coefs = coefs
def __str__(self) -> str:
msg = self.tipo + " with coefs "
msg += str(np.array(self.coefs))
return msg
def __call__(self, u: float) -> Tuple[float]:
"""
Returns a point given a p
"""
float(u)
assert -1 <= u
assert u <= 1
if self.tipo == "Circle" or self.tipo == "Ellipse":
coefs = self.coefs
cos, sin = np.cos(np.pi*u), np.sin(np.pi*u)
angle = self.angle
center = self.center
self.move(-center[0], -center[1])
self.rotate(-angle)
majaxis = np.sqrt(-self.coefs[5]/self.coefs[0])
minaxis = np.sqrt(-self.coefs[5]/self.coefs[2])
xpt, ypt = majaxis*cos, minaxis*sin
cos, sin = np.cos(angle), np.sin(angle)
xpt, ypt = xpt * cos - ypt * sin, xpt * sin + ypt * cos
xpt, ypt = xpt + center[0], ypt + center[1]
self.coefs = coefs
return (xpt, ypt)
@property
def tipo(self) -> str:
a, b, c = self.coefs[:3]
delta = b**2 - 4 * a * c
if abs(delta) < 1e-9:
return "Parabola"
if delta < 0:
if a == c and b == 0:
return "Circle"
return "Ellipse"
if delta > 0:
if a + c == 0:
return "Rectangular hyperbola"
return "Hyperbola"
@property
def center(self) -> Tuple[float]:
a, b, c, d, e, f = self.coefs
return d/(2*a), e/(2*c)
@property
def angle(self) -> float:
a, b, c = self.coefs[:3]
return np.arctan2(b, a-c)/2
@property
def coefs(self) -> Tuple[float]:
return self.__coefs
@coefs.setter
def coefs(self, values: Tuple[float]):
assert len(values) == 6
self.__coefs = values
def move(self, xval: float, yval: float):
pass
def rotate(self, angle: float, degrees : bool = False):
"""
Rotates all the shape counter-clockwise
Transform the coefficients
[ u ] [ cos -sin ] [ x ]
[ ] = [ ] * [ ]
[ v ] [ sin cos ] [ y ]
[ x ] [ cos sin ] [ u ]
[ ] = [ ] * [ ]
[ y ] [ -sin cos ] [ v ]
x^2 = u^2 * cos^2 + 2*u*v * sin*cos + v^2 * sin^2
x*y = -u^2 * sin*cos + u*v * (cos^2 - sin^2) + v^2 * sin*cos
y^2 = u^2 * sin^2 - 2*u*v * sin*cos + v^2 * cos^2
x = u * cos + v * sin
y = -u * sin + v * cos
"""
if degrees:
angle *= np.pi/180
cos, sin = np.cos(angle), np.sin(angle)
a, b, c, d, e, f = self.coefs
r = a * cos**2 - b * sin*cos + c*sin**2
s = (a-c)*2*sin*cos + b*(cos**2 - sin**2)
t = a * sin**2 + b * sin*cos + c * cos**2
p = d * cos - e * sin
q = d * sin + e * cos
self.coefs = r, s, t, p, q, f
def scale(self, xscale: float, yscale: float):
a, b, c, d, e, f = self.coefs
a /= xscale**2
b /= xscale*yscale
c /= yscale**2
d /= xscale
e /= yscale
self.coefs = a, b, c, d, e, f
def main():
coefs = [1, 0, 1, 0, 0, -1] # x^2 + y^2 - 1 = 0
# coefs = [4, 1, 4, 0, 0, -1] # 4x^2 + x*y + 4*y^2 - 1 = 0
conic = Conic(coefs)
print(conic)
print(conic.angle*180/np.pi)
print(conic.center)
angle = conic.angle
conic.rotate(-angle)
print("#"*30)
print(conic)
print(conic.angle*180/np.pi)
print(conic.center)
print("conic(-1) = ", conic(-1))
print("conic(-0.5) = ", conic(-0.5))
print("conic(0) = ", conic(0))
print("conic(0.5) = ", conic(0.5))
print("conic(1) = ", conic(1))
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment