#include // for form() - no longer #include // for sqrt() #include "Pointlist.h" #include "Quaternion.h" // define DEBUG_EIGEN if you want debugging trace // #define DEBUG_EIGEN 1 static void Compute_SOP(double Array[4][4], const Pointlist &A, const Pointlist &B, const float * weight) { register double Sxx=0, Sxy=0, Sxz=0, Syx=0, Syy=0, Syz=0, Szx=0, Szy=0, Szz=0; // entries of the 4x4 symmetric N-matrix assert(A.num_points() == B.num_points()); int num = A.num_points(); assert (num>0); if (!weight) { for(int i=0;i(diff + 100*mat_pq) == static_cast(diff)) { t = mat_pq/diff; } else { double cotangent = diff/(2*mat_pq); t = cotangent>0? 1/(cotangent + sqrt(1+cotangent*cotangent)) : 1/(cotangent - sqrt(1+cotangent*cotangent)); } // get sine and cosine of rotation from tangent double c = 1.0/sqrt(1. + t*t); double s = c*t; // compute tangent of half-angle double tau = s/(1.0+c); // compute diagonal correction double qplus = t*mat[p][q]; // update matrix[i][j] for i<=j mat[p][q] = 0; mat[p][p] -= qplus; mat[q][q] += qplus; for (int i=0; i=MAX_ITER) { cerr << "Warning: eigen4 may not have converged\n"; } // select vector for most positive eigenvalue int maxat=0; double biggest=mat[0][0]; for (int i=1; i<4; i++) { double diag = mat[i][i]; if (diag > biggest) { biggest=diag; maxat = i; } } vect[0] = vectors[0][maxat]; vect[1] = vectors[1][maxat]; vect[2] = vectors[2][maxat]; vect[3] = vectors[3][maxat]; normalize(vect); #ifdef DEBUG_EIGEN cerr << form("%3d %9g\t: %7.4f %7.4f %7.4f %7.4f\n", iter, mat[maxat][maxat], vect[0], vect[1], vect[2], vect[3]) << flush; // print normalized orig_mat*vect, to verify eigen property double prod[4]; for (int i=0; i<4; i++) { double sum=0; for (int j=0; j<4; j++) { sum += orig_mat[i][j]*vect[j]; } prod[i] = sum; } normalize(prod); cerr << form("product \t: %7.4f %7.4f %7.4f %7.4f\n", prod[0], prod[1], prod[2], prod[3]) << flush; #endif } Quaternion Optimal_rotation(const Pointlist &A, const Pointlist &B, const float * weight) { if (A.num_points() ==0) { Quaternion Q(1.0,0.0,0.0,0.0); // null rotation ok for 0 points return Q; } double mat[4][4]; double eigvector[4]; Compute_SOP(mat,A,B,weight); eigen4(mat, eigvector); return static_cast(eigvector); } // CHANGE LOG: // 15 March 2004 Kevin Karplus // Fixed old-style casts // Fri Sep 8 06:18:10 PDT 2006 Kevin Karplus // redid matrix copy as 16 assignments, rather than using reinterpret_cast // Tue Jan 2 11:32:55 PST 2007 Kevin Karplus // Added minor speedup (if wt==0) in Compute_SOP // Mon Apr 27 17:39:04 PDT 2009 Kevin Karplus // Added is_finite assertions for points in Compute_SOP