def reflection_normal(outgoing_ray, incoming_ray): """Returns the normal vector between incoming and outgoing reflection rays. """ ray1 = normalize(-incoming_ray) ray2 = normalize(outgoing_ray) return normalize((ray1 + ray2)/2)
def refract(ray, normal, origin_index, final_index): """Returns the normalized direction of a given ray (normalized or not) after refraction through a boundary between two media with given normal vector and indexes of refraction """ rho = final_index / origin_index ray_direction = normalize(ray) normal = normalize(normal) if normal.dot(ray_direction) > 0: normal = -normal incidence = dot(-ray_direction, normal) complement = (1.0 - (1.0 - incidence**2) / rho**2)**(0.5) return (ray_direction / rho) + ((incidence / rho - complement) * normal)
def reconstruct_mirror_normal( outgoing_ray, incoming_ray, surface_normal, inside_index, outside_index): """Reconstructs the mirror normal vector given the incoming ray vector, outgoing ray vector, front face normal vector and the indexes of refraction. """ outgoing_ray = normalize(outgoing_ray) incoming_ray = normalize(incoming_ray) surface_normal = normalize(surface_normal) inner_downstream = -refract( -outgoing_ray, surface_normal, outside_index, inside_index) inner_upstream = refract( incoming_ray, surface_normal, outside_index, inside_index) return reflection_normal(inner_downstream, inner_upstream)
def normal(self, point): """Return the normal at the point on the surface.""" point = self._center - np.array(point) # if abs(point.dot(point) - self._radius**2) > 1e-15: # raise RayTraceError( # 'Cannot compute normal. Point is too far from surface ({}).'.format( # (abs(point.dot(point) - self._radius**2)))) return normalize(point / self._radius)
def _radius_parameters(normal_1, normal_2, input_1, impact_1, impact_2): """Return a tuple (separation, radius). The beam separation is reported in the normal sector plane. The radius reported is that of the sphere connecting the given normal vectors normal_1 and normal_2 at the beam impact position vectors impact_1 and impact_2 for the direction input_1 of the beam at normal_1. """ alpha = abs(sys_math.acos(normal_1.dot(normal_2))) plane = normalize(Vector(np.cross(normal_1, normal_2))) input_in_plane = normalize(input_1 - (input_1.dot(plane) * plane)) theta = abs(sys_math.acos(normal_1.dot(input_in_plane))) separation = impact_1 - impact_2 #separation = np.append(separation, 0) separation -= separation.dot(plane) * plane separation = Vector(separation) separation = (abs(separation)).value return (separation, alpha, theta)
def __init__(self, initial_direction, initial_position, initial_element=None, jitter=None): """Create a beam along the initial direction and position given. Optionally, jitter can be added to the beam by passing the standard deviation of the polar direction in radians.""" if jitter is not None: initial_direction = normalize(initial_direction) initial_direction += np.linalg.inv( rotation_matrix_arrays(initial_direction)).dot(array( [np.random.normal(0, jitter), np.random.normal(0, jitter), 0])) self._ray = Ray(initial_direction, initial_position) self._history = [(0, self._ray)] self._element = Air() if initial_element is None else initial_element
def __init__(self, direction, position): """Construct a Ray from a direction and a position from the origin. The direction will be forced normal.""" self.direction = normalize(direction) self.position = np.array(position)
def __init__(self, normal, position, name=None, reflective=False): """Construct a plane from a normal vector and the position to a point on the plane.""" _Surface.__init__(self, name, reflective) self._normal = normalize(normal) self._position = np.array(position)