'Refract, reflect, absorb, and/or scatter ray. This function may create and return new rays'

def propagateRay(self, ray):

    '\n                                NOTE::    We    can    probably    use    this    to    compute    refractions    faster:    (from    GLSL    120    docs)\n\n                                For    the    incident    vector    I    and    surface    normal    N,    and    the\n                                ratio    of    indices    of    refraction    eta,    return    the    refraction\n                                vector.    The    result    is    computed    by\n                                k    =    1.0    -    eta    *    eta    *    (1.0    -    dot(N,    I)    *    dot(N,    I))\n                                if    (k    <    0.0)\n                                                return    genType(0.0)\n                                else\n                                                return    eta    *    I    -    (eta    *    dot(N,    I)    +    sqrt(k))    *    N\n                                The    input    parameters    for    the    incident    vector    I    and    the\n                                surface    normal    N    must    already    be    normalized    to    get    the\n                                desired    results.    eta    ==    ratio    of    IORs\n\n\n                                For    reflection:\n                                For    the    incident    vector    I    and    surface    orientation    N,\n                                returns    the    reflection    direction:\n                                I    \xe2\x80\x93    2    \xe2\x88\x97    dot(N,    I)    \xe2\x88\x97    N\n                                N    must    already    be    normalized    in    order    to    achieve    the\n                                desired    result.\n                                '
    iors = [self.ior(ray['wl']), 1.0]
    for i in [0, 1]:
        surface = self.surfaces[i]
        ior = iors[i]
        (p1, ai) = surface.intersectRay(ray)
        if (p1 is None):
            ray.setEnd(None)
            break
        p1 = surface.mapToItem(ray, p1)
        rd = ray['dir']
        a1 = np.arctan2(rd[1], rd[0])
        ar = ((a1 - ai) + np.arcsin(((np.sin(ai) * ray['ior']) / ior)))
        ray.setEnd(p1)
        dp = Point(np.cos(ar), np.sin(ar))
        ray = Ray(parent=ray, ior=ior, dir=dp)
    return [ray]
