# Path: tracer/spatial_geometry.py
# def rotation_to_z(vecs):
#     """
#     Generate a rotation into a frame whose Z zxis points along the direction
#     indicated by ``vecs``. The rest of the directions are determined by
#     requiring the new X to lie on the XY plane of the original frame, and by
#     the right-hand rule.
#     
#     In the singular case that the required direction is the Z axis, the
#     original frame is retained.
#     
#     Arguments:
#     vec - a 3-component 1D array representing a unit direction in 3D space.
#     
#     Returns:
#     A 3x3 array representing the global-to-local rotation to get the desired
#         frame.
#     """
#     vecs = N.atleast_2d(vecs)
#     perp = N.hstack((vecs[:,1][:,None],  -vecs[:,0][:,None],
#         N.zeros((vecs.shape[0], 1)) ))
#     perp[N.all(perp == 0, axis=1)] = N.r_[1.,  0.,  0.]
#     perp /= N.sqrt(N.sum(perp**2, axis=1))[:,None]
#     perp_rot = N.concatenate((perp[...,None], N.cross(vecs, perp)[...,None],
#         vecs[...,None]), axis=2)
#     return N.squeeze(perp_rot)


from . import optics, ray_bundle, sources
from .spatial_geometry import rotation_to_z
import numpy as N
                geometry.get_normals()),
            energy=rays.get_energy()[selector]*R,
            parents=selector)
        
        refracted_rays = rays.inherit(selector[refr], vertices=inters[:,refr],
            direction=out_dirs, parents=selector[refr],
            energy=rays.get_energy()[selector][refr]*(1 - R[refr]),
            ref_index=n2[refr])
        
        return reflected_rays + refracted_rays

class LambertianReflector(object):
    """
    Represents the optics of an ideal diffuse (lambertian) surface, i.e. one
    that reflects rays in a random direction (uniform distribution of
    directions in 3D, see tracer.sources.pillbox_sunshape_directions)
    """
    def __init__(self, absorptivity):
        self._abs = absorptivity
    
    def __call__(self, geometry, rays, selector):
        """
        Arguments:
        geometry - a GeometryManager which knows about surface normals, hit
            points etc.
        rays - the incoming ray bundle (all of it, not just rays hitting this
            surface)
        selector - indices into ``rays`` of the hitting rays.
        """
        directs = sources.pillbox_sunshape_directions(len(selector), N.pi/2.)

# Path: tracer/spatial_geometry.py
# def rotation_to_z(vecs):
#     """
#     Generate a rotation into a frame whose Z zxis points along the direction
#     indicated by ``vecs``. The rest of the directions are determined by
#     requiring the new X to lie on the XY plane of the original frame, and by
#     the right-hand rule.
#     
#     In the singular case that the required direction is the Z axis, the
#     original frame is retained.
#     
#     Arguments:
#     vec - a 3-component 1D array representing a unit direction in 3D space.
#     
#     Returns:
#     A 3x3 array representing the global-to-local rotation to get the desired
#         frame.
#     """
#     vecs = N.atleast_2d(vecs)
#     perp = N.hstack((vecs[:,1][:,None],  -vecs[:,0][:,None],
#         N.zeros((vecs.shape[0], 1)) ))
#     perp[N.all(perp == 0, axis=1)] = N.r_[1.,  0.,  0.]
#     perp /= N.sqrt(N.sum(perp**2, axis=1))[:,None]
#     perp_rot = N.concatenate((perp[...,None], N.cross(vecs, perp)[...,None],
#         vecs[...,None]), axis=2)
#     return N.squeeze(perp_rot)


# Path: tracer/optics_callables.py
from . import optics, ray_bundle, sources
from .spatial_geometry import rotation_to_z
import numpy as N

                geometry.get_normals()),
            energy=rays.get_energy()[selector]*R,
            parents=selector)
        
        refracted_rays = rays.inherit(selector[refr], vertices=inters[:,refr],
            direction=out_dirs, parents=selector[refr],
            energy=rays.get_energy()[selector][refr]*(1 - R[refr]),
            ref_index=n2[refr])
        
        return reflected_rays + refracted_rays

class LambertianReflector(object):
    """
    Represents the optics of an ideal diffuse (lambertian) surface, i.e. one
    that reflects rays in a random direction (uniform distribution of
    directions in 3D, see tracer.sources.pillbox_sunshape_directions)
    """
    def __init__(self, absorptivity):
        self._abs = absorptivity
    
    def __call__(self, geometry, rays, selector):
        """
        Arguments:
        geometry - a GeometryManager which knows about surface normals, hit
            points etc.
        rays - the incoming ray bundle (all of it, not just rays hitting this
            surface)
        selector - indices into ``rays`` of the hitting rays.
        """
        directs = sources.pillbox_sunshape_directions(len(selector), N.pi/2.)

        directs = N.sum(rotation_to_z(geometry.get_normals().T) * \