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

Isocontour.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 #include <stdio.h>
00010 #include <stdlib.h>
00011 #include <string.h>
00012 #include <math.h>
00013 #include "Inform.h"
00014 #include "utilities.h"
00015 
00016 #define ISOCONTOUR_INTERNAL 1
00017 #include "Isocontour.h"
00018 #include "VolumetricData.h"
00019 
00020 IsoContour::IsoContour(void) {}
00021 
00022 void IsoContour::clear(void) {
00023   numtriangles=0;
00024   v.clear();
00025   f.clear();
00026 }
00027 
00028 
00029 int IsoContour::compute(const VolumetricData *data, float isovalue, int step) {
00030   int x, y, z; 
00031   int tricount=0;
00032 
00033   vol=data;
00034 
00035   xax[0] = (float) (vol->xaxis[0] / ((float) (vol->xsize - 1)));
00036   xax[1] = (float) (vol->xaxis[1] / ((float) (vol->xsize - 1)));
00037   xax[2] = (float) (vol->xaxis[2] / ((float) (vol->xsize - 1)));
00038 
00039   yax[0] = (float) (vol->yaxis[0] / ((float) (vol->ysize - 1)));
00040   yax[1] = (float) (vol->yaxis[1] / ((float) (vol->ysize - 1)));
00041   yax[2] = (float) (vol->yaxis[2] / ((float) (vol->ysize - 1)));
00042 
00043   zax[0] = (float) (vol->zaxis[0] / ((float) (vol->zsize - 1)));
00044   zax[1] = (float) (vol->zaxis[1] / ((float) (vol->zsize - 1)));
00045   zax[2] = (float) (vol->zaxis[2] / ((float) (vol->zsize - 1)));
00046 
00047   for (z=0; z<(vol->zsize - step); z+=step) {
00048     for (y=0; y<(vol->ysize - step); y+=step) {
00049       for (x=0; x<(vol->xsize - step); x+=step) {
00050         tricount += DoCell(x, y, z, isovalue, step);
00051       }
00052     }
00053   }
00054 
00055   return 1;
00056 }
00057 
00058 
00059 
00060 int IsoContour::DoCell(int x, int y, int z, float isovalue, int step) {
00061   SQUARECELL gc;
00062   int addr, row, plane, rowstep, planestep, tricount;
00063   LINE tris[5];
00064 
00065   row = vol->xsize; 
00066   plane = vol->xsize * vol->ysize;
00067   addr = z*plane + y*row + x;
00068   rowstep = row*step;
00069   planestep = plane*step;
00070   
00071   gc.val[0] = vol->data[addr                             ];
00072   gc.val[1] = vol->data[addr + step                      ];
00073   gc.val[3] = vol->data[addr +        rowstep            ];
00074   gc.val[2] = vol->data[addr + step + rowstep            ];
00075   gc.val[4] = vol->data[addr +                  planestep];
00076   gc.val[5] = vol->data[addr + step +           planestep];
00077   gc.val[7] = vol->data[addr +        rowstep + planestep];
00078   gc.val[6] = vol->data[addr + step + rowstep + planestep];
00079 
00080   /*
00081      Determine the index into the edge table which
00082      tells us which vertices are inside of the surface
00083   */
00084   int cubeindex = 0;
00085   if (gc.val[0] < isovalue) cubeindex |= 1;
00086   if (gc.val[1] < isovalue) cubeindex |= 2;
00087   if (gc.val[2] < isovalue) cubeindex |= 4;
00088   if (gc.val[3] < isovalue) cubeindex |= 8;
00089   if (gc.val[4] < isovalue) cubeindex |= 16;
00090   if (gc.val[5] < isovalue) cubeindex |= 32;
00091   if (gc.val[6] < isovalue) cubeindex |= 64;
00092   if (gc.val[7] < isovalue) cubeindex |= 128;
00093 
00094   /* Cube is entirely in/out of the surface */
00095   if (edgeTable[cubeindex] == 0)
00096     return(0);
00097   gc.cubeindex = cubeindex;
00098 
00099   gc.p[0].x = (float) x;
00100   gc.p[0].y = (float) y;
00101 
00102   gc.p[1].x = (float) x + step;
00103   gc.p[1].y = (float) y;
00104 
00105   gc.p[2].x = (float) x + step;
00106   gc.p[2].y = (float) y + step;
00107   
00108   gc.p[3].x = (float) x;
00109   gc.p[3].y = (float) y + step;
00110 
00111   // calculate vertices and facets for this cube,
00112   // calculate normals by interpolating between the negated 
00113   // normalized volume gradients for the 8 reference voxels
00114   tricount = Polygonise(gc, isovalue, (LINE *) &tris);
00115 
00116   if (tricount > 0) {
00117     int i;
00118 
00119     for (i=0; i<tricount; i++) {
00120       float xx, yy, zz;
00121 
00122       f.append(numtriangles * 3    );
00123       f.append(numtriangles * 3 + 1);
00124       f.append(numtriangles * 3 + 2);
00125       numtriangles++;
00126 
00127       // add new vertices and normals into vertex and normal lists
00128       xx = tris[i].p[0].x;
00129       yy = tris[i].p[0].y;
00130       v.append((float) vol->origin[0] + xx * xax[0] + yy * yax[0] + zz * zax[0]);
00131       v.append((float) vol->origin[1] + xx * xax[1] + yy * yax[1] + zz * zax[1]);
00132       v.append((float) vol->origin[2] + xx * xax[2] + yy * yax[2] + zz * zax[2]);
00133       xx = tris[i].p[1].x;
00134       yy = tris[i].p[1].y;
00135       v.append((float) vol->origin[0] + xx * xax[0] + yy * yax[0] + zz * zax[0]);
00136       v.append((float) vol->origin[1] + xx * xax[1] + yy * yax[1] + zz * zax[1]);
00137       v.append((float) vol->origin[2] + xx * xax[2] + yy * yax[2] + zz * zax[2]);
00138       xx = tris[i].p[2].x;
00139       yy = tris[i].p[2].y;
00140       v.append((float) vol->origin[0] + xx * xax[0] + yy * yax[0] + zz * zax[0]);
00141       v.append((float) vol->origin[1] + xx * xax[1] + yy * yax[1] + zz * zax[1]);
00142       v.append((float) vol->origin[2] + xx * xax[2] + yy * yax[2] + zz * zax[2]);
00143     }
00144   }
00145 
00146   return tricount;
00147 }
00148 
00149 
00150 /*
00151    Given a grid cell and an isolevel, calculate the triangular
00152    facets required to represent the isocontour through the cell.
00153    Return the number of triangular facets, the array "triangles"
00154    will be loaded up with the vertices at most 5 triangular facets.
00155         0 will be returned if the grid cell is either totally above
00156    of totally below the isolevel.
00157    This code calculates vertex normals by interpolating the volume gradients.
00158 */
00159 int IsoContour::Polygonise(const SQUARECELL grid, const float isolevel, LINE *triangles) {
00160    int i,ntriang;
00161    int cubeindex = grid.cubeindex;
00162    XY vertlist[12];
00163 
00164    /* Find the vertices where the surface intersects the cube */
00165    if (edgeTable[cubeindex] & 1)
00166       VertexInterp(isolevel, grid, 0, 1, &vertlist[0]);
00167    if (edgeTable[cubeindex] & 2)
00168       VertexInterp(isolevel, grid, 1, 2, &vertlist[1]);
00169    if (edgeTable[cubeindex] & 4)
00170       VertexInterp(isolevel, grid, 2, 3, &vertlist[2]);
00171    if (edgeTable[cubeindex] & 8)
00172       VertexInterp(isolevel, grid, 3, 0, &vertlist[3]);
00173    if (edgeTable[cubeindex] & 16)
00174       VertexInterp(isolevel, grid, 4, 5, &vertlist[4]);
00175    if (edgeTable[cubeindex] & 32)
00176       VertexInterp(isolevel, grid, 5, 6, &vertlist[5]);
00177    if (edgeTable[cubeindex] & 64)
00178       VertexInterp(isolevel, grid, 6, 7, &vertlist[6]);
00179    if (edgeTable[cubeindex] & 128)
00180       VertexInterp(isolevel, grid, 7, 4, &vertlist[7]);
00181    if (edgeTable[cubeindex] & 256)
00182       VertexInterp(isolevel, grid, 0, 4, &vertlist[8]);
00183    if (edgeTable[cubeindex] & 512)
00184       VertexInterp(isolevel, grid, 1, 5, &vertlist[9]);
00185    if (edgeTable[cubeindex] & 1024)
00186       VertexInterp(isolevel, grid, 2, 6, &vertlist[10]);
00187    if (edgeTable[cubeindex] & 2048)
00188       VertexInterp(isolevel, grid, 3, 7, &vertlist[11]);
00189 
00190    /* Create the triangle */
00191    ntriang = 0;
00192    for (i=0; lineTable[cubeindex][i]!=-1;i+=3) {
00193      triangles[ntriang].p[0] = vertlist[lineTable[cubeindex][i  ]];
00194      triangles[ntriang].p[1] = vertlist[lineTable[cubeindex][i+1]];
00195      triangles[ntriang].p[2] = vertlist[lineTable[cubeindex][i+2]];
00196      ntriang++;
00197    }
00198 
00199    return ntriang;
00200 }
00201 
00202 
00203 /*
00204    Linearly interpolate the position where an isocontour cuts
00205    an edge between two vertices, each with their own scalar value,
00206    interpolating vertex position and vertex normal based on the 
00207    isovalue.
00208 */
00209 void IsoContour::VertexInterp(float isolevel, const SQUARECELL grid, int ind1, int ind2, XY * vert) {
00210   float mu;
00211 
00212   XY p1 = grid.p[ind1];
00213   XY p2 = grid.p[ind2];
00214   float valp1 = grid.val[ind1];
00215   float valp2 = grid.val[ind2];
00216 
00217   if (fabs(isolevel-valp1) < 0.00001) {
00218     *vert = grid.p[ind1];
00219     return;
00220   }
00221 
00222   if (fabs(isolevel-valp2) < 0.00001) {
00223     *vert = grid.p[ind2];
00224     return;
00225   }
00226 
00227   if (fabs(valp1-valp2) < 0.00001) {
00228     *vert = grid.p[ind1];
00229     return;
00230   }
00231 
00232   mu = (isolevel - valp1) / (valp2 - valp1);
00233 
00234   vert->x = p1.x + mu * (p2.x - p1.x);
00235   vert->y = p1.y + mu * (p2.y - p1.y);
00236 }
00237 

Generated on Mon May 21 01:50:54 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002