Skip to content

odak.raytracing

odak.raytracing

Provides necessary definitions for geometric optics. See "General Ray tracing procedure" from G.H. Spencerand M.V.R.K Murty for the theoratical explanation.

get_cylinder_normal(point, cylinder)

Parameters:

  • point
            Point on a cylinder defined in X,Y,Z.
    

Returns:

  • normal_vector ( ndarray ) –

    Normal vector.

Source code in odak/raytracing/boundary.py
def get_cylinder_normal(point, cylinder):
    """
    Parameters
    ----------
    point         : ndarray
                    Point on a cylinder defined in X,Y,Z.

    Returns
    ----------
    normal_vector : ndarray
                    Normal vector.
    """
    cylinder_ray = create_ray_from_two_points(cylinder[0:3], cylinder[4:7])
    closest_point = closest_point_to_a_ray(
        point,
        cylinder_ray
    )
    normal_vector = create_ray_from_two_points(closest_point, point)
    return normal_vector

get_sphere_normal(point, sphere)

Definition to get a normal of a point on a given sphere.

Parameters:

  • point
            Point on sphere in X,Y,Z.
    
  • sphere
            Center defined in X,Y,Z and radius.
    

Returns:

  • normal_vector ( ndarray ) –

    Normal vector.

Source code in odak/raytracing/boundary.py
def get_sphere_normal(point, sphere):
    """
    Definition to get a normal of a point on a given sphere.

    Parameters
    ----------
    point         : ndarray
                    Point on sphere in X,Y,Z.
    sphere        : ndarray
                    Center defined in X,Y,Z and radius.

    Returns
    ----------
    normal_vector : ndarray
                    Normal vector.
    """
    if len(point.shape) == 1:
        point = point.reshape((1, 3))
    normal_vector = create_ray_from_two_points(point, sphere[0:3])
    return normal_vector

get_triangle_normal(triangle, triangle_center=None)

Definition to calculate surface normal of a triangle.

Parameters:

  • triangle
              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, default: None ) –
              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.

Source code in odak/raytracing/boundary.py
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

intersect_parametric(ray, parametric_surface, surface_function, surface_normal_function, target_error=1e-08, iter_no_limit=100000)

Definition to intersect a ray with a parametric surface.

Parameters:

  • ray
                      Ray.
    
  • parametric_surface
                      Parameters of the surfaces.
    
  • surface_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
                      Target error that defines the precision.
    
  • iter_no_limit
                      Maximum number of iterations.
    

Returns:

  • distance ( float ) –

    Propagation distance.

  • normal ( ndarray ) –

    Ray that defines a surface normal for the intersection.

Source code in odak/raytracing/boundary.py
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

intersect_w_circle(ray, circle)

Definition to find intersection point of a ray with a circle. Returns False for each variable if the ray doesn't intersect with a given circle. Returns distance as zero if there isn't an intersection.

Parameters:

  • ray
           A vector/ray.
    
  • circle
           A list that contains (0) Set of points in X,Y and Z to define plane of a circle, (1) circle center, and (2) circle radius.
    

Returns:

  • normal ( ndarray ) –

    Surface normal at the point of intersection.

  • distance ( float ) –

    Distance in between a starting point of a ray and the intersection point with a given triangle.

Source code in odak/raytracing/boundary.py
def intersect_w_circle(ray, circle):
    """
    Definition to find intersection point of a ray with a circle. Returns False for each variable if the ray doesn't intersect with a given circle. Returns distance as zero if there isn't an intersection.

    Parameters
    ----------
    ray          : ndarray
                   A vector/ray.
    circle       : list
                   A list that contains (0) Set of points in X,Y and Z to define plane of a circle, (1) circle center, and (2) circle radius.

    Returns
    ----------
    normal       : ndarray
                   Surface normal at the point of intersection.
    distance     : float
                   Distance in between a starting point of a ray and the intersection point with a given triangle.
    """
    normal, distance = intersect_w_surface(ray, circle[0])
    if len(normal.shape) == 2:
        normal = normal.reshape((1, 2, 3))
    distance_to_center = distance_between_two_points(normal[:, 0], circle[1])
    distance[np.nonzero(distance_to_center > circle[2])] = 0
    if len(ray.shape) == 2:
        normal = normal.reshape((2, 3))
    return normal, distance

intersect_w_cylinder(ray, cylinder)

Definition to intersect a ray with a cylinder.

Parameters:

  • ray
         A ray definition.
    
  • cylinder
         A cylinder defined with a center in XYZ and radius of curvature.
    

Returns:

  • normal ( ndarray ) –

    A ray defining surface normal at the point of intersection.

  • distance ( float ) –

    Total optical propagation distance.

Source code in odak/raytracing/boundary.py
def intersect_w_cylinder(ray, cylinder):
    """
    Definition to intersect a ray with a cylinder.

    Parameters
    ----------
    ray        : ndarray
                 A ray definition.
    cylinder   : ndarray
                 A cylinder defined with a center in XYZ and radius of curvature.

    Returns
    ----------
    normal     : ndarray
                 A ray defining surface normal at the point of intersection.
    distance   : float
                 Total optical propagation distance.
    """
    distance, normal = intersect_parametric(
        ray,
        cylinder,
        cylinder_function,
        get_cylinder_normal
    )
    return normal, distance

intersect_w_sphere(ray, sphere)

Definition to intersect a ray with a sphere.

Parameters:

  • ray
         A ray definition.
    
  • sphere
         A sphere defined with a center in XYZ and radius of curvature.
    

Returns:

  • normal ( ndarray ) –

    A ray defining surface normal at the point of intersection.

  • distance ( float ) –

    Total optical propagation distance.

Source code in odak/raytracing/boundary.py
def intersect_w_sphere(ray, sphere):
    """
    Definition to intersect a ray with a sphere.

    Parameters
    ----------
    ray        : ndarray
                 A ray definition.
    sphere     : ndarray
                 A sphere defined with a center in XYZ and radius of curvature.

    Returns
    ----------
    normal     : ndarray
                 A ray defining surface normal at the point of intersection.
    distance   : float
                 Total optical propagation distance.
    """
    distance, normal = intersect_parametric(
        ray,
        sphere,
        sphere_function,
        get_sphere_normal
    )
    return normal, distance

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
           A vector/ray.
    
  • points
           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.

Source code in odak/raytracing/boundary.py
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.shape) == 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.int64(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

intersect_w_surface_batch(ray, triangle)

Parameters:

  • ray
           A vector/ray (2 x 3). It can also be a list of rays (n x 2 x 3).
    
  • points
           Set of points in X,Y and Z to define a planar surface. It can also be a list of triangles (m x 3 x 3).
    

Returns:

  • normal ( tensor ) –

    Surface normal at the point of intersection (m x n x 3 x 3).

  • distance ( tensor ) –

    Distance in between starting point of a ray with it's intersection with a planar surface (m x n).

Source code in odak/raytracing/boundary.py
def intersect_w_surface_batch(ray, triangle):
    """
    Parameters
    ----------
    ray          : torch.tensor
                   A vector/ray (2 x 3). It can also be a list of rays (n x 2 x 3).
    points       : torch.tensor
                   Set of points in X,Y and Z to define a planar surface. It can also be a list of triangles (m x 3 x 3).

    Returns
    ----------
    normal       : torch.tensor
                   Surface normal at the point of intersection (m x n x 3 x 3).
    distance     : torch.tensor
                   Distance in between starting point of a ray with it's intersection with a planar surface (m x n).
    """
    normal = get_triangle_normal(triangle)
    if len(ray.shape) == 2:
        ray = ray.unsqueeze(0)
    if len(triangle.shape) == 2:
        triangle = triangle.unsqueeze(0)
    if len(normal.shape) == 2:
        normal = normal.unsqueeze(0)

    f = normal[:, None, 0] - ray[None, :, 0]
    distance = (torch.bmm(normal[:, None, 1], f.permute(0, 2, 1)).squeeze(1) / torch.mm(normal[:, 1], ray[:, 1].T)).T

    new_normal = torch.zeros((triangle.shape[0], )+ray.shape)
    new_normal[:, :, 0] = ray[None, :, 0] + (distance[:, :, None] * ray[:, None, 1]).permute(1, 0, 2)
    new_normal[:, :, 1] = normal[:, None, 1]
    new_normal = torch.nan_to_num(
                                  new_normal,
                                  nan = float('nan'),
                                  posinf = float('nan'),
                                  neginf = float('nan')
                                 )
    distance = torch.nan_to_num(
                                distance,
                                nan = float('nan'),
                                posinf = float('nan'),
                                neginf = float('nan')
                               )
    return new_normal, distance.T

intersect_w_triangle(ray, triangle)

Definition to find intersection point of a ray with a triangle. Returns False for each variable if the ray doesn't intersect with a given triangle.

Parameters:

  • ray
           A vector/ray (2 x 3). It can also be a list of rays (n x 2 x 3).
    
  • points
           Set of points in X,Y and Z to define a planar surface. It can also be a list of triangles (m x 3 x 3).
    

Returns:

  • normal ( ndarray ) –

    Surface normal at the point of intersection.

  • distance ( float ) –

    Distance in between a starting point of a ray and the intersection point with a given triangle.

Source code in odak/raytracing/boundary.py
def intersect_w_triangle(ray, triangle):
    """
    Definition to find intersection point of a ray with a triangle. Returns False for each variable if the ray doesn't intersect with a given triangle.

    Parameters
    ----------
    ray          : torch.tensor
                   A vector/ray (2 x 3). It can also be a list of rays (n x 2 x 3).
    points       : torch.tensor
                   Set of points in X,Y and Z to define a planar surface. It can also be a list of triangles (m x 3 x 3).

    Returns
    ----------
    normal       : ndarray
                   Surface normal at the point of intersection.
    distance     : float
                   Distance in between a starting point of a ray and the intersection point with a given triangle.
    """
    normal, distance = intersect_w_surface(ray, triangle)
    if is_it_on_triangle(normal[0], triangle[0], triangle[1], triangle[2]) == False:
        return 0, 0
    return normal, distance

intersect_w_triangle_batch(ray, triangle)

Definition to find intersection points of rays with triangles. Returns False for each variable if the rays doesn't intersect with given triangles.

Parameters:

  • ray
           vectors/rays (n x 2 x 3).
    
  • triangle
           Set of points in X,Y and Z to define a single triangle.
    

Returns:

  • normal ( tensor ) –

    Surface normal at the point of intersection (m x n x 3 x 3).

  • distance ( tensor ) –

    Distance in between starting point of a ray with it's intersection with a planar surface (m x n).

  • intersect_ray ( tensor ) –

    Intersecting rays (k x 3 x 3) where k <= n.

  • intersect_normal ( tensor ) –

    Intersecting normals (k x 3 x 3) where k <= n*m.

Source code in odak/raytracing/boundary.py
def intersect_w_triangle_batch(ray, triangle):
    """
    Definition to find intersection points of rays with triangles. Returns False for each variable if the rays doesn't intersect with given triangles.

    Parameters
    ----------
    ray          : torch.tensor
                   vectors/rays (n x 2 x 3).
    triangle     : ndarray
                   Set of points in X,Y and Z to define a single triangle.

    Returns
    ----------
    normal          : torch.tensor
                      Surface normal at the point of intersection (m x n x 3 x 3).
    distance        : torch.tensor
                      Distance in between starting point of a ray with it's intersection with a planar surface (m x n).
    intersect_ray   : torch.tensor
                      Intersecting rays (k x 3 x 3) where k <= n.
    intersect_normal: torch.tensor
                      Intersecting normals (k x 3 x 3) where k <= n*m.
    """
    if len(triangle.shape) == 2:
       triangle = triangle.unsqueeze(0)
    if len(ray.shape) == 2:
       ray = ray.unsqueeze(0)

    normal, distance = intersect_w_surface_batch(ray, triangle)

    check = is_it_on_triangle_batch(normal[:, :, 0], triangle)
    intersect_ray = ray[check.any(dim=0) == True]
    intersect_normal = normal[:, check.any(dim=0) ==  True]
    return normal, distance, intersect_ray, intersect_normal, check

intersection_kernel_for_parametric_surfaces(distance, ray, parametric_surface, surface_function)

Definition for the intersection kernel when dealing with parametric surfaces.

Parameters:

  • distance
                 Distance.
    
  • ray
                 Ray.
    
  • parametric_surface (ndarray) –
                 Array that defines a parametric surface.
    
  • surface_function
                 Function to evaluate a point against a parametric surface.
    

Returns:

  • point ( ndarray ) –

    Location in X,Y,Z after propagation.

  • error ( float ) –

    Error.

Source code in odak/raytracing/boundary.py
def intersection_kernel_for_parametric_surfaces(distance, ray, parametric_surface, surface_function):
    """
    Definition for the intersection kernel when dealing with parametric surfaces.

    Parameters
    ----------
    distance           : float
                         Distance.
    ray                : ndarray
                         Ray.
    parametric_surface : ndarray
                         Array that defines a parametric surface.
    surface_function   : ndarray
                         Function to evaluate a point against a parametric surface.

    Returns
    ----------
    point              : ndarray
                         Location in X,Y,Z after propagation.
    error              : float
                         Error.
    """
    new_ray = propagate_a_ray(ray, distance)
    if len(new_ray) == 2:
        new_ray = new_ray.reshape((1, 2, 3))
    point = new_ray[:, 0]
    error = surface_function(point, parametric_surface)
    return error, point

propagate_parametric_intersection_error(distance, error)

Definition to propagate the error in parametric intersection to find the next distance to try.

Parameters:

  • distance
           List that contains the new and the old distance.
    
  • error
           List that contains the new and the old error.
    

Returns:

  • distance ( list ) –

    New distance.

  • error ( list ) –

    New error.

Source code in odak/raytracing/boundary.py
def propagate_parametric_intersection_error(distance, error):
    """
    Definition to propagate the error in parametric intersection to find the next distance to try.

    Parameters
    ----------
    distance     : list
                   List that contains the new and the old distance.
    error        : list
                   List that contains the new and the old error.

    Returns
    ----------
    distance     : list
                   New distance.
    error        : list
                   New error.
    """
    new_distance = distance[1]-error[1] * \
        (distance[1]-distance[0])/(error[1]-error[0])
    distance[0] = distance[1]
    distance[1] = np.abs(new_distance)
    error[0] = error[1]
    return distance, error

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
           A vector/ray (2x3). It can also be a list of rays (nx2x3).
    
  • normal
           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.

Source code in odak/raytracing/boundary.py
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.int64(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

bring_plane_to_origin(point, plane, shape=[10.0, 10.0], center=[0.0, 0.0, 0.0], angles=[0.0, 0.0, 0.0], mode='XYZ')

Definition to bring points back to reference origin with respect to a plane.

Parameters:

  • point
                 Point(s) to be tested.
    
  • shape
                 Dimensions of the rectangle along X and Y axes.
    
  • center
                 Center of the rectangle.
    
  • angles
                 Rotation angle of the rectangle.
    
  • mode
                 Rotation mode of the rectangle, for more see odak.tools.rotate_point and odak.tools.rotate_points.
    

Returns:

  • transformed_points ( ndarray ) –

    Point(s) that are brought back to reference origin with respect to given plane.

Source code in odak/raytracing/primitives.py
def bring_plane_to_origin(point, plane, shape=[10., 10.], center=[0., 0., 0.], angles=[0., 0., 0.], mode='XYZ'):
    """
    Definition to bring points back to reference origin with respect to a plane.

    Parameters
    ----------
    point              : ndarray
                         Point(s) to be tested.
    shape              : list
                         Dimensions of the rectangle along X and Y axes.
    center             : list
                         Center of the rectangle.
    angles             : list
                         Rotation angle of the rectangle.
    mode               : str
                         Rotation mode of the rectangle, for more see odak.tools.rotate_point and odak.tools.rotate_points.

    Returns
    ----------
    transformed_points : ndarray
                         Point(s) that are brought back to reference origin with respect to given plane.
    """
    if point.shape[0] == 3:
        point = point.reshape((1, 3))
    reverse_mode = mode[::-1]
    angles = [-angles[0], -angles[1], -angles[2]]
    center = np.asarray(center).reshape((1, 3))
    transformed_points = point-center
    transformed_points = rotate_points(
        transformed_points,
        angles=angles,
        mode=reverse_mode,
    )
    if transformed_points.shape[0] == 1:
        transformed_points = transformed_points.reshape((3,))
    return transformed_points

center_of_triangle(triangle)

Definition to calculate center of a triangle.

Parameters:

  • triangle
            An array that contains three points defining a triangle (Mx3). It can also parallel process many triangles (NxMx3).
    
Source code in odak/raytracing/primitives.py
def center_of_triangle(triangle):
    """
    Definition to calculate center of a triangle.

    Parameters
    ----------
    triangle      : ndarray
                    An array that contains three points defining a triangle (Mx3). It can also parallel process many triangles (NxMx3).
    """
    if len(triangle.shape) == 2:
        triangle = triangle.reshape((1, 3, 3))
    center = np.mean(triangle, axis=1)
    return center

cylinder_function(point, cylinder)

Definition of a cylinder function. Evaluate a point against a cylinder function. Inspired from https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html

Parameters:

  • cylinder
         Cylinder parameters, XYZ center and radius.
    
  • point
         Point in XYZ.
    
Return

result : float Result of the evaluation. Zero if point is on sphere.

Source code in odak/raytracing/primitives.py
def cylinder_function(point, cylinder):
    """
    Definition of a cylinder function. Evaluate a point against a cylinder function. Inspired from https://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html

    Parameters
    ----------
    cylinder   : ndarray
                 Cylinder parameters, XYZ center and radius.
    point      : ndarray
                 Point in XYZ.

    Return
    ----------
    result     : float
                 Result of the evaluation. Zero if point is on sphere.
    """
    point = np.asarray(point)
    if len(point.shape) == 1:
        point = point.reshape((1, 3))
    distance = point_to_ray_distance(
        point,
        np.array([cylinder[0], cylinder[1], cylinder[2]], dtype=np.float64),
        np.array([cylinder[4], cylinder[5], cylinder[6]], dtype=np.float64)
    )
    r = cylinder[3]
    result = distance - r ** 2
    return result

define_circle(center, radius, angles)

Definition to describe a circle in a single variable packed form.

Parameters:

  • center
      Center of a circle to be defined.
    
  • radius
      Radius of a circle to be defined.
    
  • angles
      Angular tilt of a circle.
    

Returns:

  • circle ( list ) –

    Single variable packed form.

Source code in odak/raytracing/primitives.py
def define_circle(center, radius, angles):
    """
    Definition to describe a circle in a single variable packed form.

    Parameters
    ----------
    center  : float
              Center of a circle to be defined.
    radius  : float
              Radius of a circle to be defined.
    angles  : float
              Angular tilt of a circle.

    Returns
    ----------
    circle  : list
              Single variable packed form.
    """
    points = define_plane(center, angles=angles)
    circle = [
        points,
        center,
        radius
    ]
    return circle

define_cylinder(center, radius, rotation=[0.0, 0.0, 0.0])

Definition to define a cylinder

Parameters:

  • center
         Center of a cylinder in X,Y,Z.
    
  • radius
         Radius of a cylinder along X axis.
    
  • rotation
         Direction angles in degrees for the orientation of a cylinder.
    

Returns:

  • cylinder ( ndarray ) –

    Single variable packed form.

Source code in odak/raytracing/primitives.py
def define_cylinder(center, radius, rotation=[0., 0., 0.]):
    """
    Definition to define a cylinder

    Parameters
    ----------
    center     : ndarray
                 Center of a cylinder in X,Y,Z.
    radius     : float
                 Radius of a cylinder along X axis.
    rotation   : list
                 Direction angles in degrees for the orientation of a cylinder.

    Returns
    ----------
    cylinder   : ndarray
                 Single variable packed form.
    """
    cylinder_ray = create_ray_from_angles(
        np.asarray(center), np.asarray(rotation))
    cylinder = np.array(
        [
            center[0],
            center[1],
            center[2],
            radius,
            center[0]+cylinder_ray[1, 0],
            center[1]+cylinder_ray[1, 1],
            center[2]+cylinder_ray[1, 2]
        ],
        dtype=np.float64
    )
    return cylinder

define_plane(point, angles=[0.0, 0.0, 0.0])

Definition to generate a rotation matrix along X axis.

Parameters:

  • point
           A point that is at the center of a plane.
    
  • angles
           Rotation angles in degrees.
    

Returns:

  • plane ( ndarray ) –

    Points defining plane.

Source code in odak/raytracing/primitives.py
def define_plane(point, angles=[0., 0., 0.]):
    """ 
    Definition to generate a rotation matrix along X axis.

    Parameters
    ----------
    point        : ndarray
                   A point that is at the center of a plane.
    angles       : list
                   Rotation angles in degrees.

    Returns
    ----------
    plane        : ndarray
                   Points defining plane.
    """
    plane = np.array([
        [10., 10., 0.],
        [0., 10., 0.],
        [0.,  0., 0.]
    ], dtype=np.float64)
    point = np.asarray(point)
    for i in range(0, plane.shape[0]):
        plane[i], _, _, _ = rotate_point(plane[i], angles=angles)
        plane[i] = plane[i]+point
    return plane

define_sphere(center, radius)

Definition to define a sphere.

Parameters:

  • center
         Center of a sphere in X,Y,Z.
    
  • radius
         Radius of a sphere.
    

Returns:

  • sphere ( ndarray ) –

    Single variable packed form.

Source code in odak/raytracing/primitives.py
def define_sphere(center, radius):
    """
    Definition to define a sphere.

    Parameters
    ----------
    center     : ndarray
                 Center of a sphere in X,Y,Z.
    radius     : float
                 Radius of a sphere.

    Returns
    ----------
    sphere     : ndarray
                 Single variable packed form.
    """
    sphere = np.array(
        [center[0], center[1], center[2], radius], dtype=np.float64)
    return sphere

is_it_on_triangle(pointtocheck, point0, point1, point2)

Definition to check if a given point is inside a triangle. If the given point is inside a defined triangle, this definition returns True.

Parameters:

  • pointtocheck
            Point to check.
    
  • point0
            First point of a triangle.
    
  • point1
            Second point of a triangle.
    
  • point2
            Third point of a triangle.
    
Source code in odak/raytracing/primitives.py
def is_it_on_triangle(pointtocheck, point0, point1, point2):
    """
    Definition to check if a given point is inside a triangle. If the given point is inside a defined triangle, this definition returns True.

    Parameters
    ----------
    pointtocheck  : list
                    Point to check.
    point0        : list
                    First point of a triangle.
    point1        : list
                    Second point of a triangle.
    point2        : list
                    Third point of a triangle.
    """
    # point0, point1 and point2 are the corners of the triangle.
    pointtocheck = np.asarray(pointtocheck).reshape(3)
    point0 = np.asarray(point0)
    point1 = np.asarray(point1)
    point2 = np.asarray(point2)
    side0 = same_side(pointtocheck, point0, point1, point2)
    side1 = same_side(pointtocheck, point1, point0, point2)
    side2 = same_side(pointtocheck, point2, point0, point1)
    if side0 == True and side1 == True and side2 == True:
        return True
    return False

is_it_on_triangle_batch(point_to_check, triangle)

Definition to check if given points are inside triangles. If the given points are inside defined triangles, this definition returns True.

Parameters:

  • pointtocheck
            Points to check (m x n x 3).
    
  • triangle

Returns:

  • result ( torch.tensor (m x n) ) –
Source code in odak/raytracing/primitives.py
def is_it_on_triangle_batch(point_to_check, triangle):
    """
    Definition to check if given points are inside triangles. If the given points are inside defined triangles, this definition returns True.

    Parameters
    ----------
    pointtocheck  : torch.tensor
                    Points to check (m x n x 3).
    triangle      : torch.tensor (m x 3 x 3)

    Returns
    ----------
    result        : torch.tensor (m x n)

    """
    if len(point_to_check.shape) == 1:
        point_to_check = point_to_check.unsqueeze(0)
    if len(triangle.shape) == 2:
        triangle = triangle.unsqueeze(0)
    v0 = triangle[:, 2] - triangle[:, 0]
    v1 = triangle[:, 1] - triangle[:, 0]
    v2 = point_to_check - triangle[:, None, 0]
    if len(v0.shape) == 1:
        v0 = v0.unsqueeze(0)
    if len(v1.shape) == 1:
        v1 = v1.unsqueeze(0)
    if len(v2.shape) == 1:
        v2 = v2.unsqueeze(0)

    dot00 = torch.bmm(v0.unsqueeze(1), v0.unsqueeze(1).permute(0, 2, 1)).squeeze(1)
    dot01 = torch.bmm(v0.unsqueeze(1), v1.unsqueeze(1).permute(0, 2, 1)).squeeze(1)
    dot02 = torch.bmm(v0.unsqueeze(1), v2.permute(0, 2, 1)).squeeze(1)
    dot11 = torch.bmm(v1.unsqueeze(1), v1.unsqueeze(1).permute(0, 2, 1)).squeeze(1)
    dot12 = torch.bmm(v1.unsqueeze(1), v2.permute(0, 2, 1)).squeeze(1)
    invDenom = 1. / (dot00 * dot11 - dot01 * dot01)
    u = (dot11 * dot02 - dot01 * dot12) * invDenom
    v = (dot00 * dot12 - dot01 * dot02) * invDenom
    result = (u >= 0.) & (v >= 0.) & ((u + v) < 1)

    return result

sphere_function(point, sphere)

Definition of a sphere function. Evaluate a point against a sphere function.

Parameters:

  • sphere
         Sphere parameters, XYZ center and radius.
    
  • point
         Point in XYZ.
    
Return

result : float Result of the evaluation. Zero if point is on sphere.

Source code in odak/raytracing/primitives.py
def sphere_function(point, sphere):
    """
    Definition of a sphere function. Evaluate a point against a sphere function.

    Parameters
    ----------
    sphere     : ndarray
                 Sphere parameters, XYZ center and radius.
    point      : ndarray
                 Point in XYZ.

    Return
    ----------
    result     : float
                 Result of the evaluation. Zero if point is on sphere.
    """
    point = np.asarray(point)
    if len(point.shape) == 1:
        point = point.reshape((1, 3))
    result = (point[:, 0]-sphere[0])**2 + (point[:, 1]-sphere[1]
                                           )**2 + (point[:, 2]-sphere[2])**2 - sphere[3]**2
    return result

calculate_intersection_of_two_rays(ray0, ray1)

Definition to calculate the intersection of two rays.

Parameters:

  • ray0
         A ray.
    
  • ray1
         A ray.
    

Returns:

  • point ( ndarray ) –

    Point in X,Y,Z.

  • distances ( ndarray ) –

    Distances.

Source code in odak/raytracing/ray.py
def calculate_intersection_of_two_rays(ray0, ray1):
    """
    Definition to calculate the intersection of two rays.

    Parameters
    ----------
    ray0       : ndarray
                 A ray.
    ray1       : ndarray
                 A ray.

    Returns
    ----------
    point      : ndarray
                 Point in X,Y,Z.
    distances  : ndarray
                 Distances.
    """
    A = np.array([
        [float(ray0[1][0]), float(ray1[1][0])],
        [float(ray0[1][1]), float(ray1[1][1])],
        [float(ray0[1][2]), float(ray1[1][2])]
    ])
    B = np.array([
        ray0[0][0]-ray1[0][0],
        ray0[0][1]-ray1[0][1],
        ray0[0][2]-ray1[0][2]
    ])
    distances = np.linalg.lstsq(A, B, rcond=None)[0]
    if np.allclose(np.dot(A, distances), B) == False:
        distances = np.array([0, 0])
    distances = distances[np.argsort(-distances)]
    point = propagate_a_ray(ray0, distances[0])[0]
    return point, distances

create_ray(x0y0z0, abg)

Definition to create a ray.

Parameters:

  • x0y0z0
           List that contains X,Y and Z start locations of a ray.
    
  • abg
           List that contaings angles in degrees with respect to the X,Y and Z axes.
    

Returns:

  • ray ( ndarray ) –

    Array that contains starting points and cosines of a created ray.

Source code in odak/raytracing/ray.py
def create_ray(x0y0z0, abg):
    """
    Definition to create a ray.

    Parameters
    ----------
    x0y0z0       : list
                   List that contains X,Y and Z start locations of a ray.
    abg          : list
                   List that contaings angles in degrees with respect to the X,Y and Z axes.

    Returns
    ----------
    ray          : ndarray
                   Array that contains starting points and cosines of a created ray.
    """
    # Due to Python 2 -> Python 3.
    x0, y0, z0 = x0y0z0
    alpha, beta, gamma = abg
    # Create a vector with the given points and angles in each direction
    point = np.array([x0, y0, z0], dtype=np.float64)
    alpha = np.cos(np.radians(alpha))
    beta = np.cos(np.radians(beta))
    gamma = np.cos(np.radians(gamma))
    # Cosines vector.
    cosines = np.array([alpha, beta, gamma], dtype=np.float64)
    ray = np.array([point, cosines], dtype=np.float64)
    return ray

create_ray_from_angles(point, angles, mode='XYZ')

Definition to create a ray from a point and angles.

Parameters:

  • point
         Point in X,Y and Z.
    
  • angles
         Angles with X,Y,Z axes in degrees. All zeros point Z axis.
    
  • mode
         Rotation mode determines ordering of the rotations at each axis. There are XYZ,YXZ    ,ZXY and ZYX modes.
    

Returns:

  • ray ( ndarray ) –

    Created ray.

Source code in odak/raytracing/ray.py
def create_ray_from_angles(point, angles, mode='XYZ'):
    """
    Definition to create a ray from a point and angles.

    Parameters
    ----------
    point      : ndarray
                 Point in X,Y and Z.
    angles     : ndarray
                 Angles with X,Y,Z axes in degrees. All zeros point Z axis.
    mode       : str
                 Rotation mode determines ordering of the rotations at each axis. There are XYZ,YXZ    ,ZXY and ZYX modes.

    Returns
    ----------
    ray        : ndarray
                 Created ray.
    """
    if len(point.shape) == 1:
        point = point.reshape((1, 3))
    new_point = np.zeros(point.shape)
    new_point[:, 2] += 5.
    new_point = rotate_points(new_point, angles, mode=mode, offset=point[:, 0])
    ray = create_ray_from_two_points(point, new_point)
    if ray.shape[0] == 1:
        ray = ray.reshape((2, 3))
    return ray

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 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 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.

Source code in odak/raytracing/ray.py
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.float64)
    x1y1z1 = np.asarray(x1y1z1, dtype=np.float64)
    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.float64)
    ray[:, 0] = x0y0z0
    ray[:, 1] = cosines
    if ray.shape[0] == 1:
        ray = ray.reshape((2, 3))
    return ray

find_nearest_points(ray0, ray1)

Find the nearest points on given rays with respect to the other ray.

Parameters:

  • ray0
         A ray.
    
  • ray1
         A ray.
    

Returns:

  • c0 ( ndarray ) –

    Closest point on ray0.

  • c1 ( ndarray ) –

    Closest point on ray1.

Source code in odak/raytracing/ray.py
def find_nearest_points(ray0, ray1):
    """
    Find the nearest points on given rays with respect to the other ray.

    Parameters
    ----------
    ray0       : ndarray
                 A ray.
    ray1       : ndarray
                 A ray.

    Returns
    ----------
    c0         : ndarray
                 Closest point on ray0.
    c1         : ndarray
                 Closest point on ray1.
    """
    p0 = ray0[0].reshape(3,)
    d0 = ray0[1].reshape(3,)
    p1 = ray1[0].reshape(3,)
    d1 = ray1[1].reshape(3,)
    n = np.cross(d0, d1)
    if np.all(n) == 0:
        point, distances = calculate_intersection_of_two_rays(ray0, ray1)
        c0 = c1 = point
    else:
        n0 = np.cross(d0, n)
        n1 = np.cross(d1, n)
        c0 = p0+(np.dot((p1-p0), n1)/np.dot(d0, n1))*d0
        c1 = p1+(np.dot((p0-p1), n0)/np.dot(d1, n0))*d1
    return c0, c1

propagate_a_ray(ray, distance)

Definition to propagate a ray at a certain given distance.

Parameters:

  • ray
         A ray.
    
  • distance
         Distance.
    

Returns:

  • new_ray ( ndarray ) –

    Propagated ray.

Source code in odak/raytracing/ray.py
def propagate_a_ray(ray, distance):
    """
    Definition to propagate a ray at a certain given distance.

    Parameters
    ----------
    ray        : ndarray
                 A ray.
    distance   : float
                 Distance.

    Returns
    ----------
    new_ray    : ndarray
                 Propagated ray.
    """
    if len(ray.shape) == 2:
        ray = ray.reshape((1, 2, 3))
    new_ray = np.copy(ray)
    new_ray[:, 0, 0] = distance*new_ray[:, 1, 0] + new_ray[:, 0, 0]
    new_ray[:, 0, 1] = distance*new_ray[:, 1, 1] + new_ray[:, 0, 1]
    new_ray[:, 0, 2] = distance*new_ray[:, 1, 2] + new_ray[:, 0, 2]
    if new_ray.shape[0] == 1:
        new_ray = new_ray.reshape((2, 3))
    return new_ray