Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/mantaflow/preprocessed/levelset.cpp')
-rw-r--r--extern/mantaflow/preprocessed/levelset.cpp876
1 files changed, 876 insertions, 0 deletions
diff --git a/extern/mantaflow/preprocessed/levelset.cpp b/extern/mantaflow/preprocessed/levelset.cpp
new file mode 100644
index 00000000000..dcc10718d71
--- /dev/null
+++ b/extern/mantaflow/preprocessed/levelset.cpp
@@ -0,0 +1,876 @@
+
+
+// DO NOT EDIT !
+// This file is generated using the MantaFlow preprocessor (prep generate).
+
+/******************************************************************************
+ *
+ * MantaFlow fluid solver framework
+ * Copyright 2011 Tobias Pfaff, Nils Thuerey
+ *
+ * This program is free software, distributed under the terms of the
+ * Apache License, Version 2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Levelset
+ *
+ ******************************************************************************/
+
+#include "levelset.h"
+#include "fastmarch.h"
+#include "kernel.h"
+#include "mcubes.h"
+#include "mesh.h"
+#include <stack>
+
+using namespace std;
+namespace Manta {
+
+//************************************************************************
+// Helper functions and kernels for marching
+
+static const int FlagInited = FastMarch<FmHeapEntryOut, +1>::FlagInited;
+
+// neighbor lookup vectors
+static const Vec3i neighbors[6] = {Vec3i(-1, 0, 0),
+ Vec3i(1, 0, 0),
+ Vec3i(0, -1, 0),
+ Vec3i(0, 1, 0),
+ Vec3i(0, 0, -1),
+ Vec3i(0, 0, 1)};
+
+struct InitFmIn : public KernelBase {
+ InitFmIn(const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ fmFlags(fmFlags),
+ phi(phi),
+ ignoreWalls(ignoreWalls),
+ obstacleType(obstacleType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType) const
+ {
+ const IndexInt idx = flags.index(i, j, k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ if (v >= 0. && ((flags[idx] & obstacleType) == 0))
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+ }
+ else {
+ if (v >= 0)
+ fmFlags[idx] = FlagInited;
+ else
+ fmFlags[idx] = 0;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<int> &getArg1()
+ {
+ return fmFlags;
+ }
+ typedef Grid<int> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline bool &getArg3()
+ {
+ return ignoreWalls;
+ }
+ typedef bool type3;
+ inline int &getArg4()
+ {
+ return obstacleType;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel InitFmIn ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<int> &fmFlags;
+ Grid<Real> &phi;
+ bool ignoreWalls;
+ int obstacleType;
+};
+
+struct InitFmOut : public KernelBase {
+ InitFmOut(const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ fmFlags(fmFlags),
+ phi(phi),
+ ignoreWalls(ignoreWalls),
+ obstacleType(obstacleType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const FlagGrid &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ bool ignoreWalls,
+ int obstacleType) const
+ {
+ const IndexInt idx = flags.index(i, j, k);
+ const Real v = phi[idx];
+ if (ignoreWalls) {
+ fmFlags[idx] = (v < 0) ? FlagInited : 0;
+ if ((flags[idx] & obstacleType) != 0) {
+ fmFlags[idx] = 0;
+ phi[idx] = 0;
+ }
+ }
+ else {
+ fmFlags[idx] = (v < 0) ? FlagInited : 0;
+ }
+ }
+ inline const FlagGrid &getArg0()
+ {
+ return flags;
+ }
+ typedef FlagGrid type0;
+ inline Grid<int> &getArg1()
+ {
+ return fmFlags;
+ }
+ typedef Grid<int> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline bool &getArg3()
+ {
+ return ignoreWalls;
+ }
+ typedef bool type3;
+ inline int &getArg4()
+ {
+ return obstacleType;
+ }
+ typedef int type4;
+ void runMessage()
+ {
+ debMsg("Executing kernel InitFmOut ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, ignoreWalls, obstacleType);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const FlagGrid &flags;
+ Grid<int> &fmFlags;
+ Grid<Real> &phi;
+ bool ignoreWalls;
+ int obstacleType;
+};
+
+struct SetUninitialized : public KernelBase {
+ SetUninitialized(const Grid<int> &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ const Real val,
+ int ignoreWalls,
+ int obstacleType)
+ : KernelBase(&flags, 1),
+ flags(flags),
+ fmFlags(fmFlags),
+ phi(phi),
+ val(val),
+ ignoreWalls(ignoreWalls),
+ obstacleType(obstacleType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(int i,
+ int j,
+ int k,
+ const Grid<int> &flags,
+ Grid<int> &fmFlags,
+ Grid<Real> &phi,
+ const Real val,
+ int ignoreWalls,
+ int obstacleType) const
+ {
+ if (ignoreWalls) {
+ if ((fmFlags(i, j, k) != FlagInited) && ((flags(i, j, k) & obstacleType) == 0)) {
+ phi(i, j, k) = val;
+ }
+ }
+ else {
+ if ((fmFlags(i, j, k) != FlagInited))
+ phi(i, j, k) = val;
+ }
+ }
+ inline const Grid<int> &getArg0()
+ {
+ return flags;
+ }
+ typedef Grid<int> type0;
+ inline Grid<int> &getArg1()
+ {
+ return fmFlags;
+ }
+ typedef Grid<int> type1;
+ inline Grid<Real> &getArg2()
+ {
+ return phi;
+ }
+ typedef Grid<Real> type2;
+ inline const Real &getArg3()
+ {
+ return val;
+ }
+ typedef Real type3;
+ inline int &getArg4()
+ {
+ return ignoreWalls;
+ }
+ typedef int type4;
+ inline int &getArg5()
+ {
+ return obstacleType;
+ }
+ typedef int type5;
+ void runMessage()
+ {
+ debMsg("Executing kernel SetUninitialized ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ const int _maxX = maxX;
+ const int _maxY = maxY;
+ if (maxZ > 1) {
+ for (int k = __r.begin(); k != (int)__r.end(); k++)
+ for (int j = 1; j < _maxY; j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, val, ignoreWalls, obstacleType);
+ }
+ else {
+ const int k = 0;
+ for (int j = __r.begin(); j != (int)__r.end(); j++)
+ for (int i = 1; i < _maxX; i++)
+ op(i, j, k, flags, fmFlags, phi, val, ignoreWalls, obstacleType);
+ }
+ }
+ void run()
+ {
+ if (maxZ > 1)
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(minZ, maxZ), *this);
+ else
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(1, maxY), *this);
+ }
+ const Grid<int> &flags;
+ Grid<int> &fmFlags;
+ Grid<Real> &phi;
+ const Real val;
+ int ignoreWalls;
+ int obstacleType;
+};
+
+template<bool inward>
+inline bool isAtInterface(const Grid<int> &fmFlags, Grid<Real> &phi, const Vec3i &p)
+{
+ // check for interface
+ int max = phi.is3D() ? 6 : 4;
+ for (int nb = 0; nb < max; nb++) {
+ const Vec3i pn(p + neighbors[nb]);
+ if (!fmFlags.isInBounds(pn))
+ continue;
+
+ if (fmFlags(pn) != FlagInited)
+ continue;
+ if ((inward && phi(pn) >= 0.) || (!inward && phi(pn) < 0.))
+ return true;
+ }
+ return false;
+}
+
+//************************************************************************
+// Levelset class def
+
+LevelsetGrid::LevelsetGrid(FluidSolver *parent, bool show) : Grid<Real>(parent, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+LevelsetGrid::LevelsetGrid(FluidSolver *parent, Real *data, bool show)
+ : Grid<Real>(parent, data, show)
+{
+ mType = (GridType)(TypeLevelset | TypeReal);
+}
+
+Real LevelsetGrid::invalidTimeValue()
+{
+ return FastMarch<FmHeapEntryOut, 1>::InvalidTime();
+}
+
+//! Kernel: perform levelset union
+struct KnJoin : public KernelBase {
+ KnJoin(Grid<Real> &a, const Grid<Real> &b) : KernelBase(&a, 0), a(a), b(b)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx, Grid<Real> &a, const Grid<Real> &b) const
+ {
+ a[idx] = min(a[idx], b[idx]);
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return a;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return b;
+ }
+ typedef Grid<Real> type1;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnJoin ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, a, b);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &a;
+ const Grid<Real> &b;
+};
+void LevelsetGrid::join(const LevelsetGrid &o)
+{
+ KnJoin(*this, o);
+}
+
+//! subtract b, note does not preserve SDF!
+struct KnSubtract : public KernelBase {
+ KnSubtract(Grid<Real> &a, const Grid<Real> &b, const FlagGrid *flags, int subtractType)
+ : KernelBase(&a, 0), a(a), b(b), flags(flags), subtractType(subtractType)
+ {
+ runMessage();
+ run();
+ }
+ inline void op(IndexInt idx,
+ Grid<Real> &a,
+ const Grid<Real> &b,
+ const FlagGrid *flags,
+ int subtractType) const
+ {
+ if (flags && ((*flags)(idx)&subtractType) == 0)
+ return;
+ if (b[idx] < 0.)
+ a[idx] = b[idx] * -1.;
+ }
+ inline Grid<Real> &getArg0()
+ {
+ return a;
+ }
+ typedef Grid<Real> type0;
+ inline const Grid<Real> &getArg1()
+ {
+ return b;
+ }
+ typedef Grid<Real> type1;
+ inline const FlagGrid *getArg2()
+ {
+ return flags;
+ }
+ typedef FlagGrid type2;
+ inline int &getArg3()
+ {
+ return subtractType;
+ }
+ typedef int type3;
+ void runMessage()
+ {
+ debMsg("Executing kernel KnSubtract ", 3);
+ debMsg("Kernel range"
+ << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ",
+ 4);
+ };
+ void operator()(const tbb::blocked_range<IndexInt> &__r) const
+ {
+ for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
+ op(idx, a, b, flags, subtractType);
+ }
+ void run()
+ {
+ tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
+ }
+ Grid<Real> &a;
+ const Grid<Real> &b;
+ const FlagGrid *flags;
+ int subtractType;
+};
+void LevelsetGrid::subtract(const LevelsetGrid &o, const FlagGrid *flags, const int subtractType)
+{
+ KnSubtract(*this, o, flags, subtractType);
+}
+
+//! re-init levelset and extrapolate velocities (in & out)
+// note - uses flags to identify border (could also be done based on ls values)
+static void doReinitMarch(Grid<Real> &phi,
+ const FlagGrid &flags,
+ Real maxTime,
+ MACGrid *velTransport,
+ bool ignoreWalls,
+ bool correctOuterLayer,
+ int obstacleType)
+{
+ const int dim = (phi.is3D() ? 3 : 2);
+ Grid<int> fmFlags(phi.getParent());
+
+ FastMarch<FmHeapEntryIn, -1> marchIn(flags, fmFlags, phi, maxTime, NULL);
+
+ // march inside
+ InitFmIn(flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FOR_IJK_BND(flags, 1)
+ {
+ if (fmFlags(i, j, k) == FlagInited)
+ continue;
+ if (ignoreWalls && ((flags(i, j, k) & obstacleType) != 0))
+ continue;
+ const Vec3i p(i, j, k);
+
+ if (isAtInterface<true>(fmFlags, phi, p)) {
+ // set value
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb = 0; nb < 2 * dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0))
+ continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) < 0. && !isAtInterface<true>(fmFlags, phi, pn)) {
+ marchIn.addToList(pn, p);
+ }
+ }
+ }
+ }
+ marchIn.performMarching();
+ // done with inwards marching
+
+ // now march out...
+
+ // set un initialized regions
+ SetUninitialized(flags, fmFlags, phi, -maxTime - 1., ignoreWalls, obstacleType);
+
+ InitFmOut(flags, fmFlags, phi, ignoreWalls, obstacleType);
+
+ FastMarch<FmHeapEntryOut, +1> marchOut(flags, fmFlags, phi, maxTime, velTransport);
+
+ // by default, correctOuterLayer is on
+ if (correctOuterLayer) {
+ // normal version, inwards march is done, now add all outside values (0..2] to list
+ // note, this might move the interface a bit! but keeps a nice signed distance field...
+ FOR_IJK_BND(flags, 1)
+ {
+ if (ignoreWalls && ((flags(i, j, k) & obstacleType) != 0))
+ continue;
+ const Vec3i p(i, j, k);
+
+ // check nbs
+ for (int nb = 0; nb < 2 * dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+
+ if (fmFlags(pn) != FlagInited)
+ continue;
+ if (ignoreWalls && ((flags.get(pn) & obstacleType)) != 0)
+ continue;
+
+ const Real nbPhi = phi(pn);
+
+ // only add nodes near interface, not e.g. outer boundary vs. invalid region
+ if (nbPhi < 0 && nbPhi >= -2)
+ marchOut.addToList(p, pn);
+ }
+ }
+ }
+ else {
+ // alternative version, keep interface, do not distort outer cells
+ // add all ouside values, but not those at the IF layer
+ FOR_IJK_BND(flags, 1)
+ {
+ if (ignoreWalls && ((flags(i, j, k) & obstacleType) != 0))
+ continue;
+
+ // only look at ouside values
+ const Vec3i p(i, j, k);
+ if (phi(p) < 0)
+ continue;
+
+ if (isAtInterface<false>(fmFlags, phi, p)) {
+ // now add all non, interface neighbors
+ fmFlags(p) = FlagInited;
+
+ // add neighbors that are not at the interface
+ for (int nb = 0; nb < 2 * dim; nb++) {
+ const Vec3i pn(p + neighbors[nb]); // index always valid due to bnd=1
+ if (ignoreWalls && ((flags.get(pn) & obstacleType) != 0))
+ continue;
+
+ // check neighbors of neighbor
+ if (phi(pn) > 0. && !isAtInterface<false>(fmFlags, phi, pn)) {
+ marchOut.addToList(pn, p);
+ }
+ }
+ }
+ }
+ }
+ marchOut.performMarching();
+
+ // set un initialized regions
+ SetUninitialized(flags, fmFlags, phi, +maxTime + 1., ignoreWalls, obstacleType);
+}
+
+//! call for levelset grids & external real grids
+
+void LevelsetGrid::reinitMarching(const FlagGrid &flags,
+ Real maxTime,
+ MACGrid *velTransport,
+ bool ignoreWalls,
+ bool correctOuterLayer,
+ int obstacleType)
+{
+ doReinitMarch(*this, flags, maxTime, velTransport, ignoreWalls, correctOuterLayer, obstacleType);
+}
+
+void LevelsetGrid::initFromFlags(const FlagGrid &flags, bool ignoreWalls)
+{
+ FOR_IDX(*this)
+ {
+ if (flags.isFluid(idx) || (ignoreWalls && flags.isObstacle(idx)))
+ mData[idx] = -0.5;
+ else
+ mData[idx] = 0.5;
+ }
+}
+
+void LevelsetGrid::fillHoles(int maxDepth, int boundaryWidth)
+{
+ Real curVal, i1, i2, j1, j2, k1, k2;
+ Vec3i c, cTmp;
+ std::stack<Vec3i> undoPos;
+ std::stack<Real> undoVal;
+ std::stack<Vec3i> todoPos;
+
+ FOR_IJK_BND(*this, boundaryWidth)
+ {
+
+ curVal = mData[index(i, j, k)];
+ i1 = mData[index(i - 1, j, k)];
+ i2 = mData[index(i + 1, j, k)];
+ j1 = mData[index(i, j - 1, k)];
+ j2 = mData[index(i, j + 1, k)];
+ k1 = mData[index(i, j, k - 1)];
+ k2 = mData[index(i, j, k + 1)];
+
+ /* Skip cells inside and cells outside with no inside neighbours early */
+ if (curVal < 0.)
+ continue;
+ if (curVal > 0. && i1 > 0. && i2 > 0. && j1 > 0. && j2 > 0. && k1 > 0. && k2 > 0.)
+ continue;
+
+ /* Cell at c is positive (outside) and has at least one negative (inside) neighbour cell */
+ c = Vec3i(i, j, k);
+
+ /* Current cell is outside and has inside neighbour(s) */
+ undoPos.push(c);
+ undoVal.push(curVal);
+ todoPos.push(c);
+
+ /* Enforce negative cell - if search depth gets exceeded this will be reverted to the original
+ * value */
+ mData[index(c.x, c.y, c.z)] = -0.5;
+
+ while (!todoPos.empty()) {
+ todoPos.pop();
+
+ /* Add neighbouring positive (inside) cells to stacks and set negavtive cell value */
+ if (c.x > 0 && mData[index(c.x - 1, c.y, c.z)] > 0.) {
+ cTmp = Vec3i(c.x - 1, c.y, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.y > 0 && mData[index(c.x, c.y - 1, c.z)] > 0.) {
+ cTmp = Vec3i(c.x, c.y - 1, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.z > 0 && mData[index(c.x, c.y, c.z - 1)] > 0.) {
+ cTmp = Vec3i(c.x, c.y, c.z - 1);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.x < (*this).getSizeX() - 1 && mData[index(c.x + 1, c.y, c.z)] > 0.) {
+ cTmp = Vec3i(c.x + 1, c.y, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.y < (*this).getSizeY() - 1 && mData[index(c.x, c.y + 1, c.z)] > 0.) {
+ cTmp = Vec3i(c.x, c.y + 1, c.z);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+ if (c.z < (*this).getSizeZ() - 1 && mData[index(c.x, c.y, c.z + 1)] > 0.) {
+ cTmp = Vec3i(c.x, c.y, c.z + 1);
+ undoPos.push(cTmp);
+ undoVal.push(mData[index(cTmp)]);
+ todoPos.push(cTmp);
+ mData[index(cTmp)] = -0.5;
+ }
+
+ /* Restore original value in cells if undo needed ie once cell undo count exceeds given limit
+ */
+ if (undoPos.size() > maxDepth) {
+ /* Clear todo stack */
+ while (!todoPos.empty()) {
+ todoPos.pop();
+ }
+ /* Clear undo stack and revert value */
+ while (!undoPos.empty()) {
+ c = undoPos.top();
+ curVal = undoVal.top();
+ undoPos.pop();
+ undoVal.pop();
+ mData[index(c.x, c.y, c.z)] = curVal;
+ }
+ break;
+ }
+
+ /* Ensure that undo stack is cleared at the end if no more items in todo stack left */
+ if (todoPos.empty()) {
+ while (!undoPos.empty()) {
+ undoPos.pop();
+ }
+ while (!undoVal.empty()) {
+ undoVal.pop();
+ }
+ }
+ /* Pop value for next while iteration */
+ else {
+ c = todoPos.top();
+ }
+ }
+ }
+}
+
+//! run marching cubes to create a mesh for the 0-levelset
+void LevelsetGrid::createMesh(Mesh &mesh)
+{
+ assertMsg(is3D(), "Only 3D grids supported so far");
+
+ mesh.clear();
+
+ const Real invalidTime = invalidTimeValue();
+ const Real isoValue = 1e-4;
+
+ // create some temp grids
+ Grid<int> edgeVX(mParent);
+ Grid<int> edgeVY(mParent);
+ Grid<int> edgeVZ(mParent);
+
+ for (int i = 0; i < mSize.x - 1; i++)
+ for (int j = 0; j < mSize.y - 1; j++)
+ for (int k = 0; k < mSize.z - 1; k++) {
+ Real value[8] = {get(i, j, k),
+ get(i + 1, j, k),
+ get(i + 1, j + 1, k),
+ get(i, j + 1, k),
+ get(i, j, k + 1),
+ get(i + 1, j, k + 1),
+ get(i + 1, j + 1, k + 1),
+ get(i, j + 1, k + 1)};
+
+ // build lookup index, check for invalid times
+ bool skip = false;
+ int cubeIdx = 0;
+ for (int l = 0; l < 8; l++) {
+ value[l] *= -1;
+ if (-value[l] <= invalidTime)
+ skip = true;
+ if (value[l] < isoValue)
+ cubeIdx |= 1 << l;
+ }
+ if (skip || (mcEdgeTable[cubeIdx] == 0))
+ continue;
+
+ // where to look up if this point already exists
+ int triIndices[12];
+ int *eVert[12] = {&edgeVX(i, j, k),
+ &edgeVY(i + 1, j, k),
+ &edgeVX(i, j + 1, k),
+ &edgeVY(i, j, k),
+ &edgeVX(i, j, k + 1),
+ &edgeVY(i + 1, j, k + 1),
+ &edgeVX(i, j + 1, k + 1),
+ &edgeVY(i, j, k + 1),
+ &edgeVZ(i, j, k),
+ &edgeVZ(i + 1, j, k),
+ &edgeVZ(i + 1, j + 1, k),
+ &edgeVZ(i, j + 1, k)};
+
+ const Vec3 pos[9] = {Vec3(i, j, k),
+ Vec3(i + 1, j, k),
+ Vec3(i + 1, j + 1, k),
+ Vec3(i, j + 1, k),
+ Vec3(i, j, k + 1),
+ Vec3(i + 1, j, k + 1),
+ Vec3(i + 1, j + 1, k + 1),
+ Vec3(i, j + 1, k + 1)};
+
+ for (int e = 0; e < 12; e++) {
+ if (mcEdgeTable[cubeIdx] & (1 << e)) {
+ // vertex already calculated ?
+ if (*eVert[e] == 0) {
+ // interpolate edge
+ const int e1 = mcEdges[e * 2];
+ const int e2 = mcEdges[e * 2 + 1];
+ const Vec3 p1 = pos[e1]; // scalar field pos 1
+ const Vec3 p2 = pos[e2]; // scalar field pos 2
+ const float valp1 = value[e1]; // scalar field val 1
+ const float valp2 = value[e2]; // scalar field val 2
+ const float mu = (isoValue - valp1) / (valp2 - valp1);
+
+ // init isolevel vertex
+ Node vertex;
+ vertex.pos = p1 + (p2 - p1) * mu + Vec3(Real(0.5));
+ vertex.normal = getNormalized(
+ getGradient(
+ *this, i + cubieOffsetX[e1], j + cubieOffsetY[e1], k + cubieOffsetZ[e1]) *
+ (1.0 - mu) +
+ getGradient(
+ *this, i + cubieOffsetX[e2], j + cubieOffsetY[e2], k + cubieOffsetZ[e2]) *
+ (mu));
+
+ triIndices[e] = mesh.addNode(vertex) + 1;
+
+ // store vertex
+ *eVert[e] = triIndices[e];
+ }
+ else {
+ // retrieve from vert array
+ triIndices[e] = *eVert[e];
+ }
+ }
+ }
+
+ // Create the triangles...
+ for (int e = 0; mcTriTable[cubeIdx][e] != -1; e += 3) {
+ mesh.addTri(Triangle(triIndices[mcTriTable[cubeIdx][e + 0]] - 1,
+ triIndices[mcTriTable[cubeIdx][e + 1]] - 1,
+ triIndices[mcTriTable[cubeIdx][e + 2]] - 1));
+ }
+ }
+
+ // mesh.rebuildCorners();
+ // mesh.rebuildLookup();
+
+ // Update mdata fields
+ mesh.updateDataFields();
+}
+
+} // namespace Manta