Concave Mirror

From GeoMod

Jump to: navigation, search

Image:Concave mirror-500.gif

A model that uses a ray diagram to show the image produced by an object in a concave mirror.

  • The white arrow is the object.
    • You can move the arrow from side to side by pulling on its base.
    • You can make the arrow taller by dragging the tip.
  • The yellow arrow is the image.
  • The green dot is the focus.

Gallery

Video: http://youtu.be/gH0ERd1PI8Y

Code

mirror-4.py

from visual import *
import subprocess

def take_screenshot(fnum):
    fnum = str(fnum).zfill(3)
    fname = "img-"+fnum+".png"
    #print fname
    cmd = ["screencapture", "-S", fname]
    test = subprocess.Popen( cmd, stdout=subprocess.PIPE).communicate()[0]


class mirror:

    def __init__(self, R=1, a=-1, c=1):
        '''for a parabolic mirror'''
        self.R = R
        self.a = a
        self.c = c
        self.vertex = vector(self.c, 0)
        self.draw_mirror()
        self.draw_focus()
        self.fd = abs(self.focus.x-self.vertex.x)      #focal distance
        self.draw_center()
        self.parallel_rays=[]
        self.focus_rays=[]
        self.parallel_rays_imag=[]
        self.focus_rays_imag=[]
        self.axis = curve(pos=[(-4.0,0),(4.0,0)],color=color.red)
        self.xmin = -3
        self.xmax = 3

    def x(self, y):
        return self.a * y**2 + self.c

    def draw_mirror(self, ny=100):
        y = arange(-self.R, self.R,2.0*self.R/ny)
        x = self.a * y * y + self.c
        
        #print theta, x, y
        mirror = curve(x=x, y=y, color=color.yellow)

    def draw_center(self, point_radius=-9999):
        if point_radius == -9999:
            point_radius = self.R/25.0

        self.center = sphere(pos=(self.vertex.x-(2*self.fd),0,0), radius=point_radius)
        self.two_f_label = label(pos=self.center.pos-vector(.0,.2,0),text="2f",
                                 height=0.1, box=0) 
   
    def draw_focus(self, point_radius=-9999):
        if point_radius == -9999:
            point_radius = self.R/30.0
            
        self.focus = sphere(pos=(self.c+(1.0/(4.0*self.a)),0), radius=point_radius, color=color.green)
        self.focus_label = label(pos=self.focus.pos-vector(0,.2,0),text="focus",
                                 height=0.1, box=0) 
        print "focus = ", self.focus.pos

    def draw_image(self, target):
        self.add_parallel_ray(target.pos+target.axis)
        self.update_parallel_rays(target)
        #self.draw_parallel_rays()
        self.add_focus_ray(target.pos+target.axis)
        self.update_focus_rays(target)
        #self.draw_focus_rays()


        '''find intersection point'''
        line1 = line_eqn_from_last_2_pts_of_curve(self.focus_rays[0])
        line2 = line_eqn_from_last_2_pts_of_curve(self.parallel_rays[0])
        intersect = intersection_of_two_lines(line1,line2)
        #print "intersection point = ", intersect

        self.image = arrow(pos=(intersect.x,0), color=color.yellow,axis=(0,intersect.y,0),shaftwidth=target.shaftwidth)

    def update_image(self, target):
        self.update_parallel_rays(target)
        self.update_focus_rays(target)

        '''find intersection point'''
        line1 = line_eqn_from_last_2_pts_of_curve(self.focus_rays[0])
        line2 = line_eqn_from_last_2_pts_of_curve(self.parallel_rays[0])
        intersect = intersection_of_two_lines(line1,line2)
        #print "intersection point = ", intersect

        self.image.pos = vector(intersect.x,0)
        self.image.axis = vector(0,intersect.y,0)

        #self.image = arrow(pos=(intersect.x,0), color=color.yellow,axis=(),shaftwidth=target.shaftwidth)

    def add_parallel_ray(self, st_pos):
        self.parallel_rays.append(curve(x=arange(0,4)))
        #self.parallel_rays[-1].append(pos=st_pos)
        self.parallel_rays_imag.append(curve(color=color.green, x=arange(0,2)))


    def update_parallel_rays(self, target):
        
        
        for n,i in enumerate(self.parallel_rays):
            xd = abs(i.x[0]-self.vertex.x)
            i.pos[0] = target.pos+target.axis

            '''find intersection point'''
            
            y = i.y[0]
            x = self.x(y)
            intpos=vector(x,y)
            i.pos[1]=intpos

            '''move through focus'''
            i.pos[2]=self.focus.pos
            '''add further point'''
            #line_eqn = line_eqn_from_last_2_pts_of_curve(i)
            line_eqn = line_from_pts(vector(i.pos[1]),vector(i.pos[2]))
            xf = self.xmin
            yf = line_eqn.y(xf)
            i.pos[3]=vector(xf, yf)
            if xd < self.fd:
                '''add imaginary (projected) lines'''
                self.parallel_rays_imag[n].pos[0]=intpos
                imag_line = line_eqn
                self.parallel_rays_imag[n].pos[1]=vector(5,imag_line.y(5))
            else:
                self.parallel_rays_imag[n].pos[0]=vector(0,0)
                self.parallel_rays_imag[n].pos[1]=vector(0,0)
                


            

            
    def add_focus_ray(self, st_pos):
        self.focus_rays.append(curve(x=arange(4)))
        self.focus_rays_imag.append(curve(color=color.green, x=arange(2)))


    def update_focus_rays(self, target):
        #print target.pos
        for n, i in enumerate(self.focus_rays):
            xd = abs(target.pos.x-self.vertex.x)
            #print xd
            
            if (xd > self.fd):
                '''initial position'''
                #print i.pos[0]
                i.pos[0] = target.pos+target.axis
                '''add focus position'''
                i.pos[1]=self.focus.pos
                '''add reflection point'''
                line_eqn = line_from_pts(vector(i.pos[0]),vector(i.pos[1]))
                intpos = self.intersection_with_line(line_eqn)
                i.pos[2]=intpos
                '''add outgoing horizontal line'''
                i.pos[3]=vector(self.xmin,intpos.y)
                '''hide imaginary rays'''
                self.focus_rays_imag[n].pos[0]=vector(0,0)
                imag_line = line_eqn
                self.focus_rays_imag[n].pos[1] = vector(0,0)

            else:
                i.pos[0] = self.focus.pos
                i.pos[1] = target.pos+target.axis
                '''add reflection point'''
                #print i.pos[0], i.pos[1]
                line_eqn = line_from_pts(vector(i.pos[0]),vector(i.pos[1]))
                #print line_eqn.m, line_eqn.b
                intpos = self.intersection_with_line(line_eqn)
                i.pos[2]=intpos
                '''add outgoing horizontal line'''
                i.pos[3]=vector(self.xmin,intpos.y)
                '''add imaginary (projected) lines'''
                self.focus_rays_imag[n].pos[0]=intpos
                imag_line = line_eqn
                self.focus_rays_imag[n].pos[1] = vector(5,intpos.y)
                                

    def intersection_with_line(self, l):
        ''' Line (l) eqn:  y = l.m x + l.b'''
##        a = l.m**2 + 1
##        b = 2 * l.b * l.m
##        c = l.b**2 - self.R**2
        a = l.m * self.a
        b = -1.0
        c = l.m * self.c + l.b
        #print l.m, l.b
        #print a, b, c

        x1 = None
        x2 = None
        

        (y1, y2) = quadratic_formula(a, b, c)

        #print "y1,y2 = ", l.m, self.a, a, b, c, y1, y2
        if y1:
            x1 = self.x(y1)
        if y2:
            x2 = self.x(y2)

        if x1 >= x2:
            return vector(x1, y1)
        else:
            return vector(x2,y2)
                        
            
    
def quadratic_formula(a, b, c):
    s = b**2 - 4.*a*c
    if s >= 0 and a<>0:
        x1 = (-b + sqrt(s))/(2.0*a)
        x2 = (-b - sqrt(s))/(2.0*a)
    else:
        x1 = None
        x2 = None
    return (x1, x2)
                        
def intersection_of_two_lines(line1, line2):
    x = (line2.b - line1.b) / (line1.m - line2.m)
    y = line1.y(x)
    return vector(x, y)
    
            

def line_eqn_from_last_2_pts_of_curve(c, pts=-1):
    p1 = c.pos[pts]
    p2 = c.pos[pts-1]
    m = (p2[1] - p1[1]) / (p2[0] - p1[0])
    b = p1[1] - m * p1[0]
    return (line(m,b))

        
def line_from_pts(p1, p2):
    '''find slope (m) and intercept (b)'''
    m = (p2.y - p1.y) / (p2.x - p1.x)
    b = p1.y - m * p1.x
    return (line(m, b))


class line:
    def __init__(self, m = 0.0, b=0.0):
        self.m = m
        self.b = b
    def y(self, x):
        return self.m * x + self.b


scene = display(title='Mirrors',
     x=0, y=0, width=1000, height=500,
     background=(0,0,0))

scene.range=3.5


reflector = mirror(R = 1.5, a=-0.15, c=2)
scene.center = reflector.focus.pos

target = arrow(shaftwidth=0.05, pos=(-3,0,0), length=0.5, axis=(0,1,0))
dx = 0.01

reflector.draw_image(target)

fnum = 0

by = 0.3 # click this close to tail or tip
drag = None # have not selected tail or tip of arrow
while True:
    rate(40)

    '''move target'''
##    if target.pos.x < reflector.vertex.x-dx:
##        fnum+=1
##        target.pos.x += dx
##        reflector.update_image(target)
##        take_screenshot(fnum)
    
    if scene.mouse.events:
        m1 = scene.mouse.getevent() # obtain event
        if m1.press:
            if mag(target.pos-m1.pos) <= by:
                drag = 'tail' # near tail of arrow
            elif mag((target.pos+target.axis)-m1.pos) <= by:
                drag = 'tip' # near tip of arrow
            drag_pos = m1.pos # save press location
        elif m1.drop: # released at end of drag
            drag = None # end dragging (None is False)
    if drag:
        new_pos = scene.mouse.pos
        if new_pos != drag_pos: # if mouse has moved
            displace = new_pos - drag_pos # moved how far
            drag_pos = new_pos # update drag position
            if drag == 'tail':
                target.pos.x += displace.x # displace the tail
                #reflector.update_focus_rays(target)
                #reflector.update_parallel_rays(target)
                reflector.update_image(target)
            else:
                target.axis.y += displace.y # displace the tip
                #reflector.update_focus_rays(target)
                #reflector.update_parallel_rays(target)
                reflector.update_image(target)



Personal tools