libatomprobe
Library for Atom Probe Tomography (APT) computation
mesh.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 D Haley
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
19 #include <helper/helpFuncs.h>
20 
22 
23 #include <string>
24 #include <algorithm>
25 #include <limits>
26 #include <list>
27 #include <utility>
28 #include <deque>
29 
30 #ifdef _OPENMP
31  #include <omp.h>
32 #endif
33 
34 namespace AtomProbe
35 {
36 using std::deque;
37 using std::make_pair;
38 using std::vector;
39 using std::string;
40 using std::endl;
41 using std::list;
42 using std::cerr;
43 
44 enum
45 {
51 };
52 
53 const char *MESH_LOAD_ERRS[] = { "",
54  "Missing error message. This is a bug, please report it",
55  "Node count was different to number of present nodes",
56  "Element count was less than number of present elements",
57  "Mesh loaded, but failed to pass sanity checks"
58 };
59 
60 
61 const size_t PROGRESS_REDUCE=500;
62 
63 bool antiRotateMatch(const unsigned int *a, const unsigned int *b, size_t n)
64 {
65  size_t matchLength=0;
66  size_t offset=0;
67 
68  //The sequence matching step is analagous to the game "Simon", where a
69  // person matches a sequence of actions which gets progressively longer.
70  //When the match fails, we jump further along in the sequence to match
71 
72  //However, as a twist, we match one array in the forwards direction, and the other in the reverse direction (2*n)
73  while(matchLength !=n)
74  {
75  if(b[matchLength] !=a[(n+offset-matchLength)%n])
76  {
77  matchLength=0;
78  offset++;
79 
80  //Spin through until we hit the same element in the sequence
81  while(offset < n)
82  {
83  if(b[0] ==a[offset])
84  break;
85  offset++;
86  }
87 
88  if(offset ==n)
89  return false;
90  }
91 
92  matchLength++;
93  }
94 
95  return true;
96 }
97 
98 //Returns true if array A matches array B by rotating array B (treat array as a ring)
99 // if directionForwards is false, it attempts to match in the reverse direction
100 bool rotateMatch(const unsigned int *a, const unsigned int *b, size_t n, bool directionForwards=true)
101 {
102  size_t matchLength=0;
103  size_t offset=0;
104 
105  //The sequence matching step is analagous to the game "Simon", where a
106  // person matches a sequence of actions which gets progressively longer.
107  //When the match fails, we jump further along in the sequence to match
108 
109  unsigned int sign,delta;
110  if(directionForwards)
111  {
112  sign=1;
113  delta=0;
114  }
115  else
116  {
117  sign=-1;
118  delta=n;
119  }
120 
121  while(matchLength !=n)
122  {
123  if(b[matchLength] !=a[(delta+offset+sign*matchLength)%n])
124  {
125  matchLength=0;
126  offset++;
127 
128  //Spin through until we hit the same element in the sequence
129  while(offset < n)
130  {
131  if(b[0] ==a[offset])
132  break;
133  offset++;
134  }
135 
136  if(offset ==n)
137  return false;
138  }
139 
140  matchLength++;
141  }
142 
143  return true;
144 }
145 
146 
147 float signVal(unsigned int val)
148 {
149  if (val &1)
150  return 1;
151  else
152  return -1;
153 }
154 
155 size_t findMaxLessThanOrEq(const vector< std::pair<size_t,size_t> > &v,
156  size_t value)
157 {
158  ASSERT(v.size());
159  size_t curMax=v.begin()->first;
160  size_t curMaxOff=0;
161  for(size_t ui=0;ui<v.size();ui++)
162  {
163  if(v[ui].first > curMax && v[ui].first <=value)
164  curMaxOff=ui;
165  }
166 
167  return curMaxOff;
168 }
169 
170 
171 // Recursive definition of determinate using expansion by minors.
172 float Determinant(float **a,int n)
173 {
174  float det = 0;
175  ASSERT( n > 1);
176 
177  //Fundamental 2x2 det.
178  if (n == 2)
179  det = a[0][0] * a[1][1] - a[1][0] * a[0][1];
180  else
181  {
182  int i,j,j1,j2;
183  //recurisve det
184  det = 0;
185  for (j1=0; j1<n; j1++) {
186  float **m = new float*[n-1];
187  for (i=0; i<n-1; i++)
188  m[i] = new float[n-1];
189  for (i=1; i<n; i++) {
190  j2 = 0;
191  for (j=0; j<n; j++) {
192  if (j == j1)
193  continue;
194  m[i-1][j2] = a[i][j];
195  j2++;
196  }
197  }
198  det += signVal(2+j1) * a[0][j1] * Determinant(m,n-1);
199  for (i=0; i<n-1; i++)
200  delete[] m[i];
201  delete[] m;
202  }
203  }
204  return(det);
205 }
206 
207 //Special case of the four by four determinant, useful for tetrahedrons
208 //|a0 a1 a2 1 |
209 //|b0 b1 b2 1 |
210 //|c0 c1 c2 1 |
211 //|d0 d1 d2 1 |
212 float fourDeterminant(const Point3D &a, const Point3D &b, const Point3D &c, const Point3D &d)
213 {
214  float **rows;
215  rows = new float*[4];
216  //Malloc cols.
217  for(unsigned int ui=0;ui<4;ui++)
218  rows[ui] = new float[4];
219 
220  for(unsigned int ui=0;ui<3;ui++)
221  {
222  rows[0][ui] = a[ui];
223  rows[1][ui] = b[ui];
224  rows[2][ui] = c[ui];
225  rows[3][ui] = d[ui];
226  }
227 
228  for(unsigned int ui=0;ui<4;ui++)
229  rows[ui][3] = 1;
230 
231  float v;
232  v=Determinant(rows,4);
233 
234 
235  for(unsigned int ui=0;ui<4;ui++)
236  delete[] rows[ui];
237 
238  delete[] rows;
239 
240  return v;
241 
242 }
243 
244 //return the edge number for a triangle.
245 //To see this, draw a triangle, and going clockwise, label the edges 0, 1 and 2
246 //With the edge facing you, label the left corner with the edge number.
247 //Draw up the table mapping the edge that is formed by the vertices i,j;
248 //that is this function.
249 unsigned int edgeIdx(unsigned int i,unsigned int j)
250 {
251  ASSERT(i<3 && j < 3);
252  switch(i+j)
253  {
254  case 1:
255  return 1;
256  case 2:
257  return 0;
258  case 3:
259  return 2;
260  }
261  ASSERT(false);
262  return -1;
263 }
264 
265 
266 //---- BEGIN This section under specific licence ---
267 // Copyright 2001, softSurfer (www.softsurfer.com)
268 // This code may be freely used and modified for any purpose
269 // providing that this copyright notice is included with it.
270 // SoftSurfer makes no warranty for this code, and cannot be held
271 // liable for any real or imagined damage resulting from its use.
272 // Users of this code must verify correctness for their application.
273 // R - ray; t, triangle (array of 3 pts)
274 // returns
275 // -1 : degenerate case (triangle degen)
276 // 0: No intersect
277 // 1 : Single Intersection
278 // 2: Edge intersection (co-planar)
279 // I - intersection of ray w triangle; if exists and is unique
280 int intersect_RayTriangle( const Point3D &rayStart, const Point3D &rayEnd,
281  Point3D *tri, Point3D &I )
282 {
283  Point3D u, v, n; // triangle vectors
284  Point3D dir, w0, w; // ray vectors
285 
286 
287 
288  // get triangle edge vectors and plane normal
289  u = tri[1] - tri[0];
290  v = tri[2] - tri[0];
291  n = u.crossProd(v); // cross product
292 
293 
294  if (n.sqrMag() < (std::numeric_limits<float>::epsilon()) )
295  return -1; // do not deal with this case, the triangle is degenerate
296 
297  n.normalise();
298 
299  dir = rayEnd - rayStart; // ray direction vector
300 
301 
302  //Check for ray-plane intersection point
303  //--
304  Point3D rv1,rv2;
305  rv1 = rayStart - tri[0];
306  rv2 = rayEnd - tri[0];
307 
308  //If the dot products do not flip, the ray cannot cross infinite plane
309  float dp1 = rv1.dotProd(n);
310  float dp2 = rv2.dotProd(n);
311  if(dp1*dp2 > 0) //(signs are the same --> ray is on one side of plane only)
312  return 0;
313  else if(rv1.dotProd(n) < std::numeric_limits<float>::epsilon() &&
314  rv2.dotProd(n) < std::numeric_limits<float>::epsilon())
315 
316  {
317  //If the ray-ends -> vertex vectors have no component in the normal direction
318  //the ray is coplanar
319  return 2;
320  }
321 
322  //Project the ray onto the plane to create intersection point
323  //Solution is found by parameterising ray and solving for
324  //dot product with normal
325  I=rayStart-dir*rv1.dotProd(n)/dir.dotProd(n);
326 
327 
328  //--
329 
330  // is I inside T? If so, then the dot product of each edge
331  // with the ray from the edge start to the intersection will always
332  // be in range [0-1]; otherwise there will be at least one that is negative
333  float uu, uv, vv, wu, wv, D;
334  uu = u.dotProd(u);
335  uv = u.dotProd(v);
336  vv = v.dotProd(v);
337  w = I - tri[0];
338  wu = w.dotProd(u);
339  wv = w.dotProd(v);
340  D = uv * uv - uu * vv;
341 
342  // get and test parametric coords
343  float s, t;
344  s = (uv * wv - vv * wu) / D;
345  if (s < 0.0 || s > 1.0) // I is outside T
346  return 0;
347  t = (uv * wu - uu * wv) / D;
348  if (t < 0.0 || (s + t) > 1.0) // I is outside T
349  return 0;
350 
351  return 1; // I is in T
352 }
353 
354 //---- END This section under specific licence ---
355 
356 //Creates a list of pair,vector of point indices that are within a certain
357 // tolerance radius of one another. Output first value in list will be strictly increasing. (i.e. it->first < (it+1)->first, regardless of it position)
358 
359 //FIXME: This algorithm is a poor effort. It just picks a semi-random point,
360 //then nicks everything within the capture radius that was not nicked before.
361 // this will work if the adjacency points are *close*, and well separated, but not otherwise.
362 
363 //TODO: Unify these two overloads!
364 //--
365 void findNearVerticies(float tolerance, const vector<Point3D> &ptVec,
366  vector<std::pair<size_t,vector<size_t> > > &clusterList)
367 {
368  ASSERT(!clusterList.size());
369 
370  vector<bool> marked;
371  marked.resize(ptVec.size(),false);
372  //Try to find the common points
373  for(size_t ui=0;ui<ptVec.size();ui++)
374  {
375  vector<size_t> curClustered;
376 
377  //FIXME: replace with KD tree based search, or some other smart structure
378  for(size_t uj=0;uj<ptVec.size();uj++)
379  {
380  if(ui==uj|| marked[uj])
381  continue;
382 
383  if(ptVec[ui].sqrDist(ptVec[uj]) < tolerance)
384  {
385  curClustered.push_back(uj);
386  marked[uj]=true;
387  }
388 
389  }
390 
391  //If we found any points, then this point has also not been seen before
392  // by handshaking lemma
393  if(curClustered.size())
394  {
395  marked[ui]=true;
396  clusterList.push_back(std::make_pair(ui,curClustered));
397  curClustered.clear();
398  }
399 
400  }
401 
402 }
403 
404 void findNearVerticies(float tolerance, const vector<Point3D> &ptVec,
405  std::list<std::pair<size_t,vector<size_t> > > &clusterList)
406 {
407  ASSERT(clusterList.empty());
408 
409  vector<bool> marked;
410  marked.resize(ptVec.size(),false);
411  //Try to find the common points
412  for(size_t ui=0;ui<ptVec.size();ui++)
413  {
414  vector<size_t> curClustered;
415 
416  //FIXME: replace with KD tree based search, or some other smart structure
417  for(size_t uj=ui+1;uj<ptVec.size();uj++)
418  {
419  if(marked[uj])
420  continue;
421 
422  if(ptVec[ui].sqrDist(ptVec[uj]) < tolerance)
423  {
424  curClustered.push_back(uj);
425  marked[uj]=true;
426  }
427 
428  }
429 
430  //If we found any points, then this point has also not been seen before
431  // by handshaking lemma
432  if(curClustered.size())
433  {
434  marked[ui]=true;
435  clusterList.push_back(std::make_pair(ui,curClustered));
436  curClustered.clear();
437  }
438 
439  }
440 }
441 //--
442 
443 
444 
445 void Mesh::print(std::ostream &o) const
446 {
447  o << " Node count :" << nodes.size() << endl;
448  o << " Point count :" << points.size() << endl;
449  o << " Line count :" << tetrahedra.size() << endl;
450  o << " Triangle count :" << triangles.size() << endl;
451  o << " Tetrahedra count :" << tetrahedra.size() << endl;
452 
453 
454  BoundCube b;
455  b.setBounds(nodes);
456  o << "Bounding box:" << endl;
457  o << b << endl;
458 
459  Point3D centroid(0,0,0);
460 
461  for(size_t ui=0;ui<nodes.size();ui++)
462  centroid+=nodes[ui];
463 
464  centroid*=1.0/(float)nodes.size();
465 
466  o << "Centroid:" << endl;
467  o << centroid << endl;
468 }
469 //Input must be sorted and unique.
470 void Mesh::killOrphanNodes(const vector<size_t> &orphans)
471 {
472 #ifdef HAVE_CPP11
473  ASSERT(std::is_sorted(orphans.begin(),orphans.end()));
474 #endif
475  ASSERT(std::adjacent_find(orphans.begin(),orphans.end()) == orphans.end())
476 
477  ASSERT(isSane());
478 
479 
480  vector<size_t> offsets;
481  offsets.resize(nodes.size());
482  size_t curOrphan=0;
483  for(size_t ui=0;ui<nodes.size();ui++)
484  {
485  while(curOrphan < orphans.size() &&
486  orphans[curOrphan] <=ui)
487  curOrphan++;
488  offsets[ui]=curOrphan;
489  }
490 
491  //renumber the points
492  vector<size_t>::iterator itJ;
493  for(size_t ui=0;ui<points.size();ui++)
494  points[ui]-=offsets[points[ui]];
495 
496  //renumber the lines
497  for(size_t ui=0;ui<lines.size();ui++)
498  for(size_t uj=0;uj<2;uj++)
499  lines[ui].p[uj]-=offsets[lines[ui].p[uj]];
500 
501  //renumber the triangles
502  for(size_t ui=0;ui<triangles.size();ui++)
503  {
504  for(size_t uj=0;uj<3;uj++)
505  {
506  ASSERT(triangles[ui].p[uj] -
507  offsets[triangles[ui].p[uj]]< nodes.size());
508  triangles[ui].p[uj]-=offsets[triangles[ui].p[uj]];
509  }
510  }
511 
512  //renumber the tetrahedra
513  for(size_t ui=0;ui<tetrahedra.size();ui++)
514  for(size_t uj=0;uj<4;uj++)
515  tetrahedra[ui].p[uj]-=offsets[tetrahedra[ui].p[uj]];
516 
517 
518  //FIXME: Not efficient
519  vector<Point3D> newNodes;
520  for(size_t ui=0;ui<nodes.size();ui++)
521  {
522  if(!binary_search(orphans.begin(),orphans.end(),ui))
523  newNodes.push_back(nodes[ui]);
524  }
525  nodes.swap(newNodes);
526 
527  //Even if each object has every vertex with its own node, not
528  // shared with any other, it cannot exceed this.
529  ASSERT(nodes.size() <= (3*triangles.size() +
530  2*lines.size() + 4*tetrahedra.size() + points.size()));
531 }
532 
533 //Tell us if the two triangles are indeed the same
534 bool Mesh::sameTriangle(unsigned int ui, unsigned int uj) const
535 {
536  vector<unsigned int> t1,t2;
537 
538  t1.resize(3);
539  t2.resize(3);
540  for(unsigned int idx=0;idx<3;idx++)
541  {
542  t1[idx]= triangles[ui].p[idx];
543  t2[idx]= triangles[uj].p[idx];
544  }
545 
546  std::sort(t1.begin(),t1.end());
547  std::sort(t2.begin(),t2.end());
548 
549  return std::equal(t1.begin(),t1.end(),t2.begin());
550 
551 }
552 
553 bool Mesh::sameTriangle(const TRIANGLE &t1, const TRIANGLE &t2)
554 {
555  vector<unsigned int> ta,tb;
556 
557  ta.resize(3);
558  tb.resize(3);
559  for(unsigned int idx=0;idx<3;idx++)
560  {
561  ta[idx]= t1.p[idx];
562  tb[idx]= t2.p[idx];
563  }
564 
565  std::sort(ta.begin(),ta.end());
566  std::sort(tb.begin(),tb.end());
567 
568  return std::equal(ta.begin(),ta.end(),tb.begin());
569 
570 }
571 
572 bool Mesh::isSane(bool output, std::ostream &outStr) const
573 {
574  //Check sanity
575  for(size_t ui=0;ui<tetrahedra.size();ui++)
576  {
577  //Tetrahedra has unique vertices
578  for(unsigned int uj=0;uj<4; uj++)
579  {
580  for(unsigned int uk=0;uk<4;uk++)
581  {
582  if(uk == uj)
583  continue;
584 
585  if( tetrahedra[ui].p[uj] == tetrahedra[ui].p[uk])
586  {
587  if(output)
588  outStr << "It's INSANE. " << __LINE__ << std::endl;
589  return false;
590  }
591  }
592 
593  //tetrahedra point to valid node
594  if(tetrahedra[ui].p[uj] > nodes.size())
595  {
596  if(output)
597  outStr << "It's INSANE. " << __LINE__ << std::endl;
598  return false;
599  }
600  }
601 
602  }
603 
604  for(size_t ui=0;ui<triangles.size();ui++)
605  {
606  //triangle vertices unique test
607  for(unsigned int uj=0;uj<3; uj++)
608  {
609  for(unsigned int uk=0;uk<3;uk++)
610  {
611  if(uk == uj)
612  continue;
613 
614  if( triangles[ui].p[uj] == triangles[ui].p[uk])
615  {
616  if(output)
617  {
618  outStr << "It's INSANE. " << __LINE__ << std::endl;
619  outStr << "vertex " << uj << " and " << uk
620  << " of triangle " << ui << "not unique" << endl;
621  outStr << triangles[ui].p[uj] << " node is duplicated" << std::endl;
622  }
623  return false;
624  }
625  }
626 
627  //triangle points to valid node
628  if(triangles[ui].p[uj] > nodes.size())
629  {
630  if(output)
631  outStr << "It's INSANE. " << __LINE__ << std::endl;
632  return false;
633  }
634  }
635 
636  }
637 
638  for(size_t ui=0;ui<lines.size();ui++)
639  {
640  //lines have no common vertices
641  for(unsigned int uj=0;uj<2; uj++)
642  {
643  for(unsigned int uk=0;uk<2;uk++)
644  {
645  if(uk == uj)
646  continue;
647 
648  if( lines[ui].p[uj] == lines[ui].p[uk])
649  {
650  if(output)
651  outStr << "It's INSANE. " << __LINE__ << std::endl;
652  return false;
653  }
654  }
655 
656  //lines point to valid node
657  if(lines[ui].p[uj] > nodes.size())
658  {
659  if(output)
660  outStr << "It's INSANE. " << __LINE__ << std::endl;
661  return false;
662  }
663  }
664 
665  }
666 
667 
668  //Check that we have enough nodes to support each primitive type
669  if(nodes.size() < 4 && tetrahedra.size())
670  {
671  if(output)
672  outStr << "It's INSANE. " << __LINE__ << std::endl;
673  return false;
674  }
675  if(nodes.size() < 3 && triangles.size())
676  {
677  if(output)
678  outStr << "It's INSANE. " << __LINE__ << std::endl;
679  return false;
680  }
681  if(nodes.size() < 2 && lines.size())
682  {
683  if(output)
684  outStr << "It's INSANE. " << __LINE__ << std::endl;
685  return false;
686  }
687 
688  return true;
689 }
690 
692 {
693  ASSERT(isSane());
694 
695  using std::list;
696  vector<size_t> dups;
697 
698  //Create a listing of all the triangles incident to each node
699  vector<list<unsigned int> > vl;
700  vl.resize(nodes.size());
701 
702  for(unsigned int ui=0;ui<triangles.size();ui++)
703  {
704  for(unsigned int uj=0;uj<3;uj++)
705  vl[triangles[ui].p[uj]].push_back(ui);
706  }
707 
708  for(unsigned int ui=0;ui<vl.size();ui++)
709  {
710  for(list<unsigned int>::iterator it=vl[ui].begin();
711  it!=vl[ui].end();++it)
712  {
713  //Examine the triangle that is coincident on this vertex, then
714  //see if the other triangles on this vertex are duplicates
715  for(list<unsigned int>::iterator itJ=it;
716  itJ!=vl[ui].end();++itJ)
717  {
718  if(itJ == it)
719  continue;
720 
721  if(sameTriangle(*it,*itJ))
722  {
723  if(std::find(dups.begin(),dups.end(),*itJ) == dups.end())
724  dups.push_back(*itJ);
725  }
726  }
727 
728  }
729  }
730 
731  for(unsigned int ui=dups.size();ui--;)
732  {
733  std::swap(triangles[dups[ui]],triangles.back());
734  triangles.pop_back();
735  }
736 }
737 
739 {
740  using std::list;
741  using std::pair;
742  vector<size_t> thisDup;
743  vector<pair<size_t,vector<size_t> > > dups;
744 
745  //Find the duplicates
746  // placing duplicates into a list of sorted vectors of duplicate indices
747  findNearVerticies(tol,nodes,dups);
748  for(size_t ui=0;ui<dups.size();ui++)
749  {
750  std::sort(dups[ui].second.begin(),
751  dups[ui].second.end());
752  }
753 
754  for(vector<pair<size_t,vector<size_t> > >::iterator it=dups.begin();
755  it!=dups.end();++it)
756  {
757  //replace the points
758  vector<size_t>::iterator itJ;
759 
760  for(size_t ui=0;ui<points.size();ui++)
761  {
762  itJ=find(it->second.begin(),it->second.end(),points[ui]);
763  if(itJ !=it->second.end())
764  points[ui]=it->first;
765  }
766 
767  //replace the lines
768  for(size_t ui=0;ui<lines.size();ui++)
769  {
770  for(size_t uj=0;uj<2;uj++)
771  {
772  itJ=find(it->second.begin(),it->second.end(),lines[ui].p[uj]);
773  if(itJ !=it->second.end())
774  lines[ui].p[uj]=it->first;
775  }
776  }
777 
778  //replace the triangles
779  for(size_t ui=0;ui<triangles.size();ui++)
780  {
781  for(size_t uj=0;uj<3;uj++)
782  {
783  itJ=find(it->second.begin(),it->second.end(),triangles[ui].p[uj]);
784  if(itJ !=it->second.end())
785  triangles[ui].p[uj]=it->first;
786  }
787  }
788 
789  //replace the tetrahedra
790  for(size_t ui=0;ui<tetrahedra.size();ui++)
791  {
792  for(size_t uj=0;uj<4;uj++)
793  {
794  itJ=find(it->second.begin(),it->second.end(),tetrahedra[ui].p[uj]);
795  if(itJ !=it->second.end())
796  tetrahedra[ui].p[uj]=it->first;
797  }
798  }
799  }
800  ASSERT(isSane());
801 
802 
803  //obtain the set of vertices that have now been orphaned
804  vector<size_t> toRemove;
805  for(vector<pair<size_t,vector<size_t> > >::iterator it=dups.begin();
806  it!=dups.end();++it)
807  {
808  for(size_t ui=0;ui<it->second.size();ui++)
809  toRemove.push_back(it->second[ui]);
810  }
811 
812  std::sort(toRemove.begin(),toRemove.end());
813  //hokay, so all we need to do is remove orphans
814  killOrphanNodes(toRemove);
815 
816  ASSERT(isSane());
817 }
818 
819 
821 {
822  vector<bool> referenced(nodes.size(),false);
823  for(size_t ui=0;ui<points.size();ui++)
824  referenced[points[ui]] =true;
825 
826  for(size_t ui=0;ui<lines.size();ui++)
827  for(size_t uj=0;uj<2;uj++)
828  referenced[lines[ui].p[uj]] =true;
829 
830  for(size_t ui=0;ui<triangles.size();ui++)
831  for(size_t uj=0;uj<3;uj++)
832  referenced[triangles[ui].p[uj]] =true;
833 
834  for(size_t ui=0;ui<tetrahedra.size();ui++)
835  for(size_t uj=0;uj<4;uj++)
836  referenced[tetrahedra[ui].p[uj]] =true;
837 
838  vector<size_t> orphans;
839 
840  for(size_t ui=0;ui<referenced.size();ui++)
841  {
842  if(!referenced[ui])
843  {
844  orphans.push_back(ui);
845  }
846  }
847 
848  if(orphans.size())
849  killOrphanNodes(orphans);
850  ASSERT(isSane());
851 }
852 
853 void Mesh::setNode(unsigned int index, Point3D val)
854 {
855  nodes[index]=val;
856 }
857 
858 void Mesh::resizeNodes(unsigned int newsize)
859 {
860  nodes.resize(newsize);
861 }
862 
863 Point3D Mesh::getNodes(unsigned int idx)
864 {
865  return nodes[idx];
866 }
867 
868 unsigned int Mesh::numDupTris() const
869 {
870  ASSERT(isSane());
871 
872  using std::list;
873  vector<size_t> dups;
874 
875  //Create a listing of all the triangles incident to each node
876  vector<list<unsigned int> > vl;
877  vl.resize(nodes.size());
878 
879  for(unsigned int ui=0;ui<triangles.size();ui++)
880  {
881  for(unsigned int uj=0;uj<3;uj++)
882  vl[triangles[ui].p[uj]].push_back(ui);
883  }
884 
885  for(unsigned int ui=0;ui<vl.size();ui++)
886  {
887  for(list<unsigned int>::iterator it=vl[ui].begin();
888  it!=vl[ui].end();++it)
889  {
890  //Examine the triangle that is coincident on this vertex, then
891  //see if the other triangles on this vertex are duplicates
892  for(list<unsigned int>::iterator itJ=it;
893  itJ!=vl[ui].end();++itJ)
894  {
895  if(itJ == it)
896  continue;
897 
898  if(sameTriangle(*it,*itJ))
899  {
900  if(std::find(dups.begin(),dups.end(),*itJ) == dups.end())
901  dups.push_back(*itJ);
902  }
903  }
904 
905  }
906  }
907 
908  return dups.size();
909 }
910 
911 unsigned int Mesh::numDupVertices(float tolerance) const
912 {
913  float sqrTol;
914  sqrTol = tolerance*tolerance;
915 
916 
917  unsigned int numDups=0;
918 
919  //TODO: Non brute force approach (k3d-mk2)
920 #pragma omp parallel for reduction(+:numDups)
921  for(size_t ui=0;ui<nodes.size();ui++)
922  {
923  for(size_t uj=0;uj<nodes.size();uj++)
924  {
925  if(ui == uj)
926  continue;
927 
928  if (nodes[ui].sqrDist(nodes[uj]) < sqrTol)
929  numDups++;
930  }
931  }
932 
933  return numDups;
934 }
935 
937 {
938  nodes.clear();
939  physGroupNames.clear();
940  tetrahedra.clear();
941  triangles.clear();
942  lines.clear();
943  points.clear();
944 }
945 
946 void Mesh::setTriangleMesh(const std::vector<float> &ptsX,
947  const std::vector<float> &ptsY, const std::vector<float> &ptsZ)
948 {
949  //Incoming data streams should describe triangles
950  ASSERT(ptsX.size() == ptsY.size() && ptsY.size() == ptsZ.size());
951  ASSERT(ptsX.size() %3 == 0);
952 
953  clear();
954 
955 
956  vector<Point3D> ptVec;
957  ptVec.resize(ptsX.size());
958 #pragma omp parallel for
959  for(size_t ui=0;ui<ptsX.size();ui++)
960  ptVec[ui]=Point3D(ptsX[ui],ptsY[ui],ptsZ[ui]);
961 
962 
963  const float MAX_SQR_RAD=0.001f;
964  std::list<std::pair<size_t,vector<size_t> > > clusterList;
965  findNearVerticies(MAX_SQR_RAD,ptVec,clusterList);
966 
967 
968  //FIXME: This is totally inefficient.
969 
970  //Now, we have a vector of pts, each group of 3 corresponding to 1 triangle
971  //and we have the mapping for the new triangles
972  vector<size_t > triangleMapping;
973 
974  triangleMapping.resize(ptVec.size());
975 #pragma omp parallel for
976  for(size_t ui=0;ui<ptVec.size(); ui++)
977  triangleMapping[ui]=ui;
978 
979  //Now run through the original mapping, and generate the new modified mapping.
980  //this maps old point -> "rally pt"
981  for(std::list<std::pair<size_t, vector<size_t> > >::iterator it=clusterList.begin();it!=clusterList.end();++it)
982  {
983  for(size_t uj=0;uj<it->second.size();uj++)
984  triangleMapping[it->second[uj]]=it->first;
985  }
986 
987 
988  //now we have to do an additional step. When we create the new node vector, we are going to exclude points
989  //that are no longer referenced. So, to do this (inefficiently), we need to know how many times each point was referenced
990  //if it was referenced zero times, we have to modify the triangle mapping for any nodes of higher index
991 
992 
993  vector<size_t> refCount;
994  refCount.resize(ptVec.size(),0);
995  for(size_t ui=0;ui<triangleMapping.size();ui++)
996  refCount[triangleMapping[ui]]++;
997 
998  //modify the triangle mapping such that it points from ptVec->nodeVec (ie the indices of the pts, after dropping unreferenced pts)
999  size_t delta=0;
1000  vector<size_t> numPtsDropped;
1001  for(size_t ui=0;ui<refCount.size();ui++)
1002  {
1003  numPtsDropped.push_back(delta);
1004  if(!refCount[ui])
1005  {
1006  delta++;
1007  continue;
1008  }
1009  nodes.push_back(ptVec[ui]);
1010  }
1011 
1012 
1013  //Build the triangle vector
1014  for(size_t ui=0;ui<triangleMapping.size()/3; ui++)
1015  {
1016  size_t offset;
1017  offset=ui*3;
1018  for(size_t uj=0;uj<3;uj++)
1019  {
1020  TRIANGLE t;
1021 
1022  //Build the triangle from the triangle mapping, accounting for the shift due
1023  //to dropped points that have been "clustered"
1024  t.p[0]=triangleMapping[offset]-numPtsDropped[triangleMapping[offset]] ;
1025  t.p[1]=triangleMapping[offset+1] - numPtsDropped[triangleMapping[offset+1]];
1026  t.p[2]=triangleMapping[offset+2]- numPtsDropped[triangleMapping[offset+2]];
1027  triangles.push_back(t);
1028  }
1029  }
1030 
1031  std::cerr << "Input size of " << ptVec.size() << std::endl;
1032  std::cerr << "found " << clusterList.size() << " shared nodes" << std::endl;
1033 
1034  ASSERT(isSane());
1035 
1036  std::cerr << "Appears to be sane?? " << std::endl;
1037 }
1038 
1039 unsigned int Mesh::loadGmshMesh(const char *meshFile, unsigned int &curLine, bool allowBadMeshes)
1040 {
1041  static_assert(ARRAYSIZE(MESH_LOAD_ERRS) == MESH_LOAD_ENUM_END, "Mesh error strings and enum sizes mismatched");
1042  vector<string> strVec;
1043 
1044  tetrahedra.clear();
1045  triangles.clear();
1046  lines.clear();
1047  points.clear();
1048  nodes.clear();
1049 
1050  curLine=0;
1051  std::ifstream f(meshFile);
1052 
1053  if(!f)
1054  return 1;
1055 
1056  curLine=1;
1057  string line;
1058 
1059  //Read file header
1060  //---
1061  getline(f,line);
1062  if(f.fail())
1063  return 1;
1064 
1065  //Check first line is "$MeshFormat"
1066  if(line != "$MeshFormat")
1067  return 1;
1068 
1069  getline(f,line);
1070  curLine++;
1071  if(f.fail())
1072  return 1;
1073 
1074  //Second line should be versionNumber file-type data-size
1075  splitStrsRef(line.c_str(),' ',strVec);
1076 
1077  if(strVec.size() != 3)
1078  return 1;
1079 
1080  //Only going to allow version 2.0 && 2.1 && 2.2; can't guarantee other versions....
1081  if(!(strVec[0] == "2.1" || strVec[0] =="2" || strVec[0] == "2.2"))
1082  return 1;
1083 
1084  //file-type should be "0" (for ascii file)
1085  //Number of bytes in a double is third arg; but I will skip it
1086  if(strVec[1] != "0")
1087  return 1;
1088 
1089  getline(f,line);
1090  curLine++;
1091  if(f.fail())
1092  return 1;
1093  if(line != "$EndMeshFormat")
1094  return 1;
1095  //--------
1096 
1097  //Read the nodes header
1098  getline(f,line);
1099  curLine++;
1100  if(f.fail())
1101  return 1;
1102 
1103  if(line != "$Nodes")
1104  return 1;
1105 
1106  getline(f,line);
1107  curLine++;
1108  if(f.fail())
1109  return 1;
1110 
1111  unsigned int nodeCount;
1112  if(stream_cast(nodeCount,line))
1113  return 1;
1114 
1115  std::cerr << "reading node coords " << std::endl;
1116  //Read the node XYZ coords
1117  do
1118  {
1119  getline(f,line);
1120  curLine++;
1121 
1122  if(f.fail())
1123  return 1;
1124 
1125  if(line == "$EndNodes")
1126  break;
1127 
1128  splitStrsRef(line.c_str(),' ',strVec);
1129 
1130  if(strVec.size() < 4)
1131  return 1;
1132 
1133  Point3D pt;
1134  if(stream_cast(pt[0],strVec[1]))
1135  return 1;
1136 
1137  if(stream_cast(pt[1],strVec[2]))
1138  return 1;
1139 
1140  if(stream_cast(pt[2],strVec[3]))
1141  return 1;
1142 
1143 
1144  nodes.push_back(pt);
1145  }
1146  while(!f.eof());
1147 
1148 
1149  if(f.eof())
1150  return 1;
1151  //Read the elements header
1152  getline(f,line);
1153  curLine++;
1154  if(f.fail())
1155  return 1;
1156 
1157  if(line != "$Elements")
1158  return 1;
1159 
1160  getline(f,line);
1161  curLine++;
1162  if(f.fail())
1163  return 1;
1164 
1165  unsigned int elementCount;
1166  if(stream_cast(elementCount,line))
1167  return 1;
1168 
1169 
1170  std::cerr << "Reading Element data" << std::endl;
1171  //Read the element data
1172  do
1173  {
1174  getline(f,line);
1175  curLine++;
1176 
1177  if(f.fail())
1178  return 1;
1179 
1180  if(line == "$EndElements")
1181  break;
1182 
1183  splitStrsRef(line.c_str(),' ',strVec);
1184 
1185  if(strVec.size() < 3)
1186  return 1;
1187 
1188  unsigned int numTags,elemType;
1189  stream_cast(numTags,strVec[2]);
1190  stream_cast(elemType,strVec[1]);
1191 
1192  bool badNode;
1193  badNode=false;
1194 
1195  switch(elemType)
1196  {
1198  {
1199  if(strVec.size() - numTags < 4)
1200  return 2;
1201 
1202  unsigned int ptNum;
1203  stream_cast(ptNum,strVec[strVec.size() -1]);
1204  ptNum--;
1205  points.push_back(ptNum);
1206  break;
1207  }
1208  case ELEM_TWO_NODE_LINE:
1209  {
1210  if(strVec.size()-numTags < 5)
1211  return 2;
1212 
1213  LINE l;
1214 
1215  if(stream_cast(l.physGroup,strVec[3]))
1216  return 1;
1217  if(stream_cast(l.p[0],strVec[strVec.size() -2]))
1218  return 1;
1219  if(stream_cast(l.p[1],strVec[strVec.size() -1]))
1220  return 1;
1221 
1222  if( l.p[0] == l.p[1])
1223  {
1224  if(allowBadMeshes)
1225  {
1226  badNode=true;
1227  std::cerr << "WARNING: Bad mesh line element at file line " << curLine << std::endl;
1228  }
1229  else
1230  return 1;
1231  }
1232  //Convert from 1-index to zero index notation
1233  l.p[0]--;
1234  l.p[1]--;
1235  lines.push_back(l);
1236  break;
1237  }
1239  {
1240  if(strVec.size()-numTags < 6)
1241  return 2;
1242 
1243  TRIANGLE t;
1244  if(stream_cast(t.physGroup,strVec[3]))
1245  return 1;
1246  if(stream_cast(t.p[0],strVec[strVec.size() -3]))
1247  return 1;
1248  if(stream_cast(t.p[1],strVec[strVec.size() -2]))
1249  return 1;
1250  if(stream_cast(t.p[2],strVec[strVec.size() -1]))
1251  return 1;
1252 
1253  if( t.p[0] == t.p[1] || t.p[1] == t.p[2] ||
1254  t.p[2] == t.p[0])
1255  {
1256  if(allowBadMeshes)
1257  {
1258  badNode=true;
1259  std::cerr << "WARNING: Bad mesh triangle at line " << curLine << std::endl;
1260  }
1261  else
1262  return 1;
1263  }
1264  if(!badNode)
1265  {
1266  //Convert from 1-index to zero index notation
1267  t.p[0]--;
1268  t.p[1]--;
1269  t.p[2]--;
1270  triangles.push_back(t);
1271  }
1272  break;
1273  }
1275  {
1276  if(strVec.size()-numTags < 7)
1277  return 2;
1278 
1279  TETRAHEDRON t;
1280  if(stream_cast(t.physGroup,strVec[3]))
1281  return 1;
1282  if(stream_cast(t.p[0],strVec[strVec.size() -4]))
1283  return 1;
1284  if(stream_cast(t.p[1],strVec[strVec.size() -3]))
1285  return 1;
1286  if(stream_cast(t.p[2],strVec[strVec.size() -2]))
1287  return 1;
1288  if(stream_cast(t.p[3],strVec[strVec.size() -1]))
1289  return 1;
1290 
1291  for(unsigned int ui=0;ui<4; ui++)
1292  {
1293  for(unsigned int uj=0;uj<4;uj++)
1294  {
1295  if(ui == uj)
1296  continue;
1297 
1298  if( t.p[ui] == t.p[uj])
1299  {
1300  if(allowBadMeshes)
1301  {
1302  std::cerr << "WARNING: Bad mesh tetrahedron at line " << curLine << std::endl;
1303  badNode=true;
1304  }
1305  else
1306  return 1;
1307  }
1308  }
1309  }
1310 
1311  if(!badNode)
1312  {
1313  //Convert from 1-index to zero index notation
1314  t.p[0]--;
1315  t.p[1]--;
1316  t.p[2]--;
1317  t.p[3]--;
1318  tetrahedra.push_back(t);
1319  }
1320  break;
1321  }
1322  default:
1323  return 3;
1324  }
1325 
1326 
1327 
1328 
1329  }while(!f.eof());
1330 
1331 
1332  //Do some final checks - element count can only be under-counted by our class
1333  // as there may be some primitives we don't support. However, it should be
1334  // never over counted
1335  if(!allowBadMeshes)
1336  {
1337  if(elementCount < triangles.size() + lines.size() + points.size() + tetrahedra.size() )
1339 
1340  if(nodeCount != nodes.size())
1341  return MESH_LOAD_BAD_NODECOUNT;
1342  }
1343 
1344  if(!isSane())
1345  return MESH_LOAD_IS_INSANE;
1346 
1347  return 0;
1348 }
1349 
1350 unsigned int Mesh::countTriNodes() const
1351 {
1352  vector<size_t> touchedNodes;
1353 
1354  touchedNodes.resize(triangles.size()*3);
1355  //Build monolithic list
1356 #pragma omp parallel for
1357  for(size_t ui=0;ui<triangles.size(); ui++)
1358  {
1359  touchedNodes[ui*3]=triangles[ui].p[0];
1360  touchedNodes[ui*3+1]=triangles[ui].p[1];
1361  touchedNodes[ui*3+2]=triangles[ui].p[2];
1362  }
1363 
1364  //Remove non-unique entries
1365  vector<size_t>::iterator it;
1366  std::sort(touchedNodes.begin(),touchedNodes.end());
1367  it=std::unique(touchedNodes.begin(),touchedNodes.end());
1368 
1369  //TODO: Test me...
1370  touchedNodes.resize(it-touchedNodes.begin());
1371 
1372  return touchedNodes.size();
1373 }
1374 
1375 void Mesh::reassignGroups(unsigned int newPhys)
1376 {
1377 #pragma omp parallel for
1378  for(size_t ui=0;ui<tetrahedra.size();ui++)
1379  tetrahedra[ui].physGroup = newPhys;
1380 
1381 #pragma omp parallel for
1382  for(size_t ui=0;ui<triangles.size();ui++)
1383  triangles[ui].physGroup = newPhys;
1384 
1385 #pragma omp parallel for
1386  for(size_t ui=0;ui<lines.size();ui++)
1387  lines[ui].physGroup = newPhys;
1388 }
1389 
1390 unsigned int Mesh::saveGmshMesh(const char *meshFile) const
1391 {
1392  ASSERT(isSane());
1393 
1394  using std::endl;
1395  using std::ofstream;
1396 
1397  ofstream f(meshFile);
1398 
1399  if(!f)
1400  return 1;
1401 
1402  f << "$MeshFormat" << endl;
1403  f << "2.1 0 8" << endl;
1404  f << "$EndMeshFormat" << endl;
1405 
1406 
1407  f << "$Nodes" << endl;
1408 
1409  f << nodes.size() << endl;
1410 
1411  for(size_t ui=0;ui<nodes.size();ui++)
1412  {
1413  f << ui+1 << " " << nodes[ui][0] << " " << nodes[ui][1]
1414  << " " << nodes[ui][2] << std::endl;
1415  }
1416 
1417  f << "$EndNodes" << endl;
1418 
1419  f << "$Elements" << endl;
1420  f << tetrahedra.size() + triangles.size() + lines.size() + points.size() << endl;
1421 
1422  for(size_t ui=0;ui<tetrahedra.size();ui++)
1423  {
1424  f << ui+1 << " " << ELEM_FOUR_NODE_TETRAHEDRON << " 3 " << tetrahedra[ui].physGroup << " 1 0 " <<
1425  tetrahedra[ui].p[0]+1 << " " << tetrahedra[ui].p[1]+1 << " "
1426  << tetrahedra[ui].p[2]+1 << " " << tetrahedra[ui].p[3]+1 << endl;
1427  }
1428 
1429  for(size_t ui=0;ui<triangles.size();ui++)
1430  {
1431  f << tetrahedra.size()+ ui+1 << " " << ELEM_THREE_NODE_TRIANGLE << " 3 " << triangles[ui].physGroup << " 1 0 " <<
1432  triangles[ui].p[0]+1 << " " << triangles[ui].p[1]+1 << " "
1433  << triangles[ui].p[2]+1 << endl;
1434  }
1435 
1436  for(size_t ui=0;ui<lines.size();ui++)
1437  {
1438  f << tetrahedra.size() + triangles.size() + ui+1 << " " << ELEM_TWO_NODE_LINE << " 3 " << lines[ui].physGroup << " 1 0 " <<
1439  lines[ui].p[0]+1 << " " << lines[ui].p[1]+1 << endl;
1440  }
1441 
1442  for(size_t ui=0;ui<points.size();ui++)
1443  {
1444  f << tetrahedra.size() + triangles.size() + lines.size() + ui+1 << " "
1445  << ELEM_SINGLE_NODE_POINT<< " 1 0 " << points[ui]+1 << endl;
1446  }
1447  f << "$EndElements" << endl;
1448 
1449  return 0;
1450 }
1451 
1452 
1453 void Mesh::rotate(const Point3D &axis, const Point3D &origin, float angle)
1454 {
1455  Point3f fAxis;
1456  fAxis.fx=axis[0];
1457  fAxis.fy=axis[1];
1458  fAxis.fz=axis[2];
1459  Quaternion qR;
1460  quat_get_rot_quat(&fAxis,angle,&qR);
1461 
1462  #pragma omp parallel shared(nodes,qR)
1463  {
1464  //Shift nodes to origin
1465  #pragma omp for
1466  for(size_t ui=0; ui<nodes.size();ui++)
1467  {
1468  Point3D p;
1469  nodes[ui] = nodes[ui]-origin;
1470  }
1471 
1472  //Rotate around origin
1473  #pragma omp for
1474  for(unsigned int ui=0;ui<nodes.size();ui++)
1475  {
1476  Point3f pf;
1477  pf.fx=nodes[ui][0];
1478  pf.fy=nodes[ui][1];
1479  pf.fz=nodes[ui][2];
1480  quat_rot_apply_quat(&pf,&qR);
1481  nodes[ui][0]=pf.fx;
1482  nodes[ui][1]=pf.fy;
1483  nodes[ui][2]=pf.fz;
1484  }
1485 
1486  //Shift nodes back
1487  #pragma omp for
1488  for(size_t ui=0; ui<nodes.size();ui++)
1489  {
1490  Point3D p;
1491  nodes[ui] = nodes[ui]+origin;
1492  }
1493  }
1494 }
1495 
1497 {
1498  Point3D origin(0,0,0);
1499  for(size_t ui=0;ui<nodes.size();ui++)
1500  origin-=nodes[ui];
1501 
1502  origin*=1.0f/(float)nodes.size();
1503 
1504  translate(origin);
1505 }
1506 
1507 void Mesh::translate(const Point3D &origin)
1508 {
1509  #pragma omp parallel for
1510  for(size_t ui=0;ui<nodes.size();ui++)
1511  nodes[ui]+=origin;
1512 }
1513 
1514 void Mesh::scale(const Point3D &origin,float scaleFactor)
1515 {
1516  #pragma omp parallel for
1517  for(size_t ui=0;ui<nodes.size();ui++)
1518  {
1519  nodes[ui][0]=(nodes[ui][0]-origin[0])*scaleFactor + origin[0];
1520  nodes[ui][1]=(nodes[ui][1]-origin[1])*scaleFactor + origin[1];
1521  nodes[ui][2]=(nodes[ui][2]-origin[2])*scaleFactor + origin[2];
1522  }
1523 }
1524 
1525 void Mesh::scale(float scaleFactor)
1526 {
1527  #pragma omp parallel for
1528  for(size_t ui=0;ui<nodes.size();ui++)
1529  nodes[ui]*=scaleFactor;
1530 }
1531 
1533 {
1534  b.setBounds(nodes);
1535 }
1536 
1537 void Mesh::getTriEdgeAdjacencyMap(std::vector<std::list<size_t> > &adj) const
1538 {
1539 
1540  using std::list;
1541 
1542  adj.resize(triangles.size());
1543 
1544  //Create a lookup table of vertices -> triangles
1545  vector<list<size_t> > triLookup;
1546  triLookup.resize(nodes.size());
1547  for(size_t ui=0; ui<triangles.size();ui++)
1548  {
1549  for(unsigned int uj=0;uj<3;uj++)
1550  triLookup[triangles[ui].p[uj]].push_back(ui);
1551  }
1552 
1553 
1554 
1555  list<size_t> connectedMap;
1556  for(size_t ui=0; ui<triangles.size();ui++)
1557  {
1558  //Check each vertex pair
1559  for(unsigned int uj=0;uj<3;uj++)
1560  {
1561  size_t v1,v2;
1562 
1563  v1 = triangles[ui].p[uj];
1564  v2 = triangles[ui].p[(uj+1)%3];
1565 
1566  ASSERT(triLookup[v1].size());
1567  ASSERT(triLookup[v2].size());
1568 
1569  //Compute the intersection of the two tri lookup table rows
1570  list<size_t> intersect;
1571  intersect=triLookup[v1];
1572  for(list<size_t>::iterator it=intersect.begin();it!=intersect.end();)
1573  {
1574  if( find(triLookup[v2].begin(),triLookup[v2].end(),*it) == triLookup[v2].end())
1575  {
1576  it=intersect.erase(it);
1577  }
1578  else
1579  ++it;
1580 
1581  }
1582 
1583  //OK, so the intersection of the two lookups is the triangles attached to the nodes.
1584  for(list<size_t>::iterator it=intersect.begin();it!=intersect.end();++it)
1585  {
1586  //Disallow self adjacency
1587  if(*it !=ui)
1588  adj[ui].push_back(*it);
1589  }
1590 
1591 
1592  }
1593 
1594  }
1595 }
1596 
1597 unsigned int Mesh::divideMeshSurface(float divisionAngle, unsigned int newPhysGroupStart,
1598  const vector<size_t> &physGroupsToSplit)
1599 {
1600  using std::list;
1601 
1602  unsigned int origStart=newPhysGroupStart;
1603  //Construct the
1604  vector<list<size_t> > adjacencyMap;
1605  vector<bool> touchedTris;
1606  vector<size_t> boundaryTris;
1607  getTriEdgeAdjacencyMap(adjacencyMap);
1608  touchedTris.resize(adjacencyMap.size(),false);
1609 
1610  //OK, so the plan is to pick a triangle (any triangle)
1611  //then to expand this out until we hit an edge, as defined by the
1612  //angle between adjacent triangle normals.
1613  //once we hit the edge, we then don't cross that vertex.
1614  //
1615  //this algorithm will FAIL (awh new, bro!)
1616  //if triangles have more than one neighbour on each edge.
1617 
1618  //Once we run out of triangles to try (BFS), we then pick one of the "untouched"
1619  //tris, and then work from there.
1620 
1621  // Step 1:
1622  // * Remove any triangles that are not in the physical groups of interest
1623 
1624  for(size_t ui=0;ui<adjacencyMap.size();ui++)
1625  {
1626  ASSERT(adjacencyMap[ui].size());
1627 
1628  //Is this triangle in our list?
1629  if(find(physGroupsToSplit.begin(),physGroupsToSplit.end(),
1630  triangles[ui].physGroup) == physGroupsToSplit.end())
1631  {
1632  //No? OK, lets kill the adj. list entry at this triangle, we don't need it.
1633  adjacencyMap[ui].clear();
1634  touchedTris[ui]=true;
1635  }
1636  else
1637  {
1638  //It is? Well, remove any triangles that are adjacent, but not in the list.
1639  for(list<size_t>::iterator it=adjacencyMap[ui].begin(); it!=adjacencyMap[ui].end(); ++it)
1640  {
1641  if(find(physGroupsToSplit.begin(),physGroupsToSplit.end(),
1642  triangles[*it].physGroup) == physGroupsToSplit.end())
1643  {
1644  it=adjacencyMap[ui].erase(it);
1645  --it;
1646  }
1647  }
1648  }
1649  }
1650 
1651 
1652 
1653  //OK, so now we have an adjacency list of the interesting phys groups.
1654  //Step 2:
1655  // * search for new triangles to group using an expanding boundary method
1656 
1657  BoundCube debugBounds,dbgTmp;
1658  debugBounds.setInverseLimits();
1659  do
1660  {
1661  //Find a triangle to use as the "seed"
1662  size_t curTri;
1663  curTri= find(touchedTris.begin(),touchedTris.end(),false) - touchedTris.begin();
1664 
1665 
1666  //No more triangles.. all touched.
1667  if(curTri == touchedTris.size())
1668  break;
1669 
1670  //OK, so now we have a "seed" triangle to work with.
1671  //create an expanding boundary via adjacency.
1672 
1673  size_t groupSize=0;
1674  list<size_t> boundary,moreBoundary;
1675  boundary.clear();
1676  boundary.push_back(curTri);
1677 
1678  std::cerr << "Seeded with triangle # " << curTri << std::endl;
1679  touchedTris[curTri]=true; // we touched it.
1680  triangles[curTri].physGroup=newPhysGroupStart; // we touched it.
1681 
1682  do
1683  {
1684  //Expand the boundary using the current boundary triangles
1685 
1686  //loop over the current boundary
1687  for(list<size_t>::iterator bIt=boundary.begin();bIt!=boundary.end();++bIt)
1688  {
1689  ASSERT(adjacencyMap[*bIt].size());
1690  //Check the adjacency map of the triangles adjacent to a specific boundary element
1691  for(list<size_t>::iterator it=adjacencyMap[*bIt].begin();it!=adjacencyMap[*bIt].end();++it)
1692  {
1693  if(!touchedTris[*it] &&
1694  (normalAngle(*bIt,*it) < divisionAngle || fabs(normalAngle(*bIt,*it,true)) < divisionAngle) )
1695  {
1696  //Alright then, add this new triangle to the potential new boundary
1697  //(let us not add straight away, as we would like to expand in a minimum
1698  //perimeter to surface area manner
1699  moreBoundary.push_back(*it);
1700  touchedTris[*it]=true;
1701  triangles[*it].physGroup=newPhysGroupStart;
1702 
1703  dbgTmp.setBounds(nodes[triangles[*it].p[0]],
1704  nodes[triangles[*it].p[1]]);
1705  dbgTmp.expand(nodes[triangles[*it].p[2]]);
1706 
1707  debugBounds.expand(dbgTmp);
1708  groupSize++;
1709 
1710  }
1711  }
1712 
1713  }
1714  //exchange the new boundary list with the boundary list
1715  boundary.swap(moreBoundary);
1716 
1717  moreBoundary.clear();
1718 
1719  }
1720  while(!boundary.empty());
1721 
1722 
1723  //Debug: print bounding box
1724  std::cerr << "Group size: "<< groupSize << std::endl;
1725  std::cerr << debugBounds << std::endl;
1726 
1727  //advance the physical group listing
1728  newPhysGroupStart++;
1729  }
1730  while(true);
1731 
1732 
1733  //return the number of divided surfaces
1734  return newPhysGroupStart-origStart+1;
1735 
1736 }
1737 
1738 
1739 float Mesh::normalAngle(size_t t1, size_t t2, bool flip) const
1740 {
1741  Point3D nA,nB;
1742 
1743  //Compute nA.
1744  getTriNormal(t1,nA);
1745  getTriNormal(t2,nB);
1746 
1747  if(flip)
1748  return nA.angle(-nB);
1749  //Compute angle
1750  return nA.angle(nB);
1751 }
1752 
1753 void Mesh::getTriNormal(size_t tri,Point3D &p) const
1754 {
1755  ASSERT(tri < triangles.size());
1756  p= (nodes[triangles[tri].p[1]] - nodes[triangles[tri].p[0]]);
1757  p = p.crossProd(nodes[triangles[tri].p[2]] - nodes[triangles[tri].p[0]]);
1758  p.normalise();
1759 }
1760 
1761 void Mesh::getContainedNodes(const BoundCube &b, std::vector<size_t> &res) const
1762 {
1763  ASSERT(!res.size());
1764  for(size_t ui=0;ui<nodes.size();ui++)
1765  {
1766  if(b.containsPt(nodes[ui]))
1767  res.push_back(ui);
1768  }
1769 
1770 }
1771 
1772 void Mesh::getIntersectingPrimitives( std::vector<size_t> &searchNodes,
1773  std::vector<size_t> &lineRes,
1774  std::vector<size_t> &triangleRes,
1775  std::vector<size_t> &tetrahedraRes ) const
1776 {
1777 
1778  std::sort(searchNodes.begin(),searchNodes.end());
1779 
1780  bool searchFound;
1781  ASSERT(lineRes.size() == triangleRes.size() && tetrahedraRes.size() == lineRes.size() &&
1782  !tetrahedraRes.size());
1783  for(size_t ui=0;ui<lines.size();ui++)
1784  {
1785  searchFound=false;
1786  for(size_t uj=0;uj<2;uj++)
1787  {
1788  searchFound=std::binary_search(searchNodes.begin(),searchNodes.end(),lines[ui].p[uj]);
1789  if(searchFound)
1790  break;
1791  }
1792 
1793  if(searchFound)
1794  lineRes.push_back(ui);
1795  }
1796 
1797  for(size_t ui=0;ui<triangles.size();ui++)
1798  {
1799  searchFound=false;
1800  for(size_t uj=0;uj<3;uj++)
1801  {
1802  searchFound=std::binary_search(searchNodes.begin(),searchNodes.end(),triangles[ui].p[uj]);
1803  if(searchFound)
1804  break;
1805  }
1806 
1807  if(searchFound)
1808  triangleRes.push_back(ui);
1809 
1810  }
1811 
1812  for(size_t ui=0;ui<tetrahedra.size();ui++)
1813  {
1814  searchFound=false;
1815  for(size_t uj=0;uj<4;uj++)
1816  {
1817  searchFound=std::binary_search(searchNodes.begin(),searchNodes.end(),tetrahedra[ui].p[uj]);
1818  if(searchFound)
1819  break;
1820  }
1821 
1822  if(searchFound)
1823  tetrahedraRes.push_back(ui);
1824 
1825  }
1826 
1827 }
1828 
1829 void Mesh::getCurPhysGroups(std::vector<std::pair<unsigned int, size_t> > &curPhys) const
1830 {
1831  ComparePairFirst cmp;
1832 
1833  //TODO: could be more efficient by replacing linear search with
1834  //boolean one
1835  for(unsigned int ui=0;ui<triangles.size();ui++)
1836  {
1837  bool found=false;
1838  for(unsigned int uj=0;uj<curPhys.size();uj++)
1839  {
1840  if(curPhys[uj].first== triangles[ui].physGroup)
1841  {
1842  found=true;
1843  curPhys[uj].second++;
1844  break;
1845  }
1846  }
1847 
1848  if(!found)
1849  {
1850  //we've not seen this before...
1851  curPhys.push_back(make_pair(triangles[ui].physGroup,1));
1852  std::sort(curPhys.begin(),curPhys.end(),cmp);
1853  }
1854 
1855  }
1856 
1857  for(unsigned int ui=0;ui<tetrahedra.size();ui++)
1858  {
1859  bool found=false;
1860  for(unsigned int uj=0;uj<curPhys.size();uj++)
1861  {
1862  if(curPhys[uj].first== tetrahedra[ui].physGroup)
1863  {
1864  found=true;
1865  curPhys[uj].second++;
1866  break;
1867  }
1868  }
1869 
1870  if(!found)
1871  {
1872  //we've not seen this before...
1873  curPhys.push_back(make_pair(tetrahedra[ui].physGroup,1));
1874  std::sort(curPhys.begin(),curPhys.end(),cmp);
1875  }
1876 
1877  }
1878 }
1879 
1880 void Mesh::erasePhysGroup(unsigned int physGroup, unsigned int typeMask)
1881 {
1882  std::cerr << "Erasing..." << typeMask << std::endl;
1883  unsigned int eraseCount;
1884  if((typeMask & ELEMENT_TRIANGLE) != 0 )
1885  {
1886  eraseCount=0;
1887  //Drop any elements that we don't need
1888  for(size_t ui=triangles.size()-1;ui!=0; ui--)
1889  {
1890  if(triangles[ui].physGroup== physGroup)
1891  {
1892  std::swap(triangles[ui],*(triangles.end()-(eraseCount+1)));
1893  eraseCount++;
1894  }
1895  }
1896 
1897  std::cerr << "Erasing " << eraseCount << std::endl;
1898  triangles.resize(triangles.size()-eraseCount);
1899  }
1900 
1901 
1902  if(typeMask & ELEMENT_TETRAHEDRON)
1903  {
1904  eraseCount=0;
1905  //Drop any elements that we don't need
1906  for(size_t ui=tetrahedra.size()-1;ui!=0; ui--)
1907  {
1908  if(tetrahedra[ui].physGroup== physGroup)
1909  {
1910  std::swap(tetrahedra[ui],tetrahedra.back());
1911  eraseCount++;
1912  }
1913  }
1914 
1915  //drop the tail elements
1916  tetrahedra.resize(tetrahedra.size()-eraseCount);
1917  }
1918 
1919  if(typeMask & ELEMENT_LINE)
1920  {
1921  eraseCount=0;
1922  //Drop any elements that we don't need
1923  for(size_t ui=tetrahedra.size()-1;ui!=0; ui++)
1924  {
1925  if(tetrahedra[ui].physGroup== physGroup)
1926  {
1927  std::swap(tetrahedra[ui],tetrahedra.back());
1928  eraseCount++;
1929  }
1930  }
1931 
1932  //drop the tail elements
1933  tetrahedra.resize(tetrahedra.size()-eraseCount);
1934  }
1935 
1936 }
1937 
1938 
1939 //Volume estimation of Zhang and Chen, using overlapping signed tetrahedron
1940 // method
1941 // EFFICIENT FEATURE EXTRACTION FOR 2D/3D OBJECTS
1942 // IN MESH REPRESENTATION. Dept. Electrical and Computer Engineering,
1943 // Carnegie Mellon University
1944 // Original URL : http://amp.ece.cmu.edu/Publication/Cha/icip01_Cha.pdf
1945 // Retrieved from internet archive.
1946 float Mesh::getVolume() const
1947 {
1948  ASSERT(isSane());
1950 
1951  //Construct triangle volume estimate
1952  //using V = 1.0/6.0* | a.(b x c) |
1953  // where a, b, c are the relative vectors from some vertex d
1954  //For us, let d = (0,0,0)
1955  float vol=0;
1956  for(size_t ui=0;ui<triangles.size();ui++)
1957  {
1958  Point3D p[3];
1959  const TRIANGLE *t;
1960  t= &(triangles[ui]);
1961 
1962  for(size_t uj=0;uj<3;uj++)
1963  p[uj]=nodes[t->p[uj]];
1964 
1965  float newVol;
1966  newVol=p[0].dotProd(p[1].crossProd(p[2]));
1967 
1968  ASSERT(newVol > 0.0f);
1969  vol+=newVol;
1970  }
1971 
1972  vol*=1.0/6.0;
1973  std::cerr << "Signed volume :" << vol << std::endl;
1974  return fabs(vol);
1975 }
1976 
1977 size_t Mesh::elementCount() const
1978 {
1979  return points.size() + tetrahedra.size() + triangles.size() + lines.size();
1980 }
1981 
1982 //This is a somewhat efficient algorithm to compute if a set of points lies
1983 //inside or outside a sealed mesh. With work, could be better.
1984 //Mesh must:
1985 // - Consist only of triangles
1986 // - Be water tight (no holes in mesh)
1987 // - be non-self intersecting
1988 // - have coherently oriented triangle normals
1989 void Mesh::pointsInside(const vector<Point3D> &p,
1990  vector<bool> &meshResults,unsigned int &prog) const
1991 {
1992 // ASSERT(trianglesFullyConnected()); TODO: Implement me
1994  ASSERT(!tetrahedra.size());
1995 
1996  Point3D centre=Point3D(0,0,0);;
1997  //Find the bounding box of the triangle component of the mesh
1998  for(size_t ui=0;ui<triangles.size();ui++)
1999  {
2000  //create a point cloud consisting of triangle vertices
2001  centre+=(nodes[triangles[ui].p[0]]);
2002  centre+=(nodes[triangles[ui].p[1]]);
2003  centre+=(nodes[triangles[ui].p[2]]);
2004  }
2005 
2006  centre=centre*1.0/(3.0f*(float)triangles.size());
2007 
2008 
2009  //Find the minimal and maximal distances from the centre of the mesh
2010  // to the surface
2011  float maxSqrDistance;
2012  maxSqrDistance=0;
2013 
2014  //This could not use sqr distance, but could use
2015  // bounding box centroid.
2016 #pragma omp parallel for reduction(max:maxSqrDistance)
2017  for(size_t ui=0;ui<triangles.size();ui++)
2018  {
2019  maxSqrDistance=std::max(maxSqrDistance,
2020  centre.sqrDist(nodes[triangles[ui].p[0]]));
2021  maxSqrDistance=std::max(maxSqrDistance,
2022  centre.sqrDist(nodes[triangles[ui].p[1]]));
2023  maxSqrDistance=std::max(maxSqrDistance,
2024  centre.sqrDist(nodes[triangles[ui].p[2]]));
2025  }
2026 
2027 
2028  //Two points outside from which we can shoot rays for Jordan
2029  //curve theorem
2030  Point3D outsideMesh[2];
2031  outsideMesh[0] = centre + Point3D(0,0,1.1)*maxSqrDistance;
2032  outsideMesh[1] = centre - Point3D(3,1,1.1)*maxSqrDistance;
2033  meshResults.resize(p.size(),false);
2034  BoundCube c;
2035  c.setBounds(nodes);
2036 
2037 
2038  size_t actualProg=0;
2039  size_t reportedProg=0;
2040  size_t curProg=0;
2041  size_t progReduce=PROGRESS_REDUCE;
2042  //Loop through the point array; generate the final mesh
2043 #pragma omp parallel for firstprivate(progReduce)
2044  for(unsigned int ui=0;ui<p.size();ui++)
2045  {
2046  //Do a quick spherical shell test,
2047  //then a cube test before doing more complex
2048  //polygonal containment test
2049  float sqrDist;
2050  sqrDist=p[ui].sqrDist(centre);
2051  if(sqrDist <= maxSqrDistance &&
2052  c.containsPt(p[ui]) )
2053  {
2054 
2055  //So the sphere test didn't give us a clear answer.
2056  // use a complete polygonal test to check if the point is inside or outside
2057  unsigned int intersectionCount;
2058  intersectionCount=0;
2059  BoundCube rayBound;
2060  Point3D *externPt;
2061 
2062  if(p[ui].sqrDist(outsideMesh[0])<
2063  p[ui].sqrDist(outsideMesh[1]))
2064  {
2065  externPt=outsideMesh;
2066  rayBound.setBounds(p[ui],outsideMesh[0]);
2067  }
2068  else
2069  {
2070  externPt=outsideMesh+1;
2071  rayBound.setBounds(p[ui],outsideMesh[1]);
2072  }
2073 
2074  //Test each triangle for intersection with the
2075  //ray coming from outside the mesh. If even,
2076  //point is outside. If odd, inside.
2077  for(size_t uj=0;uj<triangles.size();uj++)
2078  {
2079  Point3D triangle[3];
2080  Point3D dummy;
2081 
2082  triangle[0] = nodes[triangles[uj].p[0]];
2083  triangle[1] = nodes[triangles[uj].p[1]];
2084  triangle[2] = nodes[triangles[uj].p[2]];
2085 
2086  unsigned int intersectType;
2087  intersectType = intersect_RayTriangle(*externPt,
2088  p[ui],triangle,dummy);
2089  if(intersectType == 1)
2090  intersectionCount++;
2091  }
2092 
2093  //If is odd, due to boundary crossings, it must be inside
2094  meshResults[ui]=intersectionCount%2;
2095  }
2096 
2097  if(!progReduce--)
2098  {
2099 #ifdef _OPENMP
2100  if(!omp_get_thread_num())
2101  {
2102 #endif
2103  //Compute actual progress
2104  prog= (unsigned int)(((float)curProg*100.0f)/(float)p.size());
2105 
2106 #ifdef _OPENMP
2107  }
2108 #endif
2109 
2110 #pragma omp critical
2111  curProg+=PROGRESS_REDUCE;
2112 
2113  progReduce=PROGRESS_REDUCE;
2114  }
2115  }
2116 }
2117 
2118 
2119 void Mesh::pointsInside(const vector<Point3D> &p,
2120  vector<bool> &meshResults) const
2121 {
2122  unsigned int dummyProg;
2123  pointsInside(p,meshResults,dummyProg);
2124 }
2125 
2126 size_t Mesh::getNearestTri(const Point3D &p,float &signedDistance) const
2127 {
2128  //Loop over all the triangles in order to locate the nearest
2129  size_t nearTri = (size_t)-1;
2130  float distance=std::numeric_limits<float>::max();
2131  for(size_t ui=0;ui<triangles.size();ui++)
2132  {
2133  Point3D normal;
2134  getTriNormal(ui,normal);
2135 
2136  float newDist;
2137  newDist=signedDistanceToFacet(nodes[triangles[ui].p[0]],
2138  nodes[triangles[ui].p[1]],
2139  nodes[triangles[ui].p[2]],normal,p);
2140  if(fabs(newDist) < distance)
2141  {
2142  nearTri=ui;
2143  distance= fabs(newDist);
2144  signedDistance=newDist;
2145  }
2146  }
2147 
2148  return nearTri;
2149 }
2150 
2151 
2153 {
2154  ASSERT(isSane());
2155  //Need to check circulation of triangles, (edge A->B on one
2156  // triangle matches that of the other).
2157  //for all triangles in the mesh
2158 
2159  vector<bool> seenTri;
2160  seenTri.resize(triangles.size(),false);
2161 
2162  deque<size_t> triQueue;
2163 
2164  std::vector<std::list<size_t> > adjacency;
2165  getTriEdgeAdjacencyMap(adjacency);
2166 
2167  for(size_t ui=0;ui<triangles.size();ui++)
2168  {
2169  //Add unvisited to queue,
2170  if(!seenTri[ui])
2171  {
2172  triQueue.push_back(ui);
2173  seenTri[ui] = true;
2174  }
2175 
2176  //Visit all triangles contiguous to whatever is in the queue
2177  while(triQueue.size())
2178  {
2179  size_t tri;
2180  tri = triQueue.front();
2181  triQueue.pop_front();
2182 
2183  list<size_t> *curAdjT;
2184  curAdjT= &(adjacency[tri]);
2185 
2186  for(list<size_t>::const_iterator it=curAdjT->begin(); it !=curAdjT->end();++it)
2187  {
2188  if(*it == tri || seenTri[*it])
2189  continue;
2190 
2191  if(triangles[tri].edgesMismatch(triangles[*it]))
2192  return false;
2193 
2194  seenTri[*it]= true;
2195  triQueue.push_back(*it);
2196 
2197  }
2198 
2199  }
2200  }
2201 
2202 
2203  return true;
2204 }
2205 
2206 bool TRIANGLE::isSane(size_t nMax) const
2207 {
2208 
2209  for(size_t ui=0;ui<3;ui++)
2210  {
2211  if ( p[ui] == p[(ui+1)%3])
2212  return false;
2213 
2214  //if nMax supplied, use it
2215  if(nMax != (size_t) -1 && p[ui] > nMax )
2216  return false;
2217  }
2218 
2219  return true;
2220 }
2221 
2222 bool TRIANGLE::edgesMismatch(const TRIANGLE &other) const
2223 {
2224  ASSERT(isSane());
2225  ASSERT(other.isSane());
2226 
2227 
2228  vector<size_t> commonV;
2229  for(size_t ui=0;ui<3;ui++)
2230  {
2231  for(size_t uj=0;uj<3;uj++)
2232  {
2233  if ( other.p[uj] == p[ui])
2234  {
2235  commonV.push_back(p[ui]);
2236  break;
2237  }
2238  }
2239  }
2240 
2241  ASSERT(commonV.size() <=3);
2242 
2243  //If either zero or one common vertices, then there is no edge
2244  // mismatch
2245  if(commonV.size() < 2)
2246  return false;
2247  else
2248  {
2249  unsigned int pA[3],pB[3];
2250 
2251  for(size_t ui=0;ui<3;ui++)
2252  {
2253  //If common vertex cannot be found, replace with "-1"
2254  if(std::find(commonV.begin(),commonV.end(),p[ui]) == commonV.end())
2255  pA[ui]=-1;
2256  else
2257  pA[ui]=p[ui];
2258 
2259  //If common vertex cannot be found, replace with "-1"
2260  if(std::find(commonV.begin(),commonV.end(),other.p[ui]) == commonV.end())
2261  pB[ui]=-1;
2262  else
2263  pB[ui]=other.p[ui];
2264  }
2265 
2266  if (commonV.size() == 3)
2267  {
2268 
2269  //If the triangles have all 3 vertices in common, they will match IFF they
2270  // have a rotationally invariant sequence that matches (3 matching edges). As permutations
2271  // other than vertex sequence rotation will flip the triangle normal
2272  // eg : 1-2-3 matches 2-3-1, but not 1-3-2
2273  return !rotateMatch(pA,pB,3);
2274  }
2275  else
2276  {
2277  //If the triangles have 2 vs in common, then they have one edge in common.
2278  // this will match IFF the circulation (edge ordering) of the two triangles is opposite
2279  return !antiRotateMatch(pA,pB,3);
2280  }
2281  }
2282 
2283  ASSERT(false);
2284 }
2285 
2286 #ifdef DEBUG
2287 
2288 bool coherencyTests()
2289 {
2290  //Create a perfects valid mesh of tris
2291  //---
2292  Mesh m;
2293 
2294  m.nodes.push_back(Point3D(0,0,0));
2295  m.nodes.push_back(Point3D(0,0,1));
2296  m.nodes.push_back(Point3D(1,0,0));
2297  m.nodes.push_back(Point3D(0,1,0));
2298 
2299  TRIANGLE t;
2300  t.p[0] = 0;
2301  t.p[1] = 1;
2302  t.p[2] = 2;
2303  m.triangles.push_back(t);
2304 
2305  t.p[0]=1;
2306  t.p[1]=0;
2307  t.p[2]=3;
2308  m.triangles.push_back(t);
2309 
2310  t.p[0]=3;
2311  t.p[1]=2;
2312  t.p[2]=1;
2313  m.triangles.push_back(t);
2314  //---
2315 
2316  TEST(m.isOrientedCoherently(),"mesh coherency check");
2317 
2318 
2319  //Flip the shared edge representation for a tri, so we get an inverted
2320  // normal on one tri
2321  m.triangles[1].p[0]=0;
2322  m.triangles[1].p[1]=1;
2323 
2324  TEST(!m.isOrientedCoherently(),"check incoherent mesh detection");
2325 
2326  return true;
2327 }
2328 
2329 bool nearestTriTest()
2330 {
2331  Mesh m;
2332 
2333  //Make an L shaped edge
2334  m.nodes.push_back(Point3D(1,0,0));
2335  m.nodes.push_back(Point3D(-1,0,0));
2336  m.nodes.push_back(Point3D(0,0,1));
2337  m.nodes.push_back(Point3D(0,1,0));
2338 
2339 
2340  //0,3,1
2341  TRIANGLE t;
2342  t.p[0]=0;
2343  t.p[1]=3;
2344  t.p[2]=1;
2345  m.triangles.push_back(t);
2346 
2347  //0,1,2
2348  t.p[0]=0;
2349  t.p[1]=1;
2350  t.p[2]=2;
2351  m.triangles.push_back(t);
2352 
2353  //Test that the exterior test works,
2354  // using point (0.5,0,0.4)
2355  float dist;
2356  TEST(m.getNearestTri(Point3D(0,0.5,0.4),dist) == 0,"Nearest tri");
2357  TEST(m.getNearestTri(Point3D(0,0.5,0.6),dist) == 1,"Nearest tri");
2358 
2359  return true;
2360 
2361 }
2362 
2363 bool meshTests()
2364 {
2365  TEST(coherencyTests(),"Mesh coherency checks");
2366  TEST(nearestTriTest(),"Mesh nearest tri");
2367  return true;
2368 }
2369 
2370 #endif
2371 }
bool containsPt(const Point3D &pt) const
Check to see if the point is contained in, or part of the walls of the cube.
Definition: boundcube.cpp:367
std::vector< std::string > physGroupNames
Physical group storage.
Definition: mesh.h:113
void setInverseLimits()
Set the cube to be "inside out" at the limits of numeric results;.
Definition: boundcube.cpp:94
void getTriNormal(size_t tri, Point3D &normal) const
Definition: mesh.cpp:1753
float Determinant(float **a, int n)
Definition: mesh.cpp:172
bool isSane(bool output=false, std::ostream &outStream=std::cerr) const
Perform various sanity tests on mesh. Should return true if your mesh is sane.
Definition: mesh.cpp:572
float signedDistanceToFacet(const Point3D &fA, const Point3D &fB, const Point3D &fC, const Point3D &normal, const Point3D &p)
Find the distance between a point, and a triangular facet – may be positive or negative.
Definition: misc.cpp:172
unsigned int saveGmshMesh(const char *meshfile) const
Definition: mesh.cpp:1390
void resizeNodes(unsigned int newSize)
Resize the node vector.
Definition: mesh.cpp:858
unsigned int p[2]
Definition: mesh.h:73
bool isOrientedCoherently() const
Returns true if the mesh is coherently oriented.
Definition: mesh.cpp:2152
Point3D crossProd(const Point3D &pt) const
Calculate the cross product of this and another point.
Definition: point3D.cpp:285
unsigned int physGroup
Definition: mesh.h:54
bool rotateMatch(const unsigned int *a, const unsigned int *b, size_t n, bool directionForwards=true)
Definition: mesh.cpp:100
unsigned int numDupVertices(float tolerance) const
obtain the number of duplicate vertices in the mesh
Definition: mesh.cpp:911
std::vector< TETRAHEDRON > tetrahedra
Storage for node connectivity in tetrahedral form.
Definition: mesh.h:118
int intersect_RayTriangle(const Point3D &rayStart, const Point3D &rayEnd, Point3D *tri, Point3D &I)
Definition: mesh.cpp:280
void getCurPhysGroups(std::vector< std::pair< unsigned int, size_t > > &curPhys) const
Definition: mesh.cpp:1829
bool edgesMismatch(const TRIANGLE &tOther) const
Definition: mesh.cpp:2222
float fourDeterminant(const Point3D &a, const Point3D &b, const Point3D &c, const Point3D &d)
Definition: mesh.cpp:212
const char * MESH_LOAD_ERRS[]
Definition: mesh.cpp:53
void reassignGroups(unsigned int i)
reassign the physical groups to a single number
Definition: mesh.cpp:1375
void quat_get_rot_quat(const Point3f *rotVec, float angle, Quaternion *rotQuat)
Compute the quaternion for specified rotation.
Definition: quat.cpp:184
std::vector< LINE > lines
Storage for line segments. .size()%2 should always==0.
Definition: mesh.h:123
#define TEST(f, g)
Definition: aptAssert.h:49
Simple mesh class for storing and manipulating meshes consisting of 2 and 3D simplexes (triangles or ...
Definition: mesh.h:78
const unsigned int ELEM_FOUR_NODE_TETRAHEDRON
Definition: mesh.h:38
unsigned int divideMeshSurface(float divisionAngle, unsigned int newPhysGroupStart, const std::vector< size_t > &physGroupsToSplit)
Definition: mesh.cpp:1597
Point3D getNodes(unsigned int index)
Retrieve an object.
Definition: mesh.cpp:863
const unsigned int ELEM_SINGLE_NODE_POINT
Definition: mesh.h:35
void killOrphanNodes()
Kill specified orphan nodes within this dataset.
Definition: mesh.cpp:820
void removeDuplicateTris()
Remove exact duplicate triangles.
Definition: mesh.cpp:691
float sqrMag() const
Returns magnitude^2, taking this as a position vector.
Definition: point3D.cpp:332
unsigned int loadGmshMesh(const char *meshfile, unsigned int &curLine, bool allowBadMeshes=true)
Definition: mesh.cpp:1039
size_t getNearestTri(const Point3D &p, float &distance) const
Find the nearest triangle to a particular point.
Definition: mesh.cpp:2126
const unsigned int ELEM_THREE_NODE_TRIANGLE
Definition: mesh.h:37
bool antiRotateMatch(const unsigned int *a, const unsigned int *b, size_t n)
Definition: mesh.cpp:63
void quat_rot_apply_quat(Point3f *point, const Quaternion *rotQuat)
Use previously generated quats from quat_get_rot_quats to rotate a point.
Definition: quat.cpp:206
void rotate(const Point3D &axis, const Point3D &origin, float angle)
Rotate mesh.
Definition: mesh.cpp:1453
unsigned int physGroup
Definition: mesh.h:74
void splitStrsRef(const char *cpStr, const char delim, std::vector< std::string > &v)
Split string references using a single delimiter.
A 3D point data class storage.
Definition: point3D.h:39
void getContainedNodes(const BoundCube &b, std::vector< size_t > &nodes) const
Return all the nodes that are contained within specified bounding box.
Definition: mesh.cpp:1761
Data storage structure for points.
Definition: quat.h:45
float signVal(unsigned int val)
Definition: mesh.cpp:147
void clear()
Clear the mesh.
Definition: mesh.cpp:936
unsigned int p[4]
Definition: mesh.h:53
std::vector< Point3D > nodes
Point storage for 3D Data (nodes/coords/vertices..)
Definition: mesh.h:110
const unsigned int ELEM_TWO_NODE_LINE
Definition: mesh.h:36
size_t findMaxLessThanOrEq(const vector< std::pair< size_t, size_t > > &v, size_t value)
Definition: mesh.cpp:155
float angle(const Point3D &pt) const
Calculate the angle between two position vectors in radians.
Definition: point3D.cpp:388
size_t elementCount() const
Definition: mesh.cpp:1977
#define ARRAYSIZE(f)
Definition: helpFuncs.h:34
void scale(const Point3D &origin, float scaleFactor)
Scale the mesh around a specified origin.
Definition: mesh.cpp:1514
Data storage structure for quaternions.
Definition: quat.h:35
unsigned int edgeIdx(unsigned int i, unsigned int j)
Definition: mesh.cpp:249
const size_t PROGRESS_REDUCE
Definition: mesh.cpp:61
bool isSane(size_t pLimit=(size_t) -1) const
Definition: mesh.cpp:2206
unsigned int p[3]
Definition: mesh.h:59
void translate()
Translate mesh around node centroid.
Definition: mesh.cpp:1496
void print(std::ostream &o) const
Print some statistics about the mesh data.
Definition: mesh.cpp:445
Helper class to define a bounding cube.
Definition: boundcube.h:29
void normalise()
Make point unit magnitude, maintaining direction.
Definition: point3D.cpp:337
unsigned int physGroup
Definition: mesh.h:60
void findNearVerticies(float tolerance, const vector< Point3D > &ptVec, vector< std::pair< size_t, vector< size_t > > > &clusterList)
Definition: mesh.cpp:365
#define ASSERT(f)
void mergeDuplicateVertices(float tolerance)
Definition: mesh.cpp:738
void setTriangleMesh(const std::vector< float > &ptsA, const std::vector< float > &ptsB, const std::vector< float > &ptsC)
Definition: mesh.cpp:946
bool stream_cast(T1 &result, const T2 &obj)
Template function to cast and object to another by the stringstream.
Definition: stringFuncs.h:32
void setNode(unsigned int index, Point3D node)
Set the nodes value.
Definition: mesh.cpp:853
std::vector< unsigned long long > points
points
Definition: mesh.h:125
float dotProd(const Point3D &pt) const
Calculate the dot product of this and another point.
Definition: point3D.cpp:279
void erasePhysGroup(unsigned int group, unsigned int typeMask)
Definition: mesh.cpp:1880
void pointsInside(const std::vector< Point3D > &p, std::vector< bool > &meshResults, unsigned int &prog) const
Find the points that lie inside a this mesh.
Definition: mesh.cpp:1989
std::vector< TRIANGLE > triangles
Storage for node connectivity in triangle form (take in groups of 3)
Definition: mesh.h:121
unsigned int numDupTris() const
Obtain the number of duplicate triangles in the mesh.
Definition: mesh.cpp:868
void getIntersectingPrimitives(std::vector< size_t > &searchNodes, std::vector< size_t > &lines, std::vector< size_t > &triangles, std::vector< size_t > &tetrahedra) const
Return all primitives that are WHOLLY contained withing bounding box.
Definition: mesh.cpp:1772
void setBounds(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax)
Set the bounds by passing in minima and maxima of each dimension.
Definition: boundcube.cpp:49
void getBounds(BoundCube &b) const
Get the Axis aligned bounding box for this mesh.
Definition: mesh.cpp:1532
void expand(const BoundCube &b)
Expand (as needed) volume such that the argument bounding cube is enclosed by this one...
Definition: boundcube.cpp:148
float getVolume() const
Obtain the volume of the triangulated space.
Definition: mesh.cpp:1946
unsigned int countTriNodes() const
Count the number of unique nodes shared by triangles.
Definition: mesh.cpp:1350