libatomprobe
Library for Atom Probe Tomography (APT) computation
isoSurface.cpp
Go to the documentation of this file.
1 /*
2  * IsoSurface.cpp - Isosurface interface generation
3  * Copyright (C) 2018, D Haley
4 
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14 
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
20 #include <map>
21 #include <list>
22 #include <vector>
23 
24 
25 using std::list;
26 using std::map;
27 using std::vector;
28 using std::pair;
29 using std::make_pair;
30 
31 
32 #ifdef DEBUG
34 #endif
35 
36 namespace AtomProbe
37 {
38 
39 
40 
41 #ifdef DEBUG
42 template<class T1, class T2>
43 bool mapUnique(const std::map<T1,T2> &m)
44 {
45  vector<T2> vec;
46  vec.reserve(m.size());
47 
48  for(typename std::map<T1,T2>::const_iterator it = m.begin(); it!=m.end(); ++it)
49  {
50  if(std::find(vec.begin(),vec.end(),it->second) != vec.end())
51  return false;
52 
53  vec.push_back(it->second);
54 
55  }
56 
57  return true;
58 }
59 #endif
60 
61 
62 //input vector "vec" must be sorted and unique
63 template<class T>
64 void removeElements( const std::vector<size_t> &elems,std::vector<T> &vec)
65 {
66  if(vec.empty() || elems.empty())
67  return;
68 
69  if(vec.size() == elems.size())
70  {
71  vec.clear();
72  return;
73  }
74 
75  size_t offset=vec.size()-1;
76  //Run backwards, swapping out
77  for(size_t ui=elems.size();ui--;)
78  {
79  ASSERT(ui <= offset);
80  std::swap(vec[elems[ui]],vec[offset]);
81  offset--;
82  }
83  vec.resize(offset+1);
84 }
85 
86 
87 
88 
90 {
91  Point3D a,b;
92 
93  a = p[0]-p[1];
94  b = p[0]-p[2];
95 
96  n=a.crossProd(b);
97  n.normalise();
98 }
99 
101 {
102  Point3D a,b;
103 
104  a = p[0]-p[1];
105  b = p[0]-p[2];
106 
107  n=a.crossProd(b);
108  if(n.sqrMag() < sqrt(std::numeric_limits<float>::epsilon()) )
109  n=Point3D(0,0,1);
110  else
111  n.normalise();
112 
113 
114 
115 }
116 
118 {
119  Point3D a,b;
120 
121  a = p[0]-p[1];
122  b = p[0]-p[2];
123 
124  return a.crossProd(b).sqrMag();
125 
126 }
127 
129 {
130  return (p[0].sqrDist(p[1]) < std::numeric_limits<float>::epsilon() ||
131  p[0].sqrDist(p[2]) < std::numeric_limits<float>::epsilon() ||
132  p[2].sqrDist(p[1]) < std::numeric_limits<float>::epsilon());
133 }
134 
136 {
137  c=p[0];
138  c+=p[1];
139  c+=p[2];
140 
141  c*=1.0f/3.0f;
142 }
143 
144 //This code is a modified version of the following:
145 //==============
146 // Marching Cubes Example Program
147 // by Cory Bloyd (corysama@yahoo.com)
148 //
149 // A simple, portable and complete implementation of the Marching Cubes
150 // and Marching Tetrahedrons algorithms in a single source file.
151 // There are many ways that this code could be made faster, but the
152 // intent is for the code to be easy to understand.
153 //
154 // For a description of the algorithm go to
155 // http://astronomy.swin.edu.au/pbourke/modelling/polygonise/
156 //
157 // The original code is public domain, and is used here under the GNU General Public Licence, V3 or later.
158 // =========
159 
160 // For any edge, if one vertex is inside of the surface and the other is outside of the surface
161 // then the edge intersects the surface
162 // For each of the 8 vertices of the cube can be two possible states : either inside or outside of the surface
163 // For any cube the are 2^8=256 possible sets of vertex states
164 // This table lists the edges intersected by the surface for all 256 possible vertex states
165 // There are 12 edges. For each entry in the table, if edge #n is intersected, then bit #n is set to 1
167 {
168  0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
169  0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
170  0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
171  0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
172  0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
173  0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
174  0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
175  0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
176  0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
177  0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
178  0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
179  0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
180  0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
181  0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
182  0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
183  0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
184 };
185 
186 // For each of the possible vertex states listed in aiCubeEdgeFlags there is a specific triangulation
187 // of the edge intersection points. a2iTriangleConnectionTable lists all of them in the form of
188 // 0-5 edge triples with the list terminated by the invalid value -1.
189 // For example: a2iTriangleConnectionTable[3] list the 2 triangles formed when corner[0]
190 // and corner[1] are inside of the surface, but the rest of the cube is not.
191 //
192 // I found this table in an example program someone wrote long ago. It was probably generated by hand
193 
195 {
196  {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
197  {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
198  {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
199  {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
200  {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
201  {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
202  {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
203  {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
204  {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
205  {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
206  {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
207  {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
208  {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
209  {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
210  {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
211  {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
212  {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
213  {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
214  {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
215  {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
216  {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
217  {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
218  {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
219  {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
220  {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
221  {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
222  {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
223  {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
224  {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
225  {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
226  {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
227  {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
228  {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
229  {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
230  {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
231  {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
232  {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
233  {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
234  {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
235  {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
236  {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
237  {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
238  {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
239  {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
240  {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
241  {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
242  {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
243  {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
244  {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
245  {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
246  {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
247  {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
248  {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
249  {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
250  {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
251  {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
252  {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
253  {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
254  {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
255  {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
256  {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
257  {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
258  {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
259  {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
260  {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
261  {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
262  {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
263  {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
264  {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
265  {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
266  {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
267  {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
268  {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
269  {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
270  {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
271  {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
272  {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
273  {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
274  {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
275  {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
276  {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
277  {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
278  {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
279  {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
280  {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
281  {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
282  {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
283  {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
284  {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
285  {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
286  {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
287  {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
288  {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
289  {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
290  {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
291  {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
292  {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
293  {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
294  {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
295  {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
296  {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
297  {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
298  {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
299  {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
300  {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
301  {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
302  {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
303  {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
304  {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
305  {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
306  {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
307  {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
308  {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
309  {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
310  {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
311  {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
312  {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
313  {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
314  {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
315  {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
316  {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
317  {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
318  {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
319  {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
320  {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
321  {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
322  {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
323  {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
324  {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
325  {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
326  {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
327  {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
328  {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
329  {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
330  {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
331  {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
332  {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
333  {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
334  {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
335  {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
336  {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
337  {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
338  {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
339  {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
340  {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
341  {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
342  {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
343  {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
344  {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
345  {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
346  {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
347  {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
348  {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
349  {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
350  {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
351  {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
352  {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
353  {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
354  {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
355  {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
356  {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
357  {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
358  {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
359  {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
360  {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
361  {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
362  {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
363  {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
364  {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
365  {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
366  {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
367  {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
368  {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
369  {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
370  {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
371  {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
372  {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
373  {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
374  {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
375  {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
376  {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
377  {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
378  {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
379  {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
380  {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
381  {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
382  {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
383  {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
384  {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
385  {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
386  {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
387  {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
388  {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
389  {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
390  {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
391  {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
392  {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
393  {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
394  {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
395  {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
396  {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
397  {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
398  {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
399  {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
400  {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
401  {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
402  {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
403  {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
404  {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
405  {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
406  {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
407  {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
408  {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
409  {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
410  {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
411  {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
412  {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
413  {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
414  {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
415  {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
416  {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
417  {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
418  {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
419  {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
420  {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
421  {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
422  {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
423  {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
424  {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
425  {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
426  {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
427  {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
428  {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
429  {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
430  {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
431  {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
432  {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
433  {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
434  {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
435  {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
436  {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
437  {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
438  {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
439  {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
440  {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
441  {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
442  {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
443  {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
444  {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
445  {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
446  {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
447  {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
448  {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
449  {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
450  {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
451  {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
452 };
453 
454 //a2fVertexOffset lists the positions, relative to vertex0, of each of the 8 vertices of a cube
455 /*static const float a2fVertexOffset[8][3] =
456 {
457  {0.0, 0.0, 0.0},{1.0, 0.0, 0.0},{1.0, 1.0, 0.0},{0.0, 1.0, 0.0},
458  {0.0, 0.0, 1.0},{1.0, 0.0, 1.0},{1.0, 1.0, 1.0},{0.0, 1.0, 1.0}
459 };*/
460 
461 //The deltas for the vertex offsets. This is the int version of a2fVertexOffset
462 const unsigned int VERTEX_OFFSET[8][3] =
463 {
464  {0, 0, 0},{1, 0, 0},{1, 1, 0},{0, 1, 0},
465  {0, 0, 1},{1, 0, 1},{1, 1, 1},{0, 1, 1}
466 };
467 
468 //a2iEdgeConnection lists the index of the endpoint vertices for each of the 12 edges of the cube
469 /*
470 static const int a2iEdgeConnection[12][2] =
471 {
472  {0,1}, {1,2}, {2,3}, {3,0},
473  {4,5}, {5,6}, {6,7}, {7,4},
474  {0,4}, {1,5}, {2,6}, {3,7}
475 };
476 
477 //a2fEdgeDirection lists the direction vector (vertex1-vertex0) for each edge in the cube
478 static const float a2fEdgeDirection[12][3] =
479 {
480  {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0},
481  {1.0, 0.0, 0.0},{0.0, 1.0, 0.0},{-1.0, 0.0, 0.0},{0.0, -1.0, 0.0},
482  {0.0, 0.0, 1.0},{0.0, 0.0, 1.0},{ 0.0, 0.0, 1.0},{0.0, 0.0, 1.0}
483 };
484 */
485 
486 //Mapping between edges as defined in a2iEdgeConenction, (and thus implicitly in edge table)
487 //and the voxels.h definition
488 int edgeRemap[12] ={ 0,6,1,4,
489  2,7,3,5,
490  8,10,11,9};
491 
492 
493 //vMarchingCubes iterates over the entire dataset, calling vMarchCube on each cube
494 void marchingCubes(const Voxels<float> &v,float isoValue, vector<TriangleWithVertexNorm> &tVec)
495 {
496  size_t nx,ny,nz;
497  v.getSize(nx,ny,nz);
498 
499  ASSERT(nx > 1 && ny>1 && nz>1);
500 
501  //Don't try to isosurface a any volume with a unitary dimension.
502  if(nx ==1 || ny ==1 || nz == 1)
503  return;
504 
505  Point3D gridSpacing;
506  gridSpacing=v.getPitch();
507 
508 #ifdef DEBUG
509  BoundCube boundC;
510  boundC.setBounds(v.getMinBounds(),v.getMaxBounds());
511 #endif
512 
513  vector<TriangleWithIndexedVertices> indexedTriVec;
514 
515  //Loop over the vertexs, with the mesh such that the
516  //nominally cube centres are now on a grid that is dual
517  //to the original grid (excluding the external boundary of course)
518 #pragma omp parallel for
519  for(size_t iX = 0; iX < nx-1; iX++)
520  {
521  int iEdgeFlags,iFlagIndex;
522  for(size_t iY = 0; iY < ny-1; iY++)
523  {
524  for(size_t iZ = 0; iZ < nz-1; iZ++)
525  {
526  iFlagIndex=0;
527 
528  //Find which vertices are inside of the surface and which are outside
529  for(int iVertexTest = 0; iVertexTest < 8; iVertexTest++)
530  {
531  float f;
532  f=v.getData(iX+VERTEX_OFFSET[iVertexTest][0],
533  iY+VERTEX_OFFSET[iVertexTest][1],
534  iZ+VERTEX_OFFSET[iVertexTest][2]);
535 
536  //Compute position in triangle and edge connection
537  //tables
538  if(f <= isoValue)
539  iFlagIndex |= 1<<iVertexTest;
540  }
541  //Find which edges are intersected by the surface
542  iEdgeFlags = aiCubeEdgeFlags[iFlagIndex];
543  if(!iEdgeFlags)
544  continue;
545 
546 
547  //Find the point of intersection of the surface with each edge
548  //Then find the normal to the surface at those points
549  size_t asEdgeVertex[12];
550  for(int iEdge = 0; iEdge < 12; iEdge++)
551  {
552  //if there is an intersection on this edge
553  if(iEdgeFlags & (1<<iEdge))
554  {
555  //Store a reference to the vertex position
556  asEdgeVertex[iEdge] = v.deprecatedGetEdgeUniqueIndex(iX,iY,iZ,edgeRemap[iEdge]);
557  }
558  }
559 
560 
561  //Store the triangles that were found. There can be up to five per cube;
562  //these are listed as triplets in the connection table
563  for(int iTriangle = 0; iTriangle < 5; iTriangle++)
564  {
565  //Check to see if this triplet is a valid triangle
566  if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0)
567  break;
568 
570  for(int iCorner = 0; iCorner < 3; iCorner++)
571  {
572  int iVertex;
573  iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];
574  //we should only be accessing an edge if the edge was set.
575  ASSERT((1 << iVertex) & iEdgeFlags);
576 
577 
578 
579 
580  t.p[iCorner] = asEdgeVertex[iVertex];
581  }
582 #pragma omp critical
583  indexedTriVec.push_back(t);
584  }
585  }
586  }
587  }
588 
589  //---------
590 
591  //OK, so we set up a network of triangle vertices which consist of edge numbers
592  //and a list of triangles which are the triplets of those numbers.
593  //Convert this into a
594 
595  //Map that contains a list of triangles in the vector "indexedTriVec"
596  // which share a particular edge (or rather, position along that edge)
597  // First element is the edge index. Second element is the list of triangles
598  // who share this edge.
599  //
600  // We will need this when we do the vertex normals.
601  std::map<size_t,list<size_t> > edgeTriMap;
602 #pragma omp parallel for
603  for(size_t ui=0;ui<indexedTriVec.size(); ui++)
604  {
605  for(size_t uj=0;uj<3;uj++)
606  {
607  map<size_t,list<size_t> >::iterator it;
608  it = edgeTriMap.find(indexedTriVec[ui].p[uj]);
609  if(it == edgeTriMap.end())
610  {
611 
612  list<size_t> seedList;
613  seedList.push_back(ui);
614 #pragma omp critical
615  edgeTriMap.insert(
616  make_pair(indexedTriVec[ui].p[uj],seedList));
617 
618  }
619  else
620  {
621  it->second.push_back(ui);
622  }
623  }
624 
625  }
626 
627 
628  //Generate the position points for each edge
629  map<size_t,Point3D> pointMap;
630  for(map<size_t,list<size_t> >::iterator it=edgeTriMap.begin();
631  it!=edgeTriMap.end(); ++it)
632  {
633  Point3D low,high,voxelFrameIntersection;
634  float lowF,highF;
635 
636  if(pointMap.find((it->first)) != pointMap.end())
637  continue;
638 
639  //Low/high sides of edge's scalar values
640  v.getEdgeEndApproxVals(it->first,lowF,highF);
641 
642 
643  //Get the edge's low and high end node positions
644  v.getEdgeEnds(it->first,low,high);
645 
646 
647 
648  //OK, now we have that, lets use the values to "lever" the
649  //solution point note node locations for isosurface
650  if(fabs(highF-lowF) < sqrt(std::numeric_limits<float>::epsilon()))
651  {
652  //Prevent divide by zero
653  voxelFrameIntersection=(low+high)*0.5;
654  }
655  else
656  {
657  //interpolate
658  float alpha;
659  alpha= (isoValue- lowF) / (highF- lowF);
660  voxelFrameIntersection=low + (high-low)*alpha;
661  }
662 
663  voxelFrameIntersection+=gridSpacing*0.5;
664 
665 
666 
667  pointMap.insert(make_pair(it->first,voxelFrameIntersection));
668 
669  }
670 
671 
672  tVec.resize(indexedTriVec.size());
673  vector<size_t> popTris;
674  //Set all triangle vertices
675  #pragma omp parallel for
676  for(size_t ui=0;ui<tVec.size();ui++)
677  {
678 
679  //Do a lookup of the edge point locations
680  // by mapping the edge indices to the edge points
681  for(int uj=0;uj<3;uj++)
682  tVec[ui].p[uj] = pointMap.at((indexedTriVec[ui].p[uj]));
683 
684  if(tVec[ui].isDegenerate())
685  {
686 #pragma omp critical
687  popTris.push_back(ui);
688  }
689  }
690 
691 
692  //Remove any degenerate triangles from both indexed and real maps
693  removeElements(popTris,tVec);
694  removeElements(popTris,indexedTriVec);
695 
696  if(tVec.empty())
697  return;
698 
699  //set all triangle edge normals by inverse face area weighting.
700  // The idea is that big triangles don't affect the normal at the point
701  // as they are quite delocalised. Little triangles affect it more.
702  // This is entirely empirical
703  // ----
704 
705  vector<Point3D> origNormal;
706  origNormal.resize(indexedTriVec.size());
707  #pragma omp parallel for
708  for(size_t ui=0;ui<indexedTriVec.size();ui++)
709  tVec[ui].safeComputeACWNormal(origNormal[ui]);
710 
711 
712  //Loop over all vertices again, then assign a weighted
713  //normal in place of the original normal. Lets cheat and
714  //re-use "pointmap".
715  // --
716  for(map<size_t,Point3D>::iterator it=pointMap.begin();
717  it!=pointMap.end();++it)
718  it->second=Point3D(0,0,0);
719 
720  //Construct the shared normals
721  float smallNum=sqrt(std::numeric_limits<float>::epsilon());
722  for(size_t ui=0;ui<indexedTriVec.size();ui++)
723  {
724  //For each vertex in our current triangle
725  //update the weight mapping
726  float weight;
727  weight=tVec[ui].computeArea();
728 
729  if(weight > smallNum)
730  {
731  for(int uj=0;uj<3;uj++)
732  pointMap.at((indexedTriVec[ui].p[uj]))+=origNormal[ui]*weight;
733  }
734  }
735 
736 
737  //re-normalise normals
738  for(map<size_t,Point3D>::iterator it=pointMap.begin();
739  it!=pointMap.end();++it)
740  {
741  if(it->second.sqrMag() > smallNum)
742  it->second.normalise();
743  else
744  it->second=Point3D(0,0,1);
745  }
746 
747  //assign these normals to the vertices of each triangle
748  #pragma omp parallel for
749  for(size_t ui=0;ui<indexedTriVec.size();ui++)
750  {
751  for(unsigned int uj=0;uj<3;uj++)
752  tVec[ui].normal[uj] = pointMap.at((indexedTriVec[ui].p[uj]));
753  }
754  // --
755 
756  // ----
757 
758 
759 
760 }
761 
762 #ifdef DEBUG
763 bool testIsoSurface()
764 {
765  Voxels<float> data;
766 
767  data.resize(4,4,4);
768  data.fill(0);
769  data.setData(1,1,1,1.0);
770 
771 
772  vector<TriangleWithVertexNorm> tVec;
773  marchingCubes(data,0.5,tVec);
774 
775  TEST(!tVec.empty(),"isosurface exists");
776 
777 
778 
779  //Should be 2 rect. pyramids back to back, with no bases
780  TEST(tVec.size() == 8, "isosurf. triangle count");
781  //Ensure that all the points are contained within the original data bounding box
782 
783  Point3D pMin,pMax;
784  data.getBounds(pMin,pMax);
785  BoundCube b;
786  b.setBounds(pMin,pMax);
787 
788  for(size_t ui=0;ui<tVec.size();ui++)
789  {
790  for(size_t uj=0;uj<3;uj++)
791  {
792  TEST(b.containsPt(tVec[ui].p[uj]),"Mesh contained in voxel bounds");
793  }
794  }
795 
796  //Convert the triangle soup into a mesh
797  Mesh debugMesh;
798  TRIANGLE t;
799  t.physGroup=0;
800  for(size_t ui=0;ui<tVec.size();ui++)
801  {
802 
803  for(size_t uj=0;uj<3;uj++)
804  {
805  t.p[uj] = debugMesh.nodes.size();
806  debugMesh.nodes.push_back(tVec[ui].p[uj]);
807  }
808 
809  debugMesh.triangles.push_back(t);
810  }
811  ASSERT(debugMesh.isSane())
812 
813  debugMesh.saveGmshMesh("debug-isosurf.msh");
814 
815  //Convert all duplicate vertices into single blob
816  debugMesh.mergeDuplicateVertices(0.0001);
817  ASSERT(debugMesh.isSane())
818  return true;
819 }
820 #endif
821 }
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
void safeComputeACWNormal(Point3D &p) const
Definition: isoSurface.cpp:100
const unsigned int VERTEX_OFFSET[8][3]
Definition: isoSurface.cpp:462
AtomProbe::Point3D getMaxBounds() const
Definition: voxels.h:954
size_t resize(size_t newX, size_t newY, size_t newZ, const AtomProbe::Point3D &newMinBound=AtomProbe::Point3D(0.0f, 0.0f, 0.0f), const AtomProbe::Point3D &newMaxBound=AtomProbe::Point3D(1.0f, 1.0f, 1.0f))
Resize the data field.
Definition: voxels.h:835
size_t deprecatedGetEdgeUniqueIndex(size_t x, size_t y, size_t z, unsigned int edge) const
DEPRECATED FUNCTION : Get a unique integer that corresponds to the edge index for the voxel; where ed...
Definition: voxels.h:497
void getEdgeEndApproxVals(size_t edgeUniqId, T &a, T &b) const
Return the values that are associated with the edge ends, as returned by getEdgeEnds.
Definition: voxels.h:813
void removeElements(const std::vector< size_t > &elems, std::vector< T > &vec)
Definition: isoSurface.cpp:64
void getBounds(AtomProbe::Point3D &pMin, AtomProbe::Point3D &pMax) const
Get the bounding size.
Definition: voxels.h:252
int a2iTriangleConnectionTable[256][16]
Definition: isoSurface.cpp:194
AtomProbe::Point3D getMinBounds() const
Get the bounding box vertex (min/max)
Definition: voxels.h:947
Point3D crossProd(const Point3D &pt) const
Calculate the cross product of this and another point.
Definition: point3D.cpp:285
int edgeRemap[12]
Definition: isoSurface.cpp:488
void computeACWNormal(Point3D &p) const
Definition: isoSurface.cpp:89
Template class that stores 3D voxel data.
Definition: voxels.h:106
#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
float sqrMag() const
Returns magnitude^2, taking this as a position vector.
Definition: point3D.cpp:332
void fill(const T &val)
Fill all voxels with a given value.
Definition: voxels.h:1536
T getData(size_t x, size_t y, size_t z) const
Retrieve the value of a specific voxel.
Definition: voxels.h:1186
A 3D point data class storage.
Definition: point3D.h:39
void getCentroid(Point3D &p) const
Definition: isoSurface.cpp:135
void getEdgeEnds(size_t edgeIndex, AtomProbe::Point3D &a, AtomProbe::Point3D &b) const
Convert the edge index (as generated by getEdgeUniqueIndex) into a cenre position.
Definition: voxels.h:771
unsigned int p[3]
Definition: mesh.h:59
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
AtomProbe::Point3D getPitch() const
! Get the spacing for a unit cell
Definition: voxels.h:480
void setData(size_t x, size_t y, size_t z, const T &val)
Retrieve a reference to the data ata given position.
Definition: voxels.h:435
#define ASSERT(f)
int aiCubeEdgeFlags[256]
Definition: isoSurface.cpp:166
void getSize(size_t &x, size_t &y, size_t &z) const
Get the size of the data field.
Definition: voxels.h:488
void marchingCubes(const Voxels< float > &v, float isoValue, std::vector< TriangleWithVertexNorm > &tVec)
Definition: isoSurface.cpp:494
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