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:
JacksonCampolattaro 2023-03-27 18:12:20 +02:00
parent 353acb57ed
commit 45244da9e1
11 changed files with 403 additions and 421 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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}));
}

View File

@ -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());
}

View File

@ -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;