All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.biojava.nbio.structure.geometry.UnitQuaternions Maven / Gradle / Ivy

/*
 *                    BioJava development code
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  If you do not have a copy,
 * see:
 *
 *      http://www.gnu.org/copyleft/lesser.html
 *
 * Copyright for this code is held jointly by the individual
 * authors.  These should be listed in @author doc comments.
 *
 * For more information on the BioJava project and its aims,
 * or to join the biojava-l mailing list, visit the home page
 * at:
 *
 *      http://www.biojava.org/
 *
 */
package org.biojava.nbio.structure.geometry;

import javax.vecmath.AxisAngle4d;
import javax.vecmath.Point3d;
import javax.vecmath.Quat4d;

import org.biojava.nbio.structure.jama.EigenvalueDecomposition;
import org.biojava.nbio.structure.jama.Matrix;

/**
 * UnitQuaternions is a static Class that contains methods for calculating and
 * using unit quaternions. It assumes the use of {@link Quat4d} Class from
 * vecmath to represent the unit quaternions, and it also implements some of the
 * basic methods that the library is missing.
 * 

* A Unit Quaternion is a four-dimensional vector used to describe a * three-dimensional attitude representation (axis and angle of rotation). By * definition, unit quaternions are always normalized, so their length is always * 1. * * @author Aleix Lafita * @since 5.0.0 * */ public class UnitQuaternions { /** Prevent instantiation */ private UnitQuaternions() { } /** * The orientation metric is obtained by comparing the quaternion * orientations of the principal axes of each set of points in 3D. *

* First, the quaternion orientation of each set of points is calculated * using their principal axes with {@link #orientation(Point3d[])}. Then, * the two quaternions are compared using the method * {@link #orientationMetric(Quat4d, Quat4d)}. *

* A requisite for this method to work properly is that both sets of points * have to define the same shape (or very low RMSD), otherwise some of the * principal axes might change or be inverted, resulting in an unreliable * metric. For shapes with some deviations in their shape, use the metric * {@link #orientationAngle(Point3d[], Point3d[])}. * * @param a * array of Point3d * @param b * array of Point3d * @return the quaternion orientation metric */ public static double orientationMetric(Point3d[] a, Point3d[] b) { Quat4d qa = orientation(a); Quat4d qb = orientation(b); return orientationMetric(qa, qb); } /** * The orientation metric is obtained by comparing two unit quaternion * orientations. *

* The two quaternions are compared using the formula: d(q1,q2) = * arccos(|q1*q2|). The range of the metric is [0, Pi/2], where 0 means the * same orientation and Pi/2 means the opposite orientation. *

* The formula is taken from: Huynh, D. Q. (2009). Metrics for 3D rotations: * comparison and analysis. Journal of Mathematical Imaging and Vision, * 35(2), 155–164. http://doi.org/10.1007/s10851-009-0161-2 * * @param q1 * quaternion as Quat4d object * @param q2 * quaternion as Quat4d object * @return the quaternion orientation metric */ public static double orientationMetric(Quat4d q1, Quat4d q2) { return Math.acos(Math.abs(dotProduct(q1, q2))); } /** * The orientation represents the rotation of the principal axes with * respect to the axes of the coordinate system (unit vectors [1,0,0], * [0,1,0] and [0,0,1]). *

* The orientation can be expressed as a unit quaternion. * * @param points * array of Point3d * @return the orientation of the point cloud as a unit quaternion */ public static Quat4d orientation(Point3d[] points) { MomentsOfInertia moi = new MomentsOfInertia(); for (Point3d p : points) moi.addPoint(p, 1.0); // Convert rotation matrix to quaternion Quat4d quat = new Quat4d(); quat.set(moi.getOrientationMatrix()); return quat; } /** * Calculate the rotation angle component of the input unit quaternion. * * @param q * unit quaternion Quat4d * @return the angle in radians of the input quaternion */ public static double angle(Quat4d q) { AxisAngle4d axis = new AxisAngle4d(); axis.set(q); return axis.angle; } /** * The angle of the relative orientation of the two sets of points in 3D. * Equivalent to {@link #angle(Quat4d)} of the unit quaternion obtained by * {@link #relativeOrientation(Point3d[], Point3d[])}. *

* The arrays of points need to be centered at the origin. To center the * points use {@link CalcPoint#center(Point3d[])}. * * @param fixed * array of Point3d, centered at origin. Original coordinates * will not be modified. * @param moved * array of Point3d, centered at origin. Original coordinates * will not be modified. * @return the angle in radians of the relative orientation of the points, * angle to rotate moved to bring it to the same orientation as * fixed. */ public static double orientationAngle(Point3d[] fixed, Point3d[] moved) { Quat4d q = relativeOrientation(fixed, moved); return angle(q); } /** * The angle of the relative orientation of the two sets of points in 3D. * Equivalent to {@link #angle(Quat4d)} of the unit quaternion obtained by * {@link #relativeOrientation(Point3d[], Point3d[])}. * * @param fixed * array of Point3d. Original coordinates will not be modified. * @param moved * array of Point3d. Original coordinates will not be modified. * @param centered * true if the points are already centered at the origin * @return the angle in radians of the relative orientation of the points, * angle to rotate moved to bring it to the same orientation as * fixed. */ public static double orientationAngle(Point3d[] fixed, Point3d[] moved, boolean centered) { if (!centered) { fixed = CalcPoint.clonePoint3dArray(fixed); moved = CalcPoint.clonePoint3dArray(moved); CalcPoint.center(fixed); CalcPoint.center(moved); } return orientationAngle(fixed, moved); } /** * Calculate the relative quaternion orientation of two arrays of points. * * @param fixed * point array, coordinates will not be modified * @param moved * point array, coordinates will not be modified * @return a unit quaternion representing the relative orientation, to * rotate moved to bring it to the same orientation as fixed. */ public static Quat4d relativeOrientation(Point3d[] fixed, Point3d[] moved) { Matrix m = CalcPoint.formMatrix(moved, fixed); // inverse EigenvalueDecomposition eig = m.eig(); double[][] v = eig.getV().getArray(); Quat4d q = new Quat4d(v[1][3], v[2][3], v[3][3], v[0][3]); q.normalize(); q.conjugate(); return q; } /** * Compute the dot (inner) product of two quaternions. * * @param q1 * quaternion as Quat4d object * @param q2 * quaternion as Quat4d object * @return the value of the quaternion dot product */ public static double dotProduct(Quat4d q1, Quat4d q2) { return q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy