In [2]:
from vpython import *
from scipy.optimize import fsolve #You will need to install the scipy package for python
from math import sqrt #some of the equations require the use of the sqrt function
import numpy #Package for scientific computing in Python
scene = canvas()
#Classes
# A class is a template for an object
#Ray class is a template for a ray
#init: Set all of the variables for the beam
#define methods
class ray():
'''A light ray class'''
def __init__(self,startPoint,directionVector,color):
self.startPoint = startPoint
self.oldPoint = startPoint ### Position of light ray prior to current time step ###
self.currentPoint = startPoint
self.directionVector = directionVector.norm()
self.color = color
self.world_n=1 ### Value of n for the medium ray is currently in ###
self.ray = curve(pos=self.currentPoint, color=self.color)
#self.draw_ray() ### Commented out to let world() draw ray
def draw_ray(self):
'''Draw a single light ray'''
self.oldPoint = self.currentPoint ### Set old point to the current position BEFORE the update ###
newPoint = self.currentPoint + self.length*self.directionVector #add on one time step of distance
self.currentPoint = newPoint #Update the current position of the ray to be what we just calculated
self.ray.append(newPoint, color=self.color) #Add this point to an array holding the previous steps of this ray
class beam():
'''A Beam Class'''
def __init__(self, position, direction, width): #User-input parameters, applied to their own variables in the lines following
self.direction = direction
self.position = position
self.centerRay = ray(position, direction, color.green) #Creates a ray with the same parameters that the beam will have
self.currentPoint = self.centerRay.currentPoint
self.beamDirection = direction
self.width = width
self.color = self.centerRay.color
self.Rays = [] #Creates an array that will store parallel rays (built off the center ray) to form the beam
### Begin changes to fix perpendicular rays ###
self.find_perp() #Find two rays perpendicular to centerRay; establishes a set of local coordinate axes for the beam to be drawn in
self.draw_beam()
def find_perp(self):
'''Find two vectors perpendicular to the center ray'''
if self.centerRay.directionVector.y==0 and self.centerRay.directionVector.x==0:
self.perp1=vec(1,0,0)
else:
self.perp1 = norm(vec(self.centerRay.directionVector.y,-self.centerRay.directionVector.x,0))
self.perp2 = norm(vec(self.centerRay.directionVector.cross(self.perp1)))
### End changes to fix perpendicular rays ###
def draw_beam(self):
'''Draw a beam; lots of parallel rays'''#Loops through a range adding parallel rays in rings around the center ray
for i in numpy.arange(0,self.width,.5): #Increasing beam width by stepping out radially
for k in numpy.arange(0,2*pi+0.1,.5): #Adding ring by stepping around center ray in a circle
self.newStart = self.centerRay.startPoint + i*(self.perp1*cos(k)+self.perp2*sin(k))
beamRay = ray(self.newStart, self.beamDirection, self.color)
self.Rays.append(beamRay) #add new ray to the array in line 55 above
class pointSource():
'''A point source class'''
def __init__(self, position):
self.position = position
self.centerRay = ray(self.position, vec(1,0,0), color.green) #Starts with a set ray in the x-direction
self.color = self.centerRay.color
self.Rays = [] #An array to store other rays that will form the point source
self.source = sphere(pos = vec(self.centerRay.startPoint), radius = 0.01, color = self.color) #Visual object to represent the source
self.draw_pointSource()
def draw_pointSource(self):
'''Draw a point source''' #Steps through a set of parametric equations for the surface of a sphere in cartesian coordinates
self.source
c = pi/7
for i in numpy.arange(0,2*pi+c,c): #loops a half circle around in the xy-plane
for k in numpy.arange(0,2*pi+c,c): #Loops a full circle around in the yz-plane, carrying the last loop into the z-dimension
x = self.centerRay.length*(cos(k)*cos(i)) #Parametric equation for a sphere
y = self.centerRay.length*(cos(k)*sin(i))
z = self.centerRay.length*(sin(k))
pointSourceRay = ray(self.position, vec(x,y,z), self.centerRay.color) #Creates a new ray based on the values obtained from the loop (A new point on the sphere)
self.Rays.append(pointSourceRay)#Adds the newly created ray to the array in line 83
#####
# Start of World
#####
class world():
'''Creates a virtual environment for rays and objects to interact in; a world'''
def __init__(self):
self.rays=[] #An array to store rays that will interact in the 'world'
self.objects=[] #An array to store oobjects that will become obstacles to rays
self.dL = 0.1 #Ray step size
self.n = 1 #Default index of refraction for the world
self.MAX_LENGTH = 10 ### Set to 10 ###
self.current_length = 0 ### Length of current ray being drawn ###
def add_ray(self,new_ray): #Works for Ray
'''Add a ray to the world'''
self.rays.append(new_ray)
new_ray.length=self.dL
new_ray.world_n = self.n
def add_object(self,new_object): #Works for Ball, Block, Lens
'''Add a new object to the world'''
self.objects.append(new_object)
def add_light(self,light): #Works for Point Source
'''Add a point source to the world'''
for i in light.Rays:
self.add_ray(i)
def add_beam(self, beam): #Works for Beam
'''Add a beam to the world'''
for i in beam.Rays:
self.add_ray(i)
def draw_rays(self):
'''Draws rays in short steps'''
#Loop for checking Boundaries
for i in self.rays:
i.current_length = 0
while i.current_length < self.MAX_LENGTH: ### Runs until we reach a max length
for j in self.objects: ### Loop through all objects ###
j.check_boundaries(i) ### Call check_boundaries method for each object ###
i.draw_ray()
i.current_length=i.current_length+self.dL
#######
#ball class
######
class ball(): #A spherical object
'''a spherically shaped obstacle'''
def __init__(self,position,radius,mirror): #User-input parameters
self.pos = position
self.r = radius
self.color=color.red
self.n = 1.5 #Let's make it out of glass for now
self.shape = 'sphere'
self.mirror = mirror
self.sphere = sphere(pos=self.pos, radius=self.r, color=self.color, opacity=0.5) #draws a visual representation of the object
def check_boundaries(self,ray):
'''checks to location of a ray in relation to the boundaries of the ball'''
surface_norm = norm(ray.currentPoint-self.pos) #Returns a normalized vector for direction between the sphere and any given ray
rel_pos = self.pos - ray.currentPoint #Relative position from the ray on the current time step to the center of the sphere
rel_old_pos=self.pos - ray.oldPoint #Relative positiong from the ray on the previous time step to the center of the sphere
### The following code should be cleaned up and better commented by me ###
if abs(rel_pos.dot(surface_norm))< self.r and abs(rel_old_pos.dot(surface_norm))> self.r: ### Going into sphere; relative position changed from being larger than the radius to smaller ###
thetaIncident = pi-diff_angle(ray.directionVector,surface_norm) #Checking angle of incidence
thetaRefracted = asin((ray.world_n/self.n)*sin(thetaIncident)) #Snell's law solved for Refreacted angle
a1 = ray.directionVector - surface_norm * (dot(ray.directionVector,surface_norm)) #Extra parameter to make sure the ray stays in the same plane while refracting
ray.directionVector = (-1*cos(thetaRefracted)*surface_norm) + (sin(thetaRefracted)*a1.norm()) #assign a new direction for the ray to continue
ray.current_length = 0
if abs(rel_pos.dot(surface_norm))> self.r and abs(rel_old_pos.dot(surface_norm))< self.r: ### Going out of sphere; relative position changed from being smaller than the radius to larger###
thetaIncident = pi - diff_angle(ray.directionVector,surface_norm)
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
thetaRefracted = thetaIncident
a1 = ray.directionVector - surface_norm * (dot(ray.directionVector,surface_norm))
ray.directionVector = (-1*cos(thetaRefracted)*surface_norm) + (sin(thetaRefracted)*a1.norm())
ray.current_length = 0
else:
thetaRefracted = asin((self.n/ray.world_n)*sin(thetaIncident)) #Snell's Law
a1 = ray.directionVector - surface_norm * (dot(ray.directionVector,surface_norm))
ray.directionVector = (cos(thetaRefracted)*surface_norm) + (sin(thetaRefracted)*a1.norm())
ray.current_length = 0
class block():
'''an optical obstacle class'''
def __init__(self, position, axis, up, length, width, height, material, opacity):
self.position = position
self.axis = axis
self.up = up
self.material = material
self.length = length
self.width = width
self.height = height
if(self.material == "glass"):
self.n = 1.5
self.opacity = opacity
self.draw_block()
def draw_block(self):
self.shape = box(pos = self.position, axis = self.axis, up = self.up, length = self.length, width = self.width, height = self.height, opacity = self.opacity)
def check_boundaries(self, ray):
self.normalFront = self.axis.norm()
self.normalBack = -1 * self.normalFront
self.normalTop = self.up.norm()
self.normalBottom = -1 * self.normalTop
self.normalLSide = cross(self.axis.norm(), self.up.norm())
self.normalRSide = -1 * self.normalLSide
b = ray.currentPoint - self.position
b_old = ray.oldPoint - self.position
#If ALL of these 'check' statements are true, then the ray is within the block
frontCheck = bool(abs(dot(b,self.normalFront)) - ((self.length)/2) <= 0)
backCheck = bool(abs(dot(b,self.normalBack)) - ((self.length)/2) <= 0)
topCheck = bool(abs(dot(b,self.normalTop)) - ((self.height)/2) <= 0)
bottomCheck = bool(abs(dot(b,self.normalBottom)) - ((self.height)/2) <= 0)
lSideCheck = bool(abs(dot(b,self.normalLSide)) - ((self.width)/2) <= 0)
rSideCheck = bool(abs(dot(b,self.normalRSide)) - ((self.width)/2) <= 0)
#If ALL of these are true, then the ray was within the block on the last time step
frontCheck_old = bool(abs(dot(b_old,self.normalFront)) - ((self.length)/2) <= 0)
backCheck_old = bool(abs(dot(b_old,self.normalBack)) - ((self.length)/2) <= 0)
topCheck_old = bool(abs(dot(b_old,self.normalTop)) - ((self.height)/2) <= 0)
bottomCheck_old = bool(abs(dot(b_old,self.normalBottom)) - ((self.height)/2) <= 0)
lSideCheck_old = bool(abs(dot(b_old,self.normalLSide)) - ((self.width)/2) <= 0)
rSideCheck_old = bool(abs(dot(b_old,self.normalRSide)) - ((self.width)/2) <= 0)
def refractIn(face):
thetaRefracted = asin((ray.world_n/self.n)*sin(thetaIncident))
a1 = ray.directionVector - (face * dot(ray.directionVector,face))
ray.directionVector = (1*cos(thetaRefracted)*face) + (sin(thetaRefracted)*a1.norm())
def refractOut(face):
thetaRefracted = asin((self.n/ray.world_n)*sin(thetaIncident))
a1 = ray.directionVector - (face * dot(ray.directionVector,face))
ray.directionVector = (1*cos(thetaRefracted)*face) + (sin(thetaRefracted)*a1.norm())
def reflectOut(face):
ray.color = color.red #Change the color of exiting rays if it undergoes TIF
ray.ray.append(pos = ray.currentPoint, color = ray.color)
thetaReflected = thetaIncident
a1 = ray.directionVector - (face * dot(ray.directionVector,face))
ray.directionVector = (-1*cos(thetaReflected)*face) + (sin(thetaReflected)*a1.norm())
# if(self.n == "mirror"):
# if(frontCheck and not frontCheck_old):
# reflectOut(self.normalFront)
###Check if ray is exiting the block###
if((frontCheck_old and backCheck_old and topCheck_old and bottomCheck_old and lSideCheck_old and rSideCheck_old) and ((not frontCheck and frontCheck_old) or (not backCheck and backCheck_old) or (not topCheck and topCheck_old) or (not bottomCheck and bottomCheck_old) or (not lSideCheck and lSideCheck_old) or (not rSideCheck and rSideCheck_old))):
if(frontCheck_old and not frontCheck): #Exiting Block through Axis Direction
if(b.dot(self.normalBack) < b.dot(self.normalFront)): #Exiting through Front Face
thetaIncident = pi-diff_angle(ray.directionVector,self.normalBack)
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
reflectOut(self.normalFront)
else:
refractOut(self.normalFront)
if(b.dot(self.normalFront) < b.dot(self.normalBack)): #Exiting through Back Face
thetaIncident = pi-diff_angle(ray.directionVector,self.normalFront)
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
reflectOut(self.normalBack)
else:
refractOut(self.normalBack)
if(topCheck_old and not topCheck): #Exiting Block through Up Direction
if(b.dot(self.normalBottom) < b.dot(self.normalTop)): #Exiting through Top Face
thetaIncident = pi-diff_angle(ray.directionVector,self.normalBottom)
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
reflectOut(self.normalTop)
else:
refractOut(self.normalTop)
if(b.dot(self.normalTop) < b.dot(self.normalBottom)): #Exiting through Bottom Face
thetaIncident = pi-diff_angle(ray.directionVector,self.normalTop)
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
reflectOut(self.normalBottom)
else:
refractOut(self.normalBottom)
if(lSideCheck_old and not lSideCheck): #Exiting Block through Cross Direction
if(b.dot(self.normalRSide) < b.dot(self.normalLSide)): #Exiting through Left Face
thetaIncident = pi-diff_angle(ray.directionVector,self.normalRSide)
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
reflectOut(self.normalLSide)
else:
refractOut(self.normalLSide)
if(b.dot(self.normalLSide) < b.dot(self.normalRSide)): #Exiting through Right Face
thetaIncident = pi-diff_angle(ray.directionVector,self.normalLSide)
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
reflectOut(self.normalRSide)
else:
refractOut(self.normalRSide)
###Check if ray is entering the block###
if((frontCheck and backCheck and topCheck and bottomCheck and lSideCheck and rSideCheck) and (frontCheck_old or backCheck_old or topCheck_old or bottomCheck_old or lSideCheck_old or rSideCheck_old)):
if(frontCheck and not frontCheck_old): #Entering through the axis direction
if(b.dot(self.normalFront) < b.dot(self.normalBack)): #Entered through front
thetaIncident = diff_angle(ray.directionVector, self.normalFront)
refractIn(self.normalFront)
if(b.dot(self.normalBack) < b.dot(self.normalFront)): #Entered through Back
thetaIncident = diff_angle(ray.directionVector, self.normalBack)
refractIn(self.normalBack)
if(topCheck and not topCheck_old): #Entering through the up direction
if(b.dot(self.normalTop) < b.dot(self.normalBottom)): #Entering through Top
thetaIncident = pi-diff_angle(ray.directionVector, self.normalTop)
refractIn(self.normalTop)
if(b.dot(self.normalBottom) < b.dot(self.normalTop)): #Entering through Bottom
thetaIncident = pi-diff_angle(ray.directionVector, self.normalBottom)
refractIn(self.normalBottom)
if(lSideCheck and not lSideCheck_old): #Entering through cross direction
if(b.dot(self.normalLSide) < b.dot(self.normalRSide)): #Entering through Left Side
thetaIncident = pi-diff_angle(ray.directionVector, self.normalLSide)
refractIn(self.normalLSide)
if(b.dot(self.normalRSide) < b.dot(self.normalLSide)): #Entering through Right Side
thetaIncident = pi-diff_angle(ray.directionVector, self.normalRSide)
refractIn(self.normalRSide)
class mirrorBlock():
'''An block class that has outawrdly reflective faces'''
def __init__(self, position, axis, up, length, width, height, opacity):
self.position = position
self.axis = axis
self.up = up
self.length = length
self.width = width
self.height = height
self.opacity = opacity
self.draw_block()
def draw_block(self):
self.shape = box(pos = self.position, axis = self.axis, up = self.up, length = self.length, width = self.width, height = self.height, opacity = self.opacity)
def check_boundaries(self, ray):
self.normalFront = self.axis.norm()
self.normalBack = -1 * self.normalFront
self.normalTop = self.up.norm()
self.normalBottom = -1 * self.normalTop
self.normalLSide = cross(self.axis.norm(), self.up.norm())
self.normalRSide = -1 * self.normalLSide
b = ray.currentPoint - self.position
b_old = ray.oldPoint - self.position
#If ALL of these 'check' statements are true, then the ray is within the block
frontCheck = bool(abs(dot(b,self.normalFront)) - ((self.length)/2) <= 0)
backCheck = bool(abs(dot(b,self.normalBack)) - ((self.length)/2) <= 0)
topCheck = bool(abs(dot(b,self.normalTop)) - ((self.height)/2) <= 0)
bottomCheck = bool(abs(dot(b,self.normalBottom)) - ((self.height)/2) <= 0)
lSideCheck = bool(abs(dot(b,self.normalLSide)) - ((self.width)/2) <= 0)
rSideCheck = bool(abs(dot(b,self.normalRSide)) - ((self.width)/2) <= 0)
#If ALL of these are true, then the ray was within the block on the last time step
frontCheck_old = bool(abs(dot(b_old,self.normalFront)) - ((self.length)/2) <= 0)
backCheck_old = bool(abs(dot(b_old,self.normalBack)) - ((self.length)/2) <= 0)
topCheck_old = bool(abs(dot(b_old,self.normalTop)) - ((self.height)/2) <= 0)
bottomCheck_old = bool(abs(dot(b_old,self.normalBottom)) - ((self.height)/2) <= 0)
lSideCheck_old = bool(abs(dot(b_old,self.normalLSide)) - ((self.width)/2) <= 0)
rSideCheck_old = bool(abs(dot(b_old,self.normalRSide)) - ((self.width)/2) <= 0)
def reflectIn(face):
thetaReflected = thetaIncident
a1 = ray.directionVector - (face * dot(ray.directionVector,face))
ray.directionVector = (-1*cos(thetaReflected)*face) + (sin(thetaReflected)*a1.norm())
###Check if ray is entering the mirrorBlock###
if((frontCheck and backCheck and topCheck and bottomCheck and lSideCheck and rSideCheck) and (frontCheck_old or backCheck_old or topCheck_old or bottomCheck_old or lSideCheck_old or rSideCheck_old)):
if(frontCheck and not frontCheck_old): #Entering through the axis direction
if(b.dot(self.normalFront) < b.dot(self.normalBack)): #Entered through front
thetaIncident = diff_angle(ray.directionVector, self.normalFront)
reflectIn(self.normalFront)
if(b.dot(self.normalBack) < b.dot(self.normalFront)): #Entered through Back
thetaIncident = diff_angle(ray.directionVector, self.normalBack)
reflectIn(self.normalBack)
if(topCheck and not topCheck_old): #Entering through the up direction
if(b.dot(self.normalTop) < b.dot(self.normalBottom)): #Entering through Top
thetaIncident = pi-diff_angle(ray.directionVector, self.normalTop)
reflectIn(self.normalTop)
if(b.dot(self.normalBottom) < b.dot(self.normalTop)): #Entering through Bottom
thetaIncident = pi-diff_angle(ray.directionVector, self.normalBottom)
reflectIn(self.normalBottom)
if(lSideCheck and not lSideCheck_old): #Entering through cross direction
if(b.dot(self.normalLSide) < b.dot(self.normalRSide)): #Entering through Left Side
thetaIncident = pi-diff_angle(ray.directionVector, self.normalLSide)
reflectIn(self.normalLSide)
if(b.dot(self.normalRSide) < b.dot(self.normalLSide)): #Entering through Right Side
thetaIncident = pi-diff_angle(ray.directionVector, self.normalRSide)
reflectIn(self.normalRSide)
class lens():
'''a lens to focus light rays'''
def __init__ (self, position, axis, n, world_n, focal, perpRad): #User-input parameters
self.position = position #position of the center of the lens?
self.axis = norm(axis)
self.n = n #Index of refraction
self.f = focal #Desired focal length
f = self.f
self.h = perpRad #Height of lens
h = self.h
self.world_n = world_n
self.color = color.white
def thick_lens(R):
'''Function that can be used to calculate the radius of curvature of a lens
For some reason I need to take the absolute value of the argument inside the square
root. Without this fsolve throws a domain error.'''
return (n-1)*(2/R[0]+((2*R[0]-2*sqrt(abs(R[0]**2-h**2/4))*(n-1))/(n*R[0]**2)))-1/f
def thickness(R):
'''a function to return thickness based on an input radius of curvature'''
return 2*R-2*sqrt(R**2 - h**2/4)
r = fsolve(thick_lens,50)
#print(r)
self.radius = r[0]
self.thickness = thickness(self.radius)
self.C1_pos = self.position - (self.radius - (self.thickness/2))*self.axis
self.C2_pos = self.position + (self.radius - (self.thickness/2))*self.axis
self.draw_lens()
def check_boundaries(self, ray):
'''check the position of a ray relative to the boundaries of the lens--made by the intersection of two spheres as a sort of 3-dimensional venn diagram'''
surfaceNorm1 = norm(ray.currentPoint - (self.C1_pos))
surfaceNorm2 = norm(ray.currentPoint - (self.C2_pos))
rel_pos1 = self.C1_pos - ray.currentPoint
rel_pos2 = self.C2_pos - ray.currentPoint
rel_old_pos1 = self.C1_pos - ray.oldPoint
rel_old_pos2 = self.C2_pos - ray.oldPoint
circle1Check = bool(abs((rel_pos1).dot(surfaceNorm1)) <= self.radius) #if true, ray is inside 'circle1'
circle2Check = bool(abs((rel_pos2).dot(surfaceNorm2)) <= self.radius)
circle1Check_old = bool(abs((rel_old_pos1).dot(surfaceNorm1)) <= self.radius) #if true, ray was inside 'circle1' on the last time step
circle2Check_old = bool(abs((rel_old_pos2).dot(surfaceNorm2)) <= self.radius)
#Ray is entering lens
if((circle1Check and circle2Check) and ((not circle1Check_old) or (not circle2Check_old))): #ray is now in the lens, but was outside
ray.color = color.blue #Change to color of incoming rays to indicate the have interacted with the lens
ray.ray.append(pos = ray.currentPoint, color=ray.color)
if(not circle2Check_old):#Entering through face inside circle 1
thetaIncident = pi-diff_angle(ray.directionVector,surfaceNorm2)
thetaRefracted = asin((ray.world_n/self.n)*sin(thetaIncident))
a1 = ray.directionVector - surfaceNorm2 * (dot(ray.directionVector,surfaceNorm2))
ray.directionVector = (-1*cos(thetaRefracted)*surfaceNorm2) + (sin(thetaRefracted)*a1.norm())
if (not circle1Check_old): #Entering through face inside circle 2
thetaIncident = pi-diff_angle(ray.directionVector,surfaceNorm1)
thetaRefracted = asin((ray.world_n/self.n)*sin(thetaIncident))
a1 = ray.directionVector - surfaceNorm1 * (dot(ray.directionVector,surfaceNorm1))
ray.directionVector = (-1*cos(thetaRefracted)*surfaceNorm1) + (sin(thetaRefracted)*a1.norm())
#Ray is exiting the lens
if((circle1Check_old and circle2Check_old) and (not circle1Check or not circle2Check)):
ray.color = color.red #Change the color of exiting rays to know what is interacting with the lens
ray.ray.append(pos = ray.currentPoint, color = ray.color)
if(not circle2Check): #ray is still in circle 1, so it exited through face 1
thetaIncident = diff_angle(ray.directionVector,(surfaceNorm2))
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
thetaRefracted = thetaIncident
a1 = ray.directionVector - (-1*surfaceNorm2) * (dot(ray.directionVector,(-1*surfaceNorm2)))
ray.directionVector = ((-1) * cos(thetaRefracted)*(surfaceNorm2)) + (sin(thetaRefracted)*a1.norm())
ray.draw_ray()
else:
thetaRefracted = asin((self.n/ray.world_n)*sin(thetaIncident))
a1 = ray.directionVector - (-1*surfaceNorm2) * (dot(ray.directionVector,(-1*surfaceNorm2)))
ray.directionVector = (cos(thetaRefracted)*(surfaceNorm2)) + (sin(thetaRefracted)*a1.norm())
if(not circle1Check): #ray is still in circle 2, so it exited through face 2
thetaIncident = diff_angle(ray.directionVector,(surfaceNorm1))
if((self.n/ray.world_n)*sin(thetaIncident) > 1): #Argument of arcsin > 1 --> Total Internal Reflection
thetaRefracted = thetaIncident
a1 = ray.directionVector - (-1*surfaceNorm1) * (dot(ray.directionVector,(-1*surfaceNorm1)))
ray.directionVector = (-1*cos(thetaRefracted)*(surfaceNorm1)) + (sin(thetaRefracted)*a1.norm())
ray.draw_ray()
else:
thetaRefracted = asin((self.n/ray.world_n) * sin(thetaIncident))
a1 = ray.directionVector - (surfaceNorm1) * (dot(ray.directionVector,(surfaceNorm1)))
ray.directionVector = (cos(thetaRefracted) * (surfaceNorm1)) + (sin(thetaRefracted)*a1.norm())
def draw_lens(self):
self.shape = ellipsoid(pos = self.position, axis = self.axis, length = self.thickness, height = self.h, width = self.h, color = self.color, opacity = 0.5)
#######
# Test Code
#######
lens1 = lens(vec(0,0,0), vec(0.92,0.37,0), 1.5, 1, 3, 5)
#circle_thing = ball(vec(0,0,0), 3, 0)
#circle_thing_2 = ball(vec(8,0,0), 3, 0)
#square_thing_2=block(vec(10,9,0), vec(1,0,0), vec(0,1,0), 30, 30, 1, "mirror", opacity=0.3)
#ps1 = pointSource(vec(-3,0,0))
beam1 = beam(vec(-5,-2,0), vec(5,2,0), 2.2)
#light1=ray(vec(0,1,2),vec(1,1,0),color.blue)
#light2=ray(vec(-5,-2,1),vec(1,1,0), color.blue)
#light3=ray(vec(-5,1,3), vec(1,1,0), color=color.yellow)
#light4=ray(vec(-5,3,1), vec(1,1,0), color.red)
#light5=ray(vec(-5,-2,-2), vec(1,1,0), color.red)
#light6=ray(vec(-5,0,-3),vec(1,1,0),color.red)
#light7=ray(vec(-5,1,-1),vec(1,1,0), color.blue)
#light8=ray(vec(-5,0,0), vec(1,1,0), color=color.yellow)
#light9=ray(vec(-5,0,1), vec(1,1,0), color.blue)
#light10=ray(vec(-5,0,2), vec(1,1,0), color.red)
my_world=world()
#my_world.add_ray(light1)
#my_world.add_ray(light2)
#my_world.add_ray(light3)
#my_world.add_ray(light4)
#my_world.add_ray(light5)
#my_world.add_ray(light6)
#my_world.add_ray(light7)
#my_world.add_ray(light8)
#my_world.add_ray(light9)
#my_world.add_ray(light10)
my_world.add_beam(beam1)
#my_world.add_object(circle_thing)
#my_world.add_object(circle_thing_2)
my_world.add_object(lens1)
#my_world.add_light(ps1)
#my_world.add_object(square_thing)
#my_world.add_object(square_thing_2)
my_world.draw_rays()
In [ ]:
In [ ]: