diff --git a/common/view/view.cpp b/common/view/view.cpp index f24a248c0b..8bde0d5aca 100644 --- a/common/view/view.cpp +++ b/common/view/view.cpp @@ -153,10 +153,12 @@ struct queryVisitor { } - void operator()( VIEW_ITEM* aItem ) + bool operator()( VIEW_ITEM* aItem ) { if( aItem->ViewIsVisible() ) m_cont.push_back( VIEW::LAYER_ITEM_PAIR( aItem, m_layer ) ); + + return true; } Container& m_cont; @@ -387,7 +389,7 @@ struct VIEW::updateItemsColor { } - void operator()( VIEW_ITEM* aItem ) + bool operator()( VIEW_ITEM* aItem ) { // Obtain the color that should be used for coloring the item const COLOR4D color = painter->GetSettings()->GetColor( aItem, layer ); @@ -395,6 +397,8 @@ struct VIEW::updateItemsColor if( group >= 0 ) gal->ChangeGroupColor( group, color ); + + return true; } int layer; @@ -447,12 +451,14 @@ struct VIEW::changeItemsDepth { } - void operator()( VIEW_ITEM* aItem ) + bool operator()( VIEW_ITEM* aItem ) { int group = aItem->getGroup( layer ); if( group >= 0 ) gal->ChangeGroupDepth( group, depth ); + + return true; } int layer, depth; @@ -571,15 +577,17 @@ struct VIEW::drawItem { } - void operator()( VIEW_ITEM* aItem ) + bool operator()( VIEW_ITEM* aItem ) { // Conditions that have te be fulfilled for an item to be drawn bool drawCondition = aItem->ViewIsVisible() && aItem->ViewGetLOD( currentLayer->id ) < view->m_scale; if( !drawCondition ) - return; + return true; view->draw( aItem, currentLayer->id ); + + return true; } const VIEW_LAYER* currentLayer; @@ -676,9 +684,11 @@ bool VIEW::IsDirty() const struct VIEW::unlinkItem { - void operator()( VIEW_ITEM* aItem ) + bool operator()( VIEW_ITEM* aItem ) { aItem->m_view = NULL; + + return true; } }; @@ -690,7 +700,7 @@ struct VIEW::recacheItem { } - void operator()( VIEW_ITEM* aItem ) + bool operator()( VIEW_ITEM* aItem ) { // Remove previously cached group int prevGroup = aItem->getGroup( layer ); @@ -712,6 +722,8 @@ struct VIEW::recacheItem { aItem->setGroup( layer, -1 ); } + + return true; } VIEW* view; @@ -792,12 +804,14 @@ struct VIEW::clearLayerCache { } - void operator()( VIEW_ITEM* aItem ) + bool operator()( VIEW_ITEM* aItem ) { if( aItem->storesGroups() ) { aItem->deleteGroups(); } + + return true; } VIEW* view; diff --git a/include/geometry/rtree.h b/include/geometry/rtree.h index efc0f6e082..6d5a5561d7 100644 --- a/include/geometry/rtree.h +++ b/include/geometry/rtree.h @@ -163,7 +163,7 @@ public: /// Calculate Statistics - Statistics CalcStats( ); + Statistics CalcStats(); /// Remove all entries from tree void RemoveAll(); @@ -396,7 +396,7 @@ protected: bool IsInternalNode() { return m_level > 0; } // Not a leaf, but a internal node bool IsLeaf() { return m_level == 0; } // A leaf, contains data - int m_count; ///< Count + int m_count; ///< Count int m_level; ///< Leaf is zero, others positive Branch m_branch[MAXNODES]; ///< Branch }; @@ -830,18 +830,18 @@ RTREE_TEMPLATE bool RTREE_QUAL::Load( RTFileStream& a_stream ) { // Write some kind of header - int _dataFileId = ('R' << 0) | ('T' << 8) | ('R' << 16) | ('E' << 24); - int _dataSize = sizeof(DATATYPE); - int _dataNumDims = NUMDIMS; - int _dataElemSize = sizeof(ELEMTYPE); + int _dataFileId = ('R' << 0) | ('T' << 8) | ('R' << 16) | ('E' << 24); + int _dataSize = sizeof(DATATYPE); + int _dataNumDims = NUMDIMS; + int _dataElemSize = sizeof(ELEMTYPE); int _dataElemRealSize = sizeof(ELEMTYPEREAL); int _dataMaxNodes = TMAXNODES; int _dataMinNodes = TMINNODES; - int dataFileId = 0; - int dataSize = 0; - int dataNumDims = 0; - int dataElemSize = 0; + int dataFileId = 0; + int dataSize = 0; + int dataNumDims = 0; + int dataElemSize = 0; int dataElemRealSize = 0; int dataMaxNodes = 0; int dataMinNodes = 0; @@ -932,10 +932,10 @@ RTREE_TEMPLATE bool RTREE_QUAL::Save( RTFileStream& a_stream ) { // Write some kind of header - int dataFileId = ('R' << 0) | ('T' << 8) | ('R' << 16) | ('E' << 24); - int dataSize = sizeof(DATATYPE); - int dataNumDims = NUMDIMS; - int dataElemSize = sizeof(ELEMTYPE); + int dataFileId = ('R' << 0) | ('T' << 8) | ('R' << 16) | ('E' << 24); + int dataSize = sizeof(DATATYPE); + int dataNumDims = NUMDIMS; + int dataElemSize = sizeof(ELEMTYPE); int dataElemRealSize = sizeof(ELEMTYPEREAL); int dataMaxNodes = TMAXNODES; int dataMinNodes = TMINNODES; @@ -1286,27 +1286,27 @@ int RTREE_QUAL::PickBranch( Rect* a_rect, Node* a_node ) ELEMTYPEREAL increase; ELEMTYPEREAL bestIncr = (ELEMTYPEREAL) -1; ELEMTYPEREAL area; - ELEMTYPEREAL bestArea; + ELEMTYPEREAL bestArea = 0; int best = 0; Rect tempRect; for( int index = 0; index < a_node->m_count; ++index ) { Rect* curRect = &a_node->m_branch[index].m_rect; - area = CalcRectVolume( curRect ); + area = CalcRectVolume( curRect ); tempRect = CombineRect( a_rect, curRect ); increase = CalcRectVolume( &tempRect ) - area; if( (increase < bestIncr) || firstTime ) { - best = index; + best = index; bestArea = area; bestIncr = increase; firstTime = false; } else if( (increase == bestIncr) && (area < bestArea) ) { - best = index; + best = index; bestArea = area; bestIncr = increase; } @@ -1594,8 +1594,8 @@ void RTREE_QUAL::InitParVars( PartitionVars* a_parVars, int a_maxRects, int a_mi for( int index = 0; index < a_maxRects; ++index ) { - a_parVars->m_taken[index] = false; - a_parVars->m_partition[index] = -1; + a_parVars->m_taken[index] = false; + a_parVars->m_partition[index] = -1; } } @@ -1622,7 +1622,7 @@ void RTREE_QUAL::PickSeeds( PartitionVars* a_parVars ) &a_parVars->m_branchBuf[indexB].m_rect ); waste = CalcRectVolume( &oneRect ) - area[indexA] - area[indexB]; - if( waste > worst ) + if( waste >= worst ) { worst = waste; seed0 = indexA; @@ -1856,8 +1856,6 @@ bool RTREE_QUAL::Search( Node* a_node, Rect* a_rect, int& a_foundCount, bool a_r } - - //calculate the minimum distance between a point and a rectangle as defined by Manolopoulos et al. //it uses the square distance to avoid the use of ELEMTYPEREAL values, which are slower. RTREE_TEMPLATE diff --git a/include/rtree.h b/include/rtree.h deleted file mode 100644 index cfb6c86d3c..0000000000 --- a/include/rtree.h +++ /dev/null @@ -1,1758 +0,0 @@ -/* - * R-Tree index - * - * from http://www.superliminal.com/ - * - * LICENSE : Entirely free for all uses. Enjoy! - * - * AUTORS - * - 1983 Original algorithm and test code by Antonin Guttman and Michael Stonebraker, UC Berkely - * - 1994 ANCI C ported from original test code by Melinda Green - melinda@superliminal.com - * - 1995 Sphere volume fix for degeneracy problem submitted by Paul Brook - * - 2004 Templated C++ port by Greg Douglas - * - 2008 Portability issues fixed by Maxence Laurent - */ - -#ifndef RTREE_H -#define RTREE_H - -// NOTE This file compiles under MSVC 6 SP5 and MSVC .Net 2003 it may not work on other compilers without modification. - -// NOTE These next few lines may be win32 specific, you may need to modify them to compile on other platform -#include -#include -#include -#include - -#define ASSERT assert // RTree uses ASSERT( condition ) -#ifndef Min - #define Min std::min -#endif // Min -#ifndef Max - #define Max std::max -#endif // Max - -// -// RTree.h -// - -#define RTREE_TEMPLATE template -#define RTREE_SEARCH_TEMPLATE template -#define RTREE_QUAL RTree -#define RTREE_SEARCH_QUAL RTree - -#define RTREE_DONT_USE_MEMPOOLS // This version does not contain a fixed memory allocator, fill in lines with EXAMPLE to implement one. -#define RTREE_USE_SPHERICAL_VOLUME // Better split classification, may be slower on some systems - -// Fwd decl -class RTFileStream; // File I/O helper class, look below for implementation and notes. - - -/// \class RTree -/// Implementation of RTree, a multidimensional bounding rectangle tree. -/// Example usage: For a 3-dimensional tree use RTree myTree; -/// -/// This modified, templated C++ version by Greg Douglas at Auran (http://www.auran.com) -/// -/// DATATYPE Referenced data, should be int, void*, obj* etc. no larger than sizeof and simple type -/// ELEMTYPE Type of element such as int or float -/// NUMDIMS Number of dimensions such as 2 or 3 -/// ELEMTYPEREAL Type of element that allows fractional and large values such as float or double, for use in volume calcs -/// -/// NOTES: Inserting and removing data requires the knowledge of its constant Minimal Bounding Rectangle. -/// This version uses new/delete for nodes, I recommend using a fixed size allocator for efficiency. -/// Instead of using a callback function for returned results, I recommend and efficient pre-sized, grow-only memory -/// array similar to MFC CArray or STL Vector for returning search query result. -/// -template -class RTree -{ -protected: - - struct Node; // Fwd decl. Used by other internal structs and iterator -public: - - // These constant must be declared after Branch and before Node struct - // Stuck up here for MSVC 6 compiler. NSVC .NET 2003 is much happier. - enum { - MAXNODES = TMAXNODES, ///< Max elements in node - MINNODES = TMINNODES, ///< Min elements in node - }; -public: - - RTree(); - virtual ~RTree(); - - /// Insert entry - /// \param a_min Min of bounding rect - /// \param a_max Max of bounding rect - /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. - void Insert( const ELEMTYPE a_min[NUMDIMS], - const ELEMTYPE a_max[NUMDIMS], - const DATATYPE& a_dataId ); - - /// Remove entry - /// \param a_min Min of bounding rect - /// \param a_max Max of bounding rect - /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. - void Remove( const ELEMTYPE a_min[NUMDIMS], - const ELEMTYPE a_max[NUMDIMS], - const DATATYPE& a_dataId ); - - /// Find all within search rectangle - /// \param a_min Min of search bounding rect - /// \param a_max Max of search bounding rect - /// \param a_searchResult Search result array. Caller should set grow size. Function will reset, not append to array. - /// \param a_resultCallback Callback function to return result. Callback should return 'true' to continue searching - /// \param a_context User context to pass as parameter to a_resultCallback - /// \return Returns the number of entries found - int Search( const ELEMTYPE a_min[NUMDIMS], - const ELEMTYPE a_max[NUMDIMS], - bool a_resultCallback( DATATYPE a_data, void* a_context ), - void* a_context ); - - template - int Search( const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], VISITOR& a_visitor ) - { - #ifdef _DEBUG - - for( int index = 0; index 0; } - - /// Access the current data element. Caller must be sure iterator is not NULL first. - DATATYPE& operator*() - { - ASSERT( IsNotNull() ); - StackElement& curTos = m_stack[m_tos - 1]; - return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; - } - - /// Access the current data element. Caller must be sure iterator is not NULL first. - const DATATYPE& operator*() const - { - ASSERT( IsNotNull() ); - StackElement& curTos = m_stack[m_tos - 1]; - return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; - } - - /// Find the next data element - bool operator++() { return FindNextData(); } - - /// Get the bounds for this node - void GetBounds( ELEMTYPE a_min[NUMDIMS], ELEMTYPE a_max[NUMDIMS] ) - { - ASSERT( IsNotNull() ); - StackElement& curTos = m_stack[m_tos - 1]; - Branch& curBranch = curTos.m_node->m_branch[curTos.m_branchIndex]; - - for( int index = 0; index < NUMDIMS; ++index ) - { - a_min[index] = curBranch.m_rect.m_min[index]; - a_max[index] = curBranch.m_rect.m_max[index]; - } - } - -private: - - /// Reset iterator - void Init() { m_tos = 0; } - - /// Find the next data element in the tree (For internal use only) - bool FindNextData() - { - for( ; ; ) - { - if( m_tos <= 0 ) - { - return false; - } - - StackElement curTos = Pop(); // Copy stack top cause it may change as we use it - - if( curTos.m_node->IsLeaf() ) - { - // Keep walking through data while we can - if( curTos.m_branchIndex + 1 < curTos.m_node->m_count ) - { - // There is more data, just point to the next one - Push( curTos.m_node, curTos.m_branchIndex + 1 ); - return true; - } - - // No more data, so it will fall back to previous level - } - else - { - if( curTos.m_branchIndex + 1 < curTos.m_node->m_count ) - { - // Push sibling on for future tree walk - // This is the 'fall back' node when we finish with the current level - Push( curTos.m_node, curTos.m_branchIndex + 1 ); - } - - // Since cur node is not a leaf, push first of next level to get deeper into the tree - Node* nextLevelnode = curTos.m_node->m_branch[curTos.m_branchIndex].m_child; - Push( nextLevelnode, 0 ); - - // If we pushed on a new leaf, exit as the data is ready at TOS - if( nextLevelnode->IsLeaf() ) - { - return true; - } - } - } - } - - /// Push node and branch onto iteration stack (For internal use only) - void Push( Node* a_node, int a_branchIndex ) - { - m_stack[m_tos].m_node = a_node; - m_stack[m_tos].m_branchIndex = a_branchIndex; - ++m_tos; - ASSERT( m_tos <= MAX_STACK ); - } - - /// Pop element off iteration stack (For internal use only) - StackElement& Pop() - { - ASSERT( m_tos > 0 ); - --m_tos; - return m_stack[m_tos]; - } - - StackElement m_stack[MAX_STACK]; ///< Stack as we are doing iteration instead of recursion - int m_tos; ///< Top Of Stack index - - friend class RTree; // Allow hiding of non-public functions while allowing manipulation by logical owner - }; - - - /// Get 'first' for iteration - void GetFirst( Iterator& a_it ) - { - a_it.Init(); - Node* first = m_root; - - while( first ) - { - if( first->IsInternalNode() && first->m_count > 1 ) - { - a_it.Push( first, 1 ); // Descend sibling branch later - } - else if( first->IsLeaf() ) - { - if( first->m_count ) - { - a_it.Push( first, 0 ); - } - - break; - } - - first = first->m_branch[0].m_child; - } - } - - /// Get Next for iteration - void GetNext( Iterator& a_it ) { ++a_it; } - - /// Is iterator NULL, or at end? - bool IsNull( Iterator& a_it ) { return a_it.IsNull(); } - - /// Get object at iterator position - DATATYPE& GetAt( Iterator& a_it ) { return *a_it; } -protected: - - /// Minimal bounding rectangle (n-dimensional) - struct Rect - { - ELEMTYPE m_min[NUMDIMS]; ///< Min dimensions of bounding box - ELEMTYPE m_max[NUMDIMS]; ///< Max dimensions of bounding box - }; - - /// May be data or may be another subtree - /// The parents level determines this. - /// If the parents level is 0, then this is data - struct Branch - { - Rect m_rect; ///< Bounds - union - { - Node* m_child; ///< Child node - DATATYPE m_data; ///< Data Id or Ptr - }; - }; - - /// Node for each branch level - struct Node - { - bool IsInternalNode() { return m_level > 0; } // Not a leaf, but a internal node - bool IsLeaf() { return m_level == 0; } // A leaf, contains data - - int m_count; ///< Count - int m_level; ///< Leaf is zero, others positive - Branch m_branch[MAXNODES]; ///< Branch - }; - - /// A link list of nodes for reinsertion after a delete operation - struct ListNode - { - ListNode* m_next; ///< Next in list - Node* m_node; ///< Node - }; - - /// Variables for finding a split partition - struct PartitionVars - { - int m_partition[MAXNODES + 1]; - int m_total; - int m_minFill; - int m_taken[MAXNODES + 1]; - int m_count[2]; - Rect m_cover[2]; - ELEMTYPEREAL m_area[2]; - - Branch m_branchBuf[MAXNODES + 1]; - int m_branchCount; - Rect m_coverSplit; - ELEMTYPEREAL m_coverSplitArea; - }; - - Node* AllocNode(); - void FreeNode( Node* a_node ); - void InitNode( Node* a_node ); - void InitRect( Rect* a_rect ); - bool InsertRectRec( Rect* a_rect, - const DATATYPE& a_id, - Node* a_node, - Node** a_newNode, - int a_level ); - bool InsertRect( Rect* a_rect, const DATATYPE& a_id, Node** a_root, int a_level ); - Rect NodeCover( Node* a_node ); - bool AddBranch( Branch* a_branch, Node* a_node, Node** a_newNode ); - void DisconnectBranch( Node* a_node, int a_index ); - int PickBranch( Rect* a_rect, Node* a_node ); - Rect CombineRect( Rect* a_rectA, Rect* a_rectB ); - void SplitNode( Node* a_node, Branch* a_branch, Node** a_newNode ); - ELEMTYPEREAL RectSphericalVolume( Rect* a_rect ); - ELEMTYPEREAL RectVolume( Rect* a_rect ); - ELEMTYPEREAL CalcRectVolume( Rect* a_rect ); - void GetBranches( Node* a_node, Branch* a_branch, PartitionVars* a_parVars ); - void ChoosePartition( PartitionVars* a_parVars, int a_minFill ); - void LoadNodes( Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars ); - void InitParVars( PartitionVars* a_parVars, int a_maxRects, int a_minFill ); - void PickSeeds( PartitionVars* a_parVars ); - void Classify( int a_index, int a_group, PartitionVars* a_parVars ); - bool RemoveRect( Rect* a_rect, const DATATYPE& a_id, Node** a_root ); - bool RemoveRectRec( Rect* a_rect, - const DATATYPE& a_id, - Node* a_node, - ListNode** a_listNode ); - ListNode* AllocListNode(); - void FreeListNode( ListNode* a_listNode ); - bool Overlap( Rect* a_rectA, Rect* a_rectB ); - void ReInsert( Node* a_node, ListNode** a_listNode ); - - bool Search( Node * a_node, Rect * a_rect, int& a_foundCount, bool a_resultCallback( - DATATYPE a_data, - void* a_context ), void* a_context ); - - template - bool Search( Node* a_node, Rect* a_rect, VISITOR& a_visitor ) - { - ASSERT( a_node ); - ASSERT( a_node->m_level >= 0 ); - ASSERT( a_rect ); - - if( a_node->IsInternalNode() ) // This is an internal node in the tree - { - for( int index = 0; index < a_node->m_count; ++index ) - { - if( Overlap( a_rect, &a_node->m_branch[index].m_rect ) ) - { - if( !Search( a_node->m_branch[index].m_child, a_rect, a_visitor ) ) - { - return false; // Don't continue searching - } - } - } - } - else // This is a leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - if( Overlap( a_rect, &a_node->m_branch[index].m_rect ) ) - { - DATATYPE& id = a_node->m_branch[index].m_data; - - a_visitor( id ); - } - } - } - - return true; // Continue searching - } - - void RemoveAllRec( Node* a_node ); - void Reset(); - void CountRec( Node* a_node, int& a_count ); - - bool SaveRec( Node* a_node, RTFileStream& a_stream ); - bool LoadRec( Node* a_node, RTFileStream& a_stream ); - - Node* m_root; ///< Root of tree - ELEMTYPEREAL m_unitSphereVolume; ///< Unit sphere constant for required number of dimensions -}; - - -// Because there is not stream support, this is a quick and dirty file I/O helper. -// Users will likely replace its usage with a Stream implementation from their favorite API. -class RTFileStream -{ - FILE* m_file; -public: - - - RTFileStream() - { - m_file = NULL; - } - - ~RTFileStream() - { - Close(); - } - - bool OpenRead( const char* a_fileName ) - { - m_file = fopen( a_fileName, "rb" ); - - if( !m_file ) - { - return false; - } - - return true; - } - - bool OpenWrite( const char* a_fileName ) - { - m_file = fopen( a_fileName, "wb" ); - - if( !m_file ) - { - return false; - } - - return true; - } - - void Close() - { - if( m_file ) - { - fclose( m_file ); - m_file = NULL; - } - } - - template - size_t Write( const TYPE& a_value ) - { - ASSERT( m_file ); - return fwrite( (void*) &a_value, sizeof(a_value), 1, m_file ); - } - - template - size_t WriteArray( const TYPE* a_array, int a_count ) - { - ASSERT( m_file ); - return fwrite( (void*) a_array, sizeof(TYPE) * a_count, 1, m_file ); - } - - template - size_t Read( TYPE& a_value ) - { - ASSERT( m_file ); - return fread( (void*) &a_value, sizeof(a_value), 1, m_file ); - } - - template - size_t ReadArray( TYPE* a_array, int a_count ) - { - ASSERT( m_file ); - return fread( (void*) a_array, sizeof(TYPE) * a_count, 1, m_file ); - } -}; - - -RTREE_TEMPLATE RTREE_QUAL::RTree() -{ - ASSERT( MAXNODES > MINNODES ); - ASSERT( MINNODES > 0 ); - - - // We only support machine word size simple data type eg. integer index or object pointer. - // Since we are storing as union with non data branch - ASSERT( sizeof(DATATYPE) == sizeof(void*) || sizeof(DATATYPE) == sizeof(int) ); - - // Precomputed volumes of the unit spheres for the first few dimensions - const float UNIT_SPHERE_VOLUMES[] = - { - 0.000000f, 2.000000f, 3.141593f, // Dimension 0,1,2 - 4.188790f, 4.934802f, 5.263789f, // Dimension 3,4,5 - 5.167713f, 4.724766f, 4.058712f, // Dimension 6,7,8 - 3.298509f, 2.550164f, 1.884104f, // Dimension 9,10,11 - 1.335263f, 0.910629f, 0.599265f, // Dimension 12,13,14 - 0.381443f, 0.235331f, 0.140981f, // Dimension 15,16,17 - 0.082146f, 0.046622f, 0.025807f, // Dimension 18,19,20 - }; - - m_root = AllocNode(); - m_root->m_level = 0; - m_unitSphereVolume = (ELEMTYPEREAL) UNIT_SPHERE_VOLUMES[NUMDIMS]; -} - - -RTREE_TEMPLATE -RTREE_QUAL::~RTree() { - Reset(); // Free, or reset node memory -} - - -RTREE_TEMPLATE -void RTREE_QUAL::Insert( const ELEMTYPE a_min[NUMDIMS], - const ELEMTYPE a_max[NUMDIMS], - const DATATYPE& a_dataId ) -{ -#ifdef _DEBUG - - for( int index = 0; indexIsInternalNode() ) // not a leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - CountRec( a_node->m_branch[index].m_child, a_count ); - } - } - else // A leaf node - { - a_count += a_node->m_count; - } -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::Load( const char* a_fileName ) -{ - RemoveAll(); // Clear existing tree - - RTFileStream stream; - - if( !stream.OpenRead( a_fileName ) ) - { - return false; - } - - bool result = Load( stream ); - - stream.Close(); - - return result; -}; - - -RTREE_TEMPLATE -bool RTREE_QUAL::Load( RTFileStream& a_stream ) -{ - // Write some kind of header - int _dataFileId = ('R' << 0) | ('T' << 8) | ('R' << 16) | ('E' << 24); - int _dataSize = sizeof(DATATYPE); - int _dataNumDims = NUMDIMS; - int _dataElemSize = sizeof(ELEMTYPE); - int _dataElemRealSize = sizeof(ELEMTYPEREAL); - int _dataMaxNodes = TMAXNODES; - int _dataMinNodes = TMINNODES; - - int dataFileId = 0; - int dataSize = 0; - int dataNumDims = 0; - int dataElemSize = 0; - int dataElemRealSize = 0; - int dataMaxNodes = 0; - int dataMinNodes = 0; - - a_stream.Read( dataFileId ); - a_stream.Read( dataSize ); - a_stream.Read( dataNumDims ); - a_stream.Read( dataElemSize ); - a_stream.Read( dataElemRealSize ); - a_stream.Read( dataMaxNodes ); - a_stream.Read( dataMinNodes ); - - bool result = false; - - // Test if header was valid and compatible - if( (dataFileId == _dataFileId) - && (dataSize == _dataSize) - && (dataNumDims == _dataNumDims) - && (dataElemSize == _dataElemSize) - && (dataElemRealSize == _dataElemRealSize) - && (dataMaxNodes == _dataMaxNodes) - && (dataMinNodes == _dataMinNodes) - ) - { - // Recursively load tree - result = LoadRec( m_root, a_stream ); - } - - return result; -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::LoadRec( Node* a_node, RTFileStream& a_stream ) -{ - a_stream.Read( a_node->m_level ); - a_stream.Read( a_node->m_count ); - - if( a_node->IsInternalNode() ) // not a leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.ReadArray( curBranch->m_rect.m_min, NUMDIMS ); - a_stream.ReadArray( curBranch->m_rect.m_max, NUMDIMS ); - - curBranch->m_child = AllocNode(); - LoadRec( curBranch->m_child, a_stream ); - } - } - else // A leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.ReadArray( curBranch->m_rect.m_min, NUMDIMS ); - a_stream.ReadArray( curBranch->m_rect.m_max, NUMDIMS ); - - a_stream.Read( curBranch->m_data ); - } - } - - return true; // Should do more error checking on I/O operations -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::Save( const char* a_fileName ) -{ - RTFileStream stream; - - if( !stream.OpenWrite( a_fileName ) ) - { - return false; - } - - bool result = Save( stream ); - - stream.Close(); - - return result; -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::Save( RTFileStream& a_stream ) -{ - // Write some kind of header - int dataFileId = ('R' << 0) | ('T' << 8) | ('R' << 16) | ('E' << 24); - int dataSize = sizeof(DATATYPE); - int dataNumDims = NUMDIMS; - int dataElemSize = sizeof(ELEMTYPE); - int dataElemRealSize = sizeof(ELEMTYPEREAL); - int dataMaxNodes = TMAXNODES; - int dataMinNodes = TMINNODES; - - a_stream.Write( dataFileId ); - a_stream.Write( dataSize ); - a_stream.Write( dataNumDims ); - a_stream.Write( dataElemSize ); - a_stream.Write( dataElemRealSize ); - a_stream.Write( dataMaxNodes ); - a_stream.Write( dataMinNodes ); - - // Recursively save tree - bool result = SaveRec( m_root, a_stream ); - - return result; -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::SaveRec( Node* a_node, RTFileStream& a_stream ) -{ - a_stream.Write( a_node->m_level ); - a_stream.Write( a_node->m_count ); - - if( a_node->IsInternalNode() ) // not a leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.WriteArray( curBranch->m_rect.m_min, NUMDIMS ); - a_stream.WriteArray( curBranch->m_rect.m_max, NUMDIMS ); - - SaveRec( curBranch->m_child, a_stream ); - } - } - else // A leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.WriteArray( curBranch->m_rect.m_min, NUMDIMS ); - a_stream.WriteArray( curBranch->m_rect.m_max, NUMDIMS ); - - a_stream.Write( curBranch->m_data ); - } - } - - return true; // Should do more error checking on I/O operations -} - - -RTREE_TEMPLATE -void RTREE_QUAL::RemoveAll() -{ - // Delete all existing nodes - Reset(); - - m_root = AllocNode(); - m_root->m_level = 0; -} - - -RTREE_TEMPLATE -void RTREE_QUAL::Reset() -{ -#ifdef RTREE_DONT_USE_MEMPOOLS - // Delete all existing nodes - RemoveAllRec( m_root ); -#else // RTREE_DONT_USE_MEMPOOLS - // Just reset memory pools. We are not using complex types - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -RTREE_TEMPLATE -void RTREE_QUAL::RemoveAllRec( Node* a_node ) -{ - ASSERT( a_node ); - ASSERT( a_node->m_level >= 0 ); - - if( a_node->IsInternalNode() ) // This is an internal node in the tree - { - for( int index = 0; index < a_node->m_count; ++index ) - { - RemoveAllRec( a_node->m_branch[index].m_child ); - } - } - - FreeNode( a_node ); -} - - -RTREE_TEMPLATE -typename RTREE_QUAL::Node* RTREE_QUAL::AllocNode() -{ - Node* newNode; - -#ifdef RTREE_DONT_USE_MEMPOOLS - newNode = new Node; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS - InitNode( newNode ); - return newNode; -} - - -RTREE_TEMPLATE -void RTREE_QUAL::FreeNode( Node* a_node ) -{ - ASSERT( a_node ); - -#ifdef RTREE_DONT_USE_MEMPOOLS - delete a_node; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -// Allocate space for a node in the list used in DeletRect to -// store Nodes that are too empty. -RTREE_TEMPLATE -typename RTREE_QUAL::ListNode* RTREE_QUAL::AllocListNode() -{ -#ifdef RTREE_DONT_USE_MEMPOOLS - return new ListNode; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -RTREE_TEMPLATE -void RTREE_QUAL::FreeListNode( ListNode* a_listNode ) -{ -#ifdef RTREE_DONT_USE_MEMPOOLS - delete a_listNode; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -RTREE_TEMPLATE -void RTREE_QUAL::InitNode( Node* a_node ) -{ - a_node->m_count = 0; - a_node->m_level = -1; -} - - -RTREE_TEMPLATE -void RTREE_QUAL::InitRect( Rect* a_rect ) -{ - for( int index = 0; index < NUMDIMS; ++index ) - { - a_rect->m_min[index] = (ELEMTYPE) 0; - a_rect->m_max[index] = (ELEMTYPE) 0; - } -} - - -// Inserts a new data rectangle into the index structure. -// Recursively descends tree, propagates splits back up. -// Returns 0 if node was not split. Old node updated. -// If node was split, returns 1 and sets the pointer pointed to by -// new_node to point to the new node. Old node updated to become one of two. -// The level argument specifies the number of steps up from the leaf -// level to insert; e.g. a data rectangle goes in at level = 0. -RTREE_TEMPLATE -bool RTREE_QUAL::InsertRectRec( Rect* a_rect, - const DATATYPE& a_id, - Node* a_node, - Node** a_newNode, - int a_level ) -{ - ASSERT( a_rect && a_node && a_newNode ); - ASSERT( a_level >= 0 && a_level <= a_node->m_level ); - - int index; - Branch branch; - Node* otherNode; - - // Still above level for insertion, go down tree recursively - if( a_node->m_level > a_level ) - { - index = PickBranch( a_rect, a_node ); - - if( !InsertRectRec( a_rect, a_id, a_node->m_branch[index].m_child, &otherNode, a_level ) ) - { - // Child was not split - a_node->m_branch[index].m_rect = - CombineRect( a_rect, &(a_node->m_branch[index].m_rect) ); - return false; - } - else // Child was split - { - a_node->m_branch[index].m_rect = NodeCover( a_node->m_branch[index].m_child ); - branch.m_child = otherNode; - branch.m_rect = NodeCover( otherNode ); - return AddBranch( &branch, a_node, a_newNode ); - } - } - else if( a_node->m_level == a_level ) // Have reached level for insertion. Add rect, split if necessary - { - branch.m_rect = *a_rect; - branch.m_child = (Node*) a_id; - // Child field of leaves contains id of data record - return AddBranch( &branch, a_node, a_newNode ); - } - else - { - // Should never occur - ASSERT( 0 ); - return false; - } -} - - -// Insert a data rectangle into an index structure. -// InsertRect provides for splitting the root; -// returns 1 if root was split, 0 if it was not. -// The level argument specifies the number of steps up from the leaf -// level to insert; e.g. a data rectangle goes in at level = 0. -// InsertRect2 does the recursion. -// -RTREE_TEMPLATE -bool RTREE_QUAL::InsertRect( Rect* a_rect, const DATATYPE& a_id, Node** a_root, int a_level ) -{ - ASSERT( a_rect && a_root ); - ASSERT( a_level >= 0 && a_level <= (*a_root)->m_level ); -#ifdef _DEBUG - - for( int index = 0; index < NUMDIMS; ++index ) - { - ASSERT( a_rect->m_min[index] <= a_rect->m_max[index] ); - } - -#endif // _DEBUG - - Node* newRoot; - Node* newNode; - Branch branch; - - if( InsertRectRec( a_rect, a_id, *a_root, &newNode, a_level ) ) // Root split - { - newRoot = AllocNode(); // Grow tree taller and new root - newRoot->m_level = (*a_root)->m_level + 1; - branch.m_rect = NodeCover( *a_root ); - branch.m_child = *a_root; - AddBranch( &branch, newRoot, NULL ); - branch.m_rect = NodeCover( newNode ); - branch.m_child = newNode; - AddBranch( &branch, newRoot, NULL ); - *a_root = newRoot; - return true; - } - - return false; -} - - -// Find the smallest rectangle that includes all rectangles in branches of a node. -RTREE_TEMPLATE -typename RTREE_QUAL::Rect RTREE_QUAL::NodeCover( Node* a_node ) -{ - ASSERT( a_node ); - - int firstTime = true; - Rect rect; - InitRect( &rect ); - - for( int index = 0; index < a_node->m_count; ++index ) - { - if( firstTime ) - { - rect = a_node->m_branch[index].m_rect; - firstTime = false; - } - else - { - rect = CombineRect( &rect, &(a_node->m_branch[index].m_rect) ); - } - } - - return rect; -} - - -// Add a branch to a node. Split the node if necessary. -// Returns 0 if node not split. Old node updated. -// Returns 1 if node split, sets *new_node to address of new node. -// Old node updated, becomes one of two. -RTREE_TEMPLATE -bool RTREE_QUAL::AddBranch( Branch* a_branch, Node* a_node, Node** a_newNode ) -{ - ASSERT( a_branch ); - ASSERT( a_node ); - - if( a_node->m_count < MAXNODES ) // Split won't be necessary - { - a_node->m_branch[a_node->m_count] = *a_branch; - ++a_node->m_count; - - return false; - } - else - { - ASSERT( a_newNode ); - - SplitNode( a_node, a_branch, a_newNode ); - return true; - } -} - - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -RTREE_TEMPLATE -void RTREE_QUAL::DisconnectBranch( Node* a_node, int a_index ) -{ - ASSERT( a_node && (a_index >= 0) && (a_index < MAXNODES) ); - ASSERT( a_node->m_count > 0 ); - - // Remove element by swapping with the last element to prevent gaps in array - a_node->m_branch[a_index] = a_node->m_branch[a_node->m_count - 1]; - - --a_node->m_count; -} - - -// Pick a branch. Pick the one that will need the smallest increase -// in area to accomodate the new rectangle. This will result in the -// least total area for the covering rectangles in the current node. -// In case of a tie, pick the one which was smaller before, to get -// the best resolution when searching. -RTREE_TEMPLATE -int RTREE_QUAL::PickBranch( Rect* a_rect, Node* a_node ) -{ - ASSERT( a_rect && a_node ); - - bool firstTime = true; - ELEMTYPEREAL increase; - ELEMTYPEREAL bestIncr = (ELEMTYPEREAL) -1; - ELEMTYPEREAL area; - ELEMTYPEREAL bestArea; - int best = 0; // avoid compil complaint about uninitialized - Rect tempRect; - - for( int index = 0; index < a_node->m_count; ++index ) - { - Rect* curRect = &a_node->m_branch[index].m_rect; - area = CalcRectVolume( curRect ); - tempRect = CombineRect( a_rect, curRect ); - increase = CalcRectVolume( &tempRect ) - area; - - if( (increase < bestIncr) || firstTime ) - { - best = index; - bestArea = area; - bestIncr = increase; - firstTime = false; - } - else if( (increase == bestIncr) && (area < bestArea) ) - { - best = index; - bestArea = area; - bestIncr = increase; - } - } - - return best; -} - - -// Combine two rectangles into larger one containing both -RTREE_TEMPLATE -typename RTREE_QUAL::Rect RTREE_QUAL::CombineRect( Rect* a_rectA, Rect* a_rectB ) -{ - ASSERT( a_rectA && a_rectB ); - - Rect newRect; - - for( int index = 0; index < NUMDIMS; ++index ) - { - newRect.m_min[index] = Min( a_rectA->m_min[index], a_rectB->m_min[index] ); - newRect.m_max[index] = Max( a_rectA->m_max[index], a_rectB->m_max[index] ); - } - - return newRect; -} - - -// Split a node. -// Divides the nodes branches and the extra one between two nodes. -// Old node is one of the new ones, and one really new one is created. -// Tries more than one method for choosing a partition, uses best result. -RTREE_TEMPLATE -void RTREE_QUAL::SplitNode( Node* a_node, Branch* a_branch, Node** a_newNode ) -{ - ASSERT( a_node ); - ASSERT( a_branch ); - - // Could just use local here, but member or external is faster since it is reused - PartitionVars localVars; - PartitionVars* parVars = &localVars; - int level; - - // Load all the branches into a buffer, initialize old node - level = a_node->m_level; - GetBranches( a_node, a_branch, parVars ); - - // Find partition - ChoosePartition( parVars, MINNODES ); - - // Put branches from buffer into 2 nodes according to chosen partition - *a_newNode = AllocNode(); - (*a_newNode)->m_level = a_node->m_level = level; - LoadNodes( a_node, *a_newNode, parVars ); - - ASSERT( (a_node->m_count + (*a_newNode)->m_count) == parVars->m_total ); -} - - -// Calculate the n-dimensional volume of a rectangle -RTREE_TEMPLATE -ELEMTYPEREAL RTREE_QUAL::RectVolume( Rect* a_rect ) -{ - ASSERT( a_rect ); - - ELEMTYPEREAL volume = (ELEMTYPEREAL) 1; - - for( int index = 0; indexm_max[index] - a_rect->m_min[index]; - } - - ASSERT( volume >= (ELEMTYPEREAL) 0 ); - - return volume; -} - - -// The exact volume of the bounding sphere for the given Rect -RTREE_TEMPLATE -ELEMTYPEREAL RTREE_QUAL::RectSphericalVolume( Rect* a_rect ) -{ - ASSERT( a_rect ); - - ELEMTYPEREAL sumOfSquares = (ELEMTYPEREAL) 0; - ELEMTYPEREAL radius; - - for( int index = 0; index < NUMDIMS; ++index ) - { - ELEMTYPEREAL halfExtent = - ( (ELEMTYPEREAL) a_rect->m_max[index] - (ELEMTYPEREAL) a_rect->m_min[index] ) * 0.5f; - sumOfSquares += halfExtent * halfExtent; - } - - radius = (ELEMTYPEREAL) sqrt( sumOfSquares ); - - // Pow maybe slow, so test for common dims like 2,3 and just use x*x, x*x*x. - if( NUMDIMS == 3 ) - { - return radius * radius * radius * m_unitSphereVolume; - } - else if( NUMDIMS == 2 ) - { - return radius * radius * m_unitSphereVolume; - } - else - { - return (ELEMTYPEREAL) (pow( radius, NUMDIMS ) * m_unitSphereVolume); - } -} - - -// Use one of the methods to calculate retangle volume -RTREE_TEMPLATE -ELEMTYPEREAL RTREE_QUAL::CalcRectVolume( Rect* a_rect ) -{ -#ifdef RTREE_USE_SPHERICAL_VOLUME - return RectSphericalVolume( a_rect ); // Slower but helps certain merge cases -#else // RTREE_USE_SPHERICAL_VOLUME - return RectVolume( a_rect ); // Faster but can cause poor merges -#endif // RTREE_USE_SPHERICAL_VOLUME -} - - -// Load branch buffer with branches from full node plus the extra branch. -RTREE_TEMPLATE -void RTREE_QUAL::GetBranches( Node* a_node, Branch* a_branch, PartitionVars* a_parVars ) -{ - ASSERT( a_node ); - ASSERT( a_branch ); - - ASSERT( a_node->m_count == MAXNODES ); - - // Load the branch buffer - for( int index = 0; index < MAXNODES; ++index ) - { - a_parVars->m_branchBuf[index] = a_node->m_branch[index]; - } - - a_parVars->m_branchBuf[MAXNODES] = *a_branch; - a_parVars->m_branchCount = MAXNODES + 1; - - // Calculate rect containing all in the set - a_parVars->m_coverSplit = a_parVars->m_branchBuf[0].m_rect; - - for( int index = 1; index < MAXNODES + 1; ++index ) - { - a_parVars->m_coverSplit = - CombineRect( &a_parVars->m_coverSplit, &a_parVars->m_branchBuf[index].m_rect ); - } - - a_parVars->m_coverSplitArea = CalcRectVolume( &a_parVars->m_coverSplit ); - - InitNode( a_node ); -} - - -// Method #0 for choosing a partition: -// As the seeds for the two groups, pick the two rects that would waste the -// most area if covered by a single rectangle, i.e. evidently the worst pair -// to have in the same group. -// Of the remaining, one at a time is chosen to be put in one of the two groups. -// The one chosen is the one with the greatest difference in area expansion -// depending on which group - the rect most strongly attracted to one group -// and repelled from the other. -// If one group gets too full (more would force other group to violate min -// fill requirement) then other group gets the rest. -// These last are the ones that can go in either group most easily. -RTREE_TEMPLATE -void RTREE_QUAL::ChoosePartition( PartitionVars* a_parVars, int a_minFill ) -{ - ASSERT( a_parVars ); - - ELEMTYPEREAL biggestDiff; - int group, chosen=0, betterGroup=0; - - InitParVars( a_parVars, a_parVars->m_branchCount, a_minFill ); - PickSeeds( a_parVars ); - - while( ( (a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total ) - && ( a_parVars->m_count[0] < (a_parVars->m_total - a_parVars->m_minFill) ) - && ( a_parVars->m_count[1] < (a_parVars->m_total - a_parVars->m_minFill) ) ) - { - biggestDiff = (ELEMTYPEREAL) -1; - - for( int index = 0; indexm_total; ++index ) - { - if( !a_parVars->m_taken[index] ) - { - Rect* curRect = &a_parVars->m_branchBuf[index].m_rect; - Rect rect0 = CombineRect( curRect, &a_parVars->m_cover[0] ); - Rect rect1 = CombineRect( curRect, &a_parVars->m_cover[1] ); - ELEMTYPEREAL growth0 = CalcRectVolume( &rect0 ) - a_parVars->m_area[0]; - ELEMTYPEREAL growth1 = CalcRectVolume( &rect1 ) - a_parVars->m_area[1]; - ELEMTYPEREAL diff = growth1 - growth0; - - if( diff >= 0 ) - { - group = 0; - } - else - { - group = 1; - diff = -diff; - } - - if( diff > biggestDiff ) - { - biggestDiff = diff; - chosen = index; - betterGroup = group; - } - else if( (diff == biggestDiff) - && (a_parVars->m_count[group] < a_parVars->m_count[betterGroup]) ) - { - chosen = index; - betterGroup = group; - } - } - } - - Classify( chosen, betterGroup, a_parVars ); - } - - // If one group too full, put remaining rects in the other - if( (a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total ) - { - if( a_parVars->m_count[0] >= a_parVars->m_total - a_parVars->m_minFill ) - { - group = 1; - } - else - { - group = 0; - } - - for( int index = 0; indexm_total; ++index ) - { - if( !a_parVars->m_taken[index] ) - { - Classify( index, group, a_parVars ); - } - } - } - - ASSERT( (a_parVars->m_count[0] + a_parVars->m_count[1]) == a_parVars->m_total ); - ASSERT( (a_parVars->m_count[0] >= a_parVars->m_minFill) - && (a_parVars->m_count[1] >= a_parVars->m_minFill) ); -} - - -// Copy branches from the buffer into two nodes according to the partition. -RTREE_TEMPLATE -void RTREE_QUAL::LoadNodes( Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars ) -{ - ASSERT( a_nodeA ); - ASSERT( a_nodeB ); - ASSERT( a_parVars ); - - for( int index = 0; index < a_parVars->m_total; ++index ) - { - ASSERT( a_parVars->m_partition[index] == 0 || a_parVars->m_partition[index] == 1 ); - - if( a_parVars->m_partition[index] == 0 ) - { - AddBranch( &a_parVars->m_branchBuf[index], a_nodeA, NULL ); - } - else if( a_parVars->m_partition[index] == 1 ) - { - AddBranch( &a_parVars->m_branchBuf[index], a_nodeB, NULL ); - } - } -} - - -// Initialize a PartitionVars structure. -RTREE_TEMPLATE -void RTREE_QUAL::InitParVars( PartitionVars* a_parVars, int a_maxRects, int a_minFill ) -{ - ASSERT( a_parVars ); - - a_parVars->m_count[0] = a_parVars->m_count[1] = 0; - a_parVars->m_area[0] = a_parVars->m_area[1] = (ELEMTYPEREAL) 0; - a_parVars->m_total = a_maxRects; - a_parVars->m_minFill = a_minFill; - - for( int index = 0; index < a_maxRects; ++index ) - { - a_parVars->m_taken[index] = false; - a_parVars->m_partition[index] = -1; - } -} - - -RTREE_TEMPLATE -void RTREE_QUAL::PickSeeds( PartitionVars* a_parVars ) -{ - int seed0 = 0, seed1 = 0; // avoid compil complaint about uninitialized - ELEMTYPEREAL worst, waste; - ELEMTYPEREAL area[MAXNODES + 1]; - - for( int index = 0; indexm_total; ++index ) - { - area[index] = CalcRectVolume( &a_parVars->m_branchBuf[index].m_rect ); - } - - worst = -a_parVars->m_coverSplitArea - 1; - - for( int indexA = 0; indexA < a_parVars->m_total - 1; ++indexA ) - { - for( int indexB = indexA + 1; indexB < a_parVars->m_total; ++indexB ) - { - Rect oneRect = CombineRect( &a_parVars->m_branchBuf[indexA].m_rect, - &a_parVars->m_branchBuf[indexB].m_rect ); - waste = CalcRectVolume( &oneRect ) - area[indexA] - area[indexB]; - - if( waste > worst ) - { - worst = waste; - seed0 = indexA; - seed1 = indexB; - } - } - } - - Classify( seed0, 0, a_parVars ); - Classify( seed1, 1, a_parVars ); -} - - -// Put a branch in one of the groups. -RTREE_TEMPLATE -void RTREE_QUAL::Classify( int a_index, int a_group, PartitionVars* a_parVars ) -{ - ASSERT( a_parVars ); - ASSERT( !a_parVars->m_taken[a_index] ); - - a_parVars->m_partition[a_index] = a_group; - a_parVars->m_taken[a_index] = true; - - if( a_parVars->m_count[a_group] == 0 ) - { - a_parVars->m_cover[a_group] = a_parVars->m_branchBuf[a_index].m_rect; - } - else - { - a_parVars->m_cover[a_group] = CombineRect( &a_parVars->m_branchBuf[a_index].m_rect, - &a_parVars->m_cover[a_group] ); - } - - a_parVars->m_area[a_group] = CalcRectVolume( &a_parVars->m_cover[a_group] ); - ++a_parVars->m_count[a_group]; -} - - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// RemoveRect provides for eliminating the root. -RTREE_TEMPLATE -bool RTREE_QUAL::RemoveRect( Rect* a_rect, const DATATYPE& a_id, Node** a_root ) -{ - ASSERT( a_rect && a_root ); - ASSERT( *a_root ); - - Node* tempNode; - ListNode* reInsertList = NULL; - - if( !RemoveRectRec( a_rect, a_id, *a_root, &reInsertList ) ) - { - // Found and deleted a data item - // Reinsert any branches from eliminated nodes - while( reInsertList ) - { - tempNode = reInsertList->m_node; - - for( int index = 0; index < tempNode->m_count; ++index ) - { - InsertRect( &(tempNode->m_branch[index].m_rect), - tempNode->m_branch[index].m_data, - a_root, - tempNode->m_level ); - } - - ListNode* remLNode = reInsertList; - reInsertList = reInsertList->m_next; - - FreeNode( remLNode->m_node ); - FreeListNode( remLNode ); - } - - // Check for redundant root (not leaf, 1 child) and eliminate - if( (*a_root)->m_count == 1 && (*a_root)->IsInternalNode() ) - { - tempNode = (*a_root)->m_branch[0].m_child; - - ASSERT( tempNode ); - FreeNode( *a_root ); - *a_root = tempNode; - } - - return false; - } - else - { - return true; - } -} - - -// Delete a rectangle from non-root part of an index structure. -// Called by RemoveRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -RTREE_TEMPLATE -bool RTREE_QUAL::RemoveRectRec( Rect* a_rect, - const DATATYPE& a_id, - Node* a_node, - ListNode** a_listNode ) -{ - ASSERT( a_rect && a_node && a_listNode ); - ASSERT( a_node->m_level >= 0 ); - - if( a_node->IsInternalNode() ) // not a leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - if( Overlap( a_rect, &(a_node->m_branch[index].m_rect) ) ) - { - if( !RemoveRectRec( a_rect, a_id, a_node->m_branch[index].m_child, a_listNode ) ) - { - if( a_node->m_branch[index].m_child->m_count >= MINNODES ) - { - // child removed, just resize parent rect - a_node->m_branch[index].m_rect = - NodeCover( a_node->m_branch[index].m_child ); - } - else - { - // child removed, not enough entries in node, eliminate node - ReInsert( a_node->m_branch[index].m_child, a_listNode ); - DisconnectBranch( a_node, index ); // Must return after this call as count has changed - } - - return false; - } - } - } - - return true; - } - else // A leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - if( a_node->m_branch[index].m_child == (Node*) a_id ) - { - DisconnectBranch( a_node, index ); // Must return after this call as count has changed - return false; - } - } - - return true; - } -} - - -// Decide whether two rectangles overlap. -RTREE_TEMPLATE -bool RTREE_QUAL::Overlap( Rect* a_rectA, Rect* a_rectB ) -{ - ASSERT( a_rectA && a_rectB ); - - for( int index = 0; index < NUMDIMS; ++index ) - { - if( a_rectA->m_min[index] > a_rectB->m_max[index] - || a_rectB->m_min[index] > a_rectA->m_max[index] ) - { - return false; - } - } - - return true; -} - - -// Add a node to the reinsertion list. All its branches will later -// be reinserted into the index structure. -RTREE_TEMPLATE -void RTREE_QUAL::ReInsert( Node* a_node, ListNode** a_listNode ) -{ - ListNode* newListNode; - - newListNode = AllocListNode(); - newListNode->m_node = a_node; - newListNode->m_next = *a_listNode; - *a_listNode = newListNode; -} - - -// Search in an index tree or subtree for all data retangles that overlap the argument rectangle. -RTREE_TEMPLATE -bool RTREE_QUAL::Search( Node* a_node, Rect* a_rect, int& a_foundCount, bool a_resultCallback( - DATATYPE a_data, - void* a_context ), void* a_context ) -{ - ASSERT( a_node ); - ASSERT( a_node->m_level >= 0 ); - ASSERT( a_rect ); - - if( a_node->IsInternalNode() ) // This is an internal node in the tree - { - for( int index = 0; index < a_node->m_count; ++index ) - { - if( Overlap( a_rect, &a_node->m_branch[index].m_rect ) ) - { - if( !Search( a_node->m_branch[index].m_child, a_rect, a_foundCount, - a_resultCallback, a_context ) ) - { - return false; // Don't continue searching - } - } - } - } - else // This is a leaf node - { - for( int index = 0; index < a_node->m_count; ++index ) - { - if( Overlap( a_rect, &a_node->m_branch[index].m_rect ) ) - { - DATATYPE& id = a_node->m_branch[index].m_data; - - // NOTE: There are different ways to return results. Here's where to modify - if( &a_resultCallback ) - { - ++a_foundCount; - - if( !a_resultCallback( id, a_context ) ) - { - return false; // Don't continue searching - } - } - } - } - } - - return true; // Continue searching -} - - -#undef RTREE_TEMPLATE -#undef RTREE_QUAL -#undef RTREE_SEARCH_TEMPLATE -#undef RTREE_SEARCH_QUAL - -#endif // RTREE_H diff --git a/include/view/view_rtree.h b/include/view/view_rtree.h index 973ac7943e..b9ddb58a4b 100644 --- a/include/view/view_rtree.h +++ b/include/view/view_rtree.h @@ -27,7 +27,7 @@ #include -#include +#include namespace KIGFX { @@ -76,7 +76,6 @@ public: * Executes a function object aVisitor for each item whose bounding box intersects * with aBounds. */ - template void Query( const BOX2I& aBounds, Visitor& aVisitor ) // const {