Files
tenmon/3rdparty/include/pcl/QuadTree.h
T
2022-04-12 08:17:18 +02:00

1454 lines
45 KiB
C++

// ____ ______ __
// / __ \ / ____// /
// / /_/ // / / /
// / ____// /___ / /___ PixInsight Class Library
// /_/ \____//_____/ PCL 2.4.23
// ----------------------------------------------------------------------------
// pcl/QuadTree.h - Released 2022-03-12T18:59:29Z
// ----------------------------------------------------------------------------
// This file is part of the PixInsight Class Library (PCL).
// PCL is a multiplatform C++ framework for development of PixInsight modules.
//
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
//
// Redistribution and use in both source and binary forms, with or without
// modification, is permitted provided that the following conditions are met:
//
// 1. All redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. All redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
// of their contributors, may be used to endorse or promote products derived
// from this software without specific prior written permission. For written
// permission, please contact info@pixinsight.com.
//
// 4. All products derived from this software, in any form whatsoever, must
// reproduce the following acknowledgment in the end-user documentation
// and/or other materials provided with the product:
//
// "This product is based on software from the PixInsight project, developed
// by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
//
// Alternatively, if that is where third-party acknowledgments normally
// appear, this acknowledgment must be reproduced in the product itself.
//
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
// ----------------------------------------------------------------------------
#ifndef __PCL_QuadTree_h
#define __PCL_QuadTree_h
/// \file pcl/QuadTree.h
#include <pcl/Defs.h>
#include <pcl/Array.h>
#include <pcl/Rectangle.h>
#include <pcl/Vector.h>
namespace pcl
{
// ----------------------------------------------------------------------------
/*
* Default bucket capacity for point region quadtree generation.
*/
#define __PCL_QUADTREE_DEFAULT_BUCKET_CAPACITY 40
/*
* Default minimum allowed dimension of a quadtree node region.
*/
#define __PCL_QUADTREE_DEFAULT_EPSILON 1.0e-08
// ----------------------------------------------------------------------------
/*!
* \class QuadTree
* \brief Bucket PR quadtree for two-dimensional point data.
*
* A quadtree is a specialized binary search tree for partitioning of a set of
* points in two dimensions. Quadtrees have important applications in
* computational geometry problems requiring efficient rectangular range
* searching and nearest neighbor queries.
*
* This class implements a <em>bucket point region quadtree</em> structure
* (see Reference 2).
*
* The template type argument T represents the type of a \e point object stored
* in a %QuadTree structure. The type T must have the following properties:
*
* \li The standard default and copy constructors are required:\n
* \n
* T::T() \n
* T::T( const T& )
*
* \li The \c T::component subtype must be defined. It represents a component
* of an object of type T. For example, if T is a vector type, T::component
* must be the type of a vector component.
*
* \li The array subscript operator must be defined as follows:\n
* \n
* component T::operator []( int i ) const \n
* \n
* This operator must return the value of the first or second component of an
* object being stored in the quadtree. The subindex i will be either 0 or 1
* for the first or second point component, respectively.
*
* \b References
*
* 1. Mark de Berg et al, <em>Computational Geometry: Algorithms and
* Applications Third Edition,</em> Springer, 2010, Chapter 14.
*
* 2. Hanan Samet, <em>Foundations of Multidimensional and Metric Data
* Structures,</em> Morgan Kaufmann, 2006, Section 1.4.
*
* \sa KDTree
*/
template <class T>
class QuadTree
{
public:
/*!
* Represents a two-dimensional point stored in this quadtree.
*/
typedef T point;
/*!
* Represents a point component.
*/
typedef typename point::component component;
/*!
* A list of points. Used for tree build and search operations.
*/
typedef Array<point> point_list;
/*!
* A rectangular region. Used for rectangular range search operations.
*/
typedef DRect rectangle;
/*!
* The type of rectangular region coordinates.
*/
typedef rectangle::component coordinate;
// -------------------------------------------------------------------------
/*!
* \class pcl::QuadTree::Node
* \brief Quadtree node structure
*/
struct Node
{
rectangle rect = 0.0; //!< The rectangular region represented by this node.
Node* nw = nullptr; //!< North-West child node, representing the top-left subregion.
Node* ne = nullptr; //!< North-East child node, representing the top-right subregion.
Node* sw = nullptr; //!< South-West child node, representing the bottom-left subregion.
Node* se = nullptr; //!< South-East child node, representing the bottom-right subregion.
#ifdef __PCL_QUADTREE_STRUCTURAL_NODE_HAS_DATA
void* data = nullptr;
#endif
/*!
* Default constructor. Constructs an uninitialized quadtree node.
*/
Node() = default;
/*!
* Constructs a quadtree node for the specified rectangular region \a r.
*/
Node( const rectangle& r )
: rect( r )
{
}
/*!
* Returns true iff this is a leaf quadtree node. A leaf node does not
* contain child nodes, that is, there is no further subdivision of the
* domain space beyond a leaf quadtree node.
*
* In a healthy quadtree (as any QuadTree structure should be under
* normal working conditions), you can expect any leaf node to be an
* instance of QuadTree::LeafNode containing a nonempty list of points.
*/
bool IsLeaf() const
{
return nw == nullptr && ne == nullptr && sw == nullptr && se == nullptr;
}
/*!
* Returns true iff the rectangular region represented by this node
* intersects the specified rectangle \a r.
*/
bool Intersects( const rectangle& r ) const
{
return rect.x1 >= r.x0 && rect.x0 <= r.x1 &&
rect.y1 >= r.y0 && rect.y0 <= r.y1;
}
/*!
* Returns true iff the rectangular region represented by this node
* includes a point in the plane specified by its coordinates \a x, \a y.
*/
bool Includes( coordinate x, coordinate y ) const
{
return x >= rect.x0 && x <= rect.x1 &&
y >= rect.y0 && y <= rect.y1;
}
/*!
* Returns true iff the rectangular region represented by this node
* includes the specified point \a p in the plane.
*/
bool Includes( const rectangle::point& p ) const
{
return Includes( p.x, p.y );
}
/*!
* Returns the Northwest (top left) splitting rectangle for this node.
*/
rectangle NWRect() const
{
return rectangle( rect.TopLeft(), rect.Center() );
}
/*!
* Returns the Northeast (top right) splitting rectangle for this node.
*/
rectangle NERect() const
{
return rectangle( rect.CenterTop(), rect.CenterRight() );
}
/*!
* Returns the Southwest (bottom left) splitting rectangle for this node.
*/
rectangle SWRect() const
{
return rectangle( rect.CenterLeft(), rect.CenterBottom() );
}
/*!
* Returns the Southeast (bottom right) splitting rectangle for this
* node.
*/
rectangle SERect() const
{
return rectangle( rect.Center(), rect.BottomRight() );
}
};
// -------------------------------------------------------------------------
/*!
* \class pcl::QuadTree::LeafNode
* \brief Quadtree leaf node structure
*/
struct LeafNode : public Node
{
/*!
* The list of points contained by this leaf node.
*
* In a healthy quadtree (as any QuadTree structure should be under
* normal working conditions), every existing leaf node should contain a
* nonempty point list.
*/
point_list points;
#ifndef __PCL_QUADTREE_STRUCTURAL_NODE_HAS_DATA
/*!
* Pointer to an arbitrary data structure that can be associated with
* this leaf node. Its default value is \c nullptr.
*
* The quadtree structure does not access this pointer in any way.
* Destruction of the object pointed to by this member, if required, is
* the sole responsibility of the external code that has defined it.
*/
void* data = nullptr;
#endif
/*!
* Constructs a new leaf node representing the specified rectangular
* region \a r and storing a nonempty point list \a p.
*/
LeafNode( const rectangle& r, const point_list& p )
: Node( r )
, points( p )
{
PCL_CHECK( !points.IsEmpty() )
}
/*!
* Constructs a new leaf node representing the specified rectangular
* region \a r and storing the specified point \a p.
*/
LeafNode( const rectangle& r, const point& p )
: Node( r )
{
points << p;
}
/*!
* Returns the number of points contained by this leaf node. Under normal
* conditions, the returned value must be > 0.
*/
int Length() const
{
return int( points.Length() );
}
};
// -------------------------------------------------------------------------
/*!
* Constructs an empty quadtree.
*/
QuadTree() = default;
/*!
* Constructs a quadtree and builds it for the specified list of \a points.
*
* \param points A list of points that will be stored in this
* quadtree.
*
* \param bucketCapacity The maximum number of points in a leaf tree node.
* Must be &ge; 1. The default value is 40.
*
* \param epsilon The minimum allowed dimension of a quadtree node
* region. Must be larger than or equal to twice the
* machine epsilon for the \c coordinate type. The
* default value is 1e-8.
*
* If the specified list of \a points is empty, this constructor yields an
* empty quadtree.
*/
QuadTree( const point_list& points,
int bucketCapacity = __PCL_QUADTREE_DEFAULT_BUCKET_CAPACITY,
double epsilon = __PCL_QUADTREE_DEFAULT_EPSILON )
{
Build( points, bucketCapacity, epsilon );
}
/*!
* Constructs a quadtree and builds it for the specified list of \a points
* and a prescribed rectangular search region.
*
* \param rect The rectangular search region.
*
* \param points A list of points that will be stored in this
* quadtree.
*
* \param bucketCapacity The maximum number of points in a leaf tree node.
* Must be &ge; 1. The default value is 40.
*
* \param epsilon The minimum allowed dimension of a quadtree node
* region. Must be larger than or equal to twice the
* machine epsilon for the \c coordinate type. The
* default value is 1e-8.
*
* If the specified list of \a points is empty, or if no points lie within
* the \a rect region, this constructor yields an empty quadtree.
*/
QuadTree( const rectangle& rect, const point_list& points,
int bucketCapacity = __PCL_QUADTREE_DEFAULT_BUCKET_CAPACITY,
double epsilon = __PCL_QUADTREE_DEFAULT_EPSILON )
{
Build( rect, points, bucketCapacity, epsilon );
}
/*!
* Copy constructor. Copy construction is disabled because this class uses
* internal data structures that cannot be copy-constructed. However,
* %QuadTree implements move construction and move assignment.
*/
QuadTree( const QuadTree& ) = delete;
/*!
* Copy assignment operator. Copy assignment is disabled because this class
* uses internal data structures that cannot be copy-assigned. However,
* %QuadTree implements move assignment and move construction.
*/
QuadTree& operator =( const QuadTree& ) = delete;
/*!
* Move constructor.
*/
QuadTree( QuadTree&& x )
: m_root( x.m_root )
, m_bucketCapacity( x.m_bucketCapacity )
, m_epsilon( x.m_epsilon )
, m_length( x.m_length )
{
x.m_root = nullptr;
x.m_length = 0;
}
/*!
* Move assignment operator. Returns a reference to this object.
*/
QuadTree& operator =( QuadTree&& x )
{
if ( &x != this )
{
DestroyTree( m_root );
m_root = x.m_root;
m_bucketCapacity = x.m_bucketCapacity;
m_epsilon = x.m_epsilon;
m_length = x.m_length;
x.m_root = nullptr;
x.m_length = 0;
}
return *this;
}
/*!
* Destroys a quadtree. All the stored point objects are deleted.
*/
~QuadTree()
{
Clear();
}
/*!
* Removes all the stored point objects, yielding an empty quadtree.
*/
void Clear()
{
DestroyTree( m_root );
m_root = nullptr;
m_length = 0;
}
/*!
* Builds a new quadtree for the specified list of \a points.
*
* \param points A list of points that will be stored in this
* quadtree.
*
* \param bucketCapacity The maximum number of points in a leaf tree node.
* Must be &ge; 1. The default value is 40.
*
* \param epsilon The minimum allowed dimension of a quadtree node
* region. Must be larger than or equal to twice the
* machine epsilon for the \c coordinate type. The
* default value is 1e-8.
*
* If the tree stores point objects before calling this function, they are
* destroyed and removed before building a new tree.
*
* If the specified list of \a points is empty, this member function yields
* an empty quadtree.
*/
void Build( const point_list& points,
int bucketCapacity = __PCL_QUADTREE_DEFAULT_BUCKET_CAPACITY,
double epsilon = __PCL_QUADTREE_DEFAULT_EPSILON )
{
Clear();
m_bucketCapacity = Max( 1, bucketCapacity );
m_epsilon = Max( 2*std::numeric_limits<coordinate>::epsilon(), epsilon );
if ( !points.IsEmpty() )
{
component x = points[0][0];
component y = points[0][1];
rectangle rect( x, y, x, y );
for ( const point& p : points )
{
x = p[0];
y = p[1];
if ( x < rect.x0 )
rect.x0 = x;
if ( y < rect.y0 )
rect.y0 = y;
if ( x > rect.x1 )
rect.x1 = x;
if ( y > rect.y1 )
rect.y1 = y;
}
m_root = BuildTree( rect, points );
}
}
/*!
* Builds a new quadtree with the specified list of \a points and a
* prescribed rectangular search region.
*
* \param rect The rectangular search region.
*
* \param points A list of points to be stored in this quadtree.
* Only points included in the specified \a rect
* search region will be inserted in the tree.
* All points outside \a rect will be ignored.
*
* \param bucketCapacity The maximum number of points in a leaf tree node.
* Must be &ge; 1. The default value is 40.
*
* \param epsilon The minimum allowed dimension of a quadtree node
* region. Must be larger than or equal to twice the
* machine epsilon for the \c coordinate type. The
* default value is 1e-8.
*
* If the tree stores point objects before calling this function, they are
* destroyed and removed before building a new tree.
*
* If the specified list of \a points is empty, or if no points lie within
* the \a rect region, this member function yields an empty quadtree.
*/
void Build( const rectangle& rect, const point_list& points,
int bucketCapacity = __PCL_QUADTREE_DEFAULT_BUCKET_CAPACITY,
double epsilon = __PCL_QUADTREE_DEFAULT_EPSILON )
{
Clear();
m_bucketCapacity = Max( 1, bucketCapacity );
m_epsilon = Max( 2*std::numeric_limits<coordinate>::epsilon(), epsilon );
if ( !points.IsEmpty() )
m_root = BuildTree( rect.Ordered(), points );
}
/*!
* Performs a rectangular range search in this quadtree.
*
* \param rect The rectangular search region.
*
* Returns a (possibly empty) list with all the points found in this tree
* within the specified search range.
*/
point_list Search( const rectangle& rect ) const
{
point_list found;
SearchTree( found, rect.Ordered(), m_root );
return found;
}
/*!
* Performs a rectangular range search in this quadtree.
*
* \param rect The rectangular search region.
*
* \param callback Callback functional.
*
* \param data Callback data.
*
* The callback function prototype should be:
*
* \code void callback( const point& pt, void* data ) \endcode
*
* The callback function will be called once for each point found in the
* tree within the specified search range.
*/
template <class F>
void Search( const rectangle& rect, F callback, void* data ) const
{
SearchTree( rect.Ordered(), callback, data, m_root );
}
/*!
* Inserts a point in this quadtree.
*/
void Insert( const point& pt )
{
if ( m_root != nullptr )
InsertTree( pt, m_root );
else
{
component x = pt[0];
component y = pt[1];
m_root = new LeafNode( rectangle( x, y, x, y ), pt );
}
}
/*!
* Deletes all points in this quadtree equal to the specified point.
*/
void Delete( const point& pt )
{
DeleteTree( pt, m_root );
}
/*!
* Deletes all points in this quadtree included in the specified rectangular
* region \a rect.
*/
void Delete( const rectangle& rect )
{
DeleteTree( rect.Ordered(), m_root );
}
/*!
* Returns the bucket capacity of this quadtree, or the maximum number of
* points that can be stored in a leaf tree node. This parameter is
* specified when a new tree is built.
*/
int BucketCapacity() const
{
return m_bucketCapacity;
}
/*!
* Returns the total number of points stored in this quadtree.
*/
size_type Length() const
{
return m_length;
}
/*!
* Returns true iff this quadtree is empty.
*/
bool IsEmpty() const
{
return m_root == nullptr;
}
/*!
* Returns a pointer to the root node of this quadtree, or nullptr if this
* quadtree is empty.
*
* The returned pointer is const qualified to forbid uncontrolled
* alterations that might invalidate the quadtree structure.
*/
const Node* Root() const
{
return m_root;
}
/*!
* Returns a pointer to the (mutable) root node of this quadtree, or nullptr
* if this quadtree is empty.
*/
Node* Root()
{
return m_root;
}
/*!
* Returns a pointer to the (immutable) leaf node of this quadtree that
* includes the specified point \a p in the plane, or nullptr if no such
* leaf node exists in this quadtree.
*/
const LeafNode* LeafNodeAt( rectangle::point p ) const
{
return SearchLeafNode( p, m_root );
}
/*!
* Returns a pointer to the leaf node of this quadtree that includes the
* specified point \a p in the plane, or nullptr if no such leaf node exists
* in this quadtree.
*/
LeafNode* LeafNodeAt( rectangle::point p )
{
return SearchLeafNode( p, m_root );
}
/*!
* Returns a pointer to the (immutable) node of this quadtree that includes
* the specified point \a p in the plane, or nullptr if no such node exists
* in this quadtree.
*
* The returned node can be a leaf node or a structural node. This function
* should only return nullptr if the specified point \a p is exterior to the
* root rectangular region of this quadtree, or if this quadtree is empty.
*/
const Node* NodeAt( rectangle::point p ) const
{
return SearchNode( p, m_root );
}
/*!
* Returns a pointer to the node of this quadtree that includes the
* specified point \a p in the plane, or nullptr if no such node exists in
* this quadtree.
*
* The returned node can be a leaf node or a structural node. This function
* should only return nullptr if the specified point \a p is exterior to the
* root rectangular region of this quadtree, or if this quadtree is empty.
*/
Node* NodeAt( rectangle::point p )
{
return SearchNode( p, m_root );
}
/*!
* Forces a quadtree subdivision of the leaf node that includes the
* specified point \a p in the plane.
*
* Returns the newly created structural node. This function should only
* return nullptr if the specified point \a p is exterior to the root
* rectangular region of this quadtree, or if this quadtree is empty. It
* could also return nullptr in degenerate cases where no further
* subdivision of the plane would be possible because of numerical limits.
*/
Node* SplitAt( rectangle::point p )
{
Node* node = SearchDeepestStructuralNodeAt( p, m_root );
if ( node != nullptr )
{
Node** leaf = nullptr;
if ( node->nw != nullptr && node->nw->Includes( p ) )
leaf = &node->nw;
else if ( node->ne != nullptr && node->ne->Includes( p ) )
leaf = &node->ne;
else if ( node->sw != nullptr && node->sw->Includes( p ) )
leaf = &node->sw;
else if ( node->se != nullptr && node->se->Includes( p ) )
leaf = &node->se;
if ( leaf != nullptr ) // cannot be false!
{
Node* newNode = SplitLeafNode( *leaf );
if ( newNode != nullptr ) // should be true
{
delete static_cast<LeafNode*>( *leaf );
*leaf = newNode;
}
return newNode;
}
}
return nullptr;
}
/*!
* Performs a recursive left-to-right, depth-first traversal of the subtree
* rooted at the specified \a node, invoking the specified function \a f
* successively for each leaf node.
*
* The function \a f must be compatible with the form:
*
* \code void f( const rectangle& r, const point_list& p, void*& d ) \endcode
*
* where \a r is the plane region covered by the current leaf node, \a p is
* the list of points in the current leaf node, and \a d is the optional
* pointer to arbitrary data associated with the current leaf node.
*
* The sequence of calls for the subtrees in each non-leaf node is: NW, NE,
* SW, SE. Only non-empty leaf nodes are included in the traversal, hence
* the function \a f will be invoked exclusively for non-empty point lists.
*
* If the specified \a node is nullptr, this function takes no action.
*/
template <class F>
static void Traverse( const Node* node, F f )
{
if ( node != nullptr )
if ( node->IsLeaf() )
f( node->rect,
static_cast<const LeafNode*>( node )->points,
static_cast<const LeafNode*>( node )->data );
else
{
Traverse( node->nw, f );
Traverse( node->ne, f );
Traverse( node->sw, f );
Traverse( node->se, f );
}
}
/*!
* Performs a recursive left-to-right, depth-first traversal of the subtree
* rooted at the specified (mutable) \a node, invoking the specified
* function \a f successively for each leaf node.
*
* The function \a f must be compatible with the form:
*
* \code void f( const rectangle& r, point_list& p, void*& d ) \endcode
*
* where \a r is the plane region covered by the current leaf node, \a p is
* the list of points in the current leaf node, and \a d is the optional
* pointer to arbitrary data associated with the current leaf node.
*
* The sequence of calls for the subtrees in each non-leaf node is: NW, NE,
* SW, SE. Only non-empty leaf nodes are included in the traversal, hence
* the function \a f will be invoked exclusively for non-empty point lists.
*
* If the specified \a node is nullptr, this function takes no action.
*/
template <class F>
static void Traverse( Node* node, F f )
{
if ( node != nullptr )
if ( node->IsLeaf() )
f( node->rect, static_cast<LeafNode*>( node )->points,
static_cast<LeafNode*>( node )->data );
else
{
Traverse( node->nw, f );
Traverse( node->ne, f );
Traverse( node->sw, f );
Traverse( node->se, f );
}
}
/*!
* Performs a recursive left-to-right, depth-first traversal of the entire
* quadtree, invoking the specified function \a f successively for each leaf
* node. Calling this function is equivalent to:
*
* \code Traverse( Root(), f ) \endcode
*
* If this quadtree is empty, this function takes no action.
*/
template <class F>
void Traverse( F f ) const
{
Traverse( m_root, f );
}
/*!
* Performs a recursive left-to-right, depth-first traversal of the entire
* (mutable) quadtree, invoking the specified function \a f successively for
* each leaf node. Calling this function is equivalent to:
*
* \code Traverse( Root(), f ) \endcode
*
* If this quadtree is empty, this function takes no action.
*/
template <class F>
void Traverse( F f )
{
Traverse( m_root, f );
}
/*!
* Returns the total number of existing nodes in the subtree rooted at the
* specified \a node, including structural and leaf nodes.
*/
static size_type NumberOfNodes( const Node* node )
{
size_type N = 0;
GetNumberOfNodes( N, node );
return N;
}
/*!
* Returns the total number of existing nodes in this quadtree, including
* structural and leaf nodes.
*/
size_type NumberOfNodes() const
{
return NumberOfNodes( m_root );
}
/*!
* Returns the total number of existing leaf nodes in the subtree rooted at
* the specified \a node.
*/
static size_type NumberOfLeafNodes( const Node* node )
{
size_type N = 0;
GetNumberOfLeafNodes( N, node );
return N;
}
/*!
* Returns the total number of existing leaf nodes in this quadtree.
*/
size_type NumberOfLeafNodes() const
{
return NumberOfLeafNodes( m_root );
}
/*!
* Returns the height of the subtree rooted at the specified \a node.
*/
static int Height( const Node* node )
{
return TreeHeight( node, 0 );
}
/*!
* Returns the height of this quadtree.
*/
int Height() const
{
return Height( m_root );
}
/*!
* Exchanges two %QuadTree objects \a x1 and \a x2.
*/
friend void Swap( QuadTree& x1, QuadTree& x2 )
{
pcl::Swap( x1.m_root, x2.m_root );
pcl::Swap( x1.m_bucketCapacity, x2.m_bucketCapacity );
pcl::Swap( x1.m_epsilon, x2.m_epsilon );
pcl::Swap( x1.m_length, x2.m_length );
}
private:
Node* m_root = nullptr;
int m_bucketCapacity = 0;
double m_epsilon = 0;
size_type m_length = 0;
Node* NewLeafNode( const rectangle& rect, const point_list& points )
{
m_length += points.Length();
return new LeafNode( rect, points );
}
LeafNode* SearchLeafNode( const rectangle::point& p, const Node* node ) const
{
if ( node != nullptr )
if ( node->Includes( p ) )
{
if ( node->IsLeaf() )
return const_cast<LeafNode*>( static_cast<const LeafNode*>( node ) );
LeafNode* child = SearchLeafNode( p, node->nw );
if ( child == nullptr )
{
child = SearchLeafNode( p, node->ne );
if ( child == nullptr )
{
child = SearchLeafNode( p, node->sw );
if ( child == nullptr )
child = SearchLeafNode( p, node->se );
}
}
return child;
}
return nullptr;
}
Node* SearchNode( const rectangle::point& p, const Node* node ) const
{
if ( node != nullptr )
if ( node->Includes( p ) )
{
if ( node->IsLeaf() )
return const_cast<Node*>( node );
Node* child = SearchNode( p, node->nw );
if ( child == nullptr )
{
child = SearchNode( p, node->ne );
if ( child == nullptr )
{
child = SearchNode( p, node->sw );
if ( child == nullptr )
{
child = SearchNode( p, node->se );
if ( child == nullptr )
return const_cast<Node*>( node );
}
}
}
return child;
}
return nullptr;
}
Node* SearchDeepestStructuralNodeAt( const rectangle::point& p, const Node* node ) const
{
if ( node != nullptr )
if ( !node->IsLeaf() )
if ( node->Includes( p ) )
{
Node* child = SearchDeepestStructuralNodeAt( p, node->nw );
if ( child == nullptr )
{
child = SearchDeepestStructuralNodeAt( p, node->ne );
if ( child == nullptr )
{
child = SearchDeepestStructuralNodeAt( p, node->sw );
if ( child == nullptr )
{
child = SearchDeepestStructuralNodeAt( p, node->se );
if ( child == nullptr )
return const_cast<Node*>( node );
}
}
}
return child;
}
return nullptr;
}
Node* BuildTree( const rectangle& rect, const point_list& points )
{
if ( points.IsEmpty() )
return nullptr;
if ( points.Length() <= size_type( m_bucketCapacity ) )
return NewLeafNode( rect, points );
double x2 = (rect.x0 + rect.x1)/2;
double y2 = (rect.y0 + rect.y1)/2;
// Prevent geometrically degenerate subtrees. For safety, we enforce
// minimum region dimensions larger than twice the machine epsilon for
// the rectangle coordinate type.
if ( x2 - rect.x0 < m_epsilon || rect.x1 - x2 < m_epsilon ||
y2 - rect.y0 < m_epsilon || rect.y1 - y2 < m_epsilon )
{
return NewLeafNode( rect, points );
}
point_list nw, ne, sw, se;
for ( const point& p : points )
{
component x = p[0];
component y = p[1];
if ( x <= x2 )
{
if ( y <= y2 )
nw << p;
else
sw << p;
}
else
{
if ( y <= y2 )
ne << p;
else
se << p;
}
}
Node* node = new Node( rect );
node->nw = BuildTree( rectangle( rect.x0, rect.y0, x2, y2 ), nw );
node->ne = BuildTree( rectangle( x2, rect.y0, rect.x1, y2 ), ne );
node->sw = BuildTree( rectangle( rect.x0, y2, x2, rect.y1 ), sw );
node->se = BuildTree( rectangle( x2, y2, rect.x1, rect.y1 ), se );
// Further degeneracies may result, e.g. if the point class is not
// behaving as expected. Do not allow them.
if ( node->IsLeaf() )
{
delete node;
return NewLeafNode( rect, points );
}
return node;
}
Node* SplitLeafNode( const Node* node )
{
if ( node == nullptr || !node->IsLeaf() )
return nullptr;
double x2 = (node->rect.x0 + node->rect.x1)/2;
double y2 = (node->rect.y0 + node->rect.y1)/2;
// Prevent geometrically degenerate subtrees. For safety, we enforce
// minimum region dimensions larger than twice the machine epsilon for
// the rectangle coordinate type.
if ( x2 - node->rect.x0 < m_epsilon || node->rect.x1 - x2 < m_epsilon ||
y2 - node->rect.y0 < m_epsilon || node->rect.y1 - y2 < m_epsilon )
{
return nullptr;
}
const LeafNode* leaf = static_cast<const LeafNode*>( node );
point_list nw, ne, sw, se;
for ( const point& p : leaf->points )
{
component x = p[0];
component y = p[1];
if ( x <= x2 )
{
if ( y <= y2 )
nw << p;
else
sw << p;
}
else
{
if ( y <= y2 )
ne << p;
else
se << p;
}
}
size_type savedLength = m_length;
Node* newNode = new Node( node->rect );
newNode->nw = BuildTree( rectangle( node->rect.x0, node->rect.y0, x2, y2 ), nw );
newNode->ne = BuildTree( rectangle( x2, node->rect.y0, node->rect.x1, y2 ), ne );
newNode->sw = BuildTree( rectangle( node->rect.x0, y2, x2, node->rect.y1 ), sw );
newNode->se = BuildTree( rectangle( x2, y2, node->rect.x1, node->rect.y1 ), se );
m_length = savedLength;
// Further degeneracies may result, e.g. if the point class is not
// behaving as expected. Do not allow them.
if ( newNode->IsLeaf() )
{
delete newNode;
return nullptr;
}
return newNode;
}
void SearchTree( point_list& found, const rectangle& rect, const Node* node ) const
{
if ( node != nullptr )
if ( node->Intersects( rect ) )
if ( node->IsLeaf() )
{
const LeafNode* leaf = static_cast<const LeafNode*>( node );
for ( const point& p : leaf->points )
{
component x = p[0];
if ( x >= rect.x0 )
if ( x <= rect.x1 )
{
component y = p[1];
if ( y >= rect.y0 )
if ( y <= rect.y1 )
found << p;
}
}
}
else
{
SearchTree( found, rect, node->nw );
SearchTree( found, rect, node->ne );
SearchTree( found, rect, node->sw );
SearchTree( found, rect, node->se );
}
}
template <class F>
void SearchTree( const rectangle& rect, F callback, void* data, const Node* node ) const
{
if ( node != nullptr )
if ( node->Intersects( rect ) )
if ( node->IsLeaf() )
{
const LeafNode* leaf = static_cast<const LeafNode*>( node );
for ( const point& p : leaf->points )
{
component x = p[0];
if ( x >= rect.x0 )
if ( x <= rect.x1 )
{
component y = p[1];
if ( y >= rect.y0 )
if ( y <= rect.y1 )
callback( p, data );
}
}
}
else
{
SearchTree( rect, callback, data, node->nw );
SearchTree( rect, callback, data, node->ne );
SearchTree( rect, callback, data, node->sw );
SearchTree( rect, callback, data, node->se );
}
}
void InsertTree( const point& pt, Node*& node )
{
PCL_CHECK( node != nullptr )
component x = pt[0];
component y = pt[1];
if ( x < node->rect.x0 )
node->rect.x0 = x;
else if ( x > node->rect.x1 )
node->rect.x1 = x;
if ( y < node->rect.y0 )
node->rect.y0 = y;
else if ( y > node->rect.y1 )
node->rect.y1 = y;
if ( node->IsLeaf() )
{
LeafNode* leaf = static_cast<LeafNode*>( node );
if ( leaf->Length() < m_bucketCapacity )
leaf->points << pt;
else
{
rectangle rect = leaf->rect;
double x2 = (rect.x0 + rect.x1)/2;
double y2 = (rect.y0 + rect.y1)/2;
// Prevent geometrically degenerate subtrees. For safety, we
// enforce minimum region dimensions larger than twice the
// machine epsilon for the rectangle coordinate type.
if ( x2 - rect.x0 < m_epsilon || rect.x1 - x2 < m_epsilon ||
y2 - rect.y0 < m_epsilon || rect.y1 - y2 < m_epsilon )
{
leaf->points << pt;
}
else
{
point_list nw, ne, sw, se;
for ( const point& p : leaf->points )
{
component x = p[0];
component y = p[1];
if ( x <= x2 )
{
if ( y <= y2 )
nw << p;
else
sw << p;
}
else
{
if ( y <= y2 )
ne << p;
else
se << p;
}
}
if ( x <= x2 )
{
if ( y <= y2 )
nw << pt;
else
sw << pt;
}
else
{
if ( y <= y2 )
ne << pt;
else
se << pt;
}
delete leaf;
node = new Node( rect );
if ( !nw.IsEmpty() )
node->nw = new LeafNode( rectangle( rect.x0, rect.y0, x2, y2 ), nw );
if ( !ne.IsEmpty() )
node->ne = new LeafNode( rectangle( x2, rect.y0, rect.x1, y2 ), ne );
if ( !sw.IsEmpty() )
node->sw = new LeafNode( rectangle( rect.x0, y2, x2, rect.y1 ), sw );
if ( !se.IsEmpty() )
node->se = new LeafNode( rectangle( x2, y2, rect.x1, rect.y1 ), se );
}
}
++m_length;
}
else
{
rectangle rect = node->rect;
double x2 = (rect.x0 + rect.x1)/2;
double y2 = (rect.y0 + rect.y1)/2;
if ( pt[0] <= x2 )
{
if ( pt[1] <= y2 )
{
if ( node->nw == nullptr )
node->nw = new LeafNode( rectangle( rect.x0, rect.y0, x2, y2 ), pt );
else
InsertTree( pt, node->nw );
}
else
{
if ( node->sw == nullptr )
node->sw = new LeafNode( rectangle( rect.x0, y2, x2, rect.y1 ), pt );
else
InsertTree( pt, node->sw );
}
}
else
{
if ( pt[1] <= y2 )
{
if ( node->ne == nullptr )
node->ne = new LeafNode( rectangle( x2, rect.y0, rect.x1, y2 ), pt );
else
InsertTree( pt, node->ne );
}
else
{
if ( node->se == nullptr )
node->se = new LeafNode( rectangle( x2, y2, rect.x1, rect.y1 ), pt );
else
InsertTree( pt, node->se );
}
}
}
}
void DeleteTree( const rectangle& rect, Node*& node )
{
if ( node != nullptr )
if ( node->Intersects( rect ) )
{
if ( node->IsLeaf() )
{
LeafNode* leaf = static_cast<LeafNode*>( node );
point_list points;
for ( const point& p : leaf->points )
{
component x = p[0];
if ( x >= rect.x0 )
if ( x <= rect.x1 )
{
component y = p[1];
if ( y >= rect.y0 )
if ( y <= rect.y1 )
{
--m_length;
continue;
}
}
points << p;
}
if ( points.IsEmpty() )
{
delete leaf;
node = nullptr;
}
else
leaf->points = points;
}
else
{
DeleteTree( rect, node->nw );
DeleteTree( rect, node->ne );
DeleteTree( rect, node->sw );
DeleteTree( rect, node->se );
if ( node->IsLeaf() )
{
delete node;
node = nullptr;
}
}
}
}
void DeleteTree( const point& pt, Node*& node )
{
if ( node != nullptr )
{
component x = pt[0];
component y = pt[1];
if ( node->Includes( x, y ) )
if ( node->IsLeaf() )
{
LeafNode* leaf = static_cast<LeafNode*>( node );
point_list points;
for ( const point& p : leaf->points )
{
if ( p[0] == x )
if ( p[1] == y )
{
--m_length;
continue;
}
points << p;
}
if ( points.IsEmpty() )
{
delete leaf;
node = nullptr;
}
else
leaf->points = points;
}
else
{
DeleteTree( pt, node->nw );
DeleteTree( pt, node->ne );
DeleteTree( pt, node->sw );
DeleteTree( pt, node->se );
if ( node->IsLeaf() )
{
delete node;
node = nullptr;
}
}
}
}
void DestroyTree( Node* node )
{
if ( node != nullptr )
if ( node->IsLeaf() )
delete static_cast<LeafNode*>( node );
else
{
DestroyTree( node->nw );
DestroyTree( node->ne );
DestroyTree( node->sw );
DestroyTree( node->se );
delete node;
}
}
static void GetNumberOfNodes( size_type& N, const Node* node )
{
if ( node != nullptr )
{
++N;
GetNumberOfNodes( N, node->nw );
GetNumberOfNodes( N, node->ne );
GetNumberOfNodes( N, node->sw );
GetNumberOfNodes( N, node->se );
}
}
static void GetNumberOfLeafNodes( size_type& N, const Node* node )
{
if ( node != nullptr )
{
if ( node->IsLeaf() )
++N;
GetNumberOfLeafNodes( N, node->nw );
GetNumberOfLeafNodes( N, node->ne );
GetNumberOfLeafNodes( N, node->sw );
GetNumberOfLeafNodes( N, node->se );
}
}
static int TreeHeight( const Node* node, int h )
{
if ( node == nullptr )
return h;
return h + 1 + Max( Max( Max( TreeHeight( node->nw, h ),
TreeHeight( node->ne, h ) ),
TreeHeight( node->sw, h ) ),
TreeHeight( node->se, h ) );
}
};
// ----------------------------------------------------------------------------
} // pcl
#endif // __PCL_QuadTree_h
// ----------------------------------------------------------------------------
// EOF pcl/QuadTree.h - Released 2022-03-12T18:59:29Z