2023-10-30 00:41:13 -04:00
|
|
|
import numpy as np
|
|
|
|
from abc import ABC, abstractmethod
|
|
|
|
|
|
|
|
class Ray:
|
|
|
|
def __init__(self, origin, direction):
|
|
|
|
self.origin = np.array(origin)
|
|
|
|
self.direction = np.array(direction) / np.linalg.norm(direction)
|
|
|
|
|
|
|
|
class Shapes(ABC):
|
|
|
|
def __init__(self,refractive_index) -> None:
|
|
|
|
self.refractive_index = refractive_index
|
|
|
|
@abstractmethod
|
|
|
|
def find_intersection(self, ray:Ray):
|
|
|
|
pass
|
|
|
|
def get_normal(self, point):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class Scheme:
|
|
|
|
def __init__(self, shapes, rays) -> None:
|
|
|
|
self.shapes = shapes
|
|
|
|
self.rays = rays
|
|
|
|
self.raytrace()
|
|
|
|
def raytrace(self):
|
|
|
|
for ray in self.rays:
|
|
|
|
t, intersection_point, first_shape = None, None, None
|
|
|
|
for shape in self.shapes:
|
|
|
|
t1,intersection_point1 = shape.find_intersection(ray)
|
|
|
|
if t is None or ((t1 is not None) and (t1 < t)):
|
|
|
|
t, intersection_point, first_shape = t1, intersection_point1, shape
|
|
|
|
if t is None:
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
self.reflection_and_refraction(ray, first_shape, intersection_point)
|
|
|
|
def reflection_and_refraction(ray:Ray, shape:Shapes, intersection_point):
|
|
|
|
pass
|
|
|
|
|
|
|
|
class Disk(Shapes):
|
|
|
|
def __init__(self, center, radius, refractive_index):
|
|
|
|
super().__init__(refractive_index)
|
|
|
|
self.center = np.array(center)
|
|
|
|
self.radius = radius
|
|
|
|
def find_intersection(self, ray:Ray):
|
|
|
|
oc = ray.origin - self.center
|
|
|
|
a = np.dot(ray.direction, ray.direction)
|
|
|
|
b = 2.0 * np.dot(oc, ray.direction)
|
|
|
|
c = np.dot(oc, oc) - self.radius * self.radius
|
|
|
|
discriminant = b*b - 4*a*c
|
|
|
|
if discriminant < 0:
|
|
|
|
return None, None # 没有交点
|
|
|
|
else:
|
2023-10-30 15:09:10 -04:00
|
|
|
dis2 = np.dot(oc,oc)
|
|
|
|
epsilon = 1e-12
|
|
|
|
if dis2 > 1 - epsilon and dis2 < 1 + epsilon:
|
|
|
|
normal = self.get_normal(ray.origin)
|
|
|
|
if np.dot(normal, ray.direction) < 0:
|
|
|
|
t = (-b + np.sqrt(discriminant)) / (2.0 * a)
|
|
|
|
else:
|
|
|
|
return None, None
|
|
|
|
elif dis2 <= 1 - epsilon:
|
2023-10-30 00:41:13 -04:00
|
|
|
t = (-b + np.sqrt(discriminant)) / (2.0 * a)
|
|
|
|
else:
|
|
|
|
t = (-b - np.sqrt(discriminant)) / (2.0 * a)
|
2023-10-30 15:09:10 -04:00
|
|
|
if t < 0:
|
|
|
|
return None, None
|
2023-10-30 00:41:13 -04:00
|
|
|
intersection_point = ray.origin + t * ray.direction
|
2023-10-30 13:18:43 -04:00
|
|
|
intersection_point = self.center + self.radius * (intersection_point - self.center)/np.linalg.norm(intersection_point - self.center)
|
2023-10-30 00:41:13 -04:00
|
|
|
return t,intersection_point
|
|
|
|
def get_normal(self, point):
|
|
|
|
normal = (point - self.center)/self.radius
|
|
|
|
normal = normal / np.linalg.norm(normal)
|
|
|
|
return normal
|
|
|
|
|
|
|
|
class half_plane(Shapes):
|
|
|
|
def __init__(self, point, normal, refractive_index) -> None:
|
|
|
|
super().__init__(refractive_index)
|
|
|
|
self.point = point
|
|
|
|
self.normal = normal/np.linalg.norm(normal)
|
|
|
|
def find_intersection(self, ray:Ray):
|
|
|
|
dot = np.dot(ray.direction, self.normal)
|
|
|
|
if dot == 0:
|
|
|
|
return None,None
|
|
|
|
else:
|
|
|
|
t = np.dot(self.point - ray.origin, self.normal) / dot
|
|
|
|
return t, ray.origin + t*ray.direction
|
|
|
|
def get_normal(self, point):
|
|
|
|
return self.normal
|