Visualization Library 2.0.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
MarchingCubes.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 /* The marching cubes tables are from Cory Bloyd. */
33 
35 #include <vlCore/Time.hpp>
37 
38 using namespace vl;
39 
59 //------------------------------------------------------------------------------
61 {
65 
66  // OpenGL ES does not support DrawElementsUInt
67 #if defined(VL_OPENGL)
69 #else
71 #endif
72  mVolumeInfo.setAutomaticDelete(false);
73  mHighQualityNormals = true;
74 }
75 //------------------------------------------------------------------------------
76 // MarchingCubes
77 //------------------------------------------------------------------------------
78 void MarchingCubes::computeEdges(Volume* vol, float threshold)
79 {
80  // mEdges.clear();
81  mEdges.resize(vol->slices().x() * vol->slices().y() * vol->slices().z());
82  mCubes.clear();
83  mCubes.reserve(1024);
84 
86  // note: this funtion can generate double vertices when the 't' is 0.0 or 1.0
87  // this is why Geometry::computeNormals() doesn't work well with MarchingCubes
88  // If we find a way not to generate such vertices quickly we could use always
89  // Geometry::computeNormals() which is much quicker than computing the gradient.
91 
92  const float dx = vol->cellSize().x() * 0.25f;
93  const float dy = vol->cellSize().y() * 0.25f;
94  const float dz = vol->cellSize().z() * 0.25f;
95  float v0, v1, v2, v3, t;
96  int iedge = 0;
97  int w = vol->slices().x() -1;
98  int h = vol->slices().y() -1;
99  int d = vol->slices().z() -1;
100  for(unsigned short z = 0; z < vol->slices().z(); ++z)
101  {
102  for(unsigned short y = 0; y < vol->slices().y(); ++y)
103  {
104  for(unsigned short x = 0; x < vol->slices().x(); ++x, ++iedge)
105  {
106  if (x != w && y != h && z != d)
107  {
108  if (vol->cube(x,y,z).includes(threshold))
109  {
110  if (mCubes.capacity()-mCubes.size() == 0)
111  mCubes.reserve(mCubes.size()*2);
112  mCubes.push_back( usvec3(x,y,z) );
113  }
114  else
115  continue;
116  }
117 
118  if (mVerts.capacity() - mVerts.size() == 0)
119  {
120  mVerts.reserve( mVerts.size() * 2 );
121  mNorms.reserve( mNorms.size() * 2 );
122  }
123 
124  v0 = vol->value( x,y,z );
125  fvec3 v0_coord = vol->coordinate(x, y, z);
126 
127  if (x != w)
128  {
129  v1 = vol->value( x + 1, y, z );
130  if (v1!=v0)
131  {
132  //if (t>=0 && t<=1.0f)
133  if ( (threshold>=v0 && threshold<=v1) || (threshold>=v1 && threshold<=v0) )
134  {
135  t = (threshold-v0)/(v1-v0);
136  VL_CHECK(t>=-0.001f && t<=1.001f)
137  // emit vertex
138  mEdges[iedge].mX = (int)mVerts.size();
139  // compute vertex and normal position
140  mVerts.push_back( v0_coord * (1.0f-t) + vol->coordinate(x + 1, y, z) * t );
141  if (mHighQualityNormals)
142  {
143  fvec3 n;
144  vol->normalHQ(n, mVerts.back(), dx, dy, dz);
145  mNorms.push_back(n);
146  }
147  }
148  }
149  }
150  if (y != h)
151  {
152  v2 = vol->value( x, y + 1, z );
153  if (v2!=v0)
154  {
155  //if (t>=0 && t<=1.0f)
156  if ( (threshold>=v0 && threshold<=v2) || (threshold>=v2 && threshold<=v0) )
157  {
158  t = (threshold-v0)/(v2-v0);
159  VL_CHECK(t>=-0.001f && t<=1.001f)
160  // emit vertex
161  mEdges[iedge].mY = (int)mVerts.size();
162  // compute vertex and normal position
163  mVerts.push_back( v0_coord * (1.0f-t) + vol->coordinate(x, y + 1, z) * t );
164  if (mHighQualityNormals)
165  {
166  fvec3 n;
167  vol->normalHQ(n, mVerts.back(), dx, dy, dz);
168  mNorms.push_back(n);
169  }
170  }
171  }
172  }
173  if (z != d)
174  {
175  v3 = vol->value( x, y, z + 1 );
176  if (v3!=v0)
177  {
178  //if (t>=0 && t<=1.0f)
179  if ( (threshold>=v0 && threshold<=v3) || (threshold>=v3 && threshold<=v0) )
180  {
181  t = (threshold-v0)/(v3-v0);
182  VL_CHECK(t>=-0.001f && t<=1.001f)
183  // emit vertex
184  mEdges[iedge].mZ = (int)mVerts.size();
185  // compute vertex and normal position
186  mVerts.push_back( v0_coord * (1.0f-t) + vol->coordinate(x, y, z + 1) * t );
187  if (mHighQualityNormals)
188  {
189  fvec3 n;
190  vol->normalHQ(n, mVerts.back(), dx, dy, dz);
191  mNorms.push_back(n);
192  }
193  }
194  }
195  }
196  }
197  }
198  }
199 }
200 //------------------------------------------------------------------------------
201 void MarchingCubes::processCube(int x, int y, int z, Volume* vol, float threshold)
202 {
203  int inner_corners = 0;
204 
205  if ( vol->value( x, y, z ) < threshold ) inner_corners += 1;
206  if ( vol->value( x + 1, y, z ) < threshold ) inner_corners += 2;
207  if ( vol->value( x + 1, y + 1, z ) < threshold ) inner_corners += 4;
208  if ( vol->value( x, y + 1, z ) < threshold ) inner_corners += 8;
209  if ( vol->value( x, y, z + 1 ) < threshold ) inner_corners += 16;
210  if ( vol->value( x + 1, y, z + 1 ) < threshold ) inner_corners += 32;
211  if ( vol->value( x + 1, y + 1, z + 1 ) < threshold ) inner_corners += 64;
212  if ( vol->value( x, y + 1, z + 1 ) < threshold ) inner_corners += 128;
213 
214  int cut_edges = mCubeEdgeFlags[inner_corners];
215 
216  if(cut_edges == 0)
217  return;
218 
219  /*
220  int cell0 = x + y * vol->slices().x() + z * vol->slices().x()*vol->slices().y();
221  int cell1 = (x+1) + y * vol->slices().x() + z * vol->slices().x()*vol->slices().y();
222  int cell2 = (x+1) + y * vol->slices().x() + (z+1) * vol->slices().x()*vol->slices().y();
223  int cell3 = x + y * vol->slices().x() + (z+1) * vol->slices().x()*vol->slices().y();
224  int cell4 = (x+1) + (y+1) * vol->slices().x() + z * vol->slices().x()*vol->slices().y();
225  int cell5 = x + (y+1) * vol->slices().x() + z * vol->slices().x()*vol->slices().y();
226  int cell6 = x + (y+1) * vol->slices().x() + (z+1) * vol->slices().x()*vol->slices().y();
227  */
228 
229  int z0 = z * vol->slices().x()*vol->slices().y();
230  int z1 = (z+1) * vol->slices().x()*vol->slices().y();
231  int y0 = y * vol->slices().x();
232  int y1 = (y+1) * vol->slices().x();
233 
234  int cell0 = x + y0 + z0;
235  int cell1 = (x+1) + y0 + z0;
236  int cell2 = (x+1) + y0 + z1;
237  int cell3 = x + y0 + z1;
238  int cell4 = (x+1) + y1 + z0;
239  int cell5 = x + y1 + z0;
240  int cell6 = x + y1 + z1;
241 
242  int edge_ivert[12] =
243  {
244  mEdges[cell0].mX,
245  mEdges[cell1].mY,
246  mEdges[cell5].mX,
247  mEdges[cell0].mY,
248 
249  mEdges[cell3].mX,
250  mEdges[cell2].mY,
251  mEdges[cell6].mX,
252  mEdges[cell3].mY,
253 
254  mEdges[cell0].mZ,
255  mEdges[cell1].mZ,
256  mEdges[cell4].mZ,
257  mEdges[cell5].mZ,
258  };
259 
260  int ivertex;
261  for(int icorner = 0; mTriangleConnectionTable[inner_corners][icorner]>=0; icorner+=3)
262  {
263  if (mIndices.capacity() - mIndices.size() == 0)
264  mIndices.reserve( mIndices.size()*2 );
265 
266  ivertex = mTriangleConnectionTable[inner_corners][icorner+0];
267  int a = edge_ivert[ivertex];
268 
269  ivertex = mTriangleConnectionTable[inner_corners][icorner+1];
270  int b = edge_ivert[ivertex];
271 
272  ivertex = mTriangleConnectionTable[inner_corners][icorner+2];
273  int c = edge_ivert[ivertex];
274 
275  if (a<0 || b<0 || c<0)
276  continue;
277 
278  // skip degenerate tris #1
279  if (a==b||b==c||c==a)
280  continue;
281 
282  #if 0
283  // skip degenerate tris #2
284  fvec3 v0 = mVerts[a];
285  fvec3 v1 = mVerts[b] - v0;
286  fvec3 v2 = mVerts[c] - v1;
287  if (cross(v2,v1).isNull())
288  continue;
289  #endif
290 
291  mIndices.push_back((IndexType)a);
292  mIndices.push_back((IndexType)b);
293  mIndices.push_back((IndexType)c);
294  }
295 }
296 //------------------------------------------------------------------------------
298 {
299  mVertsArray->clear();
300  mNormsArray->clear();
301  mColorArray->clear();
302  mDrawElements->indexBuffer()->clear();
303  mIndices.clear();
304  mVerts.clear();
305  mNorms.clear();
306  mColors.clear();
307  mCubes.clear();
308  mEdges.clear();
309  mVolumeInfo.clear();
310 }
311 //------------------------------------------------------------------------------
312 void MarchingCubes::run(bool generate_colors)
313 {
314  mVerts.clear();
315  mNorms.clear();
316  mIndices.clear();
317  mVerts.reserve(1024);
318  mNorms.reserve(1024);
319  mColors.reserve(1024);
320  mIndices.reserve(1024);
321 
322  /*Time time; time.start();*/
323 
324  for(int ivol=0; ivol<mVolumeInfo.size(); ++ivol)
325  {
326  Volume* vol = mVolumeInfo.at(ivol)->volume();
327  float threshold = mVolumeInfo.at(ivol)->threshold();
328  int start = (int)mVerts.size();
329 
330  if (vol->dataIsDirty())
331  vol->setupInternalData();
332 
333  // note: this function takes the 90% of the time
334  computeEdges(vol, threshold);
335 
336  // note: this loop takes the remaining 10% of the time
338  //for(int z = 0; z < mVolume->slices().z()-1; ++z)
339  // for(int y = 0; y < mVolume->slices().y()-1; ++y)
340  // for(int x = 0; x < mVolume->slices().x()-1; ++x)
341  // if(vol->cube(x,y,z).includes(threshold))
342  // processCube(x, y, z, vol, threshold);
343 
344  for(unsigned int i=0; i<mCubes.size(); ++i)
345  processCube(mCubes[i].x(), mCubes[i].y(), mCubes[i].z(), vol, threshold);
346 
347  int count = (int)mVerts.size() - start;
348  mVolumeInfo.at(ivol)->setVert0(start);
349  mVolumeInfo.at(ivol)->setVertC(count);
350 
351  // fill color array
352  if (generate_colors)
353  {
354  mColors.resize( mVerts.size() );
355  for(int i=start; i<start+count; ++i)
356  mColors[i] = mVolumeInfo.at(ivol)->color();
357  }
358  }
359 
360  mVertsArray->resize(mVerts.size());
361  mVertsArray->setBufferObjectDirty();
362  if (mVerts.size())
363  memcpy(mVertsArray->ptr(), &mVerts[0], sizeof(mVerts[0]) * mVerts.size());
364 
365  mNormsArray->resize(mNorms.size());
366  mNormsArray->setBufferObjectDirty();
367  if (mNorms.size())
368  memcpy(mNormsArray->ptr(), &mNorms[0], sizeof(mNorms[0]) * mNorms.size());
369 
370  if (generate_colors)
371  {
372  mColorArray->resize(mColors.size());
373  mColorArray->setBufferObjectDirty();
374  if (mColors.size())
375  memcpy(mColorArray->ptr(), &mColors[0], sizeof(mColors[0]) * mColors.size());
376  }
377  else
378  mColorArray->clear();
379 
380  mDrawElements->indexBuffer()->resize(mIndices.size());
381  mDrawElements->indexBuffer()->setBufferObjectDirty(true);
382  if (mIndices.size())
383  memcpy(mDrawElements->indexBuffer()->ptr(), &mIndices[0], sizeof(mIndices[0]) * mIndices.size());
384 
385  if (!mHighQualityNormals)
386  {
387  ref<Geometry> geom = new Geometry;
388  geom->setVertexArray(mVertsArray.get());
389  geom->drawCalls().push_back(mDrawElements.get());
390 
391  geom->computeNormals();
392  mNormsArray->resize( geom->normalArray()->size() );
393  mNormsArray->setBufferObjectDirty();
394  memcpy(mNormsArray->ptr(), geom->normalArray()->ptr(), sizeof(mNormsArray->at(0)) * mNormsArray->size());
395  }
396 }
397 //------------------------------------------------------------------------------
398 void MarchingCubes::updateColor(const fvec3& color, int volume_index)
399 {
400  if(volume_index>=mVolumeInfo.size())
401  {
402  Log::error( Say("updateColor() volume index (%n) out of range.\n") << volume_index);
403  return;
404  }
405  int start = mVolumeInfo.at(volume_index)->vert0();
406  int count = mVolumeInfo.at(volume_index)->vertC();
407  if (start+count > (int)mColorArray->size())
408  {
409  Log::error("updateColor() color array not preset.\n");
410  return;
411  }
412  for(int i=start; i<start+count; ++i)
413  {
414  mColorArray->at(i).r() = color.r();
415  mColorArray->at(i).g() = color.g();
416  mColorArray->at(i).b() = color.b();
417  }
418 }
419 //------------------------------------------------------------------------------
420 void MarchingCubes::updateColor(const fvec4& color, int volume_index)
421 {
422  if(volume_index>=mVolumeInfo.size())
423  {
424  Log::error( Say("updateColor() volume index (%n) out of range.\n") << volume_index);
425  return;
426  }
427  int start = mVolumeInfo.at(volume_index)->vert0();
428  int count = mVolumeInfo.at(volume_index)->vertC();
429  if (start+count > (int)mColorArray->size())
430  {
431  Log::error("updateColor() color array not preset.\n");
432  return;
433  }
434  for(int i=start; i<start+count; ++i)
435  mColorArray->at(i) = color;
436 }
437 //------------------------------------------------------------------------------
438 void MarchingCubes::updateAlpha(float alpha, int volume_index)
439 {
440  if(volume_index>=mVolumeInfo.size())
441  {
442  Log::error( Say("updateColor() volume index (%n) out of range.\n") << volume_index);
443  return;
444  }
445  int start = mVolumeInfo.at(volume_index)->vert0();
446  int count = mVolumeInfo.at(volume_index)->vertC();
447  if (start+count > (int)mColorArray->size())
448  {
449  Log::error("updateColor() color array not preset.\n");
450  return;
451  }
452  for(int i=start; i<start+count; ++i)
453  mColorArray->at(i).a() = alpha;
454 }
455 //------------------------------------------------------------------------------
456 // Volume
457 //------------------------------------------------------------------------------
459 {
460  VL_DEBUG_SET_OBJECT_NAME()
461  setup(NULL, false, false, fvec3(0,0,0), fvec3(1.0f,1.0f,1.0f), ivec3(50,50,50));
462 }
463 //------------------------------------------------------------------------------
465 {
466  ref<Volume> vol = new Volume;
467  int w = mSlices.x() / 2;
468  int h = mSlices.y() / 2;
469  int d = mSlices.z() / 2;
470  if (w<1) w = 1;
471  if (h<1) h = 1;
472  if (d<1) d = 1;
473 
474  vol->setup(NULL, false, false, bottomLeft(), topRight(), ivec3(w,h,d));
475 
476  for(int z=0; z<d; ++z)
477  {
478  int z1=z*2;
479  int z2=z*2+1;
480  for(int y=0; y<h; ++y)
481  {
482  int y1=y*2;
483  int y2=y*2+1;
484  for(int x=0; x<w; ++x)
485  {
486  int x1 = x*2;
487  int x2 = x*2+1;
488  float v0 = value(x1,y1,z1);
489  float v1 = value(x1,y1,z2);
490  float v2 = value(x1,y2,z1);
491  float v3 = value(x1,y2,z2);
492  float v4 = value(x2,y1,z1);
493  float v5 = value(x2,y1,z2);
494  float v6 = value(x2,y2,z1);
495  float v7 = value(x2,y2,z2);
496  vol->value(x,y,z) = (v0+v1+v2+v3+v4+v5+v6+v7) * (1.0f/8.0f);
497  }
498  }
499  }
500 
501  return vol;
502 }
503 //------------------------------------------------------------------------------
505 {
506  mDataIsDirty = false;
507  int w = slices().x() -1;
508  int h = slices().y() -1;
509  int d = slices().z() -1;
510  mCubes.resize(w*h*d);
511  for(int z = 0; z < d; ++z)
512  {
513  for(int y = 0; y < h; ++y)
514  {
515  for(int x = 0; x < w; ++x)
516  {
517  float v[] =
518  {
519  value(x+0,y+0,z+0),
520  value(x+0,y+0,z+1),
521  value(x+0,y+1,z+0),
522  value(x+0,y+1,z+1),
523  value(x+1,y+0,z+0),
524  value(x+1,y+0,z+1),
525  value(x+1,y+1,z+0),
526  value(x+1,y+1,z+1)
527  };
528  int icube = x+w*y+w*h*z;
529  mCubes[icube].mMin = v[0];
530  mCubes[icube].mMax = v[0];
531  for(int i=1; i<8; ++i)
532  {
533  if (mCubes[icube].mMin > v[i]) mCubes[icube].mMin = v[i];
534  if (mCubes[icube].mMax < v[i]) mCubes[icube].mMax = v[i];
535  }
536  }
537  }
538  }
539 }
540 //------------------------------------------------------------------------------
541 void Volume::setup( float* data, bool use_directly, bool copy_data, const fvec3& bottom_left, const fvec3& top_right, const ivec3& slices )
542 {
543  fvec3 size = top_right-bottom_left;
544 
545  if (use_directly)
546  {
547  VL_CHECK(data);
548  // discard internal data.
549  std::vector<float>().swap( mInternalValues );
550  mValues = data;
551  }
552  else
553  {
554  // allocate internal data & copy
555  mInternalValues.resize( slices.x() * slices.y() * slices.z() );
556  mValues = &mInternalValues[0];
557  if (copy_data)
558  memcpy( mValues, data, slices.x() * slices.y() * slices.z() * sizeof(float) );
559  }
560 
561  mBottomLeft = bottom_left;
562  mTopRight = top_right;
563  mSize = topRight()-bottomLeft();
564  mSlices = slices;
565  mCellSize.x() = size.x() / (slices.x()-1);
566  mCellSize.y() = size.y() / (slices.y()-1);
567  mCellSize.z() = size.z() / (slices.z()-1);
568 
569  mMinimum = +1;
570  mMaximum = -1;
571  mAverage = 0;
572  mDataIsDirty = true;
573 }
574 //------------------------------------------------------------------------------
575 void Volume::setup(const Volume& volume)
576 {
577  *this = volume;
578  mMinimum = +1;
579  mMaximum = -1;
580  mAverage = 0;
581  mDataIsDirty = true;
582 }
583 //------------------------------------------------------------------------------
584 float Volume::sampleNearest(float x, float y, float z) const
585 {
586  x = (x - mBottomLeft.x()) / mSize.x();
587  y = (y - mBottomLeft.y()) / mSize.y();
588  z = (z - mBottomLeft.z()) / mSize.z();
589  if (x<0 || y<0 || z<0) return 0;
590  if (x>1.0001 || y>1.0001 || z>1.0001) return 0;
591  if (x > 0.9999f) x = 0.9999f;
592  if (y > 0.9999f) y = 0.9999f;
593  if (z > 0.9999f) z = 0.9999f;
594  float xt = x * (mSlices.x()-1);
595  float yt = y * (mSlices.y()-1);
596  float zt = z * (mSlices.z()-1);
597  int ix = int(xt);
598  int iy = int(yt);
599  int iz = int(zt);
600  return value(ix , iy, iz);
601 }
602 //------------------------------------------------------------------------------
603 float Volume::sampleSmooth(float x, float y, float z) const
604 {
605  x = (x - mBottomLeft.x()) / mSize.x();
606  y = (y - mBottomLeft.y()) / mSize.y();
607  z = (z - mBottomLeft.z()) / mSize.z();
608  if (x<0 || y<0 || z<0) return 0;
609  if (x>1.0f || y>1.0f || z>1.0f) return 0;
610  if (x > 0.9999f) x = 0.9999f;
611  if (y > 0.9999f) y = 0.9999f;
612  if (z > 0.9999f) z = 0.9999f;
613  float xt = x * (mSlices.x()-1);
614  float yt = y * (mSlices.y()-1);
615  float zt = z * (mSlices.z()-1);
616  int ix = int(xt); xt -= ix;
617  int iy = int(yt); yt -= iy;
618  int iz = int(zt); zt -= iz;
619  float val0 = value(ix , iy, iz);
620  float val1 = value(ix+1, iy, iz);
621  float val2 = value(ix+1, iy+1, iz);
622  float val3 = value(ix, iy+1, iz);
623  float val4 = value(ix , iy, iz+1);
624  float val5 = value(ix+1, iy, iz+1);
625  float val6 = value(ix+1, iy+1, iz+1);
626  float val7 = value(ix, iy+1, iz+1);
627  float xt1 = 1-xt;
628  float yt1 = 1-yt;
629  float zt1 = 1-zt;
630  float v1 = val0*(yt1) + val3*yt;
631  float v2 = val1*(yt1) + val2*yt;
632  float a = v1*(xt1) + v2*xt;
633  v1 = val4*(yt1) + val7*yt;
634  v2 = val5*(yt1) + val6*yt;
635  float b = v1*(xt1) + v2*xt;
636  return a*(zt1) + b*zt;
637 }
638 //------------------------------------------------------------------------------
639 void Volume::normalHQ(fvec3 &normal, const fvec3& v, float dx, float dy, float dz)
640 {
642  // note: this is the performance killer, it would be nice to optimize it...
644  normal.x() = sampleSmooth(v.x()-dx, v.y(), v.z()) - sampleSmooth(v.x()+dx, v.y(), v.z());
645  normal.y() = sampleSmooth(v.x(), v.y()-dy, v.z()) - sampleSmooth(v.x(), v.y()+dy, v.z());
646  normal.z() = sampleSmooth(v.x(), v.y(), v.z()-dz) - sampleSmooth(v.x(), v.y(), v.z()+dz);
647  normal.normalize();
648 }
649 //------------------------------------------------------------------------------
650 void Volume::normalLQ(fvec3 &normal, const fvec3& v, float dx, float dy, float dz)
651 {
652  // this function could be optimized even more by sampling the 8 points only once,
653  // and computing the x and y gradient form the same slice... but since we don't use it...
654  float v0 = sampleSmooth(v.x(), v.y(), v.z());
655  normal.x() = v0 - sampleSmooth(v.x()+dx, v.y(), v.z());
656  normal.y() = v0 - sampleSmooth(v.x(), v.y()+dy, v.z());
657  normal.z() = v0 - sampleSmooth(v.x(), v.y(), v.z()+dz);
658  normal.normalize();
659 }
660 //------------------------------------------------------------------------------
662 {
663  if (!mValues)
664  return 0;
665  float lowest = mValues[0];
666  int val_count = mSlices.x() * mSlices.y() * mSlices.z();
667  for(int i=1; i<val_count; ++i)
668  if (mValues[i] < lowest)
669  lowest = mValues[i];
670  return lowest;
671 }
672 //------------------------------------------------------------------------------
674 {
675  if (!mValues)
676  return 0;
677  float highest = mValues[0];
678  int val_count = mSlices.x() * mSlices.y() * mSlices.z();
679  for(int i=1; i<val_count; ++i)
680  if (mValues[i] > highest)
681  highest = mValues[i];
682  return highest;
683 }
684 //------------------------------------------------------------------------------
686 {
687  if (!mValues)
688  return 0;
689  double average = 0;
690  int val_count = mSlices.x() * mSlices.y() * mSlices.z();
691  for(int i=0; i<val_count; ++i)
692  average += mValues[i];
693  average /= (double)val_count;
694  return (float)average;
695 }
696 //------------------------------------------------------------------------------
697 const int MarchingCubes::mCubeEdgeFlags[256]=
698 {
699  0x000, 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c, 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
700  0x190, 0x099, 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c, 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
701  0x230, 0x339, 0x033, 0x13a, 0x636, 0x73f, 0x435, 0x53c, 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
702  0x3a0, 0x2a9, 0x1a3, 0x0aa, 0x7a6, 0x6af, 0x5a5, 0x4ac, 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
703  0x460, 0x569, 0x663, 0x76a, 0x066, 0x16f, 0x265, 0x36c, 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
704  0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0x0ff, 0x3f5, 0x2fc, 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
705  0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x055, 0x15c, 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
706  0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0x0cc, 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
707  0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc, 0x0cc, 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
708  0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c, 0x15c, 0x055, 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
709  0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc, 0x2fc, 0x3f5, 0x0ff, 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
710  0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c, 0x36c, 0x265, 0x16f, 0x066, 0x76a, 0x663, 0x569, 0x460,
711  0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac, 0x4ac, 0x5a5, 0x6af, 0x7a6, 0x0aa, 0x1a3, 0x2a9, 0x3a0,
712  0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c, 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x033, 0x339, 0x230,
713  0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c, 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x099, 0x190,
714  0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c, 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x000
715 };
716 //------------------------------------------------------------------------------
717 const int MarchingCubes::mTriangleConnectionTable[256][16] =
718 {
719  {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
720  {0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
721  {0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
722  {1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
723  {1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
724  {0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
725  {9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
726  {2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1},
727  {3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
728  {0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
729  {1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
730  {1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1},
731  {3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
732  {0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1},
733  {3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1},
734  {9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
735  {4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
736  {4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
737  {0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
738  {4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1},
739  {1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
740  {3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1},
741  {9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
742  {2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1},
743  {8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
744  {11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1},
745  {9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
746  {4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1},
747  {3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1},
748  {1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1},
749  {4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1},
750  {4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1},
751  {9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
752  {9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
753  {0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
754  {8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1},
755  {1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
756  {3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
757  {5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1},
758  {2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1},
759  {9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
760  {0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1},
761  {0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1},
762  {2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1},
763  {10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1},
764  {4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1},
765  {5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1},
766  {5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1},
767  {9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
768  {9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1},
769  {0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1},
770  {1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
771  {9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1},
772  {10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1},
773  {8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1},
774  {2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1},
775  {7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1},
776  {9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1},
777  {2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1},
778  {11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1},
779  {9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1},
780  {5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1},
781  {11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1},
782  {11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
783  {10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
784  {0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
785  {9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
786  {1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
787  {1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
788  {1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1},
789  {9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1},
790  {5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1},
791  {2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
792  {11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
793  {0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1},
794  {5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1},
795  {6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1},
796  {0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1},
797  {3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1},
798  {6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1},
799  {5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
800  {4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1},
801  {1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1},
802  {10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1},
803  {6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1},
804  {1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1},
805  {8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1},
806  {7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1},
807  {3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1},
808  {5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1},
809  {0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1},
810  {9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1},
811  {8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1},
812  {5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1},
813  {0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1},
814  {6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1},
815  {10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
816  {4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1},
817  {10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1},
818  {8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1},
819  {1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1},
820  {3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1},
821  {0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
822  {8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1},
823  {10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1},
824  {0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1},
825  {3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1},
826  {6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1},
827  {9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1},
828  {8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1},
829  {3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1},
830  {6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
831  {7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1},
832  {0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1},
833  {10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1},
834  {10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1},
835  {1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1},
836  {2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1},
837  {7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1},
838  {7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
839  {2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1},
840  {2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1},
841  {1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1},
842  {11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1},
843  {8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1},
844  {0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
845  {7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1},
846  {7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
847  {7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
848  {3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
849  {0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
850  {8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
851  {10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
852  {1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
853  {2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1},
854  {6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1},
855  {7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
856  {7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1},
857  {2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1},
858  {1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1},
859  {10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1},
860  {10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1},
861  {0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1},
862  {7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1},
863  {6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
864  {3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1},
865  {8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1},
866  {9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1},
867  {6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1},
868  {1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1},
869  {4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1},
870  {10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1},
871  {8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1},
872  {0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
873  {1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1},
874  {1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1},
875  {8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1},
876  {10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1},
877  {4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1},
878  {10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
879  {4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
880  {0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1},
881  {5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
882  {11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1},
883  {9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1},
884  {6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1},
885  {7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1},
886  {3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1},
887  {7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1},
888  {9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1},
889  {3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1},
890  {6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1},
891  {9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1},
892  {1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1},
893  {4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1},
894  {7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1},
895  {6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1},
896  {3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1},
897  {0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1},
898  {6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1},
899  {1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1},
900  {0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1},
901  {11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1},
902  {6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1},
903  {5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1},
904  {9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1},
905  {1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1},
906  {1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
907  {1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1},
908  {10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1},
909  {0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
910  {10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
911  {11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
912  {11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1},
913  {5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1},
914  {10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1},
915  {11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1},
916  {0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1},
917  {9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1},
918  {7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1},
919  {2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1},
920  {8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1},
921  {9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1},
922  {9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1},
923  {1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
924  {0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1},
925  {9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1},
926  {9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
927  {5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1},
928  {5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1},
929  {0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1},
930  {10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1},
931  {2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1},
932  {0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1},
933  {0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1},
934  {9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
935  {2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1},
936  {5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1},
937  {3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1},
938  {5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1},
939  {8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1},
940  {0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
941  {8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1},
942  {9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
943  {4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1},
944  {0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1},
945  {1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1},
946  {3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1},
947  {4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1},
948  {9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1},
949  {11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1},
950  {11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1},
951  {2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1},
952  {9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1},
953  {3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1},
954  {1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
955  {4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1},
956  {4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1},
957  {4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
958  {4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
959  {9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
960  {3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1},
961  {0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1},
962  {3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
963  {1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1},
964  {3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1},
965  {0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
966  {3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
967  {2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1},
968  {9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
969  {2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1},
970  {1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
971  {1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
972  {0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
973  {0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
974  {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}
975 };
976 //------------------------------------------------------------------------------
See DrawElements.
Defines the volume data to be used with a MarchingCube object.
const Vector3 & normalize(T_Scalar *len=NULL)
Definition: Vector3.hpp:227
static const int mCubeEdgeFlags[256]
void updateAlpha(float alpha, int volume_index)
An array of vl::fvec4.
Definition: Array.hpp:416
ref< DrawElementsUShort > mDrawElements
Vector3< float > fvec3
A 3 components vector with float precision.
Definition: Vector3.hpp:252
fvec3 coordinate(int x, int y, int z) const
const T_Scalar & b() const
Definition: Vector3.hpp:99
const Volume::Cube & cube(int x, int y, int z) const
void setup(float *data, bool use_directly, bool copy_data, const fvec3 &bottom_left, const fvec3 &top_right, const ivec3 &slices)
Setup the volume data with the specified memory management.
A simple String formatting class.
Definition: Say.hpp:124
const T_Scalar & z() const
Definition: Vector3.hpp:91
void run(bool generate_colors)
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
void setVertexArray(ArrayAbstract *data)
Conventional vertex array.
Definition: Geometry.cpp:155
ref< ArrayFloat4 > mColorArray
void updateColor(const fvec3 &color, int volume_index)
fvec3 cross(const fvec3 &v1, const fvec3 &v2)
Definition: Vector3.hpp:277
const float & value(int i) const
bool dataIsDirty() const
Returns true if the internal data hasn&#39;t been updated since the last call to setDataDirty() or setup(...
const T_Scalar & r() const
Definition: Vector3.hpp:97
The Geometry class is a Renderable that implements a polygonal mesh made of polygons, lines and points.
Definition: Geometry.hpp:66
float sampleNearest(float x, float y, float z) const
Samples the volume using nearest point sampling.
Visualization Library main namespace.
ref< ArrayFloat3 > mVertsArray
void setupInternalData()
const unsigned char * ptr() const
Returns the pointer to the first element of the local buffer. Equivalent to bufferObject()->ptr() ...
Definition: Array.hpp:103
void processCube(int x, int y, int z, Volume *vol, float threshold)
void normalHQ(fvec3 &normal, const fvec3 &v, float dx, float dy, float dz)
Computes a high quality normal (best rendering quality)
const ivec3 & slices() const
ref< ArrayFloat3 > mNormsArray
See DrawElements.
float computeMinimum() const
static const int mTriangleConnectionTable[256][16]
const T_Scalar & y() const
Definition: Vector3.hpp:90
void computeNormals(bool verbose=false)
Computes the normals in a "smooth" way, i.e.
Definition: Geometry.cpp:269
#define NULL
Definition: OpenGLDefs.hpp:81
Vector3< int > ivec3
A 3 components vector with int precision.
Definition: Vector3.hpp:248
const fvec3 & cellSize() const
Returns the x/y/z size of a cell.
ref< Volume > downsample() const
Returns a new volume which is half of the size of the original volume in each direction (thus require...
void normalLQ(fvec3 &normal, const fvec3 &v, float dx, float dy, float dz)
Computes a low quality normal (best performances)
virtual size_t size() const =0
Returns the number of elements of an array.
const T_Scalar & x() const
Definition: Vector3.hpp:89
The ref<> class is used to reference-count an Object.
Definition: Object.hpp:55
bool isNull() const
Definition: Vector3.hpp:226
An array of vl::fvec3.
Definition: Array.hpp:414
Vector3< unsigned short > usvec3
A 3 components vector with unsigned short precision.
Definition: Vector3.hpp:262
float computeMaximum() const
const T_Scalar & g() const
Definition: Vector3.hpp:98
#define VL_CHECK(expr)
Definition: checks.hpp:73
const ArrayAbstract * normalArray() const
Conventional normal array.
Definition: Geometry.hpp:254
float sampleSmooth(float x, float y, float z) const
Samples the volume using tri-linear interpolation sampling.
void computeEdges(Volume *, float threshold)
Collection< DrawCall > & drawCalls()
Returns the list of DrawCall objects bound to a Geometry.
Definition: Geometry.hpp:102
float computeAverage() const