Superpose.h
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
00086
00087
00088
00089
00090
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
00107 Mat<3,3> R(0.0);
00108 Real E0 = 0.0;
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
00120
00121
00122
00123
00124
00125 Vector_<std::complex<double> > mu0;
00126 Matrix_<std::complex<double> > a0;
00127 Eigen eigen( Matrix( R.transpose() * R ) );
00128 eigen.getAllEigenValuesAndVectors(mu0, a0);
00129
00130
00131 Vec3 a1[3];
00132 Real mu1[3];
00133 for (int i = 0; i < 3; ++i) {
00134 mu1[i] = mu0[i].real();
00135 for (int j = 0; j < 3; ++j)
00136
00137 a1[j][i] = a0[i][j].real();
00138 }
00139
00140
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;
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];
00160 Vec3 a[3];
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]);
00167
00168
00169
00170
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
00181
00182
00183 Mat<3,3> U(0.0);
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
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
00192
00193 Real variance = 0.0;
00194 if (totalMass > 0)
00195 variance = std::sqrt(2 * residualError / totalMass);
00196
00197 Rotation rotation(U);
00198
00199
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 }
00212
00213 #endif // MOLMODEL_SUPERPOSE_H_