Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

DrawRingsUtils.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2008 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: DrawRingsUtils.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.16 $       $Date: 2008/08/14 21:22:48 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * Ulities for calculating ring axes, ring puckering and displacement of
00020  * atoms from the mean ring plane.
00021  *
00022  ***************************************************************************/
00023 
00024 #include <math.h>
00025 #include "utilities.h"
00026 #include "AtomColor.h"
00027 #include "Scene.h"
00028 #include "DrawRingsUtils.h"
00029 
00030 /*
00031  * Hill-Reilly pucker-paramter based coloring
00032  */
00033 
00034 void hotcold_gradient(float pucker_sum, float *rgb) {
00035   vec_zero(rgb); // set default color to black
00036 
00037   // hot to cold color map
00038   // Red (1, 0, 0) -> Yellow (1, 1, 0) -> Green (0, 1, 0) -> Cyan (0, 1, 1) -> blue (0, 0, 1)
00039   if (pucker_sum < 0.25) {
00040     rgb[0] = 1.0;
00041     rgb[1] = pucker_sum * 4.0;
00042     rgb[2] = 0.0;
00043   } else if (pucker_sum < 0.5) {
00044     rgb[0] = 1.0 - (pucker_sum - 0.25) * 4.0;
00045     rgb[1] = 1.0;
00046     rgb[2] = 0.0;
00047   } else if (pucker_sum < 0.75) {
00048     rgb[0] = 0.0;
00049     rgb[1] = 1.0;
00050     rgb[2] = (pucker_sum - 0.5) * 4.0;
00051   } else {
00052     rgb[0] = 0.0;
00053     rgb[1] = 1.0 - (pucker_sum - 0.75) * 4.0;
00054     rgb[2] = 1.0;
00055   }
00056 
00057   clamp_color(rgb); // clamp color values to legal range
00058 }
00059 
00060 
00061 float hill_reilly_ring_pucker(SmallRing &ring, float *framepos) {
00062   int N = ring.num(); // the number of atoms in the current ring
00063 
00064   // return the default color if this isn't a 5 or 6 ring atom
00065   if (N != 5 && N != 6)
00066     return 0.0;
00067 
00068   int NP = N-3; // number of puckering parameters
00069   float *X = new float[N*3]; // atom co-ordinates
00070   float *r = new float[N*3]; // bond vectors
00071   float *a = new float[NP*3]; // puckering axes
00072   float *q = new float[NP*3]; // normalized puckering vectors
00073   float *n = new float[3]; // normal to reference plane
00074   float *p = new float[3]; // a flap normal
00075   float *theta = new float[NP]; // puckering parameters
00076   float pucker_sum;
00077   float max_pucker_sum;
00078   float *atompos;
00079   int curatomid, i, j, k, l;
00080 
00081   // load ring co-ordinates
00082   for (i=0; i<N; i++) {
00083     curatomid = ring[i];
00084     atompos = framepos + 3*curatomid;
00085     X[3*i] = atompos[0];
00086     X[3*i+1] = atompos[1];
00087     X[3*i+2] = atompos[2];
00088   }     
00089 
00090   // calculate bond vectors
00091   for (i=0; i<N; i++) {
00092     j = (i+1) % N;
00093     vec_sub(r+3*i,X+3*j,X+3*i);
00094   }
00095 
00096   // calculate puckering axes, flap normals and puckering vectors
00097   for (i=0; i<NP; i++) {
00098     k = (2*(i+1)) % N;
00099     j = (2*i) % N;
00100     l = (2*i+1) % N;
00101     vec_sub(a+3*i,X+3*k,X+3*j);
00102     cross_prod(p,r+3*j,r+3*l);
00103     cross_prod(q+3*i,a+3*i,p);
00104     vec_normalize(q+3*i);
00105   }
00106 
00107   // reference normal
00108   cross_prod(n,a+3*0,a+3*1);
00109   vec_normalize(n);
00110 
00111   // calculate the puckering parameters
00112   pucker_sum = 0.0;
00113   for (i=0; i<NP; i++) {
00114     theta[i] = (VMD_PI/2.0) - acos(dot_prod(q+3*i,n));
00115     pucker_sum += theta[i];
00116   }
00117 
00118   // 0.6154 radians (35.26 degrees) has significance for perfect tetrahedral bond geometry (see Hill paper)
00119   max_pucker_sum = NP * 0.6154;
00120   pucker_sum = fabs(pucker_sum)/max_pucker_sum;
00121   pucker_sum = (pucker_sum < 1.0f) ? pucker_sum : 1.0f;
00122  
00123   delete [] X;
00124   delete [] r;
00125   delete [] a;
00126   delete [] q;
00127   delete [] n;
00128   delete [] p;
00129   delete [] theta;
00130 
00131   return pucker_sum;
00132 }
00133 
00134 
00135 // Calculate Hill-Reilly Pucker Parameters and convert these to a ring colour
00136 void hill_reilly_ring_color(SmallRing &ring, float *framepos, float *rgb) {
00137   float pucker_sum = hill_reilly_ring_pucker(ring, framepos); 
00138   hotcold_gradient(pucker_sum, rgb);
00139 }
00140 
00141 void hill_reilly_ring_colorscale(SmallRing &ring, float *framepos, float vmin, float vmax, const Scene *scene, float *rgb) {
00142   float pucker_sum = hill_reilly_ring_pucker(ring, framepos); 
00143 
00144   // map data min/max to range 0->1
00145   // values must be clamped before use, since user-specified
00146   // min/max can cause out-of-range color indices to be generated
00147   float vscale;
00148   float vrange = vmax - vmin;
00149   if (fabs(vrange) < 0.00001)
00150     vscale = 0.0f;
00151   else
00152     vscale = 1.00001f / vrange;
00153 
00154   float level = (pucker_sum - vmin) * vscale;
00155   int colindex = (int)(level * MAPCLRS-1);
00156   if (colindex < 0)
00157     colindex = 0;
00158   else if (colindex >= MAPCLRS)
00159     colindex = MAPCLRS-1;
00160  
00161   const float *scrgb = scene->color_value(MAPCOLOR(colindex));
00162   
00163   rgb[0] = scrgb[0];
00164   rgb[1] = scrgb[1];
00165   rgb[2] = scrgb[2];
00166 }
00167 
00168 
00169 
00170 /*
00171  * Cremer-Pople pucker-parameter based coloring
00172  */
00173 
00174 // return sum + (x,y,z)
00175 void vec_incr(float sum[3], const float x, const float y, const float z) {
00176   sum[0] += x;
00177   sum[1] += y;
00178   sum[2] += z;
00179 }
00180 
00181 // Calculates cartesian axes based on coords of nuclei in ring
00182 // using cremer-pople algorithm. It is assumed that the
00183 // centre of geometry is the centre of the ring.
00184 void ring_axes(const float * X, const float * Y, const float * Z, int N, 
00185              float x[3], float y[3], float z[3]) {
00186   float Rp[3] = {0.0, 0.0, 0.0}; float Rpp[3] = {0.0, 0.0, 0.0};
00187   int j;
00188   for (j=0; j<N; j++) {
00189     float ze_angle = 2.0 * VMD_PI * float(j-1) / float(N);
00190     float ze_sin = sin(ze_angle);
00191     float ze_cos = cos(ze_angle);
00192     vec_incr( Rp, X[j]*ze_sin, Y[j]*ze_sin, Z[j]*ze_sin );
00193     vec_incr( Rpp, X[j]*ze_cos, Y[j]*ze_cos, Z[j]*ze_cos );
00194   }
00195 
00196   cross_prod(z, Rp, Rpp);
00197   vec_normalize(z);
00198 
00199   /* 
00200    * OK, now we have z, the norm to the central plane, we need
00201    * to calculate y as the projection of Rp onto the plane
00202    * and x as y x z
00203    */
00204   float lambda = dot_prod(z, Rp);
00205   y[0] = Rp[0] - z[0]*lambda;
00206   y[1] = Rp[1] - z[1]*lambda;
00207   y[2] = Rp[2] - z[2]*lambda;
00208   vec_normalize(y);
00209   cross_prod(x, y, z);    // voila !
00210 }
00211 
00212 
00213 // Calculate distances of atoms from the mean ring plane
00214 void atom_displ_from_mean_plane(float * X, float * Y, float * Z, 
00215                                 float * displ, int N) {
00216   float cog[3] = {0.0, 0.0, 0.0};
00217   float x_axis[3], y_axis[3], z_axis[3];
00218   int i;
00219 
00220   // calculate centre of geometry
00221   for (i=0; i<N; i++) {
00222       cog[0] += X[i]; cog[1] += Y[i]; cog[2] += Z[i];
00223   }
00224   cog[0] /= float(N); 
00225   cog[1] /= float(N); 
00226   cog[2] /= float(N); 
00227 
00228   // centre the ring
00229   for (i=0; i<N; i++) {
00230     X[i] -= cog[0]; 
00231     Y[i] -= cog[1]; 
00232     Z[i] -= cog[2];
00233   }
00234 
00235   ring_axes( X, Y, Z, N, x_axis, y_axis, z_axis );
00236 
00237   // calculate displacement from mean plane
00238   for (i=0; i<N; i++) {
00239     displ[i] = X[i]*z_axis[0] + Y[i]*z_axis[1] + Z[i]*z_axis[2];
00240   }
00241 }
00242 
00243 
00244 // Calculate Cremer-Pople puckering parameters
00245 int cremer_pople_params(int N_ring_atoms, float * displ, float * q, 
00246                                  float * phi, int  & m , float & Q) {
00247   int i, j, k;
00248   if (N_ring_atoms<3)
00249     return -1;
00250 
00251   float N = float(N_ring_atoms);
00252   phi[0]=0;  q[0]=0;  //no puckering parameters for m=1
00253 
00254   // if even no ring atoms, first calculate unpaired q puck parameter
00255   if (fmod(N, 2.0f)==0) {
00256     float sum =0;
00257     m = N_ring_atoms/2 -1;
00258 
00259     for (i=0; i<N_ring_atoms; i++)         
00260       sum += displ[i]*cos(i*VMD_PI);
00261 
00262     q[int(N_ring_atoms/2)-1]=sqrt(1.0/N)*sum;
00263   } else {
00264     m = int(N_ring_atoms-1)/2;
00265   }
00266 
00267   // calculate paired puckering parameters
00268   for (i=1; i<m; i++) {
00269     float q_cosphi=0, q_sinphi=0;
00270     for (j=0; j<N_ring_atoms; j++) {
00271       q_cosphi += displ[j]*cos(2.0*VMD_PI*float((i+1)*j)/N);
00272       q_sinphi += displ[j]*sin(2.0*VMD_PI*float((i+1)*j)/N);
00273     }
00274 
00275     q_cosphi *=  sqrt(2.0/N);
00276     q_sinphi *= -sqrt(2.0/N);
00277     phi[i]=atan(q_sinphi/q_cosphi);
00278 
00279     if (q_cosphi < 0)
00280       phi[i]+=VMD_PI;
00281     else if (q_sinphi < 0) 
00282       phi[i]+=2*VMD_PI;
00283 
00284     q[i]=q_cosphi/phi[i];
00285     //phi[i]*=180.0/VMD_PI;  //convert to degrees
00286 
00287     //calculate puckering amplitude
00288     Q=0.0;
00289     for (k=0; k<N_ring_atoms; k++)
00290       Q+=displ[k]*displ[k];
00291     Q=sqrt(Q);  
00292   }
00293 
00294   return 1;
00295 }
00296 
00297 
00298 // Calculate Cremer-Pople Pucker Parameters and convert these to a ring colour
00299 void cremer_pople_ring_color(SmallRing &ring, float *framepos, float *rgb) {
00300   int N = ring.num(); //the number of atoms in the current ring
00301   float *xring = new float[N];
00302   float *yring = new float[N];
00303   float *zring = new float[N];
00304   float *displ = new float[N];
00305   float *q = new float[N];
00306   float *phi = new float[N];
00307   float Q;
00308   int m;
00309   float *atompos;
00310   int curatomid;
00311 
00312   vec_zero(rgb); // set default color to black
00313 
00314   for (int i=0; i<N; i++) {
00315     curatomid = ring[i];
00316     atompos = framepos + 3*curatomid; // pointer arithmetic is evil :)
00317     xring[i] = atompos[0];
00318     yring[i] = atompos[1];
00319     zring[i] = atompos[2];
00320   }     
00321 
00322   atom_displ_from_mean_plane(xring, yring, zring, displ, N);
00323          
00324   if (N==6) { //special case - pyranose rings
00325     if (cremer_pople_params(N, displ, q, phi, m, Q)) {
00326       float cosTheta = q[2]/Q;
00327       float theta = acos(cosTheta); 
00328       float sinTheta = sin(theta);
00329 
00330       // Q is the puckering amplitude - i.e. the intensity of the pucker.
00331       // multiply by Q to show intensity, particularly for rings with 
00332       // little pucker (black)
00333       // NOTE -using abs - polar positions therefore equivalent
00334       float intensity = Q;
00335       
00336       rgb[0] = fabs(sinTheta)*intensity;
00337       rgb[1] = fabs(cosTheta)*intensity;
00338       rgb[2] = fabs(sin(3*phi[1])*sinTheta)*intensity;
00339     }
00340   } else if (N==5) { //special case - furanose rings
00341     if (cremer_pople_params(N, displ, q, phi, m, Q)) {
00342       rgb[0] = 0;
00343       rgb[1] = 0;
00344       rgb[2] = Q;
00345     }
00346   }
00347 
00348   // clamp color values to legal range
00349   clamp_color(rgb);
00350  
00351   delete [] xring;
00352   delete [] yring;
00353   delete [] zring;
00354   delete [] displ;
00355   delete [] q;
00356   delete [] phi;
00357 }
00358 
00359 
00360 /*
00361  * Ribbon spline handling
00362  */
00363 // Calculates the position at point t along the spline with co-efficients
00364 // A, B, C and D.
00365 // spline(t) = ((A * t + B) * t + C) * t + D
00366 void ribbon_spline(float *pos, const float * const A, const float * const B,
00367                                const float * const C, const float * const D, const float t) {
00368   vec_copy(pos,D);
00369   vec_scaled_add(pos,t,C);
00370   vec_scaled_add(pos,t*t,B);
00371   vec_scaled_add(pos,t*t*t,A);
00372 }
00373 
00374 
00375 
00376 

Generated on Sun Sep 7 01:25:50 2008 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002