Skip to content

Commit

Permalink
Merge pull request #1936 from danrbailey/tree_api_probe
Browse files Browse the repository at this point in the history
RootNode and InternalNode Probe Methods
  • Loading branch information
danrbailey authored Oct 29, 2024
2 parents 1cdeab7 + 485ff98 commit 57d4201
Show file tree
Hide file tree
Showing 5 changed files with 447 additions and 1 deletion.
113 changes: 113 additions & 0 deletions openvdb/openvdb/tree/InternalNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,43 @@ class InternalNode
/// If no such node exists, return nullptr.
template<typename NodeType> NodeType* probeNode(const Coord& xyz);
template<typename NodeType> const NodeType* probeConstNode(const Coord& xyz) const;
template<typename NodeType> const NodeType* probeNode(const Coord& xyz) const { return this->probeConstNode<NodeType>(xyz); }
//@}

//@{
/// @brief Return a pointer to the child node that contains voxel (x, y, z).
/// If no such node exists, return nullptr.
ChildNodeType* probeChild(const Coord& xyz);
const ChildNodeType* probeConstChild(const Coord& xyz) const;
const ChildNodeType* probeChild(const Coord& xyz) const { return this->probeConstChild(xyz); }
//@}

//@{
/// @brief Return a pointer to the child node that contains voxel (x, y, z).
/// If no such node exists, return nullptr.
ChildNodeType* probeChild(const Coord& xyz, ValueType& value, bool& active);
const ChildNodeType* probeConstChild(const Coord& xyz, ValueType& value, bool& active) const;
const ChildNodeType* probeChild(const Coord& xyz, ValueType& value, bool& active) const { return this->probeConstChild(xyz, value, active); }
//@}

//@{
/// @brief Return a pointer to the child node for a specific offset.
/// If no such node exists, return nullptr.
/// @warning This method should only be used by experts seeking low-level optimizations.
/// @note Out-of-bounds memory access attempts will wrap around using modulo indexing.
ChildNodeType* probeChildUnsafe(Index offset);
const ChildNodeType* probeConstChildUnsafe(Index offset) const;
const ChildNodeType* probeChildUnsafe(Index offset) const { return this->probeConstChildUnsafe(offset); }
//@}

//@{
/// @brief Return a pointer to the child node for a specific offset.
/// If no such node exists, return nullptr.
/// @warning This method should only be used by experts seeking low-level optimizations.
/// @note Out-of-bounds memory access attempts will wrap around using modulo indexing.
ChildNodeType* probeChildUnsafe(Index offset, ValueType& value, bool& active);
const ChildNodeType* probeConstChildUnsafe(Index offset, ValueType& value, bool& active) const;
const ChildNodeType* probeChildUnsafe(Index offset, ValueType& value, bool& active) const { return this->probeConstChildUnsafe(offset, value, active); }
//@}

//@{
Expand Down Expand Up @@ -1248,6 +1285,82 @@ InternalNode<ChildT, Log2Dim>::probeConstNodeAndCache(const Coord& xyz, Accessor
////////////////////////////////////////


template<typename ChildT, Index Log2Dim>
inline ChildT*
InternalNode<ChildT, Log2Dim>::probeChild(const Coord& xyz)
{
const Index n = this->coordToOffset(xyz);
return this->probeChildUnsafe(n);
}

template<typename ChildT, Index Log2Dim>
inline const ChildT*
InternalNode<ChildT, Log2Dim>::probeConstChild(const Coord& xyz) const
{
const Index n = this->coordToOffset(xyz);
return this->probeConstChildUnsafe(n);
}

template<typename ChildT, Index Log2Dim>
inline ChildT*
InternalNode<ChildT, Log2Dim>::probeChild(const Coord& xyz, ValueType& value, bool& active)
{
const Index n = this->coordToOffset(xyz);
return this->probeChildUnsafe(n, value, active);
}

template<typename ChildT, Index Log2Dim>
inline const ChildT*
InternalNode<ChildT, Log2Dim>::probeConstChild(const Coord& xyz, ValueType& value, bool& active) const
{
const Index n = this->coordToOffset(xyz);
return this->probeConstChildUnsafe(n, value, active);
}

template<typename ChildT, Index Log2Dim>
inline ChildT*
InternalNode<ChildT, Log2Dim>::probeChildUnsafe(Index offset)
{
OPENVDB_ASSERT(offset < NUM_VALUES);
if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
return nullptr;
}

template<typename ChildT, Index Log2Dim>
inline const ChildT*
InternalNode<ChildT, Log2Dim>::probeConstChildUnsafe(Index offset) const
{
OPENVDB_ASSERT(offset < NUM_VALUES);
if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
return nullptr;
}

template<typename ChildT, Index Log2Dim>
inline ChildT*
InternalNode<ChildT, Log2Dim>::probeChildUnsafe(Index offset, ValueType& value, bool& active)
{
OPENVDB_ASSERT(offset < NUM_VALUES);
if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
value = mNodes[offset].getValue();
active = mValueMask.isOn(offset);
return nullptr;
}

template<typename ChildT, Index Log2Dim>
inline const ChildT*
InternalNode<ChildT, Log2Dim>::probeConstChildUnsafe(Index offset, ValueType& value, bool& active) const
{
OPENVDB_ASSERT(offset < NUM_VALUES);
if (mChildMask.isOn(offset)) return mNodes[offset].getChild();
value = mNodes[offset].getValue();
active = mValueMask.isOn(offset);
return nullptr;
}


////////////////////////////////////////


template<typename ChildT, Index Log2Dim>
inline typename ChildT::LeafNodeType*
InternalNode<ChildT, Log2Dim>::probeLeaf(const Coord& xyz)
Expand Down
86 changes: 85 additions & 1 deletion openvdb/openvdb/tree/RootNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -724,9 +724,20 @@ class RootNode
template <typename NodeT>
NodeT* probeNode(const Coord& xyz);
template <typename NodeT>
const NodeT* probeNode(const Coord& xyz) const;
template <typename NodeT>
const NodeT* probeConstNode(const Coord& xyz) const;
//@}

//@{
/// @brief Return a pointer to the root child node that contains voxel (x, y, z).
/// If no such node exists, query and set the tile value and active status and
/// return @c nullptr.
bool probe(const Coord& xyz, ChildNodeType*& child, ValueType& value, bool& active);
bool probeConst(const Coord& xyz, const ChildNodeType*& child, ValueType& value, bool& active) const;
bool probe(const Coord& xyz, const ChildNodeType*& child, ValueType& value, bool& active) const { return this->probeConst(xyz, child, value, active); }
//}

//@{
/// @brief Same as probeNode() but, if necessary, update the given accessor with pointers
/// to the nodes along the path from the root node to the node containing the coordinate.
Expand All @@ -736,12 +747,20 @@ class RootNode
const NodeT* probeConstNodeAndCache(const Coord& xyz, AccessorT& acc) const;
//@}

//@{
/// @brief Return a pointer to the root child node that contains voxel (x, y, z).
/// If no such node exists, return @c nullptr.
ChildNodeType* probeChild(const Coord& xyz);
const ChildNodeType* probeConstChild(const Coord& xyz) const;
const ChildNodeType* probeChild(const Coord& xyz) const { return this->probeConstChild(xyz); }
//@}

//@{
/// @brief Return a pointer to the leaf node that contains voxel (x, y, z).
/// If no such node exists, return @c nullptr.
LeafNodeType* probeLeaf(const Coord& xyz);
const LeafNodeType* probeConstLeaf(const Coord& xyz) const;
const LeafNodeType* probeLeaf(const Coord& xyz) const;
const LeafNodeType* probeLeaf(const Coord& xyz) const { return this->probeConstLeaf(xyz); }
//@}

//@{
Expand Down Expand Up @@ -2786,6 +2805,15 @@ RootNode<ChildT>::probeNode(const Coord& xyz)
}


template<typename ChildT>
template<typename NodeT>
inline const NodeT*
RootNode<ChildT>::probeNode(const Coord& xyz) const
{
return this->template probeConstNode<NodeT>(xyz);
}


template<typename ChildT>
template<typename NodeT>
inline const NodeT*
Expand All @@ -2804,6 +2832,62 @@ RootNode<ChildT>::probeConstNode(const Coord& xyz) const
}


template<typename ChildT>
inline bool
RootNode<ChildT>::probe(const Coord& xyz, ChildNodeType*& child, ValueType& value, bool& active)
{
MapIter iter = this->findCoord(xyz);
if (iter == mTable.end()) {
child = nullptr;
return false;
} else if (isChild(iter)) {
child = &getChild(iter);
return true;
}
const Tile& tile = getTile(iter);
child = nullptr;
value = tile.value;
active = tile.active;
return true;
}


template<typename ChildT>
inline bool
RootNode<ChildT>::probeConst(const Coord& xyz, const ChildNodeType*& child, ValueType& value, bool& active) const
{
MapCIter iter = this->findCoord(xyz);
if (iter == mTable.end()) {
child = nullptr;
return false;
} else if (isChild(iter)) {
child = &getChild(iter);
return true;
}
const Tile& tile = getTile(iter);
child = nullptr;
value = tile.value;
active = tile.active;
return true;
}


template<typename ChildT>
inline ChildT*
RootNode<ChildT>::probeChild(const Coord& xyz)
{
return this->template probeNode<ChildT>(xyz);
}


template<typename ChildT>
inline const ChildT*
RootNode<ChildT>::probeConstChild(const Coord& xyz) const
{
return this->template probeConstNode<ChildT>(xyz);
}


template<typename ChildT>
inline typename ChildT::LeafNodeType*
RootNode<ChildT>::probeLeaf(const Coord& xyz)
Expand Down
122 changes: 122 additions & 0 deletions openvdb/openvdb/unittest/TestInternalNode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -120,3 +120,125 @@ TEST_F(TestInternalNode, test)
EXPECT_EQ(Index32(5), internalNode3.transientData());
}
}

TEST_F(TestInternalNode, testProbe)
{
using RootNode = FloatTree::RootNodeType;
using InternalNode = RootNode::ChildNodeType;

const Coord ijk(0, 0, 4096);
InternalNode internalNode(ijk, 1.0f);

internalNode.addTile(32, 3.0f, true); // (0, 128, 4096)
internalNode.addTile(33, 4.0f, true); // (0, 128, 4224)

auto* child = new InternalNode::ChildNodeType(Coord(0, 256, 4096), 5.0f, true);
EXPECT_TRUE(internalNode.addChild(child)); // always returns true

{ // probeNode, probeConstNode
auto* node1 = internalNode.probeNode<InternalNode::ChildNodeType>(Coord(0, 256, 4096));
EXPECT_TRUE(bool(node1));
auto* node2 = internalNode.probeNode<InternalNode::ChildNodeType>(Coord(0, 128, 4096));
EXPECT_FALSE(bool(node2));
const InternalNode& constInternalNode = internalNode;
auto* node3 = constInternalNode.probeNode<InternalNode::ChildNodeType>(Coord(0, 256, 4096));
EXPECT_TRUE(bool(node3));
auto* node4 = constInternalNode.probeNode<InternalNode::ChildNodeType>(Coord(0, 128, 4096));
EXPECT_FALSE(bool(node4));
auto* node5 = internalNode.probeConstNode<InternalNode::ChildNodeType>(Coord(0, 256, 4096));
EXPECT_TRUE(bool(node5));
auto* node6 = internalNode.probeConstNode<InternalNode::ChildNodeType>(Coord(0, 128, 4096));
EXPECT_FALSE(bool(node6));
}

{ // probeChild, probeConstChild
auto* node1 = internalNode.probeChild(Coord(0, 256, 4096));
EXPECT_TRUE(bool(node1));
auto* node2 = internalNode.probeChild(Coord(0, 128, 4096));
EXPECT_FALSE(bool(node2));
const InternalNode& constInternalNode = internalNode;
auto* node3 = constInternalNode.probeChild(Coord(0, 256, 4096));
EXPECT_TRUE(bool(node3));
auto* node4 = constInternalNode.probeChild(Coord(0, 128, 4096));
EXPECT_FALSE(bool(node4));
auto* node5 = internalNode.probeConstChild(Coord(0, 256, 4096));
EXPECT_TRUE(bool(node5));
auto* node6 = internalNode.probeConstChild(Coord(0, 128, 4096));
EXPECT_FALSE(bool(node6));
}

{ // probeChildUnsafe, probeConstChildUnsafe
auto* node1 = internalNode.probeChildUnsafe(64);
EXPECT_TRUE(bool(node1));
auto* node2 = internalNode.probeChildUnsafe(33);
EXPECT_FALSE(bool(node2));
const InternalNode& constInternalNode = internalNode;
auto* node3 = constInternalNode.probeChildUnsafe(64);
EXPECT_TRUE(bool(node3));
auto* node4 = constInternalNode.probeChildUnsafe(33);
EXPECT_FALSE(bool(node4));
auto* node5 = internalNode.probeConstChildUnsafe(64);
EXPECT_TRUE(bool(node5));
auto* node6 = internalNode.probeConstChildUnsafe(33);
EXPECT_FALSE(bool(node6));
}

float value = -1.0f;
bool active = false;

{ // probeChild, probeConstChild with value and active status
auto* node1 = internalNode.probeChild(Coord(0, 256, 4096), value, active);
EXPECT_TRUE(bool(node1));
EXPECT_EQ(value, -1.0f);
EXPECT_FALSE(active);
auto* node2 = internalNode.probeChild(Coord(0, 128, 4096), value, active);
EXPECT_FALSE(bool(node2));
EXPECT_EQ(value, 3.0f); value = -1.0f;
EXPECT_TRUE(active); active = false;
const InternalNode& constInternalNode = internalNode;
auto* node3 = constInternalNode.probeChild(Coord(0, 256, 4096), value, active);
EXPECT_TRUE(bool(node3));
EXPECT_EQ(value, -1.0f);
EXPECT_FALSE(active);
auto* node4 = constInternalNode.probeChild(Coord(0, 128, 4096), value, active);
EXPECT_FALSE(bool(node4));
EXPECT_EQ(value, 3.0f); value = -1.0f;
EXPECT_TRUE(active); active = false;
auto* node5 = internalNode.probeConstChild(Coord(0, 256, 4096), value, active);
EXPECT_TRUE(bool(node5));
EXPECT_EQ(value, -1.0f);
EXPECT_FALSE(active);
auto* node6 = internalNode.probeConstChild(Coord(0, 128, 4096), value, active);
EXPECT_FALSE(bool(node6));
EXPECT_EQ(value, 3.0f); value = -1.0f;
EXPECT_TRUE(active); active = false;
}

{ // probeChildUnsafe, probeConstChildUnsafe with value and active status
auto* node1 = internalNode.probeChildUnsafe(64, value, active);
EXPECT_TRUE(bool(node1));
EXPECT_EQ(value, -1.0f);
EXPECT_FALSE(active);
auto* node2 = internalNode.probeChildUnsafe(33, value, active);
EXPECT_FALSE(bool(node2));
EXPECT_EQ(value, 4.0f); value = -1.0f;
EXPECT_TRUE(active); active = false;
const InternalNode& constInternalNode = internalNode;
auto* node3 = constInternalNode.probeChildUnsafe(64, value, active);
EXPECT_TRUE(bool(node3));
EXPECT_EQ(value, -1.0f);
EXPECT_FALSE(active);
auto* node4 = constInternalNode.probeChildUnsafe(33, value, active);
EXPECT_FALSE(bool(node4));
EXPECT_EQ(value, 4.0f); value = -1.0f;
EXPECT_TRUE(active); active = false;
auto* node5 = internalNode.probeConstChildUnsafe(64, value, active);
EXPECT_TRUE(bool(node5));
EXPECT_EQ(value, -1.0f);
EXPECT_FALSE(active);
auto* node6 = internalNode.probeConstChildUnsafe(33, value, active);
EXPECT_FALSE(bool(node6));
EXPECT_EQ(value, 4.0f); value = -1.0f;
EXPECT_TRUE(active); active = false;
}
}
Loading

0 comments on commit 57d4201

Please sign in to comment.