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 */ 021 022package org.biojava.nbio.structure.symmetry.geometry; 023 024import org.biojava.nbio.structure.jama.EigenvalueDecomposition; 025import org.biojava.nbio.structure.jama.Matrix; 026 027import javax.vecmath.*; 028 029/** 030 * 031 * @author Peter 032 */ 033public final class SuperPosition { 034 035 public static Matrix4d superpose(Point3d[] x, Point3d[] y) { 036 //superpose x onto y 037 Point3d[] ref = clonePoint3dArray(y); 038 039 Point3d ytrans = centroid(ref); 040 ytrans.negate(); 041 translate(ytrans, ref); 042 043 center(x); 044 045 // calculate quaternion from relative orientation 046 Quat4d q = quaternionOrientation(x, ref); 047 048 Matrix4d rotTrans = new Matrix4d(); 049 rotTrans.set(q); 050 051 // set translational component of transformation matrix 052 ytrans.negate(); 053 rotTrans.setTranslation(new Vector3d(ytrans)); 054 055 // tranform coordinates 056 transform(rotTrans, x); 057 058 // TODO should include translation into transformation matrix 059 060 return rotTrans; 061 } 062 063 public static Matrix4d superposeWithTranslation(Point3d[] x, Point3d[] y) { 064 //superpose x onto y 065 066 // translate to origin 067 Point3d[] xref = clonePoint3dArray(x); 068 Point3d xtrans = centroid(xref); 069 xtrans.negate(); 070 translate(xtrans, xref); 071 072 Point3d[] yref = clonePoint3dArray(y); 073 Point3d ytrans = centroid(yref); 074 ytrans.negate(); 075 translate(ytrans, yref); 076 077 // calculate rotational component (rotation around origin) 078 Quat4d q = quaternionOrientation(xref, yref); 079 Matrix4d rotTrans = new Matrix4d(); 080 rotTrans.set(q); 081 082 // combine with x -> origin translation 083 Matrix4d trans = new Matrix4d(); 084 trans.setIdentity(); 085 trans.setTranslation(new Vector3d(xtrans)); 086 rotTrans.mul(rotTrans, trans); 087 088 // combine with origin -> y translation 089 ytrans.negate(); 090 Matrix4d transInverse = new Matrix4d(); 091 transInverse.setIdentity(); 092 transInverse.setTranslation(new Vector3d(ytrans)); 093 rotTrans.mul(transInverse, rotTrans); 094 095 // transform x coordinates onto y coordinate frame 096 transform(rotTrans, x); 097 098 return rotTrans; 099 } 100 101 public static Matrix4d superposeAtOrigin(Point3d[] x, Point3d[] y) { 102 Quat4d q = quaternionOrientation(x, y); 103 104 Matrix4d rotTrans = new Matrix4d(); 105 rotTrans.set(q); 106 107 return rotTrans; 108 } 109 110 public static Matrix4d superposeAtOrigin(Point3d[] x, Point3d[] y, AxisAngle4d axisAngle) { 111 Quat4d q = quaternionOrientation(x, y); 112 Matrix4d rotTrans = new Matrix4d(); 113 rotTrans.setIdentity(); 114 rotTrans.set(q); 115 axisAngle.set(q); 116 Vector3d axis = new Vector3d(axisAngle.x, axisAngle.y, axisAngle.z); 117 if (axis.lengthSquared() < 1.0E-6) { 118// System.err.println("Error: SuperPosition.superposeAtOrigin: axis vector undefined!"); 119 axisAngle.x = 0; 120 axisAngle.y = 0; 121 axisAngle.z = 1; 122 axisAngle.angle = 0; 123 } else { 124 axis.normalize(); 125 axisAngle.x = axis.x; 126 axisAngle.y = axis.y; 127 axisAngle.z = axis.z; 128 } 129 transform(rotTrans, x); 130// System.out.println("SuperPosition.superposeAtOrigin: rotTrans"); 131// System.out.println(rotTrans); 132// Matrix4d temp = new Matrix4d(); 133// temp.setIdentity(); 134// temp.set(axisAngle); 135// System.out.println("SuperPosition.superposeAtOrigin: from axisAngle"); 136// System.out.println(temp); 137 return rotTrans; 138 } 139 140 141 142 143 public static double rmsd(Point3d[] x, Point3d[] y) { 144 double sum = 0.0; 145 for (int i = 0; i < x.length; i++) { 146 sum += x[i].distanceSquared(y[i]); 147 } 148 return Math.sqrt(sum/x.length); 149 } 150 151 public static double rmsdMin(Point3d[] x, Point3d[] y) { 152 double sum = 0.0; 153 for (int i = 0; i < x.length; i++) { 154 double minDist = Double.MAX_VALUE; 155 for (int j = 0; j < y.length; j++) { 156 minDist = Math.min(minDist, x[i].distanceSquared(y[j])); 157 } 158 sum += minDist; 159 } 160 return Math.sqrt(sum/x.length); 161 } 162 163 /** 164 * Returns the TM-Score for two superimposed sets of coordinates 165 * Yang Zhang and Jeffrey Skolnick, PROTEINS: Structure, Function, and Bioinformatics 57:702–710 (2004) 166 * @param x coordinate set 1 167 * @param y coordinate set 2 168 * @param lengthNative total length of native sequence 169 * @return 170 */ 171 public static double TMScore(Point3d[] x, Point3d[] y, int lengthNative) { 172 double d0 = 1.24 * Math.cbrt(x.length - 15.0) - 1.8; 173 double d0Sq = d0*d0; 174 175 double sum = 0; 176 for(int i = 0; i < x.length; i++) { 177 sum += 1.0/(1.0 + x[i].distanceSquared(y[i])/d0Sq); 178 } 179 180 return sum/lengthNative; 181 } 182 183 public static double GTSlikeScore(Point3d[] x, Point3d[] y) { 184 int contacts = 0; 185 186 for (Point3d px: x) { 187 double minDist = Double.MAX_VALUE; 188 189 for (Point3d py: y) { 190 minDist = Math.min(minDist, px.distanceSquared(py)); 191 } 192 193 if (minDist > 64) continue; 194 contacts++; 195 196 if (minDist > 16) continue; 197 contacts++; 198 199 if (minDist > 4) continue; 200 contacts++; 201 202 if (minDist > 1) continue; 203 contacts++; 204 } 205 206 return contacts*25.0/x.length; 207 } 208 209 public static int contacts(Point3d[] x, Point3d[] y, double maxDistance) { 210 int contacts = 0; 211 for (int i = 0; i < x.length; i++) { 212 double minDist = Double.MAX_VALUE; 213 for (int j = 0; j < y.length; j++) { 214 minDist = Math.min(minDist, x[i].distanceSquared(y[j])); 215 } 216 if (minDist < maxDistance*maxDistance) { 217 contacts++; 218 } 219 } 220 return contacts; 221 } 222 223 public static void transform(Matrix4d rotTrans, Point3d[] x) { 224 for (Point3d p: x) { 225 rotTrans.transform(p); 226 } 227 } 228 229 public static void translate(Point3d trans, Point3d[] x) { 230 for (Point3d p: x) { 231 p.add(trans); 232 } 233 } 234 235 public static void center(Point3d[] x) { 236 Point3d center = centroid(x); 237 center.negate(); 238 translate(center, x); 239 } 240 241 public static Point3d centroid(Point3d[] x) { 242 Point3d center = new Point3d(); 243 for (Point3d p: x) { 244 center.add(p); 245 } 246 center.scale(1.0/x.length); 247 return center; 248 } 249 250 private static Quat4d quaternionOrientation(Point3d[] a, Point3d[] b) { 251 Matrix m = calcFormMatrix(a, b); 252 EigenvalueDecomposition eig = m.eig(); 253 double[][] v = eig.getV().getArray(); 254 Quat4d q = new Quat4d(v[1][3], v[2][3], v[3][3], v[0][3]); 255 q.normalize(); 256 q.conjugate(); 257// System.out.println("SuperPosition.quaternionOrientation: " + q); 258 return q; 259 } 260 261 private static Matrix calcFormMatrix(Point3d[] a, Point3d[] b) { 262 double xx=0.0, xy=0.0, xz=0.0, yx=0.0, yy=0.0, yz=0.0, zx=0.0, zy=0.0, zz=0.0; 263 264 for (int i = 0; i < a.length; i++) { 265 xx += a[i].x * b[i].x; 266 xy += a[i].x * b[i].y; 267 xz += a[i].x * b[i].z; 268 yx += a[i].y * b[i].x; 269 yy += a[i].y * b[i].y; 270 yz += a[i].y * b[i].z; 271 zx += a[i].z * b[i].x; 272 zy += a[i].z * b[i].y; 273 zz += a[i].z * b[i].z; 274 } 275 276 double[][] f = new double[4][4]; 277 f[0][0] = xx + yy + zz; 278 f[0][1] = zy - yz; 279 f[1][0] = f[0][1]; 280 f[1][1] = xx - yy - zz; 281 f[0][2] = xz - zx; 282 f[2][0] = f[0][2]; 283 f[1][2] = xy + yx; 284 f[2][1] = f[1][2]; 285 f[2][2] = yy - zz - xx; 286 f[0][3] = yx - xy; 287 f[3][0] = f[0][3]; 288 f[1][3] = zx + xz; 289 f[3][1] = f[1][3]; 290 f[2][3] = yz + zy; 291 f[3][2] = f[2][3]; 292 f[3][3] = zz - xx - yy; 293 294 return new Matrix(f); 295 } 296 297 public static Point3d[] clonePoint3dArray(Point3d[] x) { 298 Point3d[] clone = new Point3d[x.length]; 299 for (int i = 0; i < x.length; i++) { 300 clone[i] = new Point3d(x[i]); 301 } 302 return clone; 303 } 304}