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

VolumetricData.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 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: VolumetricData.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.32 $       $Date: 2010/12/16 04:08:50 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * Base class for storing volumetric data and associated gradient data
00020  *
00021  ***************************************************************************/
00022 
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <math.h>
00026 #include <string.h>
00027 #include "VolumetricData.h"
00028 #include "Matrix4.h"
00029 #include "utilities.h"
00030   
00031 #ifndef NAN //not a number
00032   const float NAN = sqrtf(-1.f); //need some kind of portable NAN definition
00033 #endif
00034 
00036 VolumetricData::VolumetricData(const char *dataname, const float *o, 
00037                  const float *xa, const float *ya, const float *za,
00038                  int xs, int ys, int zs, float *dataptr) {
00039   name = stringdup(dataname);
00040   data = dataptr;
00041   xsize = xs;
00042   ysize = ys;
00043   zsize = zs;
00044 
00045   gradient = NULL;
00046   datamin = datamax = 0;
00047 
00048   for (int i=0; i<3; i++) {
00049     origin[i] = (double)o[i];
00050     xaxis[i] = (double)xa[i];
00051     yaxis[i] = (double)ya[i];
00052     zaxis[i] = (double)za[i];
00053   } 
00054 
00055   const int ndata = xsize*ysize*zsize;
00056   if (ndata > 0) {
00057     float min, max;
00058     min = max = data[0];
00059     for (int j=1; j<ndata; j++) {
00060       if (min > data[j]) min = data[j];
00061       if (max < data[j]) max = data[j];
00062     }
00063     datamin = min;
00064     datamax = max;
00065   }
00066 }
00067 
00068 
00070 VolumetricData::~VolumetricData() {
00071   delete [] name;
00072   delete [] data;
00073   delete [] gradient;
00074 }
00075 
00078 void VolumetricData::set_name(const char *newname) {
00079   if (name) delete[] name;
00080   name = new char[strlen(newname)+1];
00081   strcpy(name, newname);
00082 }
00083 
00084 
00086 void VolumetricData::cell_lengths(float *xl, float *yl, float *zl) const {
00087   float xsinv, ysinv, zsinv;
00088 
00089   // set scaling factors correctly
00090   if (xsize > 1)
00091     xsinv = 1.0f / (xsize - 1.0f);
00092   else
00093     xsinv = 1.0f;
00094 
00095   if (ysize > 1)
00096     ysinv = 1.0f / (ysize - 1.0f);
00097   else
00098     ysinv = 1.0f;
00099 
00100   if (zsize > 1)
00101     zsinv = 1.0f / (zsize - 1.0f);
00102   else
00103     zsinv = 1.0f;
00104 
00105   *xl = sqrtf(float(dot_prod(xaxis, xaxis))) * xsinv;
00106   *yl = sqrtf(float(dot_prod(yaxis, yaxis))) * ysinv;
00107   *zl = sqrtf(float(dot_prod(zaxis, zaxis))) * zsinv;
00108 }
00109 
00110 
00112 void VolumetricData::cell_axes(float *xax, float *yax, float *zax) const {
00113   float xsinv, ysinv, zsinv;
00114 
00115   // set scaling factors correctly
00116   if (xsize > 1)
00117     xsinv = 1.0f / (xsize - 1.0f);
00118   else
00119     xsinv = 1.0f;
00120 
00121   if (ysize > 1)
00122     ysinv = 1.0f / (ysize - 1.0f);
00123   else
00124     ysinv = 1.0f;
00125 
00126   if (zsize > 1)
00127     zsinv = 1.0f / (zsize - 1.0f);
00128   else
00129     zsinv = 1.0f;
00130 
00131   xax[0] = float(xaxis[0] * xsinv);
00132   xax[1] = float(xaxis[1] * xsinv);
00133   xax[2] = float(xaxis[2] * xsinv);
00134 
00135   yax[0] = float(yaxis[0] * ysinv);
00136   yax[1] = float(yaxis[1] * ysinv);
00137   yax[2] = float(yaxis[2] * ysinv);
00138 
00139   zax[0] = float(zaxis[0] * zsinv);
00140   zax[1] = float(zaxis[1] * zsinv);
00141   zax[2] = float(zaxis[2] * zsinv);
00142 }
00143 
00144 
00146 void VolumetricData::cell_dirs(float *xad, float *yad, float *zad) const {
00147   float xl, yl, zl;
00148 
00149   cell_lengths(&xl, &yl, &zl);
00150   cell_axes(xad, yad, zad);
00151 
00152   xad[0] /= xl;
00153   xad[1] /= xl;
00154   xad[2] /= xl;
00155 
00156   yad[0] /= yl;
00157   yad[1] /= yl;
00158   yad[2] /= yl;
00159 
00160   zad[0] /= zl;
00161   zad[1] /= zl;
00162   zad[2] /= zl;
00163 }
00164 
00165 
00168 void VolumetricData::voxel_coord_from_cartesian_coord(const float *carcoord, float *voxcoord, int shiftflag) const {
00169   float min_coord[3];
00170 
00171   if (shiftflag) {
00172     // shift coordinates by a half-voxel so that integer truncation works
00173     for (int i=0; i<3; i++) 
00174       min_coord[i] = (float) origin[i] - 0.5f*float(xaxis[i]/(xsize-1) + yaxis[i]/(ysize-1) + zaxis[i]/(zsize-1));
00175   } else {
00176     for (int i=0; i<3; i++)
00177       min_coord[i] = (float) origin[i];
00178   }
00179 
00180   //create transformation matrix...
00181   float matval[16];
00182   matval[0 ] = (float) xaxis[0]/(xsize-1);
00183   matval[1 ] = (float) yaxis[0]/(ysize-1);
00184   matval[2 ] = (float) zaxis[0]/(zsize-1);
00185   matval[3 ] = 0.f;
00186   matval[4 ] = (float) xaxis[1]/(xsize-1);
00187   matval[5 ] = (float) yaxis[1]/(ysize-1);
00188   matval[6 ] = (float) zaxis[1]/(zsize-1);
00189   matval[7 ] = 0.f;
00190   matval[8 ] = (float) xaxis[2]/(xsize-1);
00191   matval[9 ] = (float) yaxis[2]/(ysize-1);
00192   matval[10] = (float) zaxis[2]/(zsize-1);
00193   matval[11] = 0.f;
00194   matval[12] = (float) min_coord[0];
00195   matval[13] = (float) min_coord[1];
00196   matval[14] = (float) min_coord[2];
00197   matval[15] = 1.f;
00198   Matrix4 matrix(matval);
00199   matrix.inverse();
00200 
00201   matrix.multpoint3d(carcoord, voxcoord);
00202 }
00203 
00204 
00206 int VolumetricData::voxel_index_from_coord(float xpos, float ypos, float zpos) const {
00207   float realcoord[3];
00208   float gridpoint[3];
00209   realcoord[0] = xpos;
00210   realcoord[1] = ypos;
00211   realcoord[2] = zpos;
00212  
00213   // calculate grid coordinate, shifting by a half-voxel 
00214   voxel_coord_from_cartesian_coord(realcoord, gridpoint, 1);
00215   
00216   int gx = (int) gridpoint[0]; 
00217   int gy = (int) gridpoint[1];
00218   int gz = (int) gridpoint[2];
00219   if (gx < 0 || gx >= xsize) return -1;
00220   if (gy < 0 || gy >= ysize) return -1;
00221   if (gz < 0 || gz >= zsize) return -1;
00222   return gz*xsize*ysize + gy*xsize + gx;
00223 }
00224 
00225 
00227 float VolumetricData::voxel_value_safe(int x, int y, int z) const {
00228   int xx, yy, zz; 
00229   xx = (x > 0) ? ((x < xsize) ? x : xsize-1) : 0;
00230   yy = (y > 0) ? ((y < ysize) ? y : ysize-1) : 0;
00231   zz = (z > 0) ? ((z < zsize) ? z : zsize-1) : 0;
00232   int index = zz*xsize*ysize + yy*xsize + xx;
00233   return data[index];
00234 }
00235 
00236 
00238 float VolumetricData::voxel_value_interpolate(float xv, float yv, float zv) const {
00239   int x = (int) xv;
00240   int y = (int) yv;
00241   int z = (int) zv;
00242   float xf = xv - x;
00243   float yf = yv - y;
00244   float zf = zv - z;
00245   float xlerps[4];
00246   float ylerps[2];
00247   float tmp;
00248 
00249   tmp = voxel_value_safe(x, y, z);
00250   xlerps[0] = tmp + xf*(voxel_value_safe(x+1, y, z) - tmp);
00251 
00252   tmp = voxel_value_safe(x, y+1, z);
00253   xlerps[1] = tmp + xf*(voxel_value_safe(x+1, y+1, z) - tmp);
00254 
00255   tmp = voxel_value_safe(x, y, z+1);
00256   xlerps[2] = tmp + xf*(voxel_value_safe(x+1, y, z+1) - tmp);
00257 
00258   tmp = voxel_value_safe(x, y+1, z+1);
00259   xlerps[3] = tmp + xf*(voxel_value_safe(x+1, y+1, z+1) - tmp);
00260 
00261   ylerps[0] = xlerps[0] + yf*(xlerps[1] - xlerps[0]);
00262   ylerps[1] = xlerps[2] + yf*(xlerps[3] - xlerps[2]);
00263 
00264   return ylerps[0] + zf*(ylerps[1] - ylerps[0]);
00265 }
00266 
00267 
00269 float VolumetricData::voxel_value_from_coord(float xpos, float ypos, float zpos) const {
00270   int ind = voxel_index_from_coord(xpos, ypos, zpos);
00271   if (ind > 0)
00272     return data[ind];
00273   else
00274     return NAN;
00275 }
00276 
00277 
00279 float VolumetricData::voxel_value_interpolate_from_coord(float xpos, float ypos, float zpos) const {;
00280   float realcoord[3];
00281   float gridpoint[3];
00282   realcoord[0] = xpos;
00283   realcoord[1] = ypos;
00284   realcoord[2] = zpos;
00285  
00286   // calculate grid coordinate, shifting by a half-voxel 
00287   voxel_coord_from_cartesian_coord(realcoord, gridpoint, 0);
00288   
00289   int gx = (int) gridpoint[0]; 
00290   int gy = (int) gridpoint[1];
00291   int gz = (int) gridpoint[2];
00292   if (gx < 0 || gx >= xsize) return NAN;
00293   if (gy < 0 || gy >= ysize) return NAN;
00294   if (gz < 0 || gz >= zsize) return NAN;
00295   return voxel_value_interpolate(gridpoint[0], gridpoint[1], gridpoint[2]);
00296 }
00297 
00298 
00300 void VolumetricData::compute_volume_gradient(void) {
00301   int xi, yi, zi;
00302   float xs, ys, zs;
00303   float xl, yl, zl;
00304   int row;
00305 
00306   if (!gradient) {
00307     gradient = new float[xsize * ysize * zsize * 3];
00308   }
00309 
00310   // calculate cell side lengths
00311   cell_lengths(&xl, &yl, &zl);
00312 
00313   // gradient axis scaling values and averaging factors, to correctly
00314   // calculate the gradient for volumes with irregular cell spacing
00315   xs = -0.5f / xl;
00316   ys = -0.5f / yl;
00317   zs = -0.5f / zl;
00318 
00319   for (zi=0; zi<zsize; zi++) {
00320     int zm, zp;
00321     zm = clamp_int(zi - 1, 0, zsize - 1);
00322     zp = clamp_int(zi + 1, 0, zsize - 1);
00323 
00324     for (yi=0; yi<ysize; yi++) {
00325       int ym, yp;
00326       ym = clamp_int(yi - 1, 0, ysize - 1);
00327       yp = clamp_int(yi + 1, 0, ysize - 1);
00328 
00329       row = (zi * xsize * ysize) + (yi * xsize);
00330       for (xi=0; xi<xsize; xi++) {
00331         int index = (row + xi) * 3;
00332         int xm, xp;
00333         xm = clamp_int(xi - 1, 0, xsize - 1);
00334         xp = clamp_int(xi + 1, 0, xsize - 1);
00335 
00336         // Calculate the volume gradient at each grid cell.
00337         // Gradients are now stored unnormalized, since we need them in pure
00338         // form in order to draw field lines etc.  Shading code will now have
00339         // to do renormalization for itself on-the-fly.
00340 
00341         // XXX this gradient is only correct for orthogonal grids, since
00342         // we're using the array index offsets rather to calculate the gradient
00343         // rather than voxel coordinate offsets.  This will have to be
00344         // re-worked for non-orthogonal datasets.
00345         gradient[index    ] =
00346           (voxel_value(xp, yi, zi) - voxel_value(xm, yi, zi)) * xs;
00347         gradient[index + 1] =
00348           (voxel_value(xi, yp, zi) - voxel_value(xi, ym, zi)) * ys;
00349         gradient[index + 2] =
00350           (voxel_value(xi, yi, zp) - voxel_value(xi, yi, zm)) * zs;
00351       }
00352     }
00353   }
00354 }
00355 
00356 
00358 void VolumetricData::voxel_gradient_safe(int x, int y, int z, float *grad) const {
00359   int xx, yy, zz;
00360   xx = (x > 0) ? ((x < xsize) ? x : xsize-1) : 0;
00361   yy = (y > 0) ? ((y < ysize) ? y : ysize-1) : 0;
00362   zz = (z > 0) ? ((z < zsize) ? z : zsize-1) : 0;
00363   int index = zz*xsize*ysize + yy*xsize + xx;
00364   grad[0] = gradient[index*3    ];
00365   grad[1] = gradient[index*3 + 1];
00366   grad[2] = gradient[index*3 + 2];
00367 }
00368 
00369 
00371 void VolumetricData::voxel_gradient_interpolate(const float *voxcoord, float *grad) const {
00372   float gtmpa[3], gtmpb[3];
00373   int x = (int) voxcoord[0];
00374   int y = (int) voxcoord[1];
00375   int z = (int) voxcoord[2];
00376   float xf = voxcoord[0] - x;
00377   float yf = voxcoord[1] - y;
00378   float zf = voxcoord[2] - z;
00379   float xlerpsa[3];
00380   float xlerpsb[3];
00381   float xlerpsc[3];
00382   float xlerpsd[3];
00383   float ylerpsa[3];
00384   float ylerpsb[3];
00385 
00386   voxel_gradient_safe(x,   y,   z,   gtmpa);
00387   voxel_gradient_safe(x+1, y,   z,   gtmpb);
00388   vec_lerp(xlerpsa, gtmpa, gtmpb, xf);
00389  
00390   voxel_gradient_safe(x,   y+1, z,   gtmpa);
00391   voxel_gradient_safe(x+1, y+1, z,   gtmpb);
00392   vec_lerp(xlerpsb, gtmpa, gtmpb, xf);
00393 
00394   voxel_gradient_safe(x,   y,   z+1, gtmpa);
00395   voxel_gradient_safe(x+1, y,   z+1, gtmpb);
00396   vec_lerp(xlerpsc, gtmpa, gtmpb, xf);
00397 
00398   voxel_gradient_safe(x,   y+1, z+1, gtmpa);
00399   voxel_gradient_safe(x+1, y+1, z+1, gtmpb);
00400   vec_lerp(xlerpsd, gtmpa, gtmpb, xf);
00401 
00402   vec_lerp(ylerpsa, xlerpsa, xlerpsb, yf);
00403   vec_lerp(ylerpsb, xlerpsc, xlerpsd, yf);
00404 
00405   vec_lerp(grad, ylerpsa, ylerpsb, zf);
00406 }
00407 
00408 
00410 void VolumetricData::voxel_gradient_from_coord(const float *coord, float *grad) const {
00411   int vx, vy, vz;
00412   float voxcoord[3];
00413   voxel_coord_from_cartesian_coord(coord, voxcoord, 1);
00414   vx = (int) voxcoord[0];
00415   vy = (int) voxcoord[1];
00416   vz = (int) voxcoord[2];
00417   voxel_gradient_safe(vx, vy, vz, grad);
00418 }
00419 
00420 
00422 void VolumetricData::voxel_gradient_interpolate_from_coord(const float *coord, float *grad) const {
00423   float voxcoord[3];
00424   voxel_coord_from_cartesian_coord(coord, voxcoord, 0);
00425 
00426   if (voxcoord[0] < 0 || voxcoord[0] >= (xsize-1) ||
00427       voxcoord[1] < 0 || voxcoord[1] >= (ysize-1) ||
00428       voxcoord[2] < 0 || voxcoord[2] >= (zsize-1)) {
00429     grad[0] = NAN; 
00430     grad[1] = NAN; 
00431     grad[2] = NAN; 
00432     return; 
00433   }
00434 
00435   voxel_gradient_interpolate(voxcoord, grad);
00436 }
00437 
00438 

Generated on Sat May 26 01:48:39 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002