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