/*
* Copyright (C) 2007 Simon Perreault
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "octree.h"
/**
* \class Octree
* \brief Generic octree template
*
* \author Simon Perreault
* \date April 2007
*
* This class template represents an octree, often used for manipulating 3-D
* scattered data efficiently. The type of the contained data is supplied as a
* template parameter.
*
* \param T Type of the contained data. Requirements on type: must be copyable
* and default-constructible.
*
* \param AS Short for "aggregate size." As an optimization, leaves can be
* aggregated so that the relative size of pointers is diminished. This is 1 by
* default, but should be set higher when the size of \a T is small. Must be
* a power of two.
*/
/**
* \param size Size of octree, in nodes. Should be a power of two. For example,
* an octree with \a size = 256 will represent a cube divided into 256x256x256
* nodes. Must be a power of two.
*
* \param emptyValue This is the value that will be returned when accessing
* regions of the 3-D volume where no node has been allocated. In other words,
* instead of following a null node pointer, this value is returned. Since the
* octree root is initially a null pointer, the whole volume is initialized to
* this value.
*/
template< typename T, int AS >
Octree::Octree( int size, const T& emptyValue )
: root_(0)
, emptyValue_(emptyValue)
, size_(size)
{
// Make sure size is power of two.
assert( ((size - 1) & size) == 0 );
assert( ((AS - 1) & AS) == 0 );
}
/**
* Performs a deep copy of an octree. All branch pointers will be followed
* recursively and new nodes will be allocated.
*
* \param o Octree to be copied.
*/
template< typename T, int AS >
Octree::Octree( const Octree& o )
: emptyValue_( o.emptyValue_ )
, size_( o.size_ )
{
if ( !o.root_ ) {
root_ = 0;
} else {
switch ( o.root_->type() ) {
case BranchNode:
root_ = new Branch ( *reinterpret_cast(o.root_) );
break;
case LeafNode:
root_ = new Leaf ( *reinterpret_cast(o.root_) );
break;
case AggregateNode:
root_ = new Aggregate( *reinterpret_cast(o.root_) );
break;
}
}
}
/**
* Recursively deletes all nodes by following branch pointers.
*/
template< typename T, int AS >
Octree::~Octree()
{
deleteNode(&root_);
}
/**
* Swaps the octree's contents with another's. This is a cheap operation as only
* the root pointers are swapped, not the whole structure.
*/
template< typename T, int AS >
void Octree::swap( Octree& o )
{
std::swap( emptyValue_, o.emptyValue_ ); // This can throw.
// These can't.
std::swap( root_, o.root_ );
std::swap( size_, o.size_ );
}
/**
* Assigns to this octree the contents of octree \a o.
*/
template< typename T, int AS >
Octree& Octree::operator= ( Octree o )
{
swap(o);
return *this;
}
/**
* \return Size of octree, in nodes, as specified in the constructor.
*/
template< typename T, int AS >
int Octree::size() const
{
return size_;
}
/**
* \return Value of empty nodes, as specified in the constructor.
* \see setEmptyValue()
*/
template< typename T, int AS >
const T& Octree::emptyValue() const
{
return emptyValue_;
}
/**
* Sets the value of empty nodes to \a emptyValue.
* \see setEmptyValue()
*/
template< typename T, int AS >
void Octree::setEmptyValue( const T& emptyValue )
{
emptyValue_ = emptyValue;
}
/**
* Deletes a node polymorphically. If the node is a branch node, it will delete
* all its subtree recursively.
*/
template< typename T, int AS >
void Octree::deleteNode( Node** node )
{
assert(node);
if (*node) {
if ( (*node)->type() == BranchNode ) {
delete reinterpret_cast(*node);
}
else if ( (*node)->type() == AggregateNode ) {
delete reinterpret_cast(*node);
}
else {
assert( (*node)->type() == LeafNode );
delete reinterpret_cast(*node);
}
*node = 0;
}
}
/**
* \return Pointer to octree's root node.
*/
template< typename T, int AS >
typename Octree::Node*& Octree::root()
{
return root_;
}
/**
* Const version of above.
*/
template< typename T, int AS >
const typename Octree::Node* Octree::root() const
{
return root_;
}
/**
* \return Value at index (\a x,\a y,\a z). If no node exists at this index, the
* value returned by emptyValue() is returned.
*
* \remarks Memory access is faster when \a x varies the quickest, followed by
* \a y and then by \a z. Therefore you should write nested loops in this order
* for faster access:
*
* \code
* for ( int z = 0; z < ...; ++z ) {
* for ( int y = 0; y < ...; ++y ) {
* for ( int x = 0; x < ...; ++x ) {
* ... = octree.at(x,y,z);
* }
* }
* }
* \endcode
*
* However, zSlice() provides an even faster way.
*/
template< typename T, int AS >
const T& Octree::at( int x, int y, int z ) const
{
assert( x >= 0 && x < size_ );
assert( y >= 0 && y < size_ );
assert( z >= 0 && z < size_ );
Node* n = root_;
int size = size_;
while ( size != aggregateSize_ ) {
if (!n) {
return emptyValue_;
}
else if ( n->type() == BranchNode ) {
size /= 2;
n = reinterpret_cast(n)->child(
!!(x & size), !!(y & size), !!(z & size) );
}
else {
assert( n->type() == LeafNode );
return reinterpret_cast(n)->value();
}
}
if (!n) {
return emptyValue_;
}
--size;
return reinterpret_cast(n)->value(
x & size, y & size, z & size );
}
/**
* Synonym of at().
*/
template< typename T, int AS >
const T& Octree::operator() ( int x, int y, int z ) const
{
return at(x,y,z);
}
/**
* \return Reference to value at index (\a x,\a y,\a z). If no node exists at
* this index, a new one is created (along with the necessary ancestry),
* initialized to the value returned by emptyValue(), and returned.
*
* \remarks Be careful when calling this function. If you do not want to
* inadvertently create new nodes, use the at() function.
*
* \see at()
*/
template< typename T, int AS >
T& Octree::operator() ( int x, int y, int z )
{
assert( x >= 0 && x < size_ );
assert( y >= 0 && y < size_ );
assert( z >= 0 && z < size_ );
Node** n = &root_;
int size = size_;
while ( size != aggregateSize_ ) {
if (!*n) {
*n = new Branch;
}
else if ( (*n)->type() == BranchNode ) {
size /= 2;
n = &reinterpret_cast(*n)->child(
!!(x & size), !!(y & size), !!(z & size) );
}
else {
return reinterpret_cast(*n)->value();
}
}
if (!*n) {
*n = new Aggregate(emptyValue_);
}
--size;
return reinterpret_cast(*n)->value(
x & size, y & size, z & size );
}
/**
* Sets the value of the node at (\a x, \a y, \a z) to \a value. If \a value is
* the empty value, the node is erased. Otherwise, the node is created if it did
* not already exist and its value is set to \a value.
*/
template< typename T, int AS >
void Octree::set( int x, int y, int z, const T& value )
{
if ( value != emptyValue() ) {
(*this)(x,y,z) = value;
}
else {
erase(x,y,z);
}
}
/**
* Erases the node at index (\a x,\a y,\a z). After the call,
* at(x,y,z)
will return the value returned by emptyValue().
*
* This function will free as much memory as possible. For example, when erasing
* the single child of a branch node, the branch node itself will be erased and
* replaced by a null pointer in its parent. This will percolate to the top of
* the tree if necessary.
*/
template< typename T, int AS >
void Octree::erase( int x, int y, int z )
{
assert( x >= 0 && x < size_ );
assert( y >= 0 && y < size_ );
assert( z >= 0 && z < size_ );
eraseRecursive( &root_, size_, x, y, z );
}
/**
* Helper function for erase() method.
*/
template< typename T, int AS >
void Octree::eraseRecursive( Node** node, int size, int x, int y, int z )
{
assert(node);
if ( !*node ) {
return;
}
if ( size != aggregateSize_ ) {
if ( (*node)->type() == BranchNode ) {
size /= 2;
Branch* b = reinterpret_cast(*node);
eraseRecursive( &b->child(!!(x & size), !!(y & size), !!(z & size)),
size, x, y, z );
for ( int i = 0; i < 8; ++i ) {
if ( b->child(i) ) {
return;
}
}
deleteNode(node);
}
else if ( reinterpret_cast(*node)->value() == emptyValue_ ) {
deleteNode(node);
}
else {
Branch* b = new Branch;
size /= 2;
int childIndex = ( x & size ? 1 : 0 )
| ( y & size ? 2 : 0 )
| ( z & size ? 4 : 0 );
const T& value = reinterpret_cast(*node)->value();
try {
for ( int i = 0; i < 8; ++i ) {
if ( i == childIndex ) {
continue;
}
if ( size == aggregateSize_ ) {
b->child(i) = new Leaf(value);
}
else {
b->child(i) = new Aggregate(value);
}
}
}
catch (...) {
Node* bb = b;
deleteNode(&bb);
throw;
}
deleteNode(node);
*node = b;
node = &b->child(childIndex);
}
}
else {
--size;
Aggregate* a = reinterpret_cast(*node);
a->setValue( x & size, y & size, z & size, emptyValue_ );
for ( int i = 0; i < AS*AS*AS; ++i ) {
if ( a->value(i) != emptyValue_ ) {
return;
}
}
deleteNode(node);
}
}
/**
* \return Number of bytes a branch node occupies.
*/
template< typename T, int AS >
unsigned long Octree::branchBytes()
{
return sizeof(Branch);
}
/**
* \return Number of bytes an aggregate node occupies.
*/
template< typename T, int AS >
unsigned long Octree::aggregateBytes()
{
return sizeof(Aggregate);
}
/**
* \return Number of bytes a leaf node occupies.
*/
template< typename T, int AS >
unsigned long Octree::leafBytes()
{
return sizeof(Leaf);
}
/**
* \return Total number of nodes in the octree.
*/
template< typename T, int AS >
int Octree::nodes() const
{
return nodesRecursive(root_);
}
/**
* Helper function for nodes() method.
*/
template< typename T, int AS >
int Octree::nodesRecursive( const Node* node )
{
if ( !node ) {
return 0;
}
int n = 1;
if ( node->type() == BranchNode ) {
for ( int i = 0; i < 8; ++i ) {
n += nodesRecursive(
reinterpret_cast(node)->child(i) );
}
}
return n;
}
/**
* \return Total number of bytes the octree occupies.
*
* \remarks Memory fragmentation may make the actual memory usage significantly
* higher.
*/
template< typename T, int AS >
unsigned long Octree::bytes() const
{
return bytesRecursive(root_) + sizeof(*this);
}
/**
* Helper function for bytes() method.
*/
template< typename T, int AS >
unsigned long Octree::bytesRecursive( const Node* node )
{
if ( !node ) {
return 0;
}
unsigned long b = 0;
switch ( node->type() ) {
case BranchNode:
b = sizeof(Branch);
for ( int i = 0; i < 8; ++i ) {
b += bytesRecursive(
reinterpret_cast(node)->child(i) );
}
break;
case LeafNode:
b = sizeof(Leaf);
break;
case AggregateNode:
b = sizeof(Aggregate);
break;
}
return b;
}
/**
* \return Number of nodes of at size \a size. For example, the root (if
* allocated) is the single node of size 1. At size n there may be a
* maximum of 2n nodes.
*
* For sizes lower than the aggregate size, this function will always return
* zero.
*/
template< typename T, int AS >
int Octree::nodesAtSize( int size ) const
{
return nodesAtSizeRecursive( size, size_, root_ );
}
/**
* Helper function for nodesAtSize() method.
*/
template< typename T, int AS >
int Octree::nodesAtSizeRecursive( int targetSize, int size, Node* node )
{
if (node) {
if ( size == targetSize ) {
return 1;
}
if ( node->type() == BranchNode ) {
int sum = 0;
for ( int i = 0; i < 2; ++i ) {
for ( int j = 0; j < 2; ++j ) {
for ( int k = 0; k < 2; ++k ) {
sum += nodesAtSizeRecursive( targetSize, size/2,
reinterpret_cast(node)->child(k,j,i) );
}
}
}
return sum;
}
}
return 0;
}
template< typename T, int AS >
Octree::Node::Node( NodeType type )
: type_(type)
{
}
template< typename T, int AS >
typename Octree::NodeType Octree::Node::type() const
{
return type_;
}
template< typename T, int AS >
Octree::Branch::Branch()
: Node(BranchNode)
{
memset( children, 0, sizeof(children) );
}
template< typename T, int AS >
Octree::Branch::Branch( const Branch& b )
: Node(BranchNode)
{
for ( int i = 0; i < 8; ++i ) {
if ( b.child(i) ) {
switch ( b.child(i)->type() ) {
case BranchNode:
child(i) = new Branch(
*reinterpret_cast(b.child(i)) );
break;
case LeafNode:
child(i) = new Leaf(
*reinterpret_cast(b.child(i)) );
break;
case AggregateNode:
child(i) = new Aggregate(
*reinterpret_cast(b.child(i)) );
break;
}
}
else {
child(i) = 0;
}
}
}
template< typename T, int AS >
Octree::Branch::~Branch()
{
for ( int i = 0; i < 2; ++i ) {
for ( int j = 0; j < 2; ++j ) {
for ( int k = 0; k < 2; ++k ) {
assert( children[i][j][k] != this );
deleteNode( &children[i][j][k] );
}
}
}
}
template< typename T, int AS >
const typename Octree::Node* Octree::Branch::child(
int x, int y, int z ) const
{
assert( x == 0 || x == 1 );
assert( y == 0 || y == 1 );
assert( z == 0 || z == 1 );
return children[z][y][x];
}
template< typename T, int AS >
typename Octree::Node*& Octree::Branch::child( int x, int y, int z )
{
assert( x == 0 || x == 1 );
assert( y == 0 || y == 1 );
assert( z == 0 || z == 1 );
return children[z][y][x];
}
template< typename T, int AS >
const typename Octree::Node* Octree::Branch::child( int index )
const
{
assert( index >= 0 && index < 8 );
return *( &children[0][0][0] + index );
}
template< typename T, int AS >
typename Octree::Node*& Octree::Branch::child( int index )
{
assert( index >= 0 && index < 8 );
return *( &children[0][0][0] + index );
}
template< typename T, int AS >
Octree::Aggregate::Aggregate( const T& v )
: Node(AggregateNode)
{
for ( int i = 0; i < AS; ++i ) {
for ( int j = 0; j < AS; ++j ) {
for ( int k = 0; k < AS; ++k ) {
value_[i][j][k] = v;
}
}
}
}
template< typename T, int AS >
const T& Octree::Aggregate::value( int x, int y, int z ) const
{
assert( x >= 0 && x < AS );
assert( y >= 0 && y < AS );
assert( z >= 0 && z < AS );
return value_[z][y][x];
}
template< typename T, int AS >
T& Octree::Aggregate::value( int x, int y, int z )
{
assert( x >= 0 && x < AS );
assert( y >= 0 && y < AS );
assert( z >= 0 && z < AS );
return value_[z][y][x];
}
template< typename T, int AS >
void Octree::Aggregate::setValue( int x, int y, int z, const T& v )
{
assert( x >= 0 && x < AS );
assert( y >= 0 && y < AS );
assert( z >= 0 && z < AS );
value_[z][y][x] = v;
}
template< typename T, int AS >
const T& Octree::Aggregate::value( int i ) const
{
assert( i >= 0 && i < AS*AS*AS );
return *( &value_[0][0][0] + i );
}
template< typename T, int AS >
T& Octree::Aggregate::value( int i )
{
assert( i >= 0 && i < AS*AS*AS );
return *( &value_[0][0][0] + i );
}
template< typename T, int AS >
void Octree::Aggregate::setValue( int i, const T& v )
{
assert( i >= 0 && i < AS*AS*AS );
*( &value_[0][0][0] + i ) = v;
}
template< typename T, int AS >
Octree::Leaf::Leaf( const T& v )
: Node(LeafNode)
, value_(v)
{
}
template< typename T, int AS >
const T& Octree::Leaf::value() const
{
return value_;
}
template< typename T, int AS >
T& Octree::Leaf::value()
{
return value_;
}
template< typename T, int AS >
void Octree::Leaf::setValue( const T& v )
{
value_ = v;
}
/**
* \return A slice of the octree, perpendicular to the Z axis. The content of
* all nodes for which the Z index is \a z will be copied into the returned
* array. If no node exists for a given index, the value returned by
* emptyValue() will be written instead.
*
* \remarks This method ought to be relatively fast as long the the time
* required to copy values does not dwarf the time for indexing into the octree
* (this should be the case for built-in C++ types such as int and double).
* As a result, using this function is an easy way to accelerate the infamous
* three-level nested loops. For example:
*
* \code
* for ( int z = 0; z < ...; ++z ) {
* tmp = octree.zSlice(z);
* for ( int y = 0; y < ...; ++y ) {
* for ( int x = 0; x < ...; ++x ) {
* ... = tmp(y,x);
* }
* }
* }
* \endcode
*/
/*template< typename T, int AS >
Array2D Octree::zSlice( int z ) const
{
assert( z >= 0 && z < size_ );
Array2D slice( size_, size_ );
zSliceRecursive( slice, root_, size_, 0, 0, 0, z );
return slice;
}*/
/**
* Helper function for zSlice() method.
*/
/*template< typename T, int AS >
void Octree::zSliceRecursive( Array2D slice, const Node* node,
int size, int x, int y, int z, int targetZ ) const
{
if (!node) {
for ( int i = 0; i < slice.M(); ++i ) {
for ( int j = 0; j < slice.N(); ++j ) {
slice(i,j) = emptyValue_;
}
}
}
else if ( node->type() == BranchNode ) {
size /= 2;
for ( int i = 0; i < 2; ++i ) {
for ( int j = 0; j < 2; ++j ) {
zSliceRecursive( slice.subarray( i*size, j*size,
(i+1)*size, (j+1)*size),
reinterpret_cast(node)->child(
j, i, !!(targetZ & size)),
size, x, y, z, targetZ );
}
}
}
else if ( node->type() == AggregateNode ) {
for ( int i = 0; i < slice.M(); ++i ) {
for ( int j = 0; j < slice.N(); ++j ) {
slice(i,j) = reinterpret_cast(node)->value(
j, i, targetZ - z & (size-1) );
}
}
}
else {
assert( node->type() == LeafNode );
for ( int i = 0; i < slice.M(); ++i ) {
for ( int j = 0; j < slice.N(); ++j ) {
slice(i,j) = reinterpret_cast(node)->value();
}
}
}
}*/
/**
* Writes the octree in binary form to the output stream \a out. This should be
* fast, but note that the type \a T will be written as it appears in memory.
* That is, if it is a complex type containing pointers, the pointer addresses
* will be written instead of the data pointed at. For complex types, you should
* roll your own function.
*/
/*template< typename T, int AS >
void Octree::writeBinary( std::ostream& out ) const
{
if ( !root_ ) {
static const char zero = 0;
out.write( &zero, 1 );
}
else {
static const char one = 1;
out.write( &one, 1 );
writeBinaryRecursive( out, root() );
}
out.write( reinterpret_cast(&emptyValue_), sizeof(T) );
out.write( reinterpret_cast(&size_), sizeof(int) );
}
template< typename T, int AS >
void Octree::writeBinaryRecursive( std::ostream& out, const Node* node )
{
assert(node);
if ( !out.good() ) {
return;
}
char type = node->type();
out.write( &type, 1 );
switch (type) {
case BranchNode:
{
const Branch* b = reinterpret_cast(node);
char children = 0;
for ( int i = 0; i < 8; ++i ) {
children |= ( b->child(i) != 0 ) << i;
}
out.write( &children, 1 );
for ( int i = 0; i < 8; ++i ) {
if ( b->child(i) ) {
writeBinaryRecursive( out, b->child(i) );
}
}
}
break;
case AggregateNode:
out.write( reinterpret_cast(
&reinterpret_cast(node)->value(0,0,0)
),
AS*AS*AS*sizeof(T) );
break;
case LeafNode:
out.write( reinterpret_cast(
&reinterpret_cast(node)->value()
),
sizeof(T) );
break;
}
}*/
/**
* Reads the octree from \a in. It must previously have been written using
* writeBinary().
*/
/*template< typename T, int AS >
void Octree::readBinary( std::istream& in )
{
Octree tmp(0);
char root;
in.read( &root, 1 );
if (root) {
readBinaryRecursive( in, &tmp.root_ );
}
in.read( reinterpret_cast(&tmp.emptyValue_), sizeof(T) );
in.read( reinterpret_cast(&tmp.size_), sizeof(int) );
if ( in.good() ) {
swap(tmp);
}
}
template< typename T, int AS >
void Octree::readBinaryRecursive( std::istream& in, Node** node )
{
assert(node);
if ( !in.good() ) {
return;
}
char type;
in.read( &type, 1 );
switch (type) {
case BranchNode:
{
Branch* b = new Branch;
*node = b;
char children;
in.read( &children, 1 );
for ( int i = 0; i < 8; ++i ) {
if ( children & (1 << i) ) {
readBinaryRecursive( in, &b->child(i) );
}
}
}
break;
case AggregateNode:
{
Aggregate* a = new Aggregate( T(0) );
*node = a;
in.read( reinterpret_cast(&a->value(0,0,0)),
AS*AS*AS*sizeof(T) );
}
break;
case LeafNode:
{
Leaf* l = new Leaf( T(0) );
*node = l;
in.read( reinterpret_cast(&l->value()), sizeof(T) );
}
break;
}
}*/