001/*
002 *                    BioJava development code
003 *
004 * This code may be freely distributed and modified under the
005 * terms of the GNU Lesser General Public Licence.  This should
006 * be distributed with the code.  If you do not have a copy,
007 * see:
008 *
009 *      http://www.gnu.org/copyleft/lesser.html
010 *
011 * Copyright for this code is held jointly by the individual
012 * authors.  These should be listed in @author doc comments.
013 *
014 * For more information on the BioJava project and its aims,
015 * or to join the biojava-l mailing list, visit the home page
016 * at:
017 *
018 *      http://www.biojava.org/
019 *
020 */
021package org.biojava.nbio.structure.geometry;
022
023import javax.vecmath.*;
024
025/**
026 * The SuperPositionQuat implements a quaternion based algorithm to superpose
027 * arrays of Points in 3D.
028 *
029 * @author Peter Rose
030 * @author Aleix Lafita
031 *
032 */
033public final class SuperPositionQuat extends SuperPositionAbstract {
034
035        /**
036         * Constructor for the quaternion based superposition algorithm.
037         *
038         * @param centered
039         *            true if the point arrays are centered at the origin (faster),
040         *            false otherwise
041         */
042        public SuperPositionQuat(boolean centered) {
043                super(centered);
044        }
045
046        @Override
047        public Matrix4d superpose(Point3d[] fixed, Point3d[] moved) {
048
049                checkInput(fixed, moved);
050
051                if (centered) {
052                        Quat4d q = UnitQuaternions.relativeOrientation(fixed, moved);
053                        Matrix4d rotTrans = new Matrix4d();
054                        rotTrans.set(q);
055                        return rotTrans;
056                }
057
058                // translate to origin
059                Point3d[] xref = CalcPoint.clonePoint3dArray(fixed);
060                Point3d xtrans = CalcPoint.centroid(xref);
061                xtrans.negate();
062                CalcPoint.translate(new Vector3d(xtrans), xref);
063
064                Point3d[] yref = CalcPoint.clonePoint3dArray(moved);
065                Point3d ytrans = CalcPoint.centroid(yref);
066                ytrans.negate();
067                CalcPoint.translate(new Vector3d(ytrans), yref);
068
069                // calculate rotational component (rotation around origin)
070                Quat4d q = UnitQuaternions.relativeOrientation(xref, yref);
071                Matrix4d rotTrans = new Matrix4d();
072                rotTrans.set(q);
073
074                // combine with moved -> origin translation
075                Matrix4d trans = new Matrix4d();
076                trans.setIdentity();
077                trans.setTranslation(new Vector3d(ytrans));
078                rotTrans.mul(rotTrans, trans);
079
080                // combine with origin -> fixed translation
081                xtrans.negate();
082                Matrix4d transInverse = new Matrix4d();
083                transInverse.setIdentity();
084                transInverse.setTranslation(new Vector3d(xtrans));
085                rotTrans.mul(transInverse, rotTrans);
086
087                return rotTrans;
088
089        }
090
091        @Override
092        public double getRmsd(Point3d[] x, Point3d[] y) {
093                Point3d[] yclone = CalcPoint.clonePoint3dArray(y);
094                superposeAndTransform(x, yclone);
095                return CalcPoint.rmsd(x, yclone);
096        }
097
098}