1 /*************************************************************************
2  *                                                                       *
3  * Vega FEM Simulation Library Version 3.1                               *
4  *                                                                       *
5  * "distance field" library , Copyright (C) 2007 CMU, 2016 USC           *
6  * All rights reserved.                                                  *
7  *                                                                       *
8  * Code author: Hongyi Xu, Jernej Barbic                                 *
9  * http://www.jernejbarbic.com/code                                      *
10  *                                                                       *
11  * Research: Jernej Barbic, Hongyi Xu, Doug L. James                     *
12  *                                                                       *
13  * Funding: National Science Foundation, Link Foundation,                *
14  *          Zumberge Research and Innovation Fund at USC                 *
15  *                                                                       *
16  * This library is free software; you can redistribute it and/or         *
17  * modify it under the terms of the BSD-style license that is            *
18  * included with this library in the file LICENSE.txt                    *
19  *                                                                       *
20  * This library is distributed in the hope that it will be useful,       *
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file     *
23  * LICENSE.TXT for more details.                                         *
24  *                                                                       *
25  *************************************************************************/
26 
27 /*
28   Narrowband distance field computation.
29 */
30 
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <float.h>
35 #include <fstream>
36 #include <set>
37 #include "triangle.h"
38 #include "boundingBox.h"
39 #include "distanceFieldNarrowBand.h"
40 #include "objMeshOrientable.h"
41 #include "objMeshOctree.h"
42 #include "trilinearInterpolation.h"
43 #include "vegalong.h"
44 using namespace std;
45 
GetFilesize(const char * filename)46 vegalong DistanceFieldNarrowBand::GetFilesize(const char *filename)
47 {
48   FILE * f = fopen(filename, "rb");  /* open the file in read only */
49 
50   vegalong size = 0;
51   if (fseek(f, 0, SEEK_END) == 0) /* seek was successful */
52       size = ftell(f);
53   fclose(f);
54   return size;
55 }
56 
DistanceFieldNarrowBand()57 DistanceFieldNarrowBand::DistanceFieldNarrowBand() : DistanceFieldBase()
58 {
59   gridPointStatus = NULL;
60   signFieldFlooded = 0;
61 }
62 
~DistanceFieldNarrowBand()63 DistanceFieldNarrowBand::~DistanceFieldNarrowBand()
64 {
65   free(gridPointStatus);
66 }
67 
68 // the routines for signed and unsigned distance field computation
69 #define COMPUTE_SIGNED_FIELD_NARROWBAND
70   #define COMPUTE_INTERIOR_FIELD_NARROWBAND
71     #include "computeFieldNarrowBand.cpp"
72   #undef COMPUTE_INTERIOR_FIELD_NARROWBAND
73     #include "computeFieldNarrowBand.cpp"
74 #undef COMPUTE_SIGNED_FIELD_NARROWBAND
75   #include "computeFieldNarrowBand.cpp"
76 
load(const std::string & filename)77 int DistanceFieldNarrowBand::load(const std::string& filename)
78 {
79   ifstream fin(filename.c_str(),ios::binary);
80   if (!fin)
81     return 1;
82 
83   fin.read((char*)&resolutionX, sizeof(int));
84 
85   // the type of data (single-precision or double-precision) is encoded as the sign of the x-resolution
86   bool floatData = (resolutionX < 0);
87   if (floatData)
88     resolutionX = -resolutionX;
89 
90   fin.read((char*)&resolutionY, sizeof(int));
91 
92   if (resolutionY < 0) // negative second resolution implies closest point data
93     return 1;
94 
95   fin.read((char*)&resolutionZ, sizeof(int));
96 
97   vegalong size =  (resolutionZ + 1) * (resolutionY + 1) * (resolutionX + 1);
98   gridPointStatus = (char*) realloc (gridPointStatus, sizeof(char) * size);
99   for(vegalong i=0; i<size; i++)
100     gridPointStatus[i] = DistanceFieldNarrowBand::EXTERIOR_UNCOMPUTED;
101 
102   fin.read((char*)&(bmin_[0]), sizeof(double));
103   fin.read((char*)&(bmin_[1]), sizeof(double));
104   fin.read((char*)&(bmin_[2]), sizeof(double));
105 
106   fin.read((char*)&(bmax_[0]), sizeof(double));
107   fin.read((char*)&(bmax_[1]), sizeof(double));
108   fin.read((char*)&(bmax_[2]), sizeof(double));
109 
110   setGridParameters();
111 
112   int numGridPoints = 0;
113   fin.read((char*)&numGridPoints, sizeof(int));
114 
115   int i, j, k;
116   double * buffer = (double*)malloc(sizeof(double));
117   for(int p = 0; p < numGridPoints; p++)
118   {
119     fin.read((char*)&i, sizeof(int));
120     fin.read((char*)&j, sizeof(int));
121     fin.read((char*)&k, sizeof(int));
122     if (floatData)
123       fin.read((char*)buffer, sizeof(float));
124     else
125       fin.read((char*)buffer, sizeof(double));
126 
127     distanceData.insert(pair<gridPoint, float>(gridPoint(i,j,k), *(float*)(buffer)));
128   }
129   free(buffer);
130 
131   finalizeGridPointStatus();
132 
133   fin.close();
134 
135   return 0;
136 }
137 
saveToText(const std::string & filename)138 int DistanceFieldNarrowBand::saveToText(const std::string& filename)
139 {
140   FILE * fout = fopen((char*)filename.c_str(), "w");
141   if (!fout)
142     return 1;
143 
144   fprintf(fout, "%d\n", resolutionX);
145   fprintf(fout, "%d\n", resolutionY);
146   fprintf(fout, "%d\n", resolutionZ);
147 
148   for (map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
149   {
150     gridPoint v = it->first;
151     fprintf(fout, "%d %d %d %G\n", v.first, v.second, v.third, it->second);
152   }
153 
154   fclose(fout);
155 
156   return 0;
157 }
158 
saveToDistanceField(const std::string & filename,bool doublePrecision)159 int DistanceFieldNarrowBand::saveToDistanceField(const std::string& filename, bool doublePrecision)
160 {
161   if (doublePrecision)
162     printf("Error: double precision output is not supported. Using float instead.\n");
163   doublePrecision = false;
164 
165   ofstream fout;
166   fout.open(filename.c_str(),ios::binary);
167 
168   int data = resolutionX;
169   if (!doublePrecision)
170     data = -data;
171 
172   fout.write((char*)&data,sizeof(int));
173   fout.write((char*)&resolutionY,sizeof(int));
174   fout.write((char*)&resolutionZ,sizeof(int));
175 
176   fout.write((char*)&(bmin_[0]),sizeof(double));
177   fout.write((char*)&(bmin_[1]),sizeof(double));
178   fout.write((char*)&(bmin_[2]),sizeof(double));
179 
180   fout.write((char*)&(bmax_[0]),sizeof(double));
181   fout.write((char*)&(bmax_[1]),sizeof(double));
182   fout.write((char*)&(bmax_[2]),sizeof(double));
183 
184   int flag = 1;
185   for(vegalong k=0; k<=resolutionZ; k++)
186     for(vegalong j=0; j<=resolutionY; j++)
187       for(vegalong i=0; i<=resolutionX; i++)
188       {
189         float dist = distance(i,j,k);
190         if (fabs(dist) != FLT_MAX)
191           flag = (dist >= 0) ? 1 : -1;
192         else
193         {
194           if (flag == -1)
195             dist = -FLT_MAX;
196         }
197         fout.write((char*)&dist, sizeof(float));
198       }
199   fout.close();
200 
201   return 0;
202 }
203 
save(const std::string & filename,bool doublePrecision)204 int DistanceFieldNarrowBand::save(const std::string& filename, bool doublePrecision)
205 {
206   if (doublePrecision)
207     printf("Error: double precision output is not supported. Using float instead.\n");
208   doublePrecision = false;
209 
210   ofstream fout;
211   fout.open(filename.c_str(),ios::binary);
212 
213   int data = resolutionX;
214   if (!doublePrecision)
215     data = -data;
216 
217   fout.write((char*)&data,sizeof(int));
218   fout.write((char*)&resolutionY,sizeof(int));
219   fout.write((char*)&resolutionZ,sizeof(int));
220 
221   fout.write((char*)&(bmin_[0]),sizeof(double));
222   fout.write((char*)&(bmin_[1]),sizeof(double));
223   fout.write((char*)&(bmin_[2]),sizeof(double));
224 
225   fout.write((char*)&(bmax_[0]),sizeof(double));
226   fout.write((char*)&(bmax_[1]),sizeof(double));
227   fout.write((char*)&(bmax_[2]),sizeof(double));
228 
229   vegalong numGridPoints = distanceData.size();
230   fout.write((char*)&(numGridPoints),sizeof(int));
231 
232   for (map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
233   {
234     gridPoint v = it->first;
235     fout.write((char*)&(v.first), sizeof(int));
236     fout.write((char*)&(v.second), sizeof(int));
237     fout.write((char*)&(v.third), sizeof(int));
238     float value = it->second;
239     fout.write((char*)&(value), sizeof(float));
240   }
241 
242   fout.close();
243 
244   return 0;
245 }
246 
finalizeGridPointStatus()247 void DistanceFieldNarrowBand::finalizeGridPointStatus()
248 {
249   // assumption: bounding box covers the entire geometry
250 
251   int flag = 1;
252   vegalong index = 0;
253   for(vegalong k=0; k<=resolutionZ; k++)
254     for(vegalong j=0; j<=resolutionY; j++)
255       for(vegalong i=0; i<=resolutionX; i++)
256       {
257         float dist = distance(i,j,k);
258         if ((dist == FLT_MAX) || (dist == -FLT_MAX))
259         {
260           gridPointStatus[index] = (flag == -1) ? DistanceFieldNarrowBand::INTERIOR_UNCOMPUTED : DistanceFieldNarrowBand::EXTERIOR_UNCOMPUTED;
261         }
262         else
263         {
264           flag = (dist >= 0) ? 1 : -1;
265           gridPointStatus[index] = DistanceFieldNarrowBand::COMPUTED;
266         }
267 
268         index++;
269       }
270 }
271 
272 typedef struct
273 {
274   int i,j,k;
275   int di,dj,dk;
276   double fieldDist, gridDist, relError;
277 } errorData;
278 
279 struct more_errorData : public std::binary_function< errorData, errorData, bool > {
operator ()more_errorData280   bool operator()(const errorData& x, const errorData& y) {
281     return((x.relError) > (y.relError));
282   }
283 };
284 
sanityCheck()285 bool DistanceFieldNarrowBand::sanityCheck()
286 {
287   //double diagonal = sqrt(gridX*gridX + gridY*gridY + gridZ*gridZ);
288 
289   bool result = true;
290   int count = 0;
291 
292   const int numErrorsPrinted = 3;
293 
294   vector<errorData> relErrors;
295   errorData emptyEntry = {0,0,0,0,0,0,0.0,0.0,-1.0};
296   for(int i=0; i<numErrorsPrinted; i++)
297    relErrors.push_back(emptyEntry);
298 
299   int counter = 0;
300   for (map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
301   {
302     gridPoint v = it->first;
303     int i = v.first;
304     int j = v.second;
305     int k = v.third;
306 
307     float d = it->second;
308     float d1;
309     float sanity;
310     float relError;
311     float fieldDist;
312     float gridDist;
313 
314     #define PROCESS(di,dj,dk)\
315     if ((i+(di) <= resolutionX) && (i+(di) >= 0) &&\
316         (j+(dj) <= resolutionY) && (j+(dj) >= 0) &&\
317         (k+(dk) <= resolutionZ) && (k+(dk) >= 0))\
318     {\
319       d1 = distance(i+(di),j+(dj),k+(dk));\
320       if ((d1 != -FLT_MAX) && (d1 != FLT_MAX))\
321       {\
322         gridDist = (float) (len(Vec3d((di)*gridX,(dj)*gridY,(dk)*gridZ)));\
323         fieldDist = fabs(d-d1);\
324         sanity = fieldDist - gridDist;\
325         if (sanity > 1E-6)\
326         {\
327           relError = sanity/gridDist;\
328           if (relError > relErrors[numErrorsPrinted-1].relError)\
329           {\
330             errorData errorEntry = {i,j,k,di,dj,dk,fieldDist,gridDist,relError};\
331             relErrors[numErrorsPrinted-1] = errorEntry;\
332             sort(relErrors.begin(),relErrors.end(),more_errorData());\
333           }\
334           result = false;\
335           count++;\
336         }\
337       }\
338     }
339 
340     PROCESS(1,0,0);
341     PROCESS(1,1,0);
342     PROCESS(0,1,0);
343     PROCESS(-1,1,0);
344     PROCESS(-1,0,0);
345     PROCESS(-1,-1,0);
346     PROCESS(0,-1,0);
347     PROCESS(1,-1,0);
348 
349     PROCESS(0,0,1);
350     PROCESS(1,0,1);
351     PROCESS(1,1,1);
352     PROCESS(0,1,1);
353     PROCESS(-1,1,1);
354     PROCESS(-1,0,1);
355     PROCESS(-1,-1,1);
356     PROCESS(0,-1,1);
357     PROCESS(1,-1,1);
358 
359     PROCESS(0,0,-1);
360     PROCESS(1,0,-1);
361     PROCESS(1,1,-1);
362     PROCESS(0,1,-1);
363     PROCESS(-1,1,-1);
364     PROCESS(-1,0,-1);
365     PROCESS(-1,-1,-1);
366     PROCESS(0,-1,-1);
367     PROCESS(1,-1,-1);
368 
369     counter++;
370     if (counter % (resolutionX * resolutionY)== 0)
371     {
372       counter = 0;
373       cout << "." << flush;
374     }
375   }
376 
377   cout << endl;
378 
379   if (count == 0)
380     cout << "Success: sanity check passed." << endl;
381   else
382   {
383     cout << "Encountered " << count << " possible errors. Largest top " << numErrorsPrinted << " errors (or all errors if fewer):" << endl;
384     for(int i=0; i< (count < numErrorsPrinted ? count : numErrorsPrinted); i++)
385     {
386       errorData * errorEntry = &relErrors[i];
387       float d1 = distance(errorEntry->i,errorEntry->j,errorEntry->k);
388       float d2 = distance(errorEntry->i + errorEntry->di ,errorEntry->j + errorEntry->dj, errorEntry->k + errorEntry->dk);
389       cout << "Distance field change too large. [" << errorEntry->i << "," << errorEntry->j << "," << errorEntry->k << "] to [" << errorEntry->i + (errorEntry->di) << "," << errorEntry->j + (errorEntry->dj) << "," << errorEntry->k + (errorEntry->dk) << "]" << " Dist 1: " << d1 << " Dist 2: " << d2 << " Reported change in distance field: " << errorEntry->fieldDist << " Grid distance: " << errorEntry->gridDist << " Relative error: " << errorEntry->relError << endl;
390     }
391   }
392   return result;
393 }
394 
distance(Vec3d pos,int constrainToBox)395 float DistanceFieldNarrowBand::distance(Vec3d pos, int constrainToBox)
396 {
397   // get the index coordinate of the lower-right-bottom corner of the voxel containing 'pos'
398   int i = (int)((pos[0] - bmin_[0]) * invGridX);
399   int j = (int)((pos[1] - bmin_[1]) * invGridY);
400   int k = (int)((pos[2] - bmin_[2]) * invGridZ);
401 
402   if (((i<0) || (i>=resolutionX) || (j<0) || (j>=resolutionY) || (k<0) || (k>=resolutionZ)) && (!constrainToBox))
403   {
404     printf("Warning: querying the distance field outside of the bounding box: (i,j,k)=(%d,%d,%d), (x, y, z)=(%lf,%lf,%lf), resolution=(%d,%d,%d)\n",i, j, k, pos[0], pos[1], pos[2], resolutionX, resolutionY, resolutionZ);
405     return FLT_MAX;
406   }
407 
408   if (constrainToBox)
409   {
410     if (i >= resolutionX)
411     {
412       i = resolutionX - 1;
413       pos[0] = bmax_[0];
414     }
415 
416     if (i < 0)
417     {
418       i = 0;
419       pos[0] = bmin_[0];
420     }
421 
422     if (j >= resolutionY)
423     {
424       j = resolutionY - 1;
425       pos[1] = bmax_[1];
426     }
427 
428     if (j < 0)
429     {
430       j = 0;
431       pos[1] = bmin_[1];
432     }
433 
434     if (k >= resolutionZ)
435     {
436       k = resolutionZ - 1;
437       pos[2] = bmax_[2];
438     }
439 
440     if (k < 0)
441     {
442       k = 0;
443       pos[2] = bmin_[2];
444     }
445   }
446 
447   float distances[8];
448 
449   #define PROCESS2(i,j,k,l)\
450    {\
451      distances[(l)] = distance((i), (j), (k));\
452      if (fabs(distances[(l)]) == FLT_MAX)\
453      {\
454        return distances[(l)];\
455      }\
456    }
457 
458   PROCESS2(i,j,k,0);
459   PROCESS2(i+1,j,k,1);
460   PROCESS2(i+1,j+1,k,2);
461   PROCESS2(i,j+1,k,3);
462   PROCESS2(i,j,k+1,4);
463   PROCESS2(i+1,j,k+1,5);
464   PROCESS2(i+1,j+1,k+1,6);
465   PROCESS2(i,j+1,k+1,7);
466 
467   double wx,wy,wz;
468   wx = ((pos[0]-bmin_[0]) / gridX) - i;
469   wy = ((pos[1]-bmin_[1]) / gridY) - j;
470   wz = ((pos[2]-bmin_[2]) / gridZ) - k;
471 
472   return (float)(TRILINEAR_INTERPOLATION(wx,wy,wz,distances[0],distances[1],distances[2],distances[3],
473                                 distances[4],distances[5],distances[6],distances[7]));
474 }
475 
maxValue()476 float DistanceFieldNarrowBand::maxValue()
477 {
478   float maxValue=-FLT_MAX;
479 
480   for(map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
481   {
482     if ((it->second) > maxValue)
483       maxValue = it->second;
484   }
485 
486   return maxValue;
487 }
488 
minValue()489 float DistanceFieldNarrowBand::minValue()
490 {
491   float minValue=FLT_MAX;
492 
493   for(map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
494   {
495     if ((it->second) < minValue)
496       minValue = it->second;
497   }
498 
499   return minValue;
500 }
501 
maxMinValue(float * maxValue,float * minValue)502 void DistanceFieldNarrowBand::maxMinValue(float* maxValue, float* minValue)
503 {
504   *minValue=FLT_MAX;
505   *maxValue=-FLT_MAX;
506 
507   for(map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
508   {
509     float dist = it->second;
510     if (dist < *minValue)
511       *minValue = dist;
512 
513     if (dist > *maxValue)
514       *maxValue = dist;
515   }
516 }
517 
maxAbsValue()518 float DistanceFieldNarrowBand::maxAbsValue()
519 {
520   float maxValue=0;
521 
522   for(map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
523   {
524     float dist = fabs(it->second);
525     if (dist > maxValue)
526       maxValue = dist;
527   }
528 
529   return maxValue;
530 }
531 
maxNonInftyAbsValue()532 float DistanceFieldNarrowBand::maxNonInftyAbsValue()
533 {
534   float maxValue=0;
535 
536   for(map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
537   {
538     float dist = fabs(it->second);
539     if ((dist > maxValue) && (dist != FLT_MAX))
540       maxValue = dist;
541   }
542 
543   return maxValue;
544 }
545 
maxAbsValue(float threshold)546 float DistanceFieldNarrowBand::maxAbsValue(float threshold)
547 {
548   float maxValue=0;
549 
550   for(map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
551   {
552     float dist = fabs(it->second);
553     if ((dist > maxValue) && (dist < threshold))
554       maxValue = dist;
555   }
556 
557   return maxValue;
558 }
559 
gradient(const Vec3d & pos)560 Vec3d DistanceFieldNarrowBand::gradient(const Vec3d& pos)
561 {
562   int i,j,k;
563 
564   // get the indices
565   i = (int)((pos[0] - bmin_[0]) * invGridX);
566   j = (int)((pos[1] - bmin_[1]) * invGridY);
567   k = (int)((pos[2] - bmin_[2]) * invGridZ);
568 
569   if ((i<=0) || (i>=resolutionX) || (j<=0) || (j>=resolutionY) || (k<=0) || (k>=resolutionZ))
570   {
571     return Vec3d(0,0,0);
572   }
573 
574   double wx,wy,wz;
575   wx = ((pos[0]-bmin_[0]) / gridX) - i;
576   wy = ((pos[1]-bmin_[1]) / gridY) - j;
577   wz = ((pos[2]-bmin_[2]) / gridZ) - k;
578 
579   // gradient with respect to trilinear interpolation
580   float distances[8];
581   #define PROCESS3(i,j,k,l)\
582   {\
583     distances[(l)] = distance(i, j, k);\
584     if ((distances[(l)] == FLT_MAX) || (distances[(l)] == -FLT_MAX))\
585     {\
586       return distances[(l)];\
587     }\
588   }
589 
590   PROCESS3(i,j,k,0);
591   PROCESS3(i+1,j,k,1);
592   PROCESS3(i+1,j+1,k,2);
593   PROCESS3(i,j+1,k,3);
594   PROCESS3(i,j,k+1,4);
595   PROCESS3(i+1,j,k+1,5);
596   PROCESS3(i+1,j+1,k+1,6);
597   PROCESS3(i,j+1,k+1,7);
598 
599   return Vec3d(
600     GRADIENT_COMPONENT_X(wx,wy,wz,distances[0],distances[1],distances[2],distances[3],distances[4],distances[5],distances[6],distances[7]),
601     GRADIENT_COMPONENT_Y(wx,wy,wz,distances[0],distances[1],distances[2],distances[3],distances[4],distances[5],distances[6],distances[7]),
602     GRADIENT_COMPONENT_Z(wx,wy,wz,distances[0],distances[1],distances[2],distances[3],distances[4],distances[5],distances[6],distances[7]) );
603 
604 }
605 
findSurfaceGridPoints(ObjMesh * objMeshIn)606 void DistanceFieldNarrowBand::findSurfaceGridPoints(ObjMesh* objMeshIn)
607 {
608   ObjMesh objMesh(*objMeshIn);
609 
610   surfaceGridPoints.clear();
611   //typedef triple<int,int,int> gridPoint;
612 
613   std::set<gridPoint> checkedGridPoints;
614   std::vector<gridPoint> scheduledGridPoints;
615 
616   for(unsigned int i=0; i < objMesh.getNumGroups(); ++i)
617   {
618     const ObjMesh::Group * group = objMesh.getGroupHandle(i);
619 
620     for (unsigned int j=0; j<group->getNumFaces(); ++j)
621     {
622       Vec3d p0 = objMesh.getPosition(group->getFace(j).getVertex(0).getPositionIndex());
623       Vec3d p1 = objMesh.getPosition(group->getFace(j).getVertex(1).getPositionIndex());
624       Vec3d p2 = objMesh.getPosition(group->getFace(j).getVertex(2).getPositionIndex());
625 
626       TriangleBasic triangle(p0,p1,p2);
627 
628       Vec3d center = 1.0/3 * (p0 + p1 + p2);
629       Vec3d recCenter = center - bmin_;
630 
631       int vi,vj,vk;
632 
633       vi = (int)(recCenter[0] / gridX);
634       vj = (int)(recCenter[1] / gridY);
635       vk = (int)(recCenter[2] / gridZ);
636 
637       checkedGridPoints.clear();
638       checkedGridPoints.insert(gridPoint(vi, vj, vk));
639 
640       scheduledGridPoints.clear();
641       scheduledGridPoints.push_back(gridPoint(vi,vj,vk));
642 
643       while (!scheduledGridPoints.empty())
644       {
645         gridPoint v = scheduledGridPoints.back();
646         scheduledGridPoints.pop_back();
647 
648         Vec3d bbmin = bmin_ + Vec3d(v.first * gridX, v.second * gridY, v.third * gridZ);
649         Vec3d bbmax = bbmin + Vec3d(gridX, gridY, gridZ);
650 
651         BoundingBox bbox(bbmin, bbmax);
652 
653         if (triangle.doesIntersectBox(bbox))
654         {
655           //surfaceVoxels.insert(v);
656           //floodFillTag[(v.third * (resolutionY+1) + v.second) * (resolutionX + 1) + v.first] = 1;
657 
658           gridPoint neighbor;
659           vegalong index;
660           #define TAGNEIGHBOR(ii,jj,kk)\
661           neighbor = gridPoint(v.first+(ii), v.second+(jj), v.third+(kk));\
662           if ((neighbor.first <= resolutionX) &&\
663               (neighbor.second <= resolutionY) &&\
664               (neighbor.third <= resolutionZ))\
665           {\
666             index = (neighbor.third * (resolutionY+1) + neighbor.second) * (resolutionX + 1) + neighbor.first;\
667                   surfaceGridPoints.push_back(index);\
668           }
669 
670           for (int iii=0; iii<=1; ++iii)
671             for (int jjj=0; jjj<=1; ++jjj)
672               for (int kkk=0; kkk<=1; ++kkk)
673               {
674                 TAGNEIGHBOR(iii, jjj, kkk);
675               }
676 
677 
678           #define CHECKNEIGHBOR(ii,jj,kk)\
679           neighbor = gridPoint(v.first+(ii), v.second+(jj), v.third+(kk));\
680                 if ((neighbor.first >= 0) && (neighbor.first <= resolutionX) &&\
681               (neighbor.second >= 0) && (neighbor.second <= resolutionY) &&\
682               (neighbor.third >= 0) && (neighbor.third <= resolutionZ))\
683           {\
684             if (checkedGridPoints.find(neighbor) == checkedGridPoints.end())\
685             {\
686               checkedGridPoints.insert(neighbor);\
687               scheduledGridPoints.push_back(neighbor);\
688             }\
689           }
690 
691           for (int iii=-1; iii<=1; ++iii)
692             for (int jjj=-1; jjj<=1; ++jjj)
693               for (int kkk=-1; kkk<=1; ++kkk)
694               {
695                 if ((iii == 0) && (jjj == 0) && (kkk == 0))
696                   continue;
697 
698                 CHECKNEIGHBOR(iii, jjj, kkk);
699               }
700         }
701       }
702     }
703   }
704 }
705 
offsetDistanceField(double offset)706 void DistanceFieldNarrowBand::offsetDistanceField(double offset)
707 {
708   for(std::map<gridPoint, float>::iterator it = distanceData.begin(); it != distanceData.end(); it++)
709     it->second += (float) offset;
710 }
711 
712