/* * This program is for 3D superposition of sets of coordinates. * It is based on the quaternions, as proposed by: * Zuker & Somorjai, Bulletin of Mathematical Biology, * vol. 51, No 1, p 55-78, 1989. * * The search for the largest eigen value is based on a QR, and not * on the Jacobian based solvation approach used by most programmers. * * In our experience, the routine is very robust. * * If you use this program standalone, the call should be on the form: * QBestFit <-bfxyz, -bfpdb> < crdfile.xyz > fitcrd.xyz * * Input: * first line: N, the number of coordinates * following 2 x N lines: N coordinates (x y z, e.g. "0.134 2.345 12.3245", i.e. no commas) * the first N xyz lines will be the template, the last N xyz lines will * undergo the best fit transformation. * * Output: * first line: original rmsd, before fit. * second line : bestfit rmsd. * nextt 4 lines: the 4x4 transformation matrix * N following lines: the N coordinates transformed. * * If you want it directly, the main function is: * * zuker_superpose(DtPoint3 *c1, DtPoint3 *c2, int len, DtMatrix4x4 M) * * This program can be freely used, modified and distributed, given that this * header is maintained. * * If using this routine for publication, please cite F. Guyon and P. Tuffery. */ #include #include #include #define DtFloat double /* Le type flottant. */ typedef DtFloat DtPoint3[3]; typedef DtFloat DtPoint4[4]; typedef DtFloat DtMatrix3x3[3][3]; typedef DtFloat DtMatrix4x4[4][4]; #define boucle(i,min,max) for((i)=(min);(i)<(max);(i)++) #define max(a,b) (a=0.0 ? fabs(a) : -fabs(a)) #define EPS 1.e-10 double **alloc_mat(int n, int m) { int i; double **mat = (double **)calloc(m,sizeof(double *)); for (i=0; i=EPS) { for(i=k+1;i=0;i--) { sum=y[i]; for(j=i+1;jeps*fabs(l) && nitereps*fabs(l) && niter Y = XM (X vecteur ligne) ----------- ------------------------------------------------------------------ */ void MkTrnsIIMat4x4(DtMatrix4x4 m, DtPoint3 tr) { m[0][0] = 1.; m[0][1] = 0.; m[0][2] = 0.; m[0][3] = 0.; m[1][0] = 0.; m[1][1] = 1.; m[1][2] = 0.; m[1][3] = 0.; m[2][0] = 0.; m[2][1] = 0.; m[2][2] = 1.; m[2][3] = 0.; m[3][0] = tr[0]; m[3][1] = tr[1]; m[3][2] = tr[2]; m[3][3] = 1.; } /* Matrices 4 x 4 (a x b dans c) ------------------------------------ */ void mulMat4x4(DtMatrix4x4 a,DtMatrix4x4 b,DtMatrix4x4 c) { int i,j,k; boucle(i,0,4) { boucle(j,0,4) { c[i][j] = 0.; boucle(k,0,4) c[i][j] += a[i][k]*b[k][j]; } } } /* =============================================================== * ---------- Transformation d'une coordonnee par rmat. ---------- * =============================================================== */ void crdRotate(DtPoint3 p,DtMatrix4x4 rmat) { double x,y,z; x = p[0] * rmat[0][0] + p[1] * rmat[1][0] + p[2] * rmat[2][0] + rmat[3][0]; y = p[0] * rmat[0][1] + p[1] * rmat[1][1] + p[2] * rmat[2][1] + rmat[3][1]; z = p[0] * rmat[0][2] + p[1] * rmat[1][2] + p[2] * rmat[2][2] + rmat[3][2]; p[0] = x; p[1] = y; p[2] = z; } #define SQUARED_DISTANCE(K,R) ((K)[0] - (R)[0]) * ((K)[0] - (R)[0]) + ((K)[1] - (R)[1]) * ((K)[1] - (R)[1]) + ((K)[2] - (R)[2]) * ((K)[2] - (R)[2]) DtFloat squared_distance(DtPoint3 R,DtPoint3 K) { return (DtFloat) ((K[0] - R[0]) * (K[0] - R[0]) + (K[1] - R[1]) * (K[1] - R[1]) + (K[2] - R[2]) * (K[2] - R[2])); } /* * Best fit matrix as proposed by: * Zuker & Somorjai, Bulletin of Mathematical Biology, * vol. 51, No 1, p 55-78, 1989. * * c1, c2 two sets of coordinates to superpose. * len : the number of coordiantes of c1, c2. * * M, the 4x4 transforamtion matrix to pass from c2 to c2 superposed onto c1. * * Input: * c1, c2, and len must be given. * M should be passed, but is meaningless. * * Output: * c2 is superposed on c1. * M, a transformation matrix ready for use. * */ double zuker_superpose(DtPoint3 *c1, DtPoint3 *c2, int len, DtMatrix4x4 M) { DtMatrix3x3 C; DtMatrix3x3 *pC; DtMatrix4x4 RM; DtMatrix4x4 TM; DtMatrix4x4 TMP; DtMatrix4x4 TX; DtMatrix4x4 TY; DtMatrix4x4 P; DtMatrix4x4 Pd; DtPoint4 lambdas; DtPoint4 V; DtPoint3 bc1, bc2; DtPoint3 trx, try; double eval; double squared_rms = 0.; int nCycles; int aDot; /* Compute transformation matrix as proposed by zuker */ pC = &C; pC = XYCov(pC, (DtPoint3 *) c1, (DtPoint3 *) c2, bc1, bc2, len); P[0][0] = -C[0][0]+C[1][1]-C[2][2]; P[0][1] = P[1][0] = -C[0][1]-C[1][0]; P[0][2] = P[2][0] = -C[1][2]-C[2][1]; P[0][3] = P[3][0] = C[0][2]-C[2][0]; P[1][1] = C[0][0]-C[1][1]-C[2][2]; P[1][2] = P[2][1] = C[0][2]+C[2][0]; P[1][3] = P[3][1] = C[1][2]-C[2][1]; P[2][2] = -C[0][0]-C[1][1]+C[2][2]; P[2][3] = P[3][2] = C[0][1]-C[1][0]; P[3][3] = C[0][0]+C[1][1]+C[2][2]; #if 0 printMat4x4("zuker P", P); #endif nCycles = largestEV4(P, V, &eval); RM[0][0] = -V[0]*V[0]+V[1]*V[1]-V[2]*V[2]+V[3]*V[3]; RM[1][0] = 2*(V[2]*V[3]-V[0]*V[1]); RM[2][0] = 2*(V[1]*V[2]+V[0]*V[3]); RM[3][0] = 0.; RM[0][1] = -2*(V[0]*V[1]+V[2]*V[3]); RM[1][1] = V[0]*V[0]-V[1]*V[1]-V[2]*V[2]+V[3]*V[3]; RM[2][1] = 2*(V[1]*V[3]-V[0]*V[2]); RM[3][1] = 0.; RM[0][2] = 2*(V[1]*V[2]-V[0]*V[3]); RM[1][2] = -2*(V[0]*V[2]+V[1]*V[3]); RM[2][2] = -V[0]*V[0]-V[1]*V[1]+V[2]*V[2]+V[3]*V[3]; RM[3][2] = 0.; RM[0][3] = 0.; RM[1][3] = 0.; RM[2][3] = 0.; RM[3][3] = 1.; /* printMat4x4("zuker RM", RM); */ /* Solution eprouvee ! */ try[0] = - bc2[0]; try[1] = - bc2[1]; try[2] = - bc2[2]; MkTrnsIIMat4x4(TY, try); MkTrnsIIMat4x4(TX, bc1); mulMat4x4(TY,RM,TMP); mulMat4x4(TMP, TX, M); /* Now superpose the coordinates */ for (aDot=0;aDot