1 /*************************************************************************
2  *                                                                       *
3  * Vega FEM Simulation Library Version 3.1                               *
4  *                                                                       *
5  * "objMesh" library , Copyright (C) 2007 CMU, 2009 MIT, 2016 USC        *
6  * All rights reserved.                                                  *
7  *                                                                       *
8  * Code authors: Jernej Barbic, Christopher Twigg, Daniel Schroeder      *
9  * http://www.jernejbarbic.com/code                                      *
10  *                                                                       *
11  * Research: Jernej Barbic, Fun Shing Sin, Daniel Schroeder,             *
12  *           Doug L. James, Jovan Popovic                                *
13  *                                                                       *
14  * Funding: National Science Foundation, Link Foundation,                *
15  *          Singapore-MIT GAMBIT Game Lab,                               *
16  *          Zumberge Research and Innovation Fund at USC                 *
17  *                                                                       *
18  * This library is free software; you can redistribute it and/or         *
19  * modify it under the terms of the BSD-style license that is            *
20  * included with this library in the file LICENSE.txt                    *
21  *                                                                       *
22  * This library is distributed in the hope that it will be useful,       *
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file     *
25  * LICENSE.TXT for more details.                                         *
26  *                                                                       *
27  *************************************************************************/
28 
29 /*
30   Author: Jernej Barbic, 2003
31   Generates a voxel representation of an offset surface
32 */
33 
34 #if defined(_WIN32) || defined(WIN32)
35   #pragma warning(disable : 4996)
36   #pragma warning(disable : 4267)
37   #pragma warning(disable : 4244)
38 #endif
39 #include "objMeshOffsetVoxels.h"
40 #include "matrixIO.h"
41 #include "matrixMacros.h"
42 #include <fstream>
43 #include <iomanip>
44 #include <string.h>
45 using namespace std;
46 
ObjMeshOffsetVoxels(ObjMesh * objMesh_,int resolution_[3],int depth_,Vec3d bmin_,Vec3d bmax_)47 ObjMeshOffsetVoxels::ObjMeshOffsetVoxels( ObjMesh * objMesh_, int resolution_[3], int depth_, Vec3d bmin_, Vec3d bmax_ )
48 {
49   objMesh = new ObjMesh(*objMesh_);
50   init(resolution_, depth_, bmin_, bmax_);
51 }
52 
ObjMeshOffsetVoxels(ObjMesh * objMesh_,int resolution_[3],int depth_,double expansionFactor)53 ObjMeshOffsetVoxels::ObjMeshOffsetVoxels( ObjMesh * objMesh_, int resolution_[3], int depth_, double expansionFactor )
54 {
55   objMesh = new ObjMesh(*objMesh_);
56 
57   // build mesh bounding box
58   Vec3d bmin_, bmax_;
59   objMesh->getCubicBoundingBox(expansionFactor, &bmin_, &bmax_);
60 
61   init(resolution_, depth_, bmin_, bmax_);
62 }
63 
init(int resolution_[3],int depth_,Vec3d bmin_,Vec3d bmax_)64 void ObjMeshOffsetVoxels::init(int resolution_[3], int depth_, Vec3d bmin_, Vec3d bmax_)
65 {
66   resolution[0] = resolution_[0];
67   resolution[1] = resolution_[1];
68   resolution[2] = resolution_[2];
69   depth = depth_;
70   bmin = bmin_;
71   bmax = bmax_;
72 
73   //cout << "Entering obj mesh voxelization routine..." << endl;
74   //cout << "Resolution is " << resolution[0] << " x " << resolution[1] << " x " << resolution[2] << " ..." << endl;
75 
76   //cout << "Checking if mesh is triangular... ";
77   if (!(objMesh->isTriangularMesh()))
78   {
79     //cout << "mesh was not triangular: triangulating... ";
80     objMesh->triangulate();
81     //cout << "done" << endl;
82   }
83   else
84   {
85     //cout << "yes" << endl;
86   }
87 
88   side = bmax - bmin;
89   inc[0] = side[0] / resolution[0];
90   inc[1] = side[1] / resolution[1];
91   inc[2] = side[2] / resolution[2];
92 
93   //cout << "Scene bounding box is: " << bmin << " " << bmax << endl;
94   //cout << "Computing voxels intersecting the model..." << endl;
95 
96   // iterate over all triangles
97   // for every triangle, find the voxel containing its center of mass
98   // then, grow the voxels until they don't intersect the triangle any more
99 
100   voxels.clear(); // will contain voxels intersecting the triangles
101 
102   // local search helpers:
103   set<voxel> checkedVoxels; // used to mark what voxels have already been visited
104   vector<voxel> scheduledVoxels; // contains voxels still to be processed
105   for (unsigned int i=0; i<objMesh->getNumGroups(); i++)
106   {
107     const ObjMesh::Group * getGroupHandle = objMesh->getGroupHandle(i);
108 
109     for (unsigned int j=0; j<getGroupHandle->getNumFaces(); j++)
110     {
111       Vec3d p0 = objMesh->getPosition(getGroupHandle->getFace(j).getVertex(0).getPositionIndex());
112       Vec3d p1 = objMesh->getPosition(getGroupHandle->getFace(j).getVertex(1).getPositionIndex());
113       Vec3d p2 = objMesh->getPosition(getGroupHandle->getFace(j).getVertex(2).getPositionIndex());
114       TriangleBasic triangle(p0,p1,p2);
115 
116       Vec3d center = 1.0 / 3 * (p0 + p1 + p2);
117       Vec3d relCenter = center-bmin;
118 
119       // find voxel containing center
120       int vi,vj,vk;
121       vi = (int)(relCenter[0] / inc[0]);
122       vj = (int)(relCenter[1] / inc[1]);
123       vk = (int)(relCenter[2] / inc[2]);
124 
125       checkedVoxels.clear();
126       checkedVoxels.insert(voxel(vi,vj,vk));
127 
128       scheduledVoxels.clear();
129       scheduledVoxels.push_back(voxel(vi,vj,vk));
130 
131       // while there are still some scheduled voxels:
132       //   take one
133       //   check if intersecting the triangle
134       //   if yes
135       //     add voxel to voxels
136       //     queue all neighbors that haven't been visited yet
137 
138       while (!scheduledVoxels.empty())
139       {
140         voxel v = scheduledVoxels.back();
141         scheduledVoxels.pop_back();
142 
143         // make bounding box for voxel
144         Vec3d bbmin = bmin + Vec3d(v.first * inc[0], v.second * inc[1], v.third * inc[2]);
145         BoundingBox bbox(bbmin, bbmin + inc);
146 
147         if (triangle.doesIntersectBox(bbox)) // intersection test
148         {
149 	  // add the voxel to the final list of hits
150           voxels.insert(v);
151           // queue all neighbors of v, and also put them into checkedVoxels
152           // (but don't do anything if they have already been queued)
153           voxel neighbor;
154           #define PROCESS(ii,jj,kk)\
155           neighbor = voxel(v.first+(ii),v.second+(jj),v.third+(kk));\
156           if ((neighbor.first >= 0) && (neighbor.first <= resolution[0]) &&\
157               (neighbor.second >= 0) && (neighbor.second <= resolution[1]) &&\
158               (neighbor.third >= 0) && (neighbor.third <= resolution[2])) \
159           {\
160             if (checkedVoxels.find(neighbor) == checkedVoxels.end())\
161             {\
162               checkedVoxels.insert(neighbor);\
163               scheduledVoxels.push_back(neighbor);\
164             }\
165           }
166           for (int iii=-1; iii<=1; iii++)
167             for (int jjj=-1; jjj<=1; jjj++)
168               for (int kkk=-1; kkk<=1; kkk++)
169               {
170                 if ((iii == 0) && (jjj ==0) && (kkk==0))
171                   continue;
172                 PROCESS(iii,jjj,kkk)
173               }
174         }
175       }
176 
177       // now, voxels contains all voxels that intersect the given triangle (plus everything from previous triangles)
178     }
179   }
180 
181   // now, voxels contains all voxels intersecting any triangle
182 
183   //cout << "Growing " << depth << " layers of voxels out of the original (squashing cubes) layer." << endl;
184 
185   // grow voxels several layers
186   set<voxel> voxeli; // temporary buffer
187   for (int i=0; i<depth; i++)
188   {
189     // expand all voxels in all directions
190     // take everything out of voxels, expand one layer, and insert into voxeli
191     voxeli.clear();
192 
193     voxel neighbor;
194 
195     #define PROCESSI(ii,jj,kk)\
196       neighbor = voxel(vox->first+(ii),vox->second+(jj),vox->third+(kk));\
197       if ((neighbor.first >= 0) && (neighbor.first <= resolution[0]) &&\
198           (neighbor.second >= 0) && (neighbor.second <= resolution[1]) &&\
199           (neighbor.third >= 0) && (neighbor.third <= resolution[2])) \
200       {\
201 	voxeli.insert(neighbor);\
202       }
203 
204     set<voxel>::iterator vox;
205 
206     for (vox = voxels.begin(); vox != voxels.end(); ++vox) // over all members of voxels
207     {
208       for (int iii=-1; iii<=1; iii++)
209         for (int jjj=-1; jjj<=1; jjj++)
210           for (int kkk=-1; kkk<=1; kkk++)
211           {
212             PROCESSI(iii,jjj,kkk)
213           }
214     }
215     voxels = voxeli;
216   }
217 
218   //cout << "Building unique list of faces..." << endl;
219   // build unique list of faces
220 
221   buildUniqueListOfFaces();
222 }
223 
emptyComponents(vector<Vec3d> & componentSeeds,vector<int> & componentSize,bool interiorOnly)224 void ObjMeshOffsetVoxels::emptyComponents(vector<Vec3d> & componentSeeds, vector<int> & componentSize, bool interiorOnly)
225 {
226   componentSeeds.clear();
227   componentSize.clear();
228 
229   set<voxel> voxelSet = voxels;
230 
231   for(int i=0; i<resolution[0]; i++)
232     for(int j=0; j<resolution[1]; j++)
233       for(int k=0; k<resolution[2]; k++)
234       {
235         if (voxelSet.find(voxel(i,j,k)) == voxelSet.end())
236         {
237           // new component detected
238           size_t sizePrev = voxelSet.size();
239           Vec3d seed(bmin[0] + inc[0] * ( i + 0.5 ),
240                      bmin[1] + inc[1] * ( j + 0.5 ),
241                      bmin[2] + inc[2] * ( k + 0.5 ));
242           bool touchesBoundingBox = floodFillFromSet(seed, voxelSet);
243           if (!(interiorOnly && touchesBoundingBox))
244           {
245             componentSize.push_back(voxelSet.size() - sizePrev);
246             componentSeeds.push_back(seed);
247           }
248         }
249       }
250 }
251 
floodFill(Vec3d seed)252 void ObjMeshOffsetVoxels::floodFill(Vec3d seed)
253 {
254   //cout << "Flood-filling from seed: " << seed << endl;
255   floodFillFromSet(seed, voxels);
256   buildUniqueListOfFaces();
257 }
258 
floodFill(vector<Vec3d> & seeds)259 void ObjMeshOffsetVoxels::floodFill(vector<Vec3d> & seeds)
260 {
261   for(unsigned int i=0; i<seeds.size(); i++)
262   {
263     //cout << "Flood-filling from seed: " << seeds[i] << endl;
264     floodFillFromSet(seeds[i], voxels);
265   }
266 
267   buildUniqueListOfFaces();
268 }
269 
floodFillFromSet(Vec3d seed,set<voxel> & voxelSet)270 bool ObjMeshOffsetVoxels::floodFillFromSet(Vec3d seed, set<voxel> & voxelSet)
271 {
272   bool touchesBoundingBox = false;
273 
274   // find voxel containing seed
275   int vi,vj,vk;
276   Vec3d relSeed = seed-bmin;
277   vi = (int)(relSeed[0] / inc[0]);
278   vj = (int)(relSeed[1] / inc[1]);
279   vk = (int)(relSeed[2] / inc[2]);
280 
281   if ((vi < 0) || (vi >= resolution[0]) ||
282      (vj < 0) || (vj >= resolution[1]) ||
283      (vk < 0) || (vk >= resolution[2]))
284   {
285     printf("Warning: flood-filling seed is outside the bounding box. Performing no flood-fill.\n");
286     return false;
287   }
288 
289 
290   voxel seedVoxel(vi,vj,vk);
291 
292   set<voxel> queue;
293   queue.insert(seedVoxel);
294   voxelSet.insert(seedVoxel);
295 
296   while (!queue.empty())
297   {
298     //cout << "." << flush;
299 
300     voxel vox = *(queue.begin());
301     queue.erase(vox);
302 
303     voxel neighbor;
304 
305     //printf("vox: %d %d %d\n",vox.first,vox.second,vox.third);
306 
307     // process all 8 neighbors
308     #define PROCESSNGH(ii,jj,kk)\
309     neighbor = voxel(vox.first+(ii),vox.second+(jj),vox.third+(kk));\
310     if ((neighbor.first >= 0) && (neighbor.first < resolution[0]) &&\
311         (neighbor.second >= 0) && (neighbor.second < resolution[1]) &&\
312         (neighbor.third >= 0) && (neighbor.third < resolution[2])) \
313     {\
314       if (voxelSet.find(neighbor) == voxelSet.end())\
315       {\
316         queue.insert(neighbor);\
317         voxelSet.insert(neighbor);\
318         if (!touchesBoundingBox)\
319           if ((neighbor.first == 0)  || (neighbor.first == resolution[0] - 1) ||\
320               (neighbor.second == 0) || (neighbor.second == resolution[1] - 1) ||\
321               (neighbor.third == 0)  || (neighbor.third == resolution[2] - 1))\
322                 touchesBoundingBox = true;\
323       }\
324     }
325 
326     PROCESSNGH(1,0,0);
327     PROCESSNGH(-1,0,0);
328     PROCESSNGH(0,1,0);
329     PROCESSNGH(0,-1,0);
330     PROCESSNGH(0,0,1);
331     PROCESSNGH(0,0,-1);
332   }
333 
334   return touchesBoundingBox;
335 }
336 
buildUniqueListOfFaces()337 void ObjMeshOffsetVoxels::buildUniqueListOfFaces()
338 {
339   surfaceFaces.clear();
340   interiorFaces.clear();
341 
342   set<voxel>::iterator vox;
343   for (vox = voxels.begin(); vox != voxels.end(); ++vox) // over all members of voxels
344   {
345     // for each face of vox:
346     //   if already on the list of surface faces, erase it from there, and add it among interior faces
347     //   else add it among surface faces
348 
349     //cout << "Voxel: " << vox->first << " " << vox->second << " " << vox->third << endl;
350 
351     gridPoint pmin(vox->first,vox->second,vox->third);
352     gridPoint pmax(vox->first+1,vox->second+1,vox->third+1);
353 
354     gridPoint p0(pmin.first,pmin.second,pmin.third);
355     gridPoint p1(pmax.first,pmin.second,pmin.third);
356     gridPoint p2(pmax.first,pmax.second,pmin.third);
357     gridPoint p3(pmin.first,pmax.second,pmin.third);
358 
359     gridPoint p4(pmin.first,pmin.second,pmax.third);
360     gridPoint p5(pmax.first,pmin.second,pmax.third);
361     gridPoint p6(pmax.first,pmax.second,pmax.third);
362     gridPoint p7(pmin.first,pmax.second,pmax.third);
363 
364     TopologicalFace * face;
365 
366     #define PROCESS_FACE(q0,q1,q2,q3)\
367     face = new TopologicalFace((q0),(q1),(q2),(q3));\
368     if (surfaceFaces.find(*face) != surfaceFaces.end())\
369     {\
370       surfaceFaces.erase(*face);\
371       interiorFaces.insert(*face);\
372     }\
373     else\
374     {\
375       surfaceFaces.insert(*face);\
376     }\
377     delete(face);
378 
379     PROCESS_FACE(p0,p3,p2,p1)
380     PROCESS_FACE(p4,p5,p6,p7)
381     PROCESS_FACE(p0,p1,p5,p4)
382     PROCESS_FACE(p3,p7,p6,p2)
383     PROCESS_FACE(p1,p2,p6,p5)
384     PROCESS_FACE(p0,p4,p7,p3)
385   }
386 }
387 
render()388 void ObjMeshOffsetVoxels::render()
389 {
390   set<voxel>::iterator vox;
391   for (vox = voxels.begin(); vox != voxels.end(); ++vox) // over all members of voxels
392      renderVoxel(*vox);
393 }
394 
renderSurfaceFaces()395 void ObjMeshOffsetVoxels::renderSurfaceFaces()
396 {
397   set<TopologicalFace,FaceOrder>::iterator face;
398 
399   for (face = surfaceFaces.begin(); face != surfaceFaces.end(); ++face) // over all surface faces
400     renderTopologicalFace(*face);
401 }
402 
403 
404 
renderVoxel(voxel vox)405 void ObjMeshOffsetVoxels::renderVoxel(voxel vox)
406 {
407   // make bounding box for voxel
408   Vec3d bbmin = bmin + Vec3d(vox.first*inc[0],vox.second*inc[1],vox.third*inc[2]);
409   BoundingBox bbox(bbmin,bbmin+inc);
410   bbox.render();
411 }
412 
renderTopologicalFace(const TopologicalFace & face) const413 void ObjMeshOffsetVoxels::renderTopologicalFace(const TopologicalFace & face) const
414 {
415   // make flat bounding box
416   Vec3d bbmin = Vec3d(face.vertex(0).first*inc[0],face.vertex(0).second*inc[1],face.vertex(0).third*inc[2]);
417   bbmin += bmin;
418   Vec3d bbmax = Vec3d(face.vertex(2).first*inc[0],face.vertex(2).second*inc[1],face.vertex(2).third*inc[2]);
419   bbmax += bmin;
420   BoundingBox bbox(bbmin,bbmax);
421   bbox.render();
422 }
423 
surfaceOffsetMesh()424 ObjMesh * ObjMeshOffsetVoxels::surfaceOffsetMesh()
425 {
426   ObjMesh * objMesh = new ObjMesh();
427 
428   // create a list of vertices
429   set<gridPoint> vertices;
430 
431   set<TopologicalFace,FaceOrder>::iterator face; // insert all vertices
432   for (face = surfaceFaces.begin(); face != surfaceFaces.end(); ++face) // over all surface faces
433   {
434     vertices.insert(face->vertex(0));
435     vertices.insert(face->vertex(1));
436     vertices.insert(face->vertex(2));
437     vertices.insert(face->vertex(3));
438   }
439 
440   // now, vertices contains all vertices with no duplications
441 
442   // create default group
443   objMesh->addGroup("Default");
444 
445   // add all vertices into a map, together with their corresponding position
446   // also, add vertices to objMesh
447   map<gridPoint,int> vertices2;
448   set<gridPoint>:: iterator v;
449   int position=0;
450   for (v = vertices.begin(); v != vertices.end(); ++v)
451   {
452     vertices2.insert(pair<gridPoint,int>(*v,position));
453     Vec3d pos = bmin + Vec3d(v->first*inc[0], v->second*inc[1], v->third*inc[2]);
454     objMesh->addVertexPosition( pos );
455     //cout << "Position " << position << ": " << pos << endl;
456     position++;
457   }
458 
459   // add all faces
460   unsigned int index;
461   for (face = surfaceFaces.begin(); face != surfaceFaces.end(); ++face) // over all surface faces
462   {
463     ObjMesh::Face newFace;
464     for (int i=0; i<4; i++)
465     {
466       index = (vertices2.find(face->vertex(i)))->second;
467 
468       std::pair< bool, unsigned int > texPos(false,0); // no textures or normals assigned
469       std::pair< bool, unsigned int > normal(false,0);
470 
471       newFace.addVertex( ObjMesh::Vertex( index, texPos, normal ) );
472 
473     }
474     objMesh->addFaceToGroup(newFace,0);
475   }
476 
477   return objMesh;
478 }
479 
operator ()(const TopologicalFace & x,const TopologicalFace & y) const480 bool ObjMeshOffsetVoxels::FaceOrder::operator()(const TopologicalFace & x, const TopologicalFace & y) const
481 {
482 
483   // first, sort the vertices on each face (order of vertices is irrelevant when comparing if two faces are equal)
484   TopologicalFace xSorted = x; xSorted.sortVertices();
485   TopologicalFace ySorted = y; ySorted.sortVertices();
486 
487   for (int i=0; i<4; i++)
488   {
489     gridPoint x1 = xSorted.vertex(i);
490     gridPoint y1 = ySorted.vertex(i);
491 
492     if (x1 < y1)
493       return true;
494     if (y1 < x1)
495       return false;
496   }
497 
498   return false;
499 }
500 
TopologicalFace(gridPoint p1,gridPoint p2,gridPoint p3,gridPoint p4)501 ObjMeshOffsetVoxels::TopologicalFace::TopologicalFace(gridPoint p1, gridPoint p2, gridPoint p3, gridPoint p4)
502 {
503   vertices_.push_back(p1); vertices_.push_back(p2); vertices_.push_back(p3); vertices_.push_back(p4);
504 
505   assert(vertices_.size() == 4);
506 }
507 
sortVertices()508 void ObjMeshOffsetVoxels::TopologicalFace::sortVertices()
509 {
510   sort(vertices_.begin(),vertices_.end());
511 
512   // sanity check
513   unique(vertices_.begin(),vertices_.end());
514   assert(vertices_.size() == 4);
515 }
516 
generateCubicMesh(const string & filenameVeg,const string & filenameInterp,const string & filenameObj)517 void ObjMeshOffsetVoxels::generateCubicMesh(const string & filenameVeg, const string & filenameInterp, const string & filenameObj)
518 {
519   cout << "Generating cubic mesh..." << endl;
520   cout << "Writing mesh to " << filenameVeg << " ." << endl;
521 
522   // open file
523   ofstream fout(filenameVeg.c_str());
524 
525   if (!fout)
526   {
527     cout << "Error: could not write to file " << filenameVeg << endl;
528     return;
529   }
530 
531   // create a list of vertices in all voxels
532   set<gridPoint> vertices;
533   // insert all voxel vertices
534   set<voxel>::iterator aVoxel;
535   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
536   {
537     unsigned int i1,j1,k1;
538     i1 = aVoxel->first;
539     j1 = aVoxel->second;
540     k1 = aVoxel->third;
541 
542     vertices.insert(gridPoint(i1,j1,k1));
543     vertices.insert(gridPoint(i1+1,j1,k1));
544     vertices.insert(gridPoint(i1+1,j1+1,k1));
545     vertices.insert(gridPoint(i1,j1+1,k1));
546 
547     vertices.insert(gridPoint(i1,j1,k1+1));
548     vertices.insert(gridPoint(i1+1,j1,k1+1));
549     vertices.insert(gridPoint(i1+1,j1+1,k1+1));
550     vertices.insert(gridPoint(i1,j1+1,k1+1));
551   }
552 
553   // now, vertices contains all voxel vertices with no duplications
554 
555   cout << "Num voxels: " << voxels.size() << " Num voxel vertices: " << vertices.size() << endl;
556 
557   // open up the objMesh for the output surface mesh
558   ObjMesh * objMesh = new ObjMesh();
559 
560   // create default group
561   objMesh->addGroup("Default");
562 
563   // add all voxel vertices into a map, together with their corresponding index (i.e. serial number of a voxel vertex in the set order)
564   map<gridPoint,int> vertices2;
565   set<gridPoint>:: iterator v; // will run over all voxel vertices
566   int position=0;
567 
568   fout << "*VERTICES" << endl;
569   fout << (int)vertices.size() << " 3 0 0" << endl;
570 
571   for (v = vertices.begin(); v != vertices.end(); ++v)
572   {
573     vertices2.insert(pair<gridPoint,int>(*v,position));
574     Vec3d pos = bmin + Vec3d(v->first*inc[0], v->second*inc[1], v->third*inc[2]);
575     objMesh->addVertexPosition(pos);
576 
577     //cout << "Position " << position << ": " << pos << endl;
578     position++;
579 
580     // write vertex to file
581     fout << setprecision (16) << position << " " << pos[0] << " " << pos[1] << " " << pos[2] << endl;
582   }
583 
584   fout << endl;
585   fout << "*ELEMENTS" << endl;
586   fout << "CUBIC" << endl;
587   fout << (int)voxels.size() << " 4 0" <<  endl;
588 
589   // print out all voxels
590   unsigned int index;
591   position = 0;
592   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
593   {
594     fout << position+1;
595     unsigned int i1,j1,k1;
596     i1 = aVoxel->first;
597     j1 = aVoxel->second;
598     k1 = aVoxel->third;
599 
600     #define PROCESS_CORNER(di,dj,dk)\
601     index = 1+(vertices2.find(gridPoint(i1+(di),j1+(dj),k1+(dk))))->second;\
602     fout << " " << index;
603 
604     PROCESS_CORNER(0,0,0);
605     PROCESS_CORNER(1,0,0);
606     PROCESS_CORNER(1,1,0);
607     PROCESS_CORNER(0,1,0);
608     PROCESS_CORNER(0,0,1);
609     PROCESS_CORNER(1,0,1);
610     PROCESS_CORNER(1,1,1);
611     PROCESS_CORNER(0,1,1);
612 
613     fout << endl;
614 
615     position++;
616   }
617 
618   fout.close();
619 
620   // generate the barycentric masks
621 
622   cout << "Writing interpolation info to file " << filenameInterp << " ." << endl;
623 
624   // open file
625   fout.open(filenameInterp.c_str());
626 
627   if (!fout)
628   {
629     cout << "Error: could not write to file " << filenameInterp << endl;
630     return;
631   }
632 
633   // for every vertex of the mesh, find what voxel it is in
634   // then find indices of the vertices of that voxel
635   // and compute the barycentric coordinates
636 
637   for (unsigned int i=0; i < objMesh->getNumVertices(); i++) // over all vertices of the mesh
638   {
639     Vec3d pos = objMesh->getPosition(i);
640     unsigned int i1,j1,k1;
641 
642     Vec3d relPos = pos-bmin;
643 
644     // find voxel containing 'pos'
645     i1 = (unsigned int)(relPos[0] / inc[0]);
646     j1 = (unsigned int)(relPos[1] / inc[1]);
647     k1 = (unsigned int)(relPos[2] / inc[2]);
648 
649     // compute barycentric coordinates
650     Vec3d w = pos - (bmin + Vec3d(i1 * inc[0], j1 * inc[1], k1 * inc[2]));
651     double alpha = w[0] / inc[0];
652     double beta = w[1] / inc[1];
653     double gamma = w[2] / inc[2];
654 
655     unsigned int c000 = vertices2.find(gridPoint(i1+0,j1+0,k1+0))->second;
656     unsigned int c100 = vertices2.find(gridPoint(i1+1,j1+0,k1+0))->second;
657     unsigned int c110 = vertices2.find(gridPoint(i1+1,j1+1,k1+0))->second;
658     unsigned int c010 = vertices2.find(gridPoint(i1+0,j1+1,k1+0))->second;
659 
660     unsigned int c001 = vertices2.find(gridPoint(i1+0,j1+0,k1+1))->second;
661     unsigned int c101 = vertices2.find(gridPoint(i1+1,j1+0,k1+1))->second;
662     unsigned int c111 = vertices2.find(gridPoint(i1+1,j1+1,k1+1))->second;
663     unsigned int c011 = vertices2.find(gridPoint(i1+0,j1+1,k1+1))->second;
664 
665     double f000 = (1-alpha)*(1-beta)*(1-gamma);
666     double f100 = (alpha)*(1-beta)*(1-gamma);
667     double f110 = (alpha)*(beta)*(1-gamma);
668     double f010 = (1-alpha)*(beta)*(1-gamma);
669 
670     double f001 = (1-alpha)*(1-beta)*(gamma);
671     double f101 = (alpha)*(1-beta)*(gamma);
672     double f111 = (alpha)*(beta)*(gamma);
673     double f011 = (1-alpha)*(beta)*(gamma);
674 
675     fout << i << " ";
676 
677     fout << c000 << " " << f000 << " ";
678     fout << c100 << " " << f100 << " ";
679     fout << c110 << " " << f110 << " ";
680     fout << c010 << " " << f010 << " ";
681 
682     fout << c001 << " " << f001 << " ";
683     fout << c101 << " " << f101 << " ";
684     fout << c111 << " " << f111 << " ";
685     fout << c011 << " " << f011 << endl;
686   }
687 
688   fout.close();
689 
690   // by now, surfaceFaces contains a unique list of all surface faces
691   // add all faces to the surface obj mesh of the voxel mesh
692   set<TopologicalFace,FaceOrder>::iterator face;
693   for (face = surfaceFaces.begin(); face != surfaceFaces.end(); ++face) // all surface faces
694   {
695     int index[4];
696     for (int i=0; i<4; i++)
697       index[i] = (vertices2.find(face->vertex(i)))->second;
698 
699     std::pair< bool, unsigned int > texPos(false,0); // no textures
700     std::pair< bool, unsigned int > normal(false,0); // no normals
701 
702 /*
703     // triangulate the face into two triangles
704 
705     Face newFace1;
706     newFace1.addVertex( Vertex( index[0], texPos, normal ) );
707     newFace1.addVertex( Vertex( index[1], texPos, normal ) );
708     newFace1.addVertex( Vertex( index[2], texPos, normal ) );
709 
710     Face newFace2;
711     newFace2.addVertex( Vertex( index[2], texPos, normal ) );
712     newFace2.addVertex( Vertex( index[3], texPos, normal ) );
713     newFace2.addVertex( Vertex( index[0], texPos, normal ) );
714 
715     objMesh->addFaceToGroup(newFace1,0);
716     objMesh->addFaceToGroup(newFace2,0);
717 */
718 
719     // make one quad face
720 
721     ObjMesh::Face newFace;
722     newFace.addVertex( ObjMesh::Vertex( index[0], texPos, normal ) );
723     newFace.addVertex( ObjMesh::Vertex( index[1], texPos, normal ) );
724     newFace.addVertex( ObjMesh::Vertex( index[2], texPos, normal ) );
725     newFace.addVertex( ObjMesh::Vertex( index[3], texPos, normal ) );
726 
727     objMesh->addFaceToGroup(newFace,0);
728   }
729 
730   // search if there already is "default" material; if there is not, add it
731   objMesh->addDefaultMaterial();
732   objMesh->computeBoundingBox();
733 
734   objMesh->save(filenameObj);
735 
736   delete(objMesh);
737 }
738 
generateCubicMesh(int * numCubeVertices,double ** cubeVertices,int * numCubes,int ** cubes,int ** interpolationVertices,double ** interpolationWeights,ObjMesh ** surfaceMesh)739 void ObjMeshOffsetVoxels::generateCubicMesh(int * numCubeVertices, double ** cubeVertices, int * numCubes, int ** cubes, int ** interpolationVertices, double ** interpolationWeights, ObjMesh ** surfaceMesh)
740 {
741   //cout << "Generating cubic mesh..." << endl;
742 
743   // create a list of vertices in all voxels
744   set<gridPoint> vertices;
745   // insert all voxel vertices
746   set<voxel>::iterator aVoxel;
747   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
748   {
749     unsigned int i1,j1,k1;
750     i1 = aVoxel->first;
751     j1 = aVoxel->second;
752     k1 = aVoxel->third;
753 
754     vertices.insert(gridPoint(i1,j1,k1));
755     vertices.insert(gridPoint(i1+1,j1,k1));
756     vertices.insert(gridPoint(i1+1,j1+1,k1));
757     vertices.insert(gridPoint(i1,j1+1,k1));
758 
759     vertices.insert(gridPoint(i1,j1,k1+1));
760     vertices.insert(gridPoint(i1+1,j1,k1+1));
761     vertices.insert(gridPoint(i1+1,j1+1,k1+1));
762     vertices.insert(gridPoint(i1,j1+1,k1+1));
763   }
764 
765   // now, "vertices" contains all voxel vertices with no duplications
766   //cout << "Num voxels: " << voxels.size() << " Num voxel vertices: " << vertices.size() << endl;
767 
768   // creates an empty objMesh (for the output surface mesh)
769   *surfaceMesh = new ObjMesh();
770 
771   // create default group
772   (*surfaceMesh)->addGroup("Default");
773 
774   // add all voxel vertices into a map, together with their corresponding index (i.e. serial number of a voxel vertex in the set order)
775   map<gridPoint,int> vertices2;
776   set<gridPoint>:: iterator v; // will run over all voxel vertices
777 
778   int position=0;
779   *numCubeVertices = vertices.size();
780   *cubeVertices = (double*) malloc (sizeof(double) * 3 * vertices.size());
781   for (v = vertices.begin(); v != vertices.end(); ++v)
782   {
783     vertices2.insert(pair<gridPoint,int>(*v,position));
784     Vec3d pos = bmin + Vec3d(v->first*inc[0], v->second*inc[1], v->third*inc[2]);
785     (*surfaceMesh)->addVertexPosition(pos);
786 
787     (*cubeVertices)[3*position+0] = pos[0];
788     (*cubeVertices)[3*position+1] = pos[1];
789     (*cubeVertices)[3*position+2] = pos[2];
790 
791     //cout << "Position " << position << ": " << pos << endl;
792     position++;
793   }
794 
795   unsigned int index;
796   position = 0;
797   *numCubes = voxels.size();
798   *cubes = (int*) malloc (sizeof(int) * voxels.size() * 8);
799   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
800   {
801     unsigned int i1,j1,k1;
802     i1 = aVoxel->first;
803     j1 = aVoxel->second;
804     k1 = aVoxel->third;
805 
806     #define PROCESS_CORNER_SHORT(di,dj,dk)\
807     index = (vertices2.find(gridPoint(i1+(di),j1+(dj),k1+(dk))))->second;
808 
809     PROCESS_CORNER_SHORT(0,0,0); (*cubes)[8*position+0] = index;
810     PROCESS_CORNER_SHORT(1,0,0); (*cubes)[8*position+1] = index;
811     PROCESS_CORNER_SHORT(1,1,0); (*cubes)[8*position+2] = index;
812     PROCESS_CORNER_SHORT(0,1,0); (*cubes)[8*position+3] = index;
813     PROCESS_CORNER_SHORT(0,0,1); (*cubes)[8*position+4] = index;
814     PROCESS_CORNER_SHORT(1,0,1); (*cubes)[8*position+5] = index;
815     PROCESS_CORNER_SHORT(1,1,1); (*cubes)[8*position+6] = index;
816     PROCESS_CORNER_SHORT(0,1,1); (*cubes)[8*position+7] = index;
817 
818     position++;
819   }
820 
821   // generate the barycentric masks
822 
823   // for every vertex of the mesh, find what voxel it is in
824   // then, find indices of the vertices of that voxel
825   // and compute the barycentric coordinates
826 
827   *interpolationVertices = (int*) malloc (sizeof(int) * 8 * objMesh->getNumVertices());
828   *interpolationWeights = (double*) malloc (sizeof(double) * 8 * objMesh->getNumVertices());
829 
830   for (unsigned int i=0; i < objMesh->getNumVertices(); i++) // over all vertices of the mesh
831   {
832     Vec3d pos = objMesh->getPosition(i);
833     unsigned int i1,j1,k1;
834 
835     Vec3d relPos = pos-bmin;
836 
837     // find voxel containing 'pos'
838     i1 = (unsigned int)(relPos[0] / inc[0]);
839     j1 = (unsigned int)(relPos[1] / inc[1]);
840     k1 = (unsigned int)(relPos[2] / inc[2]);
841 
842     // compute barycentric coordinates
843     Vec3d w = pos - (bmin + Vec3d(i1 * inc[0], j1 * inc[1], k1 * inc[2]));
844     double alpha = w[0] / inc[0];
845     double beta = w[1] / inc[1];
846     double gamma = w[2] / inc[2];
847 
848     unsigned int c000, c100, c110, c010, c001, c101, c111, c011;
849     unsigned int * cArray[8] = { &c000, &c100, &c110, &c010, &c001, &c101, &c111, &c011 };
850     int offset[8][3] = { {0, 0, 0}, {1, 0, 0}, {1, 1, 0}, {0, 1, 0}, {0, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 1, 1} };
851     for(int j=0; j<8; j++)
852     {
853       map<gridPoint,int> :: iterator iter = vertices2.find(gridPoint(i1 + offset[j][0], j1 + offset[j][1], k1 + offset[j][2]));
854       if (iter != vertices2.end())
855         *(cArray[j]) = iter->second;
856       else
857         *(cArray[j]) = 0; // handle case where vertex is at the boundary of a voxel and round-off may move it to a non-existing voxel (barycentric coordinate is zero in this case)
858     }
859 
860     //unsigned int c000 = vertices2.find(gridPoint(i1+0,j1+0,k1+0))->second;
861     //unsigned int c100 = vertices2.find(gridPoint(i1+1,j1+0,k1+0))->second;
862     //unsigned int c110 = vertices2.find(gridPoint(i1+1,j1+1,k1+0))->second;
863     //unsigned int c010 = vertices2.find(gridPoint(i1+0,j1+1,k1+0))->second;
864 
865     //unsigned int c001 = vertices2.find(gridPoint(i1+0,j1+0,k1+1))->second;
866     //unsigned int c101 = vertices2.find(gridPoint(i1+1,j1+0,k1+1))->second;
867     //unsigned int c111 = vertices2.find(gridPoint(i1+1,j1+1,k1+1))->second;
868     //unsigned int c011 = vertices2.find(gridPoint(i1+0,j1+1,k1+1))->second;
869 
870     double f000 = (1-alpha)*(1-beta)*(1-gamma);
871     double f100 = (alpha)*(1-beta)*(1-gamma);
872     double f110 = (alpha)*(beta)*(1-gamma);
873     double f010 = (1-alpha)*(beta)*(1-gamma);
874 
875     double f001 = (1-alpha)*(1-beta)*(gamma);
876     double f101 = (alpha)*(1-beta)*(gamma);
877     double f111 = (alpha)*(beta)*(gamma);
878     double f011 = (1-alpha)*(beta)*(gamma);
879 
880     (*interpolationVertices)[8*i+0] = c000;
881     (*interpolationVertices)[8*i+1] = c100;
882     (*interpolationVertices)[8*i+2] = c110;
883     (*interpolationVertices)[8*i+3] = c010;
884     (*interpolationVertices)[8*i+4] = c001;
885     (*interpolationVertices)[8*i+5] = c101;
886     (*interpolationVertices)[8*i+6] = c111;
887     (*interpolationVertices)[8*i+7] = c011;
888 
889     (*interpolationWeights)[8*i+0] = f000;
890     (*interpolationWeights)[8*i+1] = f100;
891     (*interpolationWeights)[8*i+2] = f110;
892     (*interpolationWeights)[8*i+3] = f010;
893     (*interpolationWeights)[8*i+4] = f001;
894     (*interpolationWeights)[8*i+5] = f101;
895     (*interpolationWeights)[8*i+6] = f111;
896     (*interpolationWeights)[8*i+7] = f011;
897   }
898 
899   // by now, surfaceFaces contains a unique list of all surface faces
900   // add all faces to the surface obj mesh of the voxel mesh
901   set<TopologicalFace,FaceOrder>::iterator face;
902   for (face = surfaceFaces.begin(); face != surfaceFaces.end(); ++face) // all surface faces
903   {
904     int index[4];
905     for (int i=0; i<4; i++)
906       index[i] = (vertices2.find(face->vertex(i)))->second;
907 
908     std::pair< bool, unsigned int > texPos(false,0); // no textures
909     std::pair< bool, unsigned int > normal(false,0); // no normals
910 
911     /*
912     // triangulate the face into two triangles
913 
914     Face newFace1;
915     newFace1.addVertex( Vertex( index[0], texPos, normal ) );
916     newFace1.addVertex( Vertex( index[1], texPos, normal ) );
917     newFace1.addVertex( Vertex( index[2], texPos, normal ) );
918 
919     Face newFace2;
920     newFace2.addVertex( Vertex( index[2], texPos, normal ) );
921     newFace2.addVertex( Vertex( index[3], texPos, normal ) );
922     newFace2.addVertex( Vertex( index[0], texPos, normal ) );
923 
924     objMesh->addFaceToGroup(newFace1,0);
925     objMesh->addFaceToGroup(newFace2,0);
926      */
927 
928     // make one quad face
929 
930     ObjMesh::Face newFace;
931     newFace.addVertex( ObjMesh::Vertex( index[0], texPos, normal ) );
932     newFace.addVertex( ObjMesh::Vertex( index[1], texPos, normal ) );
933     newFace.addVertex( ObjMesh::Vertex( index[2], texPos, normal ) );
934     newFace.addVertex( ObjMesh::Vertex( index[3], texPos, normal ) );
935 
936     (*surfaceMesh)->addFaceToGroup(newFace,0);
937   }
938 
939   // search if there already is "default" material; if there is not, add it
940   (*surfaceMesh)->addDefaultMaterial();
941 
942   (*surfaceMesh)->computeBoundingBox();
943 }
944 
generateInterpolationMasks(const string & filenameInterp,const string & inputObjMesh)945 void ObjMeshOffsetVoxels::generateInterpolationMasks(const string & filenameInterp, const string & inputObjMesh)
946 {
947   cout << "Generating interpolation masks for the external file " << inputObjMesh << endl;
948 
949   // create a list of vertices in all voxels
950   set<gridPoint> vertices;
951 
952   // insert all voxel vertices
953   set<voxel>::iterator aVoxel;
954   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
955   {
956     unsigned int i1,j1,k1;
957     i1 = aVoxel->first;
958     j1 = aVoxel->second;
959     k1 = aVoxel->third;
960 
961     vertices.insert(gridPoint(i1,j1,k1));
962     vertices.insert(gridPoint(i1+1,j1,k1));
963     vertices.insert(gridPoint(i1+1,j1+1,k1));
964     vertices.insert(gridPoint(i1,j1+1,k1));
965 
966     vertices.insert(gridPoint(i1,j1,k1+1));
967     vertices.insert(gridPoint(i1+1,j1,k1+1));
968     vertices.insert(gridPoint(i1+1,j1+1,k1+1));
969     vertices.insert(gridPoint(i1,j1+1,k1+1));
970   }
971 
972   // now, vertices contains all voxel vertices with no duplications
973 
974   // add all voxel vertices into a map, together with their corresponding index (i.e. serial number of a voxel vertex in the set order)
975   map<gridPoint,int> vertices2;
976   set<gridPoint>:: iterator v; // will run over all voxel vertices
977   int position=0;
978   for (v = vertices.begin(); v != vertices.end(); ++v)
979   {
980     vertices2.insert(pair<gridPoint,int>(*v,position));
981     //Vec3d pos = bmin + Vec3d(v->first*inc[0], v->second*inc[1], v->third*inc[2]);
982     //cout << "Position " << position << ": " << pos << endl;
983     position++;
984   }
985 
986   // generate the barycentric masks
987 
988   cout << "Writing interpolation info to file " << filenameInterp << " ." << endl;
989 
990   // open file
991   ofstream fout(filenameInterp.c_str());
992 
993   if (!fout)
994   {
995     cout << "Error: could not write to file " << filenameInterp << endl;
996     return;
997   }
998 
999   // for every vertex of the mesh, find what voxel it is in
1000   // then find indices of the vertices of that voxel
1001   // and compute the barycentric coordinates
1002 
1003   ObjMesh inputMesh(inputObjMesh);
1004 
1005   // will contain all voxels that contain at least one vertex of the external mesh
1006   set<voxel> visitedVoxels;
1007 
1008   cout << "Processing vertices of the external mesh file..." << endl;
1009   for (unsigned int i=0; i < inputMesh.getNumVertices(); i++) // over all vertices of the mesh
1010   {
1011     if (i % 100 == 0)
1012       cout << i << " " << flush;
1013 
1014     Vec3d pos = inputMesh.getPosition(i);
1015     unsigned int i1,j1,k1;
1016 
1017     Vec3d relPos = pos-bmin;
1018 
1019     // find voxel containing 'pos'
1020     i1 = (unsigned int)(relPos[0] / inc[0]);
1021     j1 = (unsigned int)(relPos[1] / inc[1]);
1022     k1 = (unsigned int)(relPos[2] / inc[2]);
1023 
1024     // store voxel so that we can later print out a list of visited voxels
1025     visitedVoxels.insert(voxel(i1,j1,k1));
1026 
1027     // compute barycentric coordinates
1028     Vec3d w = pos - (bmin + Vec3d(i1 * inc[0], j1 * inc[1], k1 * inc[2]));
1029     double alpha = w[0] / inc[0];
1030     double beta = w[1] / inc[1];
1031     double gamma = w[2] / inc[2];
1032 
1033     map<gridPoint,int> :: iterator voxelVertexEntry;
1034 
1035     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+0,k1+0));
1036     if (voxelVertexEntry == vertices2.end())
1037     {
1038       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 000" << endl;
1039       return;
1040     }
1041     unsigned int c000 = voxelVertexEntry->second;
1042 
1043     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+0,k1+0));
1044     if (voxelVertexEntry == vertices2.end())
1045     {
1046       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 100" << endl;
1047       return;
1048     }
1049     unsigned int c100 = voxelVertexEntry->second;
1050 
1051     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+1,k1+0));
1052     if (voxelVertexEntry == vertices2.end())
1053     {
1054       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 110" << endl;
1055       return;
1056     }
1057     unsigned int c110 = voxelVertexEntry->second;
1058 
1059     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+1,k1+0));
1060     if (voxelVertexEntry == vertices2.end())
1061     {
1062       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 010" << endl;
1063       return;
1064     }
1065     unsigned int c010 = voxelVertexEntry->second;
1066 
1067     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+0,k1+1));
1068     if (voxelVertexEntry == vertices2.end())
1069     {
1070       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 001" << endl;
1071       return;
1072     }
1073     unsigned int c001 = voxelVertexEntry->second;
1074 
1075     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+0,k1+1));
1076     if (voxelVertexEntry == vertices2.end())
1077     {
1078       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 101" << endl;
1079       return;
1080     }
1081     unsigned int c101 = voxelVertexEntry->second;
1082 
1083     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+1,k1+1));
1084     if (voxelVertexEntry == vertices2.end())
1085     {
1086       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 111" << endl;
1087       return;
1088     }
1089     unsigned int c111 = voxelVertexEntry->second;
1090 
1091     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+1,k1+1));
1092     if (voxelVertexEntry == vertices2.end())
1093     {
1094       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 011" << endl;
1095       return;
1096     }
1097     unsigned int c011 = voxelVertexEntry->second;
1098 
1099 /*
1100     unsigned int c000 = vertices2.find(gridPoint(i1+0,j1+0,k1+0))->second;
1101     unsigned int c100 = vertices2.find(gridPoint(i1+1,j1+0,k1+0))->second;
1102     unsigned int c110 = vertices2.find(gridPoint(i1+1,j1+1,k1+0))->second;
1103     unsigned int c010 = vertices2.find(gridPoint(i1+0,j1+1,k1+0))->second;
1104 
1105     unsigned int c001 = vertices2.find(gridPoint(i1+0,j1+0,k1+1))->second;
1106     unsigned int c101 = vertices2.find(gridPoint(i1+1,j1+0,k1+1))->second;
1107     unsigned int c111 = vertices2.find(gridPoint(i1+1,j1+1,k1+1))->second;
1108     unsigned int c011 = vertices2.find(gridPoint(i1+0,j1+1,k1+1))->second;
1109 */
1110     double f000 = (1-alpha)*(1-beta)*(1-gamma);
1111     double f100 = (alpha)*(1-beta)*(1-gamma);
1112     double f110 = (alpha)*(beta)*(1-gamma);
1113     double f010 = (1-alpha)*(beta)*(1-gamma);
1114 
1115     double f001 = (1-alpha)*(1-beta)*(gamma);
1116     double f101 = (alpha)*(1-beta)*(gamma);
1117     double f111 = (alpha)*(beta)*(gamma);
1118     double f011 = (1-alpha)*(beta)*(gamma);
1119 
1120     fout << i << " ";
1121 
1122     fout << c000 << " " << f000 << " ";
1123     fout << c100 << " " << f100 << " ";
1124     fout << c110 << " " << f110 << " ";
1125     fout << c010 << " " << f010 << " ";
1126 
1127     fout << c001 << " " << f001 << " ";
1128     fout << c101 << " " << f101 << " ";
1129     fout << c111 << " " << f111 << " ";
1130     fout << c011 << " " << f011 << endl;
1131   }
1132 
1133   fout.close();
1134 
1135   // print out indices of all voxels that contain vertices of the external mesh
1136   int index=1;
1137   int lineCounter = 0;
1138   printf("\nVoxels that contain vertices of the given external mesh:\n");
1139   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
1140   {
1141     unsigned int i1,j1,k1;
1142     i1 = aVoxel->first;
1143     j1 = aVoxel->second;
1144     k1 = aVoxel->third;
1145 
1146     // seek for (i1,j1,k1) in the list of all voxels
1147     if (visitedVoxels.find(voxel(i1,j1,k1)) != visitedVoxels.end())
1148     {
1149       printf("%d,",index);
1150       lineCounter++;
1151     }
1152 
1153     if (lineCounter >= 8)
1154     {
1155       lineCounter = 0;
1156       printf("\n");
1157     }
1158 
1159     index++;
1160   }
1161   printf("\n");
1162 
1163   index=1;
1164   lineCounter = 0;
1165   printf("\nVoxels that DO NOT contain vertices of the given external mesh:\n");
1166   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
1167   {
1168     unsigned int i1,j1,k1;
1169     i1 = aVoxel->first;
1170     j1 = aVoxel->second;
1171     k1 = aVoxel->third;
1172 
1173     // seek for (i1,j1,k1) in the list of all voxels
1174     if (visitedVoxels.find(voxel(i1,j1,k1)) == visitedVoxels.end())
1175     {
1176       printf("%d,",index);
1177       lineCounter++;
1178     }
1179 
1180     if (lineCounter >= 8)
1181     {
1182       lineCounter = 0;
1183       printf("\n");
1184     }
1185 
1186     index++;
1187   }
1188   printf("\n");
1189 
1190   cout << endl << "Total voxels: " << voxels.size() << " Successful termination." << endl;
1191 }
1192 
1193 //  generates the normal correction matrix for the vertices from the external file 'inputObjMesh'
generateNormalCorrectionMatrix(const string filenameCorrectionMatrix,const string inputObjMesh,const string filenameVoxelModalMatrix,const string filenameNormals)1194 void ObjMeshOffsetVoxels::generateNormalCorrectionMatrix(const string filenameCorrectionMatrix, const string inputObjMesh, const string filenameVoxelModalMatrix, const string filenameNormals)
1195 {
1196   cout << "Generating normal correction matrix  for the external file " << inputObjMesh << endl;
1197 
1198   // create a list of vertices in all voxels
1199   set<gridPoint> vertices;
1200 
1201   // insert all voxel vertices
1202   set<voxel>::iterator aVoxel;
1203   for (aVoxel = voxels.begin(); aVoxel != voxels.end(); ++aVoxel) // over all voxels
1204   {
1205     unsigned int i1,j1,k1;
1206     i1 = aVoxel->first;
1207     j1 = aVoxel->second;
1208     k1 = aVoxel->third;
1209 
1210     vertices.insert(gridPoint(i1,j1,k1));
1211     vertices.insert(gridPoint(i1+1,j1,k1));
1212     vertices.insert(gridPoint(i1+1,j1+1,k1));
1213     vertices.insert(gridPoint(i1,j1+1,k1));
1214 
1215     vertices.insert(gridPoint(i1,j1,k1+1));
1216     vertices.insert(gridPoint(i1+1,j1,k1+1));
1217     vertices.insert(gridPoint(i1+1,j1+1,k1+1));
1218     vertices.insert(gridPoint(i1,j1+1,k1+1));
1219   }
1220 
1221   // now, vertices contains all voxel vertices with no duplications
1222 
1223   // add all voxel vertices into a map, together with their corresponding index (i.e. serial number of a voxel vertex in the set order)
1224   map<gridPoint,int> vertices2;
1225   set<gridPoint>:: iterator v; // will run over all voxel vertices
1226   int position=0;
1227   for (v = vertices.begin(); v != vertices.end(); ++v)
1228   {
1229     vertices2.insert(pair<gridPoint,int>(*v,position));
1230     //Vec3d pos = bmin + Vec3d(v->first*inc[0], v->second*inc[1], v->third*inc[2]);
1231     //cout << "Position " << position << ": " << pos << endl;
1232     position++;
1233   }
1234 
1235   // === load the voxel modal matrix
1236   cout << "Loading the voxel modal matrix " << filenameVoxelModalMatrix << " ." << endl;
1237 
1238   int nVoxel,r;
1239   double * voxelModalMatrix;
1240   ReadMatrixFromDisk_((char*)filenameVoxelModalMatrix.c_str(), &nVoxel, &r, &voxelModalMatrix);
1241   nVoxel /= 3;
1242   Assert_(nVoxel,vertices.size(),1);
1243 
1244   // === load normals
1245 
1246   FILE * fin;
1247   OpenFile_((char*)filenameNormals.c_str(),&fin,"r");
1248 
1249   int numNormals;
1250   if (fscanf(fin,"%d\n",&numNormals) < 1)
1251     printf("Warning: bad input file syntax. Unable to read the number of normals.\n");
1252 
1253   vector<Vec3d> normals;
1254   for(int i=0; i<numNormals; i++)
1255   {
1256     double nx,ny,nz;
1257     if (fscanf(fin,"%lf %lf %lf\n",&nx,&ny,&nz) < 3)
1258       printf("Warning: bad input file syntax. Unable to read normals.\n");
1259     normals.push_back(Vec3d(nx,ny,nz));
1260   }
1261 
1262   fclose(fin);
1263 
1264   // === generate the normal correction matrix
1265 
1266   cout << "Loading the external file " << inputObjMesh << " ." << endl;
1267 
1268   ObjMesh inputMesh(inputObjMesh);
1269 
1270   cout << "Generating the normal correction matrix..." << endl;
1271 
1272   int n = inputMesh.getNumVertices();
1273 
1274   Assert_(n, numNormals, 2);
1275 
1276   double * outputMatrix = (double*) malloc (sizeof(double) * 3 * n * r);
1277 
1278   // for every vertex of the mesh, find what voxel it is in
1279   // then find indices of the vertices of that voxel
1280   // and compute the barycentric coordinates
1281   // the assemble the normal matrix correction
1282 
1283   cout << "Processing vertices of the external mesh file..." << endl;
1284   for (unsigned int i=0; i < inputMesh.getNumVertices(); i++) // over all vertices of the mesh
1285   {
1286     if (i % 100 == 0)
1287       cout << i << " " << flush;
1288 
1289     Vec3d pos = inputMesh.getPosition(i);
1290     unsigned int i1,j1,k1;
1291 
1292     Vec3d relPos = pos-bmin;
1293 
1294     // find voxel containing 'pos'
1295     i1 = (unsigned int)(relPos[0] / inc[0]);
1296     j1 = (unsigned int)(relPos[1] / inc[1]);
1297     k1 = (unsigned int)(relPos[2] / inc[2]);
1298 
1299     // compute barycentric coordinates
1300     Vec3d w = pos - (bmin + Vec3d(i1 * inc[0], j1 * inc[1], k1 * inc[2]));
1301     double alpha = w[0] / inc[0];
1302     double beta = w[1] / inc[1];
1303     double gamma = w[2] / inc[2];
1304 
1305     // locate voxel vertices
1306     map<gridPoint,int> :: iterator voxelVertexEntry;
1307 
1308     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+0,k1+0));
1309     if (voxelVertexEntry == vertices2.end())
1310     {
1311       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 000" << endl;
1312       return;
1313     }
1314     unsigned int c000 = voxelVertexEntry->second;
1315 
1316     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+0,k1+0));
1317     if (voxelVertexEntry == vertices2.end())
1318     {
1319       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 100" << endl;
1320       return;
1321     }
1322     unsigned int c100 = voxelVertexEntry->second;
1323 
1324     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+1,k1+0));
1325     if (voxelVertexEntry == vertices2.end())
1326     {
1327       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 110" << endl;
1328       return;
1329     }
1330     unsigned int c110 = voxelVertexEntry->second;
1331 
1332     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+1,k1+0));
1333     if (voxelVertexEntry == vertices2.end())
1334     {
1335       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 010" << endl;
1336       return;
1337     }
1338     unsigned int c010 = voxelVertexEntry->second;
1339 
1340     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+0,k1+1));
1341     if (voxelVertexEntry == vertices2.end())
1342     {
1343       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 001" << endl;
1344       return;
1345     }
1346     unsigned int c001 = voxelVertexEntry->second;
1347 
1348     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+0,k1+1));
1349     if (voxelVertexEntry == vertices2.end())
1350     {
1351       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 101" << endl;
1352       return;
1353     }
1354     unsigned int c101 = voxelVertexEntry->second;
1355 
1356     voxelVertexEntry = vertices2.find(gridPoint(i1+1,j1+1,k1+1));
1357     if (voxelVertexEntry == vertices2.end())
1358     {
1359       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 111" << endl;
1360       return;
1361     }
1362     unsigned int c111 = voxelVertexEntry->second;
1363 
1364     voxelVertexEntry = vertices2.find(gridPoint(i1+0,j1+1,k1+1));
1365     if (voxelVertexEntry == vertices2.end())
1366     {
1367       cout << "Error: vertex " << i+1 << " at location " << pos << " doesn't have corner neighbor 011" << endl;
1368       return;
1369     }
1370     unsigned int c011 = voxelVertexEntry->second;
1371 
1372 /*
1373     unsigned int c000 = vertices2.find(gridPoint(i1+0,j1+0,k1+0))->second;
1374     unsigned int c100 = vertices2.find(gridPoint(i1+1,j1+0,k1+0))->second;
1375     unsigned int c110 = vertices2.find(gridPoint(i1+1,j1+1,k1+0))->second;
1376     unsigned int c010 = vertices2.find(gridPoint(i1+0,j1+1,k1+0))->second;
1377 
1378     unsigned int c001 = vertices2.find(gridPoint(i1+0,j1+0,k1+1))->second;
1379     unsigned int c101 = vertices2.find(gridPoint(i1+1,j1+0,k1+1))->second;
1380     unsigned int c111 = vertices2.find(gridPoint(i1+1,j1+1,k1+1))->second;
1381     unsigned int c011 = vertices2.find(gridPoint(i1+0,j1+1,k1+1))->second;
1382 */
1383 /*
1384     double f000 = (1-alpha)*(1-beta)*(1-gamma);
1385     double f100 = (alpha)*(1-beta)*(1-gamma);
1386     double f110 = (alpha)*(beta)*(1-gamma);
1387     double f010 = (1-alpha)*(beta)*(1-gamma);
1388 
1389     double f001 = (1-alpha)*(1-beta)*(gamma);
1390     double f101 = (alpha)*(1-beta)*(gamma);
1391     double f111 = (alpha)*(beta)*(gamma);
1392     double f011 = (1-alpha)*(beta)*(gamma);
1393 */
1394     Vec3d gradf000(1.0 / inc[0] * -(1-beta)*(1-gamma), 1.0 / inc[1] * -(1-alpha)*(1-gamma), 1.0 / inc[2] * -(1-alpha)*(1-beta));
1395     Vec3d gradf100(1.0 / inc[0] * (1-beta)*(1-gamma), 1.0 / inc[1] * -alpha*(1-gamma), 1.0 / inc[2] * -alpha*(1-beta));
1396     Vec3d gradf110(1.0 / inc[0] * beta*(1-gamma), 1.0 / inc[1] * alpha*(1-gamma), 1.0 / inc[2] * -alpha*beta);
1397     Vec3d gradf010(1.0 / inc[0] * -beta*(1-gamma), 1.0 / inc[1] * (1-alpha)*(1-gamma), 1.0 / inc[2] * (1-alpha)*-beta);
1398 
1399     Vec3d gradf001(1.0 / inc[0] * -(1-beta)*gamma, 1.0 / inc[1] * -(1-alpha)*gamma, 1.0 / inc[2] * (1-alpha)*(1-beta));
1400     Vec3d gradf101(1.0 / inc[0] * (1-beta)*gamma, 1.0 / inc[1] * -alpha*gamma, 1.0 / inc[2] * alpha*(1-beta));
1401     Vec3d gradf111(1.0 / inc[0] * beta*gamma, 1.0 / inc[1] * alpha*gamma, 1.0 / inc[2] * alpha*beta);
1402     Vec3d gradf011(1.0 / inc[0] * -beta*gamma, 1.0 / inc[1] * (1-alpha)*gamma, 1.0 / inc[2] * (1-alpha)*beta);
1403 
1404     Vec3d normal = normals[i];
1405 
1406     for(int j=0; j<r; j++)
1407     {
1408       Vec3d u000(voxelModalMatrix[ELT(3*nVoxel,3*c000+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c000+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c000+2,j)]);
1409       Vec3d u100(voxelModalMatrix[ELT(3*nVoxel,3*c100+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c100+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c100+2,j)]);
1410       Vec3d u110(voxelModalMatrix[ELT(3*nVoxel,3*c110+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c110+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c110+2,j)]);
1411       Vec3d u010(voxelModalMatrix[ELT(3*nVoxel,3*c010+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c010+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c010+2,j)]);
1412       Vec3d u001(voxelModalMatrix[ELT(3*nVoxel,3*c001+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c001+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c001+2,j)]);
1413       Vec3d u101(voxelModalMatrix[ELT(3*nVoxel,3*c101+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c101+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c101+2,j)]);
1414       Vec3d u111(voxelModalMatrix[ELT(3*nVoxel,3*c111+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c111+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c111+2,j)]);
1415       Vec3d u011(voxelModalMatrix[ELT(3*nVoxel,3*c011+0,j)],voxelModalMatrix[ELT(3*nVoxel,3*c011+1,j)],voxelModalMatrix[ELT(3*nVoxel,3*c011+2,j)]);
1416 
1417       Vec3d coef(0,0,0);
1418       coef += dot(gradf000,normal) * u000;
1419       coef += dot(gradf100,normal) * u100;
1420       coef += dot(gradf110,normal) * u110;
1421       coef += dot(gradf010,normal) * u010;
1422       coef += dot(gradf001,normal) * u001;
1423       coef += dot(gradf101,normal) * u101;
1424       coef += dot(gradf111,normal) * u111;
1425       coef += dot(gradf011,normal) * u011;
1426 
1427       outputMatrix[ELT(3*n, 3*i+0, j)] = coef[0];
1428       outputMatrix[ELT(3*n, 3*i+1, j)] = coef[1];
1429       outputMatrix[ELT(3*n, 3*i+2, j)] = coef[2];
1430     }
1431 
1432   }
1433 
1434   cout << endl;
1435 
1436   WriteMatrixToDisk_((char*)filenameCorrectionMatrix.c_str(), 3*n, r, outputMatrix);
1437 
1438   free(outputMatrix);
1439   free(voxelModalMatrix);
1440 }
1441