vcglib/vcg/complex/algorithms/create/marching_cubes.h

718 lines
39 KiB
C++

/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004-2016 \/)\/ *
* Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | *
* \ *
* All rights reserved. *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. *
* *
****************************************************************************/
/***************************************************************************/
#ifndef __VCG_MARCHING_CUBES
#define __VCG_MARCHING_CUBES
#include "mc_lookup_table.h"
namespace vcg
{
namespace tri
{
// Doxygen documentation
/** \addtogroup trimesh */
/*@{*/
/*
* Cube description:
* 3 ________ 2 _____2__
* /| /| / | /|
* / | / | 11/ 3 10/ |
* 7 /_______ / | /__6_|__ / |1
* | | |6 | | | | |
* | 0|__|_____|1 | |__|__0__|
* | / | / 7 8/ 5 /
* | / | / | / | /9
* |/_______|/ |/___4___|/
* 4 5
*/
//! This class implements the Marching Cubes algorithm.
/*!
* The implementation is enough generic: this class works only on one volume cell for each
* call to <CODE>ProcessCell</CODE>. Using the field value at the cell corners, it adds to the
* mesh the triangles set approximating the surface that cross that cell. The ambiguities
* are resolved using an enhanced topologically controlled lookup table.
* @param TRIMESH_TYPE (Template parameter) the mesh type that will be constructed
* @param WALKER_TYPE (Template parameter) the class that implement the traversal ordering of the volume
**/
template<class TRIMESH_TYPE, class WALKER_TYPE>
class MarchingCubes
{
public:
enum Dimension {X, Y, Z};
typedef typename vcg::tri::Allocator< TRIMESH_TYPE > AllocatorType;
typedef typename TRIMESH_TYPE::ScalarType ScalarType;
typedef typename TRIMESH_TYPE::VertexType VertexType;
typedef typename TRIMESH_TYPE::VertexPointer VertexPointer;
typedef typename TRIMESH_TYPE::VertexIterator VertexIterator;
typedef typename TRIMESH_TYPE::FaceType FaceType;
typedef typename TRIMESH_TYPE::FacePointer FacePointer;
typedef typename TRIMESH_TYPE::FaceIterator FaceIterator;
typedef typename TRIMESH_TYPE::CoordType CoordType;
typedef typename TRIMESH_TYPE::CoordType* CoordPointer;
/*!
* Constructor
* \param mesh the mesh that will be constructed
* \param walker the class implementing the traversal policy
*/
MarchingCubes(TRIMESH_TYPE &mesh, WALKER_TYPE &walker)
{
_mesh = &mesh;
_walker = &walker;
};
/*!
* Execute the initialiazation.
* This method must be executed before the first call to <CODE>ApplyMC</CODE>
*/
void Initialize()
{
_mesh->Clear();
}; // end of Initialize()
/*!
*
* This method must be executed after the last call to <CODE>ApplyMC</CODE>
*/
void Finalize()
{
_mesh = NULL;
_walker = NULL;
}; // end of Finalize()
/*!
* Apply the <I>marching cubes</I> algorithm to the volume cell identified by the two points <CODE>min</CODE> and <CODE>max</CODE>.
* All the three coordinates of the first point must be smaller than the respectives three coordinatas of the second point.
* \param min the first point
* \param max the second point
*/
void ProcessCell(const vcg::Point3i &min, const vcg::Point3i &max)
{
_case = _subconfig = _config = -1;
assert(min[0]<max[0] && min[1]<max[1] && min[2]<max[2]);
_corners[0].X()=min.X(); _corners[0].Y()=min.Y(); _corners[0].Z()=min.Z();
_corners[1].X()=max.X(); _corners[1].Y()=min.Y(); _corners[1].Z()=min.Z();
_corners[2].X()=max.X(); _corners[2].Y()=max.Y(); _corners[2].Z()=min.Z();
_corners[3].X()=min.X(); _corners[3].Y()=max.Y(); _corners[3].Z()=min.Z();
_corners[4].X()=min.X(); _corners[4].Y()=min.Y(); _corners[4].Z()=max.Z();
_corners[5].X()=max.X(); _corners[5].Y()=min.Y(); _corners[5].Z()=max.Z();
_corners[6].X()=max.X(); _corners[6].Y()=max.Y(); _corners[6].Z()=max.Z();
_corners[7].X()=min.X(); _corners[7].Y()=max.Y(); _corners[7].Z()=max.Z();
for (int i=0; i<8; i++)
_field[i] = _walker->V( _corners[i].X(), _corners[i].Y(), _corners[i].Z() );
unsigned char cubetype = 0;
for (int i=0; i<8; i++)
if (_field[i]>0) cubetype += 1<<i;
_case = MCLookUpTable::Cases(cubetype, 0); //_case = cases[cubetype][0];
_config = MCLookUpTable::Cases(cubetype, 1); //_config = cases[cubetype][1];
_subconfig = 0;
VertexPointer v12 = NULL;
switch( _case )
{
case 0 : { break ; }
case 1 : { AddTriangles( MCLookUpTable::Tiling1(_config), 1 ); break; } //case 1 : { AddTriangles( tiling1[_config], 1 ); break; }
case 2 : { AddTriangles( MCLookUpTable::Tiling2(_config), 2 ); break; } //case 2 : { AddTriangles( tiling2[_config], 2 ); break; }
case 3 :
{
//if( TestFace( test3[_config]) ) AddTriangles( tiling3_2[_config], 4 ) ; // 3.2
if( TestFace( MCLookUpTable::Test3(_config)) )
AddTriangles( MCLookUpTable::Tiling3_2(_config), 4 ) ; // 3.2
else
AddTriangles( MCLookUpTable::Tiling3_1(_config), 2 ) ; // 3.1
break ;
}
case 4 :
{
//if( TestInterior( test4[_config]) ) AddTriangles( tiling4_1[_config], 2 ) ; // 4.1.1
if( TestInterior( MCLookUpTable::Test4(_config) ) )
AddTriangles( MCLookUpTable::Tiling4_1(_config), 2 ) ; // 4.1.1
else
AddTriangles( MCLookUpTable::Tiling4_2(_config), 6 ) ; // 4.1.2
break ;
}
case 5 : { AddTriangles( MCLookUpTable::Tiling5(_config), 3 ); break; }
case 6 :
{
//if( TestFace( test6[_config][0]) )
if( TestFace( MCLookUpTable::Test6(_config, 0)) )
AddTriangles( MCLookUpTable::Tiling6_2(_config), 5 ) ; // 6.2
else
{
if( TestInterior( MCLookUpTable::Test6(_config, 1)) )
AddTriangles( MCLookUpTable::Tiling6_1_1(_config), 3 ) ; // 6.1.1
else
AddTriangles( MCLookUpTable::Tiling6_1_2(_config), 7 ) ; // 6.1.2
}
break ;
}
case 7 :
{
//if( TestFace( test7[_config][0] ) ) _subconfig += 1 ;
//if( TestFace( test7[_config][1] ) ) _subconfig += 2 ;
//if( TestFace( test7[_config][2] ) ) _subconfig += 4 ;
if( TestFace( MCLookUpTable::Test7(_config, 0) ) ) _subconfig += 1 ;
if( TestFace( MCLookUpTable::Test7(_config, 1) ) ) _subconfig += 2 ;
if( TestFace( MCLookUpTable::Test7(_config, 2) ) ) _subconfig += 4 ;
switch( _subconfig )
{
case 0 : { AddTriangles( MCLookUpTable::Tiling7_1(_config), 3 ) ; break; }
case 1 : { AddTriangles( MCLookUpTable::Tiling7_2(_config,0), 5 ) ; break; }
case 2 : { AddTriangles( MCLookUpTable::Tiling7_2(_config,1), 5 ) ; break; }
case 3 : { ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling7_3(_config,0), 9, v12 ) ; break ; }
case 4 : { AddTriangles( MCLookUpTable::Tiling7_2(_config, 2), 5 ) ; break ;}
case 5 : { ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling7_3(_config,1), 9, v12 ) ; break ; }
case 6 : { ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling7_3(_config,2), 9, v12 ) ; break ; }
case 7 :
{
if( TestInterior( MCLookUpTable::Test7(_config, 3) ) )
AddTriangles( MCLookUpTable::Tiling7_4_2(_config), 9 ) ;
else
AddTriangles( MCLookUpTable::Tiling7_4_1(_config), 5 ) ;
break ;
}
};
break ;
} // end of case 7
case 8 : { AddTriangles( MCLookUpTable::Tiling8(_config), 2 ) ; break ;}
case 9 : { AddTriangles( MCLookUpTable::Tiling9(_config), 4 ) ; break ;}
case 10 :
{
if( TestFace( MCLookUpTable::Test10(_config, 0)) ) //if( TestFace( test10[_config][0]) )
{
if( TestFace( MCLookUpTable::Test10(_config,1) ) )
AddTriangles( MCLookUpTable::Tiling10_1_1_(_config), 4 ) ; // 10.1.1
else
{
ComputeCVertex(v12);
AddTriangles( MCLookUpTable::Tiling10_2(_config), 8, v12 ) ; // 10.2
}
}
else
{
if( TestFace( MCLookUpTable::Test10(_config, 1) ) )
{
ComputeCVertex(v12) ;
AddTriangles( MCLookUpTable::Tiling10_2_(_config), 8, v12 ) ; // 10.2
}
else
{
if( TestInterior( MCLookUpTable::Test10(_config, 2) ) )
AddTriangles( MCLookUpTable::Tiling10_1_1(_config), 4 ) ; // 10.1.1
else
AddTriangles( MCLookUpTable::Tiling10_1_2(_config), 8 ) ; // 10.1.2
}
}
break ;
} // end of case 10
case 11 : { AddTriangles( MCLookUpTable::Tiling11(_config), 4 ) ; break ; }
case 12 :
{
if( TestFace( MCLookUpTable::Test12(_config, 0) ) ) //if( TestFace( test12[_config][0]) )
{
if( TestFace( MCLookUpTable::Test12(_config, 1) ) )
AddTriangles( MCLookUpTable::Tiling12_1_1_(_config), 4 ) ; // 12.1.1
else
{
ComputeCVertex(v12) ;
AddTriangles( MCLookUpTable::Tiling12_2(_config), 8, v12 ) ; // 12.2
}
}
else
{
if( TestFace( MCLookUpTable::Test12(_config, 1) ) )
{
ComputeCVertex(v12) ;
AddTriangles( MCLookUpTable::Tiling12_2_(_config), 8, v12 ) ; // 12.2
}
else
{
if( TestInterior( MCLookUpTable::Test12(_config, 2) ) )
AddTriangles( MCLookUpTable::Tiling12_1_1(_config), 4 ) ; // 12.1.1
else
AddTriangles( MCLookUpTable::Tiling12_1_2(_config), 8 ) ; // 12.1.2
}
}
break ;
} // end of case 12
case 13 :
{
//if( TestFace( test13[_config][0] ) ) _subconfig += 1 ;
//if( TestFace( test13[_config][1] ) ) _subconfig += 2 ;
//if( TestFace( test13[_config][2] ) ) _subconfig += 4 ;
//if( TestFace( test13[_config][3] ) ) _subconfig += 8 ;
//if( TestFace( test13[_config][4] ) ) _subconfig += 16 ;
//if( TestFace( test13[_config][5] ) ) _subconfig += 32 ;
if( TestFace( MCLookUpTable::Test13(_config, 0) ) ) _subconfig += 1 ;
if( TestFace( MCLookUpTable::Test13(_config, 1) ) ) _subconfig += 2 ;
if( TestFace( MCLookUpTable::Test13(_config, 2) ) ) _subconfig += 4 ;
if( TestFace( MCLookUpTable::Test13(_config, 3) ) ) _subconfig += 8 ;
if( TestFace( MCLookUpTable::Test13(_config, 4) ) ) _subconfig += 16 ;
if( TestFace( MCLookUpTable::Test13(_config, 5) ) ) _subconfig += 32 ;
switch( MCLookUpTable::Subconfig13(_subconfig) ) //switch( subconfig13[_subconfig] )
{
case 0 : { /* 13.1 */ AddTriangles( MCLookUpTable::Tiling13_1(_config) , 4 ) ; break ; }
case 1 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2(_config, 0), 6 ) ; break ; }
case 2 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2(_config, 1), 6 ) ; break ; }
case 3 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2(_config, 2), 6 ) ; break ; }
case 4 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2(_config, 3), 6 ) ; break ; }
case 5 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2(_config, 4), 6 ) ; break ; }
case 6 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2(_config, 5), 6 ) ; break ; }
case 7 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 0), 10, v12 ) ; break ; }
case 8 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 1), 10, v12 ) ; break ; }
case 9 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 2), 10, v12 ) ; break ; }
case 10 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 3), 10, v12 ) ; break ; }
case 11 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 4), 10, v12 ) ; break ; }
case 12 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 5), 10, v12 ) ; break ; }
case 13 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 6), 10, v12 ) ; break ; }
case 14 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 7), 10, v12 ) ; break ; }
case 15 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 8), 10, v12 ) ; break ; }
case 16 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config, 9), 10, v12 ) ; break ; }
case 17 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config,10), 10, v12 ) ; break ; }
case 18 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3(_config,11), 10, v12 ) ; break ; }
case 19 : { /* 13.4 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_4(_config, 0), 12, v12 ) ; break ; }
case 20 : { /* 13.4 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_4(_config, 1), 12, v12 ) ; break ; }
case 21 : { /* 13.4 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_4(_config, 2), 12, v12 ) ; break ; }
case 22 : { /* 13.4 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_4(_config, 3), 12, v12 ) ; break ; }
case 23 :
{ /* 13.5 */
_subconfig = 0 ;
if( TestInterior( MCLookUpTable::Test13(_config, 6) ) )
AddTriangles( MCLookUpTable::Tiling13_5_1(_config, 0), 6 ) ;
else
AddTriangles( MCLookUpTable::Tiling13_5_2(_config, 0), 10 ) ;
break ;
}
case 24 :
{ /* 13.5 */
_subconfig = 1 ;
if( TestInterior( MCLookUpTable::Test13(_config, 6) ) )
AddTriangles( MCLookUpTable::Tiling13_5_1(_config, 1), 6 ) ;
else
AddTriangles( MCLookUpTable::Tiling13_5_2(_config, 1), 10 ) ;
break ;
}
case 25 :
{/* 13.5 */
_subconfig = 2 ;
if( TestInterior( MCLookUpTable::Test13(_config, 6) ) )
AddTriangles( MCLookUpTable::Tiling13_5_1(_config, 2), 6 ) ;
else
AddTriangles( MCLookUpTable::Tiling13_5_2(_config, 2), 10 ) ;
break ;
}
case 26 :
{/* 13.5 */
_subconfig = 3 ;
if( TestInterior( MCLookUpTable::Test13(_config, 6) ) )
AddTriangles( MCLookUpTable::Tiling13_5_1(_config, 3), 6 ) ;
else
AddTriangles( MCLookUpTable::Tiling13_5_2(_config, 3), 10 ) ;
break ;
}
case 27 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 0), 10, v12 ) ; break ; }
case 28 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 1), 10, v12 ) ; break ; }
case 29 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 2), 10, v12 ) ; break ; }
case 30 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 3), 10, v12 ) ; break ; }
case 31 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 4), 10, v12 ) ; break ; }
case 32 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 5), 10, v12 ) ; break ; }
case 33 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 6), 10, v12 ) ; break ; }
case 34 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 7), 10, v12 ) ; break ; }
case 35 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 8), 10, v12 ) ; break ; }
case 36 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config, 9), 10, v12 ) ; break ; }
case 37 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config,10), 10, v12 ) ; break ; }
case 38 : { /* 13.3 */ ComputeCVertex(v12); AddTriangles( MCLookUpTable::Tiling13_3_(_config,11), 10, v12 ) ; break ; }
case 39 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2_(_config,0), 6 ) ; break ; }
case 40 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2_(_config,1), 6 ) ; break ; }
case 41 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2_(_config,2), 6 ) ; break ; }
case 42 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2_(_config,3), 6 ) ; break ; }
case 43 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2_(_config,4), 6 ) ; break ; }
case 44 : { /* 13.2 */ AddTriangles( MCLookUpTable::Tiling13_2_(_config,5), 6 ) ; break ; }
case 45 : { /* 13.1 */ AddTriangles( MCLookUpTable::Tiling13_1_(_config) , 4 ) ; break ; }
default : { /*Impossible case 13*/ assert(false); }
}
break ;
} // end of case 13
case 14 : { AddTriangles( MCLookUpTable::Tiling14(_config), 4 ) ; }
break ;
} //end of switch (_case)
}; // end of ApplyMC
private:
/*!
*/
WALKER_TYPE *_walker;
/*!
*/
TRIMESH_TYPE *_mesh;
/*!
* The field value at the cell corners
*/
ScalarType _field[8];
/*!
* Array of the 8 corners of the volume cell being processed
*/
vcg::Point3i _corners[8];
/*!
* Case of the volume cell being processed
*/
unsigned char _case;
/*!
* Configuration of the volume cell being processed
*/
unsigned char _config;
/*!
* Subconfiguration of the volume cell being processed
*/
unsigned char _subconfig;
/*!
* Tests if the components of the tesselation of the cube should be connected
* by the interior of an ambiguous face
*/
inline bool TestFace(signed char face)
{
ScalarType A,B,C,D ;
switch( face )
{
case -1 : case 1 : A = _field[0] ; B = _field[4] ; C = _field[5] ; D = _field[1] ; break ;
case -2 : case 2 : A = _field[1] ; B = _field[5] ; C = _field[6] ; D = _field[2] ; break ;
case -3 : case 3 : A = _field[2] ; B = _field[6] ; C = _field[7] ; D = _field[3] ; break ;
case -4 : case 4 : A = _field[3] ; B = _field[7] ; C = _field[4] ; D = _field[0] ; break ;
case -5 : case 5 : A = _field[0] ; B = _field[3] ; C = _field[2] ; D = _field[1] ; break ;
case -6 : case 6 : A = _field[4] ; B = _field[7] ; C = _field[6] ; D = _field[5] ; break ;
default : assert(false); // Invalid face code
};
return face * A * ( A*C - B*D ) >= 0 ; // face and A invert signs
} // end of TestFace
/*!
* Tests if the components of the tesselation of the cube should be connected
* through the interior of the cube
*/
inline bool TestInterior(signed char s)
{
ScalarType t, At=0, Bt=0, Ct=0, Dt=0, a, b ;
char test = 0 ;
char edge = -1 ; // reference edge of the triangulation
switch( _case )
{
case 4 :
case 10 :
{
a = (_field[4]-_field[0])*(_field[6]-_field[2]) - (_field[7]-_field[3])*(_field[5]-_field[1]);
b = _field[2]*(_field[4]-_field[0])+_field[0]*(_field[6]-_field[2])-_field[1]*(_field[7]-_field[3])-_field[3]*(_field[5]-_field[1]);
t = - b / (2*a) ;
if( t<0 || t>1 )
return s>0 ;
At = _field[0] + ( _field[4] - _field[0] ) * t ;
Bt = _field[3] + ( _field[7] - _field[3] ) * t ;
Ct = _field[2] + ( _field[6] - _field[2] ) * t ;
Dt = _field[1] + ( _field[5] - _field[1] ) * t ;
break ;
}
case 6 :
case 7 :
case 12 :
case 13 :
switch( _case )
{
case 6 : edge = MCLookUpTable::Test6 (_config, 2) ; break ;
case 7 : edge = MCLookUpTable::Test7 (_config, 4) ; break ;
case 12 : edge = MCLookUpTable::Test12(_config, 3) ; break ;
case 13 : edge = MCLookUpTable::Tiling13_5_1(_config, _subconfig)[0] ; break ;
}
switch( edge )
{
case 0 :
t = _field[0] / ( _field[0] - _field[1] ) ;
At = 0 ;
Bt = _field[3] + ( _field[2] - _field[3] ) * t ;
Ct = _field[7] + ( _field[6] - _field[7] ) * t ;
Dt = _field[4] + ( _field[5] - _field[4] ) * t ;
break ;
case 1 :
t = _field[1] / ( _field[1] - _field[2] ) ;
At = 0 ;
Bt = _field[0] + ( _field[3] - _field[0] ) * t ;
Ct = _field[4] + ( _field[7] - _field[4] ) * t ;
Dt = _field[5] + ( _field[6] - _field[5] ) * t ;
break ;
case 2 :
t = _field[2] / ( _field[2] - _field[3] ) ;
At = 0 ;
Bt = _field[1] + ( _field[0] - _field[1] ) * t ;
Ct = _field[5] + ( _field[4] - _field[5] ) * t ;
Dt = _field[6] + ( _field[7] - _field[6] ) * t ;
break ;
case 3 :
t = _field[3] / ( _field[3] - _field[0] ) ;
At = 0 ;
Bt = _field[2] + ( _field[1] - _field[2] ) * t ;
Ct = _field[6] + ( _field[5] - _field[6] ) * t ;
Dt = _field[7] + ( _field[4] - _field[7] ) * t ;
break ;
case 4 :
t = _field[4] / ( _field[4] - _field[5] ) ;
At = 0 ;
Bt = _field[7] + ( _field[6] - _field[7] ) * t ;
Ct = _field[3] + ( _field[2] - _field[3] ) * t ;
Dt = _field[0] + ( _field[1] - _field[0] ) * t ;
break ;
case 5 :
t = _field[5] / ( _field[5] - _field[6] ) ;
At = 0 ;
Bt = _field[4] + ( _field[7] - _field[4] ) * t ;
Ct = _field[0] + ( _field[3] - _field[0] ) * t ;
Dt = _field[1] + ( _field[2] - _field[1] ) * t ;
break ;
case 6 :
t = _field[6] / ( _field[6] - _field[7] ) ;
At = 0 ;
Bt = _field[5] + ( _field[4] - _field[5] ) * t ;
Ct = _field[1] + ( _field[0] - _field[1] ) * t ;
Dt = _field[2] + ( _field[3] - _field[2] ) * t ;
break ;
case 7 :
t = _field[7] / ( _field[7] - _field[4] ) ;
At = 0 ;
Bt = _field[6] + ( _field[5] - _field[6] ) * t ;
Ct = _field[2] + ( _field[1] - _field[2] ) * t ;
Dt = _field[3] + ( _field[0] - _field[3] ) * t ;
break ;
case 8 :
t = _field[0] / ( _field[0] - _field[4] ) ;
At = 0 ;
Bt = _field[3] + ( _field[7] - _field[3] ) * t ;
Ct = _field[2] + ( _field[6] - _field[2] ) * t ;
Dt = _field[1] + ( _field[5] - _field[1] ) * t ;
break ;
case 9 :
t = _field[1] / ( _field[1] - _field[5] ) ;
At = 0 ;
Bt = _field[0] + ( _field[4] - _field[0] ) * t ;
Ct = _field[3] + ( _field[7] - _field[3] ) * t ;
Dt = _field[2] + ( _field[6] - _field[2] ) * t ;
break ;
case 10 :
t = _field[2] / ( _field[2] - _field[6] ) ;
At = 0 ;
Bt = _field[1] + ( _field[5] - _field[1] ) * t ;
Ct = _field[0] + ( _field[4] - _field[0] ) * t ;
Dt = _field[3] + ( _field[7] - _field[3] ) * t ;
break ;
case 11 :
t = _field[3] / ( _field[3] - _field[7] ) ;
At = 0 ;
Bt = _field[2] + ( _field[6] - _field[2] ) * t ;
Ct = _field[1] + ( _field[5] - _field[1] ) * t ;
Dt = _field[0] + ( _field[4] - _field[0] ) * t ;
break ;
default: { assert(false); /* Invalid edge */ break ; }
}
break ;
default : assert(false); /* Invalid ambiguous case */ break;
}
if( At >= 0 ) test ++ ;
if( Bt >= 0 ) test += 2 ;
if( Ct >= 0 ) test += 4 ;
if( Dt >= 0 ) test += 8 ;
switch( test )
{
case 0 : return s>0 ;
case 1 : return s>0 ;
case 2 : return s>0 ;
case 3 : return s>0 ;
case 4 : return s>0 ;
case 5 : if( At * Ct < Bt * Dt ) return s>0 ; break ;
case 6 : return s>0 ;
case 7 : return s<0 ;
case 8 : return s>0 ;
case 9 : return s>0 ;
case 10 : if( At * Ct >= Bt * Dt ) return s>0 ; break ;
case 11 : return s<0 ;
case 12 : return s>0 ;
case 13 : return s<0 ;
case 14 : return s<0 ;
case 15 : return s<0 ;
}
return s<0 ;
} //end of TestInterior
/*!
* Adds a vertex inside the current cube
* \param v The pointer to the new vertex along the edge
*/
inline void ComputeCVertex(VertexPointer &v12)
{
v12 = &*AllocatorType::AddVertices(*_mesh, 1);
v12->P() = CoordType(0.0, 0.0, 0.0);
unsigned int count = 0;
VertexPointer v = NULL;
if (_walker->Exist(_corners[0], _corners[1], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[1], _corners[2], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[3], _corners[2], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[0], _corners[3], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[4], _corners[5], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[5], _corners[6], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[7], _corners[6], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[4], _corners[7], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[0], _corners[4], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[1], _corners[5], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[2], _corners[6], v) )
{
count++;
v12->P() += v->P();
}
if (_walker->Exist(_corners[3], _corners[7], v) )
{
count++;
v12->P() += v->P();
}
v12->P() /= (float) count;
} // end of AddCVertex
/*!
* Adds new triangles to the mesh
* \param vertices_list The list of vertex indices
* \param n The number of triangles that will be added to the mesh
* \param v12 The pointer to the vertex inside the current cell
*/
inline void AddTriangles(const char *vertices_list, char n, VertexPointer v12=NULL)
{
VertexPointer vp = NULL;
size_t face_idx = _mesh->face.size();
size_t v12_idx = -1;
size_t vertices_idx[3];
if (v12 != NULL) v12_idx = v12 - &_mesh->vert[0];
AllocatorType::AddFaces(*_mesh, (int) n);
for (int trig=0; trig<3*n; face_idx++ )
{
vp = NULL;
memset(vertices_idx, -1, 3*sizeof(size_t));
for (int vert=0; vert<3; vert++, trig++) //ok
{
switch ( vertices_list[trig] )
{
case 0: { _walker->GetXIntercept(_corners[0], _corners[1], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 1: { _walker->GetYIntercept(_corners[1], _corners[2], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 2: { _walker->GetXIntercept(_corners[3], _corners[2], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 3: { _walker->GetYIntercept(_corners[0], _corners[3], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 4: { _walker->GetXIntercept(_corners[4], _corners[5], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 5: { _walker->GetYIntercept(_corners[5], _corners[6], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 6: { _walker->GetXIntercept(_corners[7], _corners[6], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 7: { _walker->GetYIntercept(_corners[4], _corners[7], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 8: { _walker->GetZIntercept(_corners[0], _corners[4], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 9: { _walker->GetZIntercept(_corners[1], _corners[5], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 10: { _walker->GetZIntercept(_corners[2], _corners[6], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 11: { _walker->GetZIntercept(_corners[3], _corners[7], vp); vertices_idx[vert] = tri::Index(*_mesh,vp); break; }
case 12: { assert(v12 != NULL); vertices_idx[vert] = v12_idx; break; }
default: { assert(false); /* Invalid edge identifier */ }
} // end of switch
// Note that vp can be zero if we are in case 12 and that vertices_idx is surely >0 so the following assert has to be corrected as below.
// assert((vp - &_mesh->vert[0])>=0 && vertices_idx[vert]<_mesh->vert.size());
assert(vertices_idx[vert]<_mesh->vert.size());
} // end for (int vert=0 ...)
_mesh->face[face_idx].V(0) = &_mesh->vert[vertices_idx[0]];
_mesh->face[face_idx].V(1) = &_mesh->vert[vertices_idx[1]];
_mesh->face[face_idx].V(2) = &_mesh->vert[vertices_idx[2]];
} // end for (int trig=0...)
} // end of AddTriangles
}; // end of class MarchingCubes
/*! @} */
//end of Doxygen documentation
} // end of namespace tri
} // end of namespace vcg
#endif //__VCG_MARCHING_CUBES