first commit
This commit is contained in:
104
lib/math_utils.py
Normal file
104
lib/math_utils.py
Normal file
@@ -0,0 +1,104 @@
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
|
||||
def rads_to_degs(rads):
|
||||
"""Convert an angle from radians to degrees"""
|
||||
return 180 * rads / math.pi
|
||||
|
||||
|
||||
def angle_from_vector_to_x(vec):
|
||||
"""computer the angle (0~2pi) between a unit vector and positive x axis"""
|
||||
angle = 0.0
|
||||
# 2 | 1
|
||||
# -------
|
||||
# 3 | 4
|
||||
if vec[0] >= 0:
|
||||
if vec[1] >= 0:
|
||||
# Qadrant 1
|
||||
angle = math.asin(vec[1])
|
||||
else:
|
||||
# Qadrant 4
|
||||
angle = 2.0 * math.pi - math.asin(-vec[1])
|
||||
else:
|
||||
if vec[1] >= 0:
|
||||
# Qadrant 2
|
||||
angle = math.pi - math.asin(vec[1])
|
||||
else:
|
||||
# Qadrant 3
|
||||
angle = math.pi + math.asin(-vec[1])
|
||||
return angle
|
||||
|
||||
|
||||
def cartesian2polar(vec, with_radius=False):
|
||||
"""convert a vector in cartesian coordinates to polar(spherical) coordinates"""
|
||||
vec = vec.round(6)
|
||||
norm = np.linalg.norm(vec)
|
||||
theta = np.arccos(vec[2] / norm) # (0, pi)
|
||||
phi = np.arctan(vec[1] / (vec[0] + 1e-15)) # (-pi, pi) # FIXME: -0.0 cannot be identified here
|
||||
if not with_radius:
|
||||
return np.array([theta, phi])
|
||||
else:
|
||||
return np.array([theta, phi, norm])
|
||||
|
||||
|
||||
def polar2cartesian(vec):
|
||||
"""convert a vector in polar(spherical) coordinates to cartesian coordinates"""
|
||||
r = 1 if len(vec) == 2 else vec[2]
|
||||
theta, phi = vec[0], vec[1]
|
||||
x = r * np.sin(theta) * np.cos(phi)
|
||||
y = r * np.sin(theta) * np.sin(phi)
|
||||
z = r * np.cos(theta)
|
||||
return np.array([x, y, z])
|
||||
|
||||
|
||||
def rotate_by_x(vec, theta):
|
||||
mat = np.array([[1, 0, 0],
|
||||
[0, np.cos(theta), -np.sin(theta)],
|
||||
[0, np.sin(theta), np.cos(theta)]])
|
||||
return np.dot(mat, vec)
|
||||
|
||||
|
||||
def rotate_by_y(vec, theta):
|
||||
mat = np.array([[np.cos(theta), 0, np.sin(theta)],
|
||||
[0, 1, 0],
|
||||
[-np.sin(theta), 0, np.cos(theta)]])
|
||||
return np.dot(mat, vec)
|
||||
|
||||
|
||||
def rotate_by_z(vec, phi):
|
||||
mat = np.array([[np.cos(phi), -np.sin(phi), 0],
|
||||
[np.sin(phi), np.cos(phi), 0],
|
||||
[0, 0, 1]])
|
||||
return np.dot(mat, vec)
|
||||
|
||||
|
||||
def polar_parameterization(normal_3d, x_axis_3d):
|
||||
"""represent a coordinate system by its rotation from the standard 3D coordinate system
|
||||
|
||||
Args:
|
||||
normal_3d (np.array): unit vector for normal direction (z-axis)
|
||||
x_axis_3d (np.array): unit vector for x-axis
|
||||
|
||||
Returns:
|
||||
theta, phi, gamma: axis-angle rotation
|
||||
"""
|
||||
normal_polar = cartesian2polar(normal_3d)
|
||||
theta = normal_polar[0]
|
||||
phi = normal_polar[1]
|
||||
|
||||
ref_x = rotate_by_z(rotate_by_y(np.array([1, 0, 0]), theta), phi)
|
||||
|
||||
gamma = np.arccos(np.dot(x_axis_3d, ref_x).round(6))
|
||||
if np.dot(np.cross(ref_x, x_axis_3d), normal_3d) < 0:
|
||||
gamma = -gamma
|
||||
return theta, phi, gamma
|
||||
|
||||
|
||||
def polar_parameterization_inverse(theta, phi, gamma):
|
||||
"""build a coordinate system by the given rotation from the standard 3D coordinate system"""
|
||||
normal_3d = polar2cartesian([theta, phi])
|
||||
ref_x = rotate_by_z(rotate_by_y(np.array([1, 0, 0]), theta), phi)
|
||||
ref_y = np.cross(normal_3d, ref_x)
|
||||
x_axis_3d = ref_x * np.cos(gamma) + ref_y * np.sin(gamma)
|
||||
return normal_3d, x_axis_3d
|
||||
Reference in New Issue
Block a user