//================ Copyright (c) 1996-2009 Valve Corporation. All Rights Reserved. ================= // // // //================================================================================================== #ifndef UTLINTERVALTREE_H #define UTLINTERVALTREE_H #ifdef _WIN32 #pragma once #endif #include // qsort #include "tier0/platform.h" #include "tier1/utlstack.h" // // An interval tree is a tree of "segments" or "intervals" of type T which can be searched for overlaps with another interval. // // Usage: /* // Convenience typedef, the application data is the DataType == const void * part of it typedef CUtlIntervalTree< const void *, float > TreeType; // Build list of intervals to insert CUtlVector< TreeType::Value_t > intervals; TreeType::Value_t iv; for ( int i = 0 ; i < numtoinsert; ++i ) { iv.m_Data = (const void *) [i'th user value ]; iv.SetLowVal( leftEdge ); iv.SetHighVal( rightEdge ); intervals.AddToTail( iv ); } // Then build up the tree TreeType tree; tree.BuildTree( intervals.Base(), intervals.Count() ); // Now search the tree TreeType::Interval_t test; test.SetLowVal( nLowTest ); test.SetHighVal( nHighTest ); // Results vector: CUtlVector< TreeType::Value_t > vec; // Search for overlapping spans, return interval data (sorted by low value if passed in true as third argument) tree.FindOverlaps( test, vec, true ); // Print results (sorted if third argument is set to true) for ( int i = 0; i < vec.Count(); ++i ) { Msg( " [%d] overlap [%f, %f] [val %d]\n", i, vec[ i ].GetLowVal(), vec[ i ].GetHighVal(), (int)vec[ i ].m_Data ); } */ // template< class DataType, class T = float > class CUtlIntervalTree { public: template< class S > class Interval { public: Interval() : m_Low(0), m_High(0) { } Interval( const S &lowVal, const S &highVal ) : m_Low( lowVal ), m_High( highVal ) { } inline void SetLowVal( const S &v ) { m_Low = v; } inline const S &GetLowVal(void) const { return m_Low; } inline void SetHighVal( const S &v ) { m_High = v; } inline const S &GetHighVal(void) const { return m_High; } inline bool IsOverlapping( const Interval< S > &other, bool bStricOverlapsOnly ) const { if ( bStricOverlapsOnly ) { return ( GetLowVal() < other.GetHighVal() && GetHighVal() > other.GetLowVal() ); } return ( GetLowVal() <= other.GetHighVal() && GetHighVal() >= other.GetLowVal() ); } private: S m_Low; S m_High; }; typedef Interval< T > Interval_t; struct Value_t : public Interval_t { DataType m_Data; }; CUtlIntervalTree() : m_pRoot( NULL ) {} ~CUtlIntervalTree(void); void BuildTree( Value_t *pIntervals, unsigned int nCount ); void FindOverlaps( const Interval_t &rCheck, CUtlVector< Value_t > &vecOverlappingIntervals, bool bSortResultsByLowVal, bool bStricOverlapsOnly = false ) const; private: struct TreeNode { TreeNode( const Value_t &interval ) : m_Interval(interval), m_pLeft( NULL ), m_pRight( NULL ) { } Value_t m_Interval; TreeNode *m_pLeft; TreeNode *m_pRight; T m_MinVal; T m_MaxVal; }; TreeNode *m_pRoot; private: void DeleteTree_R( TreeNode *pNode ); TreeNode *Insert_R( const Value_t *pIntervals, unsigned int nCount ); }; template< class DataType, class T > inline int CompareIntervals( const void *p1, const void *p2 ) { const CUtlIntervalTree::Interval_t *pInterval1 = ( const CUtlIntervalTree::Interval_t *)p1; const CUtlIntervalTree::Interval_t *pInterval2 = ( const CUtlIntervalTree::Interval_t *)p2; T lowVal1 = pInterval1->GetLowVal(); T lowVal2 = pInterval2->GetLowVal(); if ( lowVal1 > lowVal2 ) return 1; else if ( lowVal1 < lowVal2 ) return -1; return 0; } template< class DataType, class T > inline void CUtlIntervalTree< DataType, T >::BuildTree( Value_t *pIntervals, unsigned int nCount ) { if ( m_pRoot ) { DeleteTree_R( m_pRoot ); m_pRoot = NULL; } if ( nCount > 0 ) { qsort( pIntervals, nCount, sizeof( Value_t ), CompareIntervals< DataType, T > ); // Recursively build tree m_pRoot = Insert_R( pIntervals, nCount ); } } template< class DataType, class T > inline CUtlIntervalTree::~CUtlIntervalTree(void) { if ( m_pRoot ) { DeleteTree_R( m_pRoot ); } } template< class DataType, class T > inline typename CUtlIntervalTree::TreeNode *CUtlIntervalTree::Insert_R( const Value_t *pIntervals, unsigned int nCount ) { unsigned int rootIdx = nCount / 2; TreeNode *pRoot = new TreeNode( pIntervals[ rootIdx ] ); switch( nCount ) { case 1: { // m_pLeft, m_pRight are NULL by default pRoot->m_MinVal = pRoot->m_Interval.GetLowVal(); pRoot->m_MaxVal = pRoot->m_Interval.GetHighVal(); } break; case 2: { pRoot->m_pLeft = Insert_R( pIntervals, 1 ); // m_pRight == NULL by default pRoot->m_MinVal = pRoot->m_pLeft->m_MinVal; pRoot->m_MaxVal = MAX( pRoot->m_pLeft->m_MaxVal, pRoot->m_Interval.GetHighVal() ); } break; default: // nCount > 2 { pRoot->m_pLeft = Insert_R( pIntervals, rootIdx ); pRoot->m_pRight = Insert_R( &pIntervals[ rootIdx + 1 ], nCount - rootIdx - 1 ); pRoot->m_MinVal = pRoot->m_pLeft->m_MinVal; // Max is greatest of this or two children... pRoot->m_MaxVal = MAX( MAX( pRoot->m_pLeft->m_MaxVal, pRoot->m_pRight->m_MaxVal ), pRoot->m_Interval.GetHighVal() ); } break; } return pRoot; } template< class DataType, class T > inline void CUtlIntervalTree::DeleteTree_R( TreeNode *pNode ) { if ( pNode->m_pLeft ) { DeleteTree_R( pNode->m_pLeft ); } if ( pNode->m_pRight ) { DeleteTree_R( pNode->m_pRight ); } delete pNode; } template< class DataType, class T > inline void CUtlIntervalTree::FindOverlaps( const Interval_t &rCheck, CUtlVector< Value_t > &vecOverlappingIntervals, bool bSortResultsByLowVal, bool bStricOverlapsOnly /*= false*/ ) const { const TreeNode *pNode = m_pRoot; if ( !pNode ) return; // Work queue stack CUtlStack< const TreeNode * > stack; stack.Push( NULL ); while ( pNode != NULL ) { if ( rCheck.IsOverlapping( pNode->m_Interval, bStricOverlapsOnly ) ) { vecOverlappingIntervals.AddToTail( pNode->m_Interval ); } bool bCheckLeft = ( pNode->m_pLeft && pNode->m_pLeft->m_MaxVal >= rCheck.GetLowVal() ); bool bCheckRight = ( pNode->m_pRight && pNode->m_pRight->m_MinVal <= rCheck.GetHighVal() ); if ( bCheckRight ) { if ( bCheckLeft ) { // queue it up for later stack.Push( pNode->m_pLeft ); } pNode = pNode->m_pRight; } else if ( bCheckLeft ) { pNode = pNode->m_pLeft; } else { stack.Pop( pNode ); } } if ( bSortResultsByLowVal && vecOverlappingIntervals.Count() > 1 ) { qsort( vecOverlappingIntervals.Base(), vecOverlappingIntervals.Count(), sizeof( Value_t ), CompareIntervals< DataType, T > ); } } #endif // UTLINTERVALTREE_H