mirror of https://github.com/CGAL/cgal
Node can no longer directly access its children without the tree
This is necessary for the next step, but makes the API a pain to use. Some sort of `Node_handle` type is definitely worthwhile.
This commit is contained in:
parent
353acb57ed
commit
45244da9e1
|
|
@ -197,7 +197,7 @@ public:
|
|||
, m_range(point_range)
|
||||
, m_point_map(point_map) {
|
||||
|
||||
m_nodes.reserve(2048); // todo: temporary, for testing
|
||||
m_nodes.reserve(1'000'000); // todo: temporary, for testing
|
||||
m_nodes.emplace_back();
|
||||
|
||||
Array bbox_min;
|
||||
|
|
@ -331,7 +331,7 @@ public:
|
|||
|
||||
// Process each of its children
|
||||
for (int i = 0; i < Degree::value; ++i)
|
||||
todo.push(&(*current)[i]);
|
||||
todo.push(&children(*current)[i]);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -368,7 +368,7 @@ public:
|
|||
|
||||
// Collect all the leaf nodes
|
||||
std::queue<Node*> leaf_nodes;
|
||||
for (const Node& leaf: traverse(Orthtrees::Leaves_traversal())) {
|
||||
for (const Node& leaf: traverse(Orthtrees::Leaves_traversal<Self>(*this))) {
|
||||
// TODO: I'd like to find a better (safer) way of doing this
|
||||
leaf_nodes.push(const_cast<Node*>(&leaf));
|
||||
}
|
||||
|
|
@ -388,7 +388,7 @@ public:
|
|||
for (int direction = 0; direction < 6; ++direction) {
|
||||
|
||||
// Get the neighbor
|
||||
auto* neighbor = node->adjacent_node(direction);
|
||||
auto* neighbor = adjacent_node(*node, direction);
|
||||
|
||||
// If it doesn't exist, skip it
|
||||
if (!neighbor)
|
||||
|
|
@ -412,7 +412,7 @@ public:
|
|||
|
||||
// Add newly created children to the queue
|
||||
for (int i = 0; i < Degree::value; ++i) {
|
||||
leaf_nodes.push(&(*neighbor)[i]);
|
||||
leaf_nodes.push(&children(*neighbor)[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -461,9 +461,9 @@ public:
|
|||
\return a forward input iterator over the nodes of the tree
|
||||
*/
|
||||
template <typename Traversal>
|
||||
Node_range traverse(const Traversal& traversal = Traversal()) const {
|
||||
Node_range traverse(const Traversal& traversal) const {
|
||||
|
||||
const Node* first = traversal.first(&root());
|
||||
const Node* first = traversal.first();
|
||||
|
||||
Node_traversal_method_const next
|
||||
= [&](const Node* n) -> const Node* { return traversal.next(n); };
|
||||
|
|
@ -472,6 +472,12 @@ public:
|
|||
Traversal_iterator<const Node>());
|
||||
}
|
||||
|
||||
// todo: document this convenience function
|
||||
template <typename Traversal>
|
||||
Node_range traverse() const {
|
||||
return traverse<Traversal>(Traversal(*this));
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief constructs the bounding box of a node.
|
||||
|
||||
|
|
@ -534,7 +540,7 @@ public:
|
|||
index[dimension++] = (get < 0 > (r) < get < 1 > (r));
|
||||
|
||||
// Find the correct sub-node of the current node
|
||||
node_for_point = &(*node_for_point)[index.to_ulong()];
|
||||
node_for_point = &children(*node_for_point)[index.to_ulong()];
|
||||
}
|
||||
|
||||
// Return the result
|
||||
|
|
@ -618,7 +624,7 @@ public:
|
|||
return false;
|
||||
|
||||
// If all else is equal, recursively compare the trees themselves
|
||||
return Node::is_topology_equal(rhs.root(), root());
|
||||
return is_topology_equal(root(), *this, rhs.root(), rhs);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
|
@ -630,6 +636,21 @@ public:
|
|||
|
||||
/// @}
|
||||
|
||||
/// \name Node Access
|
||||
/// @{
|
||||
|
||||
using Children = typename Node::Children;
|
||||
|
||||
Children& children(Node& node) {
|
||||
CGAL_precondition (!node.is_leaf());
|
||||
return node.m_children.get();
|
||||
}
|
||||
|
||||
const Children& children(const Node& node) const {
|
||||
CGAL_precondition (!node.is_leaf());
|
||||
return node.m_children.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief splits the node into subnodes.
|
||||
|
||||
|
|
@ -711,6 +732,151 @@ public:
|
|||
return construct_point_d_from_array(bary);
|
||||
}
|
||||
|
||||
|
||||
// todo: this does what the documentation for operator== claims to do!
|
||||
static bool is_topology_equal(const Node& lhsNode, const Self& lhsTree, const Node& rhsNode, const Self& rhsTree) {
|
||||
|
||||
// If one node is a leaf, and the other isn't, they're not the same
|
||||
if (lhsNode.is_leaf() != rhsNode.is_leaf())
|
||||
return false;
|
||||
|
||||
// If both nodes are non-leaf nodes
|
||||
if (!lhsNode.is_leaf()) {
|
||||
|
||||
// Check all the children
|
||||
for (int i = 0; i < Degree::value; ++i) {
|
||||
// If any child cell is different, they're not the same
|
||||
if (!is_topology_equal(lhsTree.children(lhsNode)[i], lhsTree, rhsTree.children(rhsNode)[i], rhsTree))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If both nodes are leaf nodes, they must be in the same location
|
||||
return (lhsNode.global_coordinates() == rhsNode.global_coordinates());
|
||||
}
|
||||
|
||||
static bool is_topology_equal(const Self& lhs, const Self& rhs) {
|
||||
return is_topology_equal(lhs.root(), lhs, rhs.root(), rhs);
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief finds the directly adjacent node in a specific direction
|
||||
|
||||
\pre `!is_null()`
|
||||
\pre `direction.to_ulong < 2 * Dimension::value`
|
||||
|
||||
Adjacent nodes are found according to several properties:
|
||||
- adjacent nodes may be larger than the seek node, but never smaller
|
||||
- a node has at most `2 * Dimension::value` different adjacent nodes (in 3D: left, right, up, down, front, back)
|
||||
- adjacent nodes are not required to be leaf nodes
|
||||
|
||||
Here's a diagram demonstrating the concept for a Quadtree:
|
||||
|
||||
```
|
||||
+---------------+---------------+
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| A | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
+-------+-------+---+---+-------+
|
||||
| | | | | |
|
||||
| A | (S) +---A---+ |
|
||||
| | | | | |
|
||||
+---+---+-------+---+---+-------+
|
||||
| | | | | |
|
||||
+---+---+ A | | |
|
||||
| | | | | |
|
||||
+---+---+-------+-------+-------+
|
||||
```
|
||||
|
||||
- (S) : Seek node
|
||||
- A : Adjacent node
|
||||
|
||||
Note how the top adjacent node is larger than the seek node. The
|
||||
right adjacent node is the same size, even though it contains
|
||||
further subdivisions.
|
||||
|
||||
This implementation returns the adjacent node if it's found. If
|
||||
there is no adjacent node in that direction, it returns a null
|
||||
node.
|
||||
|
||||
\param direction which way to find the adjacent node relative to
|
||||
this one. Each successive bit selects the direction for the
|
||||
corresponding dimension: for an Octree in 3D, 010 means: negative
|
||||
direction in X, position direction in Y, negative direction in Z.
|
||||
|
||||
\return the adjacent node if it exists, a null node otherwise.
|
||||
*/
|
||||
const Node* adjacent_node(const Node& node, typename Node::Local_coordinates direction) const {
|
||||
|
||||
// Direction: LEFT RIGHT DOWN UP BACK FRONT
|
||||
// direction: 000 001 010 011 100 101
|
||||
|
||||
// Nodes only have up to 2*dim different adjacent nodes (since cubes have 6 sides)
|
||||
CGAL_precondition(direction.to_ulong() < Dimension::value * 2);
|
||||
|
||||
// The root node has no adjacent nodes!
|
||||
if (node.is_root()) return nullptr;
|
||||
|
||||
// The least significant bit indicates the sign (which side of the node)
|
||||
bool sign = direction[0];
|
||||
|
||||
// The first two bits indicate the dimension/axis (x, y, z)
|
||||
uint8_t dimension = uint8_t((direction >> 1).to_ulong());
|
||||
|
||||
// Create an offset so that the bit-significance lines up with the dimension (e.g. 1, 2, 4 --> 001, 010, 100)
|
||||
int8_t offset = (uint8_t) 1 << dimension;
|
||||
|
||||
// Finally, apply the sign to the offset
|
||||
offset = (sign ? offset : -offset);
|
||||
|
||||
// Check if this child has the opposite sign along the direction's axis
|
||||
if (node.local_coordinates()[dimension] != sign) {
|
||||
// This means the adjacent node is a direct sibling, the offset can be applied easily!
|
||||
return &children(*node.parent())[node.local_coordinates().to_ulong() + offset];
|
||||
}
|
||||
|
||||
// Find the parent's neighbor in that direction, if it exists
|
||||
const Node* adjacent_node_of_parent = adjacent_node(*node.parent(), direction);
|
||||
|
||||
// If the parent has no neighbor, then this node doesn't have one
|
||||
if (adjacent_node_of_parent == nullptr) return nullptr;
|
||||
|
||||
// If the parent's adjacent node has no children, then it's this node's adjacent node
|
||||
if (adjacent_node_of_parent->is_leaf())
|
||||
return adjacent_node_of_parent;
|
||||
|
||||
// Return the nearest node of the parent by subtracting the offset instead of adding
|
||||
return &children(*adjacent_node_of_parent)[node.local_coordinates().to_ulong() - offset];
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief equivalent to `adjacent_node()`, with an adjacency direction rather than a bitset.
|
||||
*/
|
||||
const Node* adjacent_node(const Node& node, typename Node::Adjacency adjacency) const {
|
||||
return adjacent_node(node, std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief equivalent to adjacent_node, except non-const
|
||||
*/
|
||||
Node* adjacent_node(Node& node, std::bitset<Dimension::value> direction) {
|
||||
return const_cast<Node*>(const_cast<const Self*>(this)->adjacent_node(node, direction));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief equivalent to adjacent_node, with a Direction rather than a bitset and non-const
|
||||
*/
|
||||
Node* adjacent_node(Node& node, typename Node::Adjacency adjacency) {
|
||||
return adjacent_node(node, std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private: // functions :
|
||||
|
||||
void reassign_points(Node& node, Range_iterator begin, Range_iterator end, const Point& center,
|
||||
|
|
@ -720,7 +886,7 @@ private: // functions :
|
|||
// Root case: reached the last dimension
|
||||
if (dimension == Dimension::value) {
|
||||
|
||||
node[coord.to_ulong()].points() = {begin, end};
|
||||
children(node)[coord.to_ulong()].points() = {begin, end};
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
@ -831,7 +997,7 @@ private: // functions :
|
|||
|
||||
// Fill the list with child nodes
|
||||
for (int index = 0; index < Degree::value; ++index) {
|
||||
auto& child_node = node[index];
|
||||
auto& child_node = children(node)[index];
|
||||
|
||||
// Add a child to the list, with its distance
|
||||
children_with_distances.emplace_back(typename Node::Local_coordinates(index),
|
||||
|
|
@ -845,7 +1011,7 @@ private: // functions :
|
|||
|
||||
// Loop over the children
|
||||
for (auto child_with_distance: children_with_distances) {
|
||||
auto& child_node = node[child_with_distance.index.to_ulong()];
|
||||
auto& child_node = children(node)[child_with_distance.index.to_ulong()];
|
||||
|
||||
// Check whether the bounding box of the child intersects with the search bounds
|
||||
if (do_intersect(child_node, search_bounds)) {
|
||||
|
|
@ -872,7 +1038,7 @@ private: // functions :
|
|||
|
||||
// Otherwise, each of the children need to be checked
|
||||
for (int i = 0; i < Degree::value; ++i) {
|
||||
intersected_nodes_recursive(query, node[i], output);
|
||||
intersected_nodes_recursive(query, children(node)[i], output);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
|
|
@ -970,7 +1136,7 @@ public:
|
|||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Self& orthtree) {
|
||||
// Create a range of nodes
|
||||
auto nodes = orthtree.traverse(Orthtrees::Preorder_traversal());
|
||||
auto nodes = orthtree.traverse(Orthtrees::Preorder_traversal<Self>(orthtree));
|
||||
// Iterate over the range
|
||||
for (auto& n: nodes) {
|
||||
// Show the depth
|
||||
|
|
|
|||
|
|
@ -139,13 +139,6 @@ public:
|
|||
explicit Node(Self* parent, Local_coordinates local_coordinates)
|
||||
: m_parent(parent) {
|
||||
|
||||
// if (m_parent) {
|
||||
// m_depth = m_parent->m_depth + 1;
|
||||
//
|
||||
// for (int i = 0; i < Dimension::value; i++)
|
||||
// m_global_coordinates[i] = (2 * parent->m_global_coordinates[i]) + local_coordinates[i];
|
||||
// }
|
||||
|
||||
if (parent != nullptr) {
|
||||
m_depth = parent->m_depth + 1;
|
||||
|
||||
|
|
@ -175,16 +168,6 @@ public:
|
|||
|
||||
const Point_range& points() const { return m_points; }
|
||||
|
||||
Children& children() {
|
||||
CGAL_precondition (!is_leaf());
|
||||
return m_children.get();
|
||||
}
|
||||
|
||||
const Children& children() const {
|
||||
CGAL_precondition (!is_leaf());
|
||||
return m_children.get();
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Type & Location
|
||||
|
|
@ -255,201 +238,6 @@ public:
|
|||
return m_parent;
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns the nth child of this node.
|
||||
|
||||
\pre `!is_leaf()`
|
||||
\pre `0 <= index && index < Degree::value`
|
||||
|
||||
The orthtree subdivides the space in 2 on each dimension
|
||||
available, so a child node can be accessed by selecting a Boolean
|
||||
value for each dimension. The `index` parameter is thus
|
||||
interpreted as a bitmap, where each bit matches a dimension
|
||||
(starting by the least significant bit for coordinate X).
|
||||
|
||||
For example, in the case of an octree (dimension 3):
|
||||
|
||||
- index 0 (000 in binary) is the children on the "minimum corner" (xmin, ymin, zmin)
|
||||
- index 1 (001 in binary) is on (xmax, ymin, zmin)
|
||||
- index 2 (010 in binary) is on (xmin, ymax, zmin)
|
||||
- index 6 (101 in binary) is on (xmax, ymin, zmax)
|
||||
|
||||
Diagram of a quadtree:
|
||||
|
||||
```
|
||||
Children of the current node:
|
||||
|
||||
Y axis
|
||||
A
|
||||
| +-------------------+-------------------+
|
||||
| | Coord: Ymax Xmin | Coord: Ymax Xmax |
|
||||
| | Bitmap: 1 0 | Bitmap: 1 1 |
|
||||
| | | |
|
||||
| | -> index = 2 | -> index = 3 |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| +-------------------+-------------------+
|
||||
| | Coord: Ymin Xmin | Coord: Ymin Xmax |
|
||||
| | Bitmap: 0 0 | Bitmap: 0 1 |
|
||||
| | | |
|
||||
| | -> index = 0 | -> index = 1 |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| | | |
|
||||
| +-------------------+-------------------+
|
||||
|
|
||||
+--------------------------------------------> X axis
|
||||
0
|
||||
```
|
||||
|
||||
The operator can be chained. For example, `n[5][2][3]` returns the
|
||||
third child of the second child of the fifth child of a node `n`.
|
||||
*/
|
||||
Self& operator[](std::size_t index) {
|
||||
|
||||
CGAL_precondition (!is_leaf());
|
||||
CGAL_precondition (index < Degree::value);
|
||||
|
||||
return m_children.get()[index];
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief returns the nth child of this node.
|
||||
|
||||
\pre `!is_leaf()`
|
||||
\pre `index < Degree::value`
|
||||
|
||||
The operator can be chained. For example, `n[5][2][3]` returns the
|
||||
third child of the second child of the fifth child of a node `n`.
|
||||
*/
|
||||
const Self& operator[](std::size_t index) const {
|
||||
|
||||
CGAL_precondition (!is_leaf());
|
||||
CGAL_precondition (index < Degree::value);
|
||||
|
||||
return m_children.get()[index];
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief finds the directly adjacent node in a specific direction
|
||||
|
||||
\pre `!is_null()`
|
||||
\pre `direction.to_ulong < 2 * Dimension::value`
|
||||
|
||||
Adjacent nodes are found according to several properties:
|
||||
- adjacent nodes may be larger than the seek node, but never smaller
|
||||
- a node has at most `2 * Dimension::value` different adjacent nodes (in 3D: left, right, up, down, front, back)
|
||||
- adjacent nodes are not required to be leaf nodes
|
||||
|
||||
Here's a diagram demonstrating the concept for a Quadtree:
|
||||
|
||||
```
|
||||
+---------------+---------------+
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
| A | |
|
||||
| | |
|
||||
| | |
|
||||
| | |
|
||||
+-------+-------+---+---+-------+
|
||||
| | | | | |
|
||||
| A | (S) +---A---+ |
|
||||
| | | | | |
|
||||
+---+---+-------+---+---+-------+
|
||||
| | | | | |
|
||||
+---+---+ A | | |
|
||||
| | | | | |
|
||||
+---+---+-------+-------+-------+
|
||||
```
|
||||
|
||||
- (S) : Seek node
|
||||
- A : Adjacent node
|
||||
|
||||
Note how the top adjacent node is larger than the seek node. The
|
||||
right adjacent node is the same size, even though it contains
|
||||
further subdivisions.
|
||||
|
||||
This implementation returns the adjacent node if it's found. If
|
||||
there is no adjacent node in that direction, it returns a null
|
||||
node.
|
||||
|
||||
\param direction which way to find the adjacent node relative to
|
||||
this one. Each successive bit selects the direction for the
|
||||
corresponding dimension: for an Octree in 3D, 010 means: negative
|
||||
direction in X, position direction in Y, negative direction in Z.
|
||||
|
||||
\return the adjacent node if it exists, a null node otherwise.
|
||||
*/
|
||||
const Self* adjacent_node(Local_coordinates direction) const {
|
||||
|
||||
// Direction: LEFT RIGHT DOWN UP BACK FRONT
|
||||
// direction: 000 001 010 011 100 101
|
||||
|
||||
// Nodes only have up to 2*dim different adjacent nodes (since cubes have 6 sides)
|
||||
CGAL_precondition(direction.to_ulong() < Dimension::value * 2);
|
||||
|
||||
// The root node has no adjacent nodes!
|
||||
if (is_root()) return nullptr;
|
||||
|
||||
// The least significant bit indicates the sign (which side of the node)
|
||||
bool sign = direction[0];
|
||||
|
||||
// The first two bits indicate the dimension/axis (x, y, z)
|
||||
uint8_t dimension = uint8_t((direction >> 1).to_ulong());
|
||||
|
||||
// Create an offset so that the bit-significance lines up with the dimension (e.g. 1, 2, 4 --> 001, 010, 100)
|
||||
int8_t offset = (uint8_t) 1 << dimension;
|
||||
|
||||
// Finally, apply the sign to the offset
|
||||
offset = (sign ? offset : -offset);
|
||||
|
||||
// Check if this child has the opposite sign along the direction's axis
|
||||
if (local_coordinates()[dimension] != sign) {
|
||||
// This means the adjacent node is a direct sibling, the offset can be applied easily!
|
||||
return &(*parent())[local_coordinates().to_ulong() + offset];
|
||||
}
|
||||
|
||||
// Find the parent's neighbor in that direction, if it exists
|
||||
const Self* adjacent_node_of_parent = parent()->adjacent_node(direction);
|
||||
|
||||
// If the parent has no neighbor, then this node doesn't have one
|
||||
if (!adjacent_node_of_parent) return nullptr;
|
||||
|
||||
// If the parent's adjacent node has no children, then it's this node's adjacent node
|
||||
if (adjacent_node_of_parent->is_leaf())
|
||||
return adjacent_node_of_parent;
|
||||
|
||||
// Return the nearest node of the parent by subtracting the offset instead of adding
|
||||
return &(*adjacent_node_of_parent)[local_coordinates().to_ulong() - offset];
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
\brief equivalent to `adjacent_node()`, with an adjacency direction
|
||||
rather than a bitset.
|
||||
*/
|
||||
const Self* adjacent_node(Adjacency adjacency) const {
|
||||
return adjacent_node(std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief equivalent to adjacent_node, except non-const
|
||||
*/
|
||||
Self* adjacent_node(std::bitset<Dimension::value> direction) {
|
||||
return const_cast<Self*>(const_cast<const Self*>(this)->adjacent_node(direction));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief equivalent to adjacent_node, with a Direction rather than a bitset and non-const
|
||||
*/
|
||||
Self* adjacent_node(Adjacency adjacency) {
|
||||
return adjacent_node(std::bitset<Dimension::value>(static_cast<int>(adjacency)));
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
/// \name Point Range
|
||||
|
|
@ -505,28 +293,6 @@ public:
|
|||
rhs.m_global_coordinates == m_global_coordinates;
|
||||
}
|
||||
|
||||
// todo: this does what the documentation for operator== claims to do!
|
||||
static bool is_topology_equal(const Self& a, const Self& b) {
|
||||
|
||||
// If one node is a leaf, and the other isn't, they're not the same
|
||||
if (a.is_leaf() != b.is_leaf())
|
||||
return false;
|
||||
|
||||
// If both nodes are non-leaf nodes
|
||||
if (!a.is_leaf()) {
|
||||
|
||||
// Check all the children
|
||||
for (int i = 0; i < Degree::value; ++i) {
|
||||
// If any child cell is different, they're not the same
|
||||
if (!is_topology_equal(a[i], b[i]))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If both nodes are leaf nodes, they must be in the same location
|
||||
return (a.global_coordinates() == b.global_coordinates());
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Self& node) {
|
||||
return internal::print_orthtree_node(os, node);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
namespace CGAL {
|
||||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
// todo: is this necessary?
|
||||
// Forward declaration
|
||||
template <typename T, typename PR, typename PM>
|
||||
class Orthtree;
|
||||
|
|
@ -32,8 +33,10 @@ namespace Orthtrees {
|
|||
|
||||
/// \cond SKIP_IN_MANUAL
|
||||
|
||||
template <typename Node>
|
||||
const Node* next_sibling(const Node* n) {
|
||||
// todo: all of these could be members of Orthtree
|
||||
|
||||
template <typename Tree>
|
||||
const typename Tree::Node* next_sibling(const Tree &orthtree, const typename Tree::Node* n) {
|
||||
|
||||
// Passing null returns the first node
|
||||
if (nullptr == n)
|
||||
|
|
@ -46,25 +49,25 @@ const Node* next_sibling(const Node* n) {
|
|||
// Find out which child this is
|
||||
std::size_t index = n->local_coordinates().to_ulong();
|
||||
|
||||
constexpr static int degree = Node::Degree::value;
|
||||
constexpr static int degree = Tree::Node::Degree::value;
|
||||
// Return null if this is the last child
|
||||
if (int(index) == degree - 1)
|
||||
return nullptr;
|
||||
|
||||
// Otherwise, return the next child
|
||||
return &((*n->parent())[index + 1]);
|
||||
return &(orthtree.children(*n->parent())[index + 1]);
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
const Node* next_sibling_up(const Node* n) {
|
||||
template <typename Tree>
|
||||
const typename Tree::Node* next_sibling_up(const Tree &orthtree, const typename Tree::Node* n) {
|
||||
|
||||
if (!n || n->is_root()) return nullptr;
|
||||
|
||||
auto up = n->parent();
|
||||
while (nullptr != up) {
|
||||
|
||||
if (nullptr != next_sibling(up))
|
||||
return next_sibling(up);
|
||||
if (nullptr != next_sibling(orthtree, up))
|
||||
return next_sibling(orthtree, up);
|
||||
|
||||
if (up->is_root()) return nullptr;
|
||||
|
||||
|
|
@ -74,41 +77,42 @@ const Node* next_sibling_up(const Node* n) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
const Node* deepest_first_child(const Node* n) {
|
||||
template <typename Tree>
|
||||
const typename Tree::Node* deepest_first_child(const Tree &orthtree, const typename Tree::Node* n) {
|
||||
|
||||
if (!n)
|
||||
if (n == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// Find the deepest child on the left
|
||||
auto first = n;
|
||||
while (!first->is_leaf())
|
||||
first = &(*first)[0];
|
||||
first = &orthtree.children(*first)[0];
|
||||
return first;
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
const Node& first_child_at_depth(const Node* n, std::size_t depth) {
|
||||
|
||||
template <typename Tree>
|
||||
const typename Tree::Node* first_child_at_depth(const Tree &orthtree, const typename Tree::Node* n, std::size_t depth) {
|
||||
|
||||
if (!n)
|
||||
return nullptr;
|
||||
|
||||
std::stack<const Node*> todo;
|
||||
std::stack<const typename Tree::Node*> todo;
|
||||
todo.push(n);
|
||||
|
||||
if (n->depth() == depth)
|
||||
return n;
|
||||
|
||||
while (!todo.empty()) {
|
||||
const Node* node = todo.top();
|
||||
const typename Tree::Node* node = todo.top();
|
||||
todo.pop();
|
||||
|
||||
if (node->depth() == depth)
|
||||
return node;
|
||||
|
||||
if (!node->is_leaf())
|
||||
for (int i = 0; i < Node::Degree::value; ++i)
|
||||
todo.push(&((*node)[std::size_t(Node::Degree::value - 1 - i)]));
|
||||
for (int i = 0; i < Tree::Node::Degree::value; ++i)
|
||||
todo.push(&((*node)[std::size_t(Tree::Node::Degree::value - 1 - i)]));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
|
@ -124,23 +128,31 @@ const Node& first_child_at_depth(const Node* n, std::size_t depth) {
|
|||
|
||||
\cgalModels `OrthtreeTraversal`
|
||||
*/
|
||||
template <typename Tree>
|
||||
struct Preorder_traversal {
|
||||
private:
|
||||
|
||||
template <typename Node>
|
||||
const Node* first(const Node* root) const {
|
||||
return root;
|
||||
using Node = typename Tree::Node;
|
||||
|
||||
const Tree& m_orthtree;
|
||||
|
||||
public:
|
||||
|
||||
Preorder_traversal(const Tree& orthtree) : m_orthtree(orthtree) {}
|
||||
|
||||
const Node* first() const {
|
||||
return &m_orthtree.root();
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
const Node* next(const Node* n) const {
|
||||
|
||||
if (n->is_leaf()) {
|
||||
|
||||
auto next = next_sibling(n);
|
||||
auto next = next_sibling(m_orthtree, n);
|
||||
|
||||
if (nullptr == next) {
|
||||
|
||||
return next_sibling_up(n);
|
||||
return next_sibling_up(m_orthtree, n);
|
||||
}
|
||||
|
||||
return next;
|
||||
|
|
@ -148,7 +160,7 @@ struct Preorder_traversal {
|
|||
} else {
|
||||
|
||||
// Return the first child of this node
|
||||
return &(*n)[0];
|
||||
return &m_orthtree.children(*n)[0];
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -162,18 +174,25 @@ struct Preorder_traversal {
|
|||
|
||||
\cgalModels `OrthtreeTraversal`
|
||||
*/
|
||||
template <typename Tree>
|
||||
struct Postorder_traversal {
|
||||
private:
|
||||
|
||||
template <typename Node>
|
||||
const Node* first(const Node* root) const {
|
||||
using Node = typename Tree::Node;
|
||||
|
||||
return deepest_first_child(root);
|
||||
const Tree& m_orthtree;
|
||||
|
||||
public:
|
||||
|
||||
Postorder_traversal(const Tree& orthtree) : m_orthtree(orthtree) {}
|
||||
|
||||
const Node* first() const {
|
||||
return deepest_first_child(m_orthtree, m_orthtree.root());
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
const Node* next(const Node* n) const {
|
||||
|
||||
auto next = deepest_first_child(next_sibling(n));
|
||||
auto next = deepest_first_child(m_orthtree, next_sibling(m_orthtree, n));
|
||||
|
||||
if (!next)
|
||||
next = n->parent();
|
||||
|
|
@ -190,21 +209,28 @@ struct Postorder_traversal {
|
|||
|
||||
\cgalModels `OrthtreeTraversal`
|
||||
*/
|
||||
template <typename Tree>
|
||||
struct Leaves_traversal {
|
||||
private:
|
||||
|
||||
template <typename Node>
|
||||
const Node* first(const Node* root) const {
|
||||
using Node = typename Tree::Node;
|
||||
|
||||
return deepest_first_child(root);
|
||||
const Tree& m_orthtree;
|
||||
|
||||
public:
|
||||
|
||||
Leaves_traversal(const Tree& orthtree) : m_orthtree(orthtree) {}
|
||||
|
||||
const Node* first() const {
|
||||
return deepest_first_child(m_orthtree, &m_orthtree.root());
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
const Node* next(const Node* n) const {
|
||||
|
||||
auto next = deepest_first_child(next_sibling(n));
|
||||
auto next = deepest_first_child(m_orthtree, next_sibling(m_orthtree, n));
|
||||
|
||||
if (!next)
|
||||
next = deepest_first_child(next_sibling_up(n));
|
||||
next = deepest_first_child(m_orthtree, next_sibling_up(m_orthtree, n));
|
||||
|
||||
return next;
|
||||
}
|
||||
|
|
@ -219,38 +245,39 @@ struct Leaves_traversal {
|
|||
|
||||
\cgalModels `OrthtreeTraversal`
|
||||
*/
|
||||
template <typename Tree>
|
||||
struct Level_traversal {
|
||||
|
||||
private:
|
||||
|
||||
const std::size_t depth;
|
||||
using Node = typename Tree::Node;
|
||||
|
||||
const Tree& m_orthtree;
|
||||
const std::size_t m_depth;
|
||||
|
||||
public:
|
||||
|
||||
/*!
|
||||
constructs a `depth`-level traversal.
|
||||
*/
|
||||
Level_traversal(std::size_t depth) : depth(depth) {}
|
||||
Level_traversal(const Tree& orthtree, std::size_t depth) : m_orthtree(orthtree), m_depth(depth) {}
|
||||
|
||||
template <typename Node>
|
||||
const Node* first(const Node* root) const {
|
||||
return first_child_at_depth(root, depth);
|
||||
const Node* first() const {
|
||||
return first_child_at_depth(m_orthtree, m_orthtree.root(), m_depth);
|
||||
}
|
||||
|
||||
template <typename Node>
|
||||
const Node* next(const Node* n) const {
|
||||
// fixme: leftover from debugging?
|
||||
std::cerr << depth << " ";
|
||||
const Node* next = next_sibling(n);
|
||||
const Node* next = next_sibling(m_orthtree, n);
|
||||
|
||||
if (!next) {
|
||||
const Node* up = n;
|
||||
do {
|
||||
up = next_sibling_up(up);
|
||||
up = next_sibling_up(m_orthtree, up);
|
||||
if (!up)
|
||||
return nullptr;
|
||||
|
||||
next = first_child_at_depth(up, depth);
|
||||
next = first_child_at_depth(m_orthtree, up, m_depth);
|
||||
} while (!next);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -42,36 +42,39 @@ int main(void) {
|
|||
std::cout << octree << std::endl;
|
||||
|
||||
// Root node should have no siblings
|
||||
assert(octree.root().adjacent_node(0) == nullptr);
|
||||
assert(octree.root().adjacent_node(1) == nullptr);
|
||||
assert(octree.root().adjacent_node(2) == nullptr);
|
||||
assert(octree.root().adjacent_node(3) == nullptr);
|
||||
assert(octree.root().adjacent_node(4) == nullptr);
|
||||
assert(octree.root().adjacent_node(5) == nullptr);
|
||||
assert(octree.adjacent_node(octree.root(), 0) == nullptr);
|
||||
assert(octree.adjacent_node(octree.root(), 1) == nullptr);
|
||||
assert(octree.adjacent_node(octree.root(), 2) == nullptr);
|
||||
assert(octree.adjacent_node(octree.root(), 3) == nullptr);
|
||||
assert(octree.adjacent_node(octree.root(), 4) == nullptr);
|
||||
assert(octree.adjacent_node(octree.root(), 5) == nullptr);
|
||||
|
||||
// Left Top Front node should have siblings to the Right, Down, and Back
|
||||
auto left_top_back = octree.root()[Traits::LEFT_TOP_BACK];
|
||||
auto left_top_back = octree.children(octree.root())[Traits::LEFT_TOP_BACK];
|
||||
|
||||
assert(&octree.root()[Traits::RIGHT_TOP_BACK] == left_top_back.adjacent_node(Traits::RIGHT));
|
||||
assert(&octree.root()[Traits::LEFT_BOTTOM_BACK] == left_top_back.adjacent_node(Traits::DOWN));
|
||||
assert(&octree.root()[Traits::LEFT_TOP_FRONT] == left_top_back.adjacent_node(Traits::FRONT));
|
||||
assert(left_top_back.adjacent_node(Traits::LEFT) == nullptr);
|
||||
assert(left_top_back.adjacent_node(Traits::UP) == nullptr);
|
||||
assert(left_top_back.adjacent_node(Traits::BACK) == nullptr);
|
||||
assert(&octree.children(octree.root())[Traits::RIGHT_TOP_BACK] == octree.adjacent_node(left_top_back, Traits::RIGHT));
|
||||
assert(
|
||||
&octree.children(octree.root())[Traits::LEFT_BOTTOM_BACK] == octree.adjacent_node(left_top_back, Traits::DOWN));
|
||||
assert(&octree.children(octree.root())[Traits::LEFT_TOP_FRONT] == octree.adjacent_node(left_top_back, Traits::FRONT));
|
||||
assert(octree.adjacent_node(left_top_back, Traits::LEFT) == nullptr);
|
||||
assert(octree.adjacent_node(left_top_back, Traits::UP) == nullptr);
|
||||
assert(octree.adjacent_node(left_top_back, Traits::BACK) == nullptr);
|
||||
|
||||
std::cout << octree.root()[Traits::LEFT_BOTTOM_BACK] << std::endl;
|
||||
std::cout << octree.children(octree.root())[Traits::LEFT_BOTTOM_BACK] << std::endl;
|
||||
|
||||
auto right_top_back_of_left_bottom_back = octree.root()[Traits::LEFT_BOTTOM_BACK][Traits::RIGHT_TOP_BACK];
|
||||
assert(&octree.root()[Traits::LEFT_BOTTOM_BACK][Traits::LEFT_TOP_BACK] ==
|
||||
right_top_back_of_left_bottom_back.adjacent_node(Traits::LEFT));
|
||||
assert(&octree.root()[Traits::RIGHT_BOTTOM_BACK] == right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT));
|
||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT) != nullptr);
|
||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::UP) != nullptr);
|
||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::DOWN) != nullptr);
|
||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::FRONT) != nullptr);
|
||||
auto right_top_back_of_left_bottom_back =
|
||||
octree.children(octree.children(octree.root())[Traits::LEFT_BOTTOM_BACK])[Traits::RIGHT_TOP_BACK];
|
||||
assert(&octree.children(octree.children(octree.root())[Traits::LEFT_BOTTOM_BACK])[Traits::LEFT_TOP_BACK] ==
|
||||
octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::LEFT));
|
||||
assert(&octree.children(octree.root())[Traits::RIGHT_BOTTOM_BACK] ==
|
||||
octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::RIGHT));
|
||||
assert(octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::RIGHT) != nullptr);
|
||||
assert(octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::UP) != nullptr);
|
||||
assert(octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::DOWN) != nullptr);
|
||||
assert(octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::FRONT) != nullptr);
|
||||
|
||||
// A node at the back of the tree should have no neighbor to its back
|
||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::BACK) == nullptr);
|
||||
assert(octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::BACK) == nullptr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ typedef CGAL::Simple_cartesian<double> Kernel;
|
|||
typedef Kernel::Point_3 Point;
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||
Octree;
|
||||
Octree;
|
||||
|
||||
int main(void) {
|
||||
|
||||
|
|
@ -38,9 +38,10 @@ int main(void) {
|
|||
octree.refine(10, 1);
|
||||
|
||||
std::cout << "root: " << octree.root().local_coordinates() << std::endl;
|
||||
std::cout << "first child: " << octree.root()[0].local_coordinates() << std::endl;
|
||||
std::cout << "fifth child: " << octree.root()[4].local_coordinates() << std::endl;
|
||||
std::cout << "fifth child of first child: " << octree.root()[0][4].local_coordinates() << std::endl;
|
||||
std::cout << "first child: " << octree.children(octree.root())[0].local_coordinates() << std::endl;
|
||||
std::cout << "fifth child: " << octree.children(octree.root())[4].local_coordinates() << std::endl;
|
||||
std::cout << "fifth child of first child: "
|
||||
<< octree.children(octree.children(octree.root())[0])[4].local_coordinates() << std::endl;
|
||||
|
||||
// TODO
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ typedef Kernel::Point_3 Point;
|
|||
typedef Kernel::FT FT;
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||
Octree;
|
||||
Octree;
|
||||
|
||||
void test_1_node() {
|
||||
|
||||
|
|
@ -42,14 +42,14 @@ void test_9_nodes() {
|
|||
assert(octree.bbox(octree.root()) == CGAL::Bbox_3(-1.1, -1.1, -1.1, 1.1, 1.1, 1.1));
|
||||
|
||||
// Compare the child nodes
|
||||
assert(octree.bbox(octree.root()[0]) == CGAL::Bbox_3(-1.1, -1.1, -1.1, 0, 0, 0));
|
||||
assert(octree.bbox(octree.root()[1]) == CGAL::Bbox_3(0, -1.1, -1.1, 1.1, 0, 0));
|
||||
assert(octree.bbox(octree.root()[2]) == CGAL::Bbox_3(-1.1, 0, -1.1, 0, 1.1, 0));
|
||||
assert(octree.bbox(octree.root()[3]) == CGAL::Bbox_3(0, 0, -1.1, 1.1, 1.1, 0));
|
||||
assert(octree.bbox(octree.root()[4]) == CGAL::Bbox_3(-1.1, -1.1, 0, 0, 0, 1.1));
|
||||
assert(octree.bbox(octree.root()[5]) == CGAL::Bbox_3(0, -1.1, 0, 1.1, 0, 1.1));
|
||||
assert(octree.bbox(octree.root()[6]) == CGAL::Bbox_3(-1.1, 0, 0, 0, 1.1, 1.1));
|
||||
assert(octree.bbox(octree.root()[7]) == CGAL::Bbox_3(0, 0, 0, 1.1, 1.1, 1.1));
|
||||
assert(octree.bbox(octree.children(octree.root())[0]) == CGAL::Bbox_3(-1.1, -1.1, -1.1, 0, 0, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[1]) == CGAL::Bbox_3(0, -1.1, -1.1, 1.1, 0, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[2]) == CGAL::Bbox_3(-1.1, 0, -1.1, 0, 1.1, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[3]) == CGAL::Bbox_3(0, 0, -1.1, 1.1, 1.1, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[4]) == CGAL::Bbox_3(-1.1, -1.1, 0, 0, 0, 1.1));
|
||||
assert(octree.bbox(octree.children(octree.root())[5]) == CGAL::Bbox_3(0, -1.1, 0, 1.1, 0, 1.1));
|
||||
assert(octree.bbox(octree.children(octree.root())[6]) == CGAL::Bbox_3(-1.1, 0, 0, 0, 1.1, 1.1));
|
||||
assert(octree.bbox(octree.children(octree.root())[7]) == CGAL::Bbox_3(0, 0, 0, 1.1, 1.1, 1.1));
|
||||
}
|
||||
|
||||
void test_25_nodes() {
|
||||
|
|
@ -69,34 +69,50 @@ void test_25_nodes() {
|
|||
assert(octree.bbox(octree.root()) == CGAL::Bbox_3(-1.5, -1.5, -1.5, 1.5, 1.5, 1.5));
|
||||
|
||||
// Compare the child nodes
|
||||
assert(octree.bbox(octree.root()[0]) == CGAL::Bbox_3(-1.5, -1.5, -1.5, 0, 0, 0));
|
||||
assert(octree.bbox(octree.root()[1]) == CGAL::Bbox_3(0, -1.5, -1.5, 1.5, 0, 0));
|
||||
assert(octree.bbox(octree.root()[2]) == CGAL::Bbox_3(-1.5, 0, -1.5, 0, 1.5, 0));
|
||||
assert(octree.bbox(octree.root()[3]) == CGAL::Bbox_3(0, 0, -1.5, 1.5, 1.5, 0));
|
||||
assert(octree.bbox(octree.root()[4]) == CGAL::Bbox_3(-1.5, -1.5, 0, 0, 0, 1.5));
|
||||
assert(octree.bbox(octree.root()[5]) == CGAL::Bbox_3(0, -1.5, 0, 1.5, 0, 1.5));
|
||||
assert(octree.bbox(octree.root()[6]) == CGAL::Bbox_3(-1.5, 0, 0, 0, 1.5, 1.5));
|
||||
assert(octree.bbox(octree.root()[7]) == CGAL::Bbox_3(0, 0, 0, 1.5, 1.5, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.root())[0]) == CGAL::Bbox_3(-1.5, -1.5, -1.5, 0, 0, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[1]) == CGAL::Bbox_3(0, -1.5, -1.5, 1.5, 0, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[2]) == CGAL::Bbox_3(-1.5, 0, -1.5, 0, 1.5, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[3]) == CGAL::Bbox_3(0, 0, -1.5, 1.5, 1.5, 0));
|
||||
assert(octree.bbox(octree.children(octree.root())[4]) == CGAL::Bbox_3(-1.5, -1.5, 0, 0, 0, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.root())[5]) == CGAL::Bbox_3(0, -1.5, 0, 1.5, 0, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.root())[6]) == CGAL::Bbox_3(-1.5, 0, 0, 0, 1.5, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.root())[7]) == CGAL::Bbox_3(0, 0, 0, 1.5, 1.5, 1.5));
|
||||
|
||||
// Compare children of the first child
|
||||
assert(octree.bbox(octree.root()[0][0]) == CGAL::Bbox_3(-1.5, -1.5, -1.5, -0.75, -0.75, -0.75));
|
||||
assert(octree.bbox(octree.root()[0][1]) == CGAL::Bbox_3(-0.75, -1.5, -1.5, 0, -0.75, -0.75));
|
||||
assert(octree.bbox(octree.root()[0][2]) == CGAL::Bbox_3(-1.5, -0.75, -1.5, -0.75, 0, -0.75));
|
||||
assert(octree.bbox(octree.root()[0][3]) == CGAL::Bbox_3(-0.75, -0.75, -1.5, 0, 0, -0.75));
|
||||
assert(octree.bbox(octree.root()[0][4]) == CGAL::Bbox_3(-1.5, -1.5, -0.75, -0.75, -0.75, 0));
|
||||
assert(octree.bbox(octree.root()[0][5]) == CGAL::Bbox_3(-0.75, -1.5, -0.75, 0, -0.75, 0));
|
||||
assert(octree.bbox(octree.root()[0][6]) == CGAL::Bbox_3(-1.5, -0.75, -0.75, -0.75, 0, 0));
|
||||
assert(octree.bbox(octree.root()[0][7]) == CGAL::Bbox_3(-0.75, -0.75, -0.75, 0, 0, 0));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[0]) ==
|
||||
CGAL::Bbox_3(-1.5, -1.5, -1.5, -0.75, -0.75, -0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[1]) ==
|
||||
CGAL::Bbox_3(-0.75, -1.5, -1.5, 0, -0.75, -0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[2]) ==
|
||||
CGAL::Bbox_3(-1.5, -0.75, -1.5, -0.75, 0, -0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[3]) ==
|
||||
CGAL::Bbox_3(-0.75, -0.75, -1.5, 0, 0, -0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[4]) ==
|
||||
CGAL::Bbox_3(-1.5, -1.5, -0.75, -0.75, -0.75, 0));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[5]) ==
|
||||
CGAL::Bbox_3(-0.75, -1.5, -0.75, 0, -0.75, 0));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[6]) ==
|
||||
CGAL::Bbox_3(-1.5, -0.75, -0.75, -0.75, 0, 0));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[0])[7]) ==
|
||||
CGAL::Bbox_3(-0.75, -0.75, -0.75, 0, 0, 0));
|
||||
|
||||
// Compare children of the last child
|
||||
assert(octree.bbox(octree.root()[7][0]) == CGAL::Bbox_3(0, 0, 0, 0.75, 0.75, 0.75));
|
||||
assert(octree.bbox(octree.root()[7][1]) == CGAL::Bbox_3(0.75, 0, 0, 1.5, 0.75, 0.75));
|
||||
assert(octree.bbox(octree.root()[7][2]) == CGAL::Bbox_3(0, 0.75, 0, 0.75, 1.5, 0.75));
|
||||
assert(octree.bbox(octree.root()[7][3]) == CGAL::Bbox_3(0.75, 0.75, 0, 1.5, 1.5, 0.75));
|
||||
assert(octree.bbox(octree.root()[7][4]) == CGAL::Bbox_3(0, 0, 0.75, 0.75, 0.75, 1.5));
|
||||
assert(octree.bbox(octree.root()[7][5]) == CGAL::Bbox_3(0.75, 0, 0.75, 1.5, 0.75, 1.5));
|
||||
assert(octree.bbox(octree.root()[7][6]) == CGAL::Bbox_3(0, 0.75, 0.75, 0.75, 1.5, 1.5));
|
||||
assert(octree.bbox(octree.root()[7][7]) == CGAL::Bbox_3(0.75, 0.75, 0.75, 1.5, 1.5, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[0]) ==
|
||||
CGAL::Bbox_3(0, 0, 0, 0.75, 0.75, 0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[1]) ==
|
||||
CGAL::Bbox_3(0.75, 0, 0, 1.5, 0.75, 0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[2]) ==
|
||||
CGAL::Bbox_3(0, 0.75, 0, 0.75, 1.5, 0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[3]) ==
|
||||
CGAL::Bbox_3(0.75, 0.75, 0, 1.5, 1.5, 0.75));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[4]) ==
|
||||
CGAL::Bbox_3(0, 0, 0.75, 0.75, 0.75, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[5]) ==
|
||||
CGAL::Bbox_3(0.75, 0, 0.75, 1.5, 0.75, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[6]) ==
|
||||
CGAL::Bbox_3(0, 0.75, 0.75, 0.75, 1.5, 1.5));
|
||||
assert(octree.bbox(octree.children(octree.children(octree.root())[7])[7]) ==
|
||||
CGAL::Bbox_3(0.75, 0.75, 0.75, 1.5, 1.5, 1.5));
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ typedef Kernel::Point_3 Point;
|
|||
typedef Kernel::FT FT;
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map> Octree;
|
||||
typedef CGAL::Orthtrees::Leaves_traversal Leaves_traversal;
|
||||
typedef CGAL::Orthtrees::Leaves_traversal<Octree> Leaves_traversal;
|
||||
|
||||
std::size_t count_jumps(Octree &octree) {
|
||||
|
||||
std::size_t jumps = 0;
|
||||
|
||||
for (auto &node : octree.traverse(Leaves_traversal())) {
|
||||
for (auto &node : octree.traverse<Leaves_traversal>()) {
|
||||
|
||||
for (int direction = 0; direction < 6; ++direction) {
|
||||
|
||||
auto adjacent_node = node.adjacent_node(direction);
|
||||
auto adjacent_node = octree.adjacent_node(node, direction);
|
||||
|
||||
if (adjacent_node == nullptr)
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ int main(void) {
|
|||
auto query = Point{1, 1, 1};
|
||||
|
||||
// Get a list of nodes intersected
|
||||
std::vector<const Octree::Node *> nodes{};
|
||||
std::vector<const Octree::Node*> nodes{};
|
||||
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||
|
||||
// A point should only intersect one node
|
||||
|
|
@ -63,15 +63,15 @@ int main(void) {
|
|||
auto query = Kernel::Sphere_3(Point{1, 0.5, 1}, 1.0);
|
||||
|
||||
// Get a list of nodes intersected
|
||||
std::vector<const Octree::Node *> nodes{};
|
||||
std::vector<const Octree::Node*> nodes{};
|
||||
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||
|
||||
// Check the results
|
||||
assert(4 == nodes.size());
|
||||
assert(octree.root()[Octree::Traits::RIGHT_TOP_BACK] == *nodes[0]);
|
||||
assert(octree.root()[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[1]);
|
||||
assert(octree.root()[Octree::Traits::LEFT_TOP_FRONT] == *nodes[2]);
|
||||
assert(octree.root()[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[3]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::RIGHT_TOP_BACK] == *nodes[0]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[1]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::LEFT_TOP_FRONT] == *nodes[2]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[3]);
|
||||
}
|
||||
|
||||
// Intersection with a ray
|
||||
|
|
@ -81,19 +81,22 @@ int main(void) {
|
|||
auto query = Kernel::Ray_3(Point{1, 1, 1}, Point{0, 0, 0});
|
||||
|
||||
// Get a list of nodes intersected
|
||||
std::vector<const Octree::Node *> nodes{};
|
||||
std::vector<const Octree::Node*> nodes{};
|
||||
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||
|
||||
// Check the results
|
||||
assert(8 == nodes.size());
|
||||
assert(octree.root()[Octree::Traits::LEFT_BOTTOM_BACK] == *nodes[0]);
|
||||
assert(octree.root()[Octree::Traits::RIGHT_BOTTOM_BACK][Octree::Traits::LEFT_TOP_FRONT] == *nodes[1]);
|
||||
assert(octree.root()[Octree::Traits::LEFT_TOP_BACK] == *nodes[2]);
|
||||
assert(octree.root()[Octree::Traits::RIGHT_TOP_BACK] == *nodes[3]);
|
||||
assert(octree.root()[Octree::Traits::LEFT_BOTTOM_FRONT] == *nodes[4]);
|
||||
assert(octree.root()[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[5]);
|
||||
assert(octree.root()[Octree::Traits::LEFT_TOP_FRONT] == *nodes[6]);
|
||||
assert(octree.root()[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[7]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::LEFT_BOTTOM_BACK] == *nodes[0]);
|
||||
assert(
|
||||
octree.children(octree.children(octree.root())[Octree::Traits::RIGHT_BOTTOM_BACK])[Octree::Traits::LEFT_TOP_FRONT]
|
||||
== *nodes[1]
|
||||
);
|
||||
assert(octree.children(octree.root())[Octree::Traits::LEFT_TOP_BACK] == *nodes[2]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::RIGHT_TOP_BACK] == *nodes[3]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::LEFT_BOTTOM_FRONT] == *nodes[4]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[5]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::LEFT_TOP_FRONT] == *nodes[6]);
|
||||
assert(octree.children(octree.root())[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[7]);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ typedef Kernel::Point_3 Point;
|
|||
typedef Kernel::FT FT;
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||
Octree;
|
||||
Octree;
|
||||
|
||||
void test_1_point() {
|
||||
|
||||
|
|
@ -52,24 +52,24 @@ void test_8_points() {
|
|||
octree.refine(10, 1);
|
||||
|
||||
// Existing points should end up in the same place
|
||||
assert(octree.root()[0] == octree.locate({-1, -1, -1}));
|
||||
assert(octree.root()[1] == octree.locate({1, -1, -1}));
|
||||
assert(octree.root()[2] == octree.locate({-1, 1, -1}));
|
||||
assert(octree.root()[3] == octree.locate({1, 1, -1}));
|
||||
assert(octree.root()[4] == octree.locate({-1, -1, 1}));
|
||||
assert(octree.root()[5] == octree.locate({1, -1, 1}));
|
||||
assert(octree.root()[6] == octree.locate({-1, 1, 1}));
|
||||
assert(octree.root()[7] == octree.locate({1, 1, 1}));
|
||||
assert(octree.children(octree.root())[0] == octree.locate({-1, -1, -1}));
|
||||
assert(octree.children(octree.root())[1] == octree.locate({1, -1, -1}));
|
||||
assert(octree.children(octree.root())[2] == octree.locate({-1, 1, -1}));
|
||||
assert(octree.children(octree.root())[3] == octree.locate({1, 1, -1}));
|
||||
assert(octree.children(octree.root())[4] == octree.locate({-1, -1, 1}));
|
||||
assert(octree.children(octree.root())[5] == octree.locate({1, -1, 1}));
|
||||
assert(octree.children(octree.root())[6] == octree.locate({-1, 1, 1}));
|
||||
assert(octree.children(octree.root())[7] == octree.locate({1, 1, 1}));
|
||||
|
||||
// Points adjacent to the existing points should also end up in the same place
|
||||
assert(octree.root()[0] == octree.locate({-1.1, -1.1, -1.1}));
|
||||
assert(octree.root()[1] == octree.locate({1.1, -1.1, -1.1}));
|
||||
assert(octree.root()[2] == octree.locate({-1.1, 1.1, -1.1}));
|
||||
assert(octree.root()[3] == octree.locate({1.1, 1.1, -1.1}));
|
||||
assert(octree.root()[4] == octree.locate({-1.1, -1.1, 1.1}));
|
||||
assert(octree.root()[5] == octree.locate({1.1, -1.1, 1.1}));
|
||||
assert(octree.root()[6] == octree.locate({-1.1, 1.1, 1.1}));
|
||||
assert(octree.root()[7] == octree.locate({1.1, 1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[0] == octree.locate({-1.1, -1.1, -1.1}));
|
||||
assert(octree.children(octree.root())[1] == octree.locate({1.1, -1.1, -1.1}));
|
||||
assert(octree.children(octree.root())[2] == octree.locate({-1.1, 1.1, -1.1}));
|
||||
assert(octree.children(octree.root())[3] == octree.locate({1.1, 1.1, -1.1}));
|
||||
assert(octree.children(octree.root())[4] == octree.locate({-1.1, -1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[5] == octree.locate({1.1, -1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[6] == octree.locate({-1.1, 1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[7] == octree.locate({1.1, 1.1, 1.1}));
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -93,24 +93,24 @@ void test_10_points() {
|
|||
octree.refine(10, 1);
|
||||
|
||||
// Existing points should end up in the same place
|
||||
assert(octree.root()[0] == octree.locate({-1, -1, -1}));
|
||||
assert(octree.root()[1] == octree.locate({1, -1, -1}));
|
||||
assert(octree.root()[2] == octree.locate({-1, 1, -1}));
|
||||
assert(octree.root()[3][3][3] == octree.locate({1, 1, -1}));
|
||||
assert(octree.root()[4][4][4] == octree.locate({-1, -1, 1}));
|
||||
assert(octree.root()[5] == octree.locate({1, -1, 1}));
|
||||
assert(octree.root()[6] == octree.locate({-1, 1, 1}));
|
||||
assert(octree.root()[7] == octree.locate({1, 1, 1}));
|
||||
assert(octree.children(octree.root())[0] == octree.locate({-1, -1, -1}));
|
||||
assert(octree.children(octree.root())[1] == octree.locate({1, -1, -1}));
|
||||
assert(octree.children(octree.root())[2] == octree.locate({-1, 1, -1}));
|
||||
assert(octree.children(octree.children(octree.children(octree.root())[3])[3])[3] == octree.locate({1, 1, -1}));
|
||||
assert(octree.children(octree.children(octree.children(octree.root())[4])[4])[4] == octree.locate({-1, -1, 1}));
|
||||
assert(octree.children(octree.root())[5] == octree.locate({1, -1, 1}));
|
||||
assert(octree.children(octree.root())[6] == octree.locate({-1, 1, 1}));
|
||||
assert(octree.children(octree.root())[7] == octree.locate({1, 1, 1}));
|
||||
|
||||
// Points adjacent to the existing points might end up in different places
|
||||
assert(octree.root()[0] == octree.locate({-1.1, -1.1, -1.1}));
|
||||
assert(octree.root()[1] == octree.locate({1.1, -1.1, -1.1}));
|
||||
assert(octree.root()[2] == octree.locate({-1.1, 1.1, -1.1}));
|
||||
assert(octree.root()[3][3][3] == octree.locate({1.1, 1.1, -1.1}));
|
||||
assert(octree.root()[4][4][4] == octree.locate({-1.1, -1.1, 1.1}));
|
||||
assert(octree.root()[5] == octree.locate({1.1, -1.1, 1.1}));
|
||||
assert(octree.root()[6] == octree.locate({-1.1, 1.1, 1.1}));
|
||||
assert(octree.root()[7] == octree.locate({1.1, 1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[0] == octree.locate({-1.1, -1.1, -1.1}));
|
||||
assert(octree.children(octree.root())[1] == octree.locate({1.1, -1.1, -1.1}));
|
||||
assert(octree.children(octree.root())[2] == octree.locate({-1.1, 1.1, -1.1}));
|
||||
assert(octree.children(octree.children(octree.children(octree.root())[3])[3])[3] == octree.locate({1.1, 1.1, -1.1}));
|
||||
assert(octree.children(octree.children(octree.children(octree.root())[4])[4])[4] == octree.locate({-1.1, -1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[5] == octree.locate({1.1, -1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[6] == octree.locate({-1.1, 1.1, 1.1}));
|
||||
assert(octree.children(octree.root())[7] == octree.locate({1.1, 1.1, 1.1}));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ void test_2_points() {
|
|||
// The octree should have been split once
|
||||
Octree other(points, points.point_map());
|
||||
other.split(other.root());
|
||||
assert(Node::is_topology_equal(other.root(), octree.root()));
|
||||
assert(Octree::is_topology_equal(other, octree));
|
||||
assert(1 == octree.depth());
|
||||
}
|
||||
|
||||
|
|
@ -62,9 +62,9 @@ void test_4_points() {
|
|||
// The octree should have been split once on the first level, and twice on the second
|
||||
Octree other(points, points.point_map());
|
||||
other.split(other.root());
|
||||
other.split(other.root()[3]);
|
||||
other.split(other.root()[7]);
|
||||
assert(Node::is_topology_equal(other.root(), octree.root()));
|
||||
other.split(other.children(other.root())[3]);
|
||||
other.split(other.children(other.root())[7]);
|
||||
assert(Octree::is_topology_equal(other, octree));
|
||||
assert(2 == octree.depth());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ typedef CGAL::Simple_cartesian<double> Kernel;
|
|||
typedef Kernel::Point_3 Point;
|
||||
typedef CGAL::Point_set_3<Point> Point_set;
|
||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map> Octree;
|
||||
typedef CGAL::Orthtrees::Preorder_traversal Preorder_traversal;
|
||||
typedef CGAL::Orthtrees::Preorder_traversal<Octree> Preorder_traversal;
|
||||
|
||||
bool test_preorder_1_node() {
|
||||
|
||||
|
|
@ -53,7 +53,7 @@ bool test_preorder_9_nodes() {
|
|||
assert(*iter == octree.root());
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
iter++;
|
||||
assert((*iter == octree.root()[i]));
|
||||
assert((*iter == octree.children(octree.root())[i]));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -79,28 +79,28 @@ bool test_preorder_25_nodes() {
|
|||
auto iter = nodes.begin();
|
||||
assert(*iter == octree.root());
|
||||
iter++;
|
||||
assert((*iter == octree.root()[0]));
|
||||
assert((*iter == octree.children(octree.root())[0]));
|
||||
iter++;
|
||||
assert((*iter == octree.root()[1]));
|
||||
assert((*iter == octree.children(octree.root())[1]));
|
||||
iter++;
|
||||
assert((*iter == octree.root()[2]));
|
||||
assert((*iter == octree.children(octree.root())[2]));
|
||||
iter++;
|
||||
assert((*iter == octree.root()[3]));
|
||||
assert((*iter == octree.children(octree.root())[3]));
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
iter++;
|
||||
assert((*iter == octree.root()[3][i]));
|
||||
assert((*iter == octree.children(octree.children(octree.root())[3])[i]));
|
||||
}
|
||||
iter++;
|
||||
assert((*iter == octree.root()[4]));
|
||||
assert((*iter == octree.children(octree.root())[4]));
|
||||
iter++;
|
||||
assert((*iter == octree.root()[5]));
|
||||
assert((*iter == octree.children(octree.root())[5]));
|
||||
iter++;
|
||||
assert((*iter == octree.root()[6]));
|
||||
assert((*iter == octree.children(octree.root())[6]));
|
||||
iter++;
|
||||
assert((*iter == octree.root()[7]));
|
||||
assert((*iter == octree.children(octree.root())[7]));
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
iter++;
|
||||
assert((*iter == octree.root()[7][i]));
|
||||
assert((*iter == octree.children(octree.children(octree.root())[7])[i]));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
Loading…
Reference in New Issue