Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae0875bb06 | ||
|
|
13aa50ac1f | ||
|
|
77a424312e | ||
|
|
7624beab0a | ||
|
|
7262f8b113 | ||
|
|
a6c7af8109 | ||
|
|
f5f92dcde1 |
@@ -403,6 +403,10 @@ set(OPENVDB_LIBRARY_IO_INCLUDE_FILES
|
||||
io/TempFile.h
|
||||
)
|
||||
|
||||
set(OPENVDB_LIBRARY_ADAPTIVE_INCLUDE_FILES
|
||||
adaptive/AdaptiveGrid.h
|
||||
)
|
||||
|
||||
set(OPENVDB_LIBRARY_MATH_INCLUDE_FILES
|
||||
math/BBox.h
|
||||
math/ConjGradient.h
|
||||
@@ -741,6 +745,7 @@ endif()
|
||||
|
||||
install(FILES ${OPENVDB_LIBRARY_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openvdb)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/openvdb/version.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openvdb)
|
||||
install(FILES ${OPENVDB_LIBRARY_ADAPTIVE_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openvdb/adaptive)
|
||||
install(FILES ${OPENVDB_LIBRARY_IO_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openvdb/io)
|
||||
install(FILES ${OPENVDB_LIBRARY_MATH_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openvdb/math)
|
||||
install(FILES ${OPENVDB_LIBRARY_POINTS_INCLUDE_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/openvdb/points)
|
||||
|
||||
@@ -586,10 +586,10 @@ public:
|
||||
using ValueAllIter = typename _TreeType::ValueAllIter;
|
||||
using ValueAllCIter = typename _TreeType::ValueAllCIter;
|
||||
|
||||
using Accessor = typename tree::ValueAccessor<_TreeType, true>;
|
||||
using ConstAccessor = typename tree::ValueAccessor<const _TreeType, true>;
|
||||
using UnsafeAccessor = typename tree::ValueAccessor<_TreeType, false>;
|
||||
using ConstUnsafeAccessor = typename tree::ValueAccessor<const _TreeType, false>;
|
||||
using Accessor = typename _TreeType::Accessor;
|
||||
using ConstAccessor = typename _TreeType::ConstAccessor;
|
||||
using UnsafeAccessor = typename _TreeType::UnsafeAccessor;
|
||||
using ConstUnsafeAccessor = typename _TreeType::ConstUnsafeAccessor;
|
||||
|
||||
/// @brief ValueConverter<T>::Type is the type of a grid having the same
|
||||
/// hierarchy as this grid but a different value type, T.
|
||||
@@ -729,7 +729,7 @@ public:
|
||||
/// @brief Return an accessor that provides random read and write access
|
||||
/// to this grid's voxels.
|
||||
/// @details The accessor is safe in the sense that it is registered with this grid's tree.
|
||||
Accessor getAccessor() { return Accessor(tree()); }
|
||||
Accessor getAccessor() { return mTree->getAccessor(); }
|
||||
/// @brief Return an unsafe accessor that provides random read and write access
|
||||
/// to this grid's voxels.
|
||||
/// @details The accessor is unsafe in the sense that it is not registered
|
||||
@@ -737,11 +737,11 @@ public:
|
||||
/// over a registered accessor, but it is unsafe if the tree topology is modified.
|
||||
/// @warning Only use this method if you're an expert and know the
|
||||
/// risks of using an unregistered accessor (see tree/ValueAccessor.h)
|
||||
UnsafeAccessor getUnsafeAccessor() { return UnsafeAccessor(tree()); }
|
||||
UnsafeAccessor getUnsafeAccessor() { return mTree->getUnsafeAccessor(); }
|
||||
/// Return an accessor that provides random read-only access to this grid's voxels.
|
||||
ConstAccessor getAccessor() const { return ConstAccessor(tree()); }
|
||||
ConstAccessor getAccessor() const { return mTree->getConstAccessor(); }
|
||||
/// Return an accessor that provides random read-only access to this grid's voxels.
|
||||
ConstAccessor getConstAccessor() const { return ConstAccessor(tree()); }
|
||||
ConstAccessor getConstAccessor() const { return mTree->getConstAccessor(); }
|
||||
/// @brief Return an unsafe accessor that provides random read-only access
|
||||
/// to this grid's voxels.
|
||||
/// @details The accessor is unsafe in the sense that it is not registered
|
||||
@@ -749,7 +749,7 @@ public:
|
||||
/// over a registered accessor, but it is unsafe if the tree topology is modified.
|
||||
/// @warning Only use this method if you're an expert and know the
|
||||
/// risks of using an unregistered accessor (see tree/ValueAccessor.h)
|
||||
ConstUnsafeAccessor getConstUnsafeAccessor() const { return ConstUnsafeAccessor(tree()); }
|
||||
ConstUnsafeAccessor getConstUnsafeAccessor() const { return mTree->getConstUnsafeAccessor(); }
|
||||
|
||||
/// Return an iterator over all of this grid's active values (tile and voxel).
|
||||
ValueOnIter beginValueOn() { return tree().beginValueOn(); }
|
||||
|
||||
@@ -236,6 +236,30 @@ using make_index_sequence =
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
/// @brief An enum to distinguish between different types of Tree representation.
|
||||
enum class TreeRepresentation : uint32_t {Unknown = 0, Sparse = 1, Adaptive = 2, End = 3};
|
||||
|
||||
/// @brief A TreeTraits struct that can be used to query properties of an input T.
|
||||
template<typename T>
|
||||
struct TreeTraits
|
||||
{
|
||||
constexpr static TreeRepresentation Representation = TreeRepresentation::Unknown;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool isSparseTree()
|
||||
{
|
||||
return TreeTraits<T>::Representation == TreeRepresentation::Sparse;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr bool isAdaptiveTree()
|
||||
{
|
||||
return TreeTraits<T>::Representation == TreeRepresentation::Adaptive;
|
||||
}
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
template<typename T, bool = IsSpecializationOf<T, math::Vec2>::value ||
|
||||
IsSpecializationOf<T, math::Vec3>::value ||
|
||||
@@ -446,6 +470,26 @@ template<typename FromType, typename ToType> struct CopyConstness<const FromType
|
||||
/// @endcond
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
/// @brief A type-dependent expression that always evaluates to false.
|
||||
/// This is used as a work-around for the much discussed problem of wanting to do:
|
||||
/// if constexpr (expr) { }
|
||||
/// else { static_assert(false); }
|
||||
///
|
||||
/// At present, C++ evaluates static_assert(false) regardless of the outcome of the
|
||||
/// compile-time expression. By using a type-dependent expression, the static assert
|
||||
/// is only evaluated during instantiation:
|
||||
///
|
||||
/// static_assert(openvdb::AlwaysFalseValue<T>);
|
||||
///
|
||||
/// This results in the desired outcome of generating a compile-time static assert
|
||||
/// only if the first clause evaluates to false.
|
||||
|
||||
template<class>
|
||||
inline constexpr bool AlwaysFalseValue = false;
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#ifndef OPENVDB_ADAPTIVE_ADAPTIVE_GRID_HAS_BEEN_INCLUDED
|
||||
#define OPENVDB_ADAPTIVE_ADAPTIVE_GRID_HAS_BEEN_INCLUDED
|
||||
|
||||
#include <openvdb/version.h>
|
||||
#include <openvdb/Grid.h>
|
||||
#include <openvdb/tree/Tree.h>
|
||||
|
||||
|
||||
namespace openvdb {
|
||||
OPENVDB_USE_VERSION_NAMESPACE
|
||||
namespace OPENVDB_VERSION_NAME {
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
namespace adaptive {
|
||||
|
||||
template <typename TreeT>
|
||||
class AdaptiveAccessor
|
||||
{
|
||||
public:
|
||||
using ValueType = typename TreeT::ValueType;
|
||||
|
||||
explicit AdaptiveAccessor(TreeT& tree):
|
||||
mTree(tree) { }
|
||||
|
||||
TreeT& tree() const { return mTree; }
|
||||
|
||||
private:
|
||||
TreeT& mTree;
|
||||
};
|
||||
|
||||
|
||||
template<typename _ValueType>
|
||||
class AdaptiveTree final: public TreeBase
|
||||
{
|
||||
public:
|
||||
using Ptr = SharedPtr<AdaptiveTree>;
|
||||
using ConstPtr = SharedPtr<const AdaptiveTree>;
|
||||
|
||||
using ValueType = _ValueType;
|
||||
using BuildType = _ValueType;
|
||||
|
||||
static const Index DEPTH = 1;
|
||||
|
||||
using Accessor = AdaptiveAccessor<AdaptiveTree>;
|
||||
using ConstAccessor = AdaptiveAccessor<const AdaptiveTree>;
|
||||
using UnsafeAccessor = Accessor;
|
||||
using ConstUnsafeAccessor = ConstAccessor;
|
||||
|
||||
AdaptiveTree() = default;
|
||||
|
||||
AdaptiveTree& operator=(const AdaptiveTree&) = delete; // disallow assignment
|
||||
|
||||
/// Deep copy constructor
|
||||
AdaptiveTree(const AdaptiveTree& other): TreeBase(other), mBackground(other.mBackground) { }
|
||||
|
||||
/// Empty tree constructor
|
||||
AdaptiveTree(const ValueType& background): mBackground(background) { }
|
||||
|
||||
~AdaptiveTree() override = default;
|
||||
|
||||
/// Return the name of this type of tree.
|
||||
static const Name& treeType();
|
||||
|
||||
/// Return the name of this tree's type.
|
||||
const Name& type() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// Return the name of the type of a voxel's value (e.g., "float" or "vec3d").
|
||||
Name valueType() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// Return @c true if this tree is of the same type as the template parameter.
|
||||
template<typename TreeType>
|
||||
bool isType() const { return (this->type() == TreeType::treeType()); }
|
||||
|
||||
/// Return a pointer to a deep copy of this tree
|
||||
TreeBase::Ptr copy() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Return this tree's background value.
|
||||
const ValueType& background() const { return mBackground; }
|
||||
|
||||
/// @brief Return @c true if this tree contains no nodes.
|
||||
bool empty() const { return true; }
|
||||
|
||||
/// Remove all nodes.
|
||||
void clear() { }
|
||||
|
||||
/// @brief Not implemented.
|
||||
void prune(const ValueType& /*tolerance*/ = zeroVal<ValueType>()) { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Not implemented.
|
||||
void clip(const CoordBBox&) { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
//
|
||||
// Tree methods
|
||||
//
|
||||
|
||||
/// @brief Return in @a bbox the axis-aligned bounding box of all
|
||||
/// active tiles and leaf nodes with active values.
|
||||
/// @details This is faster than calling evalActiveVoxelBoundingBox,
|
||||
/// which visits the individual active voxels, and hence
|
||||
/// evalLeafBoundingBox produces a less tight, i.e. approximate, bbox.
|
||||
/// @return @c false if the bounding box is empty (in which case
|
||||
/// the bbox is set to its default value).
|
||||
bool evalLeafBoundingBox(CoordBBox& /*bbox*/) const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Return in @a dim the dimensions of the axis-aligned bounding box
|
||||
/// of all leaf nodes.
|
||||
/// @return @c false if the bounding box is empty.
|
||||
bool evalLeafDim(Coord& /*dim*/) const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Return in @a bbox the axis-aligned bounding box of all
|
||||
/// active voxels and tiles.
|
||||
/// @details This method produces a more accurate, i.e. tighter,
|
||||
/// bounding box than evalLeafBoundingBox which is approximate but
|
||||
/// faster.
|
||||
/// @return @c false if the bounding box is empty (in which case
|
||||
/// the bbox is set to its default value).
|
||||
bool evalActiveVoxelBoundingBox(CoordBBox& /*bbox*/) const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Return in @a dim the dimensions of the axis-aligned bounding box of all
|
||||
/// active voxels. This is a tighter bounding box than the leaf node bounding box.
|
||||
/// @return @c false if the bounding box is empty.
|
||||
bool evalActiveVoxelDim(Coord& /*dim*/) const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
void getIndexRange(CoordBBox& /*bbox*/) const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Replace with background tiles any nodes whose voxel buffers
|
||||
/// have not yet been allocated.
|
||||
/// @details Typically, unallocated nodes are leaf nodes whose voxel buffers
|
||||
/// are not yet resident in memory because delayed loading is in effect.
|
||||
/// @sa readNonresidentBuffers, io::File::open
|
||||
void clipUnallocatedNodes() override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the total number of unallocated leaf nodes residing in this tree.
|
||||
Index32 unallocatedLeafCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
|
||||
//
|
||||
// Statistics
|
||||
//
|
||||
/// @brief Return the depth of this tree.
|
||||
///
|
||||
/// A tree with only a root node and leaf nodes has depth 2, for example.
|
||||
Index treeDepth() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the number of leaf nodes.
|
||||
Index32 leafCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return a vector with node counts. The number of nodes of type NodeType
|
||||
/// is given as element NodeType::LEVEL in the return vector. Thus, the size
|
||||
/// of this vector corresponds to the height (or depth) of this tree.
|
||||
std::vector<Index32> nodeCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the number of non-leaf nodes.
|
||||
Index32 nonLeafCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the number of active voxels stored in leaf nodes.
|
||||
Index64 activeLeafVoxelCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the number of inactive voxels stored in leaf nodes.
|
||||
Index64 inactiveLeafVoxelCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the total number of active voxels.
|
||||
Index64 activeVoxelCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the number of inactive voxels within the bounding box of all active voxels.
|
||||
Index64 inactiveVoxelCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Return the total number of active tiles.
|
||||
Index64 activeTileCount() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
//
|
||||
// Accessor methods
|
||||
//
|
||||
Accessor getAccessor() { return Accessor(*this); }
|
||||
UnsafeAccessor getUnsafeAccessor() { return UnsafeAccessor(*this); }
|
||||
ConstAccessor getAccessor() const { return ConstAccessor(*this); }
|
||||
ConstAccessor getConstAccessor() const { return ConstAccessor(*this); }
|
||||
ConstUnsafeAccessor getConstUnsafeAccessor() const { return ConstUnsafeAccessor(*this); }
|
||||
|
||||
//
|
||||
// I/O methods
|
||||
//
|
||||
/// Read all data buffers for this tree.
|
||||
void readBuffers(std::istream&, bool /*saveFloatAsHalf*/ = false) override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Read all of this tree's data buffers that intersect the given bounding box.
|
||||
void readBuffers(std::istream&, const CoordBBox&, bool /*saveFloatAsHalf*/ = false) override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// @brief Read all of this tree's data buffers that are not yet resident in memory
|
||||
/// (because delayed loading is in effect).
|
||||
/// @details If this tree was read from a memory-mapped file, this operation
|
||||
/// disconnects the tree from the file.
|
||||
/// @sa clipUnallocatedNodes, io::File::open, io::MappedFile
|
||||
void readNonresidentBuffers() const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
/// Write out all the data buffers for this tree.
|
||||
void writeBuffers(std::ostream&, bool /*saveFloatAsHalf*/ = false) const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Print statistics, memory usage and other information about this tree.
|
||||
/// @param os a stream to which to write textual information
|
||||
/// @param verboseLevel 1: print tree configuration only;
|
||||
/// 2: include node and voxel statistics;
|
||||
/// 3: include memory usage;
|
||||
/// 4: include minimum and maximum voxel values
|
||||
/// @warning @a verboseLevel 4 forces loading of any unallocated nodes.
|
||||
void print(std::ostream& /*os*/ = std::cout, int /*verboseLevel*/ = 1) const override { OPENVDB_THROW(NotImplementedError, ""); }
|
||||
|
||||
/// @brief Dummy declarations to keep Grid class happy
|
||||
using LeafNodeType = void;
|
||||
using ValueAllIter = void;
|
||||
using ValueAllCIter = void;
|
||||
using ValueOnIter = void;
|
||||
using ValueOnCIter = void;
|
||||
using ValueOffIter = void;
|
||||
using ValueOffCIter = void;
|
||||
|
||||
private:
|
||||
ValueType mBackground = zeroVal<ValueType>();
|
||||
}; // class AdaptiveTree
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
template<typename ValueType>
|
||||
inline const Name&
|
||||
AdaptiveTree<ValueType>::treeType()
|
||||
{
|
||||
static std::string sTreeTypeName = []()
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << "Adaptive_Tree_" << typeNameAsString<BuildType>();
|
||||
return ostr.str();
|
||||
}();
|
||||
return sTreeTypeName;
|
||||
}
|
||||
|
||||
|
||||
/// @brief Adaptive grid.
|
||||
template <typename T>
|
||||
using AdaptiveGrid = Grid<AdaptiveTree<T>>;
|
||||
|
||||
using FloatAdaptiveGrid = AdaptiveGrid<float>;
|
||||
|
||||
using AdaptiveGridTypes = TypeList<FloatAdaptiveGrid>;
|
||||
|
||||
} // namespace adaptive
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
/// Partial specialization for AdaptiveAccessor types
|
||||
template<typename _TreeType>
|
||||
struct TreeAdapter<adaptive::AdaptiveAccessor<_TreeType> >
|
||||
{
|
||||
using TreeType = _TreeType;
|
||||
using NonConstTreeType = typename std::remove_const<TreeType>::type;
|
||||
using TreePtrType = typename TreeType::Ptr;
|
||||
using ConstTreePtrType = typename TreeType::ConstPtr;
|
||||
using NonConstTreePtrType = typename NonConstTreeType::Ptr;
|
||||
using GridType = Grid<TreeType>;
|
||||
using NonConstGridType = Grid<NonConstTreeType>;
|
||||
using GridPtrType = typename GridType::Ptr;
|
||||
using NonConstGridPtrType = typename NonConstGridType::Ptr;
|
||||
using ConstGridPtrType = typename GridType::ConstPtr;
|
||||
using ValueType = typename TreeType::ValueType;
|
||||
using AccessorType = typename adaptive::AdaptiveAccessor<TreeType>;
|
||||
using ConstAccessorType = typename adaptive::AdaptiveAccessor<const NonConstTreeType>;
|
||||
using NonConstAccessorType = typename adaptive::AdaptiveAccessor<NonConstTreeType>;
|
||||
|
||||
static NonConstTreeType& tree(NonConstTreeType& t) { return t; }
|
||||
static NonConstTreeType& tree(NonConstGridType& g) { return g.tree(); }
|
||||
static NonConstTreeType& tree(NonConstAccessorType& a) { return a.tree(); }
|
||||
static const NonConstTreeType& tree(ConstAccessorType& a) { return a.tree(); }
|
||||
static const NonConstTreeType& tree(const NonConstTreeType& t) { return t; }
|
||||
static const NonConstTreeType& tree(const NonConstGridType& g) { return g.tree(); }
|
||||
static const NonConstTreeType& tree(const NonConstAccessorType& a) { return a.tree(); }
|
||||
static const NonConstTreeType& tree(const ConstAccessorType& a) { return a.tree(); }
|
||||
static const NonConstTreeType& constTree(NonConstTreeType& t) { return t; }
|
||||
static const NonConstTreeType& constTree(NonConstGridType& g) { return g.constTree(); }
|
||||
static const NonConstTreeType& constTree(NonConstAccessorType& a) { return a.tree(); }
|
||||
static const NonConstTreeType& constTree(ConstAccessorType& a) { return a.tree(); }
|
||||
static const NonConstTreeType& constTree(const NonConstTreeType& t) { return t; }
|
||||
static const NonConstTreeType& constTree(const NonConstGridType& g) { return g.constTree(); }
|
||||
static const NonConstTreeType& constTree(const NonConstAccessorType& a) { return a.tree(); }
|
||||
static const NonConstTreeType& constTree(const ConstAccessorType& a) { return a.tree(); }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
// Overload the TreeTraits struct to declare a const/non-const AdaptiveTree as adaptive
|
||||
|
||||
template<typename ValueT>
|
||||
struct TreeTraits<adaptive::AdaptiveTree<ValueT>>
|
||||
{
|
||||
constexpr static TreeRepresentation Representation = TreeRepresentation::Adaptive;
|
||||
};
|
||||
|
||||
template<typename ValueT>
|
||||
struct TreeTraits<const adaptive::AdaptiveTree<ValueT>>
|
||||
{
|
||||
constexpr static TreeRepresentation Representation = TreeRepresentation::Adaptive;
|
||||
};
|
||||
|
||||
// Overload the TreeTraits struct to declare an AdaptiveAccessor as adaptive
|
||||
|
||||
template<typename TreeT>
|
||||
struct TreeTraits<adaptive::AdaptiveAccessor<TreeT>>
|
||||
{
|
||||
constexpr static TreeRepresentation Representation = TreeRepresentation::Adaptive;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
} // namespace OPENVDB_VERSION_NAME
|
||||
} // namespace openvdb
|
||||
|
||||
#endif // OPENVDB_ADAPTIVE_ADAPTIVE_GRID_HAS_BEEN_INCLUDED
|
||||
@@ -80,7 +80,7 @@ initialize()
|
||||
|
||||
// Register common grid types.
|
||||
GridBase::clearRegistry();
|
||||
GridTypes::foreach<RegisterGrid>();
|
||||
AllGridTypes::foreach<RegisterGrid>();
|
||||
|
||||
// Register types associated with point index grids.
|
||||
Metadata::registerType(typeNameAsString<PointIndex32>(), Int32Metadata::createMetadata);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Grid.h"
|
||||
#include "tree/Tree.h"
|
||||
#include "points/PointDataGrid.h"
|
||||
#include "adaptive/AdaptiveGrid.h"
|
||||
#include "io/File.h"
|
||||
|
||||
|
||||
@@ -98,8 +99,8 @@ using NumericGridTypes = RealGridTypes::Append<IntegerGridTypes>;
|
||||
/// The Vec3 Grid types which OpenVDB will register by default.
|
||||
using Vec3GridTypes = TypeList<Vec3IGrid, Vec3SGrid, Vec3DGrid>;
|
||||
|
||||
/// The Grid types which OpenVDB will register by default.
|
||||
using GridTypes =
|
||||
/// The sparse Grid types.
|
||||
using SparseGridTypes =
|
||||
NumericGridTypes::
|
||||
Append<Vec3GridTypes>::
|
||||
Append<tools::PointIndexGrid>::
|
||||
@@ -110,6 +111,15 @@ using GridTypes =
|
||||
Append<BoolGrid, MaskGrid>;
|
||||
/// @}
|
||||
|
||||
// for backwards-compatibility
|
||||
using GridTypes = SparseGridTypes;
|
||||
|
||||
/// The Grid types which OpenVDB will register by default.
|
||||
using AllGridTypes =
|
||||
SparseGridTypes::
|
||||
Append<adaptive::AdaptiveGridTypes>;
|
||||
/// @}
|
||||
|
||||
|
||||
namespace internal {
|
||||
template <typename T> using ToTreeType = typename T::TreeType;
|
||||
|
||||
@@ -629,29 +629,35 @@ template<class ValueT, class TreeT, size_t N>
|
||||
inline void
|
||||
BoxSampler::getValues(ValueT (&data)[N][N][N], const TreeT& inTree, Coord ijk)
|
||||
{
|
||||
data[0][0][0] = inTree.getValue(ijk); // i, j, k
|
||||
// This algorithm is only defined for sparse grids
|
||||
|
||||
ijk[2] += 1;
|
||||
data[0][0][1] = inTree.getValue(ijk); // i, j, k + 1
|
||||
if constexpr (isSparseTree<TreeT>()) {
|
||||
data[0][0][0] = inTree.getValue(ijk); // i, j, k
|
||||
|
||||
ijk[1] += 1;
|
||||
data[0][1][1] = inTree.getValue(ijk); // i, j+1, k + 1
|
||||
ijk[2] += 1;
|
||||
data[0][0][1] = inTree.getValue(ijk); // i, j, k + 1
|
||||
|
||||
ijk[2] -= 1;
|
||||
data[0][1][0] = inTree.getValue(ijk); // i, j+1, k
|
||||
ijk[1] += 1;
|
||||
data[0][1][1] = inTree.getValue(ijk); // i, j+1, k + 1
|
||||
|
||||
ijk[0] += 1;
|
||||
ijk[1] -= 1;
|
||||
data[1][0][0] = inTree.getValue(ijk); // i+1, j, k
|
||||
ijk[2] -= 1;
|
||||
data[0][1][0] = inTree.getValue(ijk); // i, j+1, k
|
||||
|
||||
ijk[2] += 1;
|
||||
data[1][0][1] = inTree.getValue(ijk); // i+1, j, k + 1
|
||||
ijk[0] += 1;
|
||||
ijk[1] -= 1;
|
||||
data[1][0][0] = inTree.getValue(ijk); // i+1, j, k
|
||||
|
||||
ijk[1] += 1;
|
||||
data[1][1][1] = inTree.getValue(ijk); // i+1, j+1, k + 1
|
||||
ijk[2] += 1;
|
||||
data[1][0][1] = inTree.getValue(ijk); // i+1, j, k + 1
|
||||
|
||||
ijk[2] -= 1;
|
||||
data[1][1][0] = inTree.getValue(ijk); // i+1, j+1, k
|
||||
ijk[1] += 1;
|
||||
data[1][1][1] = inTree.getValue(ijk); // i+1, j+1, k + 1
|
||||
|
||||
ijk[2] -= 1;
|
||||
data[1][1][0] = inTree.getValue(ijk); // i+1, j+1, k
|
||||
} else {
|
||||
static_assert(AlwaysFalseValue<TreeT>, "Not Implemented");
|
||||
}
|
||||
}
|
||||
|
||||
template<class ValueT, class TreeT, size_t N>
|
||||
@@ -744,20 +750,32 @@ inline bool
|
||||
BoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord,
|
||||
typename TreeT::ValueType& result)
|
||||
{
|
||||
using ValueT = typename TreeT::ValueType;
|
||||
if constexpr (isSparseTree<TreeT>()) {
|
||||
using ValueT = typename TreeT::ValueType;
|
||||
|
||||
const Vec3i inIdx = local_util::floorVec3(inCoord);
|
||||
const Vec3R uvw = inCoord - inIdx;
|
||||
const Vec3i inIdx = local_util::floorVec3(inCoord);
|
||||
const Vec3R uvw = inCoord - inIdx;
|
||||
|
||||
// Retrieve the values of the eight voxels surrounding the
|
||||
// fractional source coordinates.
|
||||
ValueT data[2][2][2];
|
||||
// Retrieve the values of the eight voxels surrounding the
|
||||
// fractional source coordinates.
|
||||
ValueT data[2][2][2];
|
||||
|
||||
const bool hasActiveValues = BoxSampler::probeValues(data, inTree, Coord(inIdx));
|
||||
const bool hasActiveValues = BoxSampler::probeValues(data, inTree, Coord(inIdx));
|
||||
|
||||
result = BoxSampler::trilinearInterpolation(data, uvw);
|
||||
result = BoxSampler::trilinearInterpolation(data, uvw);
|
||||
|
||||
return hasActiveValues;
|
||||
return hasActiveValues;
|
||||
} else if constexpr (isAdaptiveTree<TreeT>()) {
|
||||
// As an example, return the background value.
|
||||
// This is where the logic that could sample against an adaptive tree would live.
|
||||
// Extract the tree from the Tree or ValueAccessor
|
||||
auto& tree = TreeAdapter<TreeT>::tree(inTree);
|
||||
result = tree.background();
|
||||
return true;
|
||||
} else {
|
||||
static_assert(AlwaysFalseValue<TreeT>, "Not Implemented");
|
||||
}
|
||||
std::abort(); // unreachable
|
||||
}
|
||||
|
||||
|
||||
@@ -765,18 +783,30 @@ template<class TreeT>
|
||||
inline typename TreeT::ValueType
|
||||
BoxSampler::sample(const TreeT& inTree, const Vec3R& inCoord)
|
||||
{
|
||||
using ValueT = typename TreeT::ValueType;
|
||||
if constexpr (isSparseTree<TreeT>()) {
|
||||
|
||||
const Vec3i inIdx = local_util::floorVec3(inCoord);
|
||||
const Vec3R uvw = inCoord - inIdx;
|
||||
using ValueT = typename TreeT::ValueType;
|
||||
|
||||
// Retrieve the values of the eight voxels surrounding the
|
||||
// fractional source coordinates.
|
||||
ValueT data[2][2][2];
|
||||
const Vec3i inIdx = local_util::floorVec3(inCoord);
|
||||
const Vec3R uvw = inCoord - inIdx;
|
||||
|
||||
BoxSampler::getValues(data, inTree, Coord(inIdx));
|
||||
// Retrieve the values of the eight voxels surrounding the
|
||||
// fractional source coordinates.
|
||||
ValueT data[2][2][2];
|
||||
|
||||
return BoxSampler::trilinearInterpolation(data, uvw);
|
||||
BoxSampler::getValues(data, inTree, Coord(inIdx));
|
||||
|
||||
return BoxSampler::trilinearInterpolation(data, uvw);
|
||||
} else if constexpr (isAdaptiveTree<TreeT>()) {
|
||||
// As an example, return the background value.
|
||||
// This is where the logic that could sample against an adaptive tree would live.
|
||||
// Extract the tree from the Tree or ValueAccessor
|
||||
auto& tree = TreeAdapter<TreeT>::tree(inTree);
|
||||
return tree.background();
|
||||
} else {
|
||||
static_assert(AlwaysFalseValue<TreeT>, "Not Implemented");
|
||||
}
|
||||
std::abort(); // unreachable
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -188,6 +188,11 @@ public:
|
||||
|
||||
static const Index DEPTH = RootNodeType::LEVEL + 1;
|
||||
|
||||
using Accessor = ValueAccessor<Tree, true>;
|
||||
using ConstAccessor = ValueAccessor<const Tree, true>;
|
||||
using UnsafeAccessor = ValueAccessor<Tree, false>;
|
||||
using ConstUnsafeAccessor = ValueAccessor<const Tree, false>;
|
||||
|
||||
/// @brief ValueConverter<T>::Type is the type of a tree having the same
|
||||
/// hierarchy as this tree but a different value type, T.
|
||||
///
|
||||
@@ -623,6 +628,31 @@ public:
|
||||
/// Remove all tiles from this tree and all nodes other than the root node.
|
||||
void clear();
|
||||
|
||||
/// @brief Return an accessor that provides random read and write access
|
||||
/// to this tree's voxels.
|
||||
/// @details The accessor is safe in the sense that it is registered with this tree.
|
||||
Accessor getAccessor();
|
||||
/// @brief Return an unsafe accessor that provides random read and write access
|
||||
/// to this tree's voxels.
|
||||
/// @details The accessor is unsafe in the sense that it is not registered
|
||||
/// with this tree's tree. In some rare cases this can give a performance advantage
|
||||
/// over a registered accessor, but it is unsafe if the tree topology is modified.
|
||||
/// @warning Only use this method if you're an expert and know the
|
||||
/// risks of using an unregistered accessor (see tree/ValueAccessor.h)
|
||||
UnsafeAccessor getUnsafeAccessor();
|
||||
/// Return an accessor that provides random read-only access to this tree's voxels.
|
||||
ConstAccessor getAccessor() const;
|
||||
/// Return an accessor that provides random read-only access to this tree's voxels.
|
||||
ConstAccessor getConstAccessor() const;
|
||||
/// @brief Return an unsafe accessor that provides random read-only access
|
||||
/// to this tree's voxels.
|
||||
/// @details The accessor is unsafe in the sense that it is not registered
|
||||
/// with this tree. In some rare cases this can give a performance advantage
|
||||
/// over a registered accessor, but it is unsafe if the tree topology is modified.
|
||||
/// @warning Only use this method if you're an expert and know the
|
||||
/// risks of using an unregistered accessor (see tree/ValueAccessor.h)
|
||||
ConstUnsafeAccessor getConstUnsafeAccessor();
|
||||
|
||||
/// Clear all registered accessors.
|
||||
void clearAllAccessors();
|
||||
|
||||
@@ -1318,6 +1348,41 @@ Tree<RootNodeType>::clear()
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
template<typename RootNodeType>
|
||||
typename Tree<RootNodeType>::Accessor
|
||||
Tree<RootNodeType>::getAccessor()
|
||||
{
|
||||
return Accessor(*this);
|
||||
}
|
||||
|
||||
template<typename RootNodeType>
|
||||
typename Tree<RootNodeType>::UnsafeAccessor
|
||||
Tree<RootNodeType>::getUnsafeAccessor()
|
||||
{
|
||||
return UnsafeAccessor(*this);
|
||||
}
|
||||
|
||||
template<typename RootNodeType>
|
||||
typename Tree<RootNodeType>::ConstAccessor
|
||||
Tree<RootNodeType>::getAccessor() const
|
||||
{
|
||||
return ConstAccessor(*this);
|
||||
}
|
||||
|
||||
template<typename RootNodeType>
|
||||
typename Tree<RootNodeType>::ConstAccessor
|
||||
Tree<RootNodeType>::getConstAccessor() const
|
||||
{
|
||||
return ConstAccessor(*this);
|
||||
}
|
||||
|
||||
template<typename RootNodeType>
|
||||
typename Tree<RootNodeType>::ConstUnsafeAccessor
|
||||
Tree<RootNodeType>::getConstUnsafeAccessor()
|
||||
{
|
||||
return ConstUnsafeAccessor(*this);
|
||||
}
|
||||
|
||||
template<typename RootNodeType>
|
||||
inline void
|
||||
Tree<RootNodeType>::attachAccessor(ValueAccessorBase<Tree, true>& accessor) const
|
||||
@@ -2060,6 +2125,28 @@ Tree<RootNodeType>::print(std::ostream& os, int verboseLevel) const
|
||||
}
|
||||
|
||||
} // namespace tree
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
// Overload the TreeTraits struct to declare a const/non-const Tree as sparse
|
||||
|
||||
template<typename NodeT>
|
||||
struct TreeTraits<tree::Tree<NodeT>>
|
||||
{
|
||||
constexpr static TreeRepresentation Representation = TreeRepresentation::Sparse;
|
||||
};
|
||||
|
||||
template<typename NodeT>
|
||||
struct TreeTraits<const tree::Tree<NodeT>>
|
||||
{
|
||||
constexpr static TreeRepresentation Representation = TreeRepresentation::Sparse;
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
} // namespace OPENVDB_VERSION_NAME
|
||||
} // namespace openvdb
|
||||
|
||||
|
||||
@@ -1021,6 +1021,19 @@ private:
|
||||
}; // ValueAccessorImpl
|
||||
|
||||
} // namespace tree
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
// Overload the TreeTraits struct to declare a const/non-const ValueAccessorImpl as sparse
|
||||
|
||||
template<typename TreeT, bool IsSafeT, typename MutexT, typename IndexSequenceT>
|
||||
struct TreeTraits<tree::ValueAccessorImpl<TreeT, IsSafeT, MutexT, IndexSequenceT>>
|
||||
{
|
||||
constexpr static TreeRepresentation Representation = TreeRepresentation::Sparse;
|
||||
};
|
||||
|
||||
|
||||
} // namespace OPENVDB_VERSION_NAME
|
||||
} // namespace openvdb
|
||||
|
||||
|
||||
@@ -76,6 +76,7 @@ if(OPENVDB_TESTS)
|
||||
else()
|
||||
list(APPEND UNITTEST_SOURCE_FILES
|
||||
TestActivate.cc
|
||||
TestAdaptive.cc
|
||||
TestAttributeArray.cc
|
||||
TestAttributeArrayString.cc
|
||||
TestAttributeGroup.cc
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// Copyright Contributors to the OpenVDB Project
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
#include <openvdb/openvdb.h>
|
||||
#include <openvdb/tools/Interpolation.h>
|
||||
#include <openvdb/tools/PointAdvect.h>
|
||||
#include <openvdb/adaptive/AdaptiveGrid.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
class TestAdaptive: public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp() override { openvdb::initialize(); }
|
||||
void TearDown() override { openvdb::initialize(); }
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
|
||||
|
||||
TEST_F(TestAdaptive, test)
|
||||
{
|
||||
openvdb::adaptive::AdaptiveGrid<float> adaptiveGrid(5.0f);
|
||||
|
||||
EXPECT_EQ(adaptiveGrid.background(), 5.0f);
|
||||
}
|
||||
|
||||
TEST_F(TestAdaptive, testSample)
|
||||
{
|
||||
const float background = 5.0f;
|
||||
openvdb::adaptive::AdaptiveGrid<float> adaptiveGrid(background);
|
||||
|
||||
float result = openvdb::tools::BoxSampler::sample(adaptiveGrid.tree(), openvdb::Vec3R(1.3, 1.6, 1.8));
|
||||
|
||||
EXPECT_EQ(result, background);
|
||||
}
|
||||
|
||||
TEST_F(TestAdaptive, testAdvect)
|
||||
{
|
||||
using AdaptiveGridT = openvdb::adaptive::AdaptiveGrid<openvdb::Vec3s>;
|
||||
using PointAdvectT = openvdb::tools::PointAdvect<AdaptiveGridT>;
|
||||
using PointListT = PointAdvectT::PointListType;
|
||||
|
||||
const openvdb::Vec3s background(0.0f, 1.0f, 0.0f);
|
||||
AdaptiveGridT adaptiveGrid(background);
|
||||
|
||||
openvdb::tools::PointAdvect<AdaptiveGridT> pointAdvect(adaptiveGrid);
|
||||
|
||||
PointListT points;
|
||||
points.push_back(openvdb::Vec3s(0.0f, 0.0f, 0.0f));
|
||||
points.push_back(openvdb::Vec3s(1.0f, 2.0f, 3.0f));
|
||||
|
||||
float dt = 1/24.0f;
|
||||
pointAdvect.advect(points, dt);
|
||||
|
||||
EXPECT_EQ(points[0], openvdb::Vec3s(0.0f, dt, 0.0f));
|
||||
EXPECT_EQ(points[1], openvdb::Vec3s(1.0f, 2.0f + dt, 3.0f));
|
||||
}
|
||||
@@ -40,6 +40,11 @@ public:
|
||||
using Ptr = openvdb::SharedPtr<ProxyTree>;
|
||||
using ConstPtr = openvdb::SharedPtr<const ProxyTree>;
|
||||
|
||||
using Accessor = void;
|
||||
using ConstAccessor = void;
|
||||
using UnsafeAccessor = void;
|
||||
using ConstUnsafeAccessor = void;
|
||||
|
||||
static const openvdb::Index DEPTH;
|
||||
static const ValueType backg;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user