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_range(point_range)
|
||||||
, m_point_map(point_map) {
|
, 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();
|
m_nodes.emplace_back();
|
||||||
|
|
||||||
Array bbox_min;
|
Array bbox_min;
|
||||||
|
|
@ -331,7 +331,7 @@ public:
|
||||||
|
|
||||||
// Process each of its children
|
// Process each of its children
|
||||||
for (int i = 0; i < Degree::value; ++i)
|
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
|
// Collect all the leaf nodes
|
||||||
std::queue<Node*> 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
|
// TODO: I'd like to find a better (safer) way of doing this
|
||||||
leaf_nodes.push(const_cast<Node*>(&leaf));
|
leaf_nodes.push(const_cast<Node*>(&leaf));
|
||||||
}
|
}
|
||||||
|
|
@ -388,7 +388,7 @@ public:
|
||||||
for (int direction = 0; direction < 6; ++direction) {
|
for (int direction = 0; direction < 6; ++direction) {
|
||||||
|
|
||||||
// Get the neighbor
|
// Get the neighbor
|
||||||
auto* neighbor = node->adjacent_node(direction);
|
auto* neighbor = adjacent_node(*node, direction);
|
||||||
|
|
||||||
// If it doesn't exist, skip it
|
// If it doesn't exist, skip it
|
||||||
if (!neighbor)
|
if (!neighbor)
|
||||||
|
|
@ -412,7 +412,7 @@ public:
|
||||||
|
|
||||||
// Add newly created children to the queue
|
// Add newly created children to the queue
|
||||||
for (int i = 0; i < Degree::value; ++i) {
|
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
|
\return a forward input iterator over the nodes of the tree
|
||||||
*/
|
*/
|
||||||
template <typename Traversal>
|
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
|
Node_traversal_method_const next
|
||||||
= [&](const Node* n) -> const Node* { return traversal.next(n); };
|
= [&](const Node* n) -> const Node* { return traversal.next(n); };
|
||||||
|
|
@ -472,6 +472,12 @@ public:
|
||||||
Traversal_iterator<const Node>());
|
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.
|
\brief constructs the bounding box of a node.
|
||||||
|
|
||||||
|
|
@ -534,7 +540,7 @@ public:
|
||||||
index[dimension++] = (get < 0 > (r) < get < 1 > (r));
|
index[dimension++] = (get < 0 > (r) < get < 1 > (r));
|
||||||
|
|
||||||
// Find the correct sub-node of the current node
|
// 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
|
// Return the result
|
||||||
|
|
@ -618,7 +624,7 @@ public:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// If all else is equal, recursively compare the trees themselves
|
// 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.
|
\brief splits the node into subnodes.
|
||||||
|
|
||||||
|
|
@ -711,6 +732,151 @@ public:
|
||||||
return construct_point_d_from_array(bary);
|
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 :
|
private: // functions :
|
||||||
|
|
||||||
void reassign_points(Node& node, Range_iterator begin, Range_iterator end, const Point& center,
|
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
|
// Root case: reached the last dimension
|
||||||
if (dimension == Dimension::value) {
|
if (dimension == Dimension::value) {
|
||||||
|
|
||||||
node[coord.to_ulong()].points() = {begin, end};
|
children(node)[coord.to_ulong()].points() = {begin, end};
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -831,7 +997,7 @@ private: // functions :
|
||||||
|
|
||||||
// Fill the list with child nodes
|
// Fill the list with child nodes
|
||||||
for (int index = 0; index < Degree::value; ++index) {
|
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
|
// Add a child to the list, with its distance
|
||||||
children_with_distances.emplace_back(typename Node::Local_coordinates(index),
|
children_with_distances.emplace_back(typename Node::Local_coordinates(index),
|
||||||
|
|
@ -845,7 +1011,7 @@ private: // functions :
|
||||||
|
|
||||||
// Loop over the children
|
// Loop over the children
|
||||||
for (auto child_with_distance: children_with_distances) {
|
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
|
// Check whether the bounding box of the child intersects with the search bounds
|
||||||
if (do_intersect(child_node, search_bounds)) {
|
if (do_intersect(child_node, search_bounds)) {
|
||||||
|
|
@ -872,7 +1038,7 @@ private: // functions :
|
||||||
|
|
||||||
// Otherwise, each of the children need to be checked
|
// Otherwise, each of the children need to be checked
|
||||||
for (int i = 0; i < Degree::value; ++i) {
|
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;
|
return output;
|
||||||
|
|
@ -970,7 +1136,7 @@ public:
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const Self& orthtree) {
|
friend std::ostream& operator<<(std::ostream& os, const Self& orthtree) {
|
||||||
// Create a range of nodes
|
// 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
|
// Iterate over the range
|
||||||
for (auto& n: nodes) {
|
for (auto& n: nodes) {
|
||||||
// Show the depth
|
// Show the depth
|
||||||
|
|
|
||||||
|
|
@ -139,13 +139,6 @@ public:
|
||||||
explicit Node(Self* parent, Local_coordinates local_coordinates)
|
explicit Node(Self* parent, Local_coordinates local_coordinates)
|
||||||
: m_parent(parent) {
|
: 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) {
|
if (parent != nullptr) {
|
||||||
m_depth = parent->m_depth + 1;
|
m_depth = parent->m_depth + 1;
|
||||||
|
|
||||||
|
|
@ -175,16 +168,6 @@ public:
|
||||||
|
|
||||||
const Point_range& points() const { return m_points; }
|
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
|
/// \name Type & Location
|
||||||
|
|
@ -255,201 +238,6 @@ public:
|
||||||
return m_parent;
|
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
|
/// \name Point Range
|
||||||
|
|
@ -505,28 +293,6 @@ public:
|
||||||
rhs.m_global_coordinates == m_global_coordinates;
|
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) {
|
friend std::ostream& operator<<(std::ostream& os, const Self& node) {
|
||||||
return internal::print_orthtree_node(os, node);
|
return internal::print_orthtree_node(os, node);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@
|
||||||
namespace CGAL {
|
namespace CGAL {
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
// todo: is this necessary?
|
||||||
// Forward declaration
|
// Forward declaration
|
||||||
template <typename T, typename PR, typename PM>
|
template <typename T, typename PR, typename PM>
|
||||||
class Orthtree;
|
class Orthtree;
|
||||||
|
|
@ -32,8 +33,10 @@ namespace Orthtrees {
|
||||||
|
|
||||||
/// \cond SKIP_IN_MANUAL
|
/// \cond SKIP_IN_MANUAL
|
||||||
|
|
||||||
template <typename Node>
|
// todo: all of these could be members of Orthtree
|
||||||
const Node* next_sibling(const Node* n) {
|
|
||||||
|
template <typename Tree>
|
||||||
|
const typename Tree::Node* next_sibling(const Tree &orthtree, const typename Tree::Node* n) {
|
||||||
|
|
||||||
// Passing null returns the first node
|
// Passing null returns the first node
|
||||||
if (nullptr == n)
|
if (nullptr == n)
|
||||||
|
|
@ -46,25 +49,25 @@ const Node* next_sibling(const Node* n) {
|
||||||
// Find out which child this is
|
// Find out which child this is
|
||||||
std::size_t index = n->local_coordinates().to_ulong();
|
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
|
// Return null if this is the last child
|
||||||
if (int(index) == degree - 1)
|
if (int(index) == degree - 1)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Otherwise, return the next child
|
// Otherwise, return the next child
|
||||||
return &((*n->parent())[index + 1]);
|
return &(orthtree.children(*n->parent())[index + 1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Tree>
|
||||||
const Node* next_sibling_up(const Node* n) {
|
const typename Tree::Node* next_sibling_up(const Tree &orthtree, const typename Tree::Node* n) {
|
||||||
|
|
||||||
if (!n || n->is_root()) return nullptr;
|
if (!n || n->is_root()) return nullptr;
|
||||||
|
|
||||||
auto up = n->parent();
|
auto up = n->parent();
|
||||||
while (nullptr != up) {
|
while (nullptr != up) {
|
||||||
|
|
||||||
if (nullptr != next_sibling(up))
|
if (nullptr != next_sibling(orthtree, up))
|
||||||
return next_sibling(up);
|
return next_sibling(orthtree, up);
|
||||||
|
|
||||||
if (up->is_root()) return nullptr;
|
if (up->is_root()) return nullptr;
|
||||||
|
|
||||||
|
|
@ -74,41 +77,42 @@ const Node* next_sibling_up(const Node* n) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Tree>
|
||||||
const Node* deepest_first_child(const Node* n) {
|
const typename Tree::Node* deepest_first_child(const Tree &orthtree, const typename Tree::Node* n) {
|
||||||
|
|
||||||
if (!n)
|
if (n == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Find the deepest child on the left
|
// Find the deepest child on the left
|
||||||
auto first = n;
|
auto first = n;
|
||||||
while (!first->is_leaf())
|
while (!first->is_leaf())
|
||||||
first = &(*first)[0];
|
first = &orthtree.children(*first)[0];
|
||||||
return first;
|
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)
|
if (!n)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
std::stack<const Node*> todo;
|
std::stack<const typename Tree::Node*> todo;
|
||||||
todo.push(n);
|
todo.push(n);
|
||||||
|
|
||||||
if (n->depth() == depth)
|
if (n->depth() == depth)
|
||||||
return n;
|
return n;
|
||||||
|
|
||||||
while (!todo.empty()) {
|
while (!todo.empty()) {
|
||||||
const Node* node = todo.top();
|
const typename Tree::Node* node = todo.top();
|
||||||
todo.pop();
|
todo.pop();
|
||||||
|
|
||||||
if (node->depth() == depth)
|
if (node->depth() == depth)
|
||||||
return node;
|
return node;
|
||||||
|
|
||||||
if (!node->is_leaf())
|
if (!node->is_leaf())
|
||||||
for (int i = 0; i < Node::Degree::value; ++i)
|
for (int i = 0; i < Tree::Node::Degree::value; ++i)
|
||||||
todo.push(&((*node)[std::size_t(Node::Degree::value - 1 - i)]));
|
todo.push(&((*node)[std::size_t(Tree::Node::Degree::value - 1 - i)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -124,23 +128,31 @@ const Node& first_child_at_depth(const Node* n, std::size_t depth) {
|
||||||
|
|
||||||
\cgalModels `OrthtreeTraversal`
|
\cgalModels `OrthtreeTraversal`
|
||||||
*/
|
*/
|
||||||
|
template <typename Tree>
|
||||||
struct Preorder_traversal {
|
struct Preorder_traversal {
|
||||||
|
private:
|
||||||
|
|
||||||
template <typename Node>
|
using Node = typename Tree::Node;
|
||||||
const Node* first(const Node* root) const {
|
|
||||||
return root;
|
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 {
|
const Node* next(const Node* n) const {
|
||||||
|
|
||||||
if (n->is_leaf()) {
|
if (n->is_leaf()) {
|
||||||
|
|
||||||
auto next = next_sibling(n);
|
auto next = next_sibling(m_orthtree, n);
|
||||||
|
|
||||||
if (nullptr == next) {
|
if (nullptr == next) {
|
||||||
|
|
||||||
return next_sibling_up(n);
|
return next_sibling_up(m_orthtree, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|
@ -148,7 +160,7 @@ struct Preorder_traversal {
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Return the first child of this node
|
// 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`
|
\cgalModels `OrthtreeTraversal`
|
||||||
*/
|
*/
|
||||||
|
template <typename Tree>
|
||||||
struct Postorder_traversal {
|
struct Postorder_traversal {
|
||||||
|
private:
|
||||||
|
|
||||||
template <typename Node>
|
using Node = typename Tree::Node;
|
||||||
const Node* first(const Node* root) const {
|
|
||||||
|
|
||||||
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 {
|
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)
|
if (!next)
|
||||||
next = n->parent();
|
next = n->parent();
|
||||||
|
|
@ -190,21 +209,28 @@ struct Postorder_traversal {
|
||||||
|
|
||||||
\cgalModels `OrthtreeTraversal`
|
\cgalModels `OrthtreeTraversal`
|
||||||
*/
|
*/
|
||||||
|
template <typename Tree>
|
||||||
struct Leaves_traversal {
|
struct Leaves_traversal {
|
||||||
|
private:
|
||||||
|
|
||||||
template <typename Node>
|
using Node = typename Tree::Node;
|
||||||
const Node* first(const Node* root) const {
|
|
||||||
|
|
||||||
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 {
|
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)
|
if (!next)
|
||||||
next = deepest_first_child(next_sibling_up(n));
|
next = deepest_first_child(m_orthtree, next_sibling_up(m_orthtree, n));
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
@ -219,38 +245,39 @@ struct Leaves_traversal {
|
||||||
|
|
||||||
\cgalModels `OrthtreeTraversal`
|
\cgalModels `OrthtreeTraversal`
|
||||||
*/
|
*/
|
||||||
|
template <typename Tree>
|
||||||
struct Level_traversal {
|
struct Level_traversal {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
const std::size_t depth;
|
using Node = typename Tree::Node;
|
||||||
|
|
||||||
|
const Tree& m_orthtree;
|
||||||
|
const std::size_t m_depth;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
constructs a `depth`-level traversal.
|
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>
|
template <typename Node>
|
||||||
const Node* first(const Node* root) const {
|
const Node* first() const {
|
||||||
return first_child_at_depth(root, depth);
|
return first_child_at_depth(m_orthtree, m_orthtree.root(), m_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Node>
|
template <typename Node>
|
||||||
const Node* next(const Node* n) const {
|
const Node* next(const Node* n) const {
|
||||||
// fixme: leftover from debugging?
|
const Node* next = next_sibling(m_orthtree, n);
|
||||||
std::cerr << depth << " ";
|
|
||||||
const Node* next = next_sibling(n);
|
|
||||||
|
|
||||||
if (!next) {
|
if (!next) {
|
||||||
const Node* up = n;
|
const Node* up = n;
|
||||||
do {
|
do {
|
||||||
up = next_sibling_up(up);
|
up = next_sibling_up(m_orthtree, up);
|
||||||
if (!up)
|
if (!up)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
next = first_child_at_depth(up, depth);
|
next = first_child_at_depth(m_orthtree, up, m_depth);
|
||||||
} while (!next);
|
} while (!next);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,36 +42,39 @@ int main(void) {
|
||||||
std::cout << octree << std::endl;
|
std::cout << octree << std::endl;
|
||||||
|
|
||||||
// Root node should have no siblings
|
// Root node should have no siblings
|
||||||
assert(octree.root().adjacent_node(0) == nullptr);
|
assert(octree.adjacent_node(octree.root(), 0) == nullptr);
|
||||||
assert(octree.root().adjacent_node(1) == nullptr);
|
assert(octree.adjacent_node(octree.root(), 1) == nullptr);
|
||||||
assert(octree.root().adjacent_node(2) == nullptr);
|
assert(octree.adjacent_node(octree.root(), 2) == nullptr);
|
||||||
assert(octree.root().adjacent_node(3) == nullptr);
|
assert(octree.adjacent_node(octree.root(), 3) == nullptr);
|
||||||
assert(octree.root().adjacent_node(4) == nullptr);
|
assert(octree.adjacent_node(octree.root(), 4) == nullptr);
|
||||||
assert(octree.root().adjacent_node(5) == nullptr);
|
assert(octree.adjacent_node(octree.root(), 5) == nullptr);
|
||||||
|
|
||||||
// Left Top Front node should have siblings to the Right, Down, and Back
|
// 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.children(octree.root())[Traits::RIGHT_TOP_BACK] == octree.adjacent_node(left_top_back, Traits::RIGHT));
|
||||||
assert(&octree.root()[Traits::LEFT_BOTTOM_BACK] == left_top_back.adjacent_node(Traits::DOWN));
|
assert(
|
||||||
assert(&octree.root()[Traits::LEFT_TOP_FRONT] == left_top_back.adjacent_node(Traits::FRONT));
|
&octree.children(octree.root())[Traits::LEFT_BOTTOM_BACK] == octree.adjacent_node(left_top_back, Traits::DOWN));
|
||||||
assert(left_top_back.adjacent_node(Traits::LEFT) == nullptr);
|
assert(&octree.children(octree.root())[Traits::LEFT_TOP_FRONT] == octree.adjacent_node(left_top_back, Traits::FRONT));
|
||||||
assert(left_top_back.adjacent_node(Traits::UP) == nullptr);
|
assert(octree.adjacent_node(left_top_back, Traits::LEFT) == nullptr);
|
||||||
assert(left_top_back.adjacent_node(Traits::BACK) == 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];
|
auto right_top_back_of_left_bottom_back =
|
||||||
assert(&octree.root()[Traits::LEFT_BOTTOM_BACK][Traits::LEFT_TOP_BACK] ==
|
octree.children(octree.children(octree.root())[Traits::LEFT_BOTTOM_BACK])[Traits::RIGHT_TOP_BACK];
|
||||||
right_top_back_of_left_bottom_back.adjacent_node(Traits::LEFT));
|
assert(&octree.children(octree.children(octree.root())[Traits::LEFT_BOTTOM_BACK])[Traits::LEFT_TOP_BACK] ==
|
||||||
assert(&octree.root()[Traits::RIGHT_BOTTOM_BACK] == right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT));
|
octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::LEFT));
|
||||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::RIGHT) != nullptr);
|
assert(&octree.children(octree.root())[Traits::RIGHT_BOTTOM_BACK] ==
|
||||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::UP) != nullptr);
|
octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::RIGHT));
|
||||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::DOWN) != nullptr);
|
assert(octree.adjacent_node(right_top_back_of_left_bottom_back, Traits::RIGHT) != nullptr);
|
||||||
assert(right_top_back_of_left_bottom_back.adjacent_node(Traits::FRONT) != 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
|
// 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ typedef CGAL::Simple_cartesian<double> Kernel;
|
||||||
typedef Kernel::Point_3 Point;
|
typedef Kernel::Point_3 Point;
|
||||||
typedef CGAL::Point_set_3<Point> Point_set;
|
typedef CGAL::Point_set_3<Point> Point_set;
|
||||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||||
Octree;
|
Octree;
|
||||||
|
|
||||||
int main(void) {
|
int main(void) {
|
||||||
|
|
||||||
|
|
@ -38,9 +38,10 @@ int main(void) {
|
||||||
octree.refine(10, 1);
|
octree.refine(10, 1);
|
||||||
|
|
||||||
std::cout << "root: " << octree.root().local_coordinates() << std::endl;
|
std::cout << "root: " << octree.root().local_coordinates() << std::endl;
|
||||||
std::cout << "first child: " << octree.root()[0].local_coordinates() << std::endl;
|
std::cout << "first child: " << octree.children(octree.root())[0].local_coordinates() << std::endl;
|
||||||
std::cout << "fifth child: " << octree.root()[4].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.root()[0][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
|
// TODO
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ typedef Kernel::Point_3 Point;
|
||||||
typedef Kernel::FT FT;
|
typedef Kernel::FT FT;
|
||||||
typedef CGAL::Point_set_3<Point> Point_set;
|
typedef CGAL::Point_set_3<Point> Point_set;
|
||||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||||
Octree;
|
Octree;
|
||||||
|
|
||||||
void test_1_node() {
|
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));
|
assert(octree.bbox(octree.root()) == CGAL::Bbox_3(-1.1, -1.1, -1.1, 1.1, 1.1, 1.1));
|
||||||
|
|
||||||
// Compare the child nodes
|
// 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.children(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.children(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.children(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.children(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.children(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.children(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.children(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())[7]) == CGAL::Bbox_3(0, 0, 0, 1.1, 1.1, 1.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_25_nodes() {
|
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));
|
assert(octree.bbox(octree.root()) == CGAL::Bbox_3(-1.5, -1.5, -1.5, 1.5, 1.5, 1.5));
|
||||||
|
|
||||||
// Compare the child nodes
|
// 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.children(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.children(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.children(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.children(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.children(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.children(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.children(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())[7]) == CGAL::Bbox_3(0, 0, 0, 1.5, 1.5, 1.5));
|
||||||
|
|
||||||
// Compare children of the first child
|
// 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.children(octree.children(octree.root())[0])[0]) ==
|
||||||
assert(octree.bbox(octree.root()[0][1]) == CGAL::Bbox_3(-0.75, -1.5, -1.5, 0, -0.75, -0.75));
|
CGAL::Bbox_3(-1.5, -1.5, -1.5, -0.75, -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.children(octree.children(octree.root())[0])[1]) ==
|
||||||
assert(octree.bbox(octree.root()[0][3]) == CGAL::Bbox_3(-0.75, -0.75, -1.5, 0, 0, -0.75));
|
CGAL::Bbox_3(-0.75, -1.5, -1.5, 0, -0.75, -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.children(octree.children(octree.root())[0])[2]) ==
|
||||||
assert(octree.bbox(octree.root()[0][5]) == CGAL::Bbox_3(-0.75, -1.5, -0.75, 0, -0.75, 0));
|
CGAL::Bbox_3(-1.5, -0.75, -1.5, -0.75, 0, -0.75));
|
||||||
assert(octree.bbox(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])[3]) ==
|
||||||
assert(octree.bbox(octree.root()[0][7]) == CGAL::Bbox_3(-0.75, -0.75, -0.75, 0, 0, 0));
|
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
|
// 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.children(octree.children(octree.root())[7])[0]) ==
|
||||||
assert(octree.bbox(octree.root()[7][1]) == CGAL::Bbox_3(0.75, 0, 0, 1.5, 0.75, 0.75));
|
CGAL::Bbox_3(0, 0, 0, 0.75, 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.children(octree.children(octree.root())[7])[1]) ==
|
||||||
assert(octree.bbox(octree.root()[7][3]) == CGAL::Bbox_3(0.75, 0.75, 0, 1.5, 1.5, 0.75));
|
CGAL::Bbox_3(0.75, 0, 0, 1.5, 0.75, 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.children(octree.children(octree.root())[7])[2]) ==
|
||||||
assert(octree.bbox(octree.root()[7][5]) == CGAL::Bbox_3(0.75, 0, 0.75, 1.5, 0.75, 1.5));
|
CGAL::Bbox_3(0, 0.75, 0, 0.75, 1.5, 0.75));
|
||||||
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.children(octree.children(octree.root())[7])[3]) ==
|
||||||
assert(octree.bbox(octree.root()[7][7]) == CGAL::Bbox_3(0.75, 0.75, 0.75, 1.5, 1.5, 1.5));
|
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) {
|
int main(void) {
|
||||||
|
|
|
||||||
|
|
@ -15,17 +15,17 @@ typedef Kernel::Point_3 Point;
|
||||||
typedef Kernel::FT FT;
|
typedef Kernel::FT FT;
|
||||||
typedef CGAL::Point_set_3<Point> Point_set;
|
typedef CGAL::Point_set_3<Point> Point_set;
|
||||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map> Octree;
|
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 count_jumps(Octree &octree) {
|
||||||
|
|
||||||
std::size_t jumps = 0;
|
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) {
|
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)
|
if (adjacent_node == nullptr)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ int main(void) {
|
||||||
auto query = Point{1, 1, 1};
|
auto query = Point{1, 1, 1};
|
||||||
|
|
||||||
// Get a list of nodes intersected
|
// 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));
|
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||||
|
|
||||||
// A point should only intersect one node
|
// 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);
|
auto query = Kernel::Sphere_3(Point{1, 0.5, 1}, 1.0);
|
||||||
|
|
||||||
// Get a list of nodes intersected
|
// 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));
|
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||||
|
|
||||||
// Check the results
|
// Check the results
|
||||||
assert(4 == nodes.size());
|
assert(4 == nodes.size());
|
||||||
assert(octree.root()[Octree::Traits::RIGHT_TOP_BACK] == *nodes[0]);
|
assert(octree.children(octree.root())[Octree::Traits::RIGHT_TOP_BACK] == *nodes[0]);
|
||||||
assert(octree.root()[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[1]);
|
assert(octree.children(octree.root())[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[1]);
|
||||||
assert(octree.root()[Octree::Traits::LEFT_TOP_FRONT] == *nodes[2]);
|
assert(octree.children(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_FRONT] == *nodes[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersection with a ray
|
// Intersection with a ray
|
||||||
|
|
@ -81,19 +81,22 @@ int main(void) {
|
||||||
auto query = Kernel::Ray_3(Point{1, 1, 1}, Point{0, 0, 0});
|
auto query = Kernel::Ray_3(Point{1, 1, 1}, Point{0, 0, 0});
|
||||||
|
|
||||||
// Get a list of nodes intersected
|
// 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));
|
octree.intersected_nodes(query, std::back_inserter(nodes));
|
||||||
|
|
||||||
// Check the results
|
// Check the results
|
||||||
assert(8 == nodes.size());
|
assert(8 == nodes.size());
|
||||||
assert(octree.root()[Octree::Traits::LEFT_BOTTOM_BACK] == *nodes[0]);
|
assert(octree.children(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(
|
||||||
assert(octree.root()[Octree::Traits::LEFT_TOP_BACK] == *nodes[2]);
|
octree.children(octree.children(octree.root())[Octree::Traits::RIGHT_BOTTOM_BACK])[Octree::Traits::LEFT_TOP_FRONT]
|
||||||
assert(octree.root()[Octree::Traits::RIGHT_TOP_BACK] == *nodes[3]);
|
== *nodes[1]
|
||||||
assert(octree.root()[Octree::Traits::LEFT_BOTTOM_FRONT] == *nodes[4]);
|
);
|
||||||
assert(octree.root()[Octree::Traits::RIGHT_BOTTOM_FRONT] == *nodes[5]);
|
assert(octree.children(octree.root())[Octree::Traits::LEFT_TOP_BACK] == *nodes[2]);
|
||||||
assert(octree.root()[Octree::Traits::LEFT_TOP_FRONT] == *nodes[6]);
|
assert(octree.children(octree.root())[Octree::Traits::RIGHT_TOP_BACK] == *nodes[3]);
|
||||||
assert(octree.root()[Octree::Traits::RIGHT_TOP_FRONT] == *nodes[7]);
|
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;
|
return EXIT_SUCCESS;
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ typedef Kernel::Point_3 Point;
|
||||||
typedef Kernel::FT FT;
|
typedef Kernel::FT FT;
|
||||||
typedef CGAL::Point_set_3<Point> Point_set;
|
typedef CGAL::Point_set_3<Point> Point_set;
|
||||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map>
|
||||||
Octree;
|
Octree;
|
||||||
|
|
||||||
void test_1_point() {
|
void test_1_point() {
|
||||||
|
|
||||||
|
|
@ -52,24 +52,24 @@ void test_8_points() {
|
||||||
octree.refine(10, 1);
|
octree.refine(10, 1);
|
||||||
|
|
||||||
// Existing points should end up in the same place
|
// Existing points should end up in the same place
|
||||||
assert(octree.root()[0] == octree.locate({-1, -1, -1}));
|
assert(octree.children(octree.root())[0] == octree.locate({-1, -1, -1}));
|
||||||
assert(octree.root()[1] == octree.locate({1, -1, -1}));
|
assert(octree.children(octree.root())[1] == octree.locate({1, -1, -1}));
|
||||||
assert(octree.root()[2] == octree.locate({-1, 1, -1}));
|
assert(octree.children(octree.root())[2] == octree.locate({-1, 1, -1}));
|
||||||
assert(octree.root()[3] == octree.locate({1, 1, -1}));
|
assert(octree.children(octree.root())[3] == octree.locate({1, 1, -1}));
|
||||||
assert(octree.root()[4] == octree.locate({-1, -1, 1}));
|
assert(octree.children(octree.root())[4] == octree.locate({-1, -1, 1}));
|
||||||
assert(octree.root()[5] == octree.locate({1, -1, 1}));
|
assert(octree.children(octree.root())[5] == octree.locate({1, -1, 1}));
|
||||||
assert(octree.root()[6] == octree.locate({-1, 1, 1}));
|
assert(octree.children(octree.root())[6] == octree.locate({-1, 1, 1}));
|
||||||
assert(octree.root()[7] == 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
|
// 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.children(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.children(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.children(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.children(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.children(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.children(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.children(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())[7] == octree.locate({1.1, 1.1, 1.1}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,24 +93,24 @@ void test_10_points() {
|
||||||
octree.refine(10, 1);
|
octree.refine(10, 1);
|
||||||
|
|
||||||
// Existing points should end up in the same place
|
// Existing points should end up in the same place
|
||||||
assert(octree.root()[0] == octree.locate({-1, -1, -1}));
|
assert(octree.children(octree.root())[0] == octree.locate({-1, -1, -1}));
|
||||||
assert(octree.root()[1] == octree.locate({1, -1, -1}));
|
assert(octree.children(octree.root())[1] == octree.locate({1, -1, -1}));
|
||||||
assert(octree.root()[2] == octree.locate({-1, 1, -1}));
|
assert(octree.children(octree.root())[2] == octree.locate({-1, 1, -1}));
|
||||||
assert(octree.root()[3][3][3] == octree.locate({1, 1, -1}));
|
assert(octree.children(octree.children(octree.children(octree.root())[3])[3])[3] == octree.locate({1, 1, -1}));
|
||||||
assert(octree.root()[4][4][4] == octree.locate({-1, -1, 1}));
|
assert(octree.children(octree.children(octree.children(octree.root())[4])[4])[4] == octree.locate({-1, -1, 1}));
|
||||||
assert(octree.root()[5] == octree.locate({1, -1, 1}));
|
assert(octree.children(octree.root())[5] == octree.locate({1, -1, 1}));
|
||||||
assert(octree.root()[6] == octree.locate({-1, 1, 1}));
|
assert(octree.children(octree.root())[6] == octree.locate({-1, 1, 1}));
|
||||||
assert(octree.root()[7] == 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
|
// 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.children(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.children(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.children(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.children(octree.children(octree.children(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.children(octree.children(octree.children(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.children(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.children(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())[7] == octree.locate({1.1, 1.1, 1.1}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ void test_2_points() {
|
||||||
// The octree should have been split once
|
// The octree should have been split once
|
||||||
Octree other(points, points.point_map());
|
Octree other(points, points.point_map());
|
||||||
other.split(other.root());
|
other.split(other.root());
|
||||||
assert(Node::is_topology_equal(other.root(), octree.root()));
|
assert(Octree::is_topology_equal(other, octree));
|
||||||
assert(1 == octree.depth());
|
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
|
// The octree should have been split once on the first level, and twice on the second
|
||||||
Octree other(points, points.point_map());
|
Octree other(points, points.point_map());
|
||||||
other.split(other.root());
|
other.split(other.root());
|
||||||
other.split(other.root()[3]);
|
other.split(other.children(other.root())[3]);
|
||||||
other.split(other.root()[7]);
|
other.split(other.children(other.root())[7]);
|
||||||
assert(Node::is_topology_equal(other.root(), octree.root()));
|
assert(Octree::is_topology_equal(other, octree));
|
||||||
assert(2 == octree.depth());
|
assert(2 == octree.depth());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ typedef CGAL::Simple_cartesian<double> Kernel;
|
||||||
typedef Kernel::Point_3 Point;
|
typedef Kernel::Point_3 Point;
|
||||||
typedef CGAL::Point_set_3<Point> Point_set;
|
typedef CGAL::Point_set_3<Point> Point_set;
|
||||||
typedef CGAL::Octree<Kernel, Point_set, typename Point_set::Point_map> Octree;
|
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() {
|
bool test_preorder_1_node() {
|
||||||
|
|
||||||
|
|
@ -53,7 +53,7 @@ bool test_preorder_9_nodes() {
|
||||||
assert(*iter == octree.root());
|
assert(*iter == octree.root());
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[i]));
|
assert((*iter == octree.children(octree.root())[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -79,28 +79,28 @@ bool test_preorder_25_nodes() {
|
||||||
auto iter = nodes.begin();
|
auto iter = nodes.begin();
|
||||||
assert(*iter == octree.root());
|
assert(*iter == octree.root());
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[0]));
|
assert((*iter == octree.children(octree.root())[0]));
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[1]));
|
assert((*iter == octree.children(octree.root())[1]));
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[2]));
|
assert((*iter == octree.children(octree.root())[2]));
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[3]));
|
assert((*iter == octree.children(octree.root())[3]));
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[3][i]));
|
assert((*iter == octree.children(octree.children(octree.root())[3])[i]));
|
||||||
}
|
}
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[4]));
|
assert((*iter == octree.children(octree.root())[4]));
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[5]));
|
assert((*iter == octree.children(octree.root())[5]));
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[6]));
|
assert((*iter == octree.children(octree.root())[6]));
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[7]));
|
assert((*iter == octree.children(octree.root())[7]));
|
||||||
for (int i = 0; i < 8; ++i) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
iter++;
|
iter++;
|
||||||
assert((*iter == octree.root()[7][i]));
|
assert((*iter == octree.children(octree.children(octree.root())[7])[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue