# 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 numpy import random, linalg as LA
from .ray_bundle import RayBundle
from .spatial_geometry import rotation_to_z
import numpy as N
    xi1 = random.uniform(high=2*N.pi, size=num_rays)
    xi2 = random.uniform(size=num_rays)
    theta = N.arcsin(N.sin(ang_range)*N.sqrt(xi2))
    sin_th = N.sin(theta)
    a = N.vstack((N.cos(xi1)*sin_th, N.sin(xi1)*sin_th , N.cos(theta)))
    return a

def solar_disk_bundle(num_rays,  center,  direction,  radius,  ang_range, flux=None):
    """
    Generates a ray bundle emanating from a disk, with each surface element of 
    the disk having the same ray density. The rays all point at directions uniformly 
    distributed between a given angle range from a given direction.
    Setting of the bundle's energy is left to the caller.
    
    Arguments:
    num_rays - number of rays to generate.
    center - a column 3-array with the 3D coordinate of the disk's center
    direction - a 1D 3-array with the unit average direction vector for the
        bundle.
    radius - of the disk.
    ang_range - in radians, the maximum deviation from <direction>.
    flux - if not None, the ray bundle's energy is set such that each ray has
        an equal amount of energy, and the total energy is flux*pi*radius**2
    
    Returns: 
    A RayBundle object with the above charachteristics set.
    """
    a = pillbox_sunshape_directions(num_rays, ang_range)
    
    # Rotate to a frame in which <direction> is Z:

# 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/sources.py
from numpy import random, linalg as LA
from .ray_bundle import RayBundle
from .spatial_geometry import rotation_to_z
import numpy as N

    xi1 = random.uniform(high=2*N.pi, size=num_rays)
    xi2 = random.uniform(size=num_rays)
    theta = N.arcsin(N.sin(ang_range)*N.sqrt(xi2))
    sin_th = N.sin(theta)
    a = N.vstack((N.cos(xi1)*sin_th, N.sin(xi1)*sin_th , N.cos(theta)))
    return a

def solar_disk_bundle(num_rays,  center,  direction,  radius,  ang_range, flux=None):
    """
    Generates a ray bundle emanating from a disk, with each surface element of 
    the disk having the same ray density. The rays all point at directions uniformly 
    distributed between a given angle range from a given direction.
    Setting of the bundle's energy is left to the caller.
    
    Arguments:
    num_rays - number of rays to generate.
    center - a column 3-array with the 3D coordinate of the disk's center
    direction - a 1D 3-array with the unit average direction vector for the
        bundle.
    radius - of the disk.
    ang_range - in radians, the maximum deviation from <direction>.
    flux - if not None, the ray bundle's energy is set such that each ray has
        an equal amount of energy, and the total energy is flux*pi*radius**2
    
    Returns: 
    A RayBundle object with the above charachteristics set.
    """
    a = pillbox_sunshape_directions(num_rays, ang_range)
    
    # Rotate to a frame in which <direction> is Z:

    perp_rot = rotation_to_z(direction)