geom#

class cryocat.utils.geom.Line(starting_point, line_dir)#

Bases: object

class cryocat.utils.geom.LineSegment(point1, point2)#

Bases: Line

class cryocat.utils.geom.Matrix(input_data=None, size=3)#

Bases: object

SE3_cleanup()#

Given an input matrix that is a rototranslation, perform some cleanup of rounding errors etc.

Args:

input_matrix (_type_): _description_

Returns:

_type_: _description_

add_noise_and_project_to_so3(noise_level=0.05, degrees=False)#

Add noise to a matrix and project it back to SO(3) using SVD. (Singular value decomp.)

cone_in_plane_decomp()#

Decomposes input rotation matrix into matrices cone, in_plane, where cone describes cone-rotation and in_plane describes in-plane-rotation.

It holds: rot_matrix == in_plane @ cone

dual_basis_se3(index=None)#

Given an se(3)-matrix, return the ith coefficient of said matrix in linear combination w.r.t. canonical basis of se(3)

Args:

i (int): 1,2,3,4,5 or 6 se_3 (_type_): se(3)-matrix

Returns:

float: Coefficient from linear combination

dual_basis_so3()#

Given a skew-symmetric 3x3 matric, return the coefficients of said matrix in linear combination w.r.t. canonical basis of so3

Args:

so_3 (nd-array): so(3)-matrix

in_plane_angle()#
is_SE3()#

Boolean function to check whether an input matrix is a rototranslation.

Args:

input_matrix (_type_): _description_

Returns:

_type_: _description_

is_SO3()#

Boolean function to check whether an input matrix is a rotation matrix.

matrix_power(k)#
special_euclidean_from_rot_translation(translation)#

Combine SO(3) matrix with R^3 translation to SE(3) matrix.

Args:

rotation (np.array): SO(3) matrix translation (np.array): translation vector

Returns:

np.array: SE(3) matrix

twist_from_skew_translation(translation)#

Combine so(3) matrix with R^3 translation to se(3) matrix.

Args:

skew_symm (np.array): so(3) matrix translation (np.array): translation vector

Returns:

np.array: se(3) vector

class cryocat.utils.geom.Point3D(x, y, z)#

Bases: object

cone_indicator(cone_height, cone_radius, axis=None)#

Boolean function that checks whether a given point lies within a cone.

Args:

input_point (numpy array): Point for which to check whether it lies in a cone cone_height (float): Height of the cone. cone_radius (float): Radius of the cone. axis (numpy array): Axis of revolution for cone. Defaults to -np.array([0,0,1]).

Returns:

Bool: True if input_point lies in cone. False else.

torus_indicator(inner_rad, outer_rad, axis=None)#

Boolean function that checks whether a given point lies within a solid torus.

Args:

input_point (_type_): Point for which to check whether it lies in a solid torus. inner_rad (_type_): Inner radius of solid torus outer_rad (_type_): Outer radius of solid torus axis (_type_, optional): Axis of revolution. Tours lies in orthogonal complement of the axis. Defaults to np.array([0,0,1]).

Returns:

Bool: True if input_point lies in solid torus. False else.

torus_section_indicator(inner_rad, outer_rad, cone_radius, torus_revolution=None, cone_revolution=None)#

Boolean function that checks whether a given point lies in the intersection of a solid torus and a cone.

Args:

input_point (_type_): Point for which to check whether it lies in the intersection. inner_rad (_type_): Inner radius of torus outer_rad (_type_): Outer radius of torus cone_radius (_type_): Radius of cone torus_revolution (_type_, optional): Axis of revolution of torus. Defaults to np.array([0,0,1]). cone_revolution (_type_, optional): Axis of revolution of cone. Defaults to np.array([1,0,0]).

Returns:

Bool: _description_

property x#
property y#
property z#
class cryocat.utils.geom.Triangle(a, b, c)#

Bases: object

area()#
circumcircle()#
circumcircle_radius()#
inner_angles()#
inscribed_circle()#
cryocat.utils.geom.align_points_to_xy_plane(points_on_plane, plane_normal=None)#

Plane is rotated to be aligned with xy-plane.

Parameters:
points_on_planendarray

coplanar points

plane_normalndarray, optional

Plane normal. Defaults to None. If None, plane normal is estimated from points_on_plane

Returns:
ndarray (n,3), ndarray (3,3)

Points in xy-plane, corresponding rotation matrix

Raises:
ValueError

One needs at least 3 points to specify a plane if plane normal is not given.

cryocat.utils.geom.angle_between_n_vectors(v1, v2, degrees=True)#

Compute the angle (in degrees) between corresponding pairs of vectors in two arrays.

Parameters:
v1ndarray (n, d)

Each row represents d-dimensional vector.

v2ndarray (n, d)

Each row represents d-dimensional vector.

Returns:
ndarray (n,)

Array containing the angles (in degrees) between corresponding vectors.

Examples

>>> import numpy as np
>>> v1 = np.array([[1, 0, 0], [0, 1, 0]])
>>> v2 = np.array([[0, 1, 0], [1, 0, 0]])
>>> angle_between_n_vectors(v1, v2)
array([90., 90.])
cryocat.utils.geom.angle_between_vectors(vectors1, vectors2)#

Compute the angle (in degrees) between corresponding pairs of vectors in two arrays.

Parameters:
vectors1ndarray (n, d)

Each row represents a d-dimensional vector.

vectors2ndarray (n, d)

Each row represents a d-dimensional vector.

Returns:
ndarray (n,)

Array containing the angles (in degrees) between corresponding vectors.

Examples

>>> vectors1 = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
>>> vectors2 = np.array([[0, 1, 0], [0, 0, 1], [1, 0, 0]])
>>> angle_between_vectors(vectors1, vectors2)
array([90., 90., 90.])
cryocat.utils.geom.angular_distance(input_rot1, input_rot2, convention='zxz', degrees=True, c_symmetry=1)#

Compute angular distance between two rotations. Formula is based on this post https://math.stackexchange.com/questions/90081/quaternion-distance

Parameters:
input_rot1scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle.

input_rot2scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle.

conventionstr, optional

Euler angle convention. Defaults to “zxz”.

degreesbool, optional

Return angular distance in degrees (True) or radians (False). Defaults to True.

c_symmetryint, optional

Rotational symmetry of underlying particles. Defaults to 1.

Returns:
float

Angular distance between input rotations.

Examples

>>> rot1 = srot.from_euler("zxz", [0, 0, 0], degrees=True)
>>> rot2 = srot.from_euler("zxz", [45, 45, 0], degrees=True)
>>> angular_distance(rot1, rot2)
45.0
cryocat.utils.geom.angular_score_for_c_symmetry(inplane_1, inplane_2, c_symmetry, max_val=None)#

Computes an angular similarity score for arrays of in-plane angles, based on rotational symmetry.

cryocat.utils.geom.area_triangle(coords)#

Calculate the area of a triangle given its vertex coordinates. See https://stackoverflow.com/questions/71346322/numpy-area-of-triangle-and-equation-of-a-plane-on-which-triangle-lies-on

Parameters:
coordsndarray

An array of shape (3, 3) where each row represents a vertex of the triangle, and each vertex is given by three coordinates (x, y, z).

Returns:
float

The area of the triangle.

Examples

>>> coords = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0]])
>>> area_triangle(coords)
0.5
cryocat.utils.geom.cartesian_to_spherical(coord, normalize=True)#

Convert Cartesian coordinates to spherical coordinates.

Parameters:
coordnumpy.ndarray

A 2D array of shape (N, 3*K) where N is the number of points and K is the number of sets of 3D coordinates. Each set of 3D coordinates corresponds to a point in Cartesian space.

normalizebool, optional

If True, the input Cartesian coordinates will be normalized before conversion. Default is True.

Returns:
phinumpy.ndarray

A 1D array of azimuthal angles (in radians) of shape (M,) where M is the number of valid points after filtering out NaNs.

thetanumpy.ndarray

A 1D array of polar angles (in radians) of shape (M,) where M is the number of valid points after filtering out NaNs.

Raises:
ValueError

If the input coord does not have the shape (N, 3*K).

Notes

The azimuthal angle phi is computed as the angle in the x-y plane from the positive x-axis, and the polar angle theta is computed from the positive z-axis. The function filters out any points that result in NaN values during the conversion process.

cryocat.utils.geom.change_handedness_coordinates(coordinates, dimensions)#

The change_handedness_coordinates function takes in a pandas dataframe of coordinates and the dimensions of the coordinate system. It then changes the handedness of those coordinates by subtracting each z-coordinate from dimension[2]. This is done because we want to change our coordinate system so that it has its origin at the top left corner, with positive x going right and positive y going down. The original coordinate system had its origin at bottom left, with positive x going right and positive y going up.

Parameters:
coordinates

Store the coordinates of the voxels

dimensions

Determine the new z value

Returns:
The coordinates with the z axis inverted
Doc Author:
Trelent
cryocat.utils.geom.compare_rotations(angles1, angles2, c_symmetry=1, rotation_type='all')#

Compare the rotations between two sets of angles.

Parameters:
angles1list

The first set of angles.

angles2list

The second set of angles.

c_symmetryint

The degree of rotational symmetry. Defaults to 1.

Returns:
tuple

A tuple containing the following distances: - dist_degrees (float): The overall angular distance between the two sets of angles. - dist_degrees_normals (float): The angular distance between the normal vectors of the two sets of angles. - dist_degrees_inplane (float): The angular distance within the plane of rotation between the two sets of angles.

cryocat.utils.geom.cone_distance(input_rot1, input_rot2)#

Compute great-circle distance between z-normals corresponding to orientations as represented by input rotations. This corresponds to angular distance between cone-rotation portions of respective input rotations.

Parameters:
input_rot1scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle

input_rot2scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle

Returns:
float

cone-distance in degrees

cryocat.utils.geom.cone_inplane_distance(input_rot1, input_rot2, convention='zxz', degrees=True, c_symmetry=1)#

Compute angular distance between cone-rotations and inplane-rotations, respectively.

Parameters:
input_rot1scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle.

input_rot2scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle.

conventionstr, optional

Euler angle convention. Defaults to “zxz”.

degrees :bool, optional

Return angular distance in degrees (True) or radians (False). Defaults to True.

c_symmetryint, optional

Rotational symmetry of underlying particles. Defaults to 1.

Returns:
float

Angular distance between cone-rotations

float

angular distance between inplane rotations.

cryocat.utils.geom.cube()#
cryocat.utils.geom.distance_array(vol)#
cryocat.utils.geom.dodecahedron()#
cryocat.utils.geom.euler_angles_to_normals(angles)#

Compute normal vectors pointing in z-direction from Euler angles.

Returns:
ndarray (n,3)

Unit length z-normal vectors associated to input Euler angles.

cryocat.utils.geom.fill_ellipsoid(box_size, ellipsoid_parameters)#

Fills a 3D space defined by box_size with a boolean mask where an ellipsoid defined by ellipsoid_parameters is located.

Parameters:
box_sizeint or array_like

Size of the box in which the ellipsoid will be placed. If an integer is provided, it is interpreted as the size for all three dimensions. If a tuple or list is provided, it should contain three integers defining the dimensions of the box.

ellipsoid_parametersarray_like

Coefficients for the general ellipsoid equation: Ax^2 + By^2 + Cz^2 + 2Dxy + 2Exz + 2Fyz + 2Gx + 2Hy + 2Iz + J = 0 Should contain ten elements corresponding to A, B, C, D, E, F, G, H, I, J respectively.

Returns:
numpy.ndarray

A 3D boolean array where True values represent the points inside or on the surface of the ellipsoid.

Examples

>>> box_size = 10
>>> ellipsoid_parameters = (1, 1, 1, 0, 0, 0, 0, 0, 0, -100)
>>> mask = fill_ellipsoid(box_size, ellipsoid_parameters)
>>> mask.shape
(10, 10, 10)
cryocat.utils.geom.fit_circle_2d_lsq(x, y, w=None)#

Fit a circle to 2D points using the least squares method. The method was taken from https://meshlogic.github.io/posts/jupyter/curve-fitting/fitting-a-circle-to-cluster-of-3d-points/

Parameters:
xarray_like

X-coordinates of the points.

yarray_like

Y-coordinates of the points.

warray_like, optional

Weights for each point. If provided, must be the same length as x and y. Defaults to None.

Returns:
xcfloat

X-coordinate of the fitted circle’s center.

ycfloat

Y-coordinate of the fitted circle’s center.

rfloat

Radius of the fitted circle.

errorfloat

Sum of the squared residuals of the fit.

Notes

This function fits a circle in 2D to a set of points (x, y) by solving the weighted least squares problem if weights w are provided. If no weights are provided, it solves the ordinary least squares problem.

Examples

>>> x = np.array([1, 2, 3])
>>> y = np.array([4, 5, 6])
>>> xc, yc, r, error = fit_circle_2d_lsq(x, y)
cryocat.utils.geom.fit_circle_2d_newton(coord)#

Fit a circle to 2D data using Newton’s method.

Parameters:
coordndarray

An array of shape (N, 2) containing the x and y coordinates of the data points.

Returns:
circle_centerndarray

A 1D array containing the x and y coordinates of the circle’s center.

circle_radiusfloat

The radius of the fitted circle.

confidenceint

Confidence level of the fit, 1 if successful, -1 if the fit failed.

Notes

The function implements a numerical method to fit a circle to a set of 2D points by minimizing the algebraic distance to the circle. The method used is based on the algebraic form of a circle and Newton’s optimization method to find the circle parameters that best fit the data.

Examples

>>> points = np.array([[1, 2], [3, 4], [5, 6]])
>>> center, radius, conf = fit_circle_2d_newton(points)
>>> print(center, radius, conf)
cryocat.utils.geom.fit_circle_3d_lsq(coord)#

Fit a circle to 3D points using least squares optimization.

Parameters:
coordndarray

An array of shape (N, 3) containing the 3D coordinates of the points.

Returns:
circle_centerndarray

A 1D array of length 3 containing the x, y, z coordinates of the fitted circle’s center.

circle_radiusfloat

The radius of the fitted circle.

residual_errorfloat

Sum of the squared residuals of the fit.

Notes

This function projects 3D points onto a 2D plane that is normal to their average normal vector. It then fits a circle in 2D and transforms the center back to the 3D space.

cryocat.utils.geom.fit_circle_3d_pratt(coord)#

Fit a circle to a set of 3D points using Pratt’s method after projecting them onto a 2D plane.

Parameters:
coordndarray

An array of shape (N, 3) containing N points in 3D space.

Returns:
circle_centerndarray

A 1D array of length 3 representing the center of the circle in 3D space.

circle_radiusfloat

The radius of the fitted circle.

confidenceint

Confidence indicator, returns 1 if the center is not at the origin, otherwise -1.

Notes

The function first projects the 3D points onto a 2D plane using a variance-based method. It then applies Pratt’s method to these 2D points to fit a circle. The center of the circle is then transformed back to 3D space. The radius is calculated as the mean Euclidean distance from the 3D points to the estimated center. The confidence is a simple check on the location of the center.

Examples

>>> points = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> center, radius, conf = fit_circle_3d_pratt(points)
>>> print(center, radius, conf)
cryocat.utils.geom.fit_circle_3d_taubin(coord)#

Fit a circle to 3D points using Taubin’s method projected onto a 2D plane.

Parameters:
coordndarray

An array of shape (N, 3) representing the coordinates of the 3D points.

Returns:
circle_centerndarray

A 1D array of length 3 representing the center of the fitted circle in 3D space.

circle_radiusfloat

The radius of the fitted circle.

confidencefloat

A confidence measure for the circle fitting. Returns -1 if the fitting fails.

Notes

The function projects 3D points onto a 2D plane using a variance-based method, then fits a circle in 2D using Newton’s method. The best fitting circle is selected based on the minimum radius criterion among possible circle fits.

Examples

>>> coord = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> center, radius, conf = fit_circle_3d_taubin(coord)
>>> print(center, radius, conf)
cryocat.utils.geom.fit_ellipsoid(coord)#

Fit an ellipsoid to a set of 3D coordinates. It is based on http://www.mathworks.com/matlabcentral/fileexchange/24693-ellipsoid-fit

Parameters:
coordndarray

An array of shape (N, 3) where each row represents the x, y, z coordinates.

Returns:
centerndarray

The center of the ellipsoid (x, y, z coordinates).

radiindarray

Radii of the ellipsoid along the principal axes.

evecsndarray

The eigenvectors corresponding to the principal axes of the ellipsoid.

vndarray

The 1D array of the ellipsoid parameters used to form the quadratic form.

Notes

This function fits an ellipsoid to a set of points by solving a linear least squares problem to estimate the parameters of the ellipsoid’s equation in its algebraic form.

Examples

>>> points = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> center, radii, evecs, _ = fit_ellipsoid(points)
>>> center
array([x_center, y_center, z_center])
>>> radii
array([radius_x, radius_y, radius_z])
>>> evecs
array([[evec1_x, evec1_y, evec1_z],
       [evec2_x, evec2_y, evec2_z],
       [evec3_x, evec3_y, evec3_z]])
cryocat.utils.geom.generate_angles(cone_angle, cone_sampling, inplane_angle=360.0, inplane_sampling=None, starting_angles=None, symmetry=1.0, angle_order='zxz')#

Compute Euler angles from sample for normal vectors on sphere. Sphere sample corresponds to cone-angles.

Parameters:
cone_anglefloat

Angle for sampling of cone-angles (refers to range of z-normals of particles).

cone_samplingfloat

Frequency for cone sampling.

inplane_anglefloat, optional

Desired inplane-angles for particle orientations. Defaults to 360.0.

inplane_samplingfloat, optional

Frequency for sampling of inplane-angles. Defaults to None.

starting_anglesndarray , optional

Triplet of Euler angles in convention as spefified by angle_order. Defaults to None.

symmetryfloat, optional

Refers to rotational symmetry of particles. Defaults to 1.0.

angle_orderstr, optional

Convention for Euler angles. Defaults to “zxz”.

Returns:
ndarray

Sample of Euler angles.

cryocat.utils.geom.get_axis_from_rotation(input_rotation, axis='z')#

Given an input rotation, compute the desired unit normal vector from the coordinate frame associated to the rotation.

Parameters:
input_rotationscipy.spatial.transform.Rotation object

Rotation object describing orientation of particle

axisstr, optional

Desired coordinate direction. Defaults to “z”.

Returns:
ndarray

unit vector

Raises:
ValueError

Input must be valid scipy rotation object.

cryocat.utils.geom.great_circle_distance(p1, p2)#
cryocat.utils.geom.great_circle_distance_matrix(points1, points2)#

Compute the pairwise great-circle distances between two sets of points on an n-sphere.

cryocat.utils.geom.hausdorff_distance_sphere(set1, set2)#

Compute the simplified Hausdorff distance between two discrete sets of points on an n-sphere.

cryocat.utils.geom.icosahedron()#
cryocat.utils.geom.inplane_distance(input_rot1, input_rot2, convention='zxz', degrees=True, c_symmetry=1)#

Compute the angular distance between inplane-rotation portion of two given rotations.

Parameters:
input_rot1scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle.

input_rot2scipy.spatial.transform.Rotation object

Rotation object describing orientation of particle.

conventionstr, optional

Euler angle convention. Defaults to “zxz”.

degreesbool, optional

Return angular distance in degrees (True) or radians (False). Defaults to True.

c_symmetryint, optional

Rotational symmetry of underlying particles. Defaults to 1.

Returns:
float

Angular distance between inplane rotations.

cryocat.utils.geom.min_great_circle_distance(set1, set2)#

Computes the minimum great-circle distance between two sets of points on S^n.

cryocat.utils.geom.n_gon_points(n)#
cryocat.utils.geom.normalize_vector(vector)#

Normalize a vector.

Parameters:
vectorarray_like

Input vector to be normalized.

Returns:
ndarray

Normalized vector with the same direction but with a norm of 1.

Examples

>>> import numpy as np
>>> v = np.array([2, 3, 6])
>>> normalize_vector(v)
array([0.26726124, 0.40089186, 0.80278373])
cryocat.utils.geom.normalize_vectors(v)#

Normalize each vector, handling both single vectors and arrays of vectors.

Parameters:
vndarray (n,d)
Returns:
ndarray (n,d)

Array of normalized vectors.

Examples

>>> import numpy as np
>>> v = np.array([[1, 2, 3], [4, 5, 6]])
>>> normalize_vectors(v)
array([[0.26726124, 0.53452248, 0.80178373],^
          [0.45584231, 0.56980288, 0.68376346]])
cryocat.utils.geom.normals_to_euler_angles(input_normals, output_order='zxz')#

Given normal vectors pointing in z-direction in particle frames, compute choice of Euler angles.

Parameters:
input_normalsndarray, pandas dataFrame

z-normal vectors

output_orderstr, optional

Euler angle convention. Defaults to “zxz”.

Returns:
ndarray(n,3)

n triplets of Euler angles in choses convention.

Raises:
UserInputError

input_normals have to be either pandas dataFrame or numpy array.

cryocat.utils.geom.number_of_cone_rotations(cone_angle, cone_sampling)#

Calculates the number of rotations required for a sampling process of cone-angles based on a sampling interval.

Parameters:
cone_anglefloat

The total cone-angle in degrees.

cone_samplingfloat

The angular sampling interval in degrees.

Returns:
int

The total number of rotations required for the sampling process.

cryocat.utils.geom.octahedron()#
cryocat.utils.geom.order_points_on_circle(points)#

Order points on a circle based on their angles with respect to the x-axis.

Parameters:
pointsnumpy.ndarray

A 2D array of shape (n, 3) where each row represents a point in 3D space (x, y, z).

Returns:
numpy.ndarray

A 2D array of shape (n, 3) containing the input points ordered by their angles in the xy-plane, starting from the positive x-axis and moving counterclockwise.

numpy.ndarray

A 1D array of shape (n,) containing the order of points.

Notes

This function assumes that the input points are approximately in the xy-plane, and it discards the z-coordinate for the ordering process. The points are normalized to lie on the unit circle before calculating their angles.

cryocat.utils.geom.oversample_spline(coords, target_spacing)#

Fit a spline through 3D coordinates and oversample so that the distance between points is approximately target_spacing.

Parameters:
coordsndarray

Array of shape (n, 3) representing the input points.

target_spacingfloat

Desired distance between points on the spline.

Returns:
ndarray

Oversampled coordinates along the spline.

cryocat.utils.geom.point_ellipsoid_distance(p, params)#

Computes the shortest distance from a point p to the surface of an ellipsoid.

cryocat.utils.geom.point_pairwise_dist(coord_1, coord_2)#

Calculate the pairwise Euclidean distance between two sets of coordinates.

Parameters:
coord_1ndarray

An array of shape (N, D) where N is the number of points and D is the dimensionality of each point. If N=1, the single point is broadcasted to match the number of points in coord_2.

coord_2ndarray

An array of shape (M, D) where M is the number of points and D is the dimensionality of each point. If coord_1 has N>1, then M has to be equal to N.

Returns:
pairwise_distndarray

An array of shape (max(N, M),) containing the Euclidean distances between each pair of points from coord_1 and coord_2.

Notes

If the input arrays have complex numbers, the distance calculation defaults to 0.0 for those pairs.

cryocat.utils.geom.project_3d_points_on_2d_plane_normal_aligned(coord, target_direction=None)#

Projects 3D points onto a 2D plane that is aligned with a specified normal direction.

Parameters:
coordndarray

An array of shape (N, 3) containing N points in 3D space.

target_directionarray_like, optional

A 3-element array specifying the direction to which the normal of the 2D plane should be aligned. If None, defaults to [0, 0, 1], aligning the plane with the z-axis. Defaults to None.

Returns:
coord_projndarray

An array of shape (N, 2) containing the 2D coordinates of the projected points.

coord_meanndarray

A 1D array of length 3 representing the mean of the original coordinates.

normalndarray

A 1D array of length 3 representing the normal vector of the plane onto which the points are projected.

Notes

The function first centers the points by subtracting their mean. It then uses Singular Value Decomposition (SVD) to find the principal components of the points. The smallest singular vector (normal to the plane of best fit) is used. The points are then rotated to align this normal with the target direction, effectively projecting them onto a new 2D plane.

cryocat.utils.geom.project_3d_points_on_2d_plane_variance_based(coord)#

Projects 3D points onto a 2D plane using variance-based method via Singular Value Decomposition (SVD).

Parameters:
coordndarray

An array of shape (N, 3) where n is the number of 3D points.

Returns:
coord_projndarray

The projected coordinates of the points onto the 2D plane, of shape (N, 2).

Undarray

The matrix containing the left singular vectors of the decomposition, used to project the points.

Notes

The function performs dimensionality reduction by projecting the original 3D points onto the 2D plane that captures the most variance in the data. This is achieved using SVD, which decomposes the input matrix into its singular vectors and singular values.

Examples

>>> points = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> projected_points, _ = project_3d_points_on_2d_plane_variance_based(points)
>>> print(projected_points)
cryocat.utils.geom.project_points_on_plane_with_preserved_distance(starting_point, normal, nn_points)#

Project approximately coplanar points around a starting_point onto the plane perpendicular to normal vector. The distances between projected nearest neighbors and starting point are preserved.

Parameters:
starting_pointndarray

origin of plane specified by normal vector

normalndarray

normal vector to plane

nn_pointsndarray

nearest neighbors of starting_point

Returns:
ndarray

projected points on plane specified by starting_point and normal

cryocat.utils.geom.quaternion_log(q)#

Given array of unit scalar-last quaternions, compute array of unit-quaternion logarithms.

Parameters:
qndarray (n,4)

Array of n unit quaternions in scalar-last convention.

Returns:
ndarray (n,4)

Array of n quaternion logarithms.

cryocat.utils.geom.quaternion_mult(qs1, qs2)#

Given arrays of quaternions in scalar-last convention, compute array of products of unit quaternions.

Parameters:
qs1ndarray (n,4)

n quaternions in scalar-last convention.

qs2ndarray (n,4)

n quaternions in scalar-last convention.

Returns:
ndarray (n,4)

n quaternions in scalar-last convention. Row i is product of qs1[i] and qs2[i].

cryocat.utils.geom.ray_ellipsoid_intersection_3d(point, normal, ellipsoid_params)#

Compute the intersection between a ray starting at point in direction of normal and an ellipsoid specified by ellipsoid_params.

Parameters:
pointndarray (3,)

Point in 3D describing origin of ray.

normalndarray (3,)

Normal vector describing direction of ray.

ellipsoid_paramsndarray, list or tuple of 10 floats

Coefficients describing quadratic form of ellipsoid.

Returns:
tuple (p1, p2, d1, d2, is_inside) with:

p1: ndarray describing closest intersection, or NaN. p2: ndarray describing intersection, or NaN. d1: float (distance between point and p1), or NaN. d2: float (distance between point and p2), or NaN. is_inside: bool, true if point lies inside the ellipsoid.

cryocat.utils.geom.ray_ray_intersection_3d(starting_points, ending_points)#

Calculate the intersection point and distances from the intersection to each line for a set of 3D rays.

Parameters:
starting_pointsndarray

An array of shape (N, 3) representing the starting points of N lines in 3D space.

ending_pointsndarray

An array of shape (N, 3) representing the ending points of N lines in 3D space.

Returns:
P_intersectndarray

A 1D array of shape (3,) containing the coordinates of the intersection point.

distancesndarray

A 1D array of shape (N,) containing the distances from the intersection point to each line.

Notes

This function assumes that all lines are somewhat close to intersecting at a common point and uses a least squares approach to find the best intersection point. The function may not be suitable for parallel lines or lines that do not converge.

cryocat.utils.geom.rotate_points_rodrigues(P, n0, n1)#

Rotates points by the rotation defined by two vectors.

Parameters:
Pndarray

Array containing point(s) to be rotated. Can be a 1D array for a single point or a 2D array for multiple points.

n0ndarray

Initial vector, before rotation. Must be a 1D array of 3 elements.

n1ndarray

Final vector, after rotation. Must be a 1D array of 3 elements.

Returns:
P_rotndarray

Array of rotated points. Same shape as input array P.

Notes

This function computes the rotation matrix that rotates vector n0 to align with vector n1 and applies this rotation to point(s) P. The rotation is performed using the Rodrigues’ rotation formula, facilitated by scipy’s spatial transformations.

Examples

>>> P = np.array([1, 0, 0])
>>> n0 = np.array([1, 0, 0])
>>> n1 = np.array([0, 1, 0])
>>> rotate_points_rodrigues(P, n0, n1)
array([[0., 1., 0.]])
cryocat.utils.geom.sample_cone(cone_angle, cone_sampling, center=None, radius=1.0)#

Creates an “even” distibution on sphere. Works for tame cases. Source: https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere/26127012#26127012

Parameters:
cone_anglefloat

Angle for sampling of cone-angles (refers to range of z-normals of particles).

cone_samplingfloat

Frequency for cone sampling.

centerndarray, optional

Center of sphere to be sampled. Defaults to None.

radiusfloat, optional

Radius of sphere to be sampled. Defaults to 1.0.

Returns:
ndarray

Samples on sphere.

cryocat.utils.geom.spline_sampling(coords, sampling_distance)#

Samples a spline specified by coordinates with a given sampling distance

Parameters:
coordsndarray

coordinates of the spline

sampling_distancefloat

sampling frequency in pixels

Returns:
ndarray

coordinates of points on the spline

cryocat.utils.geom.tetrahedron()#
cryocat.utils.geom.vector_angular_distance(v1, v2)#

Calculate the angular distance between two vectors in degrees.

Parameters:
v1array_like

First input vector.

v2array_like

Second input vector.

Returns:
float

The angular distance between v1 and v2 in degrees.

Examples

>>> v1 = [1, 0, 0]
>>> v2 = [0, 1, 0]
>>> vector_angular_distance(v1, v2)
90.0
cryocat.utils.geom.vector_angular_distance_signed(u, v, n=None)#

Compute the signed angular distance between two vectors.

Parameters:
uarray_like

First input vector.

varray_like

Second input vector.

narray_like, optional

Normal vector to the plane containing u and v. If not provided, the function computes the unsigned angular distance.

Returns:
float

The signed angular distance between vectors u and v. This is the angle in radians between the two vectors, signed according to the direction given by n. If n is not provided, the result is the unsigned angle.

Notes

The signed angle is computed based on the right-hand rule. If n is provided, the sign of the angle is determined by the direction of n relative to the cross product of u and v. If n is not provided, the function returns the magnitude of the angle only.

Examples

>>> u = np.array([1, 0, 0])
>>> v = np.array([0, 1, 0])
>>> vector_angular_distance_signed(u, v)
1.5707963267948966  # 90 degrees in radians
>>> n = np.array([0, 0, 1])
>>> vector_angular_distance_signed(u, v, n)
1.5707963267948966  # 90 degrees in radians, positive as per right-hand rule with `n` as z-axis
>>> n = np.array([0, 0, -1])
>>> vector_angular_distance_signed(u, v, n)
-1.5707963267948966  # 90 degrees in radians, negative as per right-hand rule with `n` as -z-axis
cryocat.utils.geom.visualize_angles(angles, plot_rotations=True, color_map=None)#

Compute z-normals of input orientations as described using Euler angles in zxz-convention. If desried, generate plot depicting z-normals of input orientations.

Parameters:
anglesndarray (n, 3)

Array of triplets of Euler angles in zxz-convention.

plot_rotationsbool, optional

If True, plot is generated. Defaults to True.

color_mapstr, optional

Specify colormap for plot. Defaults to None.

Returns:
ndarray (n,3)

Array of z-normals.

cryocat.utils.geom.visualize_rotations(rotations, plot_rotations=True, color_map=None, marker_size=20, alpha=1.0, radius=1.0)#

Compute z-normals of input rotations. If desried, generate plot depicting z-normals of input rotations.

Parameters:
rotationsarray of scipy.spatial.transform.Rotation objects

Orientations to be visualized

plot_rotationsbool, optional

If True, plot is generated. Defaults to True.

color_mapstr, optional

Specify colormap for plot. Defaults to None.

marker_sizeint, optional

Specify marker size for plot. Defaults to 20.

alphafloat, optional

Specify alpha parameter for plot. Defaults to 1.0.

radiusfloat, optional

Specify size of sphere for visualization. Defaults to 1.0.

Returns:
ndarray (n,3)

Array of z-normals.