748 lines
19 KiB
C++
748 lines
19 KiB
C++
// X2DQuadTree.h
|
|
//
|
|
// Last modified by Young-Hyun Joo, 2007/12/11
|
|
//
|
|
// Created by Testors , 2005/08/01
|
|
|
|
#pragma once
|
|
|
|
//
|
|
// X2D 에 기반이지만 어짜피 완전히 generic 하게 만들었기 때문에
|
|
// X2D::INCLUDE( X2D::Rect< T >, U ), X2D::COLLISION( X2D::Rect< T >, U ), X2D::COLLISION( U, C ), X2D::COLLISION( X2D::Rect< T >, C )
|
|
// 만 주어진다면 3D 에서의 사용도 가능하다.
|
|
//
|
|
// T : 좌표계 타입
|
|
// U : 보관할 대상타입
|
|
// THRESHOLD : 한 노드에 몇개정도까지 U 를 저장할것인가의 여부
|
|
// C : 검색시 범위 타입
|
|
//
|
|
|
|
#include <vector>
|
|
#include <cassert>
|
|
|
|
#include "X2DBasicTypes.h"
|
|
|
|
|
|
namespace X2D
|
|
{
|
|
|
|
template< typename T, typename U, bool LOOSE = true, size_t THRESHOLD = 20, size_t MAX_DEPTH = 10 >
|
|
struct QuadTree
|
|
{
|
|
typedef Box< T > NodeType;
|
|
|
|
QuadTree( const T & left, const T & top, const T & width, const T & height )
|
|
: m_masterNode( 1, left, top, width, height )
|
|
{
|
|
}
|
|
|
|
QuadTree( const T & width, const T & height )
|
|
: m_masterNode( 1, 0, 0, width, height )
|
|
{
|
|
}
|
|
|
|
~QuadTree()
|
|
{
|
|
}
|
|
|
|
void ReInit( const T & left, const T & top, const T & width, const T & height )
|
|
{
|
|
m_masterNode.Node::~Node();
|
|
new ( &m_masterNode ) Node( 1, left, top, width, height );
|
|
}
|
|
|
|
void ReInit( const T & width, const T & height )
|
|
{
|
|
m_masterNode.Node::~Node();
|
|
new ( &m_masterNode ) Node( 1, 0, 0, width, height );
|
|
}
|
|
|
|
T GetX()
|
|
{
|
|
return m_masterNode.GetX();
|
|
}
|
|
|
|
T GetY()
|
|
{
|
|
return m_masterNode.GetY();
|
|
}
|
|
|
|
T GetWidth() const
|
|
{
|
|
return m_masterNode.GetWidth();
|
|
}
|
|
|
|
T GetHeight() const
|
|
{
|
|
return m_masterNode.GetHeight();
|
|
}
|
|
|
|
bool Add( const U & u )
|
|
{
|
|
return m_masterNode.Add( u );
|
|
}
|
|
|
|
template< typename F >
|
|
bool DuplicateAdd( const U & u, F & f )
|
|
{
|
|
return m_masterNode.DuplicateAdd( u, f );
|
|
}
|
|
|
|
template< typename C, typename F >
|
|
void Enum( const C & c, F & f )
|
|
{
|
|
m_masterNode.Enum( c, f );
|
|
}
|
|
|
|
template< typename C >
|
|
void Enum( const C & c, std::vector< U > * pResult )
|
|
{
|
|
_FUNCTOR_ADAPTOR adaptor;
|
|
adaptor.pResult = pResult;
|
|
m_masterNode.Enum( c, adaptor );
|
|
}
|
|
|
|
template< typename C >
|
|
void EnumLoose( const C & c, std::vector< U > * pResult )
|
|
{
|
|
_FUNCTOR_ADAPTOR adaptor;
|
|
adaptor.pResult = pResult;
|
|
m_masterNode.EnumLoose( c, adaptor );
|
|
}
|
|
|
|
void Enum( std::vector< U > * pResult )
|
|
{
|
|
_FUNCTOR_ADAPTOR adaptor;
|
|
adaptor.pResult = pResult;
|
|
m_masterNode.Enum( adaptor );
|
|
}
|
|
|
|
template< typename F >
|
|
void Enum( F & f )
|
|
{
|
|
m_masterNode.Enum( f );
|
|
}
|
|
|
|
template< typename F >
|
|
void Iterate( F & f )
|
|
{
|
|
m_masterNode.Iterate( f );
|
|
}
|
|
|
|
template< typename C >
|
|
void Remove( const C & c )
|
|
{
|
|
m_masterNode.Remove( c );
|
|
}
|
|
|
|
template< typename C >
|
|
bool Collision( const C & c ) const
|
|
{
|
|
return m_masterNode.Collision( c );
|
|
}
|
|
|
|
template< typename C >
|
|
bool LooseCollision( const C & c ) const
|
|
{
|
|
return m_masterNode.LooseCollision( c );
|
|
}
|
|
|
|
bool Has( const U & u ) const
|
|
{
|
|
m_masterNode.Has( u );
|
|
}
|
|
|
|
void Remove( const U & u )
|
|
{
|
|
m_masterNode.Remove( u );
|
|
}
|
|
|
|
template< typename NF >
|
|
void EnumNode( NF & f, bool bReverse = false )
|
|
{
|
|
m_masterNode.EnumNode( f, bReverse );
|
|
}
|
|
|
|
template< typename IF >
|
|
void EnumItem( IF & f, bool bReverse = false )
|
|
{
|
|
m_masterNode.EnumItem( f, bReverse );
|
|
}
|
|
|
|
size_t getItemCount() const
|
|
{
|
|
return m_masterNode.getItemCount();
|
|
}
|
|
|
|
struct Node
|
|
{
|
|
Node( unsigned short depth, const T & left, const T & top, const T & width, const T & height )
|
|
{
|
|
m_unDepth = depth;
|
|
|
|
m_pNode[0] = NULL;
|
|
m_pNode[1] = NULL;
|
|
m_pNode[2] = NULL;
|
|
m_pNode[3] = NULL;
|
|
|
|
init( depth, left, top, width, height );
|
|
}
|
|
|
|
~Node()
|
|
{
|
|
if( hasChildNode() )
|
|
{
|
|
delete m_pNode[0];
|
|
delete m_pNode[1];
|
|
delete m_pNode[2];
|
|
delete m_pNode[3];
|
|
}
|
|
}
|
|
|
|
T GetX()
|
|
{
|
|
return m_rcEffectiveArea.GetX();
|
|
}
|
|
|
|
T GetY()
|
|
{
|
|
return m_rcEffectiveArea.GetY();
|
|
}
|
|
|
|
T GetWidth() const
|
|
{
|
|
return m_rcEffectiveArea.GetWidth();
|
|
}
|
|
|
|
T GetHeight() const
|
|
{
|
|
return m_rcEffectiveArea.GetHeight();
|
|
}
|
|
|
|
bool hasChildNode() const { return m_pNode[0] != NULL; }
|
|
|
|
bool Add( const U & u )
|
|
{
|
|
if( !COLLISION( m_rcEffectiveArea, u ) )
|
|
{
|
|
assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
// 자식 노드가 있다면
|
|
if( hasChildNode() )
|
|
{
|
|
Node *pNode = getFitNode( u );
|
|
if( pNode )
|
|
{
|
|
if( pNode->Add( u ) ) return true;
|
|
}
|
|
}
|
|
|
|
add( u );
|
|
|
|
return true;
|
|
}
|
|
|
|
template< typename F >
|
|
bool DuplicateAdd( const U & u, F & f )
|
|
{
|
|
if( !COLLISION( m_rcEffectiveArea, f( u ) ) )
|
|
{
|
|
assert( 0 );
|
|
return false;
|
|
}
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
bool Added( false );
|
|
if( m_pNode[ 0 ]->IsAddable( u, f ) ) { m_pNode[ 0 ]->DuplicateAdd( u, f ); Added = true; }
|
|
if( m_pNode[ 1 ]->IsAddable( u, f ) ) { m_pNode[ 1 ]->DuplicateAdd( u, f ); Added = true; }
|
|
if( m_pNode[ 2 ]->IsAddable( u, f ) ) { m_pNode[ 2 ]->DuplicateAdd( u, f ); Added = true; }
|
|
if( m_pNode[ 3 ]->IsAddable( u, f ) ) { m_pNode[ 3 ]->DuplicateAdd( u, f ); Added = true; }
|
|
if( Added ) return true;
|
|
}
|
|
|
|
duplicate_add( u, f );
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IsAddable( const U & u ) const
|
|
{
|
|
return INCLUDE( m_rcEffectiveArea, u );
|
|
}
|
|
|
|
template< typename F >
|
|
bool IsAddable( const U & u, F & f )
|
|
{
|
|
return COLLISION( m_rcEffectiveArea, f( u ) );
|
|
}
|
|
|
|
template< typename C >
|
|
bool Collision( const C & c ) const
|
|
{
|
|
if( !COLLISION( m_rcEffectiveArea, c ) ) return false;
|
|
|
|
for( std::vector< U >::const_iterator it = m_vList.begin(); it != m_vList.end(); ++it )
|
|
{
|
|
if( COLLISION( (*it), c ) ) return true;
|
|
}
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
// quadtree(0,0,100,100) 일경우 Box(70,70,80,80) 를 add() 하면 m_pNode[3] 에 들어간다.
|
|
// 그런데 이걸 point(70,70) 으로 검사하면 m_pNode[0] 이 fit 이 된다.
|
|
// 그러므로 4 노드 모두 검사 해야 한다.
|
|
if( m_pNode[0]->Collision( c ) ) return true;
|
|
if( m_pNode[1]->Collision( c ) ) return true;
|
|
if( m_pNode[2]->Collision( c ) ) return true;
|
|
if( m_pNode[3]->Collision( c ) ) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template< typename C >
|
|
bool LooseCollision( const C & c ) const
|
|
{
|
|
if( !COLLISION( m_rcEffectiveArea, c ) ) return false;
|
|
|
|
for( std::vector< U >::const_iterator it = m_vList.begin(); it != m_vList.end(); ++it )
|
|
{
|
|
if( LOOSE_COLLISION( (*it), c ) ) return true;
|
|
}
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
// quadtree(0,0,100,100) 일경우 Box(70,70,80,80) 를 add() 하면 m_pNode[3] 에 들어간다.
|
|
// 그런데 이걸 point(70,70) 으로 검사하면 m_pNode[0] 이 fit 이 된다.
|
|
// 그러므로 4 노드 모두 검사 해야 한다.
|
|
if( m_pNode[0]->LooseCollision( c ) ) return true;
|
|
if( m_pNode[1]->LooseCollision( c ) ) return true;
|
|
if( m_pNode[2]->LooseCollision( c ) ) return true;
|
|
if( m_pNode[3]->LooseCollision( c ) ) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
template< typename C, typename F >
|
|
void Enum( const C & c, F & f )
|
|
{
|
|
if( !COLLISION( m_rcEffectiveArea, c ) ) return;
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
// quadtree(0,0,100,100) 일경우 Box(70,70,80,80) 를 add() 하면 m_pNode[3] 에 들어간다.
|
|
// 그런데 이걸 point(70,70) 으로 검사하면 m_pNode[0] 이 fit 이 된다.
|
|
// 그러므로 4 노드 모두 검사 해야 한다.
|
|
m_pNode[0]->Enum( c, f );
|
|
m_pNode[1]->Enum( c, f );
|
|
m_pNode[2]->Enum( c, f );
|
|
m_pNode[3]->Enum( c, f );
|
|
}
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); ++it )
|
|
{
|
|
if( COLLISION( (*it), c ) ) f( *it );
|
|
}
|
|
}
|
|
|
|
template< typename C, typename F >
|
|
void EnumLoose( const C & c, F & f )
|
|
{
|
|
if( !COLLISION( m_rcEffectiveArea, c ) ) return;
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
// quadtree(0,0,100,100) 일경우 Box(70,70,80,80) 를 add() 하면 m_pNode[3] 에 들어간다.
|
|
// 그런데 이걸 point(70,70) 으로 검사하면 m_pNode[0] 이 fit 이 된다.
|
|
// 그러므로 4 노드 모두 검사 해야 한다.
|
|
m_pNode[0]->EnumLoose( c, f );
|
|
m_pNode[1]->EnumLoose( c, f );
|
|
m_pNode[2]->EnumLoose( c, f );
|
|
m_pNode[3]->EnumLoose( c, f );
|
|
}
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); ++it )
|
|
{
|
|
f( *it );
|
|
}
|
|
}
|
|
|
|
template< typename F >
|
|
void Enum( F & f )
|
|
{
|
|
if( hasChildNode() )
|
|
{
|
|
m_pNode[0]->Enum( f );
|
|
m_pNode[1]->Enum( f );
|
|
m_pNode[2]->Enum( f );
|
|
m_pNode[3]->Enum( f );
|
|
}
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); ++it ) f( *it );
|
|
}
|
|
|
|
template< typename F >
|
|
void Iterate( F & f )
|
|
{
|
|
if( hasChildNode() )
|
|
{
|
|
m_pNode[0]->Iterate( f );
|
|
m_pNode[1]->Iterate( f );
|
|
m_pNode[2]->Iterate( f );
|
|
m_pNode[3]->Iterate( f );
|
|
}
|
|
|
|
f( *this );
|
|
}
|
|
|
|
bool Has( const U & u ) const
|
|
{
|
|
if( !IsAddable( u ) ) return false;
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
Node *pNode = getFitNode( u );
|
|
if( pNode->Has( u ) ) return true;
|
|
}
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); )
|
|
{
|
|
if( (*it) == u )
|
|
{
|
|
if( it = m_vList.erase( it ) ) return true;
|
|
}
|
|
++it;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Remove( const U & u )
|
|
{
|
|
if( !IsAddable( u ) ) return;
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
Node *pNode = getFitNode( u );
|
|
if( pNode ) pNode->Remove( u );
|
|
}
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); )
|
|
{
|
|
if( (*it) == u )
|
|
{
|
|
it = m_vList.erase( it );
|
|
continue;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
template< typename C >
|
|
void Remove( const C & c )
|
|
{
|
|
if( hasChildNode() )
|
|
{
|
|
// quadtree(0,0,100,100) 일경우 Box(70,70,80,80) 를 add() 하면 m_pNode[3] 에 들어간다.
|
|
// 그런데 이걸 point(70,70) 으로 검사하면 m_pNode[0] 이 fit 이 된다.
|
|
// 그러므로 4 노드 모두 검사 해야 한다.
|
|
m_pNode[0]->Remove( c );
|
|
m_pNode[1]->Remove( c );
|
|
m_pNode[2]->Remove( c );
|
|
m_pNode[3]->Remove( c );
|
|
}
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); )
|
|
{
|
|
if( COLLISION( (*it), c ) )
|
|
{
|
|
it = m_vList.erase( it );
|
|
continue;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
const Rect< T > & GetEffectiveArea() const { return m_rcEffectiveArea; }
|
|
|
|
void SetDepth( unsigned short depth )
|
|
{
|
|
m_unDepth = depth;
|
|
if( hasChildNode() )
|
|
{
|
|
m_pNode[0]->SetDepth( depth );
|
|
m_pNode[1]->SetDepth( depth );
|
|
m_pNode[2]->SetDepth( depth );
|
|
m_pNode[3]->SetDepth( depth );
|
|
}
|
|
}
|
|
|
|
template< typename NF >
|
|
void EnumNode( NF & f, bool bReverse )
|
|
{
|
|
if( !bReverse ) f( m_unDepth, m_rcEffectiveArea, m_vList );
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
m_pNode[0]->EnumNode( f, bReverse );
|
|
m_pNode[1]->EnumNode( f, bReverse );
|
|
m_pNode[2]->EnumNode( f, bReverse );
|
|
m_pNode[3]->EnumNode( f, bReverse );
|
|
}
|
|
|
|
if( bReverse ) f( m_unDepth, m_rcEffectiveArea, m_vList );
|
|
}
|
|
|
|
template< typename IF >
|
|
void enum_item( IF & f )
|
|
{
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); ++it ) f( m_unDepth, *it );
|
|
}
|
|
|
|
template< typename IF >
|
|
void EnumItem( IF & f, bool bReverse )
|
|
{
|
|
if( !bReverse ) enum_item( f );
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
m_pNode[0]->EnumItem( f, bReverse );
|
|
m_pNode[1]->EnumItem( f, bReverse );
|
|
m_pNode[2]->EnumItem( f, bReverse );
|
|
m_pNode[3]->EnumItem( f, bReverse );
|
|
}
|
|
|
|
if( bReverse ) enum_item( f );
|
|
}
|
|
|
|
size_t getItemCount() const
|
|
{
|
|
size_t total = 0;
|
|
|
|
if( hasChildNode() )
|
|
{
|
|
total += m_pNode[0]->getItemCount();
|
|
total += m_pNode[1]->getItemCount();
|
|
total += m_pNode[2]->getItemCount();
|
|
total += m_pNode[3]->getItemCount();
|
|
}
|
|
|
|
return total + m_vList.size();
|
|
}
|
|
|
|
private:
|
|
|
|
Node()
|
|
{
|
|
m_pNode[0] = NULL;
|
|
m_pNode[1] = NULL;
|
|
m_pNode[2] = NULL;
|
|
m_pNode[3] = NULL;
|
|
}
|
|
|
|
Node* getFitNode( const U & u )
|
|
{
|
|
if( LOOSE )
|
|
{
|
|
if( m_pNode[0]->IsAddable( u ) ) return m_pNode[0];
|
|
else if( m_pNode[1]->IsAddable( u ) ) return m_pNode[1];
|
|
else if( m_pNode[2]->IsAddable( u ) ) return m_pNode[2];
|
|
else if( m_pNode[3]->IsAddable( u ) ) return m_pNode[3];
|
|
else return NULL;
|
|
}
|
|
|
|
bool bA0 = m_pNode[0]->IsAddable( u );
|
|
bool bA1 = m_pNode[1]->IsAddable( u );
|
|
bool bA2 = m_pNode[2]->IsAddable( u );
|
|
bool bA3 = m_pNode[3]->IsAddable( u );
|
|
|
|
if( bA1 && bA2 && !bA0 && !bA3 ) return m_pNode[1];
|
|
if( bA2 && bA3 && !bA0 && !bA1 ) return m_pNode[2];
|
|
if( bA3 && bA0 && !bA1 && !bA2 ) return m_pNode[3];
|
|
|
|
if( bA0 ) return m_pNode[0];
|
|
if( bA1 ) return m_pNode[1];
|
|
if( bA2 ) return m_pNode[2];
|
|
if( bA3 ) return m_pNode[3];
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void add( const U & u )
|
|
{
|
|
m_vList.push_back( u );
|
|
|
|
if( m_vList.size() >= THRESHOLD && m_unDepth < MAX_DEPTH ) divide();
|
|
}
|
|
|
|
template< typename F >
|
|
void duplicate_add( const U & u, F & f )
|
|
{
|
|
m_vList.push_back( u );
|
|
|
|
if( m_vList.size() >= THRESHOLD && m_unDepth < MAX_DEPTH ) duplicate_divide( f );
|
|
}
|
|
|
|
void operator()( const U & u )
|
|
{
|
|
m_vList.push_back( u );
|
|
}
|
|
|
|
void join()
|
|
{
|
|
if( !hasChildNode() ) return;
|
|
|
|
m_pNode[0]->Enum( *this );
|
|
m_pNode[1]->Enum( *this );
|
|
m_pNode[2]->Enum( *this );
|
|
m_pNode[3]->Enum( *this );
|
|
|
|
delete m_pNode[0];
|
|
delete m_pNode[1];
|
|
delete m_pNode[2];
|
|
delete m_pNode[3];
|
|
|
|
m_pNode[0] = NULL;
|
|
m_pNode[1] = NULL;
|
|
m_pNode[2] = NULL;
|
|
m_pNode[3] = NULL;
|
|
}
|
|
|
|
void divide()
|
|
{
|
|
if( hasChildNode() ) return;
|
|
|
|
m_pNode[0] = new Node;
|
|
m_pNode[1] = new Node;
|
|
m_pNode[2] = new Node;
|
|
m_pNode[3] = new Node;
|
|
|
|
if( LOOSE )
|
|
{
|
|
T quad_width = m_rcEffectiveArea.GetWidth() / 4;
|
|
T quad_height = m_rcEffectiveArea.GetHeight() / 4;
|
|
|
|
T width = m_rcEffectiveArea.GetWidth() - quad_width;
|
|
T height = m_rcEffectiveArea.GetHeight() - quad_height;
|
|
|
|
m_pNode[0]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop(), width, height );
|
|
m_pNode[1]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + quad_width, m_rcEffectiveArea.GetTop(), width, height );
|
|
m_pNode[2]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop() + quad_height, width, height );
|
|
m_pNode[3]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + quad_width, m_rcEffectiveArea.GetTop() + quad_height, width, height );
|
|
}
|
|
else
|
|
{
|
|
T half_width = m_rcEffectiveArea.GetWidth() / 2;
|
|
T half_height = m_rcEffectiveArea.GetHeight() / 2;
|
|
|
|
m_pNode[0]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop(), half_width, half_height );
|
|
m_pNode[1]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + half_width, m_rcEffectiveArea.GetTop(), half_width, half_height );
|
|
m_pNode[2]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop() + half_height, m_rcEffectiveArea.GetWidth() - half_width, m_rcEffectiveArea.GetHeight() - half_height );
|
|
m_pNode[3]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + half_width, m_rcEffectiveArea.GetTop() + half_height, m_rcEffectiveArea.GetWidth() - half_width, m_rcEffectiveArea.GetHeight() - half_height );
|
|
}
|
|
|
|
std::vector< U > vTmpList;
|
|
vTmpList.reserve( m_vList.size() );
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); ++it )
|
|
{
|
|
Node *pNode = getFitNode( *it );
|
|
if( pNode )
|
|
{
|
|
pNode->Add( *it );
|
|
continue;
|
|
}
|
|
|
|
vTmpList.push_back( *it );
|
|
}
|
|
|
|
m_vList.erase( m_vList.begin(), m_vList.end() );
|
|
m_vList.assign( vTmpList.begin(), vTmpList.end() );
|
|
}
|
|
|
|
|
|
template< typename F >
|
|
void duplicate_divide( F & f )
|
|
{
|
|
if( hasChildNode() ) return;
|
|
|
|
m_pNode[0] = new Node;
|
|
m_pNode[1] = new Node;
|
|
m_pNode[2] = new Node;
|
|
m_pNode[3] = new Node;
|
|
|
|
if( LOOSE )
|
|
{
|
|
T quad_width = m_rcEffectiveArea.GetWidth() / 4;
|
|
T quad_height = m_rcEffectiveArea.GetHeight() / 4;
|
|
|
|
T width = m_rcEffectiveArea.GetWidth() - quad_width;
|
|
T height = m_rcEffectiveArea.GetHeight() - quad_height;
|
|
|
|
m_pNode[0]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop(), width, height );
|
|
m_pNode[1]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + quad_width, m_rcEffectiveArea.GetTop(), width, height );
|
|
m_pNode[2]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop() + quad_height, width, height );
|
|
m_pNode[3]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + quad_width, m_rcEffectiveArea.GetTop() + quad_height, width, height );
|
|
}
|
|
else
|
|
{
|
|
T half_width = m_rcEffectiveArea.GetWidth() / 2;
|
|
T half_height = m_rcEffectiveArea.GetHeight() / 2;
|
|
|
|
m_pNode[0]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop(), half_width, half_height );
|
|
m_pNode[1]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + half_width, m_rcEffectiveArea.GetTop(), half_width, half_height );
|
|
m_pNode[2]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft(), m_rcEffectiveArea.GetTop() + half_height, m_rcEffectiveArea.GetWidth() - half_width, m_rcEffectiveArea.GetHeight() - half_height );
|
|
m_pNode[3]->init( m_unDepth + 1, m_rcEffectiveArea.GetLeft() + half_width, m_rcEffectiveArea.GetTop() + half_height, m_rcEffectiveArea.GetWidth() - half_width, m_rcEffectiveArea.GetHeight() - half_height );
|
|
}
|
|
|
|
std::vector< U > vTmpList;
|
|
vTmpList.reserve( m_vList.size() );
|
|
|
|
for( std::vector< U >::iterator it = m_vList.begin(); it != m_vList.end(); ++it )
|
|
{
|
|
bool Added( false );
|
|
if( m_pNode[ 0 ]->IsAddable( *it, f ) ) { m_pNode[ 0 ]->DuplicateAdd( *it, f ); Added = true; }
|
|
if( m_pNode[ 1 ]->IsAddable( *it, f ) ) { m_pNode[ 1 ]->DuplicateAdd( *it, f ); Added = true; }
|
|
if( m_pNode[ 2 ]->IsAddable( *it, f ) ) { m_pNode[ 2 ]->DuplicateAdd( *it, f ); Added = true; }
|
|
if( m_pNode[ 3 ]->IsAddable( *it, f ) ) { m_pNode[ 3 ]->DuplicateAdd( *it, f ); Added = true; }
|
|
if( Added ) continue;
|
|
|
|
vTmpList.push_back( *it );
|
|
}
|
|
|
|
m_vList.erase( m_vList.begin(), m_vList.end() );
|
|
m_vList.assign( vTmpList.begin(), vTmpList.end() );
|
|
}
|
|
|
|
|
|
void init( unsigned short depth, const T & left, const T & top, const T & width, const T & height )
|
|
{
|
|
m_rcEffectiveArea.Set( left, top, width, height );
|
|
|
|
m_unDepth = depth;
|
|
}
|
|
|
|
std::vector< U > m_vList;
|
|
Rect< T > m_rcEffectiveArea;
|
|
struct Node* m_pNode[4];
|
|
unsigned short m_unDepth;
|
|
};
|
|
|
|
struct _FUNCTOR_ADAPTOR
|
|
{
|
|
std::vector< U > * pResult;
|
|
void operator()( const U & item )
|
|
{
|
|
pResult->push_back( item );
|
|
}
|
|
};
|
|
|
|
struct Node m_masterNode;
|
|
};
|
|
|
|
}; // namespace X2D
|