Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RootNode and InternalNode Probe Methods #1936

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
danrbailey marked this conversation as resolved.
Show resolved Hide resolved
{
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)
danrbailey marked this conversation as resolved.
Show resolved Hide resolved
{
return this->template probeNode<ChildT>(xyz);
}


template<typename ChildT>
inline const ChildT*
RootNode<ChildT>::probeConstChild(const Coord& xyz) const
danrbailey marked this conversation as resolved.
Show resolved Hide resolved
{
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
Loading