GteSurfaceExtractor.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
11 #include <Imagics/GteImage3.h>
13 #include <Mathematics/GteVector3.h>
14 
15 namespace gte
16 {
17 
18 template <typename Real>
20 {
21 public:
22  // Construction and destruction.
23  virtual ~SurfaceExtractor();
25 
26  // Object copies are not allowed.
27  SurfaceExtractor() = delete;
28  SurfaceExtractor(SurfaceExtractor const&) = delete;
29  SurfaceExtractor const& operator=(SurfaceExtractor const&) = delete;
30 
31  struct Mesh
32  {
33  // All members are set to zeros.
34  Mesh();
35 
36  Topology topology;
37  std::array<Vector3<Real>, MAX_VERTICES> vertices;
38  };
39 
40  // Extract the triangle mesh approximating F = 0 for a single voxel.
41  // The input function values must be stored as
42  // F[0] = function(0,0,0), F[4] = function(0,0,1),
43  // F[1] = function(1,0,0), F[5] = function(1,0,1),
44  // F[2] = function(0,1,0), F[6] = function(0,1,1),
45  // F[3] = function(1,1,0), F[7] = function(1,1,1).
46  // Thus, F[k] = function(k & 1, (k & 2) >> 1, (k & 4) >> 2).
47  // The return value is 'true' iff the F[] values are all nonzero.
48  // If they are not, the returned 'mesh' has no vertices and no
49  // triangles--as if F[] had all positive or all negative values.
50  bool Extract(std::array<Real, 8> const& F, Mesh& mesh) const;
51 
52  // Extract the triangle mesh approximating F = 0 for all the voxels in
53  // a 3D image. The input image must be stored in a 1-dimensional array
54  // with lexicographical order; that is, image[i] corresponds to voxel
55  // location (x,y,z) where i = x + bound0 * (y + bound1 * z). The output
56  // 'indices' consists indices.size()/3 triangles, each a triple of
57  // indices into 'vertices'
58  bool Extract(Real level, std::vector<Vector3<Real>>& vertices, std::vector<int>& indices) const;
59 
60  // The extraction has duplicate vertices on edges shared by voxels. This
61  // function will eliminate the duplication.
62  void MakeUnique(std::vector<Vector3<Real>>& vertices, std::vector<int>& indices) const;
63 
64  // The extraction does not use any topological information about the level
65  // surface. The triangles can be a mixture of clockwise-ordered and
66  // counterclockwise-ordered. This function is an attempt to give the
67  // triangles a consistent ordering by selecting a normal in approximately
68  // the same direction as the average gradient at the vertices (when
69  // sameDir is true), or in the opposite direction (when sameDir is
70  // false). This might not always produce a consistent order, but is
71  // fast. A consistent order can be computed if you build a table of
72  // vertex, edge, and face adjacencies, but the resulting data structure
73  // is somewhat expensive to process to reorient triangles.
74  void OrientTriangles(std::vector<Vector3<Real>> const& vertices, std::vector<int>& indices,
75  bool sameDir) const;
76 
77  // Compute vertex normals for the mesh.
78  void ComputeNormals(std::vector<Vector3<Real>> const& vertices, std::vector<int> const& indices,
79  std::vector<Vector3<Real>>& normals) const;
80 
81 protected:
82  Vector3<Real> GetGradient(Vector3<Real> position) const;
83 
85 };
86 
87 template <typename Real>
89 {
90 }
91 
92 template <typename Real>
94  :
95  mImage(image)
96 {
97 }
98 
99 template <typename Real>
101 {
102  std::array<Real, 3> zero = { (Real)0, (Real)0, (Real)0 };
103  std::fill(vertices.begin(), vertices.end(), zero);
104 }
105 
106 template <typename Real>
107 bool SurfaceExtractor<Real>::Extract(std::array<Real, 8> const& F, Mesh& mesh) const
108 {
109  int entry = 0;
110  for (int i = 0, mask = 1; i < 8; ++i, mask <<= 1)
111  {
112  if (F[i] < (Real)0)
113  {
114  entry |= mask;
115  }
116  else if (F[i] == (Real)0)
117  {
118  return false;
119  }
120  }
121 
122  mesh.topology = GetTable(entry);
123 
124  for (int i = 0; i < mesh.topology.numVertices; ++i)
125  {
126  int j0 = mesh.topology.vpair[i][0];
127  int j1 = mesh.topology.vpair[i][1];
128 
129  Real corner0[3];
130  corner0[0] = static_cast<Real>(j0 & 1);
131  corner0[1] = static_cast<Real>((j0 & 2) >> 1);
132  corner0[2] = static_cast<Real>((j0 & 4) >> 2);
133 
134  Real corner1[3];
135  corner1[0] = static_cast<Real>(j1 & 1);
136  corner1[1] = static_cast<Real>((j1 & 2) >> 1);
137  corner1[2] = static_cast<Real>((j1 & 4) >> 2);
138 
139  Real invDenom = ((Real)1) / (F[j0] - F[j1]);
140  for (int k = 0; k < 3; ++k)
141  {
142  Real numer = F[j0] * corner1[k] - F[j1] * corner0[k];
143  mesh.vertices[i][k] = numer*invDenom;
144  }
145  }
146  return true;
147 }
148 
149 template <typename Real>
150 bool SurfaceExtractor<Real>::Extract(Real level, std::vector<Vector3<Real>>& vertices, std::vector<int>& indices) const
151 {
152  vertices.clear();
153  indices.clear();
154 
155  for (int z = 0; z + 1 < mImage.GetDimension(2); ++z)
156  {
157  for (int y = 0; y + 1 < mImage.GetDimension(1); ++y)
158  {
159  for (int x = 0; x + 1 < mImage.GetDimension(0); ++x)
160  {
161  std::array<size_t, 8> corners;
162  mImage.GetCorners(x, y, z, corners);
163 
164  std::array<Real, 8> F;
165  for (int k = 0; k < 8; ++k)
166  {
167  F[k] = mImage[corners[k]] - level;
168  }
169 
170  Mesh mesh;
171 
172  if (Extract(F, mesh))
173  {
174  int vbase = static_cast<int>(vertices.size());
175  for (int i = 0; i < mesh.topology.numVertices; ++i)
176  {
177  Vector3<float> position = mesh.vertices[i];
178  position[0] += static_cast<Real>(x);
179  position[1] += static_cast<Real>(y);
180  position[2] += static_cast<Real>(z);
181  vertices.push_back(position);
182  }
183 
184  for (int i = 0; i < mesh.topology.numTriangles; ++i)
185  {
186  for (int j = 0; j < 3; ++j)
187  {
188  indices.push_back(vbase + mesh.topology.itriple[i][j]);
189  }
190  }
191  }
192  else
193  {
194  vertices.clear();
195  indices.clear();
196  return false;
197  }
198  }
199  }
200  }
201 
202  return true;
203 }
204 
205 template <typename Real>
206 void SurfaceExtractor<Real>::MakeUnique(std::vector<Vector3<Real>>& vertices, std::vector<int>& indices) const
207 {
208  std::vector<Vector3<Real>> outVertices;
209  std::vector<int> outIndices;
210  UniqueVerticesTriangles<Vector3<Real>>(vertices, indices, outVertices, outIndices);
211  vertices = std::move(outVertices);
212  indices = std::move(outIndices);
213 }
214 
215 template <typename Real>
216 void SurfaceExtractor<Real>::OrientTriangles(std::vector<Vector3<Real>> const& vertices, std::vector<int>& indices,
217  bool sameDir) const
218 {
219  int const numTriangles = static_cast<int>(indices.size() / 3);
220  int* triangle = indices.data();
221  for (int t = 0; t < numTriangles; ++t, triangle += 3)
222  {
223  // Get triangle vertices.
224  Vector3<Real> v0 = vertices[triangle[0]];
225  Vector3<Real> v1 = vertices[triangle[1]];
226  Vector3<Real> v2 = vertices[triangle[2]];
227 
228  // Construct triangle normal based on current orientation.
229  Vector3<Real> edge1 = v1 - v0;
230  Vector3<Real> edge2 = v2 - v0;
231  Vector3<Real> normal = Cross(edge1, edge2);
232 
233  // Get the image gradient at the vertices.
234  Vector3<Real> gradient0 = GetGradient(v0);
235  Vector3<Real> gradient1 = GetGradient(v1);
236  Vector3<Real> gradient2 = GetGradient(v2);
237 
238  // Compute the average gradient.
239  Vector3<Real> gradientAvr = (gradient0 + gradient1 + gradient2) / (Real)3;
240 
241  // Compute the dot product of normal and average gradient.
242  Real dot = Dot(gradientAvr, normal);
243 
244  // Choose triangle orientation based on gradient direction.
245  if (sameDir)
246  {
247  if (dot < (Real)0)
248  {
249  // Wrong orientation, reorder it.
250  std::swap(triangle[1], triangle[2]);
251  }
252  }
253  else
254  {
255  if (dot > (Real)0)
256  {
257  // Wrong orientation, reorder it.
258  std::swap(triangle[1], triangle[2]);
259  }
260  }
261  }
262 }
263 
264 template <typename Real>
265 void SurfaceExtractor<Real>::ComputeNormals(std::vector<Vector3<Real>> const& vertices, std::vector<int> const& indices,
266  std::vector<Vector3<Real>>& normals) const
267 {
268  // Maintain a running sum of triangle normals at each vertex.
269  int const numVertices = static_cast<int>(vertices.size());
270  normals.resize(numVertices);
272  std::fill(normals.begin(), normals.end(), zero);
273 
274  int const numTriangles = static_cast<int>(indices.size() / 3);
275  int const* current = indices.data();
276  for (int i = 0; i < numTriangles; ++i)
277  {
278  int i0 = *current++;
279  int i1 = *current++;
280  int i2 = *current++;
281  Vector3<Real> v0 = vertices[i0];
282  Vector3<Real> v1 = vertices[i1];
283  Vector3<Real> v2 = vertices[i2];
284 
285  // Construct triangle normal.
286  Vector3<Real> edge1 = v1 - v0;
287  Vector3<Real> edge2 = v2 - v0;
288  Vector3<Real> normal = Cross(edge1, edge2);
289 
290  // Maintain the sum of normals at each vertex.
291  normals[i0] += normal;
292  normals[i1] += normal;
293  normals[i2] += normal;
294  }
295 
296  // The normal vector storage was used to accumulate the sum of triangle
297  // normals. Now these vectors must be rescaled to be unit length.
298  for (auto& normal : normals)
299  {
300  Normalize(normal);
301  }
302 }
303 
304 template <typename Real>
306 {
307  int x = static_cast<int>(floor(position[0]));
308  if (x < 0 || x >= mImage.GetDimension(0) - 1)
309  {
310  return Vector3<Real>::Zero();
311  }
312 
313  int y = static_cast<int>(floor(position[1]));
314  if (y < 0 || y >= mImage.GetDimension(1) - 1)
315  {
316  return Vector3<Real>::Zero();
317  }
318 
319  int z = static_cast<int>(floor(position[2]));
320  if (z < 0 || z >= mImage.GetDimension(2) - 1)
321  {
322  return Vector3<Real>::Zero();
323  }
324 
325  position[0] -= static_cast<Real>(x);
326  position[1] -= static_cast<Real>(y);
327  position[2] -= static_cast<Real>(z);
328  Real oneMX = (Real)1 - position[0];
329  Real oneMY = (Real)1 - position[1];
330  Real oneMZ = (Real)1 - position[2];
331 
332  // Get image values at corners of voxel.
333  std::array<size_t, 8> corners;
334  mImage.GetCorners(x, y, z, corners);
335  Real f000 = mImage[corners[0]];
336  Real f100 = mImage[corners[1]];
337  Real f010 = mImage[corners[2]];
338  Real f110 = mImage[corners[3]];
339  Real f001 = mImage[corners[4]];
340  Real f101 = mImage[corners[5]];
341  Real f011 = mImage[corners[6]];
342  Real f111 = mImage[corners[7]];
343 
344  Vector3<Real> gradient;
345 
346  Real tmp0 = oneMY * (f100 - f000) + position[1] * (f110 - f010);
347  Real tmp1 = oneMY * (f101 - f001) + position[1] * (f111 - f011);
348  gradient[0] = oneMZ * tmp0 + position[2] * tmp1;
349 
350  tmp0 = oneMX * (f010 - f000) + position[0] * (f110 - f100);
351  tmp1 = oneMX * (f011 - f001) + position[0] * (f111 - f101);
352  gradient[1] = oneMZ * tmp0 + position[2] * tmp1;
353 
354  tmp0 = oneMX * (f001 - f000) + position[0] * (f101 - f100);
355  tmp1 = oneMX * (f011 - f010) + position[0] * (f111 - f110);
356  gradient[2] = oneMY * tmp0 + position[1] * tmp1;
357 
358  return gradient;
359 }
360 
361 }
int const * GetTable() const
int GetDimension(int d) const
Definition: GteImage.h:169
GLenum GLenum GLsizei void * image
Definition: glext.h:2724
GLint level
Definition: glcorearb.h:103
GLfloat GLfloat v1
Definition: glcorearb.h:812
void GetCorners(std::array< int, 8 > &nbr) const
Definition: GteImage3.h:536
GLint GLenum GLint x
Definition: glcorearb.h:404
GLint GLuint mask
Definition: glcorearb.h:119
void MakeUnique(std::vector< Vector3< Real >> &vertices, std::vector< int > &indices) const
Vector3< Real > GetGradient(Vector3< Real > position) const
SurfaceExtractor const & operator=(SurfaceExtractor const &)=delete
GLsizei GLenum const void * indices
Definition: glcorearb.h:401
static Vector Zero()
Definition: GteVector.h:295
DualQuaternion< Real > Dot(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
Real Normalize(GVector< Real > &v, bool robust=false)
Definition: GteGVector.h:454
GLfloat v0
Definition: glcorearb.h:811
GLdouble GLdouble t
Definition: glext.h:239
DualQuaternion< Real > Cross(DualQuaternion< Real > const &d0, DualQuaternion< Real > const &d1)
void OrientTriangles(std::vector< Vector3< Real >> const &vertices, std::vector< int > &indices, bool sameDir) const
GLdouble GLdouble GLdouble z
Definition: glcorearb.h:843
Image3< Real > const & mImage
GLfloat GLfloat GLfloat v2
Definition: glcorearb.h:813
std::array< Vector3< Real >, MAX_VERTICES > vertices
bool Extract(std::array< Real, 8 > const &F, Mesh &mesh) const
GLint y
Definition: glcorearb.h:98
void ComputeNormals(std::vector< Vector3< Real >> const &vertices, std::vector< int > const &indices, std::vector< Vector3< Real >> &normals) const


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01