|
a |
|
b/3D Reconstruction/3D Visualization/Dual Marching Cubes/include/dualmc.h |
|
|
1 |
#ifndef DUALMC_H_INCLUDED |
|
|
2 |
#define DUALMC_H_INCLUDED |
|
|
3 |
|
|
|
4 |
/// \file dualmc.h |
|
|
5 |
/// \author Dominik Wodniok |
|
|
6 |
/// \date 2009 |
|
|
7 |
|
|
|
8 |
// c includes |
|
|
9 |
#include <cstdint> |
|
|
10 |
|
|
|
11 |
// stl includes |
|
|
12 |
#include <unordered_map> |
|
|
13 |
#include <vector> |
|
|
14 |
|
|
|
15 |
namespace dualmc { |
|
|
16 |
|
|
|
17 |
|
|
|
18 |
typedef float VertexComponentsType; |
|
|
19 |
typedef int32_t QuadIndexType; |
|
|
20 |
|
|
|
21 |
/// vertex structure for dual points |
|
|
22 |
struct Vertex { |
|
|
23 |
/// non-initializing constructor |
|
|
24 |
Vertex(); |
|
|
25 |
|
|
|
26 |
/// initializing constructor |
|
|
27 |
Vertex(VertexComponentsType x, VertexComponentsType y, VertexComponentsType z); |
|
|
28 |
|
|
|
29 |
/// initializing constructor |
|
|
30 |
Vertex(Vertex const & v); |
|
|
31 |
|
|
|
32 |
// components |
|
|
33 |
VertexComponentsType x,y,z; |
|
|
34 |
}; |
|
|
35 |
|
|
|
36 |
/// quad indices structure |
|
|
37 |
struct Quad { |
|
|
38 |
/// non-initializing constructor |
|
|
39 |
Quad(); |
|
|
40 |
|
|
|
41 |
/// initializing constructor |
|
|
42 |
Quad(QuadIndexType i0, QuadIndexType i1,QuadIndexType i2, QuadIndexType i3); |
|
|
43 |
|
|
|
44 |
// quad indices |
|
|
45 |
QuadIndexType i0,i1,i2,i3; |
|
|
46 |
|
|
|
47 |
}; |
|
|
48 |
|
|
|
49 |
/// \class DualMC |
|
|
50 |
/// \author Dominik Wodniok |
|
|
51 |
/// \date 2009 |
|
|
52 |
/// Class which implements the dual marching cubes algorithm from Gregory M. Nielson. |
|
|
53 |
/// Faces and vertices of the standard marching cubes algorithm correspond to |
|
|
54 |
/// vertices and faces in the dual algorithm. As a vertex in standard marching cubes |
|
|
55 |
/// usually is shared by 4 faces, the dual mesh is entirely made from quadrangles. |
|
|
56 |
/// Unfortunately, under rare circumstances the original algorithm can create |
|
|
57 |
/// non-manifold meshes. See the remarks of the original paper on this. |
|
|
58 |
/// The class optionally can guarantee manifold meshes by taking the Manifold |
|
|
59 |
/// Dual Marching Cubes approach from Rephael Wenger as described in |
|
|
60 |
/// chapter 3.3.5 of his book "Isosurfaces: Geometry, Topology, and Algorithms". |
|
|
61 |
template<class T> class DualMC { |
|
|
62 |
public: |
|
|
63 |
// typedefs |
|
|
64 |
typedef T VolumeDataType; |
|
|
65 |
|
|
|
66 |
/// Extracts the iso surface for a given volume and iso value. |
|
|
67 |
/// Output is a list of vertices and a list of indices, which connect |
|
|
68 |
/// vertices to quads. |
|
|
69 |
/// The quad mesh either uses shared vertex indices or is a quad soup if |
|
|
70 |
/// desired. |
|
|
71 |
void build( |
|
|
72 |
VolumeDataType const * data, |
|
|
73 |
int32_t const dimX, int32_t const dimY, int32_t const dimZ, |
|
|
74 |
VolumeDataType const iso, |
|
|
75 |
bool const generateManifold, |
|
|
76 |
bool const generateSoup, |
|
|
77 |
std::vector<Vertex> & vertices, |
|
|
78 |
std::vector<Quad> & quads |
|
|
79 |
); |
|
|
80 |
|
|
|
81 |
private: |
|
|
82 |
|
|
|
83 |
/// Extract quad mesh with shared vertex indices. |
|
|
84 |
void buildSharedVerticesQuads( |
|
|
85 |
VolumeDataType const iso, |
|
|
86 |
std::vector<Vertex> & vertices, |
|
|
87 |
std::vector<Quad> & quads |
|
|
88 |
); |
|
|
89 |
|
|
|
90 |
/// Extract quad soup. |
|
|
91 |
void buildQuadSoup( |
|
|
92 |
VolumeDataType const iso, |
|
|
93 |
std::vector<Vertex> & vertices, |
|
|
94 |
std::vector<Quad> & quads |
|
|
95 |
); |
|
|
96 |
|
|
|
97 |
|
|
|
98 |
private: |
|
|
99 |
|
|
|
100 |
/// enum with edge codes for a 12-bit voxel edge mask to indicate |
|
|
101 |
/// grid edges which intersect the ISO surface of classic marching cubes |
|
|
102 |
enum DMCEdgeCode { |
|
|
103 |
EDGE0 = 1, |
|
|
104 |
EDGE1 = 1 << 1, |
|
|
105 |
EDGE2 = 1 << 2, |
|
|
106 |
EDGE3 = 1 << 3, |
|
|
107 |
EDGE4 = 1 << 4, |
|
|
108 |
EDGE5 = 1 << 5, |
|
|
109 |
EDGE6 = 1 << 6, |
|
|
110 |
EDGE7 = 1 << 7, |
|
|
111 |
EDGE8 = 1 << 8, |
|
|
112 |
EDGE9 = 1 << 9, |
|
|
113 |
EDGE10 = 1 << 10, |
|
|
114 |
EDGE11 = 1 << 11, |
|
|
115 |
FORCE_32BIT = 0xffffffff |
|
|
116 |
}; |
|
|
117 |
|
|
|
118 |
/// get the 8-bit in-out mask for the voxel corners of the cell cube at (cx,cy,cz) |
|
|
119 |
/// and the given iso value |
|
|
120 |
int getCellCode(int32_t const cx, int32_t const cy, int32_t const cz, VolumeDataType const iso) const; |
|
|
121 |
|
|
|
122 |
/// Get the 12-bit dual point code mask, which encodes the traditional |
|
|
123 |
/// marching cube vertices of the traditional marching cubes face which |
|
|
124 |
/// corresponds to the dual point. |
|
|
125 |
/// This is also where the manifold dual marching cubes algorithm is |
|
|
126 |
/// implemented. |
|
|
127 |
int getDualPointCode(int32_t const cx, int32_t const cy, int32_t const cz, |
|
|
128 |
VolumeDataType const iso, DMCEdgeCode const edge) const; |
|
|
129 |
|
|
|
130 |
/// Given a dual point code and iso value, compute the dual point. |
|
|
131 |
void calculateDualPoint(int32_t const cx, int32_t const cy, int32_t const cz, |
|
|
132 |
VolumeDataType const iso, int const pointCode, Vertex &v) const; |
|
|
133 |
|
|
|
134 |
/// Get the shared index of a dual point which is uniquly identified by its |
|
|
135 |
/// cell cube index and a cube edge. The dual point is computed, |
|
|
136 |
/// if it has not been computed before. |
|
|
137 |
QuadIndexType getSharedDualPointIndex(int32_t const cx, int32_t const cy, int32_t const cz, |
|
|
138 |
VolumeDataType const iso, DMCEdgeCode const edge, |
|
|
139 |
std::vector<Vertex> & vertices); |
|
|
140 |
|
|
|
141 |
/// Compute a linearized cell cube index. |
|
|
142 |
int32_t gA(int32_t const x, int32_t const y, int32_t const z) const; |
|
|
143 |
|
|
|
144 |
private: |
|
|
145 |
// static lookup tables needed for (manifold) dual marching cubes |
|
|
146 |
|
|
|
147 |
/// Dual Marching Cubes table |
|
|
148 |
/// Encodes the edge vertices for the 256 marching cubes cases. |
|
|
149 |
/// A marching cube case produces up to four faces and ,thus, up to four |
|
|
150 |
/// dual points. |
|
|
151 |
static int32_t const dualPointsList[256][4]; |
|
|
152 |
|
|
|
153 |
/// Table which encodes the ambiguous face of cube configurations, which |
|
|
154 |
/// can cause non-manifold meshes. |
|
|
155 |
/// Needed for manifold dual marching cubes. |
|
|
156 |
static uint8_t const problematicConfigs[256]; |
|
|
157 |
|
|
|
158 |
private: |
|
|
159 |
|
|
|
160 |
/// convenience volume extent array for x-,y-, and z-dimension |
|
|
161 |
int32_t dims[3]; |
|
|
162 |
|
|
|
163 |
/// convenience volume data point |
|
|
164 |
VolumeDataType const * data; |
|
|
165 |
|
|
|
166 |
/// store whether the manifold dual marching cubes algorithm should be |
|
|
167 |
/// applied. |
|
|
168 |
bool generateManifold; |
|
|
169 |
|
|
|
170 |
/// Dual point key structure for hashing of shared vertices |
|
|
171 |
struct DualPointKey { |
|
|
172 |
// a dual point can be uniquely identified by ite linearized volume cell |
|
|
173 |
// id and point code |
|
|
174 |
int32_t linearizedCellID; |
|
|
175 |
int pointCode; |
|
|
176 |
/// Equal operator for unordered map |
|
|
177 |
bool operator==(DualPointKey const & other) const; |
|
|
178 |
}; |
|
|
179 |
|
|
|
180 |
/// Functor for dual point key hash generation |
|
|
181 |
struct DualPointKeyHash { |
|
|
182 |
size_t operator()(DualPointKey const & k) const { |
|
|
183 |
return size_t(k.linearizedCellID) | (size_t(k.pointCode) << 32u); |
|
|
184 |
} |
|
|
185 |
}; |
|
|
186 |
|
|
|
187 |
/// Hash map for shared vertex index computations |
|
|
188 |
std::unordered_map<DualPointKey,QuadIndexType,DualPointKeyHash> pointToIndex; |
|
|
189 |
}; |
|
|
190 |
|
|
|
191 |
// inline function definitions |
|
|
192 |
|
|
|
193 |
//------------------------------------------------------------------------------ |
|
|
194 |
|
|
|
195 |
inline |
|
|
196 |
Vertex::Vertex(){} |
|
|
197 |
|
|
|
198 |
//------------------------------------------------------------------------------ |
|
|
199 |
|
|
|
200 |
inline |
|
|
201 |
Vertex::Vertex( |
|
|
202 |
VertexComponentsType x, |
|
|
203 |
VertexComponentsType y, |
|
|
204 |
VertexComponentsType z |
|
|
205 |
) : x(x), y(y), z(z) {} |
|
|
206 |
|
|
|
207 |
//------------------------------------------------------------------------------ |
|
|
208 |
|
|
|
209 |
inline |
|
|
210 |
Vertex::Vertex(Vertex const & v) : x(v.x), y(v.y), z(v.z) {} |
|
|
211 |
|
|
|
212 |
//------------------------------------------------------------------------------ |
|
|
213 |
|
|
|
214 |
inline |
|
|
215 |
Quad::Quad(){} |
|
|
216 |
|
|
|
217 |
//------------------------------------------------------------------------------ |
|
|
218 |
|
|
|
219 |
inline |
|
|
220 |
Quad::Quad( |
|
|
221 |
QuadIndexType i0, |
|
|
222 |
QuadIndexType i1, |
|
|
223 |
QuadIndexType i2, |
|
|
224 |
QuadIndexType i3 |
|
|
225 |
) : i0(i0),i1(i1),i2(i2),i3(i3) {} |
|
|
226 |
|
|
|
227 |
//------------------------------------------------------------------------------ |
|
|
228 |
|
|
|
229 |
template<class T> inline |
|
|
230 |
int32_t DualMC<T>::gA(int32_t const x, int32_t const y, int32_t const z) const { |
|
|
231 |
return x + dims[0] * (y + dims[1] * z); |
|
|
232 |
} |
|
|
233 |
|
|
|
234 |
//------------------------------------------------------------------------------ |
|
|
235 |
template<class T> inline |
|
|
236 |
bool DualMC<T>::DualPointKey::operator==(typename DualMC<T>::DualPointKey const & other) const { |
|
|
237 |
return linearizedCellID == other.linearizedCellID && pointCode == other.pointCode; |
|
|
238 |
} |
|
|
239 |
|
|
|
240 |
#include "dualmc.tpp" |
|
|
241 |
|
|
|
242 |
#include "dualmc_tables.tpp" |
|
|
243 |
|
|
|
244 |
} // END: namespace dualmc |
|
|
245 |
#endif // DUALMC_H_INCLUDED |