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:
authorRafael Campos <rafaelcdn@gmail.com>2014-04-30 23:47:09 +0400
committerRafael Campos <rafaelcdn@gmail.com>2014-04-30 23:47:09 +0400
commit724750f47d836df1e71a538283e1c99f4e69f8fc (patch)
treeda5eb3fa7e0672cfee75e0b779848e0f7a85ef82 /extern/openvdb/internal/openvdb/tools/VolumeToMesh.h
parent155805b20959a7a41eb7e4fbbc4c5fad4c546869 (diff)
Updated OpenVDB library to 2.3.0;soc-2013-cycles_volume
Diffstat (limited to 'extern/openvdb/internal/openvdb/tools/VolumeToMesh.h')
-rw-r--r--extern/openvdb/internal/openvdb/tools/VolumeToMesh.h4875
1 files changed, 3432 insertions, 1443 deletions
diff --git a/extern/openvdb/internal/openvdb/tools/VolumeToMesh.h b/extern/openvdb/internal/openvdb/tools/VolumeToMesh.h
index 78b4d6c8066..ef0f39c7f17 100644
--- a/extern/openvdb/internal/openvdb/tools/VolumeToMesh.h
+++ b/extern/openvdb/internal/openvdb/tools/VolumeToMesh.h
@@ -31,25 +31,32 @@
#ifndef OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
#define OPENVDB_TOOLS_VOLUME_TO_MESH_HAS_BEEN_INCLUDED
+#include <openvdb/Platform.h> // for OPENVDB_HAS_CXX11
#include <openvdb/tree/ValueAccessor.h>
#include <openvdb/util/Util.h> // for COORD_OFFSETS
#include <openvdb/math/Operators.h> // for ISGradient
#include <openvdb/tools/Morphology.h> // for dilateVoxels()
+#include <openvdb/tree/LeafManager.h>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
-
#include <tbb/blocked_range.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_reduce.h>
#include <vector>
+#include <memory> // for auto_ptr/unique_ptr
+
+
+//////////
+
namespace openvdb {
OPENVDB_USE_VERSION_NAMESPACE
namespace OPENVDB_VERSION_NAME {
namespace tools {
+
////////////////////////////////////////
@@ -94,71 +101,60 @@ volumeToMesh(
/// @brief Polygon flags, used for reference based meshing.
-enum {
- POLYFLAG_EXTERIOR = 0x1, POLYFLAG_FRACTURE_SEAM = 0x2
-};
+enum { POLYFLAG_EXTERIOR = 0x1, POLYFLAG_FRACTURE_SEAM = 0x2, POLYFLAG_SUBDIVIDED = 0x4};
/// @brief Collection of quads and triangles
class PolygonPool
{
public:
- PolygonPool()
- : mNumQuads(0)
- , mNumTriangles(0)
- , mQuads(NULL)
- , mTriangles(NULL)
- , mQuadFlags(NULL)
- , mTriangleFlags(NULL)
- {
- }
- void resetQuads(size_t size)
- {
- mNumQuads = size;
- mQuads.reset(new openvdb::Vec4I[mNumQuads]);
- mQuadFlags.reset(new char[mNumQuads]);
- }
+ inline PolygonPool();
+ inline PolygonPool(const size_t numQuads, const size_t numTriangles);
- void clearQuads()
- {
- mNumQuads = 0;
- mQuads.reset(NULL);
- mQuadFlags.reset(NULL);
- }
- void resetTriangles(size_t size)
- {
- mNumTriangles = size;
- mTriangles.reset(new openvdb::Vec3I[mNumTriangles]);
- mTriangleFlags.reset(new char[mNumTriangles]);
- }
+ inline void copy(const PolygonPool& rhs);
- void clearTriangles()
- {
- mNumTriangles = 0;
- mTriangles.reset(NULL);
- mTriangleFlags.reset(NULL);
- }
+ inline void resetQuads(size_t size);
+ inline void clearQuads();
+
+ inline void resetTriangles(size_t size);
+ inline void clearTriangles();
- const size_t& numQuads() const { return mNumQuads; }
- const size_t& numTriangles() const { return mNumTriangles; }
// polygon accessor methods
- openvdb::Vec4I& quad(size_t n) { return mQuads[n]; }
- const openvdb::Vec4I& quad(size_t n) const { return mQuads[n]; }
- openvdb::Vec3I& triangle(size_t n) { return mTriangles[n]; }
- const openvdb::Vec3I& triangle(size_t n) const { return mTriangles[n]; }
+ const size_t& numQuads() const { return mNumQuads; }
+
+ openvdb::Vec4I& quad(size_t n) { return mQuads[n]; }
+ const openvdb::Vec4I& quad(size_t n) const { return mQuads[n]; }
+
+
+ const size_t& numTriangles() const { return mNumTriangles; }
+
+ openvdb::Vec3I& triangle(size_t n) { return mTriangles[n]; }
+ const openvdb::Vec3I& triangle(size_t n) const { return mTriangles[n]; }
+
// polygon flags accessor methods
- char& quadFlags(size_t n) { return mQuadFlags[n]; }
- const char& quadFlags(size_t n) const { return mQuadFlags[n]; }
- char& triangleFlags(size_t n) { return mTriangleFlags[n]; }
- const char& triangleFlags(size_t n) const { return mTriangleFlags[n]; }
+ char& quadFlags(size_t n) { return mQuadFlags[n]; }
+ const char& quadFlags(size_t n) const { return mQuadFlags[n]; }
+
+ char& triangleFlags(size_t n) { return mTriangleFlags[n]; }
+ const char& triangleFlags(size_t n) const { return mTriangleFlags[n]; }
+
+
+ // reduce the polygon containers, n has to
+ // be smaller than the current container size.
+
+ inline bool trimQuads(const size_t n, bool reallocate = false);
+ inline bool trimTrinagles(const size_t n, bool reallocate = false);
private:
+ // disallow copy by assignment
+ void operator=(const PolygonPool&) {}
+
size_t mNumQuads, mNumTriangles;
boost::scoped_array<openvdb::Vec4I> mQuads;
boost::scoped_array<openvdb::Vec3I> mTriangles;
@@ -180,23 +176,39 @@ typedef boost::scoped_array<PolygonPool> PolygonPoolList;
class VolumeToMesh
{
public:
+
/// @param isovalue Determines which isosurface to mesh.
/// @param adaptivity Adaptivity threshold [0 to 1]
VolumeToMesh(double isovalue = 0, double adaptivity = 0);
- PointList& pointList();
+
+ //////////
+
+ // Mesh data accessors
+
const size_t& pointListSize() const;
+ PointList& pointList();
+ const size_t& polygonPoolListSize() const;
PolygonPoolList& polygonPoolList();
const PolygonPoolList& polygonPoolList() const;
- const size_t& polygonPoolListSize() const;
- /// @brief main call
+ std::vector<unsigned char>& pointFlags();
+ const std::vector<unsigned char>& pointFlags() const;
+
+
+ //////////
+
+
+ /// @brief Main call
/// @note Call with scalar typed grid.
template<typename GridT>
void operator()(const GridT&);
+ //////////
+
+
/// @brief When surfacing fractured SDF fragments, the original unfractured
/// SDF grid can be used to eliminate seam lines and tag polygons that are
/// coincident with the reference surface with the @c POLYFLAG_EXTERIOR
@@ -218,93 +230,452 @@ public:
/// that do not exist in the reference grid. (Parts of the
/// fragment surface that are not coincident with the
/// reference surface.)
- /// @param smoothSeams toggle to smooth seam line edges during mesh extraction,
- /// removes staircase artifacts.
- void setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity = 0, bool smoothSeams = true);
+ void setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity = 0);
+
+
+ /// @param mask A boolean grid whose active topology defines the region to mesh.
+ /// @param invertMask Toggle to mesh the complement of the mask.
+ /// @note The mask's tree configuration has to match @c GridT's tree configuration.
+ void setSurfaceMask(const GridBase::ConstPtr& mask, bool invertMask = false);
+
+ /// @param grid A scalar grid used as an spatial multiplier for the adaptivity threshold.
+ /// @note The grid's tree configuration has to match @c GridT's tree configuration.
+ void setSpatialAdaptivity(const GridBase::ConstPtr& grid);
+
+
+ /// @param tree A boolean tree whose active topology defines the adaptivity mask.
+ /// @note The tree configuration has to match @c GridT's tree configuration.
+ void setAdaptivityMask(const TreeBase::ConstPtr& tree);
+
+
+ /// @brief Subdivide volume and mesh into disjoint parts
+ /// @param partitions Number of partitions.
+ /// @param activePart Specific partition to mesh, 0 to @c partitions - 1.
+ void partition(unsigned partitions = 1, unsigned activePart = 0);
private:
PointList mPoints;
PolygonPoolList mPolygons;
- size_t mPointListSize, mPolygonPoolListSize;
+ size_t mPointListSize, mSeamPointListSize, mPolygonPoolListSize;
double mIsovalue, mPrimAdaptivity, mSecAdaptivity;
- GridBase::ConstPtr mRefGrid;
- TreeBase::Ptr mRefEdgeTree, mRefTopologyMaskTree, mSeamPointTree;
- bool mSmoothSeams;
+ GridBase::ConstPtr mRefGrid, mSurfaceMaskGrid, mAdaptivityGrid;
+ TreeBase::ConstPtr mAdaptivityMaskTree;
+
+ TreeBase::Ptr mRefSignTree, mRefIdxTree;
+
+ bool mInvertSurfaceMask;
+ unsigned mPartitions, mActivePart;
+
+ boost::scoped_array<uint32_t> mQuantizedSeamPoints;
+
+ std::vector<unsigned char> mPointFlags;
};
////////////////////////////////////////
-// Internal utility methods
+/// @brief Given a set of tangent elements, @c points with corresponding @c normals,
+/// this method returns the intersection point of all tangent elements.
+///
+/// @note Used to extract surfaces with sharp edges and corners from volume data,
+/// see the following paper for details: "Feature Sensitive Surface
+/// Extraction from Volume Data, Kobbelt et al. 2001".
+inline Vec3d findFeaturePoint(
+ const std::vector<Vec3d>& points,
+ const std::vector<Vec3d>& normals)
+{
+ typedef math::Mat3d Mat3d;
+
+ Vec3d avgPos(0.0);
+
+ if (points.empty()) return avgPos;
+
+ for (size_t n = 0, N = points.size(); n < N; ++n) {
+ avgPos += points[n];
+ }
+
+ avgPos /= double(points.size());
+
+ // Unique components of the 3x3 A^TA matrix, where A is
+ // the matrix of normals.
+ double m00=0,m01=0,m02=0,
+ m11=0,m12=0,
+ m22=0;
+
+ // The rhs vector, A^Tb, where b = n dot p
+ Vec3d rhs(0.0);
+
+ for (size_t n = 0, N = points.size(); n < N; ++n) {
+
+ const Vec3d& n_ref = normals[n];
+
+ // A^TA
+ m00 += n_ref[0] * n_ref[0]; // diagonal
+ m11 += n_ref[1] * n_ref[1];
+ m22 += n_ref[2] * n_ref[2];
+
+ m01 += n_ref[0] * n_ref[1]; // Upper-tri
+ m02 += n_ref[0] * n_ref[2];
+ m12 += n_ref[1] * n_ref[2];
+
+ // A^Tb (centered around the origin)
+ rhs += n_ref * n_ref.dot(points[n] - avgPos);
+ }
+
+ Mat3d A(m00,m01,m02,
+ m01,m11,m12,
+ m02,m12,m22);
+ /*
+ // Inverse
+ const double det = A.det();
+ if (det > 0.01) {
+ Mat3d A_inv = A.adjoint();
+ A_inv *= (1.0 / det);
+ return avgPos + A_inv * rhs;
+ }
+ */
+
+ // Compute the pseudo inverse
+
+ math::Mat3d eigenVectors;
+ Vec3d eigenValues;
+
+ diagonalizeSymmetricMatrix(A, eigenVectors, eigenValues, 300);
+
+ Mat3d D = Mat3d::identity();
+
+
+ double tolerance = std::max(std::abs(eigenValues[0]), std::abs(eigenValues[1]));
+ tolerance = std::max(tolerance, std::abs(eigenValues[2]));
+ tolerance *= 0.01;
+
+ int clamped = 0;
+ for (int i = 0; i < 3; ++i ) {
+ if (std::abs(eigenValues[i]) < tolerance) {
+ D[i][i] = 0.0;
+ ++clamped;
+ } else {
+ D[i][i] = 1.0 / eigenValues[i];
+ }
+ }
+
+ // Assemble the pseudo inverse and calc. the intersection point
+ if (clamped < 3) {
+ Mat3d pseudoInv = eigenVectors * D * eigenVectors.transpose();
+ return avgPos + pseudoInv * rhs;
+ }
+
+ return avgPos;
+}
+
+
+////////////////////////////////////////
+
+
+// Internal utility methods
namespace internal {
+template<typename T>
+struct UniquePtr
+{
+#ifdef OPENVDB_HAS_CXX11
+ typedef std::unique_ptr<T> type;
+#else
+ typedef std::auto_ptr<T> type;
+#endif
+};
+
-// Bit-flags
-enum { INSIDE = 0x1, XEDGE = 0x2, YEDGE = 0x4, ZEDGE = 0x8 };
-
-const bool sAmbiguous[256] =
- {0,0,0,0,0,1,0,0,
- 0,0,1,0,0,0,0,0,
- 0,0,1,0,1,1,1,0,
- 1,0,1,0,1,0,1,0,
- 0,1,0,0,1,1,0,0,
- 1,1,1,0,1,1,0,0,
- 0,0,0,0,1,1,0,0,
- 1,0,1,0,1,1,1,0,
- 0,1,1,1,0,1,0,0,
- 1,1,1,1,0,0,0,0,
- 1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,
- 0,1,0,0,0,1,0,0,
- 1,1,1,1,0,1,0,0,
- 0,0,0,0,0,1,0,0,
- 1,1,1,1,1,1,1,0,
- 0,1,1,1,1,1,1,1,
- 0,0,1,0,0,0,0,0,
- 0,0,1,0,1,1,1,1,
- 0,0,1,0,0,0,1,0,
- 1,1,1,1,1,1,1,1,
- 1,1,1,1,1,1,1,1,
- 0,0,0,0,1,1,1,1,
- 0,0,1,0,1,1,1,0,
- 0,1,1,1,0,1,0,1,
- 0,0,1,1,0,0,0,0,
- 0,0,1,1,0,1,1,1,
- 0,0,1,1,0,0,1,0,
- 0,1,0,1,0,1,0,1,
- 0,1,1,1,0,1,0,0,
- 0,0,0,0,0,1,0,0,
- 0,0,1,0,0,0,0,0};
+/// @brief Bit-flags used to classify cells.
+enum { SIGNS = 0xFF, EDGES = 0xE00, INSIDE = 0x100,
+ XEDGE = 0x200, YEDGE = 0x400, ZEDGE = 0x800, SEAM = 0x1000};
+
+
+/// @brief Used to quickly determine if a given cell is adaptable.
+const bool sAdaptable[256] = {
+ 1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,1,0,1,0,1,0,1,0,1,
+ 1,0,1,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,0,1,
+ 1,0,0,0,1,0,1,1,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,0,1,1,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,1,
+ 1,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1,1,0,1,0,0,0,0,1,1,0,1,1,1,0,1,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,1,1,0,1,0,0,0,1,
+ 1,0,0,0,1,0,1,0,1,1,0,0,1,1,1,1,1,1,0,0,1,0,0,0,1,1,0,0,1,1,0,1,
+ 1,0,1,0,1,0,1,0,1,0,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,0,1,1,1,1,1};
+
+
+/// @brief Contains the ambiguous face index for certain cell configuration.
+const unsigned char sAmbiguousFace[256] = {
+ 0,0,0,0,0,5,0,0,0,0,5,0,0,0,0,0,0,0,1,0,0,5,1,0,4,0,0,0,4,0,0,0,
+ 0,1,0,0,2,0,0,0,0,1,5,0,2,0,0,0,0,0,0,0,2,0,0,0,4,0,0,0,0,0,0,0,
+ 0,0,2,2,0,5,0,0,3,3,0,0,0,0,0,0,6,6,0,0,6,0,0,0,0,0,0,0,0,0,0,0,
+ 0,1,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,4,0,4,3,0,3,0,0,0,5,0,0,0,0,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,
+ 6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+
+/// @brief Lookup table for different cell sign configurations. The first entry specifies
+/// the total number of points that need to be generated inside a cell and the
+/// remaining 12 entries indicate different edge groups.
+const unsigned char sEdgeGroupTable[256][13] = {
+ {0,0,0,0,0,0,0,0,0,0,0,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0},
+ {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,0,1,1,0,0,0,0,0,0,0,1,0},{1,1,1,1,1,0,0,0,0,1,0,1,0},
+ {1,1,0,1,0,0,0,0,0,0,1,1,0},{1,0,0,1,1,0,0,0,0,1,1,1,0},{1,0,0,1,1,0,0,0,0,0,0,0,1},
+ {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,1,1,1,1,0,0,0,0,0,1,0,1},{1,0,1,1,0,0,0,0,0,1,1,0,1},
+ {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1},
+ {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,0,0,0,0,1,0,0,1,1,0,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0},
+ {1,1,1,0,0,1,0,0,1,1,1,0,0},{1,0,1,0,1,1,0,0,1,0,1,0,0},{2,0,1,1,0,2,0,0,2,2,0,1,0},
+ {1,1,1,1,1,1,0,0,1,0,0,1,0},{1,1,0,1,0,1,0,0,1,1,1,1,0},{1,0,0,1,1,1,0,0,1,0,1,1,0},
+ {1,0,0,1,1,1,0,0,1,1,0,0,1},{1,1,0,1,0,1,0,0,1,0,0,0,1},{2,2,1,1,2,1,0,0,1,2,1,0,1},
+ {1,0,1,1,0,1,0,0,1,0,1,0,1},{1,0,1,0,1,1,0,0,1,1,0,1,1},{1,1,1,0,0,1,0,0,1,0,0,1,1},
+ {2,1,0,0,1,2,0,0,2,1,2,2,2},{1,0,0,0,0,1,0,0,1,0,1,1,1},{1,0,0,0,0,1,1,0,0,0,1,0,0},
+ {1,1,0,0,1,1,1,0,0,1,1,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0},{1,0,1,0,1,1,1,0,0,1,0,0,0},
+ {1,0,1,1,0,1,1,0,0,0,1,1,0},{2,2,2,1,1,1,1,0,0,1,2,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0},
+ {1,0,0,1,1,1,1,0,0,1,0,1,0},{2,0,0,2,2,1,1,0,0,0,1,0,2},{1,1,0,1,0,1,1,0,0,1,1,0,1},
+ {1,1,1,1,1,1,1,0,0,0,0,0,1},{1,0,1,1,0,1,1,0,0,1,0,0,1},{1,0,1,0,1,1,1,0,0,0,1,1,1},
+ {2,1,1,0,0,2,2,0,0,2,1,2,2},{1,1,0,0,1,1,1,0,0,0,0,1,1},{1,0,0,0,0,1,1,0,0,1,0,1,1},
+ {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0},
+ {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,0,1,1,0,0,1,0,1,1,1,1,0},{2,1,1,2,2,0,2,0,2,0,1,2,0},
+ {1,1,0,1,0,0,1,0,1,1,0,1,0},{1,0,0,1,1,0,1,0,1,0,0,1,0},{1,0,0,1,1,0,1,0,1,1,1,0,1},
+ {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,1,2,2,1,0,2,0,2,1,0,0,2},{1,0,1,1,0,0,1,0,1,0,0,0,1},
+ {2,0,2,0,2,0,1,0,1,2,2,1,1},{2,2,2,0,0,0,1,0,1,0,2,1,1},{2,2,0,0,2,0,1,0,1,2,0,1,1},
+ {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,0,0,0,0,0,1,1,0,0,0,1,0},{2,1,0,0,1,0,2,2,0,1,0,2,0},
+ {1,1,1,0,0,0,1,1,0,0,1,1,0},{1,0,1,0,1,0,1,1,0,1,1,1,0},{1,0,1,1,0,0,1,1,0,0,0,0,0},
+ {1,1,1,1,1,0,1,1,0,1,0,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0},{1,0,0,1,1,0,1,1,0,1,1,0,0},
+ {1,0,0,1,1,0,1,1,0,0,0,1,1},{1,1,0,1,0,0,1,1,0,1,0,1,1},{2,1,2,2,1,0,1,1,0,0,1,2,1},
+ {2,0,1,1,0,0,2,2,0,2,2,1,2},{1,0,1,0,1,0,1,1,0,0,0,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1},
+ {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,0,0,0,0,0,1,1,0,1,1,0,1},{1,0,0,0,0,1,1,1,1,1,0,1,0},
+ {1,1,0,0,1,1,1,1,1,0,0,1,0},{2,1,1,0,0,2,2,1,1,1,2,1,0},{2,0,2,0,2,1,1,2,2,0,1,2,0},
+ {1,0,1,1,0,1,1,1,1,1,0,0,0},{2,2,2,1,1,2,2,1,1,0,0,0,0},{2,2,0,2,0,1,1,2,2,2,1,0,0},
+ {2,0,0,1,1,2,2,1,1,0,2,0,0},{2,0,0,1,1,1,1,2,2,1,0,1,2},{2,2,0,2,0,2,2,1,1,0,0,2,1},
+ {4,3,2,2,3,4,4,1,1,3,4,2,1},{3,0,2,2,0,1,1,3,3,0,1,2,3},{2,0,2,0,2,2,2,1,1,2,0,0,1},
+ {2,1,1,0,0,1,1,2,2,0,0,0,2},{3,1,0,0,1,2,2,3,3,1,2,0,3},{2,0,0,0,0,1,1,2,2,0,1,0,2},
+ {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,1,0,0,1,1,0,1,0,1,1,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0},
+ {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,0,1,1,0,1,0,1,0,0,1,0,0},{2,1,1,2,2,2,0,2,0,2,1,0,0},
+ {1,1,0,1,0,1,0,1,0,0,0,0,0},{1,0,0,1,1,1,0,1,0,1,0,0,0},{1,0,0,1,1,1,0,1,0,0,1,1,1},
+ {2,2,0,2,0,1,0,1,0,1,2,2,1},{2,2,1,1,2,2,0,2,0,0,0,1,2},{2,0,2,2,0,1,0,1,0,1,0,2,1},
+ {1,0,1,0,1,1,0,1,0,0,1,0,1},{2,2,2,0,0,1,0,1,0,1,2,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1},
+ {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,0,0,0,0,0,0,1,1,1,1,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0},
+ {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,0,1,0,1,0,0,1,1,0,0,1,0},{1,0,1,1,0,0,0,1,1,1,1,0,0},
+ {2,2,2,1,1,0,0,1,1,0,2,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0},{1,0,0,1,1,0,0,1,1,0,0,0,0},
+ {2,0,0,2,2,0,0,1,1,2,2,2,1},{2,1,0,1,0,0,0,2,2,0,1,1,2},{3,2,1,1,2,0,0,3,3,2,0,1,3},
+ {2,0,1,1,0,0,0,2,2,0,0,1,2},{2,0,1,0,1,0,0,2,2,1,1,0,2},{2,1,1,0,0,0,0,2,2,0,1,0,2},
+ {2,1,0,0,1,0,0,2,2,1,0,0,2},{1,0,0,0,0,0,0,1,1,0,0,0,1},{1,0,0,0,0,0,0,1,1,0,0,0,1},
+ {1,1,0,0,1,0,0,1,1,1,0,0,1},{2,1,1,0,0,0,0,2,2,0,1,0,2},{1,0,1,0,1,0,0,1,1,1,1,0,1},
+ {1,0,1,1,0,0,0,1,1,0,0,1,1},{2,1,1,2,2,0,0,1,1,1,0,1,2},{1,1,0,1,0,0,0,1,1,0,1,1,1},
+ {2,0,0,1,1,0,0,2,2,2,2,2,1},{1,0,0,1,1,0,0,1,1,0,0,0,0},{1,1,0,1,0,0,0,1,1,1,0,0,0},
+ {1,1,1,1,1,0,0,1,1,0,1,0,0},{1,0,1,1,0,0,0,1,1,1,1,0,0},{1,0,1,0,1,0,0,1,1,0,0,1,0},
+ {1,1,1,0,0,0,0,1,1,1,0,1,0},{1,1,0,0,1,0,0,1,1,0,1,1,0},{1,0,0,0,0,0,0,1,1,1,1,1,0},
+ {1,0,0,0,0,1,0,1,0,1,0,0,1},{1,1,0,0,1,1,0,1,0,0,0,0,1},{1,1,1,0,0,1,0,1,0,1,1,0,1},
+ {1,0,1,0,1,1,0,1,0,0,1,0,1},{1,0,1,1,0,1,0,1,0,1,0,1,1},{2,2,2,1,1,2,0,2,0,0,0,2,1},
+ {2,1,0,1,0,2,0,2,0,1,2,2,1},{2,0,0,2,2,1,0,1,0,0,1,1,2},{1,0,0,1,1,1,0,1,0,1,0,0,0},
+ {1,1,0,1,0,1,0,1,0,0,0,0,0},{2,1,2,2,1,2,0,2,0,1,2,0,0},{1,0,1,1,0,1,0,1,0,0,1,0,0},
+ {1,0,1,0,1,1,0,1,0,1,0,1,0},{1,1,1,0,0,1,0,1,0,0,0,1,0},{2,2,0,0,2,1,0,1,0,2,1,1,0},
+ {1,0,0,0,0,1,0,1,0,0,1,1,0},{1,0,0,0,0,1,1,1,1,0,1,0,1},{2,1,0,0,1,2,1,1,2,2,1,0,1},
+ {1,1,1,0,0,1,1,1,1,0,0,0,1},{2,0,2,0,2,1,2,2,1,1,0,0,2},{2,0,1,1,0,1,2,2,1,0,1,2,1},
+ {4,1,1,3,3,2,4,4,2,2,1,4,3},{2,2,0,2,0,2,1,1,2,0,0,1,2},{3,0,0,1,1,2,3,3,2,2,0,3,1},
+ {1,0,0,1,1,1,1,1,1,0,1,0,0},{2,2,0,2,0,1,2,2,1,1,2,0,0},{2,2,1,1,2,2,1,1,2,0,0,0,0},
+ {2,0,1,1,0,2,1,1,2,2,0,0,0},{2,0,2,0,2,2,1,1,2,0,2,1,0},{3,1,1,0,0,3,2,2,3,3,1,2,0},
+ {2,1,0,0,1,1,2,2,1,0,0,2,0},{2,0,0,0,0,2,1,1,2,2,0,1,0},{1,0,0,0,0,0,1,1,0,1,1,0,1},
+ {1,1,0,0,1,0,1,1,0,0,1,0,1},{1,1,1,0,0,0,1,1,0,1,0,0,1},{1,0,1,0,1,0,1,1,0,0,0,0,1},
+ {2,0,2,2,0,0,1,1,0,2,2,1,2},{3,1,1,2,2,0,3,3,0,0,1,3,2},{2,1,0,1,0,0,2,2,0,1,0,2,1},
+ {2,0,0,1,1,0,2,2,0,0,0,2,1},{1,0,0,1,1,0,1,1,0,1,1,0,0},{1,1,0,1,0,0,1,1,0,0,1,0,0},
+ {2,2,1,1,2,0,1,1,0,2,0,0,0},{1,0,1,1,0,0,1,1,0,0,0,0,0},{2,0,1,0,1,0,2,2,0,1,1,2,0},
+ {2,1,1,0,0,0,2,2,0,0,1,2,0},{2,1,0,0,1,0,2,2,0,1,0,2,0},{1,0,0,0,0,0,1,1,0,0,0,1,0},
+ {1,0,0,0,0,0,1,0,1,0,0,1,1},{1,1,0,0,1,0,1,0,1,1,0,1,1},{1,1,1,0,0,0,1,0,1,0,1,1,1},
+ {2,0,2,0,2,0,1,0,1,1,1,2,2},{1,0,1,1,0,0,1,0,1,0,0,0,1},{2,2,2,1,1,0,2,0,2,2,0,0,1},
+ {1,1,0,1,0,0,1,0,1,0,1,0,1},{2,0,0,2,2,0,1,0,1,1,1,0,2},{1,0,0,1,1,0,1,0,1,0,0,1,0},
+ {1,1,0,1,0,0,1,0,1,1,0,1,0},{2,2,1,1,2,0,2,0,2,0,2,1,0},{2,0,2,2,0,0,1,0,1,1,1,2,0},
+ {1,0,1,0,1,0,1,0,1,0,0,0,0},{1,1,1,0,0,0,1,0,1,1,0,0,0},{1,1,0,0,1,0,1,0,1,0,1,0,0},
+ {1,0,0,0,0,0,1,0,1,1,1,0,0},{1,0,0,0,0,1,1,0,0,1,0,1,1},{1,1,0,0,1,1,1,0,0,0,0,1,1},
+ {2,2,2,0,0,1,1,0,0,2,1,2,2},{2,0,1,0,1,2,2,0,0,0,2,1,1},{1,0,1,1,0,1,1,0,0,1,0,0,1},
+ {2,1,1,2,2,1,1,0,0,0,0,0,2},{2,1,0,1,0,2,2,0,0,1,2,0,1},{2,0,0,2,2,1,1,0,0,0,1,0,2},
+ {1,0,0,1,1,1,1,0,0,1,0,1,0},{1,1,0,1,0,1,1,0,0,0,0,1,0},{3,1,2,2,1,3,3,0,0,1,3,2,0},
+ {2,0,1,1,0,2,2,0,0,0,2,1,0},{1,0,1,0,1,1,1,0,0,1,0,0,0},{1,1,1,0,0,1,1,0,0,0,0,0,0},
+ {2,2,0,0,2,1,1,0,0,2,1,0,0},{1,0,0,0,0,1,1,0,0,0,1,0,0},{1,0,0,0,0,1,0,0,1,0,1,1,1},
+ {2,2,0,0,2,1,0,0,1,1,2,2,2},{1,1,1,0,0,1,0,0,1,0,0,1,1},{2,0,1,0,1,2,0,0,2,2,0,1,1},
+ {1,0,1,1,0,1,0,0,1,0,1,0,1},{3,1,1,3,3,2,0,0,2,2,1,0,3},{1,1,0,1,0,1,0,0,1,0,0,0,1},
+ {2,0,0,2,2,1,0,0,1,1,0,0,2},{1,0,0,1,1,1,0,0,1,0,1,1,0},{2,1,0,1,0,2,0,0,2,2,1,1,0},
+ {2,1,2,2,1,1,0,0,1,0,0,2,0},{2,0,1,1,0,2,0,0,2,2,0,1,0},{1,0,1,0,1,1,0,0,1,0,1,0,0},
+ {2,1,1,0,0,2,0,0,2,2,1,0,0},{1,1,0,0,1,1,0,0,1,0,0,0,0},{1,0,0,0,0,1,0,0,1,1,0,0,0},
+ {1,0,0,0,0,0,0,0,0,1,1,1,1},{1,1,0,0,1,0,0,0,0,0,1,1,1},{1,1,1,0,0,0,0,0,0,1,0,1,1},
+ {1,0,1,0,1,0,0,0,0,0,0,1,1},{1,0,1,1,0,0,0,0,0,1,1,0,1},{2,1,1,2,2,0,0,0,0,0,1,0,2},
+ {1,1,0,1,0,0,0,0,0,1,0,0,1},{1,0,0,1,1,0,0,0,0,0,0,0,1},{1,0,0,1,1,0,0,0,0,1,1,1,0},
+ {1,1,0,1,0,0,0,0,0,0,1,1,0},{2,1,2,2,1,0,0,0,0,1,0,2,0},{1,0,1,1,0,0,0,0,0,0,0,1,0},
+ {1,0,1,0,1,0,0,0,0,1,1,0,0},{1,1,1,0,0,0,0,0,0,0,1,0,0},{1,1,0,0,1,0,0,0,0,1,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0}};
-template<class AccessorT>
-inline bool isAmbiguous(const AccessorT& accessor, const Coord& ijk,
- typename AccessorT::ValueType isovalue, int dim)
+////////////////////////////////////////
+
+inline bool
+isPlanarQuad(
+ const Vec3d& p0, const Vec3d& p1,
+ const Vec3d& p2, const Vec3d& p3,
+ double epsilon = 0.001)
+{
+ // compute representative plane
+ Vec3d normal = (p2-p0).cross(p1-p3);
+ normal.normalize();
+ const Vec3d centroid = (p0 + p1 + p2 + p3);
+ const double d = centroid.dot(normal) * 0.25;
+
+
+ // test vertice distance to plane
+ double absDist = std::abs(p0.dot(normal) - d);
+ if (absDist > epsilon) return false;
+
+ absDist = std::abs(p1.dot(normal) - d);
+ if (absDist > epsilon) return false;
+
+ absDist = std::abs(p2.dot(normal) - d);
+ if (absDist > epsilon) return false;
+
+ absDist = std::abs(p3.dot(normal) - d);
+ if (absDist > epsilon) return false;
+
+ return true;
+}
+
+
+////////////////////////////////////////
+
+
+/// @{
+/// @brief Utility methods for point quantization.
+
+enum { MASK_FIRST_10_BITS = 0x000003FF, MASK_DIRTY_BIT = 0x80000000, MASK_INVALID_BIT = 0x40000000 };
+
+inline uint32_t
+packPoint(const Vec3d& v)
+{
+ uint32_t data = 0;
+
+ // values are expected to be in the [0.0 to 1.0] range.
+ assert(!(v.x() > 1.0) && !(v.y() > 1.0) && !(v.z() > 1.0));
+ assert(!(v.x() < 0.0) && !(v.y() < 0.0) && !(v.z() < 0.0));
+
+ data |= (uint32_t(v.x() * 1023.0) & MASK_FIRST_10_BITS) << 20;
+ data |= (uint32_t(v.y() * 1023.0) & MASK_FIRST_10_BITS) << 10;
+ data |= (uint32_t(v.z() * 1023.0) & MASK_FIRST_10_BITS);
+
+ return data;
+}
+
+inline Vec3d
+unpackPoint(uint32_t data)
+{
+ Vec3d v;
+ v.z() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
+ data = data >> 10;
+ v.y() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
+ data = data >> 10;
+ v.x() = double(data & MASK_FIRST_10_BITS) * 0.0009775171;
+
+ return v;
+}
+
+/// @}
+
+////////////////////////////////////////
+
+
+/// @brief General method that computes the cell-sign configuration at the given
+/// @c ijk coordinate.
+template<typename AccessorT>
+inline unsigned char
+evalCellSigns(const AccessorT& accessor, const Coord& ijk, typename AccessorT::ValueType iso)
{
unsigned signs = 0;
Coord coord = ijk; // i, j, k
- if (accessor.getValue(coord) < isovalue) signs |= 1u;
- coord[0] += dim; // i+dim, j, k
- if (accessor.getValue(coord) < isovalue) signs |= 2u;
- coord[2] += dim; // i+dim, j, k+dim
- if (accessor.getValue(coord) < isovalue) signs |= 4u;
- coord[0] = ijk[0]; // i, j, k+dim
- if (accessor.getValue(coord) < isovalue) signs |= 8u;
- coord[1] += dim; coord[2] = ijk[2]; // i, j+dim, k
- if (accessor.getValue(coord) < isovalue) signs |= 16u;
- coord[0] += dim; // i+dim, j+dim, k
- if (accessor.getValue(coord) < isovalue) signs |= 32u;
- coord[2] += dim; // i+dim, j+dim, k+dim
- if (accessor.getValue(coord) < isovalue) signs |= 64u;
- coord[0] = ijk[0]; // i, j+dim, k+dim
- if (accessor.getValue(coord) < isovalue) signs |= 128u;
- return sAmbiguous[signs];
+ if (accessor.getValue(coord) < iso) signs |= 1u;
+ coord[0] += 1; // i+1, j, k
+ if (accessor.getValue(coord) < iso) signs |= 2u;
+ coord[2] += 1; // i+1, j, k+1
+ if (accessor.getValue(coord) < iso) signs |= 4u;
+ coord[0] = ijk[0]; // i, j, k+1
+ if (accessor.getValue(coord) < iso) signs |= 8u;
+ coord[1] += 1; coord[2] = ijk[2]; // i, j+1, k
+ if (accessor.getValue(coord) < iso) signs |= 16u;
+ coord[0] += 1; // i+1, j+1, k
+ if (accessor.getValue(coord) < iso) signs |= 32u;
+ coord[2] += 1; // i+1, j+1, k+1
+ if (accessor.getValue(coord) < iso) signs |= 64u;
+ coord[0] = ijk[0]; // i, j+1, k+1
+ if (accessor.getValue(coord) < iso) signs |= 128u;
+ return signs;
+}
+
+
+/// @brief Leaf node optimized method that computes the cell-sign configuration
+/// at the given local @c offset
+template<typename LeafT>
+inline unsigned char
+evalCellSigns(const LeafT& leaf, const Index offset, typename LeafT::ValueType iso)
+{
+ unsigned char signs = 0;
+
+ // i, j, k
+ if (leaf.getValue(offset) < iso) signs |= 1u;
+
+ // i, j, k+1
+ if (leaf.getValue(offset + 1) < iso) signs |= 8u;
+
+ // i, j+1, k
+ if (leaf.getValue(offset + LeafT::DIM) < iso) signs |= 16u;
+
+ // i, j+1, k+1
+ if (leaf.getValue(offset + LeafT::DIM + 1) < iso) signs |= 128u;
+
+ // i+1, j, k
+ if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) ) < iso) signs |= 2u;
+
+ // i+1, j, k+1
+ if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1) < iso) signs |= 4u;
+
+ // i+1, j+1, k
+ if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM) < iso) signs |= 32u;
+
+ // i+1, j+1, k+1
+ if (leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1) < iso) signs |= 64u;
+
+ return signs;
+}
+
+
+/// @brief Used to correct topological ambiguities related to two adjacent cells
+/// that share an ambiguous face.
+template<class AccessorT>
+inline void
+correctCellSigns(unsigned char& signs, unsigned char face,
+ const AccessorT& acc, Coord ijk, typename AccessorT::ValueType iso)
+{
+ if (face == 1) {
+ ijk[2] -= 1;
+ if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 3) signs = ~signs;
+ } else if (face == 3) {
+ ijk[2] += 1;
+ if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 1) signs = ~signs;
+ } else if (face == 2) {
+ ijk[0] += 1;
+ if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 4) signs = ~signs;
+ } else if (face == 4) {
+ ijk[0] -= 1;
+ if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 2) signs = ~signs;
+ } else if (face == 5) {
+ ijk[1] -= 1;
+ if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 6) signs = ~signs;
+ } else if (face == 6) {
+ ijk[1] += 1;
+ if (sAmbiguousFace[evalCellSigns(acc, ijk, iso)] == 5) signs = ~signs;
+ }
}
@@ -343,7 +714,7 @@ isNonManifold(const AccessorT& accessor, const Coord& ijk,
if (p[5]) signs |= 32u;
if (p[6]) signs |= 64u;
if (p[7]) signs |= 128u;
- if (sAmbiguous[signs]) return true;
+ if (!sAdaptable[signs]) return true;
// Manifold check
@@ -519,420 +890,1009 @@ isMergable(LeafType& leaf, const Coord& start, int dim,
////////////////////////////////////////
-template <class TreeT>
-class LeafCPtrList
+template<typename TreeT, typename LeafManagerT>
+class SignData
{
public:
- typedef std::vector<const typename TreeT::LeafNodeType *> ListT;
+ typedef typename TreeT::ValueType ValueT;
+ typedef tree::ValueAccessor<const TreeT> AccessorT;
+
+ typedef typename TreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef tree::ValueAccessor<IntTreeT> IntAccessorT;
+
+ typedef typename TreeT::template ValueConverter<Int16>::Type Int16TreeT;
+ typedef tree::ValueAccessor<Int16TreeT> Int16AccessorT;
- LeafCPtrList(const TreeT& tree)
+ //////////
+
+
+ SignData(const TreeT& distTree, const LeafManagerT& leafs, ValueT iso);
+
+ void run(bool threaded = true);
+
+ typename Int16TreeT::Ptr signTree() const { return mSignTree; }
+ typename IntTreeT::Ptr idxTree() const { return mIdxTree; }
+
+ //////////
+
+ SignData(SignData&, tbb::split);
+ void operator()(const tbb::blocked_range<size_t>&);
+ void join(const SignData& rhs)
{
- mLeafNodes.reserve(tree.leafCount());
- typename TreeT::LeafCIter iter = tree.cbeginLeaf();
- for ( ; iter; ++iter) mLeafNodes.push_back(iter.getLeaf());
+ mSignTree->merge(*rhs.mSignTree);
+ mIdxTree->merge(*rhs.mIdxTree);
}
- size_t size() const { return mLeafNodes.size(); }
+private:
- const typename TreeT::LeafNodeType* operator[](size_t n) const
- { return mLeafNodes[n]; }
+ const TreeT& mDistTree;
+ AccessorT mDistAcc;
- tbb::blocked_range<size_t> getRange() const
- { return tbb::blocked_range<size_t>(0, mLeafNodes.size()); }
+ const LeafManagerT& mLeafs;
+ ValueT mIsovalue;
- const ListT& getList() const { return mLeafNodes; }
+ typename Int16TreeT::Ptr mSignTree;
+ Int16AccessorT mSignAcc;
+
+ typename IntTreeT::Ptr mIdxTree;
+ IntAccessorT mIdxAcc;
-private:
- ListT mLeafNodes;
};
-template <class TreeT>
-class LeafPtrList
+template<typename TreeT, typename LeafManagerT>
+SignData<TreeT, LeafManagerT>::SignData(const TreeT& distTree,
+ const LeafManagerT& leafs, ValueT iso)
+ : mDistTree(distTree)
+ , mDistAcc(mDistTree)
+ , mLeafs(leafs)
+ , mIsovalue(iso)
+ , mSignTree(new Int16TreeT(0))
+ , mSignAcc(*mSignTree)
+ , mIdxTree(new IntTreeT(int(util::INVALID_IDX)))
+ , mIdxAcc(*mIdxTree)
{
-public:
- typedef std::vector<typename TreeT::LeafNodeType *> ListT;
+}
- LeafPtrList(TreeT& tree)
- {
- mLeafNodes.reserve(tree.leafCount());
- typename TreeT::LeafIter iter = tree.beginLeaf();
- for ( ; iter; ++iter) mLeafNodes.push_back(iter.getLeaf());
- }
- size_t size() const { return mLeafNodes.size(); }
+template<typename TreeT, typename LeafManagerT>
+SignData<TreeT, LeafManagerT>::SignData(SignData& rhs, tbb::split)
+ : mDistTree(rhs.mDistTree)
+ , mDistAcc(mDistTree)
+ , mLeafs(rhs.mLeafs)
+ , mIsovalue(rhs.mIsovalue)
+ , mSignTree(new Int16TreeT(0))
+ , mSignAcc(*mSignTree)
+ , mIdxTree(new IntTreeT(int(util::INVALID_IDX)))
+ , mIdxAcc(*mIdxTree)
+{
+}
+
+
+template<typename TreeT, typename LeafManagerT>
+void
+SignData<TreeT, LeafManagerT>::run(bool threaded)
+{
+ if (threaded) tbb::parallel_reduce(mLeafs.getRange(), *this);
+ else (*this)(mLeafs.getRange());
+}
+
+template<typename TreeT, typename LeafManagerT>
+void
+SignData<TreeT, LeafManagerT>::operator()(const tbb::blocked_range<size_t>& range)
+{
+ typedef typename Int16TreeT::LeafNodeType Int16LeafT;
+ typedef typename IntTreeT::LeafNodeType IntLeafT;
+ typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter iter;
+ unsigned char signs, face;
+ Coord ijk, coord;
+
+ typename internal::UniquePtr<Int16LeafT>::type signLeafPt(new Int16LeafT(ijk, 0));
- typename TreeT::LeafNodeType* operator[](size_t n) const
- { return mLeafNodes[n]; }
+ for (size_t n = range.begin(); n != range.end(); ++n) {
- tbb::blocked_range<size_t> getRange() const
- { return tbb::blocked_range<size_t>(0, mLeafNodes.size()); }
+ bool collectedData = false;
- const ListT& getList() const { return mLeafNodes; }
+ coord = mLeafs.leaf(n).origin();
-private:
- ListT mLeafNodes;
-};
+ if (!signLeafPt.get()) signLeafPt.reset(new Int16LeafT(coord, 0));
+ else signLeafPt->setOrigin(coord);
+
+ const typename TreeT::LeafNodeType *leafPt = mDistAcc.probeConstLeaf(coord);
+
+ coord.offset(TreeT::LeafNodeType::DIM - 1);
+
+ for (iter = mLeafs.leaf(n).cbeginValueOn(); iter; ++iter) {
+
+ ijk = iter.getCoord();
+
+ if (leafPt && ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2]) {
+ signs = evalCellSigns(*leafPt, iter.pos(), mIsovalue);
+ } else {
+ signs = evalCellSigns(mDistAcc, ijk, mIsovalue);
+ }
+
+ if (signs != 0 && signs != 0xFF) {
+ Int16 flags = (signs & 0x1) ? INSIDE : 0;
+
+ if (bool(signs & 0x1) != bool(signs & 0x2)) flags |= XEDGE;
+ if (bool(signs & 0x1) != bool(signs & 0x10)) flags |= YEDGE;
+ if (bool(signs & 0x1) != bool(signs & 0x8)) flags |= ZEDGE;
+
+ face = internal::sAmbiguousFace[signs];
+ if (face != 0) correctCellSigns(signs, face, mDistAcc, ijk, mIsovalue);
+
+ flags |= Int16(signs);
+
+ signLeafPt->setValue(ijk, flags);
+ collectedData = true;
+ }
+ }
+
+ if (collectedData) {
+
+ IntLeafT* idxLeaf = mIdxAcc.touchLeaf(coord);
+ idxLeaf->topologyUnion(*signLeafPt);
+ typename IntLeafT::ValueOnIter it = idxLeaf->beginValueOn();
+ for (; it; ++it) {
+ it.setValue(0);
+ }
+
+ mSignAcc.addLeaf(signLeafPt.release());
+ }
+ }
+}
////////////////////////////////////////
-template<typename DistTreeT>
-struct ReferenceData
+/// @brief Counts the total number of points per leaf, accounts for cells with multiple points.
+class CountPoints
{
- typedef typename DistTreeT::ValueType DistValueT;
- typedef typename DistTreeT::template ValueConverter<char>::Type CharTreeT;
- typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
- typedef typename DistTreeT::template ValueConverter<Vec3s>::Type Vec3sTreeT;
-
- ReferenceData()
- : mDistTree(NULL)
- , mEdgeTree(NULL)
- , mTopologyMaskTree(NULL)
- , mSeamPointTree(NULL)
- , mSeamMaskTree(typename BoolTreeT::Ptr())
- , mSmoothingMaskTree(typename BoolTreeT::Ptr())
- , mInternalAdaptivity(DistValueT(0.0))
+public:
+ CountPoints(std::vector<size_t>& pointList) : mPointList(pointList) {}
+
+ template <typename LeafNodeType>
+ void operator()(LeafNodeType &leaf, size_t leafIndex) const
{
+ size_t points = 0;
+
+ typename LeafNodeType::ValueOnCIter iter = leaf.cbeginValueOn();
+ for (; iter; ++iter) {
+ points += size_t(sEdgeGroupTable[(SIGNS & iter.getValue())][0]);
+ }
+
+ mPointList[leafIndex] = points;
}
- bool isValid() const
+private:
+ std::vector<size_t>& mPointList;
+};
+
+
+/// @brief Computes the point list indices for the index tree.
+template<typename Int16TreeT>
+class MapPoints
+{
+public:
+ typedef tree::ValueAccessor<const Int16TreeT> Int16AccessorT;
+
+ MapPoints(std::vector<size_t>& pointList, const Int16TreeT& signTree)
+ : mPointList(pointList)
+ , mSignAcc(signTree)
{
- return mDistTree && mEdgeTree && mTopologyMaskTree && mSeamMaskTree;
}
- const DistTreeT* mDistTree;
- const CharTreeT* mEdgeTree;
- BoolTreeT* mTopologyMaskTree;
- Vec3sTreeT* mSeamPointTree;
- typename BoolTreeT::Ptr mSeamMaskTree, mSmoothingMaskTree;
- DistValueT mInternalAdaptivity;
-};
+ template <typename LeafNodeType>
+ void operator()(LeafNodeType &leaf, size_t leafIndex) const
+ {
+ size_t ptnIdx = mPointList[leafIndex];
+ typename LeafNodeType::ValueOnIter iter = leaf.beginValueOn();
+ const typename Int16TreeT::LeafNodeType *signLeafPt =
+ mSignAcc.probeConstLeaf(leaf.origin());
-////////////////////////////////////////
+ for (; iter; ++iter) {
+ iter.setValue(ptnIdx);
+ unsigned signs = SIGNS & signLeafPt->getValue(iter.pos());
+ ptnIdx += size_t(sEdgeGroupTable[signs][0]);
+ }
+ }
+
+private:
+ std::vector<size_t>& mPointList;
+ Int16AccessorT mSignAcc;
+};
-template <class DistTreeT>
-class Count
+/// @brief Counts the total number of points per collapsed region
+template<typename IntTreeT>
+class CountRegions
{
public:
- Count(const LeafPtrList<DistTreeT>&, std::vector<size_t>&);
- inline Count(const Count<DistTreeT>&);
+ typedef tree::ValueAccessor<IntTreeT> IntAccessorT;
+ typedef typename IntTreeT::LeafNodeType IntLeafT;
+
+ CountRegions(IntTreeT& idxTree, std::vector<size_t>& regions)
+ : mIdxAcc(idxTree)
+ , mRegions(regions)
+ {
+ }
+
+ template <typename LeafNodeType>
+ void operator()(LeafNodeType &leaf, size_t leafIndex) const
+ {
- void runParallel();
- void runSerial();
+ size_t regions = 0;
+
+ IntLeafT tmpLeaf(*mIdxAcc.probeConstLeaf(leaf.origin()));
+
+ typename IntLeafT::ValueOnIter iter = tmpLeaf.beginValueOn();
+ for (; iter; ++iter) {
+ if(iter.getValue() == 0) {
+ iter.setValueOff();
+ regions += size_t(sEdgeGroupTable[(SIGNS & leaf.getValue(iter.pos()))][0]);
+ }
+ }
+
+ int onVoxelCount = int(tmpLeaf.onVoxelCount());
+ while (onVoxelCount > 0) {
+ ++regions;
+ iter = tmpLeaf.beginValueOn();
+ int regionId = iter.getValue();
+ for (; iter; ++iter) {
+ if (iter.getValue() == regionId) {
+ iter.setValueOff();
+ --onVoxelCount;
+ }
+ }
+ }
+
+ mRegions[leafIndex] = regions;
+ }
- inline void operator()(const tbb::blocked_range<size_t>&) const;
private:
- const LeafPtrList<DistTreeT>& mLeafNodes;
- std::vector<size_t>& mLeafRegionCount;
+ IntAccessorT mIdxAcc;
+ std::vector<size_t>& mRegions;
};
-template <class DistTreeT>
-Count<DistTreeT>::Count(
- const LeafPtrList<DistTreeT>& leafs,
- std::vector<size_t>& leafRegionCount)
- : mLeafNodes(leafs)
- , mLeafRegionCount(leafRegionCount)
+////////////////////////////////////////
+
+
+// @brief linear interpolation.
+inline double evalRoot(double v0, double v1, double iso) { return (iso - v0) / (v1 - v0); }
+
+
+/// @brief Extracts the eight corner values for leaf inclusive cells.
+template<typename LeafT>
+inline void
+collectCornerValues(const LeafT& leaf, const Index offset, std::vector<double>& values)
{
+ values[0] = double(leaf.getValue(offset)); // i, j, k
+ values[3] = double(leaf.getValue(offset + 1)); // i, j, k+1
+ values[4] = double(leaf.getValue(offset + LeafT::DIM)); // i, j+1, k
+ values[7] = double(leaf.getValue(offset + LeafT::DIM + 1)); // i, j+1, k+1
+ values[1] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM))); // i+1, j, k
+ values[2] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + 1)); // i+1, j, k+1
+ values[5] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM)); // i+1, j+1, k
+ values[6] = double(leaf.getValue(offset + (LeafT::DIM * LeafT::DIM) + LeafT::DIM + 1)); // i+1, j+1, k+1
}
-template <class DistTreeT>
-inline
-Count<DistTreeT>::Count(const Count<DistTreeT>& rhs)
- : mLeafNodes(rhs.mLeafNodes)
- , mLeafRegionCount(rhs.mLeafRegionCount)
+/// @brief Extracts the eight corner values for a cell starting at the given @ijk coordinate.
+template<typename AccessorT>
+inline void
+collectCornerValues(const AccessorT& acc, const Coord& ijk, std::vector<double>& values)
{
+ Coord coord = ijk;
+ values[0] = double(acc.getValue(coord)); // i, j, k
+
+ coord[0] += 1;
+ values[1] = double(acc.getValue(coord)); // i+1, j, k
+
+ coord[2] += 1;
+ values[2] = double(acc.getValue(coord)); // i+i, j, k+1
+
+ coord[0] = ijk[0];
+ values[3] = double(acc.getValue(coord)); // i, j, k+1
+
+ coord[1] += 1; coord[2] = ijk[2];
+ values[4] = double(acc.getValue(coord)); // i, j+1, k
+
+ coord[0] += 1;
+ values[5] = double(acc.getValue(coord)); // i+1, j+1, k
+
+ coord[2] += 1;
+ values[6] = double(acc.getValue(coord)); // i+1, j+1, k+1
+
+ coord[0] = ijk[0];
+ values[7] = double(acc.getValue(coord)); // i, j+1, k+1
}
-template <class DistTreeT>
-void
-Count<DistTreeT>::runParallel()
+/// @brief Computes the average cell point for a given edge group.
+inline Vec3d
+computePoint(const std::vector<double>& values, unsigned char signs,
+ unsigned char edgeGroup, double iso)
{
- tbb::parallel_for(mLeafNodes.getRange(), *this);
+ Vec3d avg(0.0, 0.0, 0.0);
+ int samples = 0;
+
+ if (sEdgeGroupTable[signs][1] == edgeGroup) { // Edged: 0 - 1
+ avg[0] += evalRoot(values[0], values[1], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][2] == edgeGroup) { // Edged: 1 - 2
+ avg[0] += 1.0;
+ avg[2] += evalRoot(values[1], values[2], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][3] == edgeGroup) { // Edged: 3 - 2
+ avg[0] += evalRoot(values[3], values[2], iso);
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][4] == edgeGroup) { // Edged: 0 - 3
+ avg[2] += evalRoot(values[0], values[3], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][5] == edgeGroup) { // Edged: 4 - 5
+ avg[0] += evalRoot(values[4], values[5], iso);
+ avg[1] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][6] == edgeGroup) { // Edged: 5 - 6
+ avg[0] += 1.0;
+ avg[1] += 1.0;
+ avg[2] += evalRoot(values[5], values[6], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][7] == edgeGroup) { // Edged: 7 - 6
+ avg[0] += evalRoot(values[7], values[6], iso);
+ avg[1] += 1.0;
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][8] == edgeGroup) { // Edged: 4 - 7
+ avg[1] += 1.0;
+ avg[2] += evalRoot(values[4], values[7], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][9] == edgeGroup) { // Edged: 0 - 4
+ avg[1] += evalRoot(values[0], values[4], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][10] == edgeGroup) { // Edged: 1 - 5
+ avg[0] += 1.0;
+ avg[1] += evalRoot(values[1], values[5], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][11] == edgeGroup) { // Edged: 2 - 6
+ avg[0] += 1.0;
+ avg[1] += evalRoot(values[2], values[6], iso);
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][12] == edgeGroup) { // Edged: 3 - 7
+ avg[1] += evalRoot(values[3], values[7], iso);
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (samples > 1) {
+ double w = 1.0 / double(samples);
+ avg[0] *= w;
+ avg[1] *= w;
+ avg[2] *= w;
+ }
+
+ return avg;
}
-template <class DistTreeT>
-void
-Count<DistTreeT>::runSerial()
+/// @brief Computes the average cell point for a given edge group, ignoring edge
+/// samples present in the @c signsMask configuration.
+inline int
+computeMaskedPoint(Vec3d& avg, const std::vector<double>& values, unsigned char signs,
+ unsigned char signsMask, unsigned char edgeGroup, double iso)
+{
+ avg = Vec3d(0.0, 0.0, 0.0);
+ int samples = 0;
+
+ if (sEdgeGroupTable[signs][1] == edgeGroup
+ && sEdgeGroupTable[signsMask][1] == 0) { // Edged: 0 - 1
+ avg[0] += evalRoot(values[0], values[1], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][2] == edgeGroup
+ && sEdgeGroupTable[signsMask][2] == 0) { // Edged: 1 - 2
+ avg[0] += 1.0;
+ avg[2] += evalRoot(values[1], values[2], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][3] == edgeGroup
+ && sEdgeGroupTable[signsMask][3] == 0) { // Edged: 3 - 2
+ avg[0] += evalRoot(values[3], values[2], iso);
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][4] == edgeGroup
+ && sEdgeGroupTable[signsMask][4] == 0) { // Edged: 0 - 3
+ avg[2] += evalRoot(values[0], values[3], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][5] == edgeGroup
+ && sEdgeGroupTable[signsMask][5] == 0) { // Edged: 4 - 5
+ avg[0] += evalRoot(values[4], values[5], iso);
+ avg[1] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][6] == edgeGroup
+ && sEdgeGroupTable[signsMask][6] == 0) { // Edged: 5 - 6
+ avg[0] += 1.0;
+ avg[1] += 1.0;
+ avg[2] += evalRoot(values[5], values[6], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][7] == edgeGroup
+ && sEdgeGroupTable[signsMask][7] == 0) { // Edged: 7 - 6
+ avg[0] += evalRoot(values[7], values[6], iso);
+ avg[1] += 1.0;
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][8] == edgeGroup
+ && sEdgeGroupTable[signsMask][8] == 0) { // Edged: 4 - 7
+ avg[1] += 1.0;
+ avg[2] += evalRoot(values[4], values[7], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][9] == edgeGroup
+ && sEdgeGroupTable[signsMask][9] == 0) { // Edged: 0 - 4
+ avg[1] += evalRoot(values[0], values[4], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][10] == edgeGroup
+ && sEdgeGroupTable[signsMask][10] == 0) { // Edged: 1 - 5
+ avg[0] += 1.0;
+ avg[1] += evalRoot(values[1], values[5], iso);
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][11] == edgeGroup
+ && sEdgeGroupTable[signsMask][11] == 0) { // Edged: 2 - 6
+ avg[0] += 1.0;
+ avg[1] += evalRoot(values[2], values[6], iso);
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (sEdgeGroupTable[signs][12] == edgeGroup
+ && sEdgeGroupTable[signsMask][12] == 0) { // Edged: 3 - 7
+ avg[1] += evalRoot(values[3], values[7], iso);
+ avg[2] += 1.0;
+ ++samples;
+ }
+
+ if (samples > 1) {
+ double w = 1.0 / double(samples);
+ avg[0] *= w;
+ avg[1] *= w;
+ avg[2] *= w;
+ }
+
+ return samples;
+}
+
+
+/// @brief Computes the average cell point for a given edge group, by computing
+/// convex weights based on the distance from the sample point @c p.
+inline Vec3d
+computeWeightedPoint(const Vec3d& p, const std::vector<double>& values,
+ unsigned char signs, unsigned char edgeGroup, double iso)
{
- (*this)(mLeafNodes.getRange());
+ std::vector<Vec3d> samples;
+ samples.reserve(8);
+
+ std::vector<double> weights;
+ weights.reserve(8);
+
+ Vec3d avg(0.0, 0.0, 0.0);
+
+ if (sEdgeGroupTable[signs][1] == edgeGroup) { // Edged: 0 - 1
+ avg[0] = evalRoot(values[0], values[1], iso);
+ avg[1] = 0.0;
+ avg[2] = 0.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][2] == edgeGroup) { // Edged: 1 - 2
+ avg[0] = 1.0;
+ avg[1] = 0.0;
+ avg[2] = evalRoot(values[1], values[2], iso);
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][3] == edgeGroup) { // Edged: 3 - 2
+ avg[0] = evalRoot(values[3], values[2], iso);
+ avg[1] = 0.0;
+ avg[2] = 1.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][4] == edgeGroup) { // Edged: 0 - 3
+ avg[0] = 0.0;
+ avg[1] = 0.0;
+ avg[2] = evalRoot(values[0], values[3], iso);
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][5] == edgeGroup) { // Edged: 4 - 5
+ avg[0] = evalRoot(values[4], values[5], iso);
+ avg[1] = 1.0;
+ avg[2] = 0.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][6] == edgeGroup) { // Edged: 5 - 6
+ avg[0] = 1.0;
+ avg[1] = 1.0;
+ avg[2] = evalRoot(values[5], values[6], iso);
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][7] == edgeGroup) { // Edged: 7 - 6
+ avg[0] = evalRoot(values[7], values[6], iso);
+ avg[1] = 1.0;
+ avg[2] = 1.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][8] == edgeGroup) { // Edged: 4 - 7
+ avg[0] = 0.0;
+ avg[1] = 1.0;
+ avg[2] = evalRoot(values[4], values[7], iso);
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][9] == edgeGroup) { // Edged: 0 - 4
+ avg[0] = 0.0;
+ avg[1] = evalRoot(values[0], values[4], iso);
+ avg[2] = 0.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][10] == edgeGroup) { // Edged: 1 - 5
+ avg[0] = 1.0;
+ avg[1] = evalRoot(values[1], values[5], iso);
+ avg[2] = 0.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][11] == edgeGroup) { // Edged: 2 - 6
+ avg[0] = 1.0;
+ avg[1] = evalRoot(values[2], values[6], iso);
+ avg[2] = 1.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+ if (sEdgeGroupTable[signs][12] == edgeGroup) { // Edged: 3 - 7
+ avg[0] = 0.0;
+ avg[1] = evalRoot(values[3], values[7], iso);
+ avg[2] = 1.0;
+
+ samples.push_back(avg);
+ weights.push_back((avg-p).lengthSqr());
+ }
+
+
+ double minWeight = std::numeric_limits<double>::max();
+ double maxWeight = -std::numeric_limits<double>::max();
+
+ for (size_t i = 0, I = weights.size(); i < I; ++i) {
+ minWeight = std::min(minWeight, weights[i]);
+ maxWeight = std::max(maxWeight, weights[i]);
+ }
+
+ const double offset = maxWeight + minWeight * 0.1;
+ for (size_t i = 0, I = weights.size(); i < I; ++i) {
+ weights[i] = offset - weights[i];
+ }
+
+
+ double weightSum = 0.0;
+ for (size_t i = 0, I = weights.size(); i < I; ++i) {
+ weightSum += weights[i];
+ }
+
+ avg[0] = 0.0;
+ avg[1] = 0.0;
+ avg[2] = 0.0;
+
+ if (samples.size() > 1) {
+ for (size_t i = 0, I = samples.size(); i < I; ++i) {
+ avg += samples[i] * (weights[i] / weightSum);
+ }
+ } else {
+ avg = samples.front();
+ }
+
+ return avg;
}
-template <class DistTreeT>
+/// @brief Computes the average cell points defined by the sign configuration
+/// @c signs and the given corner values @c values.
inline void
-Count<DistTreeT>::operator()(const tbb::blocked_range<size_t>& range) const
+computeCellPoints(std::vector<Vec3d>& points,
+ const std::vector<double>& values, unsigned char signs, double iso)
{
- for (size_t n = range.begin(); n != range.end(); ++n) {
- mLeafRegionCount[n] = size_t(mLeafNodes[n]->onVoxelCount());
+ for (size_t n = 1, N = sEdgeGroupTable[signs][0] + 1; n < N; ++n) {
+ points.push_back(computePoint(values, signs, n, iso));
}
}
-////////////////////////////////////////
+/// @brief Given a sign configuration @c lhsSigns and an edge group @c groupId,
+/// finds the corresponding edge group in a different sign configuration
+/// @c rhsSigns. Returns -1 if no match is found.
+inline int
+matchEdgeGroup(unsigned char groupId, unsigned char lhsSigns, unsigned char rhsSigns)
+{
+ int id = -1;
+ for (size_t i = 1; i <= 12; ++i) {
+ if (sEdgeGroupTable[lhsSigns][i] == groupId && sEdgeGroupTable[rhsSigns][i] != 0) {
+ id = sEdgeGroupTable[rhsSigns][i];
+ break;
+ }
+ }
+ return id;
+}
-template <class DistTreeT>
-class Merge
+/// @brief Computes the average cell points defined by the sign configuration
+/// @c signs and the given corner values @c values. Combines data from
+/// two different level sets to eliminate seam lines when meshing
+/// fractured segments.
+inline void
+computeCellPoints(std::vector<Vec3d>& points, std::vector<bool>& weightedPointMask,
+ const std::vector<double>& lhsValues, const std::vector<double>& rhsValues,
+ unsigned char lhsSigns, unsigned char rhsSigns,
+ double iso, size_t pointIdx, const boost::scoped_array<uint32_t>& seamPoints)
+{
+ for (size_t n = 1, N = sEdgeGroupTable[lhsSigns][0] + 1; n < N; ++n) {
+
+ int id = matchEdgeGroup(n, lhsSigns, rhsSigns);
+
+ if (id != -1) {
+
+ const unsigned char e(id);
+ uint32_t& quantizedPoint = seamPoints[pointIdx + (id - 1)];
+
+ if ((quantizedPoint & MASK_DIRTY_BIT) && !(quantizedPoint & MASK_INVALID_BIT)) {
+ Vec3d p = unpackPoint(quantizedPoint);
+ points.push_back(computeWeightedPoint(p, rhsValues, rhsSigns, e, iso));
+ weightedPointMask.push_back(true);
+ } else {
+ points.push_back(computePoint(rhsValues, rhsSigns, e, iso));
+ weightedPointMask.push_back(false);
+ }
+
+ } else {
+ points.push_back(computePoint(lhsValues, lhsSigns, n, iso));
+ weightedPointMask.push_back(false);
+ }
+ }
+}
+
+
+template <typename TreeT, typename LeafManagerT>
+class GenPoints
{
public:
- typedef typename DistTreeT::ValueType DistValueT;
- typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
- typedef typename DistTreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef tree::ValueAccessor<const TreeT> AccessorT;
+
+ typedef typename TreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef tree::ValueAccessor<IntTreeT> IntAccessorT;
+ typedef tree::ValueAccessor<const IntTreeT> IntCAccessorT;
- Merge(
- const DistTreeT& distTree,
- LeafPtrList<IntTreeT>& auxLeafs,
- std::vector<size_t>& leafRegionCount,
- const DistValueT iso,
- const DistValueT adaptivity);
+ typedef typename TreeT::template ValueConverter<Int16>::Type Int16TreeT;
+ typedef tree::ValueAccessor<const Int16TreeT> Int16CAccessorT;
- inline Merge(const Merge<DistTreeT>&);
+ typedef boost::scoped_array<uint32_t> QuantizedPointList;
- void setRefData(const ReferenceData<DistTreeT>&);
+ //////////
+
+
+ GenPoints(const LeafManagerT& signLeafs, const TreeT& distTree,
+ IntTreeT& idxTree, PointList& points, std::vector<size_t>& indices,
+ const math::Transform& xform, double iso);
+
+ void run(bool threaded = true);
+
+ void setRefData(const Int16TreeT* refSignTree = NULL, const TreeT* refDistTree = NULL,
+ IntTreeT* refIdxTree = NULL, const QuantizedPointList* seamPoints = NULL,
+ std::vector<unsigned char>* mSeamPointMaskPt = NULL);
+
+ //////////
- void runParallel();
- void runSerial();
void operator()(const tbb::blocked_range<size_t>&) const;
private:
- const DistTreeT& mDistTree;
- LeafPtrList<IntTreeT>& mAuxLeafs;
- std::vector<size_t>& mLeafRegionCount;
- const DistValueT mIsovalue, mAdaptivity;
- const ReferenceData<DistTreeT>* mRefData;
-};
+ const LeafManagerT& mSignLeafs;
+ AccessorT mDistAcc;
+ IntTreeT& mIdxTree;
-template <class DistTreeT>
-Merge<DistTreeT>::Merge(
- const DistTreeT& distTree,
- LeafPtrList<IntTreeT>& auxLeafs,
- std::vector<size_t>& leafRegionCount,
- const DistValueT iso,
- const DistValueT adaptivity)
- : mDistTree(distTree)
- , mAuxLeafs(auxLeafs)
- , mLeafRegionCount(leafRegionCount)
- , mIsovalue(iso)
- , mAdaptivity(adaptivity)
- , mRefData(NULL)
-{
-}
+ PointList& mPoints;
+ std::vector<size_t>& mIndices;
+ const math::Transform& mTransform;
+ const double mIsovalue;
+ // reference data
+ const Int16TreeT *mRefSignTreePt;
+ const TreeT* mRefDistTreePt;
+ const IntTreeT* mRefIdxTreePt;
+ const QuantizedPointList* mSeamPointsPt;
+ std::vector<unsigned char>* mSeamPointMaskPt;
+};
-template <class DistTreeT>
-inline
-Merge<DistTreeT>::Merge(const Merge<DistTreeT>& rhs)
- : mDistTree(rhs.mDistTree)
- , mAuxLeafs(rhs.mAuxLeafs)
- , mLeafRegionCount(rhs.mLeafRegionCount)
- , mIsovalue(rhs.mIsovalue)
- , mAdaptivity(rhs.mAdaptivity)
- , mRefData(rhs.mRefData)
+
+template <typename TreeT, typename LeafManagerT>
+GenPoints<TreeT, LeafManagerT>::GenPoints(const LeafManagerT& signLeafs,
+ const TreeT& distTree, IntTreeT& idxTree, PointList& points,
+ std::vector<size_t>& indices, const math::Transform& xform, double iso)
+ : mSignLeafs(signLeafs)
+ , mDistAcc(distTree)
+ , mIdxTree(idxTree)
+ , mPoints(points)
+ , mIndices(indices)
+ , mTransform(xform)
+ , mIsovalue(iso)
+ , mRefSignTreePt(NULL)
+ , mRefDistTreePt(NULL)
+ , mRefIdxTreePt(NULL)
+ , mSeamPointsPt(NULL)
+ , mSeamPointMaskPt(NULL)
{
}
-template <class DistTreeT>
+template <typename TreeT, typename LeafManagerT>
void
-Merge<DistTreeT>::runParallel()
+GenPoints<TreeT, LeafManagerT>::run(bool threaded)
{
- tbb::parallel_for(mAuxLeafs.getRange(), *this);
+ if (threaded) tbb::parallel_for(mSignLeafs.getRange(), *this);
+ else (*this)(mSignLeafs.getRange());
}
-template <class DistTreeT>
+template <typename TreeT, typename LeafManagerT>
void
-Merge<DistTreeT>::runSerial()
+GenPoints<TreeT, LeafManagerT>::setRefData(const Int16TreeT *refSignTree, const TreeT *refDistTree,
+ IntTreeT* refIdxTree, const QuantizedPointList* seamPoints, std::vector<unsigned char>* seamPointMask)
{
- (*this)(mAuxLeafs.getRange());
+ mRefSignTreePt = refSignTree;
+ mRefDistTreePt = refDistTree;
+ mRefIdxTreePt = refIdxTree;
+ mSeamPointsPt = seamPoints;
+ mSeamPointMaskPt = seamPointMask;
}
-template <class DistTreeT>
-void
-Merge<DistTreeT>::setRefData(const ReferenceData<DistTreeT>& refData)
-{
- mRefData = &refData;
-}
-template <class DistTreeT>
+template <typename TreeT, typename LeafManagerT>
void
-Merge<DistTreeT>::operator()(const tbb::blocked_range<size_t>& range) const
+GenPoints<TreeT, LeafManagerT>::operator()(
+ const tbb::blocked_range<size_t>& range) const
{
- typedef math::Vec3<DistValueT> Vec3T;
- typedef typename BoolTreeT::LeafNodeType BoolLeafT;
- typedef typename IntTreeT::LeafNodeType IntLeafT;
- typedef typename BoolLeafT::template ValueConverter<Vec3T>::Type Vec3LeafT;
+ typename IntTreeT::LeafNodeType::ValueOnIter iter;
+ unsigned char signs, refSigns;
+ Index offset;
+ Coord ijk, coord;
+ std::vector<Vec3d> points(4);
+ std::vector<bool> weightedPointMask(4);
+ std::vector<double> values(8), refValues(8);
- typedef typename IntLeafT::ValueOnIter IntIterT;
- typedef typename BoolLeafT::ValueOnCIter BoolCIterT;
- typedef typename tree::ValueAccessor<BoolTreeT> BoolTreeAccessorT;
- typedef typename tree::ValueAccessor<const BoolTreeT> BoolTreeCAccessorT;
+ IntAccessorT idxAcc(mIdxTree);
- boost::scoped_ptr<BoolTreeAccessorT> seamMaskAcc;
- boost::scoped_ptr<BoolTreeCAccessorT> topologyMaskAcc;
- if (mRefData && mRefData->isValid()) {
- seamMaskAcc.reset(new BoolTreeAccessorT(*mRefData->mSeamMaskTree.get()));
- topologyMaskAcc.reset(new BoolTreeCAccessorT(*mRefData->mTopologyMaskTree));
- }
- const bool hasRefData = seamMaskAcc && topologyMaskAcc;
+ // reference data accessors
+ boost::scoped_ptr<Int16CAccessorT> refSignAcc;
+ if (mRefSignTreePt) refSignAcc.reset(new Int16CAccessorT(*mRefSignTreePt));
- const int LeafDim = BoolLeafT::DIM;
- tree::ValueAccessor<const DistTreeT> distAcc(mDistTree);
+ boost::scoped_ptr<IntCAccessorT> refIdxAcc;
+ if (mRefIdxTreePt) refIdxAcc.reset(new IntCAccessorT(*mRefIdxTreePt));
+
+ boost::scoped_ptr<AccessorT> refDistAcc;
+ if (mRefDistTreePt) refDistAcc.reset(new AccessorT(*mRefDistTreePt));
- // Allocate reusable leaf buffers
- BoolLeafT mask;
- Vec3LeafT gradientBuffer;
- Coord ijk, coord, end;
for (size_t n = range.begin(); n != range.end(); ++n) {
- DistValueT adaptivity = mAdaptivity;
- IntLeafT& auxLeaf = *mAuxLeafs[n];
+ coord = mSignLeafs.leaf(n).origin();
- const Coord& origin = auxLeaf.getOrigin();
- end[0] = origin[0] + LeafDim;
- end[1] = origin[1] + LeafDim;
- end[2] = origin[2] + LeafDim;
+ const typename TreeT::LeafNodeType *leafPt = mDistAcc.probeConstLeaf(coord);
+ typename IntTreeT::LeafNodeType *idxLeafPt = idxAcc.probeLeaf(coord);
- mask.setValuesOff();
- // Mask off seam line adjacent voxels
- if (hasRefData) {
- const BoolLeafT* seamMask = seamMaskAcc->probeConstLeaf(origin);
- if (seamMask != NULL) {
- for (BoolCIterT it = seamMask->cbeginValueOn(); it; ++it) {
- ijk = it.getCoord();
- coord[0] = ijk[0] - (ijk[0] % 2);
- coord[1] = ijk[1] - (ijk[1] % 2);
- coord[2] = ijk[2] - (ijk[2] % 2);
- mask.setActiveState(coord, true);
+ // reference data leafs
+ const typename Int16TreeT::LeafNodeType *refSignLeafPt = NULL;
+ if (refSignAcc) refSignLeafPt = refSignAcc->probeConstLeaf(coord);
+
+ const typename IntTreeT::LeafNodeType *refIdxLeafPt = NULL;
+ if (refIdxAcc) refIdxLeafPt = refIdxAcc->probeConstLeaf(coord);
+
+ const typename TreeT::LeafNodeType *refDistLeafPt = NULL;
+ if (refDistAcc) refDistLeafPt = refDistAcc->probeConstLeaf(coord);
+
+
+ // generate cell points
+ size_t ptnIdx = mIndices[n];
+ coord.offset(TreeT::LeafNodeType::DIM - 1);
+
+
+
+ for (iter = idxLeafPt->beginValueOn(); iter; ++iter) {
+
+ if(iter.getValue() != 0) continue;
+
+ iter.setValue(ptnIdx);
+ iter.setValueOff();
+ offset = iter.pos();
+ ijk = iter.getCoord();
+
+ const bool inclusiveCell = ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2];
+
+ const Int16& flags = mSignLeafs.leaf(n).getValue(offset);
+ signs = SIGNS & flags;
+ refSigns = 0;
+
+ if ((flags & SEAM) && refSignLeafPt && refIdxLeafPt) {
+ if (refSignLeafPt->isValueOn(offset)) {
+ refSigns = (SIGNS & refSignLeafPt->getValue(offset));
}
}
- if (topologyMaskAcc->probeConstLeaf(origin) == NULL) {
- adaptivity = mRefData->mInternalAdaptivity;
+
+
+ if (inclusiveCell) collectCornerValues(*leafPt, offset, values);
+ else collectCornerValues(mDistAcc, ijk, values);
+
+
+ points.clear();
+ weightedPointMask.clear();
+
+ if (refSigns == 0) {
+ computeCellPoints(points, values, signs, mIsovalue);
+ } else {
+
+ if (inclusiveCell) collectCornerValues(*refDistLeafPt, offset, refValues);
+ else collectCornerValues(*refDistAcc, ijk, refValues);
+
+ computeCellPoints(points, weightedPointMask, values, refValues, signs, refSigns,
+ mIsovalue, refIdxLeafPt->getValue(offset), *mSeamPointsPt);
+ }
+
+
+ for (size_t i = 0, I = points.size(); i < I; ++i) {
+
+ // offset by cell-origin
+ points[i][0] += double(ijk[0]);
+ points[i][1] += double(ijk[1]);
+ points[i][2] += double(ijk[2]);
+
+
+ points[i] = mTransform.indexToWorld(points[i]);
+
+ mPoints[ptnIdx][0] = float(points[i][0]);
+ mPoints[ptnIdx][1] = float(points[i][1]);
+ mPoints[ptnIdx][2] = float(points[i][2]);
+
+ if (mSeamPointMaskPt && !weightedPointMask.empty() && weightedPointMask[i]) {
+ (*mSeamPointMaskPt)[ptnIdx] = 1;
+ }
+
+ ++ptnIdx;
}
}
- // Mask off ambiguous voxels
- for (IntIterT it = auxLeaf.beginValueOn(); it; ++it) {
- ijk = it.getCoord();
- coord[0] = ijk[0] - (ijk[0] % 2);
- coord[1] = ijk[1] - (ijk[1] % 2);
- coord[2] = ijk[2] - (ijk[2] % 2);
- if(mask.isValueOn(coord)) continue;
- mask.setActiveState(coord, isAmbiguous(distAcc, ijk, mIsovalue, 1));
- }
-
- int dim = 2;
- // Mask off topologically ambiguous 2x2x2 voxel sub-blocks
- for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
- for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
- for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
- if (isNonManifold(distAcc, ijk, mIsovalue, dim)) {
- mask.setActiveState(ijk, true);
- }
- }
- }
- }
-
- // Compute the gradient for the remaining voxels
- gradientBuffer.setValuesOff();
-
- for (IntIterT it = auxLeaf.beginValueOn(); it; ++it) {
-
- ijk = it.getCoord();
- coord[0] = ijk[0] - (ijk[0] % dim);
- coord[1] = ijk[1] - (ijk[1] % dim);
- coord[2] = ijk[2] - (ijk[2] % dim);
- if(mask.isValueOn(coord)) continue;
-
- Vec3T norm(math::ISGradient<math::CD_2ND>::result(distAcc, ijk));
- // Normalize (Vec3's normalize uses isApproxEqual, which uses abs and does more work)
- DistValueT length = norm.length();
- if (length > DistValueT(1.0e-7)) {
- norm *= DistValueT(1.0) / length;
- }
- gradientBuffer.setValue(ijk, norm);
- }
-
- int regionId = 1, next_dim = dim << 1;
-
- // Process the first adaptivity level.
- for (ijk[0] = 0; ijk[0] < LeafDim; ijk[0] += dim) {
- coord[0] = ijk[0] - (ijk[0] % next_dim);
- for (ijk[1] = 0; ijk[1] < LeafDim; ijk[1] += dim) {
- coord[1] = ijk[1] - (ijk[1] % next_dim);
- for (ijk[2] = 0; ijk[2] < LeafDim; ijk[2] += dim) {
- coord[2] = ijk[2] - (ijk[2] % next_dim);
- if(mask.isValueOn(ijk) || !isMergable(gradientBuffer, ijk, dim, adaptivity)) {
- mask.setActiveState(coord, true);
- continue;
- }
- mergeVoxels(auxLeaf, ijk, dim, regionId++);
- }
- }
- }
-
-
- // Process remaining adaptivity levels
- for (dim = 4; dim < LeafDim; dim = dim << 1) {
- next_dim = dim << 1;
- coord[0] = ijk[0] - (ijk[0] % next_dim);
- for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
- coord[1] = ijk[1] - (ijk[1] % next_dim);
- for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
- coord[2] = ijk[2] - (ijk[2] % next_dim);
- for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
-
- if (mask.isValueOn(ijk) || isNonManifold(distAcc, ijk, mIsovalue, dim) ||
- !isMergable(gradientBuffer, ijk, dim, adaptivity)) {
- mask.setActiveState(coord, true);
- continue;
- }
- mergeVoxels(auxLeaf, ijk, dim, regionId++);
- }
- }
- }
- }
-
-
- if (!(mask.isValueOn(origin) || isNonManifold(distAcc, origin, mIsovalue, LeafDim))
- && isMergable(gradientBuffer, origin, LeafDim, adaptivity)) {
- mergeVoxels(auxLeaf, origin, LeafDim, regionId++);
- }
-
-
- // Count unique regions
- size_t numVoxels = 0;
- IntLeafT tmpLeaf(auxLeaf);
- for (IntIterT it = tmpLeaf.beginValueOn(); it; ++it) {
- if(it.getValue() == 0) {
- it.setValueOff();
- ++numVoxels;
- }
- }
-
- while (tmpLeaf.onVoxelCount() > 0) {
- ++numVoxels;
- IntIterT it = tmpLeaf.beginValueOn();
- regionId = it.getValue();
- for (; it; ++it) {
- if (it.getValue() == regionId) it.setValueOff();
- }
- }
-
- mLeafRegionCount[n] = numVoxels;
+ // generate collapsed region points
+ int onVoxelCount = int(idxLeafPt->onVoxelCount());
+ while (onVoxelCount > 0) {
+
+ iter = idxLeafPt->beginValueOn();
+ int regionId = iter.getValue(), count = 0;
+
+ Vec3d avg(0.0), point;
+
+ for (; iter; ++iter) {
+ if (iter.getValue() != regionId) continue;
+
+ iter.setValue(ptnIdx);
+ iter.setValueOff();
+ --onVoxelCount;
+
+ ijk = iter.getCoord();
+ offset = iter.pos();
+
+ signs = (SIGNS & mSignLeafs.leaf(n).getValue(offset));
+
+ if (ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2]) {
+ collectCornerValues(*leafPt, offset, values);
+ } else {
+ collectCornerValues(mDistAcc, ijk, values);
+ }
+
+ points.clear();
+ computeCellPoints(points, values, signs, mIsovalue);
+
+ avg[0] += double(ijk[0]) + points[0][0];
+ avg[1] += double(ijk[1]) + points[0][1];
+ avg[2] += double(ijk[2]) + points[0][2];
+
+ ++count;
+ }
+
+
+ if (count > 1) {
+ double w = 1.0 / double(count);
+ avg[0] *= w;
+ avg[1] *= w;
+ avg[2] *= w;
+ }
+
+ avg = mTransform.indexToWorld(avg);
+
+ mPoints[ptnIdx][0] = float(avg[0]);
+ mPoints[ptnIdx][1] = float(avg[1]);
+ mPoints[ptnIdx][2] = float(avg[2]);
+
+ ++ptnIdx;
+ }
}
}
@@ -940,374 +1900,436 @@ Merge<DistTreeT>::operator()(const tbb::blocked_range<size_t>& range) const
////////////////////////////////////////
-template <class DistTreeT>
-class PointGen
+template<typename TreeT>
+class SeamWeights
{
public:
- typedef typename DistTreeT::ValueType DistValueT;
- typedef tree::ValueAccessor<const DistTreeT> DistTreeAccessorT;
- typedef typename DistTreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef tree::ValueAccessor<const TreeT> AccessorT;
- PointGen(
- const DistTreeT& distTree,
- const LeafPtrList<IntTreeT>& auxLeafs,
- std::vector<size_t>& leafIndices,
- const openvdb::math::Transform& xform,
- PointList& points,
- double iso = 0.0);
+ typedef typename TreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef tree::ValueAccessor<const IntTreeT> IntAccessorT;
- PointGen(const PointGen<DistTreeT>&);
+ typedef typename TreeT::template ValueConverter<Int16>::Type Int16TreeT;
+ typedef tree::ValueAccessor<const Int16TreeT> Int16AccessorT;
- void setRefData(const ReferenceData<DistTreeT>&);
+ typedef boost::scoped_array<uint32_t> QuantizedPointList;
- void runParallel();
- void runSerial();
+ //////////
- void operator()(const tbb::blocked_range<size_t>&) const;
+ SeamWeights(const TreeT& distTree, const Int16TreeT& refSignTree,
+ IntTreeT& refIdxTree, QuantizedPointList& points, double iso);
+
+ template <typename LeafNodeType>
+ void operator()(LeafNodeType &signLeaf, size_t leafIndex) const;
private:
- const DistTreeT& mDistTree;
- const LeafPtrList<IntTreeT>& mAuxLeafs;
- const std::vector<size_t>& mLeafIndices;
- const openvdb::math::Transform& mTransform;
- const PointList& mPoints;
- const double mIsovalue;
- const ReferenceData<DistTreeT>* mRefData;
+ AccessorT mDistAcc;
+ Int16AccessorT mRefSignAcc;
+ IntAccessorT mRefIdxAcc;
- double root(double v0, double v1) const { return (mIsovalue - v0) / (v1 - v0); }
- int calcAvgPoint(DistTreeAccessorT&, const Coord&, openvdb::Vec3d&) const;
+ QuantizedPointList& mPoints;
+ const double mIsovalue;
};
-template <class DistTreeT>
-PointGen<DistTreeT>::PointGen(
- const DistTreeT& distTree,
- const LeafPtrList<IntTreeT>& auxLeafs,
- std::vector<size_t>& leafIndices,
- const openvdb::math::Transform& xform,
- PointList& points,
- double iso)
- : mDistTree(distTree)
- , mAuxLeafs(auxLeafs)
- , mLeafIndices(leafIndices)
- , mTransform(xform)
+template<typename TreeT>
+SeamWeights<TreeT>::SeamWeights(const TreeT& distTree, const Int16TreeT& refSignTree,
+ IntTreeT& refIdxTree, QuantizedPointList& points, double iso)
+ : mDistAcc(distTree)
+ , mRefSignAcc(refSignTree)
+ , mRefIdxAcc(refIdxTree)
, mPoints(points)
, mIsovalue(iso)
- , mRefData(NULL)
{
}
-template <class DistTreeT>
-PointGen<DistTreeT>::PointGen(const PointGen<DistTreeT>& rhs)
- : mDistTree(rhs.mDistTree)
- , mAuxLeafs(rhs.mAuxLeafs)
- , mLeafIndices(rhs.mLeafIndices)
- , mTransform(rhs.mTransform)
- , mPoints(rhs.mPoints)
- , mIsovalue(rhs.mIsovalue)
- , mRefData(rhs.mRefData)
+template<typename TreeT>
+template <typename LeafNodeType>
+void
+SeamWeights<TreeT>::operator()(LeafNodeType &signLeaf, size_t /*leafIndex*/) const
{
-}
+ Coord coord = signLeaf.origin();
+ const typename Int16TreeT::LeafNodeType *refSignLeafPt = mRefSignAcc.probeConstLeaf(coord);
+ if (!refSignLeafPt) return;
-template <class DistTreeT>
-void
-PointGen<DistTreeT>::setRefData(
- const ReferenceData<DistTreeT>& refData)
-{
- mRefData = &refData;
-}
+ const typename TreeT::LeafNodeType *distLeafPt = mDistAcc.probeConstLeaf(coord);
+ const typename IntTreeT::LeafNodeType *refIdxLeafPt = mRefIdxAcc.probeConstLeaf(coord);
-template <class DistTreeT>
-void
-PointGen<DistTreeT>::runParallel()
-{
- tbb::parallel_for(mAuxLeafs.getRange(), *this);
-}
+ std::vector<double> values(8);
+ unsigned char lhsSigns, rhsSigns;
+ Vec3d point;
+ Index offset;
+ Coord ijk;
+ coord.offset(TreeT::LeafNodeType::DIM - 1);
-template <class DistTreeT>
-void
-PointGen<DistTreeT>::runSerial()
-{
- (*this)(mAuxLeafs.getRange());
-}
+ typename LeafNodeType::ValueOnCIter iter = signLeaf.cbeginValueOn();
+ for (; iter; ++iter) {
+ offset = iter.pos();
+ ijk = iter.getCoord();
-template <class DistTreeT>
-void
-PointGen<DistTreeT>::operator()(const tbb::blocked_range<size_t>& range) const
-{
- typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
- typedef typename DistTreeT::template ValueConverter<Vec3s>::Type Vec3sTreeT;
+ const bool inclusiveCell = ijk[0] < coord[0] && ijk[1] < coord[1] && ijk[2] < coord[2];
- typedef tree::ValueAccessor<BoolTreeT> BoolTreeAccessorT;
- typedef tree::ValueAccessor<Vec3sTreeT> Vec3sTreeAccessorT;
+ if ((iter.getValue() & SEAM) && refSignLeafPt->isValueOn(offset)) {
- typedef typename BoolTreeT::LeafNodeType BoolLeafT;
- typedef typename IntTreeT::LeafNodeType IntLeafT;
- typedef typename Vec3sTreeT::LeafNodeType Vec3sLeafT;
+ lhsSigns = SIGNS & iter.getValue();
+ rhsSigns = SIGNS & refSignLeafPt->getValue(offset);
- boost::scoped_ptr<DistTreeAccessorT> refDistAcc;
- boost::scoped_ptr<BoolTreeAccessorT> refMaskAcc, refSmoothMaskAcc;
- boost::scoped_ptr<Vec3sTreeAccessorT> refPtnAcc;
- if (mRefData && mRefData->isValid()) {
- refDistAcc.reset(new DistTreeAccessorT(*mRefData->mDistTree));
- refMaskAcc.reset(new BoolTreeAccessorT(*mRefData->mTopologyMaskTree));
- refSmoothMaskAcc.reset(new BoolTreeAccessorT(*mRefData->mSmoothingMaskTree));
- refPtnAcc.reset(new Vec3sTreeAccessorT(*mRefData->mSeamPointTree));
- }
+ if (inclusiveCell) {
+ collectCornerValues(*distLeafPt, offset, values);
+ } else {
+ collectCornerValues(mDistAcc, ijk, values);
+ }
- const bool hasRefData = refDistAcc && refMaskAcc;
- typename IntTreeT::LeafNodeType::ValueOnIter auxIter;
- DistTreeAccessorT distAcc(mDistTree);
+ for (size_t n = 1, N = sEdgeGroupTable[lhsSigns][0] + 1; n < N; ++n) {
- Coord ijk;
- openvdb::Vec3d avg, tmp;
+ int id = matchEdgeGroup(n, lhsSigns, rhsSigns);
- for (size_t n = range.begin(); n != range.end(); ++n) {
+ if (id != -1) {
+
+ uint32_t& data = mPoints[refIdxLeafPt->getValue(offset) + (id - 1)];
+
+ if (!(data & MASK_DIRTY_BIT)) {
- size_t idx = mLeafIndices[n];
- IntLeafT& auxLeaf = *mAuxLeafs[n];
+ int smaples = computeMaskedPoint(point, values, lhsSigns, rhsSigns, n, mIsovalue);
- BoolLeafT* maskLeaf = NULL;
- BoolLeafT* smoothMaskLeaf = NULL;
- Vec3sLeafT* ptnLeaf = NULL;
- if (hasRefData) {
- maskLeaf = refMaskAcc->probeLeaf(auxLeaf.getOrigin());
- smoothMaskLeaf = refSmoothMaskAcc->probeLeaf(auxLeaf.getOrigin());
- ptnLeaf = refPtnAcc->probeLeaf(auxLeaf.getOrigin());
+ if (smaples > 0) data = packPoint(point);
+ else data = MASK_INVALID_BIT;
+
+ data |= MASK_DIRTY_BIT;
+ }
+ }
+ }
}
+ }
+}
- for (auxIter = auxLeaf.beginValueOn(); auxIter; ++auxIter) {
- if(auxIter.getValue() == 0) {
+////////////////////////////////////////
- auxIter.setValue(idx);
- auxIter.setValueOff();
- ijk = auxIter.getCoord();
- if (hasRefData && maskLeaf && maskLeaf->isValueOn(ijk)) {
+template <typename TreeT, typename LeafManagerT>
+class MergeVoxelRegions
+{
+public:
+ typedef typename TreeT::ValueType ValueT;
+ typedef tree::ValueAccessor<const TreeT> AccessorT;
- if (ptnLeaf && ptnLeaf->isValueOn(ijk)) {
- avg = ptnLeaf->getValue(ijk);
- } else {
- int e1 = calcAvgPoint(*refDistAcc.get(), ijk, avg);
+ typedef typename TreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef tree::ValueAccessor<IntTreeT> IntAccessorT;
- if (e1 != (XEDGE|YEDGE|ZEDGE)) {
- int e2 = calcAvgPoint(distAcc, ijk, tmp);
- if((e2 & (~e1)) != 0) smoothMaskLeaf->setValueOn(ijk);
- }
- }
- } else {
- calcAvgPoint(distAcc, ijk, avg);
- }
+ typedef typename TreeT::template ValueConverter<bool>::Type BoolTreeT;
- openvdb::Vec3s& ptn = mPoints[idx];
- ptn[0] = float(avg[0]);
- ptn[1] = float(avg[1]);
- ptn[2] = float(avg[2]);
+ typedef typename LeafManagerT::TreeType::template ValueConverter<Int16>::Type Int16TreeT;
+ typedef tree::ValueAccessor<const Int16TreeT> Int16AccessorT;
- ++idx;
- }
- }
+ typedef typename TreeT::template ValueConverter<float>::Type FloatTreeT;
+ typedef Grid<FloatTreeT> FloatGridT;
- while(auxLeaf.onVoxelCount() > 0) {
- avg[0] = 0;
- avg[1] = 0;
- avg[2] = 0;
+ //////////
- auxIter = auxLeaf.beginValueOn();
- int regionId = auxIter.getValue(), points = 0;
+ MergeVoxelRegions(const LeafManagerT& signLeafs, const Int16TreeT& signTree,
+ const TreeT& distTree, IntTreeT& idxTree, ValueT iso, ValueT adaptivity);
- for (; auxIter; ++auxIter) {
- if(auxIter.getValue() == regionId) {
+ void run(bool threaded = true);
- auxIter.setValue(idx);
- auxIter.setValueOff();
- ijk = auxIter.getCoord();
+ void setSpatialAdaptivity(
+ const math::Transform& distGridXForm, const FloatGridT& adaptivityField);
- if (hasRefData && maskLeaf && maskLeaf->isValueOn(ijk)) {
- calcAvgPoint(*refDistAcc.get(), ijk, tmp);
- } else {
- calcAvgPoint(distAcc, ijk, tmp);
- }
+ void setAdaptivityMask(const BoolTreeT* mask);
- avg += tmp;
- ++points;
- }
- }
+ void setRefData(const Int16TreeT* signTree, ValueT adaptivity);
- if (points > 1) {
- double w = 1.0 / double(points);
- avg[0] *= w;
- avg[1] *= w;
- avg[2] *= w;
- }
+ //////////
- openvdb::Vec3s& ptn = mPoints[idx];
- ptn[0] = float(avg[0]);
- ptn[1] = float(avg[1]);
- ptn[2] = float(avg[2]);
- ++idx;
- }
- }
+
+ void operator()(const tbb::blocked_range<size_t>&) const;
+
+private:
+
+ const LeafManagerT& mSignLeafs;
+
+ const Int16TreeT& mSignTree;
+ Int16AccessorT mSignAcc;
+
+ const TreeT& mDistTree;
+ AccessorT mDistAcc;
+
+ IntTreeT& mIdxTree;
+ ValueT mIsovalue, mSurfaceAdaptivity, mInternalAdaptivity;
+
+ const math::Transform* mTransform;
+ const FloatGridT* mAdaptivityGrid;
+ const BoolTreeT* mMask;
+
+ const Int16TreeT* mRefSignTree;
+};
+
+template <typename TreeT, typename LeafManagerT>
+MergeVoxelRegions<TreeT, LeafManagerT>::MergeVoxelRegions(
+ const LeafManagerT& signLeafs, const Int16TreeT& signTree,
+ const TreeT& distTree, IntTreeT& idxTree, ValueT iso, ValueT adaptivity)
+ : mSignLeafs(signLeafs)
+ , mSignTree(signTree)
+ , mSignAcc(mSignTree)
+ , mDistTree(distTree)
+ , mDistAcc(mDistTree)
+ , mIdxTree(idxTree)
+ , mIsovalue(iso)
+ , mSurfaceAdaptivity(adaptivity)
+ , mInternalAdaptivity(adaptivity)
+ , mTransform(NULL)
+ , mAdaptivityGrid(NULL)
+ , mMask(NULL)
+ , mRefSignTree(NULL)
+{
}
-template <class DistTreeT>
-int
-PointGen<DistTreeT>::calcAvgPoint(DistTreeAccessorT& acc,
- const Coord& ijk, openvdb::Vec3d& avg) const
+
+template <typename TreeT, typename LeafManagerT>
+void
+MergeVoxelRegions<TreeT, LeafManagerT>::run(bool threaded)
{
- double values[8];
- bool signMask[8];
- Coord coord;
+ if (threaded) tbb::parallel_for(mSignLeafs.getRange(), *this);
+ else (*this)(mSignLeafs.getRange());
+}
- // Sample corner values
- coord = ijk;
- values[0] = double(acc.getValue(coord)); // i, j, k
- coord[0] += 1;
- values[1] = double(acc.getValue(coord)); // i+1, j, k
+template <typename TreeT, typename LeafManagerT>
+void
+MergeVoxelRegions<TreeT, LeafManagerT>::setSpatialAdaptivity(
+ const math::Transform& distGridXForm, const FloatGridT& adaptivityField)
+{
+ mTransform = &distGridXForm;
+ mAdaptivityGrid = &adaptivityField;
+}
- coord[2] += 1;
- values[2] = double(acc.getValue(coord)); // i+i, j, k+1
- coord[0] = ijk[0];
- values[3] = double(acc.getValue(coord)); // i, j, k+1
+template <typename TreeT, typename LeafManagerT>
+void
+MergeVoxelRegions<TreeT, LeafManagerT>::setAdaptivityMask(const BoolTreeT* mask)
+{
+ mMask = mask;
+}
- coord[1] += 1; coord[2] = ijk[2];
- values[4] = double(acc.getValue(coord)); // i, j+1, k
+template <typename TreeT, typename LeafManagerT>
+void
+MergeVoxelRegions<TreeT, LeafManagerT>::setRefData(const Int16TreeT* signTree, ValueT adaptivity)
+{
+ mRefSignTree = signTree;
+ mInternalAdaptivity = adaptivity;
+}
- coord[0] += 1;
- values[5] = double(acc.getValue(coord)); // i+1, j+1, k
- coord[2] += 1;
- values[6] = double(acc.getValue(coord)); // i+1, j+1, k+1
+template <typename TreeT, typename LeafManagerT>
+void
+MergeVoxelRegions<TreeT, LeafManagerT>::operator()(const tbb::blocked_range<size_t>& range) const
+{
+ typedef math::Vec3<ValueT> Vec3T;
- coord[0] = ijk[0];
- values[7] = double(acc.getValue(coord)); // i, j+1, k+1
+ typedef typename TreeT::LeafNodeType LeafT;
+ typedef typename IntTreeT::LeafNodeType IntLeafT;
+ typedef typename BoolTreeT::LeafNodeType BoolLeafT;
+ typedef typename LeafT::template ValueConverter<Vec3T>::Type Vec3LeafT;
- // init sign mask
- for (int n = 0; n < 8; ++n) signMask[n] = (values[n] < mIsovalue);
+ const int LeafDim = LeafT::DIM;
- int samples = 0, edgeFlags = 0;
- avg[0] = 0.0;
- avg[1] = 0.0;
- avg[2] = 0.0;
+ IntAccessorT idxAcc(mIdxTree);
- if (signMask[0] != signMask[1]) { // Edged: 0 - 1
- avg[0] += root(values[0], values[1]);
- ++samples;
- edgeFlags |= XEDGE;
- }
+ typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter iter;
- if (signMask[1] != signMask[2]) { // Edged: 1 - 2
- avg[0] += 1.0;
- avg[2] += root(values[1], values[2]);
- ++samples;
- edgeFlags |= ZEDGE;
+ typedef typename tree::ValueAccessor<const FloatTreeT> FloatTreeCAccessorT;
+ boost::scoped_ptr<FloatTreeCAccessorT> adaptivityAcc;
+ if (mAdaptivityGrid) {
+ adaptivityAcc.reset(new FloatTreeCAccessorT(mAdaptivityGrid->tree()));
}
- if (signMask[3] != signMask[2]) { // Edged: 3 - 2
- avg[0] += root(values[3], values[2]);
- avg[2] += 1.0;
- ++samples;
- edgeFlags |= XEDGE;
+ typedef typename tree::ValueAccessor<const Int16TreeT> Int16TreeCAccessorT;
+ boost::scoped_ptr<Int16TreeCAccessorT> refAcc;
+ if (mRefSignTree) {
+ refAcc.reset(new Int16TreeCAccessorT(*mRefSignTree));
}
- if (signMask[0] != signMask[3]) { // Edged: 0 - 3
- avg[2] += root(values[0], values[3]);
- ++samples;
- edgeFlags |= ZEDGE;
+ typedef typename tree::ValueAccessor<const BoolTreeT> BoolTreeCAccessorT;
+ boost::scoped_ptr<BoolTreeCAccessorT> maskAcc;
+ if (mMask) {
+ maskAcc.reset(new BoolTreeCAccessorT(*mMask));
}
- if (signMask[4] != signMask[5]) { // Edged: 4 - 5
- avg[0] += root(values[4], values[5]);
- avg[1] += 1.0;
- ++samples;
- edgeFlags |= XEDGE;
- }
+ // Allocate reusable leaf buffers
+ BoolLeafT mask;
+ Vec3LeafT gradientBuffer;
+ Coord ijk, nijk, coord, end;
- if (signMask[5] != signMask[6]) { // Edged: 5 - 6
- avg[0] += 1.0;
- avg[1] += 1.0;
- avg[2] += root(values[5], values[6]);
- ++samples;
- edgeFlags |= ZEDGE;
- }
+ for (size_t n = range.begin(); n != range.end(); ++n) {
- if (signMask[7] != signMask[6]) { // Edged: 7 - 6
- avg[0] += root(values[7], values[6]);
- avg[1] += 1.0;
- avg[2] += 1.0;
- ++samples;
- edgeFlags |= XEDGE;
- }
+ const Coord& origin = mSignLeafs.leaf(n).origin();
- if (signMask[4] != signMask[7]) { // Edged: 4 - 7
- avg[1] += 1.0;
- avg[2] += root(values[4], values[7]);
- ++samples;
- edgeFlags |= ZEDGE;
- }
+ ValueT adaptivity = mSurfaceAdaptivity;
- if (signMask[0] != signMask[4]) { // Edged: 0 - 4
- avg[1] += root(values[0], values[4]);
- ++samples;
- edgeFlags |= YEDGE;
- }
+ if (refAcc && refAcc->probeConstLeaf(origin) == NULL) {
+ adaptivity = mInternalAdaptivity;
+ }
- if (signMask[1] != signMask[5]) { // Edged: 1 - 5
- avg[0] += 1.0;
- avg[1] += root(values[1], values[5]);
- ++samples;
- edgeFlags |= YEDGE;
- }
+ IntLeafT& idxLeaf = *idxAcc.probeLeaf(origin);
- if (signMask[2] != signMask[6]) { // Edged: 2 - 6
- avg[0] += 1.0;
- avg[1] += root(values[2], values[6]);
- avg[2] += 1.0;
- ++samples;
- edgeFlags |= YEDGE;
- }
+ end[0] = origin[0] + LeafDim;
+ end[1] = origin[1] + LeafDim;
+ end[2] = origin[2] + LeafDim;
- if (signMask[3] != signMask[7]) { // Edged: 3 - 7
- avg[1] += root(values[3], values[7]);
- avg[2] += 1.0;
- ++samples;
- edgeFlags |= YEDGE;
- }
+ mask.setValuesOff();
+
+ // Mask off seam line adjacent voxels
+ if (maskAcc) {
+ const BoolLeafT* maskLeaf = maskAcc->probeConstLeaf(origin);
+ if (maskLeaf != NULL) {
+ typename BoolLeafT::ValueOnCIter it;
+ for (it = maskLeaf->cbeginValueOn(); it; ++it) {
+ ijk = it.getCoord();
+ coord[0] = ijk[0] - (ijk[0] % 2);
+ coord[1] = ijk[1] - (ijk[1] % 2);
+ coord[2] = ijk[2] - (ijk[2] % 2);
+ mask.setActiveState(coord, true);
+ }
+ }
+ }
- if (samples > 1) {
- double w = 1.0 / double(samples);
- avg[0] *= w;
- avg[1] *= w;
- avg[2] *= w;
- }
- // offset by cell-origin
- avg[0] += double(ijk[0]);
- avg[1] += double(ijk[1]);
- avg[2] += double(ijk[2]);
+ LeafT adaptivityLeaf(origin, adaptivity);
- avg = mTransform.indexToWorld(avg);
+ if (mAdaptivityGrid) {
+ for (Index offset = 0; offset < LeafT::NUM_VALUES; ++offset) {
+ ijk = adaptivityLeaf.offsetToGlobalCoord(offset);
+ Vec3d xyz = mAdaptivityGrid->transform().worldToIndex(
+ mTransform->indexToWorld(ijk));
+ ValueT tmpA = ValueT(adaptivityAcc->getValue(util::nearestCoord(xyz)));
+ adaptivityLeaf.setValueOnly(offset, tmpA * adaptivity);
+ }
+ }
- return edgeFlags;
+ // Mask off ambiguous voxels
+ for (iter = mSignLeafs.leaf(n).cbeginValueOn(); iter; ++iter) {
+ ijk = iter.getCoord();
+ coord[0] = ijk[0] - (ijk[0] % 2);
+ coord[1] = ijk[1] - (ijk[1] % 2);
+ coord[2] = ijk[2] - (ijk[2] % 2);
+ if(mask.isValueOn(coord)) continue;
+
+
+
+ int flags = int(iter.getValue());
+ unsigned char signs = SIGNS & flags;
+ if ((flags & SEAM) || !sAdaptable[signs] || sEdgeGroupTable[signs][0] > 1) {
+ mask.setActiveState(coord, true);
+ continue;
+ }
+
+ for (int i = 0; i < 26; ++i) {
+ nijk = ijk + util::COORD_OFFSETS[i];
+ signs = SIGNS & mSignAcc.getValue(nijk);
+ if (!sAdaptable[signs] || sEdgeGroupTable[signs][0] > 1) {
+ mask.setActiveState(coord, true);
+ break;
+ }
+ }
+ }
+
+ int dim = 2;
+ // Mask off topologically ambiguous 2x2x2 voxel sub-blocks
+ for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
+ for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
+ for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
+ if (isNonManifold(mDistAcc, ijk, mIsovalue, dim)) {
+ mask.setActiveState(ijk, true);
+ }
+ }
+ }
+ }
+
+ // Compute the gradient for the remaining voxels
+ gradientBuffer.setValuesOff();
+ for (iter = mSignLeafs.leaf(n).cbeginValueOn(); iter; ++iter) {
+
+ ijk = iter.getCoord();
+ coord[0] = ijk[0] - (ijk[0] % dim);
+ coord[1] = ijk[1] - (ijk[1] % dim);
+ coord[2] = ijk[2] - (ijk[2] % dim);
+ if(mask.isValueOn(coord)) continue;
+
+ Vec3T norm(math::ISGradient<math::CD_2ND>::result(mDistAcc, ijk));
+ // Normalize (Vec3's normalize uses isApproxEqual, which uses abs and does more work)
+ ValueT length = norm.length();
+ if (length > ValueT(1.0e-7)) {
+ norm *= ValueT(1.0) / length;
+ }
+ gradientBuffer.setValue(ijk, norm);
+ }
+
+ int regionId = 1, next_dim = dim << 1;
+
+ // Process the first adaptivity level.
+ for (ijk[0] = 0; ijk[0] < LeafDim; ijk[0] += dim) {
+ coord[0] = ijk[0] - (ijk[0] % next_dim);
+ for (ijk[1] = 0; ijk[1] < LeafDim; ijk[1] += dim) {
+ coord[1] = ijk[1] - (ijk[1] % next_dim);
+ for (ijk[2] = 0; ijk[2] < LeafDim; ijk[2] += dim) {
+ coord[2] = ijk[2] - (ijk[2] % next_dim);
+ adaptivity = adaptivityLeaf.getValue(ijk);
+ if (mask.isValueOn(ijk) || !isMergable(gradientBuffer, ijk, dim, adaptivity)) {
+ mask.setActiveState(coord, true);
+ continue;
+ }
+ mergeVoxels(idxLeaf, ijk, dim, regionId++);
+ }
+ }
+ }
+
+
+ // Process remaining adaptivity levels
+ for (dim = 4; dim < LeafDim; dim = dim << 1) {
+ next_dim = dim << 1;
+ coord[0] = ijk[0] - (ijk[0] % next_dim);
+ for (ijk[0] = origin[0]; ijk[0] < end[0]; ijk[0] += dim) {
+ coord[1] = ijk[1] - (ijk[1] % next_dim);
+ for (ijk[1] = origin[1]; ijk[1] < end[1]; ijk[1] += dim) {
+ coord[2] = ijk[2] - (ijk[2] % next_dim);
+ for (ijk[2] = origin[2]; ijk[2] < end[2]; ijk[2] += dim) {
+ adaptivity = adaptivityLeaf.getValue(ijk);
+ if (mask.isValueOn(ijk) || isNonManifold(mDistAcc, ijk, mIsovalue, dim) ||
+ !isMergable(gradientBuffer, ijk, dim, adaptivity))
+ {
+ mask.setActiveState(coord, true);
+ continue;
+ }
+ mergeVoxels(idxLeaf, ijk, dim, regionId++);
+ }
+ }
+ }
+ }
+
+ adaptivity = adaptivityLeaf.getValue(origin);
+ if (!(mask.isValueOn(origin) || isNonManifold(mDistAcc, origin, mIsovalue, LeafDim))
+ && isMergable(gradientBuffer, origin, LeafDim, adaptivity))
+ {
+ mergeVoxels(idxLeaf, origin, LeafDim, regionId++);
+ }
+ }
}
////////////////////////////////////////
-struct QuadMeshOp
+// Constructs qudas
+struct UniformPrimBuilder
{
- QuadMeshOp(): mIdx(0), mPolygonPool(NULL) {}
+ UniformPrimBuilder(): mIdx(0), mPolygonPool(NULL) {}
void init(const size_t upperBound, PolygonPool& quadPool)
{
@@ -1331,7 +2353,10 @@ struct QuadMeshOp
++mIdx;
}
- void done() {}
+ void done()
+ {
+ mPolygonPool->trimQuads(mIdx);
+ }
private:
size_t mIdx;
@@ -1339,16 +2364,16 @@ private:
};
-struct AdaptiveMeshOp
+// Constructs qudas and triangles
+struct AdaptivePrimBuilder
{
- AdaptiveMeshOp(): mQuadIdx(0), mTriangleIdx(0), mPolygonPool(NULL), mTmpPolygonPool() {}
+ AdaptivePrimBuilder() : mQuadIdx(0), mTriangleIdx(0), mPolygonPool(NULL) {}
void init(const size_t upperBound, PolygonPool& polygonPool)
{
mPolygonPool = &polygonPool;
-
- mTmpPolygonPool.resetQuads(upperBound);
- mTmpPolygonPool.resetTriangles(upperBound);
+ mPolygonPool->resetQuads(upperBound);
+ mPolygonPool->resetTriangles(upperBound);
mQuadIdx = 0;
mTriangleIdx = 0;
@@ -1358,35 +2383,35 @@ struct AdaptiveMeshOp
{
if (verts[0] != verts[1] && verts[0] != verts[2] && verts[0] != verts[3]
&& verts[1] != verts[2] && verts[1] != verts[3] && verts[2] != verts[3]) {
- mTmpPolygonPool.quadFlags(mQuadIdx) = flags;
+ mPolygonPool->quadFlags(mQuadIdx) = flags;
addQuad(verts, reverse);
} else if (
verts[0] == verts[3] &&
verts[1] != verts[2] &&
verts[1] != verts[0] &&
verts[2] != verts[0]) {
- mTmpPolygonPool.triangleFlags(mTriangleIdx) = flags;
+ mPolygonPool->triangleFlags(mTriangleIdx) = flags;
addTriangle(verts[0], verts[1], verts[2], reverse);
} else if (
verts[1] == verts[2] &&
verts[0] != verts[3] &&
verts[0] != verts[1] &&
verts[3] != verts[1]) {
- mTmpPolygonPool.triangleFlags(mTriangleIdx) = flags;
+ mPolygonPool->triangleFlags(mTriangleIdx) = flags;
addTriangle(verts[0], verts[1], verts[3], reverse);
} else if (
verts[0] == verts[1] &&
verts[2] != verts[3] &&
verts[2] != verts[0] &&
verts[3] != verts[0]) {
- mTmpPolygonPool.triangleFlags(mTriangleIdx) = flags;
+ mPolygonPool->triangleFlags(mTriangleIdx) = flags;
addTriangle(verts[0], verts[2], verts[3], reverse);
} else if (
verts[2] == verts[3] &&
verts[0] != verts[1] &&
verts[0] != verts[2] &&
verts[1] != verts[2]) {
- mTmpPolygonPool.triangleFlags(mTriangleIdx) = flags;
+ mPolygonPool->triangleFlags(mTriangleIdx) = flags;
addTriangle(verts[0], verts[1], verts[2], reverse);
}
}
@@ -1394,19 +2419,8 @@ struct AdaptiveMeshOp
void done()
{
- mPolygonPool->resetQuads(mQuadIdx);
- for (size_t i = 0; i < mQuadIdx; ++i) {
- mPolygonPool->quad(i) = mTmpPolygonPool.quad(i);
- mPolygonPool->quadFlags(i) = mTmpPolygonPool.quadFlags(i);
- }
- mTmpPolygonPool.clearQuads();
-
- mPolygonPool->resetTriangles(mTriangleIdx);
- for (size_t i = 0; i < mTriangleIdx; ++i) {
- mPolygonPool->triangle(i) = mTmpPolygonPool.triangle(i);
- mPolygonPool->triangleFlags(i) = mTmpPolygonPool.triangleFlags(i);
- }
- mTmpPolygonPool.clearTriangles();
+ mPolygonPool->trimQuads(mQuadIdx, /*reallocate=*/true);
+ mPolygonPool->trimTrinagles(mTriangleIdx, /*reallocate=*/true);
}
private:
@@ -1414,9 +2428,9 @@ private:
void addQuad(const Vec4I& verts, bool reverse)
{
if (!reverse) {
- mTmpPolygonPool.quad(mQuadIdx) = verts;
+ mPolygonPool->quad(mQuadIdx) = verts;
} else {
- Vec4I& quad = mTmpPolygonPool.quad(mQuadIdx);
+ Vec4I& quad = mPolygonPool->quad(mQuadIdx);
quad[0] = verts[3];
quad[1] = verts[2];
quad[2] = verts[1];
@@ -1427,7 +2441,7 @@ private:
void addTriangle(unsigned v0, unsigned v1, unsigned v2, bool reverse)
{
- Vec3I& prim = mTmpPolygonPool.triangle(mTriangleIdx);
+ Vec3I& prim = mPolygonPool->triangle(mTriangleIdx);
prim[1] = v1;
@@ -1443,206 +2457,295 @@ private:
size_t mQuadIdx, mTriangleIdx;
PolygonPool *mPolygonPool;
- PolygonPool mTmpPolygonPool;
};
-////////////////////////////////////////
+template<typename SignAccT, typename IdxAccT, typename PrimBuilder>
+inline void
+constructPolygons(Int16 flags, Int16 refFlags, const Vec4i& offsets, const Coord& ijk,
+ const SignAccT& signAcc, const IdxAccT& idxAcc, PrimBuilder& mesher, Index32 pointListSize)
+{
+ const Index32 v0 = idxAcc.getValue(ijk);
+ if (v0 == util::INVALID_IDX) return;
+ char tag[2];
+ tag[0] = (flags & SEAM) ? POLYFLAG_FRACTURE_SEAM : 0;
+ tag[1] = tag[0] | char(POLYFLAG_EXTERIOR);
-template<class DistTreeT, class MeshingOp>
-class MeshGen
-{
-public:
- typedef typename DistTreeT::template ValueConverter<char>::Type CharTreeT;
- typedef typename DistTreeT::template ValueConverter<int>::Type IntTreeT;
+ const bool isInside = flags & INSIDE;
- MeshGen(const LeafCPtrList<CharTreeT>& edgeLeafs, const IntTreeT& auxTree, PolygonPoolList&);
- MeshGen(const MeshGen<DistTreeT, MeshingOp>&);
+ Coord coord;
+ openvdb::Vec4I quad;
+ unsigned char cell;
+ Index32 tmpIdx = 0;
- void setRefData(const ReferenceData<DistTreeT>&);
+ if (flags & XEDGE) {
- void runParallel();
- void runSerial();
+ quad[0] = v0 + offsets[0];
- void operator()(const tbb::blocked_range<size_t>&) const;
+ // i, j-1, k
+ coord[0] = ijk[0];
+ coord[1] = ijk[1] - 1;
+ coord[2] = ijk[2];
-private:
- const LeafCPtrList<CharTreeT>& mEdgeLeafs;
- const IntTreeT& mAuxTree;
- const PolygonPoolList& mPolygonPoolList;
- size_t mID;
- const ReferenceData<DistTreeT>* mRefData;
-};
+ quad[1] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[1] + Index32(sEdgeGroupTable[cell][5] - 1);
+ if (tmpIdx < pointListSize) quad[1] = tmpIdx;
+ }
+ // i, j-1, k-1
+ coord[2] -= 1;
-template<class DistTreeT, class MeshingOp>
-MeshGen<DistTreeT, MeshingOp>::MeshGen(const LeafCPtrList<CharTreeT>& edgeLeafs,
- const IntTreeT& auxTree, PolygonPoolList& polygonPoolList)
- : mEdgeLeafs(edgeLeafs)
- , mAuxTree(auxTree)
- , mPolygonPoolList(polygonPoolList)
- , mRefData(NULL)
-{
-}
+ quad[2] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[2] + Index32(sEdgeGroupTable[cell][7] - 1);
+ if (tmpIdx < pointListSize) quad[2] = tmpIdx;
+ }
+ // i, j, k-1
+ coord[1] = ijk[1];
-template<class DistTreeT, class MeshingOp>
-MeshGen<DistTreeT, MeshingOp>::MeshGen(const MeshGen<DistTreeT, MeshingOp>& rhs)
- : mEdgeLeafs(rhs.mEdgeLeafs)
- , mAuxTree(rhs.mAuxTree)
- , mPolygonPoolList(rhs.mPolygonPoolList)
- , mRefData(rhs.mRefData)
-{
+ quad[3] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[3] + Index32(sEdgeGroupTable[cell][3] - 1);
+ if (tmpIdx < pointListSize) quad[3] = tmpIdx;
+ }
+
+ if (quad[1] != util::INVALID_IDX &&
+ quad[2] != util::INVALID_IDX && quad[3] != util::INVALID_IDX) {
+ mesher.addPrim(quad, isInside, tag[bool(refFlags & XEDGE)]);
+ }
+ }
+
+
+ if (flags & YEDGE) {
+
+ quad[0] = v0 + offsets[1];
+
+ // i, j, k-1
+ coord[0] = ijk[0];
+ coord[1] = ijk[1];
+ coord[2] = ijk[2] - 1;
+
+ quad[1] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[1] + Index32(sEdgeGroupTable[cell][12] - 1);
+ if (tmpIdx < pointListSize) quad[1] = tmpIdx;
+ }
+
+ // i-1, j, k-1
+ coord[0] -= 1;
+
+ quad[2] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[2] + Index32(sEdgeGroupTable[cell][11] - 1);
+ if (tmpIdx < pointListSize) quad[2] = tmpIdx;
+ }
+
+ // i-1, j, k
+ coord[2] = ijk[2];
+
+ quad[3] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[3] + Index32(sEdgeGroupTable[cell][10] - 1);
+ if (tmpIdx < pointListSize) quad[3] = tmpIdx;
+ }
+
+ if (quad[1] != util::INVALID_IDX &&
+ quad[2] != util::INVALID_IDX && quad[3] != util::INVALID_IDX) {
+ mesher.addPrim(quad, isInside, tag[bool(refFlags & YEDGE)]);
+ }
+ }
+
+ if (flags & ZEDGE) {
+
+ quad[0] = v0 + offsets[2];
+
+ // i, j-1, k
+ coord[0] = ijk[0];
+ coord[1] = ijk[1] - 1;
+ coord[2] = ijk[2];
+
+ quad[1] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[1] + Index32(sEdgeGroupTable[cell][8] - 1);
+ if (tmpIdx < pointListSize) quad[1] = tmpIdx;
+ }
+
+ // i-1, j-1, k
+ coord[0] -= 1;
+
+ quad[2] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[2] + Index32(sEdgeGroupTable[cell][6] - 1);
+ if (tmpIdx < pointListSize) quad[2] = tmpIdx;
+ }
+
+ // i-1, j, k
+ coord[1] = ijk[1];
+
+ quad[3] = idxAcc.getValue(coord);
+ cell = SIGNS & signAcc.getValue(coord);
+ if (sEdgeGroupTable[cell][0] > 1) {
+ tmpIdx = quad[3] + Index32(sEdgeGroupTable[cell][2] - 1);
+ if (tmpIdx < pointListSize) quad[3] = tmpIdx;
+ }
+
+ if (quad[1] != util::INVALID_IDX &&
+ quad[2] != util::INVALID_IDX && quad[3] != util::INVALID_IDX) {
+ mesher.addPrim(quad, !isInside, tag[bool(refFlags & ZEDGE)]);
+ }
+ }
}
-template<class DistTreeT, class MeshingOp>
-void
-MeshGen<DistTreeT, MeshingOp>::setRefData(
- const ReferenceData<DistTreeT>& refData)
+////////////////////////////////////////
+
+
+template<typename LeafManagerT, typename PrimBuilder>
+class GenPolygons
{
- mRefData = &refData;
-}
+public:
+ typedef typename LeafManagerT::TreeType::template ValueConverter<int>::Type IntTreeT;
+ typedef typename LeafManagerT::TreeType::template ValueConverter<Int16>::Type Int16TreeT;
+ typedef tree::ValueAccessor<const IntTreeT> IntAccessorT;
+ typedef tree::ValueAccessor<const Int16TreeT> Int16AccessorT;
-template<class DistTreeT, class MeshingOp>
-void
-MeshGen<DistTreeT, MeshingOp>::runParallel()
+ //////////
+
+
+ GenPolygons(const LeafManagerT& signLeafs, const Int16TreeT& signTree,
+ const IntTreeT& idxTree, PolygonPoolList& polygons, Index32 pointListSize);
+
+ void run(bool threaded = true);
+
+
+ void setRefSignTree(const Int16TreeT *r) { mRefSignTree = r; }
+
+ //////////
+
+
+ void operator()(const tbb::blocked_range<size_t>&) const;
+
+private:
+ const LeafManagerT& mSignLeafs;
+ const Int16TreeT& mSignTree;
+ const IntTreeT& mIdxTree;
+ const PolygonPoolList& mPolygonPoolList;
+ const Index32 mPointListSize;
+
+ const Int16TreeT *mRefSignTree;
+ };
+
+
+template<typename LeafManagerT, typename PrimBuilder>
+GenPolygons<LeafManagerT, PrimBuilder>::GenPolygons(const LeafManagerT& signLeafs,
+ const Int16TreeT& signTree, const IntTreeT& idxTree, PolygonPoolList& polygons,
+ Index32 pointListSize)
+ : mSignLeafs(signLeafs)
+ , mSignTree(signTree)
+ , mIdxTree(idxTree)
+ , mPolygonPoolList(polygons)
+ , mPointListSize(pointListSize)
+ , mRefSignTree(NULL)
{
- tbb::parallel_for(mEdgeLeafs.getRange(), *this);
}
-
-template<class DistTreeT, class MeshingOp>
+template<typename LeafManagerT, typename PrimBuilder>
void
-MeshGen<DistTreeT, MeshingOp>::runSerial()
+GenPolygons<LeafManagerT, PrimBuilder>::run(bool threaded)
{
- (*this)(mEdgeLeafs.getRange());
+ if (threaded) tbb::parallel_for(mSignLeafs.getRange(), *this);
+ else (*this)(mSignLeafs.getRange());
}
-
-template<class DistTreeT, class MeshingOp>
+template<typename LeafManagerT, typename PrimBuilder>
void
-MeshGen<DistTreeT, MeshingOp>::operator()(
+GenPolygons<LeafManagerT, PrimBuilder>::operator()(
const tbb::blocked_range<size_t>& range) const
{
- typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
- typedef typename BoolTreeT::LeafNodeType BoolLeafT;
- typedef typename CharTreeT::LeafNodeType CharLeafT;
+ typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter iter;
+ IntAccessorT idxAcc(mIdxTree);
+ Int16AccessorT signAcc(mSignTree);
- typedef openvdb::tree::ValueAccessor<const CharTreeT> CharTreeAccessorT;
- typedef openvdb::tree::ValueAccessor<const IntTreeT> IntTreeAccessorT;
- typedef openvdb::tree::ValueAccessor<const BoolTreeT> BoolTreeAccessorT;
- boost::scoped_ptr<CharTreeAccessorT> refEdgeAcc;
- boost::scoped_ptr<BoolTreeAccessorT> refMaskAcc;
- if (mRefData && mRefData->isValid()) {
- refEdgeAcc.reset(new CharTreeAccessorT(*mRefData->mEdgeTree));
- refMaskAcc.reset(new BoolTreeAccessorT(*mRefData->mSeamMaskTree.get()));
- }
- const bool hasRefData = refEdgeAcc && refMaskAcc;
+ PrimBuilder mesher;
+ size_t edgeCount;
+ Coord ijk, origin;
- typename CharTreeT::LeafNodeType::ValueOnCIter iter;
- IntTreeAccessorT auxAcc(mAuxTree);
+ // reference data
+ boost::scoped_ptr<Int16AccessorT> refSignAcc;
+ if (mRefSignTree) refSignAcc.reset(new Int16AccessorT(*mRefSignTree));
- Coord ijk, coord;
- char refEdgeFlags, isSemLinePoly;
- const char isExteriorPoly[2] = {0, char(POLYFLAG_EXTERIOR)};
- openvdb::Vec4I quad;
- size_t edgeCount;
-
- MeshingOp mesher;
for (size_t n = range.begin(); n != range.end(); ++n) {
- const Coord origin = mEdgeLeafs[n]->getOrigin();
+ origin = mSignLeafs.leaf(n).origin();
// Get an upper bound on the number of primitives.
edgeCount = 0;
- iter = mEdgeLeafs[n]->cbeginValueOn();
+ iter = mSignLeafs.leaf(n).cbeginValueOn();
for (; iter; ++iter) {
- char edgeFlags = iter.getValue() >> 1;
- edgeCount += edgeFlags & 0x1;
-
- edgeFlags = edgeFlags >> 1;
- edgeCount += edgeFlags & 0x1;
-
- edgeFlags = edgeFlags >> 1;
- edgeCount += edgeFlags & 0x1;
+ if (iter.getValue() & XEDGE) ++edgeCount;
+ if (iter.getValue() & YEDGE) ++edgeCount;
+ if (iter.getValue() & ZEDGE) ++edgeCount;
}
+ if(edgeCount == 0) continue;
+
mesher.init(edgeCount, mPolygonPoolList[n]);
- const CharLeafT* refEdgeLeaf = NULL;
- const BoolLeafT* refMaskLeaf = NULL;
+ const typename Int16TreeT::LeafNodeType *signleafPt = signAcc.probeConstLeaf(origin);
+ const typename IntTreeT::LeafNodeType *idxLeafPt = idxAcc.probeConstLeaf(origin);
- if (hasRefData) {
- refEdgeLeaf = refEdgeAcc->probeConstLeaf(origin);
- refMaskLeaf = refMaskAcc->probeConstLeaf(origin);
- }
+ if (!signleafPt || !idxLeafPt) continue;
- iter = mEdgeLeafs[n]->cbeginValueOn();
- for (; iter; ++iter) {
- ijk = iter.getCoord();
- const char& edgeFlags = iter.getValue();
- const bool isInside = edgeFlags & INSIDE;
-
- refEdgeFlags = 0;
- isSemLinePoly = 0;
- if (hasRefData) {
- if(refEdgeLeaf) refEdgeFlags = refEdgeLeaf->getValue(ijk);
- if (refMaskLeaf && refMaskLeaf->isValueOn(ijk)) {
- isSemLinePoly = char(POLYFLAG_FRACTURE_SEAM);
- }
- }
+ const typename Int16TreeT::LeafNodeType *refSignLeafPt = NULL;
+ if (refSignAcc) refSignLeafPt = refSignAcc->probeConstLeaf(origin);
+ Vec4i offsets;
- int v0 = auxAcc.getValue(ijk);
+ iter = mSignLeafs.leaf(n).cbeginValueOn();
+ for (; iter; ++iter) {
+ ijk = iter.getCoord();
- if (edgeFlags & XEDGE) {
+ Int16 flags = iter.getValue();
- quad[0] = v0;
- coord[0] = ijk[0]; coord[1] = ijk[1]-1; coord[2] = ijk[2]; // i, j-1, k
- quad[1] = auxAcc.getValue(coord);
- coord[2] -= 1; // i, j-1, k-1
- quad[2] = auxAcc.getValue(coord);
- coord[1] = ijk[1]; // i, j, k-1
- quad[3] = auxAcc.getValue(coord);
+ if (!(flags & 0xE00)) continue;
- mesher.addPrim(quad, isInside,
- (isSemLinePoly | isExteriorPoly[bool(refEdgeFlags & XEDGE)]));
+ Int16 refFlags = 0;
+ if (refSignLeafPt) {
+ refFlags = refSignLeafPt->getValue(iter.pos());
}
+ offsets[0] = 0;
+ offsets[1] = 0;
+ offsets[2] = 0;
- if (edgeFlags & YEDGE) {
-
- quad[0] = v0;
- coord[0] = ijk[0]; coord[1] = ijk[1]; coord[2] = ijk[2]-1; // i, j, k-1
- quad[1] = auxAcc.getValue(coord);
- coord[0] -= 1; // i-1, j, k-1
- quad[2] = auxAcc.getValue(coord);
- coord[2] = ijk[2]; // i-1, j, k
- quad[3] = auxAcc.getValue(coord);
+ const unsigned char cell = (SIGNS & flags);
- mesher.addPrim(quad, isInside,
- (isSemLinePoly | isExteriorPoly[bool(refEdgeFlags & YEDGE)]));
+ if (sEdgeGroupTable[cell][0] > 1) {
+ offsets[0] = (sEdgeGroupTable[cell][1] - 1);
+ offsets[1] = (sEdgeGroupTable[cell][9] - 1);
+ offsets[2] = (sEdgeGroupTable[cell][4] - 1);
}
- if (edgeFlags & ZEDGE) {
-
- quad[0] = v0;
- coord[0] = ijk[0]; coord[1] = ijk[1]-1; coord[2] = ijk[2]; // i, j-1, k
- quad[1] = auxAcc.getValue(coord);
- coord[0] -= 1; // i-1, j-1, k
- quad[2] = auxAcc.getValue(coord);
- coord[1] = ijk[1]; // i, j, k
- quad[3] = auxAcc.getValue(coord);
-
- mesher.addPrim(quad, !isInside,
- (isSemLinePoly | isExteriorPoly[bool(refEdgeFlags & ZEDGE)]));
+ if (ijk[0] > origin[0] && ijk[1] > origin[1] && ijk[2] > origin[2]) {
+ constructPolygons(flags, refFlags, offsets, ijk, *signleafPt, *idxLeafPt, mesher, mPointListSize);
+ } else {
+ constructPolygons(flags, refFlags, offsets, ijk, signAcc, idxAcc, mesher, mPointListSize);
}
}
@@ -1653,474 +2756,699 @@ MeshGen<DistTreeT, MeshingOp>::operator()(
////////////////////////////////////////
+// Masking and mesh partitioning
-template<class DistTreeT, class AuxDataT = int>
-class AuxiliaryData
+struct PartOp
{
-public:
- typedef openvdb::tree::ValueAccessor<const DistTreeT> SourceAccessorT;
- typedef typename DistTreeT::ValueType ValueT;
- typedef typename DistTreeT::template ValueConverter<char>::Type CharTreeT;
- typedef openvdb::tree::ValueAccessor<CharTreeT> EdgeAccessorT;
+ PartOp(size_t leafCount, size_t partitions, size_t activePart)
+ {
+ size_t leafSegments = leafCount / partitions;
+ mStart = leafSegments * activePart;
+ mEnd = activePart >= (partitions - 1) ? leafCount : mStart + leafSegments;
+ }
- typedef typename DistTreeT::template ValueConverter<AuxDataT>::Type AuxTreeT;
- typedef openvdb::tree::ValueAccessor<AuxTreeT> AuxAccessorT;
+ template <typename LeafNodeType>
+ void operator()(LeafNodeType &leaf, size_t leafIndex) const
+ {
+ if (leafIndex < mStart || leafIndex >= mEnd) leaf.setValuesOff();
+ }
- AuxiliaryData(const DistTreeT&, const LeafCPtrList<DistTreeT>&,
- double iso = 0.0, bool extraCheck = false);
- AuxiliaryData(AuxiliaryData&, tbb::split);
+private:
+ size_t mStart, mEnd;
+};
- void runParallel();
- void runSerial();
- typename CharTreeT::Ptr edgeTree() const { return mEdgeTree; }
- typename AuxTreeT::Ptr auxTree() const { return mAuxTree; }
+////////////////////////////////////////
- void operator()(const tbb::blocked_range<size_t>&);
- void join(const AuxiliaryData& rhs)
- {
- mEdgeTree->merge(*rhs.mEdgeTree);
- mAuxTree->merge(*rhs.mAuxTree);
- }
+template<typename SrcTreeT>
+class PartGen
+{
+public:
+ typedef tree::LeafManager<const SrcTreeT> LeafManagerT;
+ typedef typename SrcTreeT::template ValueConverter<bool>::Type BoolTreeT;
+ typedef tree::ValueAccessor<BoolTreeT> BoolAccessorT;
-private:
- const LeafCPtrList<DistTreeT>& mLeafNodes;
- const DistTreeT& mSourceTree;
- SourceAccessorT mSourceAccessor;
+ //////////
- typename CharTreeT::Ptr mEdgeTree;
- EdgeAccessorT mEdgeAccessor;
- typename AuxTreeT::Ptr mAuxTree;
- AuxAccessorT mAuxAccessor;
+ PartGen(const LeafManagerT& leafs, size_t partitions, size_t activePart);
- const double mIsovalue;
- const bool mExtraCheck;
+ void run(bool threaded = true);
+
+ BoolTreeT& tree() { return mTree; }
- int edgeCheck(const Coord& ijk, const bool thisInside);
+
+ //////////
+
+ PartGen(PartGen&, tbb::split);
+ void operator()(const tbb::blocked_range<size_t>&);
+ void join(PartGen& rhs) { mTree.merge(rhs.mTree); }
+
+private:
+ const LeafManagerT& mLeafManager;
+ BoolTreeT mTree;
+ size_t mStart, mEnd;
};
-template<class DistTreeT, class AuxDataT>
-AuxiliaryData<DistTreeT, AuxDataT>::AuxiliaryData(const DistTreeT& tree,
- const LeafCPtrList<DistTreeT>& leafNodes, double iso, bool extraCheck)
- : mLeafNodes(leafNodes)
- , mSourceTree(tree)
- , mSourceAccessor(mSourceTree)
- , mEdgeTree(new CharTreeT(0))
- , mEdgeAccessor(*mEdgeTree)
- , mAuxTree(new AuxTreeT(AuxDataT(0)))
- , mAuxAccessor(*mAuxTree)
- , mIsovalue(iso)
- , mExtraCheck(extraCheck)
+template<typename SrcTreeT>
+PartGen<SrcTreeT>::PartGen(const LeafManagerT& leafs, size_t partitions, size_t activePart)
+ : mLeafManager(leafs)
+ , mTree(false)
+ , mStart(0)
+ , mEnd(0)
{
+ size_t leafCount = leafs.leafCount();
+ size_t leafSegments = leafCount / partitions;
+ mStart = leafSegments * activePart;
+ mEnd = activePart >= (partitions - 1) ? leafCount : mStart + leafSegments;
}
-template<class DistTreeT, class AuxDataT>
-AuxiliaryData<DistTreeT, AuxDataT>::AuxiliaryData(AuxiliaryData& rhs, tbb::split)
- : mLeafNodes(rhs.mLeafNodes)
- , mSourceTree(rhs.mSourceTree)
- , mSourceAccessor(mSourceTree)
- , mEdgeTree(new CharTreeT(0))
- , mEdgeAccessor(*mEdgeTree)
- , mAuxTree(new AuxTreeT(AuxDataT(0)))
- , mAuxAccessor(*mAuxTree)
- , mIsovalue(rhs.mIsovalue)
- , mExtraCheck(rhs.mExtraCheck)
+template<typename SrcTreeT>
+PartGen<SrcTreeT>::PartGen(PartGen& rhs, tbb::split)
+ : mLeafManager(rhs.mLeafManager)
+ , mTree(false)
+ , mStart(rhs.mStart)
+ , mEnd(rhs.mEnd)
{
}
+template<typename SrcTreeT>
+void
+PartGen<SrcTreeT>::run(bool threaded)
+{
+ if (threaded) tbb::parallel_reduce(mLeafManager.getRange(), *this);
+ else (*this)(mLeafManager.getRange());
+}
+
-template<class DistTreeT, typename AuxDataT>
+template<typename SrcTreeT>
void
-AuxiliaryData<DistTreeT, AuxDataT>::runParallel()
+PartGen<SrcTreeT>::operator()(const tbb::blocked_range<size_t>& range)
{
- tbb::parallel_reduce(mLeafNodes.getRange(), *this);
+ Coord ijk;
+ BoolAccessorT acc(mTree);
+
+ typedef typename BoolTreeT::LeafNodeType BoolLeafT;
+ typename SrcTreeT::LeafNodeType::ValueOnCIter iter;
+
+ for (size_t n = range.begin(); n != range.end(); ++n) {
+ if (n < mStart || n >= mEnd) continue;
+ BoolLeafT* leaf = acc.touchLeaf(mLeafManager.leaf(n).origin());
+ leaf->topologyUnion(mLeafManager.leaf(n));
+ }
}
-template<class DistTreeT, typename AuxDataT>
+
+////////////////////////////////////////
+
+
+template<typename TreeT, typename LeafManagerT>
+class GenSeamMask
+{
+public:
+ typedef typename TreeT::template ValueConverter<bool>::Type BoolTreeT;
+
+ //////////
+
+ GenSeamMask(const LeafManagerT& leafs, const TreeT& tree);
+
+ void run(bool threaded = true);
+
+ BoolTreeT& mask() { return mMaskTree; }
+
+ //////////
+
+ GenSeamMask(GenSeamMask&, tbb::split);
+ void operator()(const tbb::blocked_range<size_t>&);
+ void join(GenSeamMask& rhs) { mMaskTree.merge(rhs.mMaskTree); }
+
+private:
+
+ const LeafManagerT& mLeafManager;
+ const TreeT& mTree;
+
+ BoolTreeT mMaskTree;
+};
+
+
+template<typename TreeT, typename LeafManagerT>
+GenSeamMask<TreeT, LeafManagerT>::GenSeamMask(const LeafManagerT& leafs, const TreeT& tree)
+ : mLeafManager(leafs)
+ , mTree(tree)
+ , mMaskTree(false)
+{
+}
+
+
+template<typename TreeT, typename LeafManagerT>
+GenSeamMask<TreeT, LeafManagerT>::GenSeamMask(GenSeamMask& rhs, tbb::split)
+ : mLeafManager(rhs.mLeafManager)
+ , mTree(rhs.mTree)
+ , mMaskTree(false)
+{
+}
+
+
+template<typename TreeT, typename LeafManagerT>
void
-AuxiliaryData<DistTreeT, AuxDataT>::runSerial()
+GenSeamMask<TreeT, LeafManagerT>::run(bool threaded)
{
- (*this)(mLeafNodes.getRange());
+ if (threaded) tbb::parallel_reduce(mLeafManager.getRange(), *this);
+ else (*this)(mLeafManager.getRange());
}
-template<class DistTreeT, typename AuxDataT>
+
+template<typename TreeT, typename LeafManagerT>
void
-AuxiliaryData<DistTreeT, AuxDataT>::operator()(const tbb::blocked_range<size_t>& range)
+GenSeamMask<TreeT, LeafManagerT>::operator()(const tbb::blocked_range<size_t>& range)
{
- typename DistTreeT::LeafNodeType::ValueOnCIter iter;
Coord ijk;
- bool thisInside;
- int edgeFlags;
- ValueT val;
+ tree::ValueAccessor<const TreeT> acc(mTree);
+ tree::ValueAccessor<BoolTreeT> maskAcc(mMaskTree);
- if (!mExtraCheck) {
- for (size_t n = range.begin(); n != range.end(); ++n) {
- for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
- ijk = iter.getCoord();
- thisInside = iter.getValue() < mIsovalue;
- edgeFlags = edgeCheck(ijk, thisInside);
+ typename LeafManagerT::TreeType::LeafNodeType::ValueOnCIter it;
+
+ for (size_t n = range.begin(); n != range.end(); ++n) {
+
+ it = mLeafManager.leaf(n).cbeginValueOn();
+
+ for (; it; ++it) {
+
+ ijk = it.getCoord();
- if (edgeFlags != 0) {
- edgeFlags |= int(thisInside);
- mEdgeAccessor.setValue(ijk, char(edgeFlags));
+ unsigned char rhsSigns = acc.getValue(ijk) & SIGNS;
+
+ if (sEdgeGroupTable[rhsSigns][0] > 0) {
+ unsigned char lhsSigns = it.getValue() & SIGNS;
+ if (rhsSigns != lhsSigns) {
+ maskAcc.setValueOn(ijk);
}
}
}
- } else {
- for (size_t n = range.begin(); n != range.end(); ++n) {
- for (iter = mLeafNodes[n]->cbeginValueOn(); iter; ++iter) {
+ }
+}
- ijk = iter.getCoord();
- thisInside = iter.getValue() < mIsovalue;
- edgeFlags = edgeCheck(ijk, thisInside);
- if (edgeFlags != 0) {
- edgeFlags |= int(thisInside);
- mEdgeAccessor.setValue(ijk, char(edgeFlags));
- }
+////////////////////////////////////////
- --ijk[0];
- if (!mSourceAccessor.probeValue(ijk, val)) {
- thisInside = val < mIsovalue;
- edgeFlags = edgeCheck(ijk, thisInside);
- if (edgeFlags != 0) {
- edgeFlags |= int(thisInside);
- mEdgeAccessor.setValue(ijk, char(edgeFlags));
- }
- }
+template<typename TreeT>
+class TagSeamEdges
+{
+public:
+ typedef tree::ValueAccessor<const TreeT> AccessorT;
- ++ijk[0];
- --ijk[1];
- if (!mSourceAccessor.probeValue(ijk, val)) {
- thisInside = val < mIsovalue;
- edgeFlags = edgeCheck(ijk, thisInside);
+ TagSeamEdges(const TreeT& tree) : mAcc(tree) {}
- if (edgeFlags != 0) {
- edgeFlags |= int(thisInside);
- mEdgeAccessor.setValue(ijk, char(edgeFlags));
- }
- }
+ template <typename LeafNodeType>
+ void operator()(LeafNodeType &leaf, size_t/*leafIndex*/) const
+ {
+ const typename TreeT::LeafNodeType *maskLeaf =
+ mAcc.probeConstLeaf(leaf.origin());
- ++ijk[1];
- --ijk[2];
- if (!mSourceAccessor.probeValue(ijk, val)) {
- thisInside = val < mIsovalue;
- edgeFlags = edgeCheck(ijk, thisInside);
+ if (!maskLeaf) return;
- if (edgeFlags != 0) {
- edgeFlags |= int(thisInside);
- mEdgeAccessor.setValue(ijk, char(edgeFlags));
- }
- }
+ typename LeafNodeType::ValueOnIter it = leaf.beginValueOn();
+
+ for (; it; ++it) {
+
+ if (maskLeaf->isValueOn(it.pos())) {
+ it.setValue(it.getValue() | SEAM);
}
}
}
-}
-template<class DistTreeT, typename AuxDataT>
-inline int
-AuxiliaryData<DistTreeT, AuxDataT>::edgeCheck(const Coord& ijk, const bool thisInside)
+private:
+ AccessorT mAcc;
+};
+
+
+
+template<typename BoolTreeT>
+struct MaskEdges
{
- int edgeFlags = 0;
- Coord n_ijk, coord;
+ typedef tree::ValueAccessor<const BoolTreeT> BoolAccessorT;
+
+ MaskEdges(const BoolTreeT& valueMask) : mMaskAcc(valueMask) {}
+
+ template <typename LeafNodeType>
+ void operator()(LeafNodeType &leaf, size_t /*leafIndex*/) const
+ {
+ typename LeafNodeType::ValueOnIter it = leaf.beginValueOn();
+
+ const typename BoolTreeT::LeafNodeType * maskLeaf =
+ mMaskAcc.probeConstLeaf(leaf.origin());
- // Eval upwind x-edge
- n_ijk = ijk; ++n_ijk[0];
- bool otherInside = (mSourceAccessor.getValue(n_ijk) < mIsovalue);
- if (otherInside != thisInside) {
+ if (maskLeaf) {
+ for (; it; ++it) {
+ if (!maskLeaf->isValueOn(it.pos())) {
+ it.setValue(0x1FF & it.getValue());
+ }
+ }
+ } else {
+ for (; it; ++it) {
+ it.setValue(0x1FF & it.getValue());
+ }
+ }
+ }
- edgeFlags = XEDGE;
+private:
+ BoolAccessorT mMaskAcc;
+};
- mAuxAccessor.setActiveState(ijk, true);
- coord[0] = ijk[0]; coord[1] = ijk[1]-1; coord[2] = ijk[2];
- mAuxAccessor.setActiveState(coord, true);
+class FlagUsedPoints
+{
+public:
+ //////////
- coord[0] = ijk[0]; coord[1] = ijk[1]-1; coord[2] = ijk[2]-1;
- mAuxAccessor.setActiveState(coord, true);
+ FlagUsedPoints(const PolygonPoolList& polygons, size_t polyListCount,
+ std::vector<unsigned char>& usedPointMask)
+ : mPolygons(polygons)
+ , mPolyListCount(polyListCount)
+ , mUsedPointMask(usedPointMask)
+ {
+ }
- coord[0] = ijk[0]; coord[1] = ijk[1]; coord[2] = ijk[2]-1;
- mAuxAccessor.setActiveState(coord, true);
+ void run(bool threaded = true)
+ {
+ if (threaded) {
+ tbb::parallel_for(tbb::blocked_range<size_t>(0, mPolyListCount), *this);
+ } else {
+ (*this)(tbb::blocked_range<size_t>(0, mPolyListCount));
+ }
}
- // Eval upwind y-edge
- n_ijk[0] = ijk[0]; ++n_ijk[1];
- otherInside = (mSourceAccessor.getValue(n_ijk) < mIsovalue);
- if (otherInside != thisInside) {
+ //////////
- edgeFlags |= YEDGE;
+ void operator()(const tbb::blocked_range<size_t>& range) const
+ {
+ // Concurrent writes to same memory address can occur, but
+ // all threads are writing the same value and char is atomic.
+ for (size_t n = range.begin(); n != range.end(); ++n) {
+ const PolygonPool& polygons = mPolygons[n];
+ for (size_t i = 0; i < polygons.numQuads(); ++i) {
+ const Vec4I& quad = polygons.quad(i);
+ mUsedPointMask[quad[0]] = 1;
+ mUsedPointMask[quad[1]] = 1;
+ mUsedPointMask[quad[2]] = 1;
+ mUsedPointMask[quad[3]] = 1;
+ }
- mAuxAccessor.setActiveState(ijk, true);
+ for (size_t i = 0; i < polygons.numTriangles(); ++i) {
+ const Vec3I& triangle = polygons.triangle(i);
+ mUsedPointMask[triangle[0]] = 1;
+ mUsedPointMask[triangle[1]] = 1;
+ mUsedPointMask[triangle[2]] = 1;
+ }
+ }
+ }
- coord[0] = ijk[0]; coord[1] = ijk[1]; coord[2] = ijk[2]-1;
- mAuxAccessor.setActiveState(coord, true);
- coord[0] = ijk[0]-1; coord[1] = ijk[1]; coord[2] = ijk[2];
- mAuxAccessor.setActiveState(coord, true);
+private:
+ const PolygonPoolList& mPolygons;
+ size_t mPolyListCount;
+ std::vector<unsigned char>& mUsedPointMask;
+};
+
+class RemapIndices
+{
+public:
+ //////////
- coord[0] = ijk[0]-1; coord[1] = ijk[1]; coord[2] = ijk[2]-1;
- mAuxAccessor.setActiveState(coord, true);
+ RemapIndices(PolygonPoolList& polygons,
+ size_t polyListCount, const std::vector<unsigned>& indexMap)
+ : mPolygons(polygons)
+ , mPolyListCount(polyListCount)
+ , mIndexMap(indexMap)
+ {
}
- // Eval upwind z-edge
- n_ijk[1] = ijk[1]; ++n_ijk[2];
- otherInside = (mSourceAccessor.getValue(n_ijk) < mIsovalue);
- if (otherInside != thisInside) {
+ void run(bool threaded = true)
+ {
+ if (threaded) {
+ tbb::parallel_for(tbb::blocked_range<size_t>(0, mPolyListCount), *this);
+ } else {
+ (*this)(tbb::blocked_range<size_t>(0, mPolyListCount));
+ }
+ }
- edgeFlags |= ZEDGE;
+ //////////
- mAuxAccessor.setActiveState(ijk, true);
+ void operator()(const tbb::blocked_range<size_t>& range) const
+ {
+ for (size_t n = range.begin(); n != range.end(); ++n) {
+ PolygonPool& polygons = mPolygons[n];
+ for (size_t i = 0; i < polygons.numQuads(); ++i) {
+ Vec4I& quad = polygons.quad(i);
+ quad[0] = mIndexMap[quad[0]];
+ quad[1] = mIndexMap[quad[1]];
+ quad[2] = mIndexMap[quad[2]];
+ quad[3] = mIndexMap[quad[3]];
+ }
- coord[0] = ijk[0]; coord[1] = ijk[1]-1; coord[2] = ijk[2];
- mAuxAccessor.setActiveState(coord, true);
+ for (size_t i = 0; i < polygons.numTriangles(); ++i) {
+ Vec3I& triangle = polygons.triangle(i);
+ triangle[0] = mIndexMap[triangle[0]];
+ triangle[1] = mIndexMap[triangle[1]];
+ triangle[2] = mIndexMap[triangle[2]];
+ }
+ }
+ }
+
+
+private:
+ PolygonPoolList& mPolygons;
+ size_t mPolyListCount;
+ const std::vector<unsigned>& mIndexMap;
+};
- coord[0] = ijk[0]-1; coord[1] = ijk[1]; coord[2] = ijk[2];
- mAuxAccessor.setActiveState(coord, true);
- coord[0] = ijk[0]-1; coord[1] = ijk[1]-1; coord[2] = ijk[2];
- mAuxAccessor.setActiveState(coord, true);
+class MovePoints
+{
+public:
+ //////////
+
+ MovePoints(
+ internal::UniquePtr<openvdb::Vec3s>::type& newPointList,
+ const PointList& oldPointList,
+ const std::vector<unsigned>& indexMap,
+ const std::vector<unsigned char>& usedPointMask)
+ : mNewPointList(newPointList)
+ , mOldPointList(oldPointList)
+ , mIndexMap(indexMap)
+ , mUsedPointMask(usedPointMask)
+ {
+ }
+
+ void run(bool threaded = true)
+ {
+ if (threaded) {
+ tbb::parallel_for(tbb::blocked_range<size_t>(0, mIndexMap.size()), *this);
+ } else {
+ (*this)(tbb::blocked_range<size_t>(0, mIndexMap.size()));
+ }
}
- return edgeFlags;
-}
+
+ //////////
+
+ void operator()(const tbb::blocked_range<size_t>& range) const
+ {
+ for (size_t n = range.begin(); n != range.end(); ++n) {
+ if (mUsedPointMask[n]) {
+ const size_t index = mIndexMap[n];
+ mNewPointList.get()[index] = mOldPointList[n];
+ }
+ }
+ }
+
+private:
+ internal::UniquePtr<openvdb::Vec3s>::type& mNewPointList;
+ const PointList& mOldPointList;
+ const std::vector<unsigned>& mIndexMap;
+ const std::vector<unsigned char>& mUsedPointMask;
+};
////////////////////////////////////////
-template <class DistTreeT>
-class SeamMaskGen
+template<typename SrcTreeT>
+class GenTopologyMask
{
public:
- typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
- typedef typename DistTreeT::template ValueConverter<int>::Type IntTreeT;
- typedef tree::ValueAccessor<const BoolTreeT> BoolTreeAccessorT;
- typedef tree::ValueAccessor<const IntTreeT> IntTreeAccessorT;
+ typedef tree::LeafManager<const SrcTreeT> LeafManagerT;
+ typedef typename SrcTreeT::template ValueConverter<bool>::Type BoolTreeT;
+ typedef tree::ValueAccessor<const SrcTreeT> SrcAccessorT;
+ typedef tree::ValueAccessor<BoolTreeT> BoolAccessorT;
+ typedef Grid<BoolTreeT> BoolGridT;
- SeamMaskGen(LeafPtrList<BoolTreeT>& seamMaskLeafs,
- const BoolTreeT& topologyMaskTree, const IntTreeT& auxTree);
- SeamMaskGen(const SeamMaskGen<DistTreeT>&);
+ //////////
- void runParallel();
- void runSerial();
- void operator()(const tbb::blocked_range<size_t>&) const;
+ GenTopologyMask(const BoolGridT& mask, const LeafManagerT& srcLeafs,
+ const math::Transform& srcXForm, bool invertMask);
+
+ void run(bool threaded = true);
+
+ BoolTreeT& tree() { return mTree; }
+
+
+ //////////
+
+ GenTopologyMask(GenTopologyMask&, tbb::split);
+
+ void operator()(const tbb::blocked_range<size_t>&);
+
+ void join(GenTopologyMask& rhs) { mTree.merge(rhs.mTree); }
private:
- LeafPtrList<BoolTreeT>& mSeamMaskLeafs;
- const BoolTreeT& mTopologyMaskTree;
- BoolTreeAccessorT mTopologyMaskAcc;
- const IntTreeT& mAuxTree;
- IntTreeAccessorT mAuxAcc;
+
+ const BoolGridT& mMask;
+ const LeafManagerT& mLeafManager;
+ const math::Transform& mSrcXForm;
+ bool mInvertMask;
+ BoolTreeT mTree;
};
-template <class DistTreeT>
-SeamMaskGen<DistTreeT>::SeamMaskGen(LeafPtrList<BoolTreeT>& seamMaskLeafs,
- const BoolTreeT& topologyMaskTree, const IntTreeT& auxTree)
- : mSeamMaskLeafs(seamMaskLeafs)
- , mTopologyMaskTree(topologyMaskTree)
- , mTopologyMaskAcc(mTopologyMaskTree)
- , mAuxTree(auxTree)
- , mAuxAcc(mAuxTree)
+template<typename SrcTreeT>
+GenTopologyMask<SrcTreeT>::GenTopologyMask(const BoolGridT& mask, const LeafManagerT& srcLeafs,
+ const math::Transform& srcXForm, bool invertMask)
+ : mMask(mask)
+ , mLeafManager(srcLeafs)
+ , mSrcXForm(srcXForm)
+ , mInvertMask(invertMask)
+ , mTree(false)
{
}
-template <class DistTreeT>
-SeamMaskGen<DistTreeT>::SeamMaskGen(const SeamMaskGen<DistTreeT>& rhs)
- : mSeamMaskLeafs(rhs.mSeamMaskLeafs)
- , mTopologyMaskTree(rhs.mTopologyMaskTree)
- , mTopologyMaskAcc(mTopologyMaskTree)
- , mAuxTree(rhs.mAuxTree)
- , mAuxAcc(mAuxTree)
-{
-}
-template <class DistTreeT>
-void
-SeamMaskGen<DistTreeT>::runParallel()
+template<typename SrcTreeT>
+GenTopologyMask<SrcTreeT>::GenTopologyMask(GenTopologyMask& rhs, tbb::split)
+ : mMask(rhs.mMask)
+ , mLeafManager(rhs.mLeafManager)
+ , mSrcXForm(rhs.mSrcXForm)
+ , mInvertMask(rhs.mInvertMask)
+ , mTree(false)
{
- tbb::parallel_for(mSeamMaskLeafs.getRange(), *this);
}
-template <class DistTreeT>
+
+template<typename SrcTreeT>
void
-SeamMaskGen<DistTreeT>::runSerial()
+GenTopologyMask<SrcTreeT>::run(bool threaded)
{
- (*this)(mSeamMaskLeafs.getRange());
+ if (threaded) {
+ tbb::parallel_reduce(mLeafManager.getRange(), *this);
+ } else {
+ (*this)(mLeafManager.getRange());
+ }
}
-template <class DistTreeT>
+
+template<typename SrcTreeT>
void
-SeamMaskGen<DistTreeT>::operator()(const tbb::blocked_range<size_t>& range) const
+GenTopologyMask<SrcTreeT>::operator()(const tbb::blocked_range<size_t>& range)
{
- typedef typename BoolTreeT::LeafNodeType::ValueOnIter ValueOnIterT;
- Coord ijk, n_ijk;
- for (size_t leafIdx = range.begin(); leafIdx != range.end(); ++leafIdx) {
- ValueOnIterT it = mSeamMaskLeafs[leafIdx]->beginValueOn();
- for (; it; ++it) {
- ijk = it.getCoord();
- if (!mTopologyMaskAcc.isValueOn(ijk)) {
- it.setValueOff();
- } else {
- bool turnOff = true;
- for (size_t n = 0; n < 6; ++n) {
- n_ijk = ijk + util::COORD_OFFSETS[n];
- if (!mAuxTree.isValueOn(n_ijk) && mTopologyMaskAcc.isValueOn(n_ijk)) {
- turnOff = false;
- break;
+ Coord ijk;
+ Vec3d xyz;
+ typedef typename BoolTreeT::LeafNodeType BoolLeafT;
+ const math::Transform& maskXForm = mMask.transform();
+ tree::ValueAccessor<const BoolTreeT> maskAcc(mMask.tree());
+ tree::ValueAccessor<BoolTreeT> acc(mTree);
+
+ typename SrcTreeT::LeafNodeType::ValueOnCIter iter;
+ for (size_t n = range.begin(); n != range.end(); ++n) {
+
+ ijk = mLeafManager.leaf(n).origin();
+ BoolLeafT* leaf = new BoolLeafT(ijk, false);
+ bool addLeaf = false;
+
+ if (maskXForm == mSrcXForm) {
+
+ const BoolLeafT* maskLeaf = maskAcc.probeConstLeaf(ijk);
+
+ if (maskLeaf) {
+
+ for (iter = mLeafManager.leaf(n).cbeginValueOn(); iter; ++iter) {
+ Index pos = iter.pos();
+ if(maskLeaf->isValueOn(pos) != mInvertMask) {
+ leaf->setValueOn(pos);
+ addLeaf = true;
}
}
- if (turnOff) it.setValueOff();
+
+ } else if (maskAcc.isValueOn(ijk) != mInvertMask) {
+ leaf->topologyUnion(mLeafManager.leaf(n));
+ addLeaf = true;
+ }
+
+ } else {
+ for (iter = mLeafManager.leaf(n).cbeginValueOn(); iter; ++iter) {
+ ijk = iter.getCoord();
+ xyz = maskXForm.worldToIndex(mSrcXForm.indexToWorld(ijk));
+ if(maskAcc.isValueOn(util::nearestCoord(xyz)) != mInvertMask) {
+ leaf->setValueOn(iter.pos());
+ addLeaf = true;
+ }
}
}
+
+ if (addLeaf) acc.addLeaf(leaf);
+ else delete leaf;
}
}
+
////////////////////////////////////////
-template <class DistTreeT>
-class EdgeSmooth
+template<typename SrcTreeT>
+class GenBoundaryMask
{
public:
- typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
- typedef typename DistTreeT::template ValueConverter<int>::Type IntTreeT;
- typedef tree::ValueAccessor<const BoolTreeT> BoolTreeAccessorT;
- typedef tree::ValueAccessor<const IntTreeT> IntTreeAccessorT;
+ typedef typename SrcTreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef typename SrcTreeT::template ValueConverter<bool>::Type BoolTreeT;
+ typedef tree::LeafManager<const SrcTreeT> LeafManagerT;
- EdgeSmooth(
- LeafPtrList<BoolTreeT>& leafs,
- const BoolTreeT& edgeMaskTree,
- const IntTreeT& auxTree,
- PointList& points,
- const math::Transform& xform);
+ //////////
- EdgeSmooth(const EdgeSmooth<DistTreeT>&);
+ GenBoundaryMask(const LeafManagerT& leafs, const BoolTreeT&, const IntTreeT&);
- void runParallel(const size_t iterations);
- void runSerial(const size_t iterations);
+ void run(bool threaded = true);
- void operator()(const tbb::blocked_range<size_t>&) const;
+ BoolTreeT& tree() { return mTree; }
+
+ //////////
+
+ GenBoundaryMask(GenBoundaryMask&, tbb::split);
+ void operator()(const tbb::blocked_range<size_t>&);
+ void join(GenBoundaryMask& rhs) { mTree.merge(rhs.mTree); }
private:
- LeafPtrList<BoolTreeT>& mLeafs;
- const BoolTreeT& mEdgeMaskTree;
- const IntTreeT& mAuxTree;
- PointList& mPoints;
- const math::Transform& mTransform;
+ // This typedef is needed for Windows
+ typedef tree::ValueAccessor<const IntTreeT> IntTreeAccessorT;
- bool pointInAABB(const Vec3s& p, const Vec3s& bmin, const Vec3s& bmax) const
- {
- for (int i = 0; i < 3; ++i) {
- if (p[i] < bmin[i] || p[i] > bmax[i]) {
- return false;
- }
- }
- return true;
- }
+ bool neighboringLeaf(const Coord&, const IntTreeAccessorT&) const;
+ const LeafManagerT& mLeafManager;
+ const BoolTreeT& mMaskTree;
+ const IntTreeT& mIdxTree;
+ BoolTreeT mTree;
+ CoordBBox mLeafBBox;
};
-template <class DistTreeT>
-EdgeSmooth<DistTreeT>::EdgeSmooth(
- LeafPtrList<BoolTreeT>& leafs,
- const BoolTreeT& edgeMaskTree,
- const IntTreeT& auxTree,
- PointList& points,
- const math::Transform& xform)
- : mLeafs(leafs)
- , mEdgeMaskTree(edgeMaskTree)
- , mAuxTree(auxTree)
- , mPoints(points)
- , mTransform(xform)
+template<typename SrcTreeT>
+GenBoundaryMask<SrcTreeT>::GenBoundaryMask(const LeafManagerT& leafs,
+ const BoolTreeT& maskTree, const IntTreeT& auxTree)
+ : mLeafManager(leafs)
+ , mMaskTree(maskTree)
+ , mIdxTree(auxTree)
+ , mTree(false)
{
+ mIdxTree.evalLeafBoundingBox(mLeafBBox);
+ mLeafBBox.expand(IntTreeT::LeafNodeType::DIM);
}
-template <class DistTreeT>
-EdgeSmooth<DistTreeT>::EdgeSmooth(const EdgeSmooth<DistTreeT>& rhs)
- : mLeafs(rhs.mLeafs)
- , mEdgeMaskTree(rhs.mEdgeMaskTree)
- , mAuxTree(rhs.mAuxTree)
- , mPoints(rhs.mPoints)
- , mTransform(rhs.mTransform)
+
+template<typename SrcTreeT>
+GenBoundaryMask<SrcTreeT>::GenBoundaryMask(GenBoundaryMask& rhs, tbb::split)
+ : mLeafManager(rhs.mLeafManager)
+ , mMaskTree(rhs.mMaskTree)
+ , mIdxTree(rhs.mIdxTree)
+ , mTree(false)
+ , mLeafBBox(rhs.mLeafBBox)
{
}
-template <class DistTreeT>
+
+template<typename SrcTreeT>
void
-EdgeSmooth<DistTreeT>::runParallel(const size_t iterations)
+GenBoundaryMask<SrcTreeT>::run(bool threaded)
{
- for (size_t i = 0; i < iterations; ++i) {
- tbb::parallel_for(mLeafs.getRange(), *this);
+ if (threaded) {
+ tbb::parallel_reduce(mLeafManager.getRange(), *this);
+ } else {
+ (*this)(mLeafManager.getRange());
}
}
-template <class DistTreeT>
-void
-EdgeSmooth<DistTreeT>::runSerial(const size_t iterations)
+
+template<typename SrcTreeT>
+bool
+GenBoundaryMask<SrcTreeT>::neighboringLeaf(const Coord& ijk, const IntTreeAccessorT& acc) const
{
- for (size_t i = 0; i < iterations; ++i) {
- (*this)(mLeafs.getRange());
- }
+ if (acc.probeConstLeaf(ijk)) return true;
+
+ const int dim = IntTreeT::LeafNodeType::DIM;
+
+ // face adjacent neghbours
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1], ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1], ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] + dim, ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] - dim, ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1], ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1], ijk[2] - dim))) return true;
+
+ // edge adjacent neighbors
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1], ijk[2] - dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1], ijk[2] - dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1], ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1], ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] + dim, ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] + dim, ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] - dim, ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] - dim, ijk[2]))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] - dim, ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] - dim, ijk[2] - dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] + dim, ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0], ijk[1] + dim, ijk[2] - dim))) return true;
+
+ // corner adjacent neighbors
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] - dim, ijk[2] - dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] - dim, ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] - dim, ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] - dim, ijk[2] - dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] + dim, ijk[2] - dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] - dim, ijk[1] + dim, ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] + dim, ijk[2] + dim))) return true;
+ if (acc.probeConstLeaf(Coord(ijk[0] + dim, ijk[1] + dim, ijk[2] - dim))) return true;
+
+ return false;
}
-template <class DistTreeT>
+
+template<typename SrcTreeT>
void
-EdgeSmooth<DistTreeT>::operator()(const tbb::blocked_range<size_t>& range) const
+GenBoundaryMask<SrcTreeT>::operator()(const tbb::blocked_range<size_t>& range)
{
- typedef typename BoolTreeT::LeafNodeType::ValueOnIter ValueOnIterT;
- BoolTreeAccessorT maskAcc(mEdgeMaskTree);
- IntTreeAccessorT auxAcc(mAuxTree);
-
- float dx = float(mTransform.voxelSize()[0]);
- openvdb::Vec3s avg, bmin, bmax;
- Coord ijk, nijk;
- int count;
-
- for (size_t leafIdx = range.begin(); leafIdx != range.end(); ++leafIdx) {
- typename BoolTreeT::LeafNodeType::ValueOnIter valueIt = mLeafs[leafIdx]->beginValueOn();
- for ( ; valueIt; ++valueIt) {
-
- ijk = valueIt.getCoord();
- openvdb::Vec3s& ptn = mPoints[auxAcc.getValue(ijk)];
-
- avg = ptn;
- count = 1;
- for (int n = 0; n < 26; ++n) {
- nijk = ijk + util::COORD_OFFSETS[n];
- if (maskAcc.isValueOn(nijk)) {
- avg += mPoints[auxAcc.getValue(nijk)];
- ++count;
- }
- }
+ Coord ijk;
+ tree::ValueAccessor<const BoolTreeT> maskAcc(mMaskTree);
+ tree::ValueAccessor<const IntTreeT> idxAcc(mIdxTree);
+ tree::ValueAccessor<BoolTreeT> acc(mTree);
- if (count > 1) {
- avg *= (1.0 / float(count));
+ typename SrcTreeT::LeafNodeType::ValueOnCIter iter;
- // Constrain to current cell
- bmin = openvdb::Vec3s(mTransform.indexToWorld(ijk));
- bmax = bmin + dx;
+ for (size_t n = range.begin(); n != range.end(); ++n) {
- bool inCell = true;
- for (int i = 0; i < 10; ++i) {
+ const typename SrcTreeT::LeafNodeType&
+ leaf = mLeafManager.leaf(n);
- inCell = pointInAABB(avg, bmin, bmax);
+ ijk = leaf.origin();
- if (inCell) break;
+ if (!mLeafBBox.isInside(ijk) || !neighboringLeaf(ijk, idxAcc)) continue;
- avg += ptn;
- avg *= 0.5;
- }
+ const typename BoolTreeT::LeafNodeType*
+ maskLeaf = maskAcc.probeConstLeaf(ijk);
- if (inCell) ptn = avg;
- }
+ if (!maskLeaf || !leaf.hasSameTopology(maskLeaf)) {
+ acc.touchLeaf(ijk)->topologyUnion(leaf);
}
}
}
@@ -2129,235 +3457,239 @@ EdgeSmooth<DistTreeT>::operator()(const tbb::blocked_range<size_t>& range) const
////////////////////////////////////////
-template<class CharAccessorT, typename AuxAccessorT>
-class AuxDataGenerator
+template<typename TreeT>
+class GenTileMask
{
public:
- AuxDataGenerator(CharAccessorT& edgeAcc, AuxAccessorT& auxAcc)
- : mEdgeAcc(edgeAcc), mAuxAcc(auxAcc) {}
+ typedef typename TreeT::template ValueConverter<bool>::Type BoolTreeT;
+ typedef typename TreeT::ValueType ValueT;
- void setXEdge(char edgeFlags, const Coord& ijk)
- {
- mEdgeAcc.setValue(ijk, edgeFlags | XEDGE);
+ //////////
- mAuxAcc.setActiveState(ijk, true);
+ GenTileMask(const std::vector<Vec4i>& tiles, const TreeT& distTree, ValueT iso);
- Coord coord = ijk;
- coord[1] = ijk[1]-1;
- mAuxAcc.setActiveState(coord, true);
+ void run(bool threaded = true);
- coord[0] = ijk[0]; coord[1] = ijk[1]-1; coord[2] = ijk[2]-1;
- mAuxAcc.setActiveState(coord, true);
+ BoolTreeT& tree() { return mTree; }
- coord[0] = ijk[0]; coord[1] = ijk[1]; coord[2] = ijk[2]-1;
- mAuxAcc.setActiveState(coord, true);
- }
+ //////////
- void setYEdge(char edgeFlags, const Coord& ijk)
- {
- mEdgeAcc.setValue(ijk, edgeFlags | YEDGE);
-
- mAuxAcc.setActiveState(ijk, true);
-
- Coord coord = ijk;
- coord[2] = ijk[2]-1;
- mAuxAcc.setActiveState(coord, true);
-
- coord[0] = ijk[0]-1; coord[1] = ijk[1]; coord[2] = ijk[2];
- mAuxAcc.setActiveState(coord, true);
+ GenTileMask(GenTileMask&, tbb::split);
+ void operator()(const tbb::blocked_range<size_t>&);
+ void join(GenTileMask& rhs) { mTree.merge(rhs.mTree); }
- coord[0] = ijk[0]-1; coord[1] = ijk[1]; coord[2] = ijk[2]-1;
- mAuxAcc.setActiveState(coord, true);
- }
+private:
- void setZEdge(char edgeFlags, const Coord& ijk)
- {
- mEdgeAcc.setValue(ijk, edgeFlags | ZEDGE);
+ const std::vector<Vec4i>& mTiles;
+ const TreeT& mDistTree;
+ ValueT mIsovalue;
- mAuxAcc.setActiveState(ijk, true);
+ BoolTreeT mTree;
+};
- Coord coord = ijk;
- coord[1] = ijk[1]-1;
- mAuxAcc.setActiveState(coord, true);
- coord[0] = ijk[0]-1; coord[1] = ijk[1]; coord[2] = ijk[2];
- mAuxAcc.setActiveState(coord, true);
+template<typename TreeT>
+GenTileMask<TreeT>::GenTileMask(
+ const std::vector<Vec4i>& tiles, const TreeT& distTree, ValueT iso)
+ : mTiles(tiles)
+ , mDistTree(distTree)
+ , mIsovalue(iso)
+ , mTree(false)
+{
+}
- coord[0] = ijk[0]-1; coord[1] = ijk[1]-1; coord[2] = ijk[2];
- mAuxAcc.setActiveState(coord, true);
- }
-private:
- CharAccessorT& mEdgeAcc;
- AuxAccessorT& mAuxAcc;
-};
+template<typename TreeT>
+GenTileMask<TreeT>::GenTileMask(GenTileMask& rhs, tbb::split)
+ : mTiles(rhs.mTiles)
+ , mDistTree(rhs.mDistTree)
+ , mIsovalue(rhs.mIsovalue)
+ , mTree(false)
+{
+}
-////////////////////////////////////////
+template<typename TreeT>
+void
+GenTileMask<TreeT>::run(bool threaded)
+{
+ if (threaded) tbb::parallel_reduce(tbb::blocked_range<size_t>(0, mTiles.size()), *this);
+ else (*this)(tbb::blocked_range<size_t>(0, mTiles.size()));
+}
-template<class DistTreeT, class AuxTreeT, class CharTreeT>
-inline void
-tileAuxiliaryData(
- const DistTreeT& distTree, CharTreeT& edgeTree, AuxTreeT& auxTree,
- double iso)
+template<typename TreeT>
+void
+GenTileMask<TreeT>::operator()(const tbb::blocked_range<size_t>& range)
{
- typedef tree::ValueAccessor<const DistTreeT> DistAccessorT;
- typedef tree::ValueAccessor<AuxTreeT> AuxTreeAccessorT;
- typedef tree::ValueAccessor<CharTreeT> CharTreeAccessorT;
-
- typename DistTreeT::ValueType isoValue = typename DistTreeT::ValueType(iso);
+ tree::ValueAccessor<const TreeT> distAcc(mDistTree);
+ CoordBBox region, bbox;
+ Coord ijk, nijk;
+ bool processRegion = true;
+ ValueT value;
- DistAccessorT distAcc(distTree);
- CharTreeAccessorT edgeAcc(edgeTree);
- AuxTreeAccessorT auxAcc(auxTree);
- AuxDataGenerator<CharTreeAccessorT, AuxTreeAccessorT> auxData(edgeAcc, auxAcc);
+ for (size_t n = range.begin(); n != range.end(); ++n) {
- Coord ijk, nijk;
- typename DistTreeT::ValueType value;
- CoordBBox bbox;
- bool processTileFace;
+ const Vec4i& tile = mTiles[n];
- typename DistTreeT::ValueOnCIter tileIter(distTree);
- tileIter.setMaxDepth(DistTreeT::ValueOnCIter::LEAF_DEPTH - 1);
+ bbox.min()[0] = tile[0];
+ bbox.min()[1] = tile[1];
+ bbox.min()[2] = tile[2];
- for ( ; tileIter; ++tileIter) {
- tileIter.getBoundingBox(bbox);
+ bbox.max() = bbox.min();
+ bbox.max().offset(tile[3]);
- const bool thisInside = (distAcc.getValue(bbox.min()) < isoValue);
+ const bool thisInside = (distAcc.getValue(bbox.min()) < mIsovalue);
const int thisDepth = distAcc.getValueDepth(bbox.min());
-
- // Eval x-edges
+ // eval x-edges
ijk = bbox.max();
nijk = ijk;
++nijk[0];
- processTileFace = true;
+ processRegion = true;
if (thisDepth >= distAcc.getValueDepth(nijk)) {
- processTileFace = thisInside != (distAcc.getValue(nijk) < isoValue);
+ processRegion = thisInside != (distAcc.getValue(nijk) < mIsovalue);
}
- if (processTileFace) {
- for (ijk[1] = bbox.min()[1]; ijk[1] <= bbox.max()[1]; ++ijk[1]) {
- nijk[1] = ijk[1];
- for (ijk[2] = bbox.min()[2]; ijk[2] <= bbox.max()[2]; ++ijk[2]) {
- nijk[2] = ijk[2];
- if ((distAcc.getValue(nijk) < isoValue) != thisInside) {
- auxData.setXEdge(edgeAcc.getValue(ijk) | char(thisInside), ijk);
- }
- }
- }
+
+ if (processRegion) {
+ region = bbox;
+ region.min()[0] = region.max()[0] = ijk[0];
+ mTree.fill(region, true);
}
+
ijk = bbox.min();
--ijk[0];
- processTileFace = true;
+ processRegion = true;
if (thisDepth >= distAcc.getValueDepth(ijk)) {
- processTileFace = !distAcc.probeValue(ijk, value) && thisInside != (value < isoValue);
+ processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue);
}
- if (processTileFace) {
- for (ijk[1] = bbox.min()[1]; ijk[1] <= bbox.max()[1]; ++ijk[1]) {
- for (ijk[2] = bbox.min()[2]; ijk[2] <= bbox.max()[2]; ++ijk[2]) {
- if (!distAcc.probeValue(ijk, value) && (value < isoValue) != thisInside) {
- auxData.setXEdge(edgeAcc.getValue(ijk) | char(!thisInside), ijk);
- }
- }
- }
+ if (processRegion) {
+ region = bbox;
+ region.min()[0] = region.max()[0] = ijk[0];
+ mTree.fill(region, true);
}
- // Eval y-edges
+ // eval y-edges
ijk = bbox.max();
nijk = ijk;
++nijk[1];
- processTileFace = true;
+ processRegion = true;
if (thisDepth >= distAcc.getValueDepth(nijk)) {
- processTileFace = thisInside != (distAcc.getValue(nijk) < isoValue);
+ processRegion = thisInside != (distAcc.getValue(nijk) < mIsovalue);
}
- if (processTileFace) {
- for (ijk[0] = bbox.min()[0]; ijk[0] <= bbox.max()[0]; ++ijk[0]) {
- nijk[0] = ijk[0];
- for (ijk[2] = bbox.min()[2]; ijk[2] <= bbox.max()[2]; ++ijk[2]) {
- nijk[2] = ijk[2];
-
- if ((distAcc.getValue(nijk) < isoValue) != thisInside) {
- auxData.setYEdge(edgeAcc.getValue(ijk) | char(thisInside), ijk);
- }
- }
- }
+ if (processRegion) {
+ region = bbox;
+ region.min()[1] = region.max()[1] = ijk[1];
+ mTree.fill(region, true);
}
ijk = bbox.min();
--ijk[1];
- processTileFace = true;
+ processRegion = true;
if (thisDepth >= distAcc.getValueDepth(ijk)) {
- processTileFace = !distAcc.probeValue(ijk, value) && thisInside != (value < isoValue);
+ processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue);
}
- if (processTileFace) {
- for (ijk[0] = bbox.min()[0]; ijk[0] <= bbox.max()[0]; ++ijk[0]) {
- for (ijk[2] = bbox.min()[2]; ijk[2] <= bbox.max()[2]; ++ijk[2]) {
-
- if (!distAcc.probeValue(ijk, value) && (value < isoValue) != thisInside) {
- auxData.setYEdge(edgeAcc.getValue(ijk) | char(!thisInside), ijk);
- }
- }
- }
+ if (processRegion) {
+ region = bbox;
+ region.min()[1] = region.max()[1] = ijk[1];
+ mTree.fill(region, true);
}
- // Eval z-edges
+ // eval z-edges
ijk = bbox.max();
nijk = ijk;
++nijk[2];
- processTileFace = true;
+ processRegion = true;
if (thisDepth >= distAcc.getValueDepth(nijk)) {
- processTileFace = thisInside != (distAcc.getValue(nijk) < isoValue);
+ processRegion = thisInside != (distAcc.getValue(nijk) < mIsovalue);
}
- if (processTileFace) {
- for (ijk[0] = bbox.min()[0]; ijk[0] <= bbox.max()[0]; ++ijk[0]) {
- nijk[0] = ijk[0];
- for (ijk[1] = bbox.min()[1]; ijk[1] <= bbox.max()[1]; ++ijk[1]) {
- nijk[1] = ijk[1];
+ if (processRegion) {
+ region = bbox;
+ region.min()[2] = region.max()[2] = ijk[2];
+ mTree.fill(region, true);
+ }
- if ((distAcc.getValue(nijk) < isoValue) != thisInside) {
- auxData.setZEdge(edgeAcc.getValue(ijk) | char(thisInside), ijk);
- }
- }
- }
+ ijk = bbox.min();
+ --ijk[2];
+
+ processRegion = true;
+ if (thisDepth >= distAcc.getValueDepth(ijk)) {
+ processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue);
}
+ if (processRegion) {
+ region = bbox;
+ region.min()[2] = region.max()[2] = ijk[2];
+ mTree.fill(region, true);
+ }
+
+
ijk = bbox.min();
+ --ijk[1];
--ijk[2];
- processTileFace = true;
+ processRegion = true;
if (thisDepth >= distAcc.getValueDepth(ijk)) {
- processTileFace = !distAcc.probeValue(ijk, value) && thisInside != (value < isoValue);
+ processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue);
}
- if (processTileFace) {
- for (ijk[0] = bbox.min()[0]; ijk[0] <= bbox.max()[0]; ++ijk[0]) {
- for (ijk[1] = bbox.min()[1]; ijk[1] <= bbox.max()[1]; ++ijk[1]) {
+ if (processRegion) {
+ region = bbox;
+ region.min()[1] = region.max()[1] = ijk[1];
+ region.min()[2] = region.max()[2] = ijk[2];
+ mTree.fill(region, true);
+ }
- if (!distAcc.probeValue(ijk, value) && (value < isoValue) != thisInside) {
- auxData.setZEdge(edgeAcc.getValue(ijk) | char(!thisInside), ijk);
- }
- }
- }
+
+ ijk = bbox.min();
+ --ijk[0];
+ --ijk[1];
+
+ processRegion = true;
+ if (thisDepth >= distAcc.getValueDepth(ijk)) {
+ processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue);
+ }
+
+ if (processRegion) {
+ region = bbox;
+ region.min()[1] = region.max()[1] = ijk[1];
+ region.min()[0] = region.max()[0] = ijk[0];
+ mTree.fill(region, true);
+ }
+
+ ijk = bbox.min();
+ --ijk[0];
+ --ijk[2];
+
+ processRegion = true;
+ if (thisDepth >= distAcc.getValueDepth(ijk)) {
+ processRegion = !distAcc.probeValue(ijk, value) && thisInside != (value < mIsovalue);
+ }
+
+ if (processRegion) {
+ region = bbox;
+ region.min()[2] = region.max()[2] = ijk[2];
+ region.min()[0] = region.max()[0] = ijk[0];
+ mTree.fill(region, true);
}
}
}
@@ -2366,6 +3698,58 @@ tileAuxiliaryData(
////////////////////////////////////////
+template<class DistTreeT, class SignTreeT, class IdxTreeT>
+inline void
+tileData(const DistTreeT& distTree, SignTreeT& signTree, IdxTreeT& idxTree, double iso)
+{
+ typename DistTreeT::ValueOnCIter tileIter(distTree);
+ tileIter.setMaxDepth(DistTreeT::ValueOnCIter::LEAF_DEPTH - 1);
+
+ if (!tileIter) return; // volume has no active tiles.
+
+ size_t tileCount = 0;
+ for ( ; tileIter; ++tileIter) {
+ ++tileCount;
+ }
+
+ std::vector<Vec4i> tiles(tileCount);
+
+ tileCount = 0;
+ tileIter = distTree.cbeginValueOn();
+ tileIter.setMaxDepth(DistTreeT::ValueOnCIter::LEAF_DEPTH - 1);
+
+ CoordBBox bbox;
+ for (; tileIter; ++tileIter) {
+ Vec4i& tile = tiles[tileCount++];
+ tileIter.getBoundingBox(bbox);
+ tile[0] = bbox.min()[0];
+ tile[1] = bbox.min()[1];
+ tile[2] = bbox.min()[2];
+ tile[3] = bbox.max()[0] - bbox.min()[0];
+ }
+
+ typename DistTreeT::ValueType isovalue = typename DistTreeT::ValueType(iso);
+
+ GenTileMask<DistTreeT> tileMask(tiles, distTree, isovalue);
+ tileMask.run();
+
+ typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
+ typedef tree::LeafManager<BoolTreeT> BoolLeafManagerT;
+
+ BoolLeafManagerT leafs(tileMask.tree());
+
+
+ internal::SignData<DistTreeT, BoolLeafManagerT> op(distTree, leafs, isovalue);
+ op.run();
+
+ signTree.merge(*op.signTree());
+ idxTree.merge(*op.idxTree());
+}
+
+
+////////////////////////////////////////
+
+
// Utility class for the volumeToMesh wrapper
class PointListCopy
{
@@ -2388,30 +3772,216 @@ private:
};
-} // namespace internal
+// Checks if the isovalue is in proximity to the active voxel boundary.
+template <typename LeafManagerT>
+inline bool
+needsActiveVoxePadding(const LeafManagerT& leafs, double iso, double voxelSize)
+{
+ double interiorWidth = 0.0, exteriorWidth = 0.0;
+ {
+ typename LeafManagerT::TreeType::LeafNodeType::ValueOffCIter it;
+ bool foundInterior = false, foundExterior = false;
+ for (size_t n = 0, N = leafs.leafCount(); n < N; ++n) {
+
+ for (it = leafs.leaf(n).cbeginValueOff(); it; ++it) {
+ double value = double(it.getValue());
+ if (value < 0.0) {
+ interiorWidth = value;
+ foundInterior = true;
+ } else if (value > 0.0) {
+ exteriorWidth = value;
+ foundExterior = true;
+ }
+
+ if (foundInterior && foundExterior) break;
+ }
+
+ if (foundInterior && foundExterior) break;
+ }
+
+ }
+
+ double minDist = std::min(std::abs(interiorWidth - iso), std::abs(exteriorWidth - iso));
+ return !(minDist > (2.0 * voxelSize));
+}
+
+
+} // end namespace internal
+
+
+////////////////////////////////////////
+
+
+inline
+PolygonPool::PolygonPool()
+ : mNumQuads(0)
+ , mNumTriangles(0)
+ , mQuads(NULL)
+ , mTriangles(NULL)
+ , mQuadFlags(NULL)
+ , mTriangleFlags(NULL)
+{
+}
+
+
+inline
+PolygonPool::PolygonPool(const size_t numQuads, const size_t numTriangles)
+ : mNumQuads(numQuads)
+ , mNumTriangles(numTriangles)
+ , mQuads(new openvdb::Vec4I[mNumQuads])
+ , mTriangles(new openvdb::Vec3I[mNumTriangles])
+ , mQuadFlags(new char[mNumQuads])
+ , mTriangleFlags(new char[mNumTriangles])
+{
+}
+
+
+inline void
+PolygonPool::copy(const PolygonPool& rhs)
+{
+ resetQuads(rhs.numQuads());
+ resetTriangles(rhs.numTriangles());
+
+ for (size_t i = 0; i < mNumQuads; ++i) {
+ mQuads[i] = rhs.mQuads[i];
+ mQuadFlags[i] = rhs.mQuadFlags[i];
+ }
+
+ for (size_t i = 0; i < mNumTriangles; ++i) {
+ mTriangles[i] = rhs.mTriangles[i];
+ mTriangleFlags[i] = rhs.mTriangleFlags[i];
+ }
+}
+
+
+inline void
+PolygonPool::resetQuads(size_t size)
+{
+ mNumQuads = size;
+ mQuads.reset(new openvdb::Vec4I[mNumQuads]);
+ mQuadFlags.reset(new char[mNumQuads]);
+}
+
+
+inline void
+PolygonPool::clearQuads()
+{
+ mNumQuads = 0;
+ mQuads.reset(NULL);
+ mQuadFlags.reset(NULL);
+}
+
+
+inline void
+PolygonPool::resetTriangles(size_t size)
+{
+ mNumTriangles = size;
+ mTriangles.reset(new openvdb::Vec3I[mNumTriangles]);
+ mTriangleFlags.reset(new char[mNumTriangles]);
+}
+
+
+inline void
+PolygonPool::clearTriangles()
+{
+ mNumTriangles = 0;
+ mTriangles.reset(NULL);
+ mTriangleFlags.reset(NULL);
+}
+
+
+inline bool
+PolygonPool::trimQuads(const size_t n, bool reallocate)
+{
+ if (!(n < mNumQuads)) return false;
+
+ if (reallocate) {
+
+ if (n == 0) {
+ mQuads.reset(NULL);
+ } else {
+
+ boost::scoped_array<openvdb::Vec4I> quads(new openvdb::Vec4I[n]);
+ boost::scoped_array<char> flags(new char[n]);
+
+ for (size_t i = 0; i < n; ++i) {
+ quads[i] = mQuads[i];
+ flags[i] = mQuadFlags[i];
+ }
+
+ mQuads.swap(quads);
+ mQuadFlags.swap(flags);
+ }
+ }
+
+ mNumQuads = n;
+ return true;
+}
+
+
+inline bool
+PolygonPool::trimTrinagles(const size_t n, bool reallocate)
+{
+ if (!(n < mNumTriangles)) return false;
+
+ if (reallocate) {
+
+ if (n == 0) {
+ mTriangles.reset(NULL);
+ } else {
+
+ boost::scoped_array<openvdb::Vec3I> triangles(new openvdb::Vec3I[n]);
+ boost::scoped_array<char> flags(new char[n]);
+
+ for (size_t i = 0; i < n; ++i) {
+ triangles[i] = mTriangles[i];
+ flags[i] = mTriangleFlags[i];
+ }
+
+ mTriangles.swap(triangles);
+ mTriangleFlags.swap(flags);
+ }
+ }
+
+ mNumTriangles = n;
+ return true;
+}
////////////////////////////////////////
inline VolumeToMesh::VolumeToMesh(double isovalue, double adaptivity)
- : mPointListSize(0)
+ : mPoints(NULL)
+ , mPolygons()
+ , mPointListSize(0)
+ , mSeamPointListSize(0)
, mPolygonPoolListSize(0)
, mIsovalue(isovalue)
, mPrimAdaptivity(adaptivity)
, mSecAdaptivity(0.0)
, mRefGrid(GridBase::ConstPtr())
- , mRefEdgeTree(TreeBase::Ptr())
- , mRefTopologyMaskTree(TreeBase::Ptr())
+ , mSurfaceMaskGrid(GridBase::ConstPtr())
+ , mAdaptivityGrid(GridBase::ConstPtr())
+ , mAdaptivityMaskTree(TreeBase::ConstPtr())
+ , mRefSignTree(TreeBase::Ptr())
+ , mRefIdxTree(TreeBase::Ptr())
+ , mInvertSurfaceMask(false)
+ , mPartitions(1)
+ , mActivePart(0)
+ , mQuantizedSeamPoints(NULL)
+ , mPointFlags(0)
{
}
+
inline PointList&
VolumeToMesh::pointList()
{
return mPoints;
}
+
inline const size_t&
VolumeToMesh::pointListSize() const
{
@@ -2441,15 +4011,60 @@ VolumeToMesh::polygonPoolListSize() const
inline void
-VolumeToMesh::setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity, bool smoothSeams)
+VolumeToMesh::setRefGrid(const GridBase::ConstPtr& grid, double secAdaptivity)
{
mRefGrid = grid;
mSecAdaptivity = secAdaptivity;
+
// Clear out old auxiliary data
- mRefEdgeTree = TreeBase::Ptr();
- mRefTopologyMaskTree = TreeBase::Ptr();
- mSeamPointTree = TreeBase::Ptr();
- mSmoothSeams = smoothSeams;
+ mRefSignTree = TreeBase::Ptr();
+ mRefIdxTree = TreeBase::Ptr();
+ mSeamPointListSize = 0;
+ mQuantizedSeamPoints.reset(NULL);
+}
+
+
+inline void
+VolumeToMesh::setSurfaceMask(const GridBase::ConstPtr& mask, bool invertMask)
+{
+ mSurfaceMaskGrid = mask;
+ mInvertSurfaceMask = invertMask;
+}
+
+
+inline void
+VolumeToMesh::setSpatialAdaptivity(const GridBase::ConstPtr& grid)
+{
+ mAdaptivityGrid = grid;
+}
+
+
+inline void
+VolumeToMesh::setAdaptivityMask(const TreeBase::ConstPtr& tree)
+{
+ mAdaptivityMaskTree = tree;
+}
+
+
+inline void
+VolumeToMesh::partition(unsigned partitions, unsigned activePart)
+{
+ mPartitions = std::max(partitions, unsigned(1));
+ mActivePart = std::min(activePart, mPartitions-1);
+}
+
+
+inline std::vector<unsigned char>&
+VolumeToMesh::pointFlags()
+{
+ return mPointFlags;
+}
+
+
+inline const std::vector<unsigned char>&
+VolumeToMesh::pointFlags() const
+{
+ return mPointFlags;
}
@@ -2458,172 +4073,542 @@ inline void
VolumeToMesh::operator()(const GridT& distGrid)
{
typedef typename GridT::TreeType DistTreeT;
+ typedef tree::LeafManager<const DistTreeT> DistLeafManagerT;
typedef typename DistTreeT::ValueType DistValueT;
- typedef typename DistTreeT::template ValueConverter<char>::Type CharTreeT;
- typedef typename DistTreeT::template ValueConverter<int>::Type IntTreeT;
- typedef typename DistTreeT::template ValueConverter<Vec3s>::Type Vec3sTreeT;
typedef typename DistTreeT::template ValueConverter<bool>::Type BoolTreeT;
+ typedef tree::LeafManager<BoolTreeT> BoolLeafManagerT;
+ typedef Grid<BoolTreeT> BoolGridT;
+
+ typedef typename DistTreeT::template ValueConverter<Int16>::Type Int16TreeT;
+ typedef tree::LeafManager<Int16TreeT> Int16LeafManagerT;
+
+ typedef typename DistTreeT::template ValueConverter<int>::Type IntTreeT;
+ typedef typename DistTreeT::template ValueConverter<float>::Type FloatTreeT;
+ typedef Grid<FloatTreeT> FloatGridT;
- const bool noAdaptivity = mPrimAdaptivity < 1e-6 && mSecAdaptivity < 1e-6;
const openvdb::math::Transform& transform = distGrid.transform();
const DistTreeT& distTree = distGrid.tree();
- typename CharTreeT::Ptr edgeTree; // edge flags
- typename IntTreeT::Ptr auxTree; // auxiliary data
+ const DistValueT isovalue = DistValueT(mIsovalue);
+
+ typename Int16TreeT::Ptr signTreePt;
+ typename IntTreeT::Ptr idxTreePt;
+ typename BoolTreeT::Ptr pointMask;
- const bool nonLevelSetGrid = distGrid.getGridClass() != GRID_LEVEL_SET;
+ BoolTreeT valueMask(false), seamMask(false);
+ const bool adaptive = mPrimAdaptivity > 1e-7 || mSecAdaptivity > 1e-7;
+ bool maskEdges = false;
- const bool extraSignCheck = nonLevelSetGrid ||
- (std::abs(mIsovalue - double(distGrid.background())) < (1.5 * transform.voxelSize()[0]));
+ const BoolGridT * surfaceMask = NULL;
+ if (mSurfaceMaskGrid && mSurfaceMaskGrid->type() == BoolGridT::gridType()) {
+ surfaceMask = static_cast<const BoolGridT*>(mSurfaceMaskGrid.get());
+ }
+
+ const FloatGridT * adaptivityField = NULL;
+ if (mAdaptivityGrid && mAdaptivityGrid->type() == FloatGridT::gridType()) {
+ adaptivityField = static_cast<const FloatGridT*>(mAdaptivityGrid.get());
+ }
+
+ if (mAdaptivityMaskTree && mAdaptivityMaskTree->type() == BoolTreeT::treeType()) {
+ const BoolTreeT *adaptivityMaskPt =
+ static_cast<const BoolTreeT*>(mAdaptivityMaskTree.get());
+ seamMask.topologyUnion(*adaptivityMaskPt);
+ }
// Collect auxiliary data
{
- internal::LeafCPtrList<DistTreeT> sourceLeafs(distTree);
- internal::AuxiliaryData<DistTreeT> op(distTree, sourceLeafs, mIsovalue, extraSignCheck);
- op.runParallel();
- edgeTree = op.edgeTree();
- auxTree = op.auxTree();
+ DistLeafManagerT distLeafs(distTree);
- // Collect auxiliary data from active tiles
- if (nonLevelSetGrid) {
- internal::tileAuxiliaryData(distTree, *edgeTree, *auxTree, mIsovalue);
+ // Check if the isovalue is in proximity to the active voxel boundary.
+ bool padActiveVoxels = false;
+ int padVoxels = 3;
+
+ if (distGrid.getGridClass() != GRID_LEVEL_SET) {
+ padActiveVoxels = true;
+ } else {
+ padActiveVoxels = internal::needsActiveVoxePadding(distLeafs,
+ mIsovalue, transform.voxelSize()[0]);
}
- }
+ // always pad the active region for small volumes (the performance hit is neglectable).
+ if (!padActiveVoxels) {
+ Coord dim;
+ distTree.evalActiveVoxelDim(dim);
+ int maxDim = std::max(std::max(dim[0], dim[1]), dim[2]);
+ if (maxDim < 1000) {
+ padActiveVoxels = true;
+ padVoxels = 1;
+ }
+ }
- // Optionally collect auxiliary data from a reference surface.
- internal::ReferenceData<DistTreeT> refData;
- if (mRefGrid) {
- const GridT* refGrid = static_cast<const GridT*>(mRefGrid.get());
- if (refGrid && refGrid->activeVoxelCount() > 0) {
-
- refData.mDistTree = &refGrid->tree();
- refData.mInternalAdaptivity = DistValueT(mSecAdaptivity);
-
- // Cache reference data for reuse.
- if (!mRefEdgeTree && !mRefTopologyMaskTree) {
- internal::LeafCPtrList<DistTreeT> leafs(*refData.mDistTree);
- internal::AuxiliaryData<DistTreeT, bool> op(
- *refData.mDistTree, leafs, mIsovalue, extraSignCheck);
- op.runParallel();
- mRefEdgeTree = op.edgeTree();
- mRefTopologyMaskTree = op.auxTree();
- mSeamPointTree = typename Vec3sTreeT::Ptr(new Vec3sTreeT(Vec3s(0.0)));
+ if (surfaceMask || mPartitions > 1) {
+
+ maskEdges = true;
+
+ if (surfaceMask) {
+
+ { // Mask
+ internal::GenTopologyMask<DistTreeT> masking(
+ *surfaceMask, distLeafs, transform, mInvertSurfaceMask);
+ masking.run();
+ valueMask.merge(masking.tree());
+ }
+
+ if (mPartitions > 1) { // Partition
+ tree::LeafManager<BoolTreeT> leafs(valueMask);
+ leafs.foreach(internal::PartOp(leafs.leafCount() , mPartitions, mActivePart));
+ valueMask.pruneInactive();
+ }
+
+ } else { // Partition
+
+ internal::PartGen<DistTreeT> partitioner(distLeafs, mPartitions, mActivePart);
+ partitioner.run();
+ valueMask.merge(partitioner.tree());
+ }
+
+ {
+ if (padActiveVoxels) tools::dilateVoxels(valueMask, padVoxels);
+ BoolLeafManagerT leafs(valueMask);
+
+ internal::SignData<DistTreeT, BoolLeafManagerT>
+ signDataOp(distTree, leafs, isovalue);
+ signDataOp.run();
+
+ signTreePt = signDataOp.signTree();
+ idxTreePt = signDataOp.idxTree();
}
- if (mRefEdgeTree && mRefTopologyMaskTree) {
- refData.mEdgeTree = static_cast<CharTreeT*>(mRefEdgeTree.get());
- refData.mTopologyMaskTree = static_cast<BoolTreeT*>(mRefTopologyMaskTree.get());
- refData.mSeamPointTree = static_cast<Vec3sTreeT*>(mSeamPointTree.get());
- refData.mSeamMaskTree = typename BoolTreeT::Ptr(new BoolTreeT(false));
- refData.mSmoothingMaskTree = typename BoolTreeT::Ptr(new BoolTreeT(false));
+ {
+ internal::GenBoundaryMask<DistTreeT> boundary(distLeafs, valueMask, *idxTreePt);
+ boundary.run();
+
+ BoolLeafManagerT bleafs(boundary.tree());
+
+ internal::SignData<DistTreeT, BoolLeafManagerT>
+ signDataOp(distTree, bleafs, isovalue);
+ signDataOp.run();
+
+ signTreePt->merge(*signDataOp.signTree());
+ idxTreePt->merge(*signDataOp.idxTree());
+ }
+
+ } else {
+
+ // Collect voxel-sign configurations
+ if (padActiveVoxels) {
+
+ BoolTreeT regionMask(false);
+ regionMask.topologyUnion(distTree);
+ tools::dilateVoxels(regionMask, padVoxels);
+
+ BoolLeafManagerT leafs(regionMask);
+
+ internal::SignData<DistTreeT, BoolLeafManagerT>
+ signDataOp(distTree, leafs, isovalue);
+ signDataOp.run();
+
+ signTreePt = signDataOp.signTree();
+ idxTreePt = signDataOp.idxTree();
+ } else {
+
+ internal::SignData<DistTreeT, DistLeafManagerT>
+ signDataOp(distTree, distLeafs, isovalue);
+ signDataOp.run();
+
+ signTreePt = signDataOp.signTree();
+ idxTreePt = signDataOp.idxTree();
}
}
+
}
- BoolTreeT edgeMaskTree(0.0);
- // Generate the seamline mask
- if (refData.mSeamMaskTree) {
- refData.mSeamMaskTree->topologyUnion(*auxTree.get());
+ // Collect auxiliary data from active tiles
+ internal::tileData(distTree, *signTreePt, *idxTreePt, isovalue);
+
+ // Optionally collect auxiliary data from a reference level set.
+ Int16TreeT *refSignTreePt = NULL;
+ IntTreeT *refIdxTreePt = NULL;
+ const DistTreeT *refDistTreePt = NULL;
+
+ if (mRefGrid && mRefGrid->type() == GridT::gridType()) {
+
+ const GridT* refGrid = static_cast<const GridT*>(mRefGrid.get());
+ refDistTreePt = &refGrid->tree();
+
+ // Collect and cache auxiliary data from the reference grid.
+ if (!mRefSignTree && !mRefIdxTree) {
+
+ DistLeafManagerT refDistLeafs(*refDistTreePt);
+ internal::SignData<DistTreeT, DistLeafManagerT>
+ signDataOp(*refDistTreePt, refDistLeafs, isovalue);
- internal::LeafPtrList<BoolTreeT> leafs(*refData.mSeamMaskTree.get());
- internal::SeamMaskGen<DistTreeT> op(leafs, *refData.mTopologyMaskTree, *auxTree.get());
- op.runParallel();
+ signDataOp.run();
- refData.mSeamMaskTree->pruneInactive();
- edgeMaskTree.topologyUnion(*refData.mSeamMaskTree);
- dilateVoxels(*refData.mSeamMaskTree);
- dilateVoxels(*refData.mSeamMaskTree);
- dilateVoxels(*refData.mSeamMaskTree);
+ mRefSignTree = signDataOp.signTree();
+ mRefIdxTree = signDataOp.idxTree();
+ }
+
+ // Get cached auxiliary data
+ if (mRefSignTree && mRefIdxTree) {
+ refSignTreePt = static_cast<Int16TreeT*>(mRefSignTree.get());
+ refIdxTreePt = static_cast<IntTreeT*>(mRefIdxTree.get());
+ }
}
// Process auxiliary data
+ Int16LeafManagerT signLeafs(*signTreePt);
+
+ if (maskEdges) {
+ signLeafs.foreach(internal::MaskEdges<BoolTreeT>(valueMask));
+ valueMask.clear();
+ }
+
+
+ // Generate the seamline mask
+ if (refSignTreePt) {
+ internal::GenSeamMask<Int16TreeT, Int16LeafManagerT> seamOp(signLeafs, *refSignTreePt);
+ seamOp.run();
+
+ tools::dilateVoxels(seamOp.mask(), 3);
+ signLeafs.foreach(internal::TagSeamEdges<BoolTreeT>(seamOp.mask()));
+
+ seamMask.merge(seamOp.mask());
+ }
+
+
+ std::vector<size_t> regions(signLeafs.leafCount(), 0);
+ if (regions.empty()) return;
+
+ if (adaptive) {
+
+ internal::MergeVoxelRegions<DistTreeT, Int16LeafManagerT> merge(
+ signLeafs, *signTreePt, distTree, *idxTreePt, isovalue, DistValueT(mPrimAdaptivity));
+
+ if (adaptivityField) {
+ merge.setSpatialAdaptivity(transform, *adaptivityField);
+ }
+
+ if (refSignTreePt || mAdaptivityMaskTree) {
+ merge.setAdaptivityMask(&seamMask);
+ }
+
+ if (refSignTreePt) {
+ merge.setRefData(refSignTreePt, DistValueT(mSecAdaptivity));
+ }
+
+ merge.run();
+
+ signLeafs.foreach(internal::CountRegions<IntTreeT>(*idxTreePt, regions));
+
+ } else {
+ signLeafs.foreach(internal::CountPoints(regions));
+ }
+
+
{
- internal::LeafPtrList<IntTreeT> auxLeafs(*auxTree);
- std::vector<size_t> regions(auxLeafs.size(), 0);
+ mPointListSize = 0;
+ size_t tmp = 0;
+ for (size_t n = 0, N = regions.size(); n < N; ++n) {
+ tmp = regions[n];
+ regions[n] = mPointListSize;
+ mPointListSize += tmp;
+ }
+ }
- {
- if (noAdaptivity) {
- internal::Count<IntTreeT> count(auxLeafs, regions);
- count.runParallel();
- } else {
- internal::Merge<DistTreeT> merge(distTree, auxLeafs,
- regions, DistValueT(mIsovalue), DistValueT(mPrimAdaptivity));
- merge.setRefData(refData);
- merge.runParallel();
+
+ // Generate the unique point list
+ mPoints.reset(new openvdb::Vec3s[mPointListSize]);
+ mPointFlags.clear();
+
+ // Generate seam line sample points
+ if (refSignTreePt && refIdxTreePt) {
+
+ if (mSeamPointListSize == 0) {
+
+ std::vector<size_t> pointMap;
+
+ {
+ Int16LeafManagerT refSignLeafs(*refSignTreePt);
+ pointMap.resize(refSignLeafs.leafCount(), 0);
+
+ refSignLeafs.foreach(internal::CountPoints(pointMap));
+
+ size_t tmp = 0;
+ for (size_t n = 0, N = pointMap.size(); n < N; ++n) {
+ tmp = pointMap[n];
+ pointMap[n] = mSeamPointListSize;
+ mSeamPointListSize += tmp;
+ }
}
- mPointListSize = 0;
- size_t tmp = 0;
- for (size_t n = 0, N = regions.size(); n < N; ++n) {
- tmp = regions[n];
- regions[n] = mPointListSize;
- mPointListSize += tmp;
+ if (!pointMap.empty() && mSeamPointListSize != 0) {
+
+ mQuantizedSeamPoints.reset(new uint32_t[mSeamPointListSize]);
+ memset(mQuantizedSeamPoints.get(), 0, sizeof(uint32_t) * mSeamPointListSize);
+
+ typedef tree::LeafManager<IntTreeT> IntLeafManagerT;
+
+ IntLeafManagerT refIdxLeafs(*refIdxTreePt);
+ refIdxLeafs.foreach(internal::MapPoints<Int16TreeT>(pointMap, *refSignTreePt));
}
}
- if (refData.isValid()) { // match leaf topology
- tree::ValueAccessor<BoolTreeT> acc(*refData.mSmoothingMaskTree);
- for (size_t n = 0, N = auxLeafs.size(); n < N; ++n) {
- acc.touchLeaf(auxLeafs[n]->getOrigin());
- }
+ if (mSeamPointListSize != 0) {
+ signLeafs.foreach(internal::SeamWeights<DistTreeT>(
+ distTree, *refSignTreePt, *refIdxTreePt, mQuantizedSeamPoints, mIsovalue));
+ }
+ }
+
+
+ internal::GenPoints<DistTreeT, Int16LeafManagerT>
+ pointOp(signLeafs, distTree, *idxTreePt, mPoints, regions, transform, mIsovalue);
+
+
+ if (mSeamPointListSize != 0) {
+ mPointFlags.resize(mPointListSize);
+ pointOp.setRefData(refSignTreePt, refDistTreePt, refIdxTreePt,
+ &mQuantizedSeamPoints, &mPointFlags);
+ }
+
+ pointOp.run();
+
+
+ mPolygonPoolListSize = signLeafs.leafCount();
+ mPolygons.reset(new PolygonPool[mPolygonPoolListSize]);
+
+
+ if (adaptive) {
+
+ internal::GenPolygons<Int16LeafManagerT, internal::AdaptivePrimBuilder>
+ mesher(signLeafs, *signTreePt, *idxTreePt, mPolygons, Index32(mPointListSize));
+
+ mesher.setRefSignTree(refSignTreePt);
+ mesher.run();
+
+ } else {
+
+ internal::GenPolygons<Int16LeafManagerT, internal::UniformPrimBuilder>
+ mesher(signLeafs, *signTreePt, *idxTreePt, mPolygons, Index32(mPointListSize));
+
+ mesher.setRefSignTree(refSignTreePt);
+ mesher.run();
+ }
+
+ // Clean up unused points, only necessary if masking and/or
+ // automatic mesh partitioning is enabled.
+ if ((surfaceMask || mPartitions > 1) && mPointListSize > 0) {
+
+ // Flag used points
+ std::vector<unsigned char> usedPointMask(mPointListSize, 0);
+
+ internal::FlagUsedPoints flagPoints(mPolygons, mPolygonPoolListSize, usedPointMask);
+ flagPoints.run();
+
+ // Create index map
+ std::vector<unsigned> indexMap(mPointListSize);
+ size_t usedPointCount = 0;
+ for (size_t p = 0; p < mPointListSize; ++p) {
+ if (usedPointMask[p]) indexMap[p] = usedPointCount++;
}
- // Generate the unique point list
- mPoints.reset(new openvdb::Vec3s[mPointListSize]);
+ if (usedPointCount < mPointListSize) {
+
+ // move points
+ internal::UniquePtr<openvdb::Vec3s>::type
+ newPointList(new openvdb::Vec3s[usedPointCount]);
- internal::PointGen<DistTreeT>
- pointGen(distTree, auxLeafs, regions, transform, mPoints, mIsovalue);
- pointGen.setRefData(refData);
- pointGen.runParallel();
+ internal::MovePoints movePoints(newPointList, mPoints, indexMap, usedPointMask);
+ movePoints.run();
+
+ mPointListSize = usedPointCount;
+ mPoints.reset(newPointList.release());
+
+ // update primitives
+ internal::RemapIndices remap(mPolygons, mPolygonPoolListSize, indexMap);
+ remap.run();
+ }
}
- // Smooth seam line edges
- if (mSmoothSeams && refData.isValid()) {
- refData.mSmoothingMaskTree->pruneInactive();
- internal::LeafPtrList<BoolTreeT> leafs(*refData.mSmoothingMaskTree);
- internal::EdgeSmooth<DistTreeT> op(leafs, edgeMaskTree, *auxTree, mPoints, transform);
- op.runParallel(3);
- // Cache shared points
- tree::ValueAccessor<Vec3sTreeT> ptnAcc(*refData.mSeamPointTree);
- tree::ValueAccessor<IntTreeT> auxAcc(*auxTree);
- Coord ijk;
+ // Subdivide nonplanar quads near the seamline edges
+ // todo: thread and clean up
+ if (refSignTreePt || refIdxTreePt || refDistTreePt) {
+ std::vector<Vec3s> newPoints;
+
+ for (size_t n = 0; n < mPolygonPoolListSize; ++n) {
+
+ PolygonPool& polygons = mPolygons[n];
+
+ std::vector<size_t> nonPlanarQuads;
+ nonPlanarQuads.reserve(polygons.numQuads());
+
+ for (size_t i = 0; i < polygons.numQuads(); ++i) {
+
+ char& flags = polygons.quadFlags(i);
+
+ if ((flags & POLYFLAG_FRACTURE_SEAM) && !(flags & POLYFLAG_EXTERIOR)) {
- typename BoolTreeT::LeafIter leafIt = refData.mSeamMaskTree->beginLeaf();
- for ( ; leafIt; ++leafIt) {
- typename BoolTreeT::LeafNodeType::ValueOnIter valueIt = leafIt->beginValueOn();
- for ( ; valueIt; ++valueIt) {
- ijk = valueIt.getCoord();
- const int idx = auxAcc.getValue(ijk);
- if (idx != 0 && !ptnAcc.isValueOn(ijk)) {
- ptnAcc.setValue(ijk, mPoints[idx]);
+ openvdb::Vec4I& quad = polygons.quad(i);
+
+ const bool edgePoly = mPointFlags[quad[0]] || mPointFlags[quad[1]]
+ || mPointFlags[quad[2]] || mPointFlags[quad[3]];
+
+ if (!edgePoly) continue;
+
+ const Vec3s& p0 = mPoints[quad[0]];
+ const Vec3s& p1 = mPoints[quad[1]];
+ const Vec3s& p2 = mPoints[quad[2]];
+ const Vec3s& p3 = mPoints[quad[3]];
+
+ if (!internal::isPlanarQuad(p0, p1, p2, p3, 1e-6f)) {
+ nonPlanarQuads.push_back(i);
+ }
}
}
+
+
+ if (!nonPlanarQuads.empty()) {
+
+ PolygonPool tmpPolygons;
+
+ tmpPolygons.resetQuads(polygons.numQuads() - nonPlanarQuads.size());
+ tmpPolygons.resetTriangles(polygons.numTriangles() + 4 * nonPlanarQuads.size());
+
+ size_t triangleIdx = 0;
+ for (size_t i = 0; i < nonPlanarQuads.size(); ++i) {
+
+ size_t& quadIdx = nonPlanarQuads[i];
+
+ openvdb::Vec4I& quad = polygons.quad(quadIdx);
+ char& quadFlags = polygons.quadFlags(quadIdx);
+ //quadFlags |= POLYFLAG_SUBDIVIDED;
+
+ Vec3s centroid = (mPoints[quad[0]] + mPoints[quad[1]] +
+ mPoints[quad[2]] + mPoints[quad[3]]) * 0.25;
+
+ size_t pointIdx = newPoints.size() + mPointListSize;
+
+ newPoints.push_back(centroid);
+
+
+ {
+ Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
+
+ triangle[0] = quad[0];
+ triangle[1] = pointIdx;
+ triangle[2] = quad[3];
+
+ tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
+
+ if (mPointFlags[triangle[0]] || mPointFlags[triangle[2]]) {
+ tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED;
+ }
+ }
+
+ ++triangleIdx;
+
+ {
+ Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
+
+ triangle[0] = quad[0];
+ triangle[1] = quad[1];
+ triangle[2] = pointIdx;
+
+ tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
+
+ if (mPointFlags[triangle[0]] || mPointFlags[triangle[1]]) {
+ tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED;
+ }
+ }
+
+ ++triangleIdx;
+
+ {
+ Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
+
+ triangle[0] = quad[1];
+ triangle[1] = quad[2];
+ triangle[2] = pointIdx;
+
+ tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
+
+ if (mPointFlags[triangle[0]] || mPointFlags[triangle[1]]) {
+ tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED;
+ }
+ }
+
+
+ ++triangleIdx;
+
+ {
+ Vec3I& triangle = tmpPolygons.triangle(triangleIdx);
+
+ triangle[0] = quad[2];
+ triangle[1] = quad[3];
+ triangle[2] = pointIdx;
+
+ tmpPolygons.triangleFlags(triangleIdx) = quadFlags;
+
+ if (mPointFlags[triangle[0]] || mPointFlags[triangle[1]]) {
+ tmpPolygons.triangleFlags(triangleIdx) |= POLYFLAG_SUBDIVIDED;
+ }
+ }
+
+ ++triangleIdx;
+
+ quad[0] = util::INVALID_IDX;
+ }
+
+
+ for (size_t i = 0; i < polygons.numTriangles(); ++i) {
+ tmpPolygons.triangle(triangleIdx) = polygons.triangle(i);
+ tmpPolygons.triangleFlags(triangleIdx) = polygons.triangleFlags(i);
+ ++triangleIdx;
+ }
+
+
+ size_t quadIdx = 0;
+ for (size_t i = 0; i < polygons.numQuads(); ++i) {
+ openvdb::Vec4I& quad = polygons.quad(i);
+
+ if (quad[0] != util::INVALID_IDX) {
+ tmpPolygons.quad(quadIdx) = quad;
+ tmpPolygons.quadFlags(quadIdx) = polygons.quadFlags(i);
+ ++quadIdx;
+ }
+ }
+
+
+ polygons.copy(tmpPolygons);
+ }
+
}
- }
- // Generate mesh
- {
- internal::LeafCPtrList<CharTreeT> edgeLeafs(*edgeTree);
- mPolygonPoolListSize = edgeLeafs.size();
- mPolygons.reset(new PolygonPool[mPolygonPoolListSize]);
-
- if (noAdaptivity) {
- internal::MeshGen<DistTreeT, internal::QuadMeshOp>
- meshGen(edgeLeafs, *auxTree, mPolygons);
- meshGen.setRefData(refData);
- meshGen.runParallel();
- } else {
- internal::MeshGen<DistTreeT, internal::AdaptiveMeshOp>
- meshGen(edgeLeafs, *auxTree, mPolygons);
- meshGen.setRefData(refData);
- meshGen.runParallel();
+
+ if (!newPoints.empty()) {
+
+ size_t newPointCount = newPoints.size() + mPointListSize;
+
+ internal::UniquePtr<openvdb::Vec3s>::type
+ newPointList(new openvdb::Vec3s[newPointCount]);
+
+ for (size_t i = 0; i < mPointListSize; ++i) {
+ newPointList.get()[i] = mPoints[i];
+ }
+
+ for (size_t i = mPointListSize; i < newPointCount; ++i) {
+ newPointList.get()[i] = newPoints[i - mPointListSize];
+ }
+
+ mPointListSize = newPointCount;
+ mPoints.reset(newPointList.release());
+ mPointFlags.resize(mPointListSize, 0);
}
}
}
@@ -2699,6 +4684,10 @@ volumeToMesh(
volumeToMesh(grid,points, triangles, quads, isovalue, 0.0);
}
+
+////////////////////////////////////////
+
+
} // namespace tools
} // namespace OPENVDB_VERSION_NAME
} // namespace openvdb