Allolib  1.0
C++ Components For Interactive Multimedia
al_Isosurface.hpp
1 #ifndef INCLUDE_AL_ISOSURFACE_HPP
2 #define INCLUDE_AL_ISOSURFACE_HPP
3 
4 /* Allocore --
5  Multimedia / virtual environment application class library
6 
7  Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology,
8  UCSB. Copyright (C) 2012. The Regents of the University of California. All
9  rights reserved.
10 
11  Redistribution and use in source and binary forms, with or without
12  modification, are permitted provided that the following conditions are
13  met:
14 
15  Redistributions of source code must retain the above copyright
16  notice, this list of conditions and the following disclaimer.
17 
18  Redistributions in binary form must reproduce the above
19  copyright notice, this list of conditions and the following disclaimer in the
20  documentation and/or other materials provided with the
21  distribution.
22 
23  Neither the name of the University of California nor the names
24  of its contributors may be used to endorse or promote products derived from
25  this software without specific prior written permission.
26 
27  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
28  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
31  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
34  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
35  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
36  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
37  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 
39  File author(s):
40  Lance Putnam, 2010, putnam.lance@gmail.com
41 
42  This file incorporates work covered by the following copyright(s) and
43  permission notice(s):
44 
45  Author: Raghavendra Chandrashekara
46  Email: rc99@doc.ic.ac.uk, rchandrashekara@hotmail.com
47  Last Modified: 5/8/2000
48 
49  This work incorporates work covered by the following copyright
50  and permission notice:
51 
52  Marching Cubes Example Program
53  by Cory Bloyd (corysama@yahoo.com)
54 
55  A simple, portable and complete implementation of the
56  Marching Cubes and Marching Tetrahedrons algorithms in a single source file.
57  There are many ways that this code could be made faster,
58  but the intent is for the code to be easy to understand.
59 
60  For a description of the algorithm go to
61  http://astronomy.swin.edu.au/pbourke/modelling/polygonise/
62 
63  This code is public domain.
64 */
65 
66 #include "al/graphics/al_Mesh.hpp"
67 #include "al/types/al_Buffer.hpp"
68 #include <map>
69 #include <unordered_map>
70 #include <vector>
71 
72 namespace al {
73 
78 class Isosurface : public Mesh {
79 public:
80  struct EdgeVertex {
81  Vec3i pos; // cell coordinates
82  Vec3i corners[2]; // edge corners as offsets from cell coordinates
83  float x, y, z; // vertex position
84  float mu; // fraction along edge of vertex
85 
87  Vec3i edgePos(int i) const { return pos + corners[i]; }
88  };
89 
90  struct EdgeTriangle {
91  int edgeIDs[3];
92  };
93 
94  struct VertexAction {
95  virtual ~VertexAction() {}
96  virtual void operator()(const Isosurface::EdgeVertex &v, Isosurface &s) = 0;
97  };
98 
99  struct NoVertexAction : public VertexAction {
100  virtual void operator()(const EdgeVertex &v, Isosurface &s) {}
101  };
102 
103  static NoVertexAction noVertexAction;
104 
108  Isosurface(float level = 0, VertexAction &action = noVertexAction);
109 
110  virtual ~Isosurface();
111 
113  int fieldDim(int i) const { return mNF[i]; }
114 
116  float level() const { return mIsolevel; }
117 
119  bool validSurface() const { return mValidSurface; }
120 
122 
125  bool volumeLengths(double &volLengthX, double &volLengthY,
126  double &volLengthZ) const;
127 
128  // Get unique identifier of 3d position indices
129  int posID(int ix, int iy, int iz) const {
130  return ix + mNF[0] * (iy + mNF[1] * iz);
131  }
132 
133  template <class VEC3I> int posID(const VEC3I &i3) const {
134  return posID(i3[0], i3[1], i3[2]);
135  }
136 
137  // Get unique identifier of cell
138  int cellID(int ix, int iy, int iz) const { return 3 * posID(ix, iy, iz); }
139 
140  // Get unique identifier of edge
141  int edgeID(int cellID, int edgeNo) const {
142  return cellID + mEdgeIDOffsets[edgeNo];
143  }
144 
146  Isosurface &fieldDims(int nx, int ny, int nz);
147 
149  Isosurface &fieldDims(int n) { return fieldDims(n, n, n); }
150 
152  Isosurface &cellLengths(double dx, double dy, double dz);
153 
155  Isosurface &cellLengths(double v) { return cellLengths(v, v, v); }
156 
158  Isosurface &level(float v) {
159  mIsolevel = v;
160  return *this;
161  }
162 
164  Isosurface &normals(bool v) {
165  mComputeNormals = v;
166  return *this;
167  }
168 
171  mNormalize = v;
172  return *this;
173  }
174 
176  void begin();
177 
179  void end();
180 
182 
185  template <class T>
186  void addCell(int ix, int iy, int iz, const T &xyz, const T &Xyz, const T &xYz,
187  const T &XYz, const T &xyZ, const T &XyZ, const T &xYZ,
188  const T &XYZ) {
189  int inds[3] = {ix, iy, iz};
190  const float vals[8] = {xyz, Xyz, xYz, XYz, xyZ, XyZ, xYZ, XYZ};
191  addCell(inds, vals);
192  }
193 
195  void addCell(const int *indices3, const float *values8);
196 
198  template <class T> void generate(const T *scalarField);
199 
201 
206  template <class T>
207  void generate(const T *scalarField, int nX, int nY, int nZ, float cellLengthX,
208  float cellLengthY, float cellLengthZ) {
209  fieldDims(nX, nY, nZ);
210  cellLengths(cellLengthX, cellLengthY, cellLengthZ);
211  generate(scalarField);
212  }
213 
214  template <class T>
215  void generate(const T *scalarField, int n, float cellLength) {
216  generate(scalarField, n, n, n, cellLength, cellLength, cellLength);
217  }
218 
219  /*
220  // support for building isosurface from al::Voxels class
221  void generate(const MRC& mrc, float glUnitLength) {
222  generate((float*)mrc.dataPtr(), mrc.array().dim(0),
223  mrc.array().dim(1), mrc.array().dim(2), mrc.header().cella[0]/glUnitLength,
224  mrc.header().cella[1]/glUnitLength, mrc.header().cella[2]/glUnitLength);
225  }*/
226 
227  void vertexAction(VertexAction &a) { mVertexAction = &a; }
228 
229  const bool inBox() const { return mInBox; }
230 
232 
237  Isosurface &inBox(bool v);
238 
239 protected:
241  size_t operator()(int v) const { return v; }
242  // size_t operator()(int v) const { return v*2654435761UL; }
243  };
244 
245  typedef std::unordered_map<int, int, IsosurfaceHashInt> EdgeToVertex;
246 
247  EdgeToVertex mEdgeToVertex; // map from edge ID to vertex
248 
249  // TODO - This never gets used???
250  std::vector<EdgeTriangle>
251  mEdgeTriangles; // surface triangles in terms of edge IDs
252 
253  std::vector<int> mEdgeToVertexArray;
254  // al::Buffer<int> mTempEdges;
255 
256  double mL[3]; // cell length in x, y, and z directions
257  int mNF[3]; // number of field points in x, y, and z directions
258  int mEdgeIDOffsets[12]; // used to obtain edge ID from vertex ID and edge
259  // number
260  float mIsolevel; // isosurface level
261  VertexAction *mVertexAction;
262  bool mValidSurface; // indicates whether a valid surface is present
263  bool mComputeNormals; // whether to compute normals
264  bool mNormalize; // whether to normalize normals
265  bool mInBox;
266 
267  EdgeVertex calcIntersection(int nX, int nY, int nZ, int nEdgeNo,
268  const float *vals) const;
269  void addEdgeVertex(int x, int y, int z, int cellID, int edge,
270  const float *vals);
271 
272  void compressTriangles();
273 };
274 
275 // Implementation ______________________________________________________________
276 
277 template <class T> void Isosurface::generate(const T *vals) {
278  inBox(true);
279  begin();
280 
281  int Nx = mNF[0];
282  int Nxy = Nx * mNF[1];
283 
284  // iterate through cubes (not field points)
285  // for(int z=0; z < mNF[2]-1; ++z){
286  // support transparency (assumes higher indices are farther away)
287  for (int z = mNF[2] - 2; z >= 0; --z) {
288  int z0 = z * Nxy;
289  int z1 = (z + 1) * Nxy;
290  for (int y = 0; y < mNF[1] - 1; ++y) {
291  int y0 = y * Nx;
292  int y1 = (y + 1) * Nx;
293 
294  int z0y0 = z0 + y0;
295  int z0y1 = z0 + y1;
296  int z1y0 = z1 + y0;
297  int z1y1 = z1 + y1;
298 
299  int z0y0_1 = z0y0 + 1;
300  int z0y1_1 = z0y1 + 1;
301  int z1y0_1 = z1y0 + 1;
302  int z1y1_1 = z1y1 + 1;
303 
304  for (int x = 0; x < mNF[0] - 1; ++x) {
305  float v8[] = {float(vals[z0y0 + x]), float(vals[z0y0_1 + x]),
306  float(vals[z0y1 + x]), float(vals[z0y1_1 + x]),
307  float(vals[z1y0 + x]), float(vals[z1y0_1 + x]),
308  float(vals[z1y1 + x]), float(vals[z1y1_1 + x])};
309 
310  int i3[] = {x, y, z};
311 
312  addCell(i3, v8);
313  }
314  }
315  }
316 
317  end();
318 }
319 
320 } // namespace al
321 
322 #endif
Isosurface generated using marching cubes.
Isosurface & normals(bool v)
Set whether to compute normals.
void addCell(const int *indices3, const float *values8)
Add a cell from a scalar field.
void end()
End cell-at-a-time mode.
Isosurface(float level=0, VertexAction &action=noVertexAction)
Isosurface & normalize(bool v)
Set whether to normalize normals (if being computed)
void addCell(int ix, int iy, int iz, const T &xyz, const T &Xyz, const T &xYz, const T &XYz, const T &xyZ, const T &XyZ, const T &xYZ, const T &XYZ)
Add a cell from a scalar field.
Isosurface & cellLengths(double v)
Set all lengths of cell.
Isosurface & fieldDims(int nx, int ny, int nz)
Set individual dimensions of the scalar field.
int fieldDim(int i) const
Get a field dimension.
float level() const
Get isolevel.
void generate(const T *scalarField, int nX, int nY, int nZ, float cellLengthX, float cellLengthY, float cellLengthZ)
Generate isosurface from scalar field.
bool validSurface() const
Returns true if a valid surface has been generated.
void generate(const T *scalarField)
Generate isosurface from scalar field.
Isosurface & inBox(bool v)
Set whether isosurface is assumed to fit snugly within a box.
bool volumeLengths(double &volLengthX, double &volLengthY, double &volLengthZ) const
Gets the length, width, and height of the isosurface volume.
Isosurface & cellLengths(double dx, double dy, double dz)
Set individual lengths of cell.
void begin()
Begin cell-at-a-time mode.
Isosurface & fieldDims(int n)
Set all dimensions of the scalar field.
Isosurface & level(float v)
Set isolevel.
Stores buffers related to rendering graphical objects.
Definition: al_Mesh.hpp:62
Definition: al_App.hpp:23
Vec3i edgePos(int i) const
Returns position of edge vertices.