#ifndef RTREE_H
#define RTREE_H
#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <stdlib.h>
#define ASSERT assert
#ifndef Min
#define Min __min
#endif
#ifndef Max
#define Max __max
#endif
#define rtree_min(a,b) (a<b?a:b)
#define rtree_max(a,b) (a>b?a:b)
#define RTREE_TEMPLATE template<class DATATYPE, class DATATYPENP, class ELEMTYPE, int NUMDIMS, class CONTEXT, class ELEMTYPEREAL, int TMAXNODES, int TMINNODES>
#define RTREE_QUAL RTree<DATATYPE, DATATYPENP, ELEMTYPE, NUMDIMS, CONTEXT, ELEMTYPEREAL, TMAXNODES, TMINNODES>
#define RTREE_DONT_USE_MEMPOOLS
#define RTREE_USE_SPHERICAL_VOLUME
#undef RTREE_WANTS_IO
#ifdef RTREE_WANTS_IO
class RTFileStream;
#endif
template<class DATATYPE, class DATATYPENP, class ELEMTYPE, int NUMDIMS, class CONTEXT,
class ELEMTYPEREAL = ELEMTYPE, int TMAXNODES = 8, int TMINNODES = TMAXNODES / 2>
class RTree
{
protected:
struct Node;
public:
enum
{
MAXNODES = TMAXNODES,
MINNODES = TMINNODES
};
public:
typedef void(DATATYPENP::* Operation)(const CONTEXT &) const;
RTree(Operation operation);
virtual ~RTree();
virtual void Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId);
virtual void Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId);
virtual int Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const CONTEXT &c) const;
void RemoveAll();
int Count();
#ifdef RTREE_WANTS_IO
bool Load(const char* a_fileName);
bool Load(RTFileStream& a_stream);
bool Save(const char* a_fileName);
bool Save(RTFileStream& a_stream);
#endif
class Iterator
{
private:
enum { MAX_STACK = 32 };
struct StackElement
{
Node* m_node;
int m_branchIndex;
};
public:
Iterator() { Init(); }
~Iterator() { }
bool IsNull() { return (m_tos <= 0); }
bool IsNotNull() { return (m_tos > 0); }
DATATYPE& operator*()
{
ASSERT(IsNotNull());
StackElement& curTos = m_stack[m_tos - 1];
return curTos.m_node->m_branch[curTos.m_branchIndex].m_data;
}
const DATATYPE& operator*() const
{
ASSERT(IsNotNull());
StackElement& curTos = m_stack[m_tos - 1];
return curTos.m_node->m_branch[curTos.m_branchIndex].m_data;
}
bool operator++() { return FindNextData(); }
private:
void Init() { m_tos = 0; }
bool FindNextData()
{
for(;;)
{
if(m_tos <= 0)
{
return false;
}
StackElement curTos = Pop();
if(curTos.m_node->IsLeaf())
{
if(curTos.m_branchIndex+1 < curTos.m_node->m_count)
{
Push(curTos.m_node, curTos.m_branchIndex + 1);
return true;
}
}
else
{
if(curTos.m_branchIndex+1 < curTos.m_node->m_count)
{
Push(curTos.m_node, curTos.m_branchIndex + 1);
}
Node* nextLevelnode = curTos.m_node->m_branch[curTos.m_branchIndex].m_child;
Push(nextLevelnode, 0);
if(nextLevelnode->IsLeaf())
{
return true;
}
}
}
}
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);
}
StackElement& Pop()
{
ASSERT(m_tos > 0);
--m_tos;
return m_stack[m_tos];
}
StackElement m_stack[MAX_STACK];
int m_tos;
friend class RTree<DATATYPE, DATATYPENP, ELEMTYPE, NUMDIMS, CONTEXT, ELEMTYPEREAL, TMAXNODES, TMINNODES>;
};
void GetFirst(Iterator& a_it)
{
a_it.Init();
if(m_root && (m_root->m_count > 0))
{
a_it.Push(m_root, 0);
a_it.FindNextData();
}
}
void GetNext(Iterator& a_it) { ++a_it; }
bool IsNull(Iterator& a_it) { return a_it.IsNull(); }
DATATYPE& GetAt(Iterator& a_it) { return *a_it; }
protected:
struct Rect
{
ELEMTYPE m_min[NUMDIMS];
ELEMTYPE m_max[NUMDIMS];
};
struct Branch
{
Rect m_rect;
union
{
Node* m_child;
DATATYPE m_data;
};
};
struct Node
{
bool IsInternalNode() const { return (m_level > 0); }
bool IsLeaf() const { return (m_level == 0); }
int m_count;
int m_level;
Branch m_branch[MAXNODES];
};
struct ListNode
{
ListNode* m_next;
Node* m_node;
};
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) const;
void ReInsert(Node* a_node, ListNode** a_listNode);
bool Search(Node* a_node, Rect* a_rect, int& a_foundCount, const CONTEXT &c) const;
void RemoveAllRec(Node* a_node);
void Reset();
void CountRec(Node* a_node, int& a_count);
#ifdef RTREE_WANTS_IO
bool SaveRec(Node* a_node, RTFileStream& a_stream);
bool LoadRec(Node* a_node, RTFileStream& a_stream);
#endif
Node* m_root;
ELEMTYPEREAL m_unitSphereVolume;
Operation myOperation;
};
#ifdef RTREE_WANTS_IO
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< typename TYPE >
size_t Write(const TYPE& a_value)
{
ASSERT(m_file);
return fwrite((void*)&a_value, sizeof(a_value), 1, m_file);
}
template< typename TYPE >
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< typename TYPE >
size_t Read(TYPE& a_value)
{
ASSERT(m_file);
return fread((void*)&a_value, sizeof(a_value), 1, m_file);
}
template< typename TYPE >
size_t ReadArray(TYPE* a_array, int a_count)
{
ASSERT(m_file);
return fread((void*)a_array, sizeof(TYPE) * a_count, 1, m_file);
}
};
#endif
RTREE_TEMPLATE
RTREE_QUAL::RTree(Operation operation)
: myOperation(operation)
{
ASSERT(MAXNODES > MINNODES);
ASSERT(MINNODES > 0);
ASSERT(sizeof(DATATYPE) == sizeof(void*) || sizeof(DATATYPE) == sizeof(int));
const float UNIT_SPHERE_VOLUMES[] = {
0.000000f, 2.000000f, 3.141593f,
4.188790f, 4.934802f, 5.263789f,
5.167713f, 4.724766f, 4.058712f,
3.298509f, 2.550164f, 1.884104f,
1.335263f, 0.910629f, 0.599265f,
0.381443f, 0.235331f, 0.140981f,
0.082146f, 0.046622f, 0.025807f,
};
m_root = AllocNode();
m_root->m_level = 0;
m_unitSphereVolume = (ELEMTYPEREAL)UNIT_SPHERE_VOLUMES[NUMDIMS];
}
RTREE_TEMPLATE
RTREE_QUAL::~RTree()
{
Reset();
}
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; index<NUMDIMS; ++index)
{
ASSERT(a_min[index] <= a_max[index]);
}
#endif
Rect rect;
for(int axis=0; axis<NUMDIMS; ++axis)
{
rect.m_min[axis] = a_min[axis];
rect.m_max[axis] = a_max[axis];
}
InsertRect(&rect, a_dataId, &m_root, 0);
}
RTREE_TEMPLATE
void RTREE_QUAL::Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId)
{
#ifdef _DEBUG
for(int index=0; index<NUMDIMS; ++index)
{
ASSERT(a_min[index] <= a_max[index]);
}
#endif
Rect rect;
for(int axis=0; axis<NUMDIMS; ++axis)
{
rect.m_min[axis] = a_min[axis];
rect.m_max[axis] = a_max[axis];
}
RemoveRect(&rect, a_dataId, &m_root);
}
RTREE_TEMPLATE
int RTREE_QUAL::Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const CONTEXT &c) const
{
#ifdef _DEBUG
for(int index=0; index<NUMDIMS; ++index)
{
ASSERT(a_min[index] <= a_max[index]);
}
#endif
Rect rect;
for(int axis=0; axis<NUMDIMS; ++axis)
{
rect.m_min[axis] = a_min[axis];
rect.m_max[axis] = a_max[axis];
}
int foundCount = 0;
Search(m_root, &rect, foundCount, c);
return foundCount;
}
RTREE_TEMPLATE
int RTREE_QUAL::Count()
{
int count = 0;
CountRec(m_root, count);
return count;
}
RTREE_TEMPLATE
void RTREE_QUAL::CountRec(Node* a_node, int& a_count)
{
if(a_node->IsInternalNode())
{
for(int index = 0; index < a_node->m_count; ++index)
{
CountRec(a_node->m_branch[index].m_child, a_count);
}
}
else
{
a_count += a_node->m_count;
}
}
#ifdef RTREE_WANTS_IO
RTREE_TEMPLATE
bool RTREE_QUAL::Load(const char* a_fileName)
{
RemoveAll();
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)
{
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;
if( (dataFileId == _dataFileId)
&& (dataSize == _dataSize)
&& (dataNumDims == _dataNumDims)
&& (dataElemSize == _dataElemSize)
&& (dataElemRealSize == _dataElemRealSize)
&& (dataMaxNodes == _dataMaxNodes)
&& (dataMinNodes == _dataMinNodes)
)
{
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())
{
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
{
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;
}
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)
{
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);
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())
{
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
{
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;
}
#endif
RTREE_TEMPLATE
void RTREE_QUAL::RemoveAll()
{
Reset();
m_root = AllocNode();
m_root->m_level = 0;
}
RTREE_TEMPLATE
void RTREE_QUAL::Reset()
{
#ifdef RTREE_DONT_USE_MEMPOOLS
RemoveAllRec(m_root);
#else
#endif
}
RTREE_TEMPLATE
void RTREE_QUAL::RemoveAllRec(Node* a_node)
{
ASSERT(a_node);
ASSERT(a_node->m_level >= 0);
if(a_node->IsInternalNode())
{
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
#endif
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
#endif
}
RTREE_TEMPLATE
typename RTREE_QUAL::ListNode* RTREE_QUAL::AllocListNode()
{
#ifdef RTREE_DONT_USE_MEMPOOLS
return new ListNode;
#else
#endif
}
RTREE_TEMPLATE
void RTREE_QUAL::FreeListNode(ListNode* a_listNode)
{
#ifdef RTREE_DONT_USE_MEMPOOLS
delete a_listNode;
#else
#endif
}
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;
}
}
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;
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))
{
a_node->m_branch[index].m_rect = CombineRect(a_rect, &(a_node->m_branch[index].m_rect));
return false;
}
else
{
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)
{
branch.m_rect = *a_rect;
branch.m_child = (Node*) a_id;
return AddBranch(&branch, a_node, a_newNode);
}
else
{
ASSERT(0);
return false;
}
}
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
Node* newRoot;
Node* newNode;
Branch branch;
if(InsertRectRec(a_rect, a_id, *a_root, &newNode, a_level))
{
newRoot = AllocNode();
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;
}
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;
}
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)
{
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;
}
}
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);
a_node->m_branch[a_index] = a_node->m_branch[a_node->m_count - 1];
--a_node->m_count;
}
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 = 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);
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;
}
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] = rtree_min(a_rectA->m_min[index], a_rectB->m_min[index]);
newRect.m_max[index] = rtree_max(a_rectA->m_max[index], a_rectB->m_max[index]);
}
return newRect;
}
RTREE_TEMPLATE
void RTREE_QUAL::SplitNode(Node* a_node, Branch* a_branch, Node** a_newNode)
{
ASSERT(a_node);
ASSERT(a_branch);
PartitionVars localVars;
PartitionVars* parVars = &localVars;
int level;
level = a_node->m_level;
GetBranches(a_node, a_branch, parVars);
ChoosePartition(parVars, MINNODES);
*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);
}
RTREE_TEMPLATE
ELEMTYPEREAL RTREE_QUAL::RectVolume(Rect* a_rect)
{
ASSERT(a_rect);
ELEMTYPEREAL volume = (ELEMTYPEREAL)1;
for(int index=0; index<NUMDIMS; ++index)
{
volume *= a_rect->m_max[index] - a_rect->m_min[index];
}
ASSERT(volume >= (ELEMTYPEREAL)0);
return volume;
}
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);
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);
}
}
RTREE_TEMPLATE
ELEMTYPEREAL RTREE_QUAL::CalcRectVolume(Rect* a_rect)
{
#ifdef RTREE_USE_SPHERICAL_VOLUME
return RectSphericalVolume(a_rect);
#else
return RectVolume(a_rect);
#endif
}
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);
int index;
for(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;
a_parVars->m_coverSplit = a_parVars->m_branchBuf[0].m_rect;
for(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);
}
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; index<a_parVars->m_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((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; index<a_parVars->m_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));
}
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);
}
}
}
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=1;
ELEMTYPEREAL worst, waste;
ELEMTYPEREAL area[MAXNODES+1];
for(int index=0; index<a_parVars->m_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);
}
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];
}
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))
{
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);
}
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;
}
}
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())
{
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)
{
a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child);
}
else
{
ReInsert(a_node->m_branch[index].m_child, a_listNode);
DisconnectBranch(a_node, index);
}
return false;
}
}
}
return true;
}
else
{
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);
return false;
}
}
return true;
}
}
RTREE_TEMPLATE
bool RTREE_QUAL::Overlap(Rect* a_rectA, Rect* a_rectB) const
{
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;
}
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;
}
RTREE_TEMPLATE
bool RTREE_QUAL::Search(Node* a_node, Rect* a_rect, int& a_foundCount, const CONTEXT &c) const
{
ASSERT(a_node);
ASSERT(a_node->m_level >= 0);
ASSERT(a_rect);
if(a_node->IsInternalNode())
{
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, c))
{
return false;
}
}
}
}
else
{
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_foundCount;
(id->*myOperation)(c);
}
}
}
return true;
}
#undef RTREE_TEMPLATE
#undef RTREE_QUAL
#endif