Superpose.h

Go to the documentation of this file.
00001 /* -------------------------------------------------------------------------- *
00002  *                      SimTK Core: SimTK Molmodel                            *
00003  * -------------------------------------------------------------------------- *
00004  * This is part of the SimTK Core biosimulation toolkit originating from      *
00005  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00006  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00007  * Medical Research, grant U54 GM072970. See https://simtk.org.               *
00008  *                                                                            *
00009  * Portions copyright (c) 2008 Stanford University and the Authors.           *
00010  * Authors: Christopher Bruns                                                 *
00011  * Contributors:                                                              *
00012  *                                                                            *
00013  * Permission is hereby granted, free of charge, to any person obtaining a    *
00014  * copy of this software and associated documentation files (the "Software"), *
00015  * to deal in the Software without restriction, including without limitation  *
00016  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
00017  * and/or sell copies of the Software, and to permit persons to whom the      *
00018  * Software is furnished to do so, subject to the following conditions:       *
00019  *                                                                            *
00020  * The above copyright notice and this permission notice shall be included in *
00021  * all copies or substantial portions of the Software.                        *
00022  *                                                                            *
00023  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
00024  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
00025  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
00026  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
00027  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
00028  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
00029  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
00030  * -------------------------------------------------------------------------- */
00031 
00032 
00038 #ifndef MOLMODEL_SUPERPOSE_H_
00039 #define MOLMODEL_SUPERPOSE_H_
00040 
00041 #include "SimTKmath.h"
00042 #include <vector>
00043 
00044 namespace SimTK {
00045 
00047 class Vec3Pair 
00048 {
00049 public:
00050     Vec3Pair(const Vec3& s, const Vec3& t, Real w = 1.0)
00051         : source(s), target(t), weight(w) {}
00052 
00053     const Vec3& getSource() const {return source;}
00054     const Vec3& getTarget() const {return target;}
00055     Real getWeight() const {return weight;}
00056 
00057 private:
00058     Vec3 source;
00059     Vec3 target;
00060     Real weight;
00061 };
00062 
00063 class TransformAndResidual {
00064 public:
00065     TransformAndResidual(const Transform& t, Real r)
00066         : transform(t), residual(r) {}
00067 
00068     Transform transform;
00069     Real residual;
00070 };
00071 
00072 class SimTK_MOLMODEL_EXPORT Kabsch78 {
00073 public:
00074     typedef std::vector<Vec3Pair> VectorSet ;
00075 
00083     static TransformAndResidual superpose(const VectorSet& vectors) 
00084     {
00085         // a) Remove any translation between the two given
00086         // vector sets x(n) and y(n), and determine
00087         // E0 = 1/2 SUM[ w(n)*(x(n)^2 + y(n)^2) ]
00088         // and R, r(ij) = SUM(n)[ w(n)*y(ni)*x(nj) ]
00089 
00090         // 1) Identify center of mass of each set of vectors
00091         Real totalMass = 0.0;
00092         Vec3 sourceCentroid(0.0, 0.0, 0.0);
00093         Vec3 targetCentroid(0.0, 0.0, 0.0);
00094         VectorSet::const_iterator vI;
00095         for (vI = vectors.begin(); vI != vectors.end(); ++vI)
00096         {
00097             totalMass += vI->getWeight();
00098             sourceCentroid += vI->getWeight() * vI->getSource();
00099             targetCentroid += vI->getWeight() * vI->getTarget();
00100         }
00101         if (totalMass != 0.0) {
00102             sourceCentroid /= totalMass;
00103             targetCentroid /= totalMass;
00104         }
00105 
00106         // Form R matrix from Kabsch paper
00107         Mat<3,3> R(0.0);
00108         Real E0 = 0.0; // Initial residual, see Kabsch
00109         for (vI = vectors.begin(); vI != vectors.end(); ++vI)
00110         {
00111             Vec3 x = vI->getSource() - sourceCentroid;
00112             Vec3 y = vI->getTarget() - targetCentroid;
00113             E0 += 0.5 * vI->getWeight() * ( dot(x, x) + dot(y, y) );
00114             for (int i = 0; i < 3; ++i)
00115                 for (int j = 0; j < 3; ++j)
00116                       R[i][j] += vI->getWeight() * y[i] * x[j];
00117         }
00118 
00119         // b) Form ~RR, determine eigenvalues mu(k) and the
00120         // mutually orthogonal eigenvectors a(k) and
00121         //    sort so that mu1 >= mu2 >= mu3.
00122         // Set
00123         //    a3 == a1 cross a2
00124         // to be sure to have a right handed system
00125         Vector_<std::complex<double> > mu0; // eigenvalues, complex, unsorted
00126         Matrix_<std::complex<double> > a0; // eigenvectors, complex, unsorted
00127         Eigen eigen( Matrix( R.transpose() * R ) );
00128         eigen.getAllEigenValuesAndVectors(mu0, a0);
00129 
00130         // use only real component of results
00131         Vec3 a1[3]; // eigenvectors, real, unsorted
00132         Real mu1[3]; // eigenvalues, real, unsorted
00133         for (int i = 0; i < 3; ++i) {
00134             mu1[i] = mu0[i].real();
00135             for (int j = 0; j < 3; ++j) 
00136                 // Note swapping of indices: It appears that the columns of a0 are eigenvectors
00137                 a1[j][i] = a0[i][j].real();
00138         }
00139 
00140         // sort indices of eigenvalues, from largest eigenvalue to smallest
00141         int indMax(0);
00142         int indMin(0);
00143         for (int i = 0; i < 3; ++i) {
00144             if ( mu1[i] > mu1[indMax] ) {
00145                 indMax = i;
00146             }
00147             if ( mu1[i] <= mu1[indMin] ) {
00148                 indMin = i;
00149             }
00150         }
00151         assert (indMin != indMax);
00152         int indMid = 3 - indMax - indMin; // too clever...
00153         assert(indMid >= 0);
00154         assert(indMid <= 2);
00155         assert(indMid != indMax);
00156         assert(indMid != indMin);
00157         int indSort[3] = {indMax, indMid, indMin};
00158 
00159         Real mu[3]; // eigenvalues, sorted
00160         Vec3 a[3]; // eigenvectors, sorted
00161         for (int i = 0; i < 3; ++i) {
00162             mu[i] = mu1[indSort[i]];
00163             a[i] = Vec3(UnitVec3(a1[indSort[i]]));
00164         }
00165 
00166         a[2] = cross(a[0], a[1]); // force right handed system
00167         
00168         // c) Determine Ra(k) (k = 1,2,3), normalize the first
00169         // two vectors to obtain b1, b2, and set b3 == b1 cross b2.
00170         // This will also take care of the case mu2 > mu3 = 0.
00171         Real sigma[] = {1.0, 1.0, 1.0};
00172         Vec3 b[3];
00173         b[0] = Vec3(UnitVec3(R * a[0]));
00174         b[1] = Vec3(UnitVec3(R * a[1]));
00175         b[2] = cross(b[0], b[1]);
00176 
00177         if ( dot(b[2], R * a[2]) < 0 )
00178             sigma[2] = -1.0;
00179 
00180         // d) Form U according to eq. 7:
00181         // u(ij) = SUM(k)[ b(ki)a(kj) ]
00182         // where b(k) = R*a(k)/(sigma(k)sqrt(mu(k)))
00183         Mat<3,3> U(0.0);   // initialize 2-d array
00184         for (int i = 0; i < 3; ++i)
00185             for (int j = 0; j < 3; ++j)
00186                 for (int k = 0; k < 3; ++k)
00187                     U[i][j] += b[k][i] * a[k][j];
00188         
00189         // Compute residual error
00190         Real residualError = E0 - sigma[0] * std::sqrt(mu[0]) - sigma[1] * std::sqrt(mu[1]) - sigma[2] * std::sqrt(std::abs(mu[2]));
00191         // E = 1/2 SUM(over n)[w(n)*(Ux(n) - y(n))^2]
00192         // variance would be sqrt( 1/SUM(w(n)) * SUM(w(n)*(Ux(n) - y(n))^2) )
00193         Real variance = 0.0;
00194         if (totalMass > 0)
00195             variance = std::sqrt(2 * residualError / totalMass);
00196 
00197         Rotation rotation(U);
00198 
00199         // No rotation for single point overlay
00200         if (vectors.size() < 2)
00201             rotation = Rotation();
00202 
00203         Transform transform1(-sourceCentroid);
00204         Transform transform2(rotation);
00205         Transform transform3(targetCentroid);
00206 
00207         return TransformAndResidual(transform3 * transform2 * transform1, variance);
00208     }
00209 };
00210 
00211 } // namespace SimTK
00212 
00213 #endif // MOLMODEL_SUPERPOSE_H_

Generated on Wed Dec 30 11:04:54 2009 for SimTKcore by  doxygen 1.6.1