mae_envs/util/geometry.py (29 lines of code) (raw):
import numpy as np
from mujoco_worldgen.util.rotation import quat_mul, quat_conjugate
def dist_pt_to_cuboid(pt1, cuboid_center, cuboid_dims, cuboid_quat):
'''
This function calculates the shortest distance between test points
and cuboids at arbitrary locations, widths and rotations
Args:
pt1 (num points x 3): test point positions
cuboid_center (num cuboids x 3): cuboid centers
cuboid_dims (num cuboids x 3): cuboid half-width
cuboid_quat (num cuboids x 4): cuboid quaternion
Returns:
Distance array of size num points x num cuboids
'''
assert cuboid_center.shape[0] == cuboid_dims.shape[0] == cuboid_quat.shape[0], \
"First dimension of cuboid_center, cuboid_dims and cuboid_quat need to match, " + \
f"but were {cuboid_center.shape[0]}, {cuboid_dims.shape[0]} and {cuboid_quat.shape[0]}."
assert pt1.shape[1] == cuboid_center.shape[1] == cuboid_dims.shape[1] == 3, \
"Second dimension of pt1, cuboid_center and cuboid_dims needs to be 3, " + \
f"but were {pt1.shape[1]}, {cuboid_center.shape[1]} and {cuboid_dims.shape[1]}."
assert cuboid_quat.shape[1] == 4, \
f"Second dimension of cuboid_quat needs to be 4, but was {cuboid_quat.shape[1]}."
# calculate relative position of test points
rel_pos = pt1[:, None, :] - cuboid_center[None, :, :]
# convert into quaternion (leading dimension is zero)
q_rel_pos = np.concatenate([np.zeros_like(rel_pos[:, :, [0]]), rel_pos], axis=-1)
# broadcast cuboid_quat by hand
cuboid_quat = np.repeat(cuboid_quat[None, :], pt1.shape[0], axis=0)
# rotate relative position in cuboid frame
# since cuboid_quat specifies how the cuboid is rotated wrt to the standard coordinate system,
# we need to rotate the test points using the inverse rotation (i.e. conjugate quaternion)
#
# For rotation of vectors using quaternions see
# https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
q_rel_pos = quat_mul(quat_conjugate(cuboid_quat), quat_mul(q_rel_pos, cuboid_quat))
# now we can pretend that the cuboid is aligned to x-axis
# calculate vector to closest point on the cuboid
# this can be done as described here:
# https://gamedev.stackexchange.com/questions/44483/how-do-i-calculate-distance-between-a-point-and-an-axis-aligned-rectangle
dist_vec = np.maximum(0, np.abs(q_rel_pos[:, :, 1:]) - cuboid_dims[None, :, :])
# distance is length of distance vector
dist = np.linalg.norm(dist_vec, axis=-1)
return dist