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 authors: Jernej Barbic, Hongyi Xu, Yijing Li                     *
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   This code generates a distance filed, either signed or unsigned,
29   to the given triangle mesh.
30 
31   The distance field can be loaded/saved to a file.
32   You can also lookup the field (once computed or loaded) at arbitrary
33   locations inside the field, using trilinear interpolation.
34 
35   Input mesh need not have triangle faces (e.g., can have quads;
36   they will be triangulated).
37 
38   For signed field generation, the input mesh must be a closed manifold mesh.
39 
40   Input mesh must be given in the .obj format:
41   http://www.royriggs.com/obj.html
42 
43   By default, the bounding box will be a cube, obtained by fitting the
44   smallest cube to the geometry, and then expanded (scaled) from its
45   center by a factor of 1.5. You can provide your own bounding boxes.
46   However, note: (1) the provided bounding box must cover all the geometry,
47   and (2) bounding boxes that are not cubes were not (yet) tested.
48 
49   The bounding box will be divided into a "resolution" number of
50   cubes ("voxels") along each axis. The distance field will be computed at the
51   vertices of these voxels. So, if resolution is 256, the bounding box
52   will get divided into 256 x 256 x 256 voxels, and the distance field
53   will be computed on the resulting 257 x 257 x 257 grid of voxel vertices.
54   Note that when indexing voxels, the indices (i,j,k) will run from 0 to 255
55   inclusive, whereas when indexing voxel vertices (also called "grid vertices"),
56   they will run from 0 to 256 inclusive.
57 
58   Distance field data is stored at voxel vertices.
59   In memory, distance field value at voxel vertex (i,j,k) is stored
60   at location k * (resolutionX+1)*(resolutionY+1) + j * (resolutionX+1) + i .
61 
62   Internally, the code builds an octree on top of the triangle mesh.
63   There are two parameters that control this process (you can keep them
64   at default values, which worked well in practice for us) :
65   the max depth of the octree is "maxDepth", and
66   the max number of triangles intersecting an octree cell is "maxTriCount".
67   Note: once max depth level is reached, the maxTriCount bound is not imposed any more.
68 */
69 
70 #include <stdlib.h>
71 #include <stdio.h>
72 #include <string.h>
73 #include <float.h>
74 #include <fstream>
75 #include <set>
76 #include "triangle.h"
77 #include "triple.h"
78 #include "boundingBox.h"
79 #include "distanceField.h"
80 #include "trilinearInterpolation.h"
81 #include "vegalong.h"
82 using namespace std;
83 
84 //#define GENERATE_DEBUG_DATA
85 
GetFilesize(const char * filename)86 vegalong DistanceField::GetFilesize(const char *filename)
87 {
88   FILE * f = fopen(filename, "rb");  /* open the file in read only */
89 
90   vegalong size = 0;
91   if (fseek(f,0,SEEK_END)==0) /* seek was successful */
92       size = ftell(f);
93   fclose(f);
94   return size;
95 }
96 
DistanceField()97 DistanceField::DistanceField() : DistanceFieldBase()
98 {
99   distanceData = NULL;
100   pseudoData = NULL;
101   computeVoronoiDiagram = false;
102   voronoiDiagram = NULL;
103   minBoundaryDistance = 0;
104   floodFillTag = NULL;
105 }
106 
DistanceField(int resolutionX_,int resolutionY_,int resolutionZ_)107 DistanceField::DistanceField(int resolutionX_, int resolutionY_, int resolutionZ_): DistanceFieldBase(resolutionX_, resolutionY_, resolutionZ_)
108 {
109   distanceData = NULL;
110   pseudoData = NULL;
111   computeVoronoiDiagram = false;
112   voronoiDiagram = NULL;
113   minBoundaryDistance = 0;
114   floodFillTag = NULL;
115 
116   distanceData = (float*) malloc (sizeof(float)*(resolutionX+1)*(resolutionY+1)*(resolutionZ+1));
117 }
118 
~DistanceField()119 DistanceField::~DistanceField()
120 {
121   free(distanceData);
122   free(pseudoData);
123   free(floodFillTag);
124   free(voronoiDiagram);
125 }
126 
enableVoronoiDiagramComputation(bool computeVoronoiDiagram)127 void DistanceField::enableVoronoiDiagramComputation(bool computeVoronoiDiagram)
128 {
129   this->computeVoronoiDiagram = computeVoronoiDiagram;
130 }
131 
132 // the routines for signed and unsigned distance field computation
133 #define COMPUTE_SIGNED_FIELD
134   #define COMPUTE_FLOOD_FIELD
135     #include "computeField.cpp"
136   #undef COMPUTE_FLOOD_FIELD
137     #include "computeField.cpp"
138 #undef COMPUTE_SIGNED_FIELD
139   #include "computeField.cpp"
140 
load(const std::string & filename)141 int DistanceField::load(const std::string& filename)
142 {
143   ifstream fin(filename.c_str(),ios::binary);
144   if (!fin)
145     return 1;
146 
147   fin.read((char*)&resolutionX, sizeof(int));
148 
149   // the type of data (single-precision or double-precision) is encoded
150   //   as the sign of the x-resolution
151   bool floatData = (resolutionX < 0);
152   if (floatData)
153     resolutionX = -resolutionX;
154 
155   fin.read((char*)&resolutionY, sizeof(int));
156 
157   if (resolutionY < 0) // negative second resolution implies closest point data
158     return 1;
159 
160   fin.read((char*)&resolutionZ, sizeof(int));
161 
162   fin.read((char*)&(bmin_[0]), sizeof(double));
163   fin.read((char*)&(bmin_[1]), sizeof(double));
164   fin.read((char*)&(bmin_[2]), sizeof(double));
165 
166   fin.read((char*)&(bmax_[0]), sizeof(double));
167   fin.read((char*)&(bmax_[1]), sizeof(double));
168   fin.read((char*)&(bmax_[2]), sizeof(double));
169 
170   setGridParameters();
171 
172   distanceData = (float*) realloc (distanceData, sizeof(float) * (resolutionX+1) * (resolutionY+1) * (resolutionZ+1));
173 
174   float * distanceDataPos = distanceData;
175   int sliceResolution = (resolutionX+1) * (resolutionY+1);
176   int unitSize = floatData ? sizeof(float) : sizeof(double);
177   for(int k=0; k <= resolutionZ; k++, distanceDataPos += sliceResolution)
178     fin.read((char*)distanceDataPos, unitSize * sliceResolution);
179   //printf("\n");
180   fin.close();
181 
182   return 0;
183 }
184 
openStreamDistanceField(const std::string & filename,Vec3d * bmin,Vec3d * bmax,int * resolutionX,int * resolutionY,int * resolutionZ,bool * floatData,ifstream & fin)185 int DistanceField::openStreamDistanceField(const std::string& filename, Vec3d * bmin, Vec3d * bmax, int * resolutionX, int * resolutionY, int * resolutionZ, bool * floatData, ifstream & fin)
186 {
187   fin.open(filename.c_str(),ios::binary);
188   if (!fin)
189     return 1;
190 
191   fin.read((char*)resolutionX, 4);
192 
193   // the type of data (single-precision or double-precision) is encoded
194   //   as the sign of the x-resolution
195   *floatData = (*resolutionX < 0);
196   if (*floatData)
197     *resolutionX = - *resolutionX;
198 
199   fin.read((char*)resolutionY, 4);
200 
201   if (*resolutionY < 0) // negative second resolution implies closest point data
202     return 1;
203 
204   fin.read((char*)resolutionZ, 4);
205 
206   double bminx, bminy, bminz;
207   fin.read((char*)&bminx, 8);
208   fin.read((char*)&bminy, 8);
209   fin.read((char*)&bminz, 8);
210 
211   double bmaxx, bmaxy, bmaxz;
212   fin.read((char*)&bmaxx, 8);
213   fin.read((char*)&bmaxy, 8);
214   fin.read((char*)&bmaxz, 8);
215 
216   (*bmin)[0] = bminx;
217   (*bmin)[1] = bminy;
218   (*bmin)[2] = bminz;
219 
220   (*bmax)[0] = bmaxx;
221   (*bmax)[1] = bmaxy;
222   (*bmax)[2] = bmaxz;
223 
224   return 0;
225 }
226 
retrieveZSlice(ifstream & fin,bool floatData,int resolutionX,int resolutionY,int resolutionZ,float * slice)227 void DistanceField::retrieveZSlice(ifstream & fin, bool floatData, int resolutionX, int resolutionY, int resolutionZ, float * slice)
228 {
229   double * buffer = (double*) malloc (sizeof(double) * (resolutionX+1) * (resolutionY+1)); // place for one slice
230 
231   float * distanceDataPos = slice;
232 
233   if (floatData)
234     fin.read((char*)buffer, sizeof(float) * (resolutionX+1) * (resolutionY+1));
235   else
236     fin.read((char*)buffer, sizeof(double) * (resolutionX+1) * (resolutionY+1));
237 
238   char * bufferPos = (char*)buffer;
239   int bufferPosInc = floatData ? sizeof(float) : sizeof(double);
240 
241   // copy data to the slice
242   for(int j = 0; j <= resolutionY; j++)
243     for(int i = 0; i <= resolutionX; i++)
244     {
245       if (floatData)
246         *distanceDataPos = *(float*)bufferPos;
247       else
248         *distanceDataPos = *(double*)bufferPos;
249       distanceDataPos++;
250       bufferPos += bufferPosInc;
251     }
252 }
253 
set(int resolutionX,int resolutionY,int resolutionZ,Vec3d bmin_,Vec3d bmax_,float * distanceData)254 void DistanceField::set(int resolutionX, int resolutionY, int resolutionZ, Vec3d bmin_, Vec3d bmax_, float * distanceData)
255 {
256   this->resolutionX = resolutionX;
257   this->resolutionY = resolutionY;
258   this->resolutionZ = resolutionZ;
259   this->bmin_ = bmin_;
260   this->bmax_ = bmax_;
261 
262   setGridParameters();
263 
264   free(this->distanceData);
265   this->distanceData = (float*) malloc (sizeof(float)*(resolutionX+1)*(resolutionY+1)*(resolutionZ+1));
266   memcpy(this->distanceData, distanceData, sizeof(float)*(resolutionX+1)*(resolutionY+1)*(resolutionZ+1));
267 }
268 
isDoublePrecision(const std::string & filename,bool & doublePrecision)269 int DistanceField::isDoublePrecision(const std::string & filename, bool & doublePrecision)
270 {
271   ifstream fin(filename.c_str(),ios::binary);
272   if (!fin)
273     return 1;
274 
275   int res;
276   fin.read((char*)&res,4);
277 
278   // the type of data (single-precision or double-precision) is encoded
279   //   as the sign of the x-resolution
280   doublePrecision = (res >= 0);
281 
282   fin.close();
283 
284   return 0;
285 }
286 
saveToText(const std::string & filename)287 int DistanceField::saveToText(const std::string& filename)
288 {
289   FILE * fout = fopen((char*)filename.c_str(), "w");
290   if (!fout)
291     return 1;
292 
293   fprintf(fout, "%d\n", resolutionX);
294   fprintf(fout, "%d\n", resolutionY);
295   fprintf(fout, "%d\n", resolutionZ);
296 
297   for(int i=0; i<=resolutionX; i++)
298     for(int j=0; j<=resolutionY; j++)
299       for(int k=0; k<=resolutionZ; k++)
300       {
301         fprintf(fout,"%G\n", distance(i,j,k));
302       }
303 
304   fclose(fout);
305 
306   return 0;
307 }
308 
save(const std::string & filename,bool doublePrecision)309 int DistanceField::save(const std::string& filename, bool doublePrecision)
310 {
311   if (doublePrecision)
312     printf("Error: double precision output is not supported. Using float instead.\n");
313   doublePrecision = false;
314 
315   ofstream fout(filename.c_str(),ios::binary);
316 
317   int data = resolutionX;
318   if (!doublePrecision)
319     data = -data;
320 
321   fout.write((char*)&data,sizeof(int));
322   fout.write((char*)&resolutionY,sizeof(int));
323   fout.write((char*)&resolutionZ,sizeof(int));
324 
325   fout.write((char*)&(bmin_[0]),sizeof(double));
326   fout.write((char*)&(bmin_[1]),sizeof(double));
327   fout.write((char*)&(bmin_[2]),sizeof(double));
328 
329   fout.write((char*)&(bmax_[0]),sizeof(double));
330   fout.write((char*)&(bmax_[1]),sizeof(double));
331   fout.write((char*)&(bmax_[2]),sizeof(double));
332 
333   // float precision
334   //fout.write((char*)distanceData,sizeof(float)*(resolutionX+1)*(resolutionY+1)*(resolutionZ+1)); // this version sometimes resulted in the field incorrectly written to file (unclear why)
335 
336   for(int k=0; k<=resolutionZ; k++)
337     for(int j=0; j<=resolutionY; j++)
338       for(int i=0; i<=resolutionX; i++)
339       {
340         fout.write((char*)&distanceData[k * (resolutionX+1)*(resolutionY+1) + j * (resolutionX+1) + i], sizeof(float));
341       }
342 
343 /*
344   if (doublePrecision)
345     fout.write((char*)distanceData,sizeof(double)*(resolution+1)*(resolution+1)*(resolution+1));
346   else
347   {
348     float * buffer;
349     convertToFloat(&buffer);
350     fout.write((char*)buffer,sizeof(float)*(resolution+1)*(resolution+1)*(resolution+1));
351     free(buffer);
352   }
353 */
354   fout.close();
355 
356   #ifdef GENERATE_DEBUG_DATA
357     ofstream fout1("debugPseudo", ios::binary);
358     fout1.write((char*)pseudoData, 6*sizeof(float)*(resolution+1)*(resolution+1)*(resolution+1));
359     fout1.close();
360   #endif
361 
362   return 0;
363 }
364 
saveVoronoiDiagram(const std::string & filename)365 int DistanceField::saveVoronoiDiagram(const std::string& filename)
366 {
367   if (voronoiDiagram == NULL)
368   {
369     printf("Error in saveVoronoiDiagram: Voronoi diagram has not been computed.\n");
370     return 1;
371   }
372 
373   ofstream fout(filename.c_str(), ios::binary);
374 
375   int header = 0;
376 
377   fout.write((char*)&header,sizeof(int));
378   fout.write((char*)&resolutionX,sizeof(int));
379   fout.write((char*)&resolutionY,sizeof(int));
380   fout.write((char*)&resolutionZ,sizeof(int));
381 
382   fout.write((char*)&(bmin_[0]),sizeof(double));
383   fout.write((char*)&(bmin_[1]),sizeof(double));
384   fout.write((char*)&(bmin_[2]),sizeof(double));
385 
386   fout.write((char*)&(bmax_[0]),sizeof(double));
387   fout.write((char*)&(bmax_[1]),sizeof(double));
388   fout.write((char*)&(bmax_[2]),sizeof(double));
389 
390   fout.write((char*)voronoiDiagram, sizeof(int) * (resolutionX+1) * (resolutionY+1) * (resolutionZ+1));
391 
392   fout.close();
393 
394   return 0;
395 }
396 
397 typedef struct
398 {
399   int i,j,k;
400   int di,dj,dk;
401   double fieldDist, gridDist, relError;
402 } errorData;
403 
404 struct more_errorData : public std::binary_function< errorData, errorData, bool > {
operator ()more_errorData405   bool operator()(const errorData& x, const errorData& y) {
406     return((x.relError) > (y.relError));
407   }
408 };
409 
sanityCheck()410 bool DistanceField::sanityCheck()
411 {
412   //double diagonal = sqrt(gridX*gridX + gridY*gridY + gridZ*gridZ);
413 
414   bool result = true;
415   int count = 0;
416 
417   const int numErrorsPrinted = 3;
418 
419   vector<errorData> relErrors;
420   errorData emptyEntry = {0,0,0,0,0,0,0.0,0.0,-1.0};
421   for(int i=0; i<numErrorsPrinted; i++)
422    relErrors.push_back(emptyEntry);
423 
424   for (int k=0; k <= resolutionZ; k++)
425   {
426     for (int j=0; j <= resolutionY; j++)
427       for (int i=0; i <= resolutionX; i++)
428       {
429         float d = distance(i,j,k);
430         float d1;
431         float sanity;
432         float relError;
433         float fieldDist;
434         float gridDist;
435 
436         #define PROCESS(di,dj,dk)\
437         if ((i+(di) <= resolutionX) && (i+(di) >= 0) &&\
438             (j+(dj) <= resolutionY) && (j+(dj) >= 0) &&\
439             (k+(dk) <= resolutionZ) && (k+(dk) >= 0))\
440         {\
441           d1 = distance(i+(di),j+(dj),k+(dk));\
442           gridDist = (float) len(Vec3d((di)*gridX,(dj)*gridY,(dk)*gridZ));\
443           fieldDist = fabs(d-d1);\
444           sanity = fieldDist - gridDist;\
445           if (sanity > 1E-6)\
446           {\
447             relError = sanity/gridDist;\
448             if (relError > relErrors[numErrorsPrinted-1].relError)\
449             {\
450               errorData errorEntry = {i,j,k,di,dj,dk,fieldDist,gridDist,relError};\
451               relErrors[numErrorsPrinted-1] = errorEntry;\
452               sort(relErrors.begin(),relErrors.end(),more_errorData());\
453             }\
454             result = false;\
455             count++;\
456           }\
457         }
458 
459         PROCESS(1,0,0);
460         PROCESS(1,1,0);
461         PROCESS(0,1,0);
462         PROCESS(-1,1,0);
463         PROCESS(-1,0,0);
464         PROCESS(-1,-1,0);
465         PROCESS(0,-1,0);
466         PROCESS(1,-1,0);
467 
468         PROCESS(0,0,1);
469         PROCESS(1,0,1);
470         PROCESS(1,1,1);
471         PROCESS(0,1,1);
472         PROCESS(-1,1,1);
473         PROCESS(-1,0,1);
474         PROCESS(-1,-1,1);
475         PROCESS(0,-1,1);
476         PROCESS(1,-1,1);
477 
478         PROCESS(0,0,-1);
479         PROCESS(1,0,-1);
480         PROCESS(1,1,-1);
481         PROCESS(0,1,-1);
482         PROCESS(-1,1,-1);
483         PROCESS(-1,0,-1);
484         PROCESS(-1,-1,-1);
485         PROCESS(0,-1,-1);
486         PROCESS(1,-1,-1);
487 
488       }
489     cout << "." << flush;
490   }
491 
492   cout << endl;
493 
494   if (count == 0)
495     cout << "Success: sanity check passed." << endl;
496   else
497   {
498     cout << "Encountered " << count << " possible errors. Largest top " << numErrorsPrinted << " errors (or all errors if fewer):" << endl;
499     for(int i=0; i< (count < numErrorsPrinted ? count : numErrorsPrinted); i++)
500     {
501       errorData * errorEntry = &relErrors[i];
502       float d1 = distance(errorEntry->i,errorEntry->j,errorEntry->k);
503       float d2 = distance(errorEntry->i + errorEntry->di ,errorEntry->j + errorEntry->dj, errorEntry->k + errorEntry->dk);
504       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;
505     }
506   }
507   return result;
508 }
509 
distance(Vec3d pos,int constrainToBox)510 float DistanceField::distance(Vec3d pos, int constrainToBox)
511 {
512   // get the index coordinate of the lower-right-bottom corner of the voxel containing 'pos'
513   int i = (int)((pos[0] - bmin_[0]) * invGridX);
514   int j = (int)((pos[1] - bmin_[1]) * invGridY);
515   int k = (int)((pos[2] - bmin_[2]) * invGridZ);
516 
517   if (((i<0) || (i>=resolutionX) || (j<0) || (j>=resolutionY) || (k<0) || (k>=resolutionZ)) && (!constrainToBox))
518   {
519     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);
520     return FLT_MAX;
521   }
522 
523   if (constrainToBox)
524   {
525     if (i >= resolutionX)
526     {
527       i = resolutionX - 1;
528       pos[0] = bmax_[0];
529     }
530 
531     if (i < 0)
532     {
533       i = 0;
534       pos[0] = bmin_[0];
535     }
536 
537     if (j >= resolutionY)
538     {
539       j = resolutionY - 1;
540       pos[1] = bmax_[1];
541     }
542 
543     if (j < 0)
544     {
545       j = 0;
546       pos[1] = bmin_[1];
547     }
548 
549     if (k >= resolutionZ)
550     {
551       k = resolutionZ - 1;
552       pos[2] = bmax_[2];
553     }
554 
555     if (k < 0)
556     {
557       k = 0;
558       pos[2] = bmin_[2];
559     }
560   }
561 
562   //printf("I=%d J=%d K=%d\n", i,j,k);
563   //printf("remx=%f remy=%f remz=%f\n", pos[0] - bmin_[0] - gridX * i,
564   //        pos[1] - bmin_[1] - gridY * j, pos[2] - bmin_[2] - gridZ * k);
565 
566   double wx,wy,wz;
567   wx = ((pos[0]-bmin_[0]) / gridX) - i;
568   wy = ((pos[1]-bmin_[1]) / gridY) - j;
569   wz = ((pos[2]-bmin_[2]) / gridZ) - k;
570 
571   return (float) (TRILINEAR_INTERPOLATION(wx,wy,wz,distance(i,j,k),distance(i+1,j,k),distance(i+1,j+1,k),distance(i,j+1,k),
572                                 distance(i,j,k+1),distance(i+1,j,k+1),distance(i+1,j+1,k+1),distance(i,j+1,k+1)));
573 }
574 
maxValue()575 float DistanceField::maxValue()
576 {
577   float maxValue=-FLT_MAX;
578   for (int k=0; k <= resolutionZ; k++)
579     for (int j=0; j <= resolutionY; j++)
580       for (int i=0; i <= resolutionX; i++)
581       {
582         float dist = distance(i,j,k);
583         if (dist > maxValue)
584           maxValue = dist;
585       }
586   return maxValue;
587 }
588 
minValue()589 float DistanceField::minValue()
590 {
591   float minValue=FLT_MAX;
592   for (int k=0; k <= resolutionZ; k++)
593     for (int j=0; j <= resolutionY; j++)
594       for (int i=0; i <= resolutionX; i++)
595       {
596         float dist = distance(i,j,k);
597         if (dist < minValue)
598           minValue = dist;
599       }
600   return minValue;
601 }
602 
maxMinValue(float * maxValue,float * minValue)603 void DistanceField::maxMinValue(float* maxValue, float* minValue)
604 {
605   *minValue=FLT_MAX;
606   *maxValue=-FLT_MAX;
607   for (int k=0; k <= resolutionZ; k++)
608     for (int j=0; j <= resolutionY; j++)
609       for (int i=0; i <= resolutionX; i++)
610       {
611         float dist = distance(i,j,k);
612         if (dist < *minValue)
613           *minValue = dist;
614         if (dist > *maxValue)
615           *maxValue = dist;
616       }
617 }
618 
maxAbsValue()619 float DistanceField::maxAbsValue()
620 {
621   float maxValue=0;
622   for (int k=0; k <= resolutionZ; k++)
623     for (int j=0; j <= resolutionY; j++)
624       for (int i=0; i <= resolutionX; i++)
625       {
626         float dist = fabs(distance(i,j,k));
627         if (dist > maxValue)
628           maxValue = dist;
629       }
630   return maxValue;
631 }
632 
maxNonInftyAbsValue()633 float DistanceField::maxNonInftyAbsValue()
634 {
635   float maxValue=0;
636   for (int k=0; k <= resolutionZ; k++)
637     for (int j=0; j <= resolutionY; j++)
638       for (int i=0; i <= resolutionX; i++)
639       {
640         float dist = fabs(distance(i,j,k));
641         if ((dist > maxValue) && (dist != FLT_MAX))
642           maxValue = dist;
643       }
644   return maxValue;
645 }
646 
maxAbsValue(float threshold)647 float DistanceField::maxAbsValue(float threshold)
648 {
649   float maxValue=0;
650   for (int k=0; k <= resolutionZ; k++)
651     for (int j=0; j <= resolutionY; j++)
652       for (int i=0; i <= resolutionX; i++)
653       {
654         float dist = fabs(distance(i,j,k));
655         if ((dist > maxValue) && (dist < threshold))
656           maxValue = dist;
657       }
658   return maxValue;
659 }
660 
gradient(const Vec3d & pos)661 Vec3d DistanceField::gradient(const Vec3d& pos)
662 {
663   int i,j,k;
664 
665   // get the indices
666   i = (int)((pos[0] - bmin_[0]) * invGridX);
667   j = (int)((pos[1] - bmin_[1]) * invGridY);
668   k = (int)((pos[2] - bmin_[2]) * invGridZ);
669 
670   if ((i<=0) || (i>=resolutionX) || (j<=0) || (j>=resolutionY) || (k<=0) || (k>=resolutionZ))
671   {
672     return Vec3d(0,0,0);
673   }
674 
675   double wx,wy,wz;
676   wx = ((pos[0]-bmin_[0]) / gridX) - i;
677   wy = ((pos[1]-bmin_[1]) / gridY) - j;
678   wz = ((pos[2]-bmin_[2]) / gridZ) - k;
679 
680   // gradient with respect to trilinear interpolation
681 
682   float v000 = distance(i,j,k);
683   float v100 = distance(i+1,j,k);
684   float v110 = distance(i+1,j+1,k);
685   float v010 = distance(i,j+1,k);
686   float v001 = distance(i,j,k+1);
687   float v101 = distance(i+1,j,k+1);
688   float v111 = distance(i+1,j+1,k+1);
689   float v011 = distance(i,j+1,k+1);
690 
691   return Vec3d(
692     GRADIENT_COMPONENT_X(wx,wy,wz,v000,v100,v110,v010,v001,v101,v111,v011),
693     GRADIENT_COMPONENT_Y(wx,wy,wz,v000,v100,v110,v010,v001,v101,v111,v011),
694     GRADIENT_COMPONENT_Z(wx,wy,wz,v000,v100,v110,v010,v001,v101,v111,v011) );
695 
696 }
697 
getDistanceData(float ** floatBuffer)698 void DistanceField::getDistanceData(float ** floatBuffer)
699 {
700   unsigned int size = (resolutionX+1) * (resolutionY+1) * (resolutionZ+1);
701   *floatBuffer = (float*) malloc (sizeof(float) * size);
702   memcpy(*floatBuffer, distanceData, sizeof(float) * size);
703   //for(unsigned int i=0; i< size; i++)
704     //(*floatBuffer)[i] = (float) (distanceData[i]);
705 }
706 
707 
708 /*
709 void DistanceField::convertToFloat(float ** floatBuffer)
710 {
711   unsigned int size = (resolutionX+1) * (resolutionY+1) * (resolutionZ+1);
712   *floatBuffer = (float*) malloc (sizeof(float) * size);
713   for(unsigned int i=0; i< size; i++)
714     (*floatBuffer)[i] = (float) (distanceData[i]);
715 }
716 */
717 
718 /*
719 void DistanceField::convertToDouble(double ** doubleBuffer)
720 {
721   unsigned int size = (resolutionX+1) * (resolutionY+1) * (resolutionZ+1);
722   *doubleBuffer = (double*) malloc (sizeof(double) * size);
723   memcpy(*doubleBuffer, distanceData, sizeof(double) * size);
724 }
725 */
726 
isSurfaceVoxel(int i,int j,int k)727 bool DistanceField::isSurfaceVoxel(int i, int j, int k)
728 {
729   float v[8];
730   v[0] = distance(i,j,k);
731   v[1] = distance(i+1,j,k);
732   v[2] = distance(i+1,j+1,k);
733   v[3] = distance(i,j+1,k);
734   v[4] = distance(i,j,k+1);
735   v[5] = distance(i+1,j,k+1);
736   v[6] = distance(i+1,j+1,k+1);
737   v[7] = distance(i,j+1,k+1);
738 
739   bool allPositive = true;
740   for(int l=0; l<8; l++)
741     if (v[l] < 0)
742     {
743       allPositive = false;
744       break;
745     }
746 
747   bool allNegative = true;
748   for(int l=0; l<8; l++)
749     if (v[l] >= 0)
750     {
751       allNegative = false;
752       break;
753     }
754 
755   return (!allNegative && !allPositive);
756 }
757 
isSurfaceVoxel(int customResolutionX,int customResolutionY,int customResolutionZ,int i,int j,int k,float levelSetValue)758 bool DistanceField::isSurfaceVoxel(int customResolutionX, int customResolutionY, int customResolutionZ, int i, int j, int k, float levelSetValue)
759 {
760   //printf("i: %d j:%d k:%d\n",i,j,k);
761   Vec3d customGrid;
762   customGrid[0] = 1.0 * side[0] / customResolutionX;
763   customGrid[1] = 1.0 * side[1] / customResolutionY;
764   customGrid[2] = 1.0 * side[2] / customResolutionZ;
765 
766   Vec3d basePos = bmin_ + Vec3d( 1.0 * i * customGrid[0], 1.0 * j * customGrid[1], 1.0 * k * customGrid[2] );
767 
768   if (((i < 0) || (i >= customResolutionX)) && ((j < 0) || (j >= customResolutionY)) && ((k < 0) || (k >= customResolutionZ)))
769   {
770     printf("Warning (inside isSurfaceVoxel): voxel insides specified outside of the bounding box: (i,j,k)=(%d,%d,%d), customResolution=(%d,%d,%d)\n", i, j, k, customResolutionX, customResolutionY, customResolutionZ);
771   }
772 
773   // pass parameter 1 to constrain to box
774   float v[8];
775   v[0] = distance(basePos, 1) - levelSetValue;
776   v[1] = distance(basePos + Vec3d(customGrid[0], 0, 0), 1) - levelSetValue;
777   v[2] = distance(basePos + Vec3d(customGrid[0], customGrid[1], 0), 1) - levelSetValue;
778   v[3] = distance(basePos + Vec3d(0, customGrid[1], 0), 1) - levelSetValue;
779   v[4] = distance(basePos + Vec3d(0, 0, customGrid[2]), 1) - levelSetValue;
780   v[5] = distance(basePos + Vec3d(customGrid[0], 0, customGrid[2]), 1) - levelSetValue;
781   v[6] = distance(basePos + Vec3d(customGrid[0], customGrid[1], customGrid[2]), 1) - levelSetValue;
782   v[7] = distance(basePos + Vec3d(0, customGrid[1], customGrid[2]), 1) - levelSetValue;
783 
784 /*
785   double v[8];
786   v[0] = distance(i,j,k);
787   v[1] = distance(i+1,j,k);
788   v[2] = distance(i+1,j+1,k);
789   v[3] = distance(i,j+1,k);
790   v[4] = distance(i,j,k+1);
791   v[5] = distance(i+1,j,k+1);
792   v[6] = distance(i+1,j+1,k+1);
793   v[7] = distance(i,j+1,k+1);
794 */
795 
796   bool allPositive = true;
797   for(int l=0; l<8; l++)
798     if (v[l] < 0)
799     {
800       allPositive = false;
801       break;
802     }
803 
804   bool allNegative = true;
805   for(int l=0; l<8; l++)
806     if (v[l] >= 0)
807     {
808       allNegative = false;
809       break;
810     }
811 
812   return (!allNegative && !allPositive);
813 }
814 
numSurfaceVoxels(float levelSetValue)815 int DistanceField::numSurfaceVoxels(float levelSetValue)
816 {
817   return numSurfaceVoxels(resolutionX, resolutionY, resolutionZ, levelSetValue);
818 }
819 
numSurfaceVoxels(int customResolutionX,int customResolutionY,int customResolutionZ,float levelSetValue)820 int DistanceField::numSurfaceVoxels(int customResolutionX, int customResolutionY, int customResolutionZ, float levelSetValue)
821 {
822   printf("num surface voxels... custom res: (%d,%d,%d)\n", customResolutionX, customResolutionY, customResolutionZ);
823   int count = 0;
824 
825   for(int k=0; k<customResolutionZ; k++)
826     for(int j=0; j<customResolutionY; j++)
827       for(int i=0; i<customResolutionX; i++)
828         if (isSurfaceVoxel(customResolutionX, customResolutionY, customResolutionZ, i, j, k, levelSetValue))
829           count++;
830 
831   return count;
832 }
833 
minBoundaryValue()834 float DistanceField::minBoundaryValue()
835 {
836   float minDistance = FLT_MAX;
837   for(int k=0; k <= resolutionZ; k++)
838     for(int j=0; j <= resolutionY; j++)
839       for(int i=0; i <= resolutionX; i += resolutionX)
840       {
841         float value = distance(i,j,k);
842         if (value < minDistance)
843           minDistance = value;
844       }
845 
846   for(int k=0; k <= resolutionZ; k++)
847     for(int j=0; j <= resolutionY; j += resolutionY)
848       for(int i=0; i <= resolutionX; i++)
849       {
850         float value = distance(i,j,k);
851         if (value < minDistance)
852           minDistance = value;
853       }
854 
855   for(int k=0; k <= resolutionZ; k += resolutionZ)
856     for(int j=0; j <= resolutionY; j++)
857       for(int i=0; i <= resolutionX; i++)
858       {
859         float value = distance(i,j,k);
860         if (value < minDistance)
861           minDistance = value;
862       }
863 
864   minBoundaryDistance = minDistance;
865   return minDistance;
866 }
867 
print()868 void DistanceField::print()
869 {
870   for(int k=0; k <= resolutionX; k++)
871     for(int j=0; j <= resolutionY; j++)
872       for(int i=0; i <= resolutionZ; i++)
873       {
874         printf("i=%d j=%d k=%d d=%G\n", i, j, k, distance(i,j,k));
875       }
876 }
877 
computeFloodFillTag(ObjMesh * objMeshIn)878 void DistanceField::computeFloodFillTag(ObjMesh* objMeshIn)
879 {
880   ObjMesh objMesh(*objMeshIn);
881   vegalong size = sizeof(char) * (resolutionX+1) * (resolutionY+1) * (resolutionZ+1);
882   if (floodFillTag != NULL)
883     free(floodFillTag);
884   floodFillTag = (char*) malloc(size);
885   memset(floodFillTag, 0, sizeof(char) * (resolutionX+1) * (resolutionY+1) * (resolutionZ+1));
886 
887   typedef triple<int,int,int> voxel;
888 
889   std::set<voxel> checkedVoxels;
890   std::vector<voxel> scheduledVoxels;
891 
892   for(unsigned int i=0; i < objMesh.getNumGroups(); ++i)
893   {
894     const ObjMesh::Group * group = objMesh.getGroupHandle(i);
895 
896     for (unsigned int j=0; j<group->getNumFaces(); ++j)
897     {
898       Vec3d p0 = objMesh.getPosition(group->getFace(j).getVertex(0).getPositionIndex());
899       Vec3d p1 = objMesh.getPosition(group->getFace(j).getVertex(1).getPositionIndex());
900       Vec3d p2 = objMesh.getPosition(group->getFace(j).getVertex(2).getPositionIndex());
901 
902       TriangleBasic triangle(p0,p1,p2);
903 
904       Vec3d center = 1.0/3 * (p0 + p1 + p2);
905       Vec3d recCenter = center - bmin_;
906 
907       int vi,vj,vk;
908 
909       vi = (int)(recCenter[0] / gridX);
910       vj = (int)(recCenter[1] / gridY);
911       vk = (int)(recCenter[2] / gridZ);
912 
913       checkedVoxels.clear();
914       checkedVoxels.insert(voxel(vi, vj, vk));
915 
916       scheduledVoxels.clear();
917       scheduledVoxels.push_back(voxel(vi,vj,vk));
918 
919       while (!scheduledVoxels.empty())
920       {
921         voxel v = scheduledVoxels.back();
922         scheduledVoxels.pop_back();
923 
924         Vec3d bbmin = bmin_ + Vec3d(v.first * gridX, v.second * gridY, v.third * gridZ);
925         Vec3d bbmax = bbmin + Vec3d(gridX, gridY, gridZ);
926 
927         BoundingBox bbox(bbmin, bbmax);
928 
929         if (triangle.doesIntersectBox(bbox))
930         {
931           //surfaceVoxels.insert(v);
932           //floodFillTag[(v.third * (resolutionY+1) + v.second) * (resolutionX + 1) + v.first] = 1;
933 
934           voxel neighbor;
935           vegalong index;
936           #define TAGNEIGHBOR(ii,jj,kk)\
937           neighbor = voxel(v.first+(ii), v.second+(jj), v.third+(kk));\
938           if ((neighbor.first <= resolutionX) &&\
939               (neighbor.second <= resolutionY) &&\
940               (neighbor.third <= resolutionZ))\
941           {\
942             index = (neighbor.third * (resolutionY+1) + neighbor.second) * (resolutionX + 1) + neighbor.first;\
943             floodFillTag[index] = 1;\
944           }
945 
946           for (int kkk=0; kkk<=1; ++kkk)
947             for (int jjj=0; jjj<=1; ++jjj)
948               for (int iii=0; iii<=1; ++iii)
949               {
950                 TAGNEIGHBOR(iii, jjj, kkk);
951               }
952 
953 
954           #define CHECKNEIGHBOR(ii,jj,kk)\
955           neighbor = voxel(v.first+(ii), v.second+(jj), v.third+(kk));\
956           if ((neighbor.first >= 0) && (neighbor.first <= resolutionX) &&\
957               (neighbor.second >= 0) && (neighbor.second <= resolutionY) &&\
958               (neighbor.third >= 0) && (neighbor.third <= resolutionZ))\
959               {\
960             if (checkedVoxels.find(neighbor) == checkedVoxels.end())\
961             {\
962               checkedVoxels.insert(neighbor);\
963               scheduledVoxels.push_back(neighbor);\
964             }\
965           }
966 
967           for (int kkk=-1; kkk<=1; ++kkk)
968             for (int jjj=-1; jjj<=1; ++jjj)
969               for (int iii=-1; iii<=1; ++iii)
970               {
971                 if ((iii == 0) && (jjj == 0) && (kkk == 0))
972                   continue;
973 
974                 CHECKNEIGHBOR(iii, jjj, kkk);
975               }
976         }
977       }
978     }
979   }
980 }
981 
pointCCD(Vec3d startPos,Vec3d endPos)982 double DistanceField::pointCCD(Vec3d startPos, Vec3d endPos)
983 {
984   int constrainToBox = 0;
985   double startDist = distance(startPos, constrainToBox);
986   double endDist = distance(endPos, constrainToBox);
987 
988   if (((startDist > 0) && (endDist > 0)) || (startDist - endDist == 0))
989     return -1.0;
990 
991   int flip = 0;
992   if (startDist > 0)
993   {
994     flip = 1;
995     Vec3d bufv = startPos;
996     startPos = endPos;
997     endPos = bufv;
998     double buf = startDist;
999     startDist = endDist;
1000     endDist = buf;
1001   }
1002 
1003   // now, startPos is inside, and endPos is outside
1004 
1005   double eps = 1E-12;
1006   double d;
1007   Vec3d x;
1008   double t = 0.0;
1009   double tLo = 0.0;
1010   double tHi = 1.0;
1011   Vec3d xLo = startPos;
1012   Vec3d xHi = endPos;
1013   double distLo = startDist;
1014   double distHi = endDist;
1015   do
1016   {
1017     // distLo + deltaT * (distHi - distLo) = 0
1018     t += distLo / (distLo - distHi) * (tHi - tLo);
1019     x = startPos + t * (endPos - startPos);
1020     d = distance(x, constrainToBox);
1021 
1022     if (d <= 0)
1023     {
1024       // lo must go to new point
1025       tLo = t;
1026       xLo = x;
1027       distLo = d;
1028     }
1029     else
1030     {
1031       // hi must go to new point
1032       tHi = t;
1033       xHi = x;
1034       distHi = d;
1035     }
1036   }
1037   while (fabs(d) > eps);
1038 
1039   if (flip)
1040     t = 1.0 - t;
1041 
1042   return t;
1043 }
1044 
offsetDistanceField(double offset)1045 void DistanceField::offsetDistanceField(double offset)
1046 {
1047   vegalong numGridPoints = (resolutionX+1) * (resolutionY+1) * (resolutionZ+1);
1048 
1049   printf("Applying offset %G to the distance field. Resolution is %d x %d x %d.\n", offset, resolutionX, resolutionY, resolutionZ);
1050 
1051   for(vegalong i=0; i<numGridPoints; i++)
1052     distanceData[i] += (float) offset;
1053 }
1054 
1055