1b0ba13c70710b55d4874bbb61de44ed0d542ba4
[blender-staging.git] / intern / elbeem / intern / isosurface.cpp
1 /******************************************************************************
2  *
3  * El'Beem - Free Surface Fluid Simulation with the Lattice Boltzmann Method
4  * Copyright 2003-2006 Nils Thuerey
5  *
6  * Marching Cubes surface mesh generation
7  *
8  *****************************************************************************/
9
10 #include "isosurface.h"
11 #include "mcubes_tables.h"
12 #include "particletracer.h"
13 #include <algorithm>
14 #include <stdio.h>
15
16 #if (defined (__sun__) || defined (__sun)) || (!defined(linux) && (defined (__sparc) || defined (__sparc__)))
17 #include <ieeefp.h>
18 #endif
19
20 // just use default rounding for platforms where its not available
21 #ifndef round
22 #define round(x) (x)
23 #endif
24
25 /******************************************************************************
26  * Constructor
27  *****************************************************************************/
28 IsoSurface::IsoSurface(double iso) :
29         ntlGeometryObject(),
30         mSizex(-1), mSizey(-1), mSizez(-1),
31         mpData(NULL),
32   mIsoValue( iso ), 
33         mPoints(), 
34         mUseFullEdgeArrays(false),
35         mpEdgeVerticesX(NULL), mpEdgeVerticesY(NULL), mpEdgeVerticesZ(NULL),
36         mEdgeArSize(-1),
37         mIndices(),
38
39   mStart(0.0), mEnd(0.0), mDomainExtent(0.0),
40   mInitDone(false),
41         mSmoothSurface(0.0), mSmoothNormals(0.0),
42         mAcrossEdge(), mAdjacentFaces(),
43         mCutoff(-1), mCutArray(NULL), // off by default
44         mpIsoParts(NULL), mPartSize(0.), mSubdivs(0),
45         mFlagCnt(1),
46         mSCrad1(0.), mSCrad2(0.), mSCcenter(0.)
47 {
48 }
49
50
51 /******************************************************************************
52  * The real init...
53  *****************************************************************************/
54 void IsoSurface::initializeIsosurface(int setx, int sety, int setz, ntlVec3Gfx extent) 
55 {
56         // range 1-10 (max due to subd array in triangulate)
57         if(mSubdivs<1) mSubdivs=1;
58         if(mSubdivs>10) mSubdivs=10;
59
60         // init solver and size
61         mSizex = setx;
62         mSizey = sety;
63         if(setz == 1) {// 2D, create thin 2D surface
64                 setz = 5; 
65         }
66         mSizez = setz;
67         mDomainExtent = extent;
68
69         /* check triangulation size (for raytraing) */
70         if( ( mStart[0] >= mEnd[0] ) && ( mStart[1] >= mEnd[1] ) && ( mStart[2] >= mEnd[2] ) ){
71                 // extent was not set, use normalized one from parametrizer
72                 mStart = ntlVec3Gfx(0.0) - extent*0.5;
73                 mEnd = ntlVec3Gfx(0.0) + extent*0.5;
74         }
75
76   // init 
77         mIndices.clear();
78   mPoints.clear();
79
80         int nodes = mSizez*mSizey*mSizex;
81   mpData = new float[nodes];
82   for(int i=0;i<nodes;i++) { mpData[i] = 0.0; }
83
84   // allocate edge arrays  (last slices are never used...)
85         int initsize = -1;
86         if(mUseFullEdgeArrays) {
87                 mEdgeArSize = nodes;
88                 mpEdgeVerticesX = new int[nodes];
89                 mpEdgeVerticesY = new int[nodes];
90                 mpEdgeVerticesZ = new int[nodes];
91                 initsize = 3*nodes;
92         } else {
93                 int sliceNodes = 2*mSizex*mSizey*mSubdivs*mSubdivs;
94                 mEdgeArSize = sliceNodes;
95                 mpEdgeVerticesX = new int[sliceNodes];
96                 mpEdgeVerticesY = new int[sliceNodes];
97                 mpEdgeVerticesZ = new int[sliceNodes];
98                 initsize = 3*sliceNodes;
99         }
100   for(int i=0;i<mEdgeArSize;i++) { mpEdgeVerticesX[i] = mpEdgeVerticesY[i] = mpEdgeVerticesZ[i] = -1; }
101         // WARNING - make sure this is consistent with calculateMemreqEstimate
102   
103         // marching cubes are ready 
104         mInitDone = true;
105         debMsgStd("IsoSurface::initializeIsosurface",DM_MSG,"Inited, edgenodes:"<<initsize<<" subdivs:"<<mSubdivs<<" fulledg:"<<mUseFullEdgeArrays , 10);
106 }
107
108
109
110 /*! Reset all values */
111 void IsoSurface::resetAll(gfxReal val) {
112         int nodes = mSizez*mSizey*mSizex;
113   for(int i=0;i<nodes;i++) { mpData[i] = val; }
114 }
115
116
117 /******************************************************************************
118  * Destructor
119  *****************************************************************************/
120 IsoSurface::~IsoSurface( void )
121 {
122         if(mpData) delete [] mpData;
123         if(mpEdgeVerticesX) delete [] mpEdgeVerticesX;
124         if(mpEdgeVerticesY) delete [] mpEdgeVerticesY;
125         if(mpEdgeVerticesZ) delete [] mpEdgeVerticesZ;
126 }
127
128
129
130
131
132 /******************************************************************************
133  * triangulate the scalar field given by pointer
134  *****************************************************************************/
135 void IsoSurface::triangulate( void )
136 {
137   double gsx,gsy,gsz; // grid spacing in x,y,z direction
138   double px,py,pz;    // current position in grid in x,y,z direction
139   IsoLevelCube cubie;    // struct for a small subcube
140         myTime_t tritimestart = getTime(); 
141
142         if(!mpData) {
143                 errFatal("IsoSurface::triangulate","no LBM object, and no scalar field...!",SIMWORLD_INITERROR);
144                 return;
145         }
146
147   // get grid spacing (-2 to have same spacing as sim)
148   gsx = (mEnd[0]-mStart[0])/(double)(mSizex-2.0);
149   gsy = (mEnd[1]-mStart[1])/(double)(mSizey-2.0);
150   gsz = (mEnd[2]-mStart[2])/(double)(mSizez-2.0);
151
152   // clean up previous frame
153         mIndices.clear();
154         mPoints.clear();
155
156         // reset edge vertices
157   for(int i=0;i<mEdgeArSize;i++) {
158                 mpEdgeVerticesX[i] = -1;
159                 mpEdgeVerticesY[i] = -1;
160                 mpEdgeVerticesZ[i] = -1;
161         }
162
163         ntlVec3Gfx pos[8];
164         float value[8];
165         int cubeIndex;      // index entry of the cube 
166         int triIndices[12]; // vertex indices 
167         int *eVert[12];
168         IsoLevelVertex ilv;
169
170         // edges between which points?
171         const int mcEdges[24] = { 
172                 0,1,  1,2,  2,3,  3,0,
173                 4,5,  5,6,  6,7,  7,4,
174                 0,4,  1,5,  2,6,  3,7 };
175
176         const int cubieOffsetX[8] = {
177                 0,1,1,0,  0,1,1,0 };
178         const int cubieOffsetY[8] = {
179                 0,0,1,1,  0,0,1,1 };
180         const int cubieOffsetZ[8] = {
181                 0,0,0,0,  1,1,1,1 };
182
183         const int coAdd=2;
184   // let the cubes march 
185         if(mSubdivs<=1) {
186
187                 pz = mStart[2]-gsz*0.5;
188                 for(int k=1;k<(mSizez-2);k++) {
189                         pz += gsz;
190                         py = mStart[1]-gsy*0.5;
191                         for(int j=1;j<(mSizey-2);j++) {
192                                 py += gsy;
193                                 px = mStart[0]-gsx*0.5;
194                                 for(int i=1;i<(mSizex-2);i++) {
195                                         px += gsx;
196
197                                         value[0] = *getData(i  ,j  ,k  );
198                                         value[1] = *getData(i+1,j  ,k  );
199                                         value[2] = *getData(i+1,j+1,k  );
200                                         value[3] = *getData(i  ,j+1,k  );
201                                         value[4] = *getData(i  ,j  ,k+1);
202                                         value[5] = *getData(i+1,j  ,k+1);
203                                         value[6] = *getData(i+1,j+1,k+1);
204                                         value[7] = *getData(i  ,j+1,k+1);
205
206                                         // check intersections of isosurface with edges, and calculate cubie index
207                                         cubeIndex = 0;
208                                         if (value[0] < mIsoValue) cubeIndex |= 1;
209                                         if (value[1] < mIsoValue) cubeIndex |= 2;
210                                         if (value[2] < mIsoValue) cubeIndex |= 4;
211                                         if (value[3] < mIsoValue) cubeIndex |= 8;
212                                         if (value[4] < mIsoValue) cubeIndex |= 16;
213                                         if (value[5] < mIsoValue) cubeIndex |= 32;
214                                         if (value[6] < mIsoValue) cubeIndex |= 64;
215                                         if (value[7] < mIsoValue) cubeIndex |= 128;
216
217                                         // No triangles to generate?
218                                         if (mcEdgeTable[cubeIndex] == 0) {
219                                                 continue;
220                                         }
221
222                                         // where to look up if this point already exists
223                                         int edgek = 0;
224                                         if(mUseFullEdgeArrays) edgek=k;
225                                         const int baseIn = ISOLEVEL_INDEX( i+0, j+0, edgek+0);
226                                         eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
227                                         eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
228                                         eVert[ 2] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
229                                         eVert[ 3] = &mpEdgeVerticesY[ baseIn ];
230
231                                         eVert[ 4] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
232                                         eVert[ 5] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+1, j+0, edgek+1) ];
233                                         eVert[ 6] = &mpEdgeVerticesX[ ISOLEVEL_INDEX( i+0, j+1, edgek+1) ];
234                                         eVert[ 7] = &mpEdgeVerticesY[ ISOLEVEL_INDEX( i+0, j+0, edgek+1) ];
235
236                                         eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];
237                                         eVert[ 9] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+0, edgek+0) ];
238                                         eVert[10] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+1, j+1, edgek+0) ];
239                                         eVert[11] = &mpEdgeVerticesZ[ ISOLEVEL_INDEX( i+0, j+1, edgek+0) ];
240
241                                         // grid positions
242                                         pos[0] = ntlVec3Gfx(px    ,py    ,pz);
243                                         pos[1] = ntlVec3Gfx(px+gsx,py    ,pz);
244                                         pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz);
245                                         pos[3] = ntlVec3Gfx(px    ,py+gsy,pz);
246                                         pos[4] = ntlVec3Gfx(px    ,py    ,pz+gsz);
247                                         pos[5] = ntlVec3Gfx(px+gsx,py    ,pz+gsz);
248                                         pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz);
249                                         pos[7] = ntlVec3Gfx(px    ,py+gsy,pz+gsz);
250
251                                         // check all edges
252                                         for(int e=0;e<12;e++) {
253                                                 if (mcEdgeTable[cubeIndex] & (1<<e)) {
254                                                         // is the vertex already calculated?
255                                                         if(*eVert[ e ] < 0) {
256                                                                 // interpolate edge
257                                                                 const int e1 = mcEdges[e*2  ];
258                                                                 const int e2 = mcEdges[e*2+1];
259                                                                 const ntlVec3Gfx p1 = pos[ e1  ];    // scalar field pos 1
260                                                                 const ntlVec3Gfx p2 = pos[ e2  ];    // scalar field pos 2
261                                                                 const float valp1  = value[ e1  ];  // scalar field val 1
262                                                                 const float valp2  = value[ e2  ];  // scalar field val 2
263                                                                 const float mu = (mIsoValue - valp1) / (valp2 - valp1);
264
265                                                                 // init isolevel vertex
266                                                                 ilv.v = p1 + (p2-p1)*mu;
267                                                                 ilv.n = getNormal( i+cubieOffsetX[e1], j+cubieOffsetY[e1], k+cubieOffsetZ[e1]) * (1.0-mu) +
268                                                                                                 getNormal( i+cubieOffsetX[e2], j+cubieOffsetY[e2], k+cubieOffsetZ[e2]) * (    mu) ;
269                                                                 mPoints.push_back( ilv );
270
271                                                                 triIndices[e] = (mPoints.size()-1);
272                                                                 // store vertex 
273                                                                 *eVert[ e ] = triIndices[e];
274                                                         }       else {
275                                                                 // retrieve  from vert array
276                                                                 triIndices[e] = *eVert[ e ];
277                                                         }
278                                                 } // along all edges 
279                                         }
280
281                                         if( (i<coAdd+mCutoff) || (j<coAdd+mCutoff) ||
282                                                         ((mCutoff>0) && (k<coAdd)) ||// bottom layer
283                                                         (i>mSizex-2-coAdd-mCutoff) ||
284                                                         (j>mSizey-2-coAdd-mCutoff) ) {
285                                                 if(mCutArray) {
286                                                         if(k < mCutArray[j*this->mSizex+i]) continue;
287                                                 } else { continue; }
288                                         }
289
290                                         // Create the triangles... 
291                                         for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
292                                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
293                                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] );
294                                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
295                                         }
296                                         
297                                 }//i
298                         }// j
299
300                         // copy edge arrays
301                         if(!mUseFullEdgeArrays) {
302                         for(int j=0;j<(mSizey-0);j++) 
303                                 for(int i=0;i<(mSizex-0);i++) {
304                                         //int edgek = 0;
305                                         const int dst = ISOLEVEL_INDEX( i+0, j+0, 0);
306                                         const int src = ISOLEVEL_INDEX( i+0, j+0, 1);
307                                         mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
308                                         mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ];
309                                         mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
310                                         mpEdgeVerticesX[ src ]=-1;
311                                         mpEdgeVerticesY[ src ]=-1;
312                                         mpEdgeVerticesZ[ src ]=-1;
313                                 }
314                         } // */
315
316                 } // k
317
318         // precalculate normals using an approximation of the scalar field gradient 
319                 for(int ni=0;ni<(int)mPoints.size();ni++) { normalize( mPoints[ni].n ); }
320
321         } else { // subdivs
322
323 #define EDGEAR_INDEX(Ai,Aj,Ak, Bi,Bj) ((mSizex*mSizey*mSubdivs*mSubdivs*(Ak))+\
324                 (mSizex*mSubdivs*((Aj)*mSubdivs+(Bj)))+((Ai)*mSubdivs)+(Bi))
325
326 #define ISOTRILININT(fi,fj,fk) ( \
327                                 (1.-(fi))*(1.-(fj))*(1.-(fk))*orgval[0] + \
328                                 (   (fi))*(1.-(fj))*(1.-(fk))*orgval[1] + \
329                                 (   (fi))*(   (fj))*(1.-(fk))*orgval[2] + \
330                                 (1.-(fi))*(   (fj))*(1.-(fk))*orgval[3] + \
331                                 (1.-(fi))*(1.-(fj))*(   (fk))*orgval[4] + \
332                                 (   (fi))*(1.-(fj))*(   (fk))*orgval[5] + \
333                                 (   (fi))*(   (fj))*(   (fk))*orgval[6] + \
334                                 (1.-(fi))*(   (fj))*(   (fk))*orgval[7] )
335
336                 // use subdivisions
337                 gfxReal subdfac = 1./(gfxReal)(mSubdivs);
338                 gfxReal orgGsx = gsx;
339                 gfxReal orgGsy = gsy;
340                 gfxReal orgGsz = gsz;
341                 gsx *= subdfac;
342                 gsy *= subdfac;
343                 gsz *= subdfac;
344                 if(mUseFullEdgeArrays) {
345                         errMsg("IsoSurface::triangulate","Disabling mUseFullEdgeArrays!");
346                 }
347
348                 // subdiv local arrays
349                 gfxReal orgval[8];
350                 gfxReal subdAr[2][11][11]; // max 10 subdivs!
351                 ParticleObject* *arppnt = new ParticleObject*[mSizez*mSizey*mSizex];
352
353                 // construct pointers
354                 // part test
355                 int pInUse = 0;
356                 int pUsedTest = 0;
357                 // reset particles
358                 // reset list array
359                 for(int k=0;k<(mSizez);k++) 
360                         for(int j=0;j<(mSizey);j++) 
361                                 for(int i=0;i<(mSizex);i++) {
362                                         arppnt[ISOLEVEL_INDEX(i,j,k)] = NULL;
363                                 }
364                 if(mpIsoParts) {
365                         for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
366                                         pit!= mpIsoParts->getParticlesEnd(); pit++) {
367                                 if( (*pit).getActive()==false ) continue;
368                                 if( (*pit).getType()!=PART_DROP) continue;
369                                 (*pit).setNext(NULL);
370                         }
371                         // build per node lists
372                         for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
373                                         pit!= mpIsoParts->getParticlesEnd(); pit++) {
374                                 if( (*pit).getActive()==false ) continue;
375                                 if( (*pit).getType()!=PART_DROP) continue;
376                                 // check lifetime ignored here
377                                 ParticleObject *p = &(*pit);
378                                 const ntlVec3Gfx ppos = p->getPos();
379                                 const int pi= (int)round(ppos[0])+0; 
380                                 const int pj= (int)round(ppos[1])+0; 
381                                 int       pk= (int)round(ppos[2])+0;// no offset necessary
382                                 // 2d should be handled by solver. if(LBMDIM==2) { pk = 0; }
383
384                                 if(pi<0) continue;
385                                 if(pj<0) continue;
386                                 if(pk<0) continue;
387                                 if(pi>mSizex-1) continue;
388                                 if(pj>mSizey-1) continue;
389                                 if(pk>mSizez-1) continue;
390                                 ParticleObject* &pnt = arppnt[ISOLEVEL_INDEX(pi,pj,pk)]; 
391                                 if(pnt) {
392                                         // append
393                                         ParticleObject* listpnt = pnt;
394                                         while(listpnt) {
395                                                 if(!listpnt->getNext()) {
396                                                         listpnt->setNext(p); listpnt = NULL;
397                                                 } else {
398                                                         listpnt = listpnt->getNext();
399                                                 }
400                                         }
401                                 } else {
402                                         // start new list
403                                         pnt = p;
404                                 }
405                                 pInUse++;
406                         }
407                 } // mpIsoParts
408
409                 debMsgStd("IsoSurface::triangulate",DM_MSG,"Starting. Parts in use:"<<pInUse<<", Subdivs:"<<mSubdivs, 9);
410                 pz = mStart[2]-(double)(0.*gsz)-0.5*orgGsz;
411                 for(int ok=1;ok<(mSizez-2)*mSubdivs;ok++) {
412                         pz += gsz;
413                         const int k = ok/mSubdivs;
414                         if(k<=0) continue; // skip zero plane
415                         for(int j=1;j<(mSizey-2);j++) {
416                                 for(int i=1;i<(mSizex-2);i++) {
417
418                                         orgval[0] = *getData(i  ,j  ,k  );
419                                         orgval[1] = *getData(i+1,j  ,k  );
420                                         orgval[2] = *getData(i+1,j+1,k  ); // with subdivs
421                                         orgval[3] = *getData(i  ,j+1,k  );
422                                         orgval[4] = *getData(i  ,j  ,k+1);
423                                         orgval[5] = *getData(i+1,j  ,k+1);
424                                         orgval[6] = *getData(i+1,j+1,k+1); // with subdivs
425                                         orgval[7] = *getData(i  ,j+1,k+1);
426
427                                         // prebuild subsampled array slice
428                                         const int sdkOffset = ok-k*mSubdivs; 
429                                         for(int sdk=0; sdk<2; sdk++) 
430                                                 for(int sdj=0; sdj<mSubdivs+1; sdj++) 
431                                                         for(int sdi=0; sdi<mSubdivs+1; sdi++) {
432                                                                 subdAr[sdk][sdj][sdi] = ISOTRILININT(sdi*subdfac, sdj*subdfac, (sdkOffset+sdk)*subdfac);
433                                                         }
434
435                                         const int poDistOffset=2;
436                                         for(int pok=-poDistOffset; pok<1+poDistOffset; pok++) {
437                                                 if(k+pok<0) continue;
438                                                 if(k+pok>=mSizez-1) continue;
439                                         for(int poj=-poDistOffset; poj<1+poDistOffset; poj++) {
440                                                 if(j+poj<0) continue;
441                                                 if(j+poj>=mSizey-1) continue;
442                                         for(int poi=-poDistOffset; poi<1+poDistOffset; poi++) {
443                                                 if(i+poi<0) continue;
444                                                 if(i+poi>=mSizex-1) continue; 
445                                                 ParticleObject *p;
446                                                 p = arppnt[ISOLEVEL_INDEX(i+poi,j+poj,k+pok)];
447                                                 while(p) { // */
448                                         /*
449                                         for(vector<ParticleObject>::iterator pit= mpIsoParts->getParticlesBegin();
450                                                         pit!= mpIsoParts->getParticlesEnd(); pit++) { { { {
451                                                 // debug test! , full list slow!
452                                                 if(( (*pit).getActive()==false ) || ( (*pit).getType()!=PART_DROP)) continue;
453                                                 ParticleObject *p;
454                                                 p = &(*pit); // */
455
456                                                         pUsedTest++;
457                                                         ntlVec3Gfx ppos = p->getPos();
458                                                         const int spi= (int)round( (ppos[0]+1.-(gfxReal)i) *(gfxReal)mSubdivs-1.5); 
459                                                         const int spj= (int)round( (ppos[1]+1.-(gfxReal)j) *(gfxReal)mSubdivs-1.5); 
460                                                         const int spk= (int)round( (ppos[2]+1.-(gfxReal)k) *(gfxReal)mSubdivs-1.5)-sdkOffset; // why -2?
461                                                         // 2d should be handled by solver. if(LBMDIM==2) { spk = 0; }
462
463                                                         gfxReal pfLen = p->getSize()*1.5*mPartSize;  // test, was 1.1
464                                                         const gfxReal minPfLen = subdfac*0.8;
465                                                         if(pfLen<minPfLen) pfLen = minPfLen;
466                                                         //errMsg("ISOPPP"," at "<<PRINT_IJK<<"  pp"<<ppos<<"  sp"<<PRINT_VEC(spi,spj,spk)<<" pflen"<<pfLen );
467                                                         //errMsg("ISOPPP"," subdfac="<<subdfac<<" size"<<p->getSize()<<" ps"<<mPartSize );
468                                                         const int icellpsize = (int)(1.*pfLen*(gfxReal)mSubdivs)+1;
469                                                         for(int swk=-icellpsize; swk<=icellpsize; swk++) {
470                                                                 if(spk+swk<         0) { continue; }
471                                                                 if(spk+swk>         1) { continue; } // */
472                                                         for(int swj=-icellpsize; swj<=icellpsize; swj++) {
473                                                                 if(spj+swj<         0) { continue; }
474                                                                 if(spj+swj>mSubdivs+0) { continue; } // */
475                                                         for(int swi=-icellpsize; swi<=icellpsize; swi++) {
476                                                                 if(spi+swi<         0) { continue; } 
477                                                                 if(spi+swi>mSubdivs+0) { continue; } // */
478                                                                 ntlVec3Gfx cellp = ntlVec3Gfx(
479                                                                                 (1.5+(gfxReal)(spi+swi))           *subdfac + (gfxReal)(i-1),
480                                                                                 (1.5+(gfxReal)(spj+swj))           *subdfac + (gfxReal)(j-1),
481                                                                                 (1.5+(gfxReal)(spk+swk)+sdkOffset) *subdfac + (gfxReal)(k-1)
482                                                                                 );
483                                                                 //if(swi==0 && swj==0 && swk==0) subdAr[spk][spj][spi] = 1.; // DEBUG
484                                                                 // clip domain boundaries again 
485                                                                 if(cellp[0]<1.) { continue; } 
486                                                                 if(cellp[1]<1.) { continue; } 
487                                                                 if(cellp[2]<1.) { continue; } 
488                                                                 if(cellp[0]>(gfxReal)mSizex-3.) { continue; } 
489                                                                 if(cellp[1]>(gfxReal)mSizey-3.) { continue; } 
490                                                                 if(cellp[2]>(gfxReal)mSizez-3.) { continue; } 
491                                                                 gfxReal len = norm(cellp-ppos);
492                                                                 gfxReal isoadd = 0.; 
493                                                                 const gfxReal baseIsoVal = mIsoValue*1.1;
494                                                                 if(len<pfLen) { 
495                                                                         isoadd = baseIsoVal*1.;
496                                                                 } else { 
497                                                                         // falloff linear with pfLen (kernel size=2pfLen
498                                                                         isoadd = baseIsoVal*(1. - (len-pfLen)/(pfLen)); 
499                                                                 }
500                                                                 if(isoadd<0.) { continue; }
501                                                                 //errMsg("ISOPPP"," at "<<PRINT_IJK<<" sp"<<PRINT_VEC(spi+swi,spj+swj,spk+swk)<<" cellp"<<cellp<<" pp"<<ppos << " l"<< len<< " add"<< isoadd);
502                                                                 const gfxReal arval = subdAr[spk+swk][spj+swj][spi+swi];
503                                                                 if(arval>1.) { continue; }
504                                                                 subdAr[spk+swk][spj+swj][spi+swi] = arval + isoadd;
505                                                         } } }
506
507                                                         p = p->getNext();
508                                                 }
509                                         } } } // poDist loops */
510
511                                         py = mStart[1]+(((double)j-0.5)*orgGsy)-gsy;
512                                         for(int sj=0;sj<mSubdivs;sj++) {
513                                                 py += gsy;
514                                                 px = mStart[0]+(((double)i-0.5)*orgGsx)-gsx;
515                                                 for(int si=0;si<mSubdivs;si++) {
516                                                         px += gsx;
517                                                         value[0] = subdAr[0+0][sj+0][si+0]; 
518                                                         value[1] = subdAr[0+0][sj+0][si+1]; 
519                                                         value[2] = subdAr[0+0][sj+1][si+1]; 
520                                                         value[3] = subdAr[0+0][sj+1][si+0]; 
521                                                         value[4] = subdAr[0+1][sj+0][si+0]; 
522                                                         value[5] = subdAr[0+1][sj+0][si+1]; 
523                                                         value[6] = subdAr[0+1][sj+1][si+1]; 
524                                                         value[7] = subdAr[0+1][sj+1][si+0]; 
525
526                                                         // check intersections of isosurface with edges, and calculate cubie index
527                                                         cubeIndex = 0;
528                                                         if (value[0] < mIsoValue) cubeIndex |= 1;
529                                                         if (value[1] < mIsoValue) cubeIndex |= 2; // with subdivs
530                                                         if (value[2] < mIsoValue) cubeIndex |= 4;
531                                                         if (value[3] < mIsoValue) cubeIndex |= 8;
532                                                         if (value[4] < mIsoValue) cubeIndex |= 16;
533                                                         if (value[5] < mIsoValue) cubeIndex |= 32; // with subdivs
534                                                         if (value[6] < mIsoValue) cubeIndex |= 64;
535                                                         if (value[7] < mIsoValue) cubeIndex |= 128;
536
537                                                         if (mcEdgeTable[cubeIndex] >  0) {
538
539                                                         // where to look up if this point already exists
540                                                         const int edgek = 0;
541                                                         const int baseIn = EDGEAR_INDEX( i+0, j+0, edgek+0, si,sj);
542                                                         eVert[ 0] = &mpEdgeVerticesX[ baseIn ];
543                                                         eVert[ 1] = &mpEdgeVerticesY[ baseIn + 1 ];
544                                                         eVert[ 2] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
545                                                         eVert[ 3] = &mpEdgeVerticesY[ baseIn ];                             
546                                                                                                                                                                                                                                                                                                                                         
547                                                         eVert[ 4] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
548                                                         eVert[ 5] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+1,sj+0) ]; // with subdivs
549                                                         eVert[ 6] = &mpEdgeVerticesX[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+1) ];
550                                                         eVert[ 7] = &mpEdgeVerticesY[ EDGEAR_INDEX( i, j, edgek+1, si+0,sj+0) ];
551                                                                                                                                                                                                                                                                                                                                         
552                                                         eVert[ 8] = &mpEdgeVerticesZ[ baseIn ];                             
553                                                         eVert[ 9] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+0) ]; // with subdivs
554                                                         eVert[10] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+1,sj+1) ];
555                                                         eVert[11] = &mpEdgeVerticesZ[ EDGEAR_INDEX( i, j, edgek+0, si+0,sj+1) ];
556
557                                                         // grid positions
558                                                         pos[0] = ntlVec3Gfx(px    ,py    ,pz);
559                                                         pos[1] = ntlVec3Gfx(px+gsx,py    ,pz);
560                                                         pos[2] = ntlVec3Gfx(px+gsx,py+gsy,pz); // with subdivs
561                                                         pos[3] = ntlVec3Gfx(px    ,py+gsy,pz);
562                                                         pos[4] = ntlVec3Gfx(px    ,py    ,pz+gsz);
563                                                         pos[5] = ntlVec3Gfx(px+gsx,py    ,pz+gsz);
564                                                         pos[6] = ntlVec3Gfx(px+gsx,py+gsy,pz+gsz); // with subdivs
565                                                         pos[7] = ntlVec3Gfx(px    ,py+gsy,pz+gsz);
566
567                                                         // check all edges
568                                                         for(int e=0;e<12;e++) {
569                                                                 if (mcEdgeTable[cubeIndex] & (1<<e)) {
570                                                                         // is the vertex already calculated?
571                                                                         if(*eVert[ e ] < 0) {
572                                                                                 // interpolate edge
573                                                                                 const int e1 = mcEdges[e*2  ];
574                                                                                 const int e2 = mcEdges[e*2+1];
575                                                                                 const ntlVec3Gfx p1 = pos[ e1  ];   // scalar field pos 1
576                                                                                 const ntlVec3Gfx p2 = pos[ e2  ];   // scalar field pos 2
577                                                                                 const float valp1  = value[ e1  ];  // scalar field val 1
578                                                                                 const float valp2  = value[ e2  ];  // scalar field val 2
579                                                                                 const float mu = (mIsoValue - valp1) / (valp2 - valp1);
580
581                                                                                 // init isolevel vertex
582                                                                                 ilv.v = p1 + (p2-p1)*mu; // with subdivs
583                                                                                 mPoints.push_back( ilv );
584                                                                                 triIndices[e] = (mPoints.size()-1);
585                                                                                 // store vertex 
586                                                                                 *eVert[ e ] = triIndices[e]; 
587                                                                         }       else {
588                                                                                 // retrieve  from vert array
589                                                                                 triIndices[e] = *eVert[ e ];
590                                                                         }
591                                                                 } // along all edges 
592                                                         }
593                                                         // removed cutoff treatment...
594
595                                                         // Create the triangles... 
596                                                         for(int e=0; mcTriTable[cubeIndex][e]!=-1; e+=3) {
597                                                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+0] ] );
598                                                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+1] ] ); // with subdivs
599                                                                 mIndices.push_back( triIndices[ mcTriTable[cubeIndex][e+2] ] );
600                                                                 //errMsg("TTT"," i1"<<mIndices[mIndices.size()-3]<<" "<< " i2"<<mIndices[mIndices.size()-2]<<" "<< " i3"<<mIndices[mIndices.size()-1]<<" "<< mIndices.size() );
601                                                         }
602
603                                                         } // triangles in edge table?
604                                                         
605                                                 }//si
606                                         }// sj
607
608                                 }//i
609                         }// j
610
611                         // copy edge arrays
612                         for(int j=0;j<(mSizey-0)*mSubdivs;j++) 
613                                 for(int i=0;i<(mSizex-0)*mSubdivs;i++) {
614                                         //int edgek = 0;
615                                         const int dst = EDGEAR_INDEX( 0, 0, 0, i,j);
616                                         const int src = EDGEAR_INDEX( 0, 0, 1, i,j);
617                                         mpEdgeVerticesX[ dst ] = mpEdgeVerticesX[ src ];
618                                         mpEdgeVerticesY[ dst ] = mpEdgeVerticesY[ src ]; // with subdivs
619                                         mpEdgeVerticesZ[ dst ] = mpEdgeVerticesZ[ src ];
620                                         mpEdgeVerticesX[ src ]=-1;
621                                         mpEdgeVerticesY[ src ]=-1; // with subdivs
622                                         mpEdgeVerticesZ[ src ]=-1;
623                                 }
624                         // */
625
626                 } // ok, k subdiv loop
627
628                 //delete [] subdAr;
629                 delete [] arppnt;
630                 computeNormals();
631         } // with subdivs
632
633         // perform smoothing
634         float smoSubdfac = 1.;
635         if(mSubdivs>0) {
636                 //smoSubdfac = 1./(float)(mSubdivs);
637                 smoSubdfac = pow(0.55,(double)mSubdivs); // slightly stronger
638         }
639         if(mSmoothSurface>0. || mSmoothNormals>0.) debMsgStd("IsoSurface::triangulate",DM_MSG,"Smoothing...",10);
640         if(mSmoothSurface>0.0) { 
641                 smoothSurface(mSmoothSurface*smoSubdfac, (mSmoothNormals<=0.0) ); 
642         }
643         if(mSmoothNormals>0.0) { 
644                 smoothNormals(mSmoothNormals*smoSubdfac); 
645         }
646
647         myTime_t tritimeend = getTime(); 
648         debMsgStd("IsoSurface::triangulate",DM_MSG,"took "<< getTimeString(tritimeend-tritimestart)<<", S("<<mSmoothSurface<<","<<mSmoothNormals<<"),"<<
649                         " verts:"<<mPoints.size()<<" tris:"<<(mIndices.size()/3)<<" subdivs:"<<mSubdivs
650                  , 10 );
651         if(mpIsoParts) debMsgStd("IsoSurface::triangulate",DM_MSG,"parts:"<<mpIsoParts->getNumParticles(), 10);
652 }
653
654
655         
656
657
658 /******************************************************************************
659  * Get triangles for rendering
660  *****************************************************************************/
661 void IsoSurface::getTriangles(double t, vector<ntlTriangle> *triangles, 
662                                                                                                          vector<ntlVec3Gfx> *vertices, 
663                                                                                                          vector<ntlVec3Gfx> *normals, int objectId )
664 {
665         if(!mInitDone) {
666                 debugOut("IsoSurface::getTriangles warning: Not initialized! ", 10);
667                 return;
668         }
669         t = 0.;
670         //return; // DEBUG
671
672   /* triangulate field */
673   triangulate();
674         //errMsg("TRIS"," "<<mIndices.size() );
675
676         // new output with vertice reuse
677         int iniVertIndex = (*vertices).size();
678         int iniNormIndex = (*normals).size();
679         if(iniVertIndex != iniNormIndex) {
680                 errFatal("getTriangles Error","For '"<<mName<<"': Vertices and normal array sizes to not match!!!",SIMWORLD_GENERICERROR);
681                 return; 
682         }
683         //errMsg("NM"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
684         //errMsg("NM"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
685
686   for(int i=0;i<(int)mPoints.size();i++) {
687                 vertices->push_back( mPoints[i].v );
688         }
689   for(int i=0;i<(int)mPoints.size();i++) {
690                 normals->push_back( mPoints[i].n );
691         }
692
693         //errMsg("N2"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
694         //errMsg("N2"," ovs"<<mVertices.size()<<" ons"<<mVertNormals.size()<<" ots"<<mIndices.size() );
695
696   for(int i=0;i<(int)mIndices.size();i+=3) {
697                 const int smooth = 1;
698     int t1 = mIndices[i];
699     int t2 = mIndices[i+1];
700                 int t3 = mIndices[i+2];
701                 //errMsg("NM"," tri"<<t1<<" "<<t2<<" "<<t3 );
702
703                 ntlTriangle tri;
704
705                 tri.getPoints()[0] = t1+iniVertIndex;
706                 tri.getPoints()[1] = t2+iniVertIndex;
707                 tri.getPoints()[2] = t3+iniVertIndex;
708
709                 /* init flags */
710                 int flag = 0; 
711                 if(getVisible()){ flag |= TRI_GEOMETRY; }
712                 if(getCastShadows() ) { 
713                         flag |= TRI_CASTSHADOWS; } 
714
715                 /* init geo init id */
716                 int geoiId = getGeoInitId(); 
717                 if(geoiId > 0) { 
718                         flag |= (1<< (geoiId+4)); 
719                         flag |= mGeoInitType; 
720                 } 
721
722                 tri.setFlags( flag );
723
724                 /* triangle normal missing */
725                 tri.setNormal( ntlVec3Gfx(0.0) );
726                 tri.setSmoothNormals( smooth );
727                 tri.setObjectId( objectId );
728                 triangles->push_back( tri ); 
729         }
730         //errMsg("N3"," ivi"<<iniVertIndex<<" ini"<<iniNormIndex<<" vs"<<vertices->size()<<" ns"<<normals->size()<<" ts"<<triangles->size() );
731         return;
732 }
733
734
735
736 inline ntlVec3Gfx IsoSurface::getNormal(int i, int j,int k) {
737         // WARNING - this requires a security boundary layer... 
738         ntlVec3Gfx ret(0.0);
739         ret[0] = *getData(i-1,j  ,k  ) - 
740                  *getData(i+1,j  ,k  );
741         ret[1] = *getData(i  ,j-1,k  ) - 
742                  *getData(i  ,j+1,k  );
743         ret[2] = *getData(i  ,j  ,k-1  ) - 
744                  *getData(i  ,j  ,k+1  );
745         return ret;
746 }
747
748
749
750
751 /******************************************************************************
752  * 
753  * Surface improvement, inspired by trimesh2 library
754  * (http://www.cs.princeton.edu/gfx/proj/trimesh2/)
755  * 
756  *****************************************************************************/
757
758 void IsoSurface::setSmoothRad(float radi1, float radi2, ntlVec3Gfx mscc) {
759         mSCrad1 = radi1*radi1;
760         mSCrad2 = radi2*radi2;
761         mSCcenter = mscc;
762 }
763
764 // compute normals for all generated triangles
765 void IsoSurface::computeNormals() {
766   for(int i=0;i<(int)mPoints.size();i++) {
767                 mPoints[i].n = ntlVec3Gfx(0.);
768         }
769
770   for(int i=0;i<(int)mIndices.size();i+=3) {
771     const int t1 = mIndices[i];
772     const int t2 = mIndices[i+1];
773                 const int t3 = mIndices[i+2];
774                 const ntlVec3Gfx p1 = mPoints[t1].v;
775                 const ntlVec3Gfx p2 = mPoints[t2].v;
776                 const ntlVec3Gfx p3 = mPoints[t3].v;
777                 const ntlVec3Gfx n1=p1-p2;
778                 const ntlVec3Gfx n2=p2-p3;
779                 const ntlVec3Gfx n3=p3-p1;
780                 const gfxReal len1 = normNoSqrt(n1);
781                 const gfxReal len2 = normNoSqrt(n2);
782                 const gfxReal len3 = normNoSqrt(n3);
783                 const ntlVec3Gfx norm = cross(n1,n2);
784                 mPoints[t1].n += norm * (1./(len1*len3));
785                 mPoints[t2].n += norm * (1./(len1*len2));
786                 mPoints[t3].n += norm * (1./(len2*len3));
787         }
788
789   for(int i=0;i<(int)mPoints.size();i++) {
790                 normalize(mPoints[i].n);
791         }
792 }
793
794 // Diffuse a vector field at 1 vertex, weighted by
795 // a gaussian of width 1/sqrt(invsigma2)
796 bool IsoSurface::diffuseVertexField(ntlVec3Gfx *field, const int pointerScale, int src, float invsigma2, ntlVec3Gfx &target)
797 {
798         if((neighbors[src].size()<1) || (pointareas[src]<=0.0)) return 0;
799         const ntlVec3Gfx srcp = mPoints[src].v;
800         const ntlVec3Gfx srcn = mPoints[src].n;
801         if(mSCrad1>0.0 && mSCrad2>0.0) {
802                 ntlVec3Gfx dp = mSCcenter-srcp; dp[2] = 0.0; // only xy-plane
803                 float rd = normNoSqrt(dp);
804                 if(rd > mSCrad2) {
805                         return 0;
806                 } else if(rd > mSCrad1) {
807                         // optimize?
808                         float org = 1.0/sqrt(invsigma2);
809                         org *= (1.0- (rd-mSCrad1) / (mSCrad2-mSCrad1));
810                         invsigma2 = 1.0/(org*org);
811                         //errMsg("TRi","p"<<srcp<<" rd:"<<rd<<" r1:"<<mSCrad1<<" r2:"<<mSCrad2<<" org:"<<org<<" is:"<<invsigma2);
812                 } else {
813                 }
814         }
815         target = ntlVec3Gfx(0.0);
816         target += *(field+pointerScale*src) *pointareas[src];
817         float smstrSum = pointareas[src];
818
819         int flag = mFlagCnt; 
820         mFlagCnt++;
821         flags[src] = flag;
822         mDboundary = neighbors[src];
823         while (!mDboundary.empty()) {
824                 const int bbn = mDboundary.back();
825                 mDboundary.pop_back();
826                 if(flags[bbn]==flag) continue;
827                 flags[bbn] = flag;
828
829                 // normal check
830                 const float nvdot = dot(srcn, mPoints[bbn].n); // faster than before d2 calc?
831                 if(nvdot <= 0.0f) continue;
832
833                 // gaussian weight of width 1/sqrt(invsigma2)
834                 const float d2 = invsigma2 * normNoSqrt(mPoints[bbn].v - srcp);
835                 if(d2 >= 9.0f) continue;
836
837                 // aggressive smoothing factor
838                 float smstr = nvdot * pointareas[bbn];
839                 // Accumulate weight times field at neighbor
840                 target += *(field+pointerScale*bbn)*smstr;
841                 smstrSum += smstr;
842
843                 for(int i = 0; i < (int)neighbors[bbn].size(); i++) {
844                         const int nn = neighbors[bbn][i];
845                         if (flags[nn] == flag) continue;
846                         mDboundary.push_back(nn);
847                 }
848         }
849         target /= smstrSum;
850         return 1;
851 }
852
853         
854 // perform smoothing of the surface (and possible normals)
855 void IsoSurface::smoothSurface(float sigma, bool normSmooth)
856 {
857         int nv = mPoints.size();
858         if ((int)flags.size() != nv) flags.resize(nv);
859         int nf = mIndices.size()/3;
860
861         { // need neighbors
862                 vector<int> numneighbors(mPoints.size());
863                 int i;
864                 for (i = 0; i < (int)mIndices.size()/3; i++) {
865                         numneighbors[mIndices[i*3+0]]++;
866                         numneighbors[mIndices[i*3+1]]++;
867                         numneighbors[mIndices[i*3+2]]++;
868                 }
869
870                 neighbors.clear();
871                 neighbors.resize(mPoints.size());
872                 for (i = 0; i < (int)mPoints.size(); i++) {
873                         neighbors[i].clear();
874                         neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
875                 }
876
877                 for (i = 0; i < (int)mIndices.size()/3; i++) {
878                         for (int j = 0; j < 3; j++) {
879                                 vector<int> &me = neighbors[ mIndices[i*3+j]];
880                                 int n1 =  mIndices[i*3+((j+1)%3)];
881                                 int n2 =  mIndices[i*3+((j+2)%3)];
882                                 if (std::find(me.begin(), me.end(), n1) == me.end())
883                                         me.push_back(n1);
884                                 if (std::find(me.begin(), me.end(), n2) == me.end())
885                                         me.push_back(n2);
886                         }
887                 }
888         } // need neighbor
889
890         { // need pointarea
891                 pointareas.clear();
892                 pointareas.resize(nv);
893                 cornerareas.clear();
894                 cornerareas.resize(nf);
895
896                 for (int i = 0; i < nf; i++) {
897                         // Edges
898                         ntlVec3Gfx e[3] = { 
899                                 mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
900                                 mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
901                                 mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
902
903                         // Compute corner weights
904                         float area = 0.5f * norm( cross(e[0], e[1]));
905                         float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
906                         float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
907                                         l2[1] * (l2[2] + l2[0] - l2[1]),
908                                         l2[2] * (l2[0] + l2[1] - l2[2]) };
909                         if (ew[0] <= 0.0f) {
910                                 cornerareas[i][1] = -0.25f * l2[2] * area /
911                                                                 dot(e[0] , e[2]);
912                                 cornerareas[i][2] = -0.25f * l2[1] * area /
913                                                                 dot(e[0] , e[1]);
914                                 cornerareas[i][0] = area - cornerareas[i][1] -
915                                                                 cornerareas[i][2];
916                         } else if (ew[1] <= 0.0f) {
917                                 cornerareas[i][2] = -0.25f * l2[0] * area /
918                                                                 dot(e[1] , e[0]);
919                                 cornerareas[i][0] = -0.25f * l2[2] * area /
920                                                                 dot(e[1] , e[2]);
921                                 cornerareas[i][1] = area - cornerareas[i][2] -
922                                                                 cornerareas[i][0];
923                         } else if (ew[2] <= 0.0f) {
924                                 cornerareas[i][0] = -0.25f * l2[1] * area /
925                                                                 dot(e[2] , e[1]);
926                                 cornerareas[i][1] = -0.25f * l2[0] * area /
927                                                                 dot(e[2] , e[0]);
928                                 cornerareas[i][2] = area - cornerareas[i][0] -
929                                                                 cornerareas[i][1];
930                         } else {
931                                 float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
932                                 for (int j = 0; j < 3; j++)
933                                         cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
934                                                                                          ew[(j+2)%3]);
935                         }
936
937                         // NT important, check this...
938 #ifndef WIN32
939                         if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6;
940                         if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6;
941                         if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6;
942 #else // WIN32
943                         // FIXME check as well...
944                         if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6;
945                         if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6;
946                         if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6;
947 #endif // WIN32
948
949                         pointareas[mIndices[i*3+0]] += cornerareas[i][0];
950                         pointareas[mIndices[i*3+1]] += cornerareas[i][1];
951                         pointareas[mIndices[i*3+2]] += cornerareas[i][2];
952                 }
953
954         } // need pointarea
955         // */
956
957         float invsigma2 = 1.0f / (sigma*sigma);
958
959         vector<ntlVec3Gfx> dflt(nv);
960         for (int i = 0; i < nv; i++) {
961                 if(diffuseVertexField( &mPoints[0].v, 2,
962                                    i, invsigma2, dflt[i])) {
963                         // Just keep the displacement
964                         dflt[i] -= mPoints[i].v;
965                 } else { dflt[i] = 0.0; } //?mPoints[i].v; }
966         }
967
968         // Slightly better small-neighborhood approximation
969         for (int i = 0; i < nf; i++) {
970                 ntlVec3Gfx c = mPoints[mIndices[i*3+0]].v +
971                           mPoints[mIndices[i*3+1]].v +
972                           mPoints[mIndices[i*3+2]].v;
973                 c /= 3.0f;
974                 for (int j = 0; j < 3; j++) {
975                         int v = mIndices[i*3+j];
976                         ntlVec3Gfx d =(c - mPoints[v].v) * 0.5f;
977                         dflt[v] += d * (cornerareas[i][j] /
978                                    pointareas[mIndices[i*3+j]] *
979                                    exp(-0.5f * invsigma2 * normNoSqrt(d)) );
980                 }
981         }
982
983         // Filter displacement field
984         vector<ntlVec3Gfx> dflt2(nv);
985         for (int i = 0; i < nv; i++) {
986                 if(diffuseVertexField( &dflt[0], 1,
987                                    i, invsigma2, dflt2[i])) { }
988                 else { /*mPoints[i].v=0.0;*/ dflt2[i] = 0.0; }//dflt2[i]; }
989         }
990
991         // Update vertex positions
992         for (int i = 0; i < nv; i++) {
993                 mPoints[i].v += dflt[i] - dflt2[i]; // second Laplacian
994         }
995
996         // when normals smoothing off, this cleans up quite well
997         // costs ca. 50% additional time though
998         float nsFac = 1.5f;
999         if(normSmooth) { float ninvsigma2 = 1.0f / (nsFac*nsFac*sigma*sigma);
1000                 for (int i = 0; i < nv; i++) {
1001                         if( diffuseVertexField( &mPoints[0].n, 2, i, ninvsigma2, dflt[i]) ) {
1002                                 normalize(dflt[i]);
1003                         } else {
1004                                 dflt[i] = mPoints[i].n;
1005                         }
1006                 }
1007                 for (int i = 0; i < nv; i++) {
1008                         mPoints[i].n = dflt[i];
1009                 } 
1010         } // smoothNormals copy */
1011
1012         //errMsg("SMSURF","done v:"<<sigma); // DEBUG
1013 }
1014
1015 // only smoothen the normals
1016 void IsoSurface::smoothNormals(float sigma) {
1017         // reuse from smoothSurface
1018         if(neighbors.size() != mPoints.size()) { 
1019                 // need neighbor
1020                 vector<int> numneighbors(mPoints.size());
1021                 int i;
1022                 for (i = 0; i < (int)mIndices.size()/3; i++) {
1023                         numneighbors[mIndices[i*3+0]]++;
1024                         numneighbors[mIndices[i*3+1]]++;
1025                         numneighbors[mIndices[i*3+2]]++;
1026                 }
1027
1028                 neighbors.clear();
1029                 neighbors.resize(mPoints.size());
1030                 for (i = 0; i < (int)mPoints.size(); i++) {
1031                         neighbors[i].clear();
1032                         neighbors[i].reserve(numneighbors[i]+2); // Slop for boundaries
1033                 }
1034
1035                 for (i = 0; i < (int)mIndices.size()/3; i++) {
1036                         for (int j = 0; j < 3; j++) {
1037                                 vector<int> &me = neighbors[ mIndices[i*3+j]];
1038                                 int n1 =  mIndices[i*3+((j+1)%3)];
1039                                 int n2 =  mIndices[i*3+((j+2)%3)];
1040                                 if (std::find(me.begin(), me.end(), n1) == me.end())
1041                                         me.push_back(n1);
1042                                 if (std::find(me.begin(), me.end(), n2) == me.end())
1043                                         me.push_back(n2);
1044                         }
1045                 }
1046         } // need neighbor
1047
1048         { // need pointarea
1049                 int nf = mIndices.size()/3, nv = mPoints.size();
1050                 pointareas.clear();
1051                 pointareas.resize(nv);
1052                 cornerareas.clear();
1053                 cornerareas.resize(nf);
1054
1055                 for (int i = 0; i < nf; i++) {
1056                         // Edges
1057                         ntlVec3Gfx e[3] = { 
1058                                 mPoints[mIndices[i*3+2]].v - mPoints[mIndices[i*3+1]].v,
1059                                 mPoints[mIndices[i*3+0]].v - mPoints[mIndices[i*3+2]].v,
1060                                 mPoints[mIndices[i*3+1]].v - mPoints[mIndices[i*3+0]].v };
1061
1062                         // Compute corner weights
1063                         float area = 0.5f * norm( cross(e[0], e[1]));
1064                         float l2[3] = { normNoSqrt(e[0]), normNoSqrt(e[1]), normNoSqrt(e[2]) };
1065                         float ew[3] = { l2[0] * (l2[1] + l2[2] - l2[0]),
1066                                         l2[1] * (l2[2] + l2[0] - l2[1]),
1067                                         l2[2] * (l2[0] + l2[1] - l2[2]) };
1068                         if (ew[0] <= 0.0f) {
1069                                 cornerareas[i][1] = -0.25f * l2[2] * area /
1070                                                                 dot(e[0] , e[2]);
1071                                 cornerareas[i][2] = -0.25f * l2[1] * area /
1072                                                                 dot(e[0] , e[1]);
1073                                 cornerareas[i][0] = area - cornerareas[i][1] -
1074                                                                 cornerareas[i][2];
1075                         } else if (ew[1] <= 0.0f) {
1076                                 cornerareas[i][2] = -0.25f * l2[0] * area /
1077                                                                 dot(e[1] , e[0]);
1078                                 cornerareas[i][0] = -0.25f * l2[2] * area /
1079                                                                 dot(e[1] , e[2]);
1080                                 cornerareas[i][1] = area - cornerareas[i][2] -
1081                                                                 cornerareas[i][0];
1082                         } else if (ew[2] <= 0.0f) {
1083                                 cornerareas[i][0] = -0.25f * l2[1] * area /
1084                                                                 dot(e[2] , e[1]);
1085                                 cornerareas[i][1] = -0.25f * l2[0] * area /
1086                                                                 dot(e[2] , e[0]);
1087                                 cornerareas[i][2] = area - cornerareas[i][0] -
1088                                                                 cornerareas[i][1];
1089                         } else {
1090                                 float ewscale = 0.5f * area / (ew[0] + ew[1] + ew[2]);
1091                                 for (int j = 0; j < 3; j++)
1092                                         cornerareas[i][j] = ewscale * (ew[(j+1)%3] +
1093                                                                                          ew[(j+2)%3]);
1094                         }
1095
1096                         // NT important, check this...
1097 #ifndef WIN32
1098                         if(! finite(cornerareas[i][0]) ) cornerareas[i][0]=1e-6;
1099                         if(! finite(cornerareas[i][1]) ) cornerareas[i][1]=1e-6;
1100                         if(! finite(cornerareas[i][2]) ) cornerareas[i][2]=1e-6;
1101 #else // WIN32
1102                         // FIXME check as well...
1103                         if(! (cornerareas[i][0]>=0.0) ) cornerareas[i][0]=1e-6;
1104                         if(! (cornerareas[i][1]>=0.0) ) cornerareas[i][1]=1e-6;
1105                         if(! (cornerareas[i][2]>=0.0) ) cornerareas[i][2]=1e-6;
1106 #endif // WIN32
1107
1108                         pointareas[mIndices[i*3+0]] += cornerareas[i][0];
1109                         pointareas[mIndices[i*3+1]] += cornerareas[i][1];
1110                         pointareas[mIndices[i*3+2]] += cornerareas[i][2];
1111                 }
1112
1113         } // need pointarea
1114
1115         int nv = mPoints.size();
1116         if ((int)flags.size() != nv) flags.resize(nv);
1117         float invsigma2 = 1.0f / (sigma*sigma);
1118
1119         vector<ntlVec3Gfx> nflt(nv);
1120         for (int i = 0; i < nv; i++) {
1121                 if(diffuseVertexField( &mPoints[0].n, 2, i, invsigma2, nflt[i])) {
1122                         normalize(nflt[i]);
1123                 } else { nflt[i]=mPoints[i].n; }
1124         }
1125
1126         // copy results
1127         for (int i = 0; i < nv; i++) { mPoints[i].n = nflt[i]; }
1128 }
1129
1130