Blender V2.61 - r43446

isosurface.cpp

Go to the documentation of this file.
00001 
00004 /******************************************************************************
00005  *
00006  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
00007  * Copyright 2003-2006 Nils Thuerey
00008  *
00009  * Marching Cubes surface mesh generation
00010  *
00011  *****************************************************************************/
00012 
00013 #include "isosurface.h"
00014 #include "mcubes_tables.h"
00015 #include "particletracer.h"
00016 #include <algorithm>
00017 #include <stdio.h>
00018 
00019 #ifdef sun
00020 #include "ieeefp.h"
00021 #endif
00022 
00023 // just use default rounding for platforms where its not available
00024 #ifndef round
00025 #define round(x) (x)
00026 #endif
00027 
00028 /******************************************************************************
00029  * Constructor
00030  *****************************************************************************/
00031 IsoSurface::IsoSurface(double iso) :
00032     ntlGeometryObject(),
00033     mSizex(-1), mSizey(-1), mSizez(-1),
00034     mpData(NULL),
00035   mIsoValue( iso ), 
00036     mPoints(), 
00037     mUseFullEdgeArrays(false),
00038     mpEdgeVerticesX(NULL), mpEdgeVerticesY(NULL), mpEdgeVerticesZ(NULL),
00039     mEdgeArSize(-1),
00040     mIndices(),
00041 
00042   mStart(0.0), mEnd(0.0), mDomainExtent(0.0),
00043   mInitDone(false),
00044     mSmoothSurface(0.0), mSmoothNormals(0.0),
00045     mAcrossEdge(), mAdjacentFaces(),
00046     mCutoff(-1), mCutArray(NULL), // off by default
00047     mpIsoParts(NULL), mPartSize(0.), mSubdivs(0),
00048     mFlagCnt(1),
00049     mSCrad1(0.), mSCrad2(0.), mSCcenter(0.)
00050 {
00051 }
00052 
00053 
00054 /******************************************************************************
00055  * The real init...
00056  *****************************************************************************/
00057 void IsoSurface::initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent) 
00058 {
00059     // range 1-10 (max due to subd array in triangulate)
00060     if(mSubdivs<1) mSubdivs=1;
00061     if(mSubdivs>10) mSubdivs=10;
00062 
00063     // init solver and size
00064     mSizex = setx;
00065     mSizey = sety;
00066     if(setz == 1) {// 2D, create thin 2D surface
00067         setz = 5; 
00068     }
00069     mSizez = setz;
00070     mDomainExtent = extent;
00071 
00072     /* check triangulation size (for raytraing) */
00073     if( ( mStart[0] >= mEnd[0] ) && ( mStart[1] >= mEnd[1] ) && ( mStart[2] >= mEnd[2] ) ){
00074         // extent was not set, use normalized one from parametrizer
00075         mStart = ntlVec3Gfx(0.0) - extent*0.5;
00076         mEnd = ntlVec3Gfx(0.0) + extent*0.5;
00077     }
00078 
00079   // init 
00080     mIndices.clear();
00081   mPoints.clear();
00082 
00083     int nodes = mSizez*mSizey*mSizex;
00084   mpData = new float[nodes];
00085   for(int i=0;i<nodes;i++) { mpData[i] = 0.0; }
00086 
00087   // allocate edge arrays  (last slices are never used...)
00088     int initsize = -1;
00089     if(mUseFullEdgeArrays) {
00090         mEdgeArSize = nodes;
00091         mpEdgeVerticesX = new int[nodes];
00092         mpEdgeVerticesY = new int[nodes];
00093         mpEdgeVerticesZ = new int[nodes];
00094         initsize = 3*nodes;
00095     } else {
00096         int sliceNodes = 2*mSizex*mSizey*mSubdivs*mSubdivs;
00097         mEdgeArSize = sliceNodes;
00098         mpEdgeVerticesX = new int[sliceNodes];
00099         mpEdgeVerticesY = new int[sliceNodes];
00100         mpEdgeVerticesZ = new int[sliceNodes];
00101         initsize = 3*sliceNodes;
00102     }
00103   for(int i=0;i<mEdgeArSize;i++) { mpEdgeVerticesX[i] = mpEdgeVerticesY[i] = mpEdgeVerticesZ[i] = -1; }
00104     // WARNING - make sure this is consistent with calculateMemreqEstimate
00105   
00106     // marching cubes are ready 
00107     mInitDone = true;
00108     debMsgStd("IsoSurface::initializeIsosurface",DM_MSG,"Inited, edgenodes:"<<initsize<<" subdivs:"<<mSubdivs<<" fulledg:"<<mUseFullEdgeArrays , 10);
00109 }
00110 
00111 
00112 
00114 void IsoSurface::resetAll(gfxReal val) {
00115     int nodes = mSizez*mSizey*mSizex;
00116   for(int i=0;i<nodes;i++) { mpData[i] = val; }
00117 }
00118 
00119 
00120 /******************************************************************************
00121  * Destructor
00122  *****************************************************************************/
00123 IsoSurface::~IsoSurface( void )
00124 {
00125     if(mpData) delete [] mpData;
00126     if(mpEdgeVerticesX) delete [] mpEdgeVerticesX;
00127     if(mpEdgeVerticesY) delete [] mpEdgeVerticesY;
00128     if(mpEdgeVerticesZ) delete [] mpEdgeVerticesZ;
00129 }
00130 
00131 
00132 
00133 
00134 
00135 /******************************************************************************
00136  * triangulate the scalar field given by pointer
00137  *****************************************************************************/
00138 void IsoSurface::triangulate( void )
00139 {
00140   double gsx,gsy,gsz; // grid spacing in x,y,z direction
00141   double px,py,pz;    // current position in grid in x,y,z direction
00142   IsoLevelCube cubie;    // struct for a small subcube
00143     myTime_t tritimestart = getTime(); 
00144 
00145     if(!mpData) {
00146         errFatal("IsoSurface::triangulate","no LBM object, and no scalar field...!",SIMWORLD_INITERROR);
00147         return;
00148     }
00149 
00150   // get grid spacing (-2 to have same spacing as sim)
00151   gsx = (mEnd[0]-mStart[0])/(double)(mSizex-2.0);
00152   gsy = (mEnd[1]-mStart[1])/(double)(mSizey-2.0);
00153   gsz = (mEnd[2]-mStart[2])/(double)(mSizez-2.0);
00154 
00155   // clean up previous frame
00156     mIndices.clear();
00157     mPoints.clear();
00158 
00159     // reset edge vertices
00160   for(int i=0;i<mEdgeArSize;i++) {
00161         mpEdgeVerticesX[i] = -1;
00162         mpEdgeVerticesY[i] = -1;
00163         mpEdgeVerticesZ[i] = -1;
00164     }
00165 
00166     ntlVec3Gfx pos[8];
00167     float value[8];
00168     int cubeIndex;      // index entry of the cube 
00169     int triIndices[12]; // vertex indices 
00170     int *eVert[12];
00171     IsoLevelVertex ilv;
00172 
00173     // edges between which points?
00174     const int mcEdges[24] = { 
00175         0,1,  1,2,  2,3,  3,0,
00176         4,5,  5,6,  6,7,  7,4,
00177         0,4,  1,5,  2,6,  3,7 };
00178 
00179     const int cubieOffsetX[8] = {
00180         0,1,1,0,  0,1,1,0 };
00181     const int cubieOffsetY[8] = {
00182         0,0,1,1,  0,0,1,1 };
00183     const int cubieOffsetZ[8] = {
00184         0,0,0,0,  1,1,1,1 };
00185 
00186     const int coAdd=2;
00187   // let the cubes march 
00188     if(mSubdivs<=1) {
00189 
00190         pz = mStart[2]-gsz*0.5;
00191         for(int k=1;k<(mSizez-2);k++) {
00192             pz += gsz;
00193             py = mStart[1]-gsy*0.5;
00194             for(int j=1;j<(mSizey-2);j++) {
00195                 py += gsy;
00196                 px = mStart[0]-gsx*0.5;
00197                 for(int i=1;i<(mSizex-2);i++) {
00198                     px += gsx;
00199 
00200                     value[0] = *getData(i  ,j  ,k  );
00201                     value[1] = *getData(i+1,j  ,k  );
00202                     value[2] = *getData(i+1,j+1,k  );
00203                     value[3] = *getData(i  ,j+1,k  );
00204                     value[4] = *getData(i  ,j  ,k+1);
00205                     value[5] = *getData(i+1,j  ,k+1);
00206                     value[6] = *getData(i+1,j+1,k+1);
00207                     value[7] = *getData(i  ,j+1,k+1);
00208 
00209                     // check intersections of isosurface with edges, and calculate cubie index
00210                     cubeIndex = 0;
00211                     if (value[0] < mIsoValue) cubeIndex |= 1;
00212                     if (value[1] < mIsoValue) cubeIndex |= 2;
00213                     if (value[2] < mIsoValue) cubeIndex |= 4;
00214                     if (value[3] < mIsoValue) cubeIndex |= 8;
00215                     if (value[4] < mIsoValue) cubeIndex |= 16;
00216                     if (value[5] < mIsoValue) cubeIndex |= 32;
00217                     if (value[6] < mIsoValue) cubeIndex |= 64;
00218                     if (value[7] < mIsoValue) cubeIndex |= 128;
00219 
00220                     // No triangles to generate?
00221                     if (mcEdgeTable[cubeIndex] == 0) {
00222                         continue;
00223                     }
00224 
00225                     // where to look up if this point already exists
00226                     int edgek = 0;
00227                     if(mUseFullEdgeArrays) edgek=k;
00228                     const int baseIn = ISOLEVEL_INDEX( i+0, j+0, edgek+0);
00229                     eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
00230                     eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
00231                     eVert[ 2] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
00232                     eVert[ 3] = &mpEdgeVerticesY[ baseIn ];
00233 
00234                     eVert[ 4] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
00235                     eVert[ 5] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+1, j+0, edgek+1) ];
00236                     eVert[ 6] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+1) ];
00237                     eVert[ 7] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
00238 
00239                     eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];
00240                     eVert[ 9] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+0, edgek+0) ];
00241                     eVert[10] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+1, edgek+0) ];
00242                     eVert[11] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
00243 
00244                     // grid positions
00245                     pos[0] = ntlVec3Gfx(px    ,py    ,pz);
00246                     pos[1] = ntlVec3Gfx(px+gsx,py    ,pz);
00247                     pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz);
00248                     pos[3] = ntlVec3Gfx(px    ,py+gsy,pz);
00249                     pos[4] = ntlVec3Gfx(px    ,py    ,pz+gsz);
00250                     pos[5] = ntlVec3Gfx(px+gsx,py    ,pz+gsz);
00251                     pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz);
00252                     pos[7] = ntlVec3Gfx(px    ,py+gsy,pz+gsz);
00253 
00254                     // check all edges
00255                     for(int e=0;e<12;e++) {
00256                         if (mcEdgeTable[cubeIndex] & (1<<e)) {
00257                             // is the vertex already calculated?
00258                             if(*eVert[ e ] < 0) {
00259                                 // interpolate edge
00260                                 const int e1 = mcEdges[e*2  ];
00261                                 const int e2 = mcEdges[e*2+1];
00262                                 const ntlVec3Gfx p1 = pos[ e1  ];    // scalar field pos 1
00263                                 const ntlVec3Gfx p2 = pos[ e2  ];    // scalar field pos 2
00264                                 const float valp1  = value[ e1  ];  // scalar field val 1
00265                                 const float valp2  = value[ e2  ];  // scalar field val 2
00266                                 const float mu = (mIsoValue - valp1) / (valp2 - valp1);
00267 
00268                                 // init isolevel vertex
00269                                 ilv.v = p1 + (p2-p1)*mu;
00270                                 ilv.n = getNormal( i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
00271                                                 getNormal( i+cubieOffsetX[e2], j+cubieOffsetY[e2], k+cubieOffsetZ[e2]) * (    mu) ;
00272                                 mPoints.push_back( ilv );
00273 
00274                                 triIndices[e] = (mPoints.size()-1);
00275                                 // store vertex 
00276                                 *eVert[ e ] = triIndices[e];
00277                             }   else {
00278                                 // retrieve  from vert array
00279                                 triIndices[e] = *eVert[ e ];
00280                             }
00281                         } // along all edges 
00282                     }
00283 
00284                     if( (i<coAdd+mCutoff) || (j<coAdd+mCutoff) ||
00285                             ((mCutoff>0) && (k<coAdd)) ||// bottom layer
00286                             (i>mSizex-2-coAdd-mCutoff) ||
00287                             (j>mSizey-2-coAdd-mCutoff) ) {
00288                         if(mCutArray) {
00289                             if(k < mCutArray[j*this->mSizex+i]) continue;
00290                         } else { continue; }
00291                     }
00292 
00293                     // Create the triangles... 
00294                     for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
00295                         mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
00296                         mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] );
00297                         mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
00298                     }
00299                     
00300                 }//i
00301             }// j
00302 
00303             // copy edge arrays
00304             if(!mUseFullEdgeArrays) {
00305             for(int j=0;j<(mSizey-0);j++) 
00306                 for(int i=0;i<(mSizex-0);i++) {
00307                     //int edgek = 0;
00308                     const int dst = ISOLEVEL_INDEX( i+0, j+0, 0);
00309                     const int src = ISOLEVEL_INDEX( i+0, j+0, 1);
00310                     mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
00311                     mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ];
00312                     mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
00313                     mpEdgeVerticesX[ src ]=-1;
00314                     mpEdgeVerticesY[ src ]=-1;
00315                     mpEdgeVerticesZ[ src ]=-1;
00316                 }
00317             } // */
00318 
00319         } // k
00320 
00321     // precalculate normals using an approximation of the scalar field gradient 
00322         for(int ni=0;ni<(int)mPoints.size();ni++) { normalize( mPoints[ni].n ); }
00323 
00324     } else { // subdivs
00325 
00326 #define EDGEAR_INDEX(Ai,Aj,Ak, Bi,Bj) ((mSizex*mSizey*mSubdivs*mSubdivs*(Ak))+\
00327         (mSizex*mSubdivs*((Aj)*mSubdivs+(Bj)))+((Ai)*mSubdivs)+(Bi))
00328 
00329 #define ISOTRILININT(fi,fj,fk) ( \
00330                 (1.-(fi))*(1.-(fj))*(1.-(fk))*orgval[0] + \
00331                 (   (fi))*(1.-(fj))*(1.-(fk))*orgval[1] + \
00332                 (   (fi))*(   (fj))*(1.-(fk))*orgval[2] + \
00333                 (1.-(fi))*(   (fj))*(1.-(fk))*orgval[3] + \
00334                 (1.-(fi))*(1.-(fj))*(   (fk))*orgval[4] + \
00335                 (   (fi))*(1.-(fj))*(   (fk))*orgval[5] + \
00336                 (   (fi))*(   (fj))*(   (fk))*orgval[6] + \
00337                 (1.-(fi))*(   (fj))*(   (fk))*orgval[7] )
00338 
00339         // use subdivisions
00340         gfxReal subdfac = 1./(gfxReal)(mSubdivs);
00341         gfxReal orgGsx = gsx;
00342         gfxReal orgGsy = gsy;
00343         gfxReal orgGsz = gsz;
00344         gsx *= subdfac;
00345         gsy *= subdfac;
00346         gsz *= subdfac;
00347         if(mUseFullEdgeArrays) {
00348             errMsg("IsoSurface::triangulate","Disabling mUseFullEdgeArrays!");
00349         }
00350 
00351         // subdiv local arrays
00352         gfxReal orgval[8];
00353         gfxReal subdAr[2][11][11]; // max 10 subdivs!
00354         ParticleObject* *arppnt = new ParticleObject*[mSizez*mSizey*mSizex];
00355 
00356         // construct pointers
00357         // part test
00358         int pInUse = 0;
00359         int pUsedTest = 0;
00360         // reset particles
00361         // reset list array
00362         for(int k=0;k<(mSizez);k++) 
00363             for(int j=0;j<(mSizey);j++) 
00364                 for(int i=0;i<(mSizex);i++) {
00365                     arppnt[ISOLEVEL_INDEX(i,j,k)] = NULL;
00366                 }
00367         if(mpIsoParts) {
00368             for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
00369                     pit!= mpIsoParts->getParticlesEnd(); pit++) {
00370                 if( (*pit).getActive()==false ) continue;
00371                 if( (*pit).getType()!=PART_DROP) continue;
00372                 (*pit).setNext(NULL);
00373             }
00374             // build per node lists
00375             for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
00376                     pit!= mpIsoParts->getParticlesEnd(); pit++) {
00377                 if( (*pit).getActive()==false ) continue;
00378                 if( (*pit).getType()!=PART_DROP) continue;
00379                 // check lifetime ignored here
00380                 ParticleObject *p = &(*pit);
00381                 const ntlVec3Gfx ppos = p->getPos();
00382                 const int pi= (int)round(ppos[0])+0; 
00383                 const int pj= (int)round(ppos[1])+0; 
00384                 int       pk= (int)round(ppos[2])+0;// no offset necessary
00385                 // 2d should be handled by solver. if(LBMDIM==2) { pk = 0; }
00386 
00387                 if(pi<0) continue;
00388                 if(pj<0) continue;
00389                 if(pk<0) continue;
00390                 if(pi>mSizex-1) continue;
00391                 if(pj>mSizey-1) continue;
00392                 if(pk>mSizez-1) continue;
00393                 ParticleObject* &pnt = arppnt[ISOLEVEL_INDEX(pi,pj,pk)]; 
00394                 if(pnt) {
00395                     // append
00396                     ParticleObject* listpnt = pnt;
00397                     while(listpnt) {
00398                         if(!listpnt->getNext()) {
00399                             listpnt->setNext(p); listpnt = NULL;
00400                         } else {
00401                             listpnt = listpnt->getNext();
00402                         }
00403                     }
00404                 } else {
00405                     // start new list
00406                     pnt = p;
00407                 }
00408                 pInUse++;
00409             }
00410         } // mpIsoParts
00411 
00412         debMsgStd("IsoSurface::triangulate",DM_MSG,"Starting. Parts in use:"<<pInUse<<", Subdivs:"<<mSubdivs, 9);
00413         pz = mStart[2]-(double)(0.*gsz)-0.5*orgGsz;
00414         for(int ok=1;ok<(mSizez-2)*mSubdivs;ok++) {
00415             pz += gsz;
00416             const int k = ok/mSubdivs;
00417             if(k<=0) continue; // skip zero plane
00418             for(int j=1;j<(mSizey-2);j++) {
00419                 for(int i=1;i<(mSizex-2);i++) {
00420 
00421                     orgval[0] = *getData(i  ,j  ,k  );
00422                     orgval[1] = *getData(i+1,j  ,k  );
00423                     orgval[2] = *getData(i+1,j+1,k  ); // with subdivs
00424                     orgval[3] = *getData(i  ,j+1,k  );
00425                     orgval[4] = *getData(i  ,j  ,k+1);
00426                     orgval[5] = *getData(i+1,j  ,k+1);
00427                     orgval[6] = *getData(i+1,j+1,k+1); // with subdivs
00428                     orgval[7] = *getData(i  ,j+1,k+1);
00429 
00430                     // prebuild subsampled array slice
00431                     const int sdkOffset = ok-k*mSubdivs; 
00432                     for(int sdk=0; sdk<2; sdk++) 
00433                         for(int sdj=0; sdj<mSubdivs+1; sdj++) 
00434                             for(int sdi=0; sdi<mSubdivs+1; sdi++) {
00435                                 subdAr[sdk][sdj][sdi] = ISOTRILININT(sdi*subdfac, sdj*subdfac, (sdkOffset+sdk)*subdfac);
00436                             }
00437 
00438                     const int poDistOffset=2;
00439                     for(int pok=-poDistOffset; pok<1+poDistOffset; pok++) {
00440                         if(k+pok<0) continue;
00441                         if(k+pok>=mSizez-1) continue;
00442                     for(int poj=-poDistOffset; poj<1+poDistOffset; poj++) {
00443                         if(j+poj<0) continue;
00444                         if(j+poj>=mSizey-1) continue;
00445                     for(int poi=-poDistOffset; poi<1+poDistOffset; poi++) {
00446                         if(i+poi<0) continue;
00447                         if(i+poi>=mSizex-1) continue; 
00448                         ParticleObject *p;
00449                         p = arppnt[ISOLEVEL_INDEX(i+poi,j+poj,k+pok)];
00450                         while(p) { // */
00451                     /*
00452                     for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
00453                             pit!= mpIsoParts->getParticlesEnd(); pit++) { { { {
00454                         // debug test! , full list slow!
00455                         if(( (*pit).getActive()==false ) || ( (*pit).getType()!=PART_DROP)) continue;
00456                         ParticleObject *p;
00457                         p = &(*pit); // */
00458 
00459                             pUsedTest++;
00460                             ntlVec3Gfx ppos = p->getPos();
00461                             const int spi= (int)round( (ppos[0]+1.-(gfxReal)i) *(gfxReal)mSubdivs-1.5); 
00462                             const int spj= (int)round( (ppos[1]+1.-(gfxReal)j) *(gfxReal)mSubdivs-1.5); 
00463                             const int spk= (int)round( (ppos[2]+1.-(gfxReal)k) *(gfxReal)mSubdivs-1.5)-sdkOffset; // why -2?
00464                             // 2d should be handled by solver. if(LBMDIM==2) { spk = 0; }
00465 
00466                             gfxReal pfLen = p->getSize()*1.5*mPartSize;  // test, was 1.1
00467                             const gfxReal minPfLen = subdfac*0.8;
00468                             if(pfLen<minPfLen) pfLen = minPfLen;
00469                             //errMsg("ISOPPP"," at "<<PRINT_IJK<<"  pp"<<ppos<<"  sp"<<PRINT_VEC(spi,spj,spk)<<" pflen"<<pfLen );
00470                             //errMsg("ISOPPP"," subdfac="<<subdfac<<" size"<<p->getSize()<<" ps"<<mPartSize );
00471                             const int icellpsize = (int)(1.*pfLen*(gfxReal)mSubdivs)+1;
00472                             for(int swk=-icellpsize; swk<=icellpsize; swk++) {
00473                                 if(spk+swk<         0) { continue; }
00474                                 if(spk+swk>         1) { continue; } // */
00475                             for(int swj=-icellpsize; swj<=icellpsize; swj++) {
00476                                 if(spj+swj<         0) { continue; }
00477                                 if(spj+swj>mSubdivs+0) { continue; } // */
00478                             for(int swi=-icellpsize; swi<=icellpsize; swi++) {
00479                                 if(spi+swi<         0) { continue; } 
00480                                 if(spi+swi>mSubdivs+0) { continue; } // */
00481                                 ntlVec3Gfx cellp = ntlVec3Gfx(
00482                                         (1.5+(gfxReal)(spi+swi))           *subdfac + (gfxReal)(i-1),
00483                                         (1.5+(gfxReal)(spj+swj))           *subdfac + (gfxReal)(j-1),
00484                                         (1.5+(gfxReal)(spk+swk)+sdkOffset) *subdfac + (gfxReal)(k-1)
00485                                         );
00486                                 //if(swi==0 && swj==0 && swk==0) subdAr[spk][spj][spi] = 1.; // DEBUG
00487                                 // clip domain boundaries again 
00488                                 if(cellp[0]<1.) { continue; } 
00489                                 if(cellp[1]<1.) { continue; } 
00490                                 if(cellp[2]<1.) { continue; } 
00491                                 if(cellp[0]>(gfxReal)mSizex-3.) { continue; } 
00492                                 if(cellp[1]>(gfxReal)mSizey-3.) { continue; } 
00493                                 if(cellp[2]>(gfxReal)mSizez-3.) { continue; } 
00494                                 gfxReal len = norm(cellp-ppos);
00495                                 gfxReal isoadd = 0.; 
00496                                 const gfxReal baseIsoVal = mIsoValue*1.1;
00497                                 if(len<pfLen) { 
00498                                     isoadd = baseIsoVal*1.;
00499                                 } else { 
00500                                     // falloff linear with pfLen (kernel size=2pfLen
00501                                     isoadd = baseIsoVal*(1. - (len-pfLen)/(pfLen)); 
00502                                 }
00503                                 if(isoadd<0.) { continue; }
00504                                 //errMsg("ISOPPP"," at "<<PRINT_IJK<<" sp"<<PRINT_VEC(spi+swi,spj+swj,spk+swk)<<" cellp"<<cellp<<" pp"<<ppos << " l"<< len<< " add"<< isoadd);
00505                                 const gfxReal arval = subdAr[spk+swk][spj+swj][spi+swi];
00506                                 if(arval>1.) { continue; }
00507                                 subdAr[spk+swk][spj+swj][spi+swi] = arval + isoadd;
00508                             } } }
00509 
00510                             p = p->getNext();
00511                         }
00512                     } } } // poDist loops */
00513 
00514                     py = mStart[1]+(((double)j-0.5)*orgGsy)-gsy;
00515                     for(int sj=0;sj<mSubdivs;sj++) {
00516                         py += gsy;
00517                         px = mStart[0]+(((double)i-0.5)*orgGsx)-gsx;
00518                         for(int si=0;si<mSubdivs;si++) {
00519                             px += gsx;
00520                             value[0] = subdAr[0+0][sj+0][si+0]; 
00521                             value[1] = subdAr[0+0][sj+0][si+1]; 
00522                             value[2] = subdAr[0+0][sj+1][si+1]; 
00523                             value[3] = subdAr[0+0][sj+1][si+0]; 
00524                             value[4] = subdAr[0+1][sj+0][si+0]; 
00525                             value[5] = subdAr[0+1][sj+0][si+1]; 
00526                             value[6] = subdAr[0+1][sj+1][si+1]; 
00527                             value[7] = subdAr[0+1][sj+1][si+0]; 
00528 
00529                             // check intersections of isosurface with edges, and calculate cubie index
00530                             cubeIndex = 0;
00531                             if (value[0] < mIsoValue) cubeIndex |= 1;
00532                             if (value[1] < mIsoValue) cubeIndex |= 2; // with subdivs
00533                             if (value[2] < mIsoValue) cubeIndex |= 4;
00534                             if (value[3] < mIsoValue) cubeIndex |= 8;
00535                             if (value[4] < mIsoValue) cubeIndex |= 16;
00536                             if (value[5] < mIsoValue) cubeIndex |= 32; // with subdivs
00537                             if (value[6] < mIsoValue) cubeIndex |= 64;
00538                             if (value[7] < mIsoValue) cubeIndex |= 128;
00539 
00540                             if (mcEdgeTable[cubeIndex] >  0) {
00541 
00542                             // where to look up if this point already exists
00543                             const int edgek = 0;
00544                             const int baseIn = EDGEAR_INDEX( i+0, j+0, edgek+0, si,sj);
00545                             eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
00546                             eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
00547                             eVert[ 2] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
00548                             eVert[ 3] = &mpEdgeVerticesY[ baseIn ];                             
00549                                                                                                                                                                     
00550                             eVert[ 4] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
00551                             eVert[ 5] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+1,sj+0) ]; // with subdivs
00552                             eVert[ 6] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+1) ];
00553                             eVert[ 7] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
00554                                                                                                                                                                     
00555                             eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];                             
00556                             eVert[ 9] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+0) ]; // with subdivs
00557                             eVert[10] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+1) ];
00558                             eVert[11] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
00559 
00560                             // grid positions
00561                             pos[0] = ntlVec3Gfx(px    ,py    ,pz);
00562                             pos[1] = ntlVec3Gfx(px+gsx,py    ,pz);
00563                             pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz); // with subdivs
00564                             pos[3] = ntlVec3Gfx(px    ,py+gsy,pz);
00565                             pos[4] = ntlVec3Gfx(px    ,py    ,pz+gsz);
00566                             pos[5] = ntlVec3Gfx(px+gsx,py    ,pz+gsz);
00567                             pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz); // with subdivs
00568                             pos[7] = ntlVec3Gfx(px    ,py+gsy,pz+gsz);
00569 
00570                             // check all edges
00571                             for(int e=0;e<12;e++) {
00572                                 if (mcEdgeTable[cubeIndex] & (1<<e)) {
00573                                     // is the vertex already calculated?
00574                                     if(*eVert[ e ] < 0) {
00575                                         // interpolate edge
00576                                         const int e1 = mcEdges[e*2  ];
00577                                         const int e2 = mcEdges[e*2+1];
00578                                         const ntlVec3Gfx p1 = pos[ e1  ];   // scalar field pos 1
00579                                         const ntlVec3Gfx p2 = pos[ e2  ];   // scalar field pos 2
00580                                         const float valp1  = value[ e1  ];  // scalar field val 1
00581                                         const float valp2  = value[ e2  ];  // scalar field val 2
00582                                         const float mu = (mIsoValue - valp1) / (valp2 - valp1);
00583 
00584                                         // init isolevel vertex
00585                                         ilv.v = p1 + (p2-p1)*mu; // with subdivs
00586                                         mPoints.push_back( ilv );
00587                                         triIndices[e] = (mPoints.size()-1);
00588                                         // store vertex 
00589                                         *eVert[ e ] = triIndices[e]; 
00590                                     }   else {
00591                                         // retrieve  from vert array
00592                                         triIndices[e] = *eVert[ e ];
00593                                     }
00594                                 } // along all edges 
00595                             }
00596                             // removed cutoff treatment...
00597 
00598                             // Create the triangles... 
00599                             for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
00600                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
00601                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] ); // with subdivs
00602                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
00603                                 //errMsg("TTT"," i1"<<mIndices[mIndices.size()-3]<<" "<< " i2"<<mIndices[mIndices.size()-2]<<" "<< " i3"<<mIndices[mIndices.size()-1]<<" "<< mIndices.size() );
00604                             }
00605 
00606                             } // triangles in edge table?
00607                             
00608                         }//si
00609                     }// sj
00610 
00611                 }//i
00612             }// j
00613 
00614             // copy edge arrays
00615             for(int j=0;j<(mSizey-0)*mSubdivs;j++) 
00616                 for(int i=0;i<(mSizex-0)*mSubdivs;i++) {
00617                     //int edgek = 0;
00618                     const int dst = EDGEAR_INDEX( 0, 0, 0, i,j);
00619                     const int src = EDGEAR_INDEX( 0, 0, 1, i,j);
00620                     mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
00621                     mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ]; // with subdivs
00622                     mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
00623                     mpEdgeVerticesX[ src ]=-1;
00624                     mpEdgeVerticesY[ src ]=-1; // with subdivs
00625                     mpEdgeVerticesZ[ src ]=-1;
00626                 }
00627             // */
00628 
00629         } // ok, k subdiv loop
00630 
00631         //delete [] subdAr;
00632         delete [] arppnt;
00633         computeNormals();
00634     } // with subdivs
00635 
00636     // perform smoothing
00637     float smoSubdfac = 1.;
00638     if(mSubdivs>0) {
00639         //smoSubdfac = 1./(float)(mSubdivs);
00640         smoSubdfac = pow(0.55,(double)mSubdivs); // slightly stronger
00641     }
00642     if(mSmoothSurface>0. || mSmoothNormals>0.) debMsgStd("IsoSurface::triangulate",DM_MSG,"Smoothing...",10);
00643     if(mSmoothSurface>0.0) { 
00644         smoothSurface(mSmoothSurface*smoSubdfac, (mSmoothNormals<=0.0) ); 
00645     }
00646     if(mSmoothNormals>0.0) { 
00647         smoothNormals(mSmoothNormals*smoSubdfac); 
00648     }
00649 
00650     myTime_t tritimeend = getTime(); 
00651     debMsgStd("IsoSurface::triangulate",DM_MSG,"took "<< getTimeString(tritimeend-tritimestart)<<", S("<<mSmoothSurface<<","<<mSmoothNormals<<"),"<<
00652             " verts:"<<mPoints.size()<<" tris:"<<(mIndices.size()/3)<<" subdivs:"<<mSubdivs
00653          , 10 );
00654     if(mpIsoParts) debMsgStd("IsoSurface::triangulate",DM_MSG,"parts:"<<mpIsoParts->getNumParticles(), 10);
00655 }
00656 
00657 
00658     
00659 
00660 
00661 /******************************************************************************
00662  * Get triangles for rendering
00663  *****************************************************************************/
00664 void IsoSurface::getTriangles(double t, vector<ntlTriangle> *triangles, 
00665                                                      vector<ntlVec3Gfx> *vertices, 
00666                                                      vector<ntlVec3Gfx> *normals, int objectId )
00667 {
00668     if(!mInitDone) {
00669         debugOut("IsoSurface::getTriangles warning: Not initialized! ", 10);
00670         return;
00671     }
00672     t = 0.;
00673     //return; // DEBUG
00674 
00675   /* triangulate field */
00676   triangulate();
00677     //errMsg("TRIS"," "<<mIndices.size() );
00678 
00679     // new output with vertice reuse
00680     int iniVertIndex = (*vertices).size();
00681     int iniNormIndex = (*normals).size();
00682     if(iniVertIndex != iniNormIndex) {
00683         errFatal("getTriangles Error","For '"<<mName<<"': Vertices and normal array sizes to not match!!!",SIMWORLD_GENERICERROR);
00684         return; 
00685     }
00686     //errMsg("NM"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
00687     //errMsg("NM"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
00688 
00689   for(int i=0;i<(int)mPoints.size();i++) {
00690         vertices->push_back( mPoints[i].v );
00691     }
00692   for(int i=0;i<(int)mPoints.size();i++) {
00693         normals->push_back( mPoints[i].n );
00694     }
00695 
00696     //errMsg("N2"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
00697     //errMsg("N2"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
00698 
00699   for(int i=0;i<(int)mIndices.size();i+=3) {
00700         const int smooth = 1;
00701     int t1 = mIndices[i];
00702     int t2 = mIndices[i+1];
00703         int t3 = mIndices[i+2];
00704         //errMsg("NM"," tri"<<t1<<" "<<t2<<" "<<t3 );
00705 
00706         ntlTriangle tri;
00707 
00708         tri.getPoints()[0] = t1+iniVertIndex;
00709         tri.getPoints()[1] = t2+iniVertIndex;
00710         tri.getPoints()[2] = t3+iniVertIndex;
00711 
00712         /* init flags */
00713         int flag = 0; 
00714         if(getVisible()){ flag |= TRI_GEOMETRY; }
00715         if(getCastShadows() ) { 
00716             flag |= TRI_CASTSHADOWS; } 
00717 
00718         /* init geo init id */
00719         int geoiId = getGeoInitId(); 
00720         if(geoiId > 0) { 
00721             flag |= (1<< (geoiId+4)); 
00722             flag |= mGeoInitType; 
00723         } 
00724 
00725         tri.setFlags( flag );
00726 
00727         /* triangle normal missing */
00728         tri.setNormal( ntlVec3Gfx(0.0) );
00729         tri.setSmoothNormals( smooth );
00730         tri.setObjectId( objectId );
00731         triangles->push_back( tri ); 
00732     }
00733     //errMsg("N3"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
00734     return;
00735 }
00736 
00737 
00738 
00739 inline ntlVec3Gfx IsoSurface::getNormal(int i, int j,int k) {
00740     // WARNING - this requires a security boundary layer... 
00741     ntlVec3Gfx ret(0.0);
00742     ret[0] = *getData(i-1,j  ,k  ) - 
00743              *getData(i+1,j  ,k  );
00744     ret[1] = *getData(i  ,j-1,k  ) - 
00745              *getData(i  ,j+1,k  );
00746     ret[2] = *getData(i  ,j  ,k-1  ) - 
00747              *getData(i  ,j  ,k+1  );
00748     return ret;
00749 }
00750 
00751 
00752 
00753 
00754 /******************************************************************************
00755  * 
00756  * Surface improvement, inspired by trimesh2 library
00757  * (http://www.cs.princeton.edu/gfx/proj/trimesh2/)
00758  * 
00759  *****************************************************************************/
00760 
00761 void IsoSurface::setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc) {
00762     mSCrad1 = radi1*radi1;
00763     mSCrad2 = radi2*radi2;
00764     mSCcenter = mscc;
00765 }
00766 
00767 // compute normals for all generated triangles
00768 void IsoSurface::computeNormals() {
00769   for(int i=0;i<(int)mPoints.size();i++) {
00770         mPoints[i].n = ntlVec3Gfx(0.);
00771     }
00772 
00773   for(int i=0;i<(int)mIndices.size();i+=3) {
00774     const int t1 = mIndices[i];
00775     const int t2 = mIndices[i+1];
00776         const int t3 = mIndices[i+2];
00777         const ntlVec3Gfx p1 = mPoints[t1].v;
00778         const ntlVec3Gfx p2 = mPoints[t2].v;
00779         const ntlVec3Gfx p3 = mPoints[t3].v;
00780         const ntlVec3Gfx n1=p1-p2;
00781         const ntlVec3Gfx n2=p2-p3;
00782         const ntlVec3Gfx n3=p3-p1;
00783         const gfxReal len1 = normNoSqrt(n1);
00784         const gfxReal len2 = normNoSqrt(n2);
00785         const gfxReal len3 = normNoSqrt(n3);
00786         const ntlVec3Gfx norm = cross(n1,n2);
00787         mPoints[t1].n += norm * (1./(len1*len3));
00788         mPoints[t2].n += norm * (1./(len1*len2));
00789         mPoints[t3].n += norm * (1./(len2*len3));
00790     }
00791 
00792   for(int i=0;i<(int)mPoints.size();i++) {
00793         normalize(mPoints[i].n);
00794     }
00795 }
00796 
00797 // Diffuse a vector field at 1 vertex, weighted by
00798 // a gaussian of width 1/sqrt(invsigma2)
00799 bool IsoSurface::diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int src, float invsigma2, ntlVec3Gfx &target)
00800 {
00801     if((neighbors[src].size()<1) || (pointareas[src]<=0.0)) return 0;
00802     const ntlVec3Gfx srcp = mPoints[src].v;
00803     const ntlVec3Gfx srcn = mPoints[src].n;
00804     if(mSCrad1>0.0 && mSCrad2>0.0) {
00805         ntlVec3Gfx dp = mSCcenter-srcp; dp[2] = 0.0; // only xy-plane
00806         float rd = normNoSqrt(dp);
00807         if(rd > mSCrad2) {
00808             return 0;
00809         } else if(rd > mSCrad1) {
00810             // optimize?
00811             float org = 1.0/sqrt(invsigma2);
00812             org *= (1.0- (rd-mSCrad1) / (mSCrad2-mSCrad1));
00813             invsigma2 = 1.0/(org*org);
00814             //errMsg("TRi","p"<<srcp<<" rd:"<<rd<<" r1:"<<mSCrad1<<" r2:"<<mSCrad2<<" org:"<<org<<" is:"<<invsigma2);
00815         } else {
00816         }
00817     }
00818     target = ntlVec3Gfx(0.0);
00819     target += *(field+pointerScale*src) *pointareas[src];
00820     float smstrSum = pointareas[src];
00821 
00822     int flag = mFlagCnt; 
00823     mFlagCnt++;
00824     flags[src] = flag;
00825     mDboundary = neighbors[src];
00826     while (!mDboundary.empty()) {
00827         const int bbn = mDboundary.back();
00828         mDboundary.pop_back();
00829         if(flags[bbn]==flag) continue;
00830         flags[bbn] = flag;
00831 
00832         // normal check
00833         const float nvdot = dot(srcn, mPoints[bbn].n); // faster than before d2 calc?
00834         if(nvdot <= 0.0f) continue;
00835 
00836         // gaussian weight of width 1/sqrt(invsigma2)
00837         const float d2 = invsigma2 * normNoSqrt(mPoints[bbn].v - srcp);
00838         if(d2 >= 9.0f) continue;
00839 
00840         // aggressive smoothing factor
00841         float smstr = nvdot * pointareas[bbn];
00842         // Accumulate weight times field at neighbor
00843         target += *(field+pointerScale*bbn)*smstr;
00844         smstrSum += smstr;
00845 
00846         for(int i = 0; i < (int)neighbors[bbn].size(); i++) {
00847             const int nn = neighbors[bbn][i];
00848             if (flags[nn] == flag) continue;
00849             mDboundary.push_back(nn);
00850         }
00851     }
00852     target /= smstrSum;
00853     return 1;
00854 }
00855 
00856     
00857 // perform smoothing of the surface (and possible normals)
00858 void IsoSurface::smoothSurface(float sigma, bool normSmooth)
00859 {
00860     int nv = mPoints.size();
00861     if ((int)flags.size() != nv) flags.resize(nv);
00862     int nf = mIndices.size()/3;
00863 
00864     { // need neighbors
00865         vector<int> numneighbors(mPoints.size());
00866         int i;
00867         for (i = 0; i < (int)mIndices.size()/3; i++) {
00868             numneighbors[mIndices[i*3+0]]++;
00869             numneighbors[mIndices[i*3+1]]++;
00870             numneighbors[mIndices[i*3+2]]++;
00871         }
00872 
00873         neighbors.clear();
00874         neighbors.resize(mPoints.size());
00875         for (i = 0; i < (int)mPoints.size(); i++) {
00876             neighbors[i].clear();
00877             neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
00878         }
00879 
00880         for (i = 0; i < (int)mIndices.size()/3; i++) {
00881             for (int j = 0; j < 3; j++) {
00882                 vector<int> &me = neighbors[ mIndices[i*3+j]];
00883                 int n1 =  mIndices[i*3+((j+1)%3)];
00884                 int n2 =  mIndices[i*3+((j+2)%3)];
00885                 if (std::find(me.begin(), me.end(), n1) == me.end())
00886                     me.push_back(n1);
00887                 if (std::find(me.begin(), me.end(), n2) == me.end())
00888                     me.push_back(n2);
00889             }
00890         }
00891     } // need neighbor
00892 
00893     { // need pointarea
00894         pointareas.clear();
00895         pointareas.resize(nv);
00896         cornerareas.clear();
00897         cornerareas.resize(nf);
00898 
00899         for (int i = 0; i < nf; i++) {
00900             // Edges
00901             ntlVec3Gfx e[3] = { 
00902                 mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
00903                 mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
00904                 mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
00905 
00906             // Compute corner weights
00907             float area = 0.5f * norm( cross(e[0], e[1]));
00908             float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
00909             float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
00910                     l2[1] * (l2[2] + l2[0] - l2[1]),
00911                     l2[2] * (l2[0] + l2[1] - l2[2]) };
00912             if (ew[0] <= 0.0f) {
00913                 cornerareas[i][1] = -0.25f * l2[2] * area /
00914                                 dot(e[0] , e[2]);
00915                 cornerareas[i][2] = -0.25f * l2[1] * area /
00916                                 dot(e[0] , e[1]);
00917                 cornerareas[i][0] = area - cornerareas[i][1] -
00918                                 cornerareas[i][2];
00919             } else if (ew[1] <= 0.0f) {
00920                 cornerareas[i][2] = -0.25f * l2[0] * area /
00921                                 dot(e[1] , e[0]);
00922                 cornerareas[i][0] = -0.25f * l2[2] * area /
00923                                 dot(e[1] , e[2]);
00924                 cornerareas[i][1] = area - cornerareas[i][2] -
00925                                 cornerareas[i][0];
00926             } else if (ew[2] <= 0.0f) {
00927                 cornerareas[i][0] = -0.25f * l2[1] * area /
00928                                 dot(e[2] , e[1]);
00929                 cornerareas[i][1] = -0.25f * l2[0] * area /
00930                                 dot(e[2] , e[0]);
00931                 cornerareas[i][2] = area - cornerareas[i][0] -
00932                                 cornerareas[i][1];
00933             } else {
00934                 float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
00935                 for (int j = 0; j < 3; j++)
00936                     cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
00937                                              ew[(j+2)%3]);
00938             }
00939 
00940             // NT important, check this...
00941 #ifndef WIN32
00942             if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6;
00943             if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6;
00944             if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6;
00945 #else // WIN32
00946             // FIXME check as well...
00947             if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6;
00948             if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6;
00949             if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6;
00950 #endif // WIN32
00951 
00952             pointareas[mIndices[i*3+0]] += cornerareas[i][0];
00953             pointareas[mIndices[i*3+1]] += cornerareas[i][1];
00954             pointareas[mIndices[i*3+2]] += cornerareas[i][2];
00955         }
00956 
00957     } // need pointarea
00958     // */
00959 
00960     float invsigma2 = 1.0f / (sigma*sigma);
00961 
00962     vector<ntlVec3Gfx> dflt(nv);
00963     for (int i = 0; i < nv; i++) {
00964         if(diffuseVertexField( &mPoints[0].v, 2,
00965                    i, invsigma2, dflt[i])) {
00966             // Just keep the displacement
00967             dflt[i] -= mPoints[i].v;
00968         } else { dflt[i] = 0.0; } //?mPoints[i].v; }
00969     }
00970 
00971     // Slightly better small-neighborhood approximation
00972     for (int i = 0; i < nf; i++) {
00973         ntlVec3Gfx c = mPoints[mIndices[i*3+0]].v +
00974               mPoints[mIndices[i*3+1]].v +
00975               mPoints[mIndices[i*3+2]].v;
00976         c /= 3.0f;
00977         for (int j = 0; j < 3; j++) {
00978             int v = mIndices[i*3+j];
00979             ntlVec3Gfx d =(c - mPoints[v].v) * 0.5f;
00980             dflt[v] += d * (cornerareas[i][j] /
00981                    pointareas[mIndices[i*3+j]] *
00982                    exp(-0.5f * invsigma2 * normNoSqrt(d)) );
00983         }
00984     }
00985 
00986     // Filter displacement field
00987     vector<ntlVec3Gfx> dflt2(nv);
00988     for (int i = 0; i < nv; i++) {
00989         if(diffuseVertexField( &dflt[0], 1,
00990                    i, invsigma2, dflt2[i])) { }
00991         else { /*mPoints[i].v=0.0;*/ dflt2[i] = 0.0; }//dflt2[i]; }
00992     }
00993 
00994     // Update vertex positions
00995     for (int i = 0; i < nv; i++) {
00996         mPoints[i].v += dflt[i] - dflt2[i]; // second Laplacian
00997     }
00998 
00999     // when normals smoothing off, this cleans up quite well
01000     // costs ca. 50% additional time though
01001     float nsFac = 1.5f;
01002     if(normSmooth) { float ninvsigma2 = 1.0f / (nsFac*nsFac*sigma*sigma);
01003         for (int i = 0; i < nv; i++) {
01004             if( diffuseVertexField( &mPoints[0].n, 2, i, ninvsigma2, dflt[i]) ) {
01005                 normalize(dflt[i]);
01006             } else {
01007                 dflt[i] = mPoints[i].n;
01008             }
01009         }
01010         for (int i = 0; i < nv; i++) {
01011             mPoints[i].n = dflt[i];
01012         } 
01013     } // smoothNormals copy */
01014 
01015     //errMsg("SMSURF","done v:"<<sigma); // DEBUG
01016 }
01017 
01018 // only smoothen the normals
01019 void IsoSurface::smoothNormals(float sigma) {
01020     // reuse from smoothSurface
01021     if(neighbors.size() != mPoints.size()) { 
01022         // need neighbor
01023         vector<int> numneighbors(mPoints.size());
01024         int i;
01025         for (i = 0; i < (int)mIndices.size()/3; i++) {
01026             numneighbors[mIndices[i*3+0]]++;
01027             numneighbors[mIndices[i*3+1]]++;
01028             numneighbors[mIndices[i*3+2]]++;
01029         }
01030 
01031         neighbors.clear();
01032         neighbors.resize(mPoints.size());
01033         for (i = 0; i < (int)mPoints.size(); i++) {
01034             neighbors[i].clear();
01035             neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
01036         }
01037 
01038         for (i = 0; i < (int)mIndices.size()/3; i++) {
01039             for (int j = 0; j < 3; j++) {
01040                 vector<int> &me = neighbors[ mIndices[i*3+j]];
01041                 int n1 =  mIndices[i*3+((j+1)%3)];
01042                 int n2 =  mIndices[i*3+((j+2)%3)];
01043                 if (std::find(me.begin(), me.end(), n1) == me.end())
01044                     me.push_back(n1);
01045                 if (std::find(me.begin(), me.end(), n2) == me.end())
01046                     me.push_back(n2);
01047             }
01048         }
01049     } // need neighbor
01050 
01051     { // need pointarea
01052         int nf = mIndices.size()/3, nv = mPoints.size();
01053         pointareas.clear();
01054         pointareas.resize(nv);
01055         cornerareas.clear();
01056         cornerareas.resize(nf);
01057 
01058         for (int i = 0; i < nf; i++) {
01059             // Edges
01060             ntlVec3Gfx e[3] = { 
01061                 mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
01062                 mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
01063                 mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
01064 
01065             // Compute corner weights
01066             float area = 0.5f * norm( cross(e[0], e[1]));
01067             float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
01068             float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
01069                     l2[1] * (l2[2] + l2[0] - l2[1]),
01070                     l2[2] * (l2[0] + l2[1] - l2[2]) };
01071             if (ew[0] <= 0.0f) {
01072                 cornerareas[i][1] = -0.25f * l2[2] * area /
01073                                 dot(e[0] , e[2]);
01074                 cornerareas[i][2] = -0.25f * l2[1] * area /
01075                                 dot(e[0] , e[1]);
01076                 cornerareas[i][0] = area - cornerareas[i][1] -
01077                                 cornerareas[i][2];
01078             } else if (ew[1] <= 0.0f) {
01079                 cornerareas[i][2] = -0.25f * l2[0] * area /
01080                                 dot(e[1] , e[0]);
01081                 cornerareas[i][0] = -0.25f * l2[2] * area /
01082                                 dot(e[1] , e[2]);
01083                 cornerareas[i][1] = area - cornerareas[i][2] -
01084                                 cornerareas[i][0];
01085             } else if (ew[2] <= 0.0f) {
01086                 cornerareas[i][0] = -0.25f * l2[1] * area /
01087                                 dot(e[2] , e[1]);
01088                 cornerareas[i][1] = -0.25f * l2[0] * area /
01089                                 dot(e[2] , e[0]);
01090                 cornerareas[i][2] = area - cornerareas[i][0] -
01091                                 cornerareas[i][1];
01092             } else {
01093                 float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
01094                 for (int j = 0; j < 3; j++)
01095                     cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
01096                                              ew[(j+2)%3]);
01097             }
01098 
01099             // NT important, check this...
01100 #ifndef WIN32
01101             if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6;
01102             if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6;
01103             if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6;
01104 #else // WIN32
01105             // FIXME check as well...
01106             if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6;
01107             if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6;
01108             if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6;
01109 #endif // WIN32
01110 
01111             pointareas[mIndices[i*3+0]] += cornerareas[i][0];
01112             pointareas[mIndices[i*3+1]] += cornerareas[i][1];
01113             pointareas[mIndices[i*3+2]] += cornerareas[i][2];
01114         }
01115 
01116     } // need pointarea
01117 
01118     int nv = mPoints.size();
01119     if ((int)flags.size() != nv) flags.resize(nv);
01120     float invsigma2 = 1.0f / (sigma*sigma);
01121 
01122     vector<ntlVec3Gfx> nflt(nv);
01123     for (int i = 0; i < nv; i++) {
01124         if(diffuseVertexField( &mPoints[0].n, 2, i, invsigma2, nflt[i])) {
01125             normalize(nflt[i]);
01126         } else { nflt[i]=mPoints[i].n; }
01127     }
01128 
01129     // copy results
01130     for (int i = 0; i < nv; i++) { mPoints[i].n = nflt[i]; }
01131 }
01132 
01133