Ejemplo n.º 1
0
def batch_of_rays(entry, exit):
    """
    Definition to generate a batch of rays with given entry point(s) and exit point(s). Note that the mapping is one to one, meaning nth item in your entry points list will exit from nth item in your exit list and generate that particular ray. Note that you can have a combination like nx3 points for entry or exit and 1 point for entry or exit. But if you have multiple points both for entry and exit, the number of points have to be same both for entry and exit.

    Parameters
    ----------
    entry      : ndarray
                 Either a single point with size of 3 or multiple points with the size of nx3.
    exit       : ndarray
                 Either a single point with size of 3 or multiple points with the size of nx3.

    Returns
    ----------
    rays       : ndarray
                 Generated batch of rays.
    """
    norays = np.array([0, 0])
    if len(entry.shape) == 1:
        entry = entry.reshape((1, 3))
    if len(exit.shape) == 1:
        exit = exit.reshape((1, 3))
    norays = np.amax(np.asarray([entry.shape[0], exit.shape[0]]))
    if norays > exit.shape[0]:
        exit = np.repeat(exit, norays, axis=0)
    elif norays > entry.shape[0]:
        entry = np.repeat(entry, norays, axis=0)
    rays = []
    norays = int(norays)
    for i in range(norays):
        rays.append(create_ray_from_two_points(entry[i], exit[i]))
    rays = np.asarray(rays)
    return rays
Ejemplo n.º 2
0
def read_PLY_point_cloud(filename):
    """
    Definition to read a PLY file as a point cloud.

    Parameters
    ----------
    filename     : str
                   Filename of a PLY file.

    Returns
    ----------
    point_cloud  : ndarray
                   An array filled with poitns from the PLY file.
    """
    plydata      = PlyData.read(filename)
    if np.__name__ != 'numpy':
        import numpy as np_ply
        point_cloud      = np_ply.zeros((plydata['vertex'][:].shape[0],3))
        point_cloud[:,0] = np_ply.asarray(plydata['vertex']['x'][:])
        point_cloud[:,1] = np_ply.asarray(plydata['vertex']['y'][:])
        point_cloud[:,2] = np_ply.asarray(plydata['vertex']['z'][:])
        point_cloud      = np.asarray(point_cloud)
    else:
        point_cloud      = np.zeros((plydata['vertex'][:].shape[0],3))
        point_cloud[:,0] = np.asarray(plydata['vertex']['x'][:])
        point_cloud[:,1] = np.asarray(plydata['vertex']['y'][:])
        point_cloud[:,2] = np.asarray(plydata['vertex']['z'][:])
    return point_cloud
Ejemplo n.º 3
0
def reflect(input_ray, normal):
    """ 
    Definition to reflect an incoming ray from a surface defined by a surface normal. Used method described in G.H. Spencer and M.V.R.K. Murty, "General Ray-Tracing Procedure", 1961.

    Parameters
    ----------
    input_ray    : ndarray
                   A vector/ray (2x3). It can also be a list of rays (nx2x3).
    normal       : ndarray
                   A surface normal (2x3). It also be a list of normals (nx2x3).

    Returns
    ----------
    output_ray   : ndarray
                   Array that contains starting points and cosines of a reflected ray.
    """
    input_ray = np.asarray(input_ray)
    normal = np.asarray(normal)
    if len(input_ray.shape) == 2:
        input_ray = input_ray.reshape((1, 2, 3))
    if len(normal.shape) == 2:
        normal = normal.reshape((1, 2, 3))
    mu = 1
    div = normal[:, 1, 0]**2 + normal[:, 1, 1]**2 + normal[:, 1, 2]**2
    a = mu * (input_ray[:, 1, 0] * normal[:, 1, 0] + input_ray[:, 1, 1] *
              normal[:, 1, 1] + input_ray[:, 1, 2] * normal[:, 1, 2]) / div
    n = np.int(np.amax(np.array([normal.shape[0], input_ray.shape[0]])))
    output_ray = np.zeros((n, 2, 3))
    output_ray[:, 0] = normal[:, 0]
    output_ray[:, 1] = input_ray[:, 1] - 2 * a * normal[:, 1]
    if output_ray.shape[0] == 1:
        output_ray = output_ray.reshape((2, 3))
    return output_ray
Ejemplo n.º 4
0
def nufft2(field, fx, fy, size=None, sign=1, eps=10**(-12)):
    """
    """
    if np.__name__ == 'cupy':
        fx = np.asnumpy(fx).astype(np.float64)
        fy = np.asnumpy(fy).astype(np.float64)
        image = np.asnumpy(np.copy(field)).astype(np.complex128)
    else:
        image = np.copy(field).astype(np.complex128)
    if type(size) == type(None):
        result = finufft.nufft2d1(fx.flatten(),
                                  fy.flatten(),
                                  image.flatten(),
                                  image.shape,
                                  eps=eps,
                                  isign=sign)
    else:
        result = finufft.nufft2d1(fx.flatten(),
                                  fy.flatten(),
                                  image.flatten(), (size[0], size[1]),
                                  eps=eps,
                                  isign=sign)

    if np.__name__ == 'cupy':
        result = np.asarray(result)
    return result
Ejemplo n.º 5
0
def generate_bandlimits(size=[512, 512], levels=9):
    """
    A definition to calculate octaves used in bandlimiting frequencies in the frequency domain.

    Parameters
    ----------
    size       : list
                 Size of each mask in octaves.

    Returns
    ----------
    masks      : ndarray
                 Masks (Octaves).
    """
    masks = np.zeros((levels, size[0], size[1]))
    cx = int(size[0] / 2)
    cy = int(size[1] / 2)
    for i in range(0, masks.shape[0]):
        deltax = int((size[0]) / (2**(i + 1)))
        deltay = int((size[1]) / (2**(i + 1)))
        masks[i, cx - deltax:cx + deltax, cy - deltay:cy + deltay] = 1.
        masks[i,
              int(cx - deltax / 2.):int(cx + deltax / 2.),
              int(cy - deltay / 2.):int(cy + deltay / 2.)] = 0.
    masks = np.asarray(masks)
    return masks
Ejemplo n.º 6
0
    def intersect(self,ray):
        """
        A  definition to find out which surface to intersect a ray(s).

        Parameters
        ----------
        ray          : ndarray
                       Ray(s) to be intersected. 
        """
        convex_normal,convex_distance = intersect_w_sphere(
                                                           ray,
                                                           self.convex_surface
                                                          )
        plane_normal,plane_distance   = intersect_w_circle(
                                                           ray,
                                                           self.plane_surface
                                                          )
        test_normal                   = convex_normal
        if len(test_normal.shape) < 3:
            test_normal = convex_normal[0]
        is_it_in_lens                 = same_side(
                                                  test_normal,
                                                  self.convex_point,
                                                  self.plane_surface[0][1],
                                                  self.plane_surface[0][2]
                                                 )
        surface_normals               = np.array([convex_normal,plane_normal],dtype=np.float)
        surface_distances             = np.array([convex_distance,plane_distance],dtype=np.float)
        which_surface                 = np.amin(surface_distances,axis=0)
        ids                           = np.where(surface_distances==which_surface)
        ids                           = np.asarray(ids)
#        ids[0]                        = ids[0] | is_it_in_lens
        normal                        = surface_normals[ids[0],ids[1]]
        distance                      = surface_distances[ids[0],ids[1]]
        return normal,distance
Ejemplo n.º 7
0
def get_triangle_normal(triangle, triangle_center=None):
    """
    Definition to calculate surface normal of a triangle.

    Parameters
    ----------
    triangle        : ndarray
                      Set of points in X,Y and Z to define a planar surface (3,3). It can also be list of triangles (mx3x3).
    triangle_center : ndarray
                      Center point of the given triangle. See odak.raytracing.center_of_triangle for more. In many scenarios you can accelerate things by precomputing triangle centers.

    Returns
    ----------
    normal          : ndarray
                      Surface normal at the point of intersection.
    """
    triangle = np.asarray(triangle)
    if len(triangle.shape) == 2:
        triangle = triangle.reshape((1, 3, 3))
    normal = np.zeros((triangle.shape[0], 2, 3))
    direction = np.cross(triangle[:, 0] - triangle[:, 1],
                         triangle[:, 2] - triangle[:, 1])
    if type(triangle_center) == type(None):
        normal[:, 0] = center_of_triangle(triangle)
    else:
        normal[:, 0] = triangle_center
    normal[:, 1] = direction / np.sum(direction, axis=1)[0]
    if normal.shape[0] == 1:
        normal = normal.reshape((2, 3))
    return normal
Ejemplo n.º 8
0
def resize_image(img, target_size):
    if np.__name__ == 'cupy':
        import numpy
        img = np.asnumpy(img)
    img = scipy.misc.imresize(img, (target_size[0], target_size[1]))
    if np.__name__ == 'cupy':
        img = np.asarray(img)
    return img
Ejemplo n.º 9
0
def rotate_point(point,angles=[0,0,0],mode='XYZ',origin=[0,0,0],offset=[0,0,0]):
    """
    Definition to rotate a given point. Note that rotation is always with respect to 0,0,0.

    Parameters
    ----------
    point        : ndarray
                   A point.
    angles       : list
                   Rotation angles in degrees. 
    mode         : str
                   Rotation mode determines ordering of the rotations at each axis. There are XYZ,YXZ,ZXY and ZYX modes.
    origin       : list
                   Reference point for a rotation.
    offset       : list
                   Shift with the given offset.

    Returns
    ----------
    result       : ndarray
                   Result of the rotation
    rotx         : ndarray
                   Rotation matrix along X axis.
    roty         : ndarray
                   Rotation matrix along Y axis.
    rotz         : ndarray
                   Rotation matrix along Z axis.
    """
    point  = np.asarray(point)
    point -= np.asarray(origin)
    rotx   = rotmatx(angles[0])
    roty   = rotmaty(angles[1])
    rotz   = rotmatz(angles[2])
    if mode == 'XYZ':
        result = np.dot(rotz,np.dot(roty,np.dot(rotx,point)))
    elif mode == 'XZY':
        result = np.dot(roty,np.dot(rotz,np.dot(rotx,point)))
    elif mode == 'YXZ':
        result = np.dot(rotz,np.dot(rotx,np.dot(roty,point)))
    elif mode == 'ZXY':
        result = np.dot(roty,np.dot(rotx,np.dot(rotz,point)))
    elif mode == 'ZYX':
        result = np.dot(rotx,np.dot(roty,np.dot(rotz,point)))
    result += np.asarray(origin)
    result += np.asarray(offset)
    return result,rotx,roty,rotz
Ejemplo n.º 10
0
def write_PLY(triangles,savefn='output.ply'):
    """
    Definition to generate a PLY file from given points.

    Parameters
    ----------
    triangles   : ndarray
                  List of triangles with the size of Mx3x3.
    savefn      : string
                  Filename for a PLY file.
    """
    tris  = []
    pnts  = []
    color = [255,255,255]
    for tri_id in range(triangles.shape[0]):
       tris.append(
                   (
                    [3*tri_id,3*tri_id+1,3*tri_id+2], 
                    color[0],
                    color[1],
                    color[2]
                   )
                  )
       for i in range(0,3):
           pnts.append(
                       (
                        float(triangles[tri_id][i][0]),
                        float(triangles[tri_id][i][1]),
                        float(triangles[tri_id][i][2])
                       )
                      )
    if np.__name__ == 'cupy':
        import numpy as np_cpu
        tris   = np_cpu.asarray(tris, dtype=[('vertex_indices', 'i4', (3,)),('red', 'u1'), ('green', 'u1'),('blue', 'u1')])
        pnts   = np_cpu.asarray(pnts, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
    else:
        tris   = np.asarray(tris, dtype=[('vertex_indices', 'i4', (3,)),('red', 'u1'), ('green', 'u1'),('blue', 'u1')])
        pnts   = np.asarray(pnts, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
    # Save mesh.
    el1       = PlyElement.describe(pnts, 'vertex', comments=['Vertex data'])
    el2       = PlyElement.describe(tris, 'face', comments=['Face data'])
    PlyData([el1,el2],text="True").write(savefn)
Ejemplo n.º 11
0
def distance_between_two_points(point1, point2):
    """
    Definition to calculate distance between two given points.

    Parameters
    ----------
    point1      : list
                  First point in X,Y,Z.
    point2      : list
                  Second point in X,Y,Z.

    Returns
    ----------
    distance    : float
                  Distance in between given two points.
    """
    point1 = np.asarray(point1)
    point2 = np.asarray(point2)
    if len(point1.shape) == 1 and len(point2.shape) == 1:
        distance = np.sqrt(np.sum((point1 - point2)**2))
    elif len(point1.shape) == 2 or len(point2.shape) == 2:
        distance = np.sqrt(np.sum((point1 - point2)**2, axis=1))
    return distance
Ejemplo n.º 12
0
def create_ray_from_two_points(x0y0z0, x1y1z1):
    """
    Definition to create a ray from two given points. Note that both inputs must match in shape.

    Parameters
    ----------
    x0y0z0       : list
                   List that contains X,Y and Z start locations of a ray (3). It can also be a list of points as well (mx3). This is the starting point.
    x1y1z1       : list
                   List that contains X,Y and Z ending locations of a ray (3). It can also be a list of points as well (mx3). This is the end point.

    Returns
    ----------
    ray          : ndarray
                   Array that contains starting points and cosines of a created ray.
    """
    x0y0z0 = np.asarray(x0y0z0, dtype=np.float)
    x1y1z1 = np.asarray(x1y1z1, dtype=np.float)
    if len(x0y0z0.shape) == 1:
        x0y0z0 = x0y0z0.reshape((1, 3))
    if len(x1y1z1.shape) == 1:
        x1y1z1 = x1y1z1.reshape((1, 3))
    xdiff = x1y1z1[:, 0] - x0y0z0[:, 0]
    ydiff = x1y1z1[:, 1] - x0y0z0[:, 1]
    zdiff = x1y1z1[:, 2] - x0y0z0[:, 2]
    s = np.sqrt(xdiff**2 + ydiff**2 + zdiff**2)
    s[s == 0] = np.NaN
    cosines = np.zeros((xdiff.shape[0], 3))
    cosines[:, 0] = xdiff / s
    cosines[:, 1] = ydiff / s
    cosines[:, 2] = zdiff / s
    ray = np.zeros((xdiff.shape[0], 2, 3), dtype=np.float)
    ray[:, 0] = x0y0z0
    ray[:, 1] = cosines
    if ray.shape[0] == 1:
        ray = ray.reshape((2, 3))
    return ray
Ejemplo n.º 13
0
    def __init__(self,item='LA1024',location=[0.,0.,0.],rotation=[0.,0.,0.],wavelength=0.000532,meduium='air'):
        """
        Class to represent plano-convex lens.

        Parameters
        ----------
        item        : str
                      Plano convex lens label. Check Thorlabs catalog for labels. There are also json files within library.
        location    : list
                      Location in X,Y, and Z.
        rotation    : list
                      Rotation in X,Y, and Z.
        wavelength  : float
                      Wavelength in mm (default).
        medium      : str
                      Medium that the lens is in. Default is air.
        """
        self.item            = item
        self.location        = np.asarray(location)
        self.rotation        = np.asarray(rotation)
        self.path_to_catalog = "{}/data/plano_convex_lenses.json".format(os.path.dirname(odak.catalog.__file__))
        self.settings        = load_dictionary(self.path_to_catalog)[self.item]
        self.set_variables()
        self.define_geometry()
Ejemplo n.º 14
0
def roi(image, location=[0, 100, 0, 100], threshold=[0, 1, 0, 1]):
    """
    Definition to get the lines from a target ROI.

    Parameters
    ----------
    image      : ndarray
                 a 2D image to be sliced (nxm).
    location   : ndarray
                 Locations for taking the ROI.
    threshold  : list
                 Threshold below and above these numbers.

    Returns
    -------
    line_x     : ndarray
                 Line slice.
    line_y     : ndarray
                 Line slice.
    """
    img = image[location[0]:location[1], location[2]:location[3]]
    if len(img.shape) == 3:
        img = np.sum(img, axis=2)
    line_x = img[:, int(img.shape[1] / 2)]
    line_y = img[int(img.shape[0] / 2), :]
    line_x = np.asarray(line_x)
    line_y = np.asarray(line_y)
    line_x = line_x - np.amin(line_x)
    line_x = line_x / np.amax(line_x)
    line_y = line_y - np.amin(line_y)
    line_y = line_y / np.amax(line_y)
    line_x[line_x < threshold[0]] = 0
    line_x[line_x > threshold[1]] = 1
    line_y[line_y < threshold[2]] = 0
    line_y[line_y > threshold[3]] = 1
    return line_x, line_y, img
Ejemplo n.º 15
0
def intersect_parametric(ray,
                         parametric_surface,
                         surface_function,
                         surface_normal_function,
                         target_error=0.00000001,
                         iter_no_limit=100000):
    """
    Definition to intersect a ray with a parametric surface.

    Parameters
    ----------
    ray                     : ndarray
                              Ray.
    parametric_surface      : ndarray
                              Parameters of the surfaces.
    surface_function        : function
                              Function to evaluate a point against a surface.
    surface_normal_function : function
                              Function to calculate surface normal for a given point on a surface.
    target_error            : float
                              Target error that defines the precision.  
    iter_no_limit           : int
                              Maximum number of iterations.

    Returns
    ----------
    distance                : float
                              Propagation distance.
    normal                  : ndarray
                              Ray that defines a surface normal for the intersection.
    """
    if len(ray.shape) == 2:
        ray = ray.reshape((1, 2, 3))
    error = [150, 100]
    distance = [0, 0.1]
    iter_no = 0
    while np.abs(np.max(np.asarray(error[1]))) > target_error:
        error[1], point = intersection_kernel_for_parametric_surfaces(
            distance[1], ray, parametric_surface, surface_function)
        distance, error = propagate_parametric_intersection_error(
            distance, error)
        iter_no += 1
        if iter_no > iter_no_limit:
            return False, False
        if np.isnan(np.sum(point)):
            return False, False
    normal = surface_normal_function(point, parametric_surface)
    return distance[1], normal
Ejemplo n.º 16
0
def nuifft2(field, fx, fy, size=None, sign=1, eps=10**(-12)):
    """
    A definition to take 2D Adjoint Non-Uniform Fast Fourier Transform (NUFFT).

    Parameters
    ----------
    field       : ndarray
                  Input field.
    fx          : ndarray
                  Frequencies along x axis.
    fy          : ndarray
                  Frequencies along y axis.
    size        : list or ndarray
                  Shape of the NUFFT calculated for an input field.
    sign        : float
                  Sign of the exponential used in NUFFT kernel.
    eps         : float
                  Accuracy of NUFFT.

    Returns
    ----------
    result      : ndarray
                  NUFFT of the input field.
    """
    if np.__name__ == 'cupy':
        fx = np.asnumpy(fx).astype(np.float64)
        fy = np.asnumpy(fy).astype(np.float64)
        image = np.asnumpy(np.copy(field)).astype(np.complex128)
    else:
        image = np.copy(field).astype(np.complex128)
    if type(size) == type(None):
        result = finufft.nufft2d1(fx.flatten(),
                                  fy.flatten(),
                                  image.flatten(),
                                  image.shape,
                                  eps=eps,
                                  isign=sign)
    else:
        result = finufft.nufft2d1(fx.flatten(),
                                  fy.flatten(),
                                  image.flatten(), (size[0], size[1]),
                                  eps=eps,
                                  isign=sign)
    if np.__name__ == 'cupy':
        result = np.asarray(result)
    return result
Ejemplo n.º 17
0
def nuifft2(field, fx, fy, sign=1, eps=10**(-12)):
    """
    """
    if np.__name__ == 'cupy':
        fx = np.asnumpy(fx).astype(np.float64)
        fy = np.asnumpy(fy).astype(np.float64)
        image = np.asnumpy(np.copy(field)).astype(np.complex128)
    else:
        image = np.copy(field).astype(np.complex128)
    result = finufft.nufft2d2(fx.flatten(),
                              fy.flatten(),
                              image,
                              eps=eps,
                              isign=sign)
    result = result.reshape(field.shape)
    if np.__name__ == 'cupy':
        result = np.asarray(result)
    return result
Ejemplo n.º 18
0
def rotate_points(points,angles=[0,0,0],mode='XYZ',origin=[0,0,0],offset=[0,0,0]):
    """
    Definition to rotate points.

    Parameters
    ----------
    points       : ndarray
                   Points.
    angles       : list
                   Rotation angles in degrees. 
    mode         : str
                   Rotation mode determines ordering of the rotations at each axis. There are XYZ,YXZ,ZXY and ZYX modes.
    origin       : list
                   Reference point for a rotation.
    offset       : list
                   Shift with the given offset.

    Returns
    ----------
    result       : ndarray
                   Result of the rotation   
    """
    points  = np.asarray(points)
    if angles[0] == 0 and angles[1] == 0 and angles[2] ==0:
        result = np.array(offset) + points
        return result
    points -= np.array(origin)
    rotx    = rotmatx(angles[0])
    roty    = rotmaty(angles[1])
    rotz    = rotmatz(angles[2])
    if mode == 'XYZ':
        result = np.dot(rotz,np.dot(roty,np.dot(rotx,points.T))).T
    elif mode == 'XZY':
        result = np.dot(roty,np.dot(rotz,np.dot(rotx,points.T))).T
    elif mode == 'YXZ':
        result = np.dot(rotz,np.dot(rotx,np.dot(roty,points.T))).T
    elif mode == 'ZXY':
        result = np.dot(roty,np.dot(rotx,np.dot(rotz,points.T))).T
    elif mode == 'ZYX':
        result = np.dot(rotx,np.dot(roty,np.dot(rotz,points.T))).T
    result += np.array(origin)
    result += np.array(offset)
    return result
Ejemplo n.º 19
0
def cross_product(vector1, vector2):
    """
    Definition to cross product two vectors and return the resultant vector. Used method described under: http://en.wikipedia.org/wiki/Cross_product

    Parameters
    ----------
    vector1      : ndarray
                   A vector/ray.
    vector2      : ndarray
                   A vector/ray.

    Returns
    ----------
    ray          : ndarray
                   Array that contains starting points and cosines of a created ray.
    """
    angle = np.cross(vector1[1].T, vector2[1].T)
    angle = np.asarray(angle)
    ray = np.array([vector1[0], angle], dtype=np.float)
    return ray
Ejemplo n.º 20
0
def read_PLY(fn,offset=[0,0,0],angles=[0.,0.,0.],mode='XYZ'):
    """
    Definition to read a PLY file and extract meshes from a given PLY file. Note that rotation is always with respect to 0,0,0.

    Parameters
    ----------
    fn           : string
                   Filename of a PLY file.
    offset       : ndarray
                   Offset in X,Y,Z.
    angles       : list
                   Rotation angles in degrees.
    mode         : str
                   Rotation mode determines ordering of the rotations at each axis. There are XYZ,YXZ,ZXY and ZYX modes.                  

    Returns
    ----------
    triangles    : ndarray
                  Triangles from a given PLY file. Note that the triangles coming out of this function isn't always structured in the right order and with the size of (MxN)x3. You can use numpy's reshape to restructure it to mxnx3 if you know what you are doing.
    """
    if np.__name__ != 'numpy':
        import numpy as np_ply
    else:
        np_ply = np
    with open(fn,'rb') as f:
        plydata = PlyData.read(f)
    triangle_ids = np_ply.vstack(plydata['face'].data['vertex_indices'])
    triangles    = []
    for vertex_ids in triangle_ids:
        triangle     = [
                        rotate_point(plydata['vertex'][int(vertex_ids[0])].tolist(),angles=angles,offset=offset)[0],
                        rotate_point(plydata['vertex'][int(vertex_ids[1])].tolist(),angles=angles,offset=offset)[0],
                        rotate_point(plydata['vertex'][int(vertex_ids[2])].tolist(),angles=angles,offset=offset)[0]
                       ]
        triangle     = np_ply.asarray(triangle)
        triangles.append(triangle)
    triangles = np_ply.array(triangles)
    triangles = np.asarray(triangles,dtype=np.float)
    return triangles
Ejemplo n.º 21
0
def line_spread_function(line):
    """
    Definition to take the gradient of a 1D function.

    Parameters
    ----------
    line          : ndarray
                    1D array.

    Returns
    ----------
    result        : ndarray
                    Gradient of the given 1D array.
    """
    if np.__name__ == 'cupy':
        import numpy
        cache = np.asnumpy(line)
        result = numpy.gradient(cache)
    else:
        result = np.gradient(line)
    result = np.asarray(result)
    return result
Ejemplo n.º 22
0
def intersect_w_surface(ray, points):
    """
    Definition to find intersection point inbetween a surface and a ray. For more see: http://geomalgorithms.com/a06-_intersect-2.html

    Parameters
    ----------
    ray          : ndarray
                   A vector/ray.
    points       : ndarray
                   Set of points in X,Y and Z to define a planar surface.

    Returns
    ----------
    normal       : ndarray
                   Surface normal at the point of intersection.
    distance     : float
                   Distance in between starting point of a ray with it's intersection with a planar surface.
    """
    points = np.asarray(points)
    normal = get_triangle_normal(points)
    if len(ray.shape) == 2:
        ray = ray.reshape((1, 2, 3))
    if len(points) == 2:
        points = points.reshape((1, 3, 3))
    if len(normal.shape) == 2:
        normal = normal.reshape((1, 2, 3))
    f = normal[:, 0] - ray[:, 0]
    distance = np.dot(normal[:, 1], f.T) / np.dot(normal[:, 1], ray[:, 1].T)
    n = np.int(np.amax(np.array([ray.shape[0], normal.shape[0]])))
    normal = np.zeros((n, 2, 3))
    normal[:, 0] = ray[:, 0] + distance.T * ray[:, 1]
    distance = np.abs(distance)
    if normal.shape[0] == 1:
        normal = normal.reshape((2, 3))
        distance = distance.reshape((1))
    if distance.shape[0] == 1 and len(distance.shape) > 1:
        distance = distance.reshape((distance.shape[1]))
    return normal, distance
Ejemplo n.º 23
0
    def raytrace(self, ray):
        """
        Definition to raytrace the diffuser.


        Parameters
        ----------
        ray         : ndarray
                      Ray(s).

        Returns
        ----------
        new_rays    : ndarray
                      Diffusion rays.
        normal      : ndarray
                      Surface normals
        distance    : ndarray 
                      Distance ray(s) has/have travelled until to the point of diffusion.
        """
        if len(ray.shape) == 2:
            ray = ray.reshape((1, ray.shape[0], ray.shape[1]))
        normal, distance = intersect_w_surface(ray, self.plane)
        ########################################################################
        # This is the bottleneck for has to be replaced for better performance #
        ########################################################################
        new_rays = np.empty((0, 2, 3))
        for point_id in range(0, normal.shape[0]):
            tilt_angles = tilt_towards(ray[point_id, 0], normal[point_id, 0])
            tilted_points = rotate_points(self.diffusion_points,
                                          angles=tilt_angles,
                                          offset=normal[point_id, 0])
            new_rays = np.vstack(
                (new_rays,
                 create_ray_from_two_points(normal[point_id, 0],
                                            tilted_points)))
        new_rays = np.asarray(new_rays)
        return new_rays, normal, distance
Ejemplo n.º 24
0
def point_wise(field,distances,k,dx,wavelength,lens_method='ideal',propagation_method='Bandlimited Angular Spectrum',n_iteration=3):
    """
    Point-wise hologram calculation method. For more Maimone, Andrew, Andreas Georgiou, and Joel S. Kollin. "Holographic near-eye displays for virtual and augmented reality." ACM Transactions on Graphics (TOG) 36.4 (2017): 1-16.

    Parameters
    ----------
    field            : ndarray
                       Complex input field to be converted into a hologram.
    distances        : ndarray
                       Depth map of the input field.
    k                : odak.wave.wavenumber
                       Wave number of a wave, see odak.wave.wavenumber for more.
    dx               : float
                       Pixel pitch.
    wavelength       : float
                       Wavelength of the light.
    lens_model       : str
                       Method to calculate the lens patterns.
    propagation_mode : str
                       Beam propagation method to be used if the lens_model is not equal to `ideal`.
    n_iteration      : int
                       Number of iterations.

    Returns
    ----------
    hologram   : ndarray
                 Generated complex hologram.
    """
    hologram      = np.zeros(field.shape,dtype=np.complex64)
    nx,ny         = field.shape
    cx            = int(nx/2)
    cy            = int(ny/2)
    non_zeros     = np.asarray((np.abs(field)>0).nonzero())
    unique_dist   = np.unique(distances)
    unique_dist   = unique_dist[unique_dist!=0]
    target        = np.zeros((nx,ny),dtype=np.complex64)
    target[cx,cy] = 1.
    lenses        = []
    for distance in unique_dist:
        if lens_method == 'ideal':
            new_lens = quadratic_phase_function(nx,ny,k,focal=distance,dx=dx)
            lenses.append(new_lens)
        elif lens_method == 'Gerchberg-Saxton':
            new_lens,_ = gerchberg_saxton(
                                          target,
                                          n_iteration,
                                          distance,
                                          dx,
                                          wavelength,
                                          np.pi*2,
                                          propagation_method
                                         )
            lenses.append(new_lens)
    for m in tqdm(range(non_zeros.shape[1])):
        i         = int(non_zeros[0,m])
        j         = int(non_zeros[1,m])
        lens_id   = int(np.argwhere(unique_dist==distances[i,j]))
        lens      = lenses[lens_id]
        lens      = np.roll(lens,i-cx,axis=0)
        lens      = np.roll(lens,j-cy,axis=1)
        hologram += lens*field[i,j]
    return hologram