- °³¿ä
- C++ Implementation
- ¸µÅ©
1 °³¿ä
R-TREES: A DYNAMIC INDEX STRUCTURE FOR SPATIAL SEARCHING
N Â÷¿øÀÇ °ø°£¿¡¼ N Â÷¿øÀÇ »ç°¢Çü(¾ö¹ÐÈ÷ ¸»ÇÏÀÚ¸é 2Â÷¿ø¿¡¼³ª »ç°¢ÇüÀÌÁö¸¸, µüÈ÷ µû·Î ºÎ¸£±â ±ÍÂú´Ù.)À» ºü¸£°Ô ã±â À§ÇÑ ÀÚ·á ±¸Á¶´Ù. ÀÌ ÀڷᱸÁ¶¸¦ ÀÌ¿ëÇÏ¸é ¾Æ·¡¿Í °°Àº Äõ¸®¸¦ È¿°úÀûÀ¸·Î ó¸®ÇÒ ¼ö ÀÖ´Ù.
- ¾î¶² Á¡¿¡ °¡Àå °¡±î¿î »ç°¢ÇüÀº ¾î´À °ÍÀΰ¡?
- ¾î¶² Á¡À» Æ÷ÇÔÇÏ´Â »ç°¢ÇüÀº ¾î´À ¾î´À °ÍÀΰ¡?
- ¾î¶² »ç°¢Çü°ú °ãÄ¡´Â »ç°¢ÇüÀº ¾î´À ¾î´À °ÍÀΰ¡?
- ¾î¶² »ç°¢ÇüÀ» Æ÷ÇÔÇÏ´Â »ç°¢ÇüÀº ¾î´À ¾î´À °ÍÀΰ¡?
³ëµåÀÇ »ðÀÔ/»èÁ¦¿¡´Â ±×¸® È¿°úÀûÀÎ ÀڷᱸÁ¶°¡ ¾Æ´Ï¹Ç·Î, µ¿ÀûÀÎ ÀÚ·á ±¸Á¶¸¦ ó¸®ÇÏ´Â µ¥¿¡´Â ¸ÂÁö ¾Ê´Ù. °ÔÀÓ¿¡¼´Â Á¤ÀûÀÎ ¸Ê Á¤º¸¸¦ ±¸¼ºÇÏ´Â µ¥ »ç¿ëÇÒ ¼ö ÀÖÀ» µí ÇÏ´Ù.
2 C++ Implementation
//////////////////////////////////////////////////////////////////////////////
/// \file RTree.h
/// \author
/// 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
/// \date 2004.9.2
/// \note http://www.superliminal.com/sources/sources.htm ¿¡¼ ´Ù¿î·Îµå¹Þ¾Æ
/// ¾à°£ÀÇ ¼öÁ¤À» °¡ÇÑ ¼Ò½ºÀÌ´Ù.
//////////////////////////////////////////////////////////////////////////////
#ifndef __RTREE_H__
#define __RTREE_H__
#include <math.h>
// ÇöÀç ¹öÀüÀº ¸Þ¸ð¸® Ç®À» »ç¿ëÇÏÁö ¾Ê´Â´Ù. ¸Þ¸ð¸®Ç®À» »ç¿ëÇϱâ À§Çؼ´Â
// ÀÌ ¸ÅÅ©·Î°¡ ¼±¾ðµÇ¾î ÀÖ´Â ºÎºÐÀ» ã¾Æ¼ ¼öÁ¤ÇØ¾ß ÇÑ´Ù.
#define RTREE_DONT_USE_MEMPOOLS
// ³ëµåÀÇ ºÐÇÒÀ» À§Çؼ '±¸' Çü½ÄÀÇ ºÎÇǸ¦ »ç¿ëÇÑ´Ù.
// ³ëµå¸¦ Á» ´õ Àß ºÐÇÒÇÒ ¼ö ÀÖÀ¸³ª, ¼Óµµ°¡ ¾à°£ ´À¸± ¼ö ÀÖ´Ù.
#define RTREE_USE_SPHERICAL_VOLUME
// ÆÄÀÏ IO ÇïÆÛ Ŭ·¡½º
class RTFileStream;
//////////////////////////////////////////////////////////////////////////////
/// \class RTree
/// \brief N Â÷¿øÀÇ ¹Ù¿îµù ¹Ú½º Æ®¸®.
///
/// DATATYPE À¯Àú µ¥ÀÌÅÍ Çü½Ä. int, void*, obj* °°Àº Çü½Ä¸¸ »ç¿ë °¡´É.
/// Áï int º¸´Ù »çÀÌÁî°¡ Å« ŸÀÔÀº »ç¿ëÇÒ ¼ö ¾ø´Ù.
/// ELEMTYPE ÁÂÇ¥°è¸¦ ³ªÅ¸³»´Â µ¥ »ç¿ëÇÒ Å¸ÀÔ. int, float µîµî
/// NUMDIMS Â÷¿øÀÇ ¼ö. 2, 3 µîµî
/// ELEMTYPEREAL ³»ºÎÀûÀ¸·Î ºÎÇÇ µîÀ» °è»êÇÏ´Â µ¥ ¾²ÀÏ Å¸ÀÔ. Á¤¼öÇüº¸´Ù´Â
/// ½Ç¼öÇüÀÇ Å¸ÀÔÀ» »ç¿ëÇØ¾ß ÇÑ´Ù.
/// TMAXNODES ÇÑ ³ëµå¿¡ µé¾î°¥ ¼ö ÀÖ´Â ÀÚ½Ä ³ëµåÀÇ ÃÖ´ë °¹¼ö
/// TMINNODES ÇÑ ³ëµå¿¡ µé¾î°¡¾ßÇÏ´Â ÀÚ½Ä ³ëµåÀÇ ÃÖ¼Ò °¹¼ö
///
/// 3Â÷¿øÀÇ Æ®¸®¸¦ ±¸¼ºÇϱâ À§Çؼ´Â RTree<Object*, float, 3>°ú °°Àº Çü½ÄÀ¸·Î
/// »ç¿ëÇÏ¸é µÈ´Ù.
///
/// \note À¯Àú µ¥ÀÌÅ͸¦ Áý¾î³Ö°í »èÁ¦Çϱâ À§Çؼ´Â ±× µ¥ÀÌÅ͸¦ °¨½Î´Â ÃÖ¼ÒÀÇ
/// ¹Ù¿îµù ¹Ú½º(Minimal Bounding Box)¸¦ ¾Ë¾Æ¾ß ÇÑ´Ù.
/// \note ÇöÀç ¹öÀüÀº ³ëµåÀÇ ÇÒ´ç/»èÁ¦¸¦ À§ÇØ ±×³É new/delete¸¦ »ç¿ëÇÑ´Ù.
/// È¿À²À» À§Çؼ´Â ¸Þ¸ð¸® Ç®À» ÀÌ¿ëÇÏ´Â °ÍÀÌ ÁÁÀ» °ÍÀÌ´Ù.
//////////////////////////////////////////////////////////////////////////////
template <typename DATATYPE, typename ELEMTYPE, int NUMDIMS,
typename ELEMTYPEREAL = ELEMTYPE, int TMAXNODES = 8, int TMINNODES = TMAXNODES / 2>
class RTree
{
protected:
struct Node;
public:
enum
{
MAXNODES = TMAXNODES, ///< ÇÑ ³ëµå¿¡ µé¾î°¥ ¼ö ÀÖ´Â ÀÚ½Ä ³ëµåÀÇ ÃÖ´ë °¹¼ö
MINNODES = TMINNODES ///< ÇÑ ³ëµå¿¡ µé¾î°¡¾ßÇÏ´Â ÀÚ½Ä ³ëµåÀÇ ÃÖ¼Ò °¹¼ö
};
// °á°ú°ªÀ» ¹ÝȯÇϱâ À§ÇÑ º¤ÅÍ
typedef std::vector<DATATYPE> RESULTS;
private:
Node* m_root; ///< ·çÆ® ³ëµå
ELEMTYPEREAL m_unitSphereVolume; ///< ºÎÇǸ¦ °è»êÇϱâ À§ÇÑ »ó¼ö
public:
RTree();
virtual ~RTree();
public:
/// \brief µ¥ÀÌÅ͸¦ Áý¾î³Ö´Â´Ù.
/// \param min ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ¼Ò°ª
/// \param max ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ´ë°ª
/// \param dataId ½ÇÁ¦ µ¥ÀÌÅÍÀÇ ID. ¾ç¼ö¿©¾ß ÇÑ´Ù. 0Àº µÇ³ª À½¼ö°ªÀº
/// »ç¿ëÇÒ ¼ö ¾ø´Ù.
void Insert(const ELEMTYPE min[NUMDIMS], const ELEMTYPE max[NUMDIMS], const DATATYPE& dataId);
/// \brief µ¥ÀÌÅ͸¦ Á¦°ÅÇÑ´Ù.
/// \param min ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ¼Ò°ª
/// \param max ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ´ë°ª
/// \param dataId ½ÇÁ¦ µ¥ÀÌÅÍÀÇ ID. ¾ç¼ö¿©¾ß ÇÑ´Ù. 0Àº µÇ³ª À½¼ö°ªÀº
/// »ç¿ëÇÒ ¼ö ¾ø´Ù.
void Remove(const ELEMTYPE min[NUMDIMS], const ELEMTYPE max[NUMDIMS], const DATATYPE& dataId);
/// \brief ÇØ´çÇÏ´Â ¹Ù¿îµù ¹Ú½º¿Í °ãÄ¡´Â ¸ðµç µ¥ÀÌÅ͵éÀ» ã´Â´Ù.
/// \param min ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ¼Ò°ª
/// \param max ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ´ë°ª
/// \param results °á°ú°ªÀ» Áý¾î³ÖÀ» Ä÷º¼Ç °´Ã¼
/// \return ãÀº µ¥ÀÌÅÍÀÇ °¹¼ö
int Search(const ELEMTYPE min[NUMDIMS], const ELEMTYPE max[NUMDIMS], RESULTS& results);
/// \brief ¸ðµç µ¥ÀÌÅ͸¦ Á¦°ÅÇϰí, ·çÆ® ³ëµå¸¦ ÃʱâÈÇÑ´Ù.
void RemoveAll();
/// \brief Æ®¸® ¾È¿¡ ÀÖ´Â µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ ¹ÝȯÇÑ´Ù.
///
/// ³»ºÎÀûÀ¸·Î µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ À¯ÁöÇÏÁö ¾Ê°í, ÀÌ ÇÔ¼ö°¡ È£ÃâµÉ ¶§¸¶´Ù
/// °è»êÇϱ⠶§¹®¿¡ ´À¸®´Ù. ÀÚÁÖ È£ÃâÇÏÁö ¸» °Í.
///
/// \return int Æ®¸® ¾È¿¡ ÀÖ´Â µ¥ÀÌÅÍÀÇ °¹¼ö
int Count();
public:
/// \brief ÆÄÀÏ¿¡¼ Æ®¸®¸¦ ·ÎµåÇÑ´Ù.
/// \param fileName ÆÄÀÏ À̸§
/// \return bool Á¤»óÀûÀ¸·Î ·ÎµåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool Load(const char* fileName);
/// \brief ½ºÆ®¸²¿¡¼ Æ®¸®¸¦ ·ÎµåÇÑ´Ù.
/// \param stream ½ºÆ®¸² °´Ã¼
/// \return bool Á¤»óÀûÀ¸·Î ·ÎµåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool Load(RTFileStream& stream);
/// \brief ÆÄÀÏ¿¡´Ù Æ®¸®¸¦ ÀúÀåÇÑ´Ù.
/// \param fileName ÆÄÀÏ À̸§
/// \return bool Á¤»óÀûÀ¸·Î ÀúÀåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇѰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool Save(const char* fileName);
/// \brief ½ºÆ®¸²¿¡´Ù Æ®¸®¸¦ ÀúÀåÇÑ´Ù.
/// \param stream ½ºÆ®¸² °´Ã¼
/// \return bool Á¤»óÀûÀ¸·Î ÀúÀåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇѰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool Save(RTFileStream& stream);
public:
//////////////////////////////////////////////////////////////////////////
/// \class Iterator
/// \brief
//////////////////////////////////////////////////////////////////////////
class Iterator
{
friend RTree;
private:
// Max stack size. Allows almost n^32 where n is number of branches in node
enum { MAX_STACK = 32 };
struct StackElement
{
Node* m_node;
int m_branchIndex;
};
StackElement m_stack[MAX_STACK]; ///< Àç±ÍÈ£ÃâÀ» ÇÇÇϱâ À§ÇÑ ½ºÅÃ
int m_tos; ///< ½ºÅà ž
public:
/// \brief »ý¼ºÀÚ
Iterator() { Init(); }
/// \brief ¼Ò¸êÀÚ
~Iterator() { }
public:
/// \brief ¿Ã¹Ù¸¥ °ªÀ» °¡Áö°í Àִ°¡ÀÇ ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
/// \return bool ¹«È¿ÈµÈ Ⱦ´ÜÀÚÀÏ °æ¿ì true
bool IsNull() const { return m_tos <= 0; }
/// \brief ¿Ã¹Ù¸¥ °ªÀ» °¡Áö°í Àִ°¡ÀÇ ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
/// \return bool À¯È¿ÇÑ È¾´ÜÀÚÀÏ °æ¿ì true
bool IsNotNull() { return m_tos > 0; }
/// \brief ÇöÀç Ⱦ´ÜÀÚÀÇ µ¥ÀÌÅÍ °ªÀ» ¹ÝȯÇÑ´Ù. È£ÃâÇϱâ ÀÌÀü¿¡
/// Ⱦ´ÜÀÚÀÇ °ªÀÌ Á¤»óÀûÀÎÁö¸¦ ¸ÕÀú Ã¼Å©ÇØ¾ß ÇÑ´Ù.
/// \return DATATYPE& µ¥ÀÌÅÍ °ª
DATATYPE& operator*()
{
Assert(IsNotNull());
StackElement& curTos = m_stack[m_tos - 1];
return curTos.m_node->m_branch[curTos.m_branchIndex].m_data;
}
/// \brief ÇöÀç Ⱦ´ÜÀÚÀÇ µ¥ÀÌÅÍ °ªÀ» ¹ÝȯÇÑ´Ù. È£ÃâÇϱâ ÀÌÀü¿¡
/// Ⱦ´ÜÀÚÀÇ °ªÀÌ Á¤»óÀûÀÎÁö¸¦ ¸ÕÀú Ã¼Å©ÇØ¾ß ÇÑ´Ù.
/// \return const DATATYPE& µ¥ÀÌÅÍ °ª
const DATATYPE& operator*() const
{
Assert(IsNotNull());
StackElement& curTos = m_stack[m_tos - 1];
return curTos.m_node->m_branch[curTos.m_branchIndex].m_data;
}
/// \brief ´ÙÀ½ µ¥ÀÌÅÍ °ªÀ» ¹ÝȯÇÑ´Ù.
/// \return bool ´ÙÀ½ µ¥ÀÌÅͰªÀÌ Á¸ÀçÇÏ´Â °æ¿ì true, ´õ ÀÌ»óÀÇ
/// µ¥ÀÌÅͰ¡ Á¸ÀçÇÏÁö ¾Ê´Â´Ù¸é false.
bool operator++() { return FindNextData(); }
private:
/// \brief Ⱦ´ÜÀÚ¸¦ ÃʱâÈÇÑ´Ù.
void Init() { m_tos = 0; }
/// \brief Æ®¸® ¾È¿¡ ÀÕ´Â ´ÙÀ½ µ¥ÀÌÅ͸¦ ã´Â´Ù. (³»ºÎ¿¡¼¸¸ »ç¿ëÇÏ´Â
/// ÇÔ¼ö´Ù.)
/// \return bool ´ÙÀ½ µ¥ÀÌÅͰªÀÌ Á¸ÀçÇÏ´Â °æ¿ì true, ´õ ÀÌ»óÀÇ
/// µ¥ÀÌÅͰ¡ Á¸ÀçÇÏÁö ¾Ê´Â´Ù¸é false.
bool FindNextData()
{
for (;;)
{
if (m_tos <= 0)
return false;
StackElement curTos = Pop(); // ½ºÅà žÀ» º¹»çÇØµÐ´Ù.
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;
}
}
}
/// \brief ³ëµå¿Í ºê·£Ä¡¸¦ ½ºÅÿ¡´Ù Ǫ½¬ÇÑ´Ù. (³»ºÎÀûÀ¸·Î¸¸ »ç¿ëÇÑ´Ù.)
/// \param node ³ëµå
/// \param branchIndex ºê·£Ä¡ À妽º
void Push(Node* node, int branchIndex)
{
m_stack[m_tos].m_node = node;
m_stack[m_tos].m_branchIndex = branchIndex;
++m_tos;
Assert(m_tos <= MAX_STACK);
}
/// \brief ½ºÅÿ¡¼ µ¥ÀÌÅ͸¦ ²¨³½´Ù. (³»ºÎÀûÀ¸·Î¸¸ »ç¿ëÇÑ´Ù.)
/// \return StackElement& ½ºÅà µ¥ÀÌÅÍ
StackElement& Pop()
{
Assert(m_tos > 0);
--m_tos;
return m_stack[m_tos];
}
};
/// \brief Á¦ÀÏ ¾ÕÂÊÀÇ È¾´ÜÀÚ¸¦ ¸®ÅÏÇÑ´Ù.
/// \param it Ⱦ´ÜÀÚÀÇ ÂüÁ¶
void GetFirst(Iterator& it)
{
it.Init();
if (m_root && (m_root->m_count > 0))
{
it.Push(m_root, 0);
it.FindNextData();
}
}
/// \brief ´ÙÀ½ Ⱦ´ÜÀÚ¸¦ °è»êÇÑ´Ù.
/// \param it Ⱦ´ÜÀÚÀÇ ÂüÁ¶
void GetNext(Iterator& it) { ++it; }
/// \brief Ⱦ´ÜÀÚ°¡ Á¤»óÀûÀÎÁöÀÇ ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
/// \param it Ⱦ´ÜÀÚÀÇ ÂüÁ¶
bool IsNull(Iterator& it) { return it.IsNull(); }
/// \brief ÇØ´ç Ⱦ´ÜÀÚÀÇ µ¥ÀÌÅÍ °ªÀ» ¹ÝȯÇÑ´Ù.
/// \param it Ⱦ´ÜÀÚÀÇ ÂüÁ¶
DATATYPE& GetAt(Iterator& it) { return *it; }
protected:
/// ¹Ù¿îµù ¹Ú½º (N Â÷¿ø)
struct Rect
{
ELEMTYPE m_min[NUMDIMS]; ///< ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ¼Ò°ª
ELEMTYPE m_max[NUMDIMS]; ///< ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ´ë°ª
};
/// ½ÇÁ¦ À¯Àú µ¥ÀÌÅÍÀÏ ¼öµµ ÀÖ°í, ÀÚ½Ä Æ®¸®ÀÏ ¼öµµ ÀÖ´Ù.
/// ºÎ¸ðÀÇ ·¹º§ÀÌ À̸¦ °áÁ¤ÇÑ´Ù. ºÎ¸ðÀÇ ·¹º§ÀÌ 0À̶ó¸é, À¯Àú µ¥ÀÌÅÍÀÌ´Ù.
struct Branch
{
Rect m_rect; ///< ¹Ù¿îµù ¹Ú½º
union
{
Node* m_child; ///< ÀÚ½Ä ³ëµå
DATATYPE m_data; ///< À¯Àú µ¥ÀÌÅÍ
};
};
/// ½ÇÁ¦ ³ëµå
struct Node
{
/// \brief ÇöÀç ³ëµå°¡ ¸®ÇÁ ³ëµå°¡ ¾Æ´ÑÁöÀÇ ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
bool IsInternalNode() const { return (m_level > 0); }
/// \brief ÇöÀç ³ëµå°¡ ¸®ÇÁ ³ëµå, Áï ½ÇÁ¦ µ¥ÀÌÅ͸¦ °¡Áö´Â ³ëµåÀÎÁöÀÇ
/// ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
bool IsLeaf() const { return (m_level == 0); }
int m_count; ///< Ä«¿îÆ®
int m_level; ///< ¸®ÇÁ ³ëµåÀÏ °æ¿ì 0, ´Ù¸¥ °æ¿ì¿¡´Â ¾ç¼ö
Branch m_branch[MAXNODES]; ///< ÀÚ½Ä ³ëµåµé
};
/// ³ëµå »èÁ¦ ÈÄ¿¡ »õ·Î¿î »ðÀÔÀ» À§ÇÑ ¸µÅ©µå ¸®½ºÆ®
struct ListNode
{
ListNode* m_next; ///< Next in list
Node* m_node; ///< 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;
};
protected:
/// \brief ³ëµå¸¦ ÇÒ´çÇÑ´Ù.
/// \return Node* »õ·Î ÇÒ´çÇÑ ³ëµå °´Ã¼
Node* AllocNode();
/// \brief ³ëµå¸¦ »èÁ¦ÇÑ´Ù.
/// \param node »èÁ¦ÇÒ ³ëµå
void FreeNode(Node* node);
/// \brief ³ëµå¸¦ ÃʱâÈÇÑ´Ù.
/// \param node ÃʱâÈÇÒ ³ëµå
void InitNode(Node* node);
/// \brief ¹Ù¿îµù ¹Ú½º¸¦ ÃʱâÈÇÑ´Ù.
/// \param rect ÃʱâÈÇÒ ¹Ù¿îµù ¹Ú½º
void InitRect(Rect* rect);
/// \brief À¯Àú µ¥ÀÌÅÍ¿Í »ç°¢ÇüÀ» Æ®¸®¿¡´Ù Áý¾î³Ö´Â´Ù. Àç±ÍÀûÀ¸·Î Æ®¸®¸¦
/// µû¶ó ³»·Á°¡¸ç, ÇÊ¿äÇÏ´Ù¸é »õ·Î¿î ºÐÇÒµµ ¸¸µç´Ù.
/// \param rect ¹Ù¿îµù ¹Ú½º
/// \param id À¯Àú µ¥ÀÌÅÍ
/// \param node ºÎ¸ð ³ëµå
/// \param newNode ³ëµå°¡ ºÐÇÒµÈ °æ¿ì, »õ·Î¿î ³ëµåÀÇ °ªÀÌ µé¾î°£´Ù.
/// \param level ¸®ÇÁ ³ëµå·ÎºÎÅÍ ¾ó¸¶³ª ¿Ã¶ó¿Ô´Â°¡¸¦ ³ªÅ¸³»´Â º¯¼ö.
/// Áï ¸®ÇÁ/ ³ëµå(µ¥ÀÌÅÍ ³ëµå)¶ó¸é ÀÌ °ªÀº 0ÀÌ´Ù.
/// \return bool ³ëµå°¡ ºÐÇÒµÇÁö ¾Ê¾Ò´Ù¸é, 0À» ¹ÝȯÇÑ´Ù. ³ëµå°¡
/// ºÐÇҵǾú´Ù¸é true¸¦ ¹ÝȯÇϰí, newNode Æ÷ÀÎÅÍÀÇ °ªÀ» »õ·Î¿î
/// °¡¸£Å°µµ·Ï º¯°æÇÑ´Ù.
bool InsertRectRec(Rect* rect, const DATATYPE& id, Node* node, Node** newNode, int level);
/// \brief À¯Àú µ¥ÀÌÅÍ¿Í »ç°¢ÇüÀ» Æ®¸®¿¡´Ù Áý¾î³Ö´Â´Ù.
/// \param rect ¹Ù¿îµù ¹Ú½º
/// \param id À¯Àú µ¥ÀÌÅÍ
/// \param root ·çÆ® ³ëµå
/// \param level ¸®ÇÁ ³ëµå·ÎºÎÅÍ ¾ó¸¶³ª ¿Ã¶ó¿Ô´Â°¡¸¦ ³ªÅ¸³»´Â º¯¼ö.
/// Áï ¸®ÇÁ/ ³ëµå(µ¥ÀÌÅÍ ³ëµå)¶ó¸é ÀÌ °ªÀº 0ÀÌ´Ù.
/// \return bool ³ëµå°¡ ºÐÇÒµÇÁö ¾Ê¾Ò´Ù¸é, 0À» ¹ÝȯÇÑ´Ù. ³ëµå°¡ ºÐÇҵǾú´Ù¸é
/// true¸¦ ¹ÝȯÇÑ´Ù.
bool InsertRect(Rect* rect, const DATATYPE& id, Node** root, int level);
/// \brief ÇØ´çÇÏ´Â ³ëµå ¾È¿¡ µé¾îÀÖ´Â »ç°¢ÇüµéÀ» ¸ðµÎ °¨½Î´Â °¡Àå ÀÛÀº
/// ¹Ù¿îµù ¹Ú½º¸¦ °è»êÇÑ´Ù.
/// \param node ³ëµå
/// \return Rect Minimal Bounding Box
Rect NodeCover(Node* node);
/// \brief ³ëµå¿¡´Ù°¡ ºê·£Ä¡¸¦ Ãß°¡ÇÑ´Ù. ºÐÇÒÀÌ ÇÊ¿äÇÒ °æ¿ì¿¡´Â ºÐÇÒµµ
/// ÇÑ´Ù.
/// \param branch Ãß°¡ÇÒ ºê·£Ä¡
/// \param node ³ëµå
/// \param newNode ³ëµå°¡ ºÐÇÒµÈ °æ¿ì, »õ·Î¿î ³ëµåÀÇ °ªÀÌ µé¾î°£´Ù.
/// \return bool ³ëµå°¡ ºÐÇÒµÇÁö ¾Ê¾Ò´Ù¸é 0À» ¹ÝȯÇÑ´Ù. ºÐÇҵǾú´Ù¸é 1À»
/// ¹ÝȯÇѰí, newNodeÀÇ °ªÀ» »õ·Î¿î ³ëµå¸¦ °¡¸£Å°µµ·Ï º¯°æÇÑ´Ù.
bool AddBranch(Branch* branch, Node* node, Node** newNode);
/// \brief ³ëµå¿Í ºê·£Ä¡ÀÇ ¿¬°áÀ» ²÷´Â´Ù.
///
/// ÀÌ ÇÔ¼ö¸¦ È£ÃâÇÑ ´ÙÀ½¿¡´Â iteratorÀÇ °ªÀÌ ¹«È¿ÈµÇ´Ï ÁÖÀÇÇØ¾ß ÇÑ´Ù.
///
/// \param node ³ëµå
/// \param index ºê·£Ä¡ À妽º
void DisconnectBranch(Node* node, int index);
/// \brief »õ·Î¿î ¹Ù¿îµù ¹Ú½º¸¦ Áý¾î³Ö¾úÀ» ¶§, ºÎÇǰ¡ °¡Àå Àû°Ô ´Ã¾î³ª´Â
/// ºê·£Ä¡¸¦ ã´Â´Ù.
/// \param rect ¹Ù¿îµù ¹Ú½º
/// \param node ³ëµå
/// \return int ºê·£Ä¡ À妽º
int PickBranch(Rect* rect, Node* node);
/// \brief µÎ ¹Ù¿îµù ¹Ú½º¸¦ ¸ðµÎ Æ÷ÇÔÇÏ´Â ¹Ù¿îµù ¹Ú½º¸¦ °è»êÇÑ´Ù.
/// \param rectA ¹Ù¿îµù ¹Ú½º
/// \param rectB ¹Ù¿îµù ¹Ú½º
/// \return Rect µÎ ¹Ù¿îµù ¹Ú½º¸¦ ¸ðµÎ Æ÷ÇÔÇÏ´Â ¹Ù¿îµù ¹Ú½º
Rect CombineRect(Rect* rectA, Rect* rectB);
/// \brief ³ëµå¸¦ ºÐÇÒÇÑ´Ù.
///
/// ÁÖ¾îÁø ³ëµåÀÇ ºê·£Ä¡ + »õ·Î¿î ºê·£Ä¡ == 2 ³ëµå·Î ºÐÇÒÇÑ´Ù.
///
/// \param node ³ëµå (º¯°æµÈ´Ù)
/// \param branch »õ·Î¿î ºê·£Ä¡
/// \param newNode »õ·Î »ý¼ºÇÑ ³ëµå
void SplitNode(Node* node, Branch* branch, Node** newNode);
/// \brief ¹Ù¿îµù ¹Ú½ºÀÇ ±¸ ºÎÇÇ °ªÀ» ¹ÝȯÇÑ´Ù.
/// \param rect ¹Ù¿îµù ¹Ú½º
/// \return ELEMTYPEREAL ºÎÇÇ °ª
ELEMTYPEREAL RectSphericalVolume(Rect* rect);
/// \brief ¹Ù¿îµù ¹Ú½ºÀÇ ºÎÇǸ¦ °è»êÇÑ´Ù.
/// \param rect ¹Ù¿îµù ¹Ú½º
/// \return ELEMTYPEREAL ºÎÇÇ °ª
ELEMTYPEREAL RectVolume(Rect* rect);
/// \brief ¹Ù¿îµù ¹Ú½ºÀÇ ºÎÇǸ¦ °è»êÇÑ´Ù.
/// \param rect ¹Ù¿îµù ¹Ú½º
/// \return ELEMTYPEREAL ºÎÇÇ
ELEMTYPEREAL CalcRectVolume(Rect* rect);
/// \brief °¡µæÂù ³ëµå Çϳª + ºê·£Ä¡ Çϳª¸¦ Àоîµé¿© ¹öÆÛ¸¦ ä¿î´Ù.
/// \param node ³ëµå
/// \param branch ºê·£Ä¡
/// \param parVars ¹öÆÛ
void GetBranches(Node* node, Branch* branch, PartitionVars* parVars);
/// \brief ºÐÇÒÀ» ¼±ÅÃÇϱâ À§ÇÑ ÇÔ¼ö
///
/// 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.
///
/// \param parVars ¹öÆÛ
/// \param minFill ÃÖ¼Ò Ã¤¿ì±â °ª
void ChoosePartition(PartitionVars* parVars, int minFill);
/// \brief ºÐÇÒ¿¡ µû¶ó, ºê·£µåÄ¡µéÀ» ¹öÆÛ¿¡¼ º¹»çÇÑ´Ù.
/// \param nodeA ³ëµå
/// \param nodeB ³ëµå
/// \param parVars ¹öÆÛ
void LoadNodes(Node* nodeA, Node* nodeB, PartitionVars* parVars);
/// \brief Æ®¸®ÀÇ ºÐÇÒÀ» ãÀ» ¶§ ¾²ÀÌ´Â º¯¼ö °´Ã¼¸¦ ÃʱâÈÇÑ´Ù.
/// \param parVars º¯¼ö °´Ã¼
/// \param maxRects »ç°ÝÇüÀÇ °¹¼ö
/// \param minFill ÃÖ¼Ò Ã¤¿ì±â °ª
void InitParVars(PartitionVars* parVars, int maxRects, int minFill);
/// \brief Æ®¸®ÀÇ ºÐÇÒÀ» À§ÇÑ ½Ãµå °ªÀ» °è»êÇÑ´Ù.
/// \param parVars Æ®¸®ÀÇ ºÐÇÒÀ» ãÀ» ¶§ ¾²ÀÌ´Â º¯¼ö °´Ã¼
void PickSeeds(PartitionVars* parVars);
/// \brief ºê·£Ä¡¸¦ ±×·ìº°·Î ±¸ºÐÇÑ´Ù.
/// \param index ºê·£Ä¡ÀÇ À妽º
/// \param group ±×·ì À妽º
/// \param parVars Æ®¸®ÀÇ ºÐÇÒÀ» ãÀ» ¶§ ¾²ÀÌ´Â º¯¼ö °´Ã¼
void Classify(int index, int group, PartitionVars* parVars);
/// \brief ¹Ù¿îµù ¹Ú½º¸¦ »èÁ¦ÇÑ´Ù.
/// \param rect Á¦°ÅÇÒ ¹Ù¿îµù ¹Ú½º
/// \param id Á¦°ÅÇÒ À¯Àú µ¥ÀÌÅÍ
/// \param root ·çÆ® ³ëµå
/// \return bool ¼º°øÀûÀ¸·Î »èÁ¦ÇÑ °æ¿ì¿¡´Â 0À» ¹ÝȯÇϰí, ÇØ´ç µ¥ÀÌÅ͸¦ ãÁö
/// ¸øÇÑ °æ¿ì¿¡´Â 1À» ¹ÝȯÇÑ´Ù.
bool RemoveRect(Rect* rect, const DATATYPE& id, Node** root);
/// \brief ·çÆ®°¡ ¾Æ´Ñ ´Ù¸¥ ³ëµå¿¡¼ ¹Ù¿îµù ¹Ú½º¸¦ »èÁ¦ÇÑ´Ù.
///
/// RemoveRect ÇÔ¼ö¿¡¼ È£ÃâÇÑ´Ù. Æ®¸®¸¦ µû¶ó³»·Á°¡¸ç, ³ëµå¸¦ ÇÕÃľßÇÏ´Â
/// °æ¿ì¿¡´Â ÇÕÄ£´Ù.
///
/// \param rect Á¦°ÅÇÒ ¹Ù¿îµù ¹Ú½º
/// \param id Á¦°ÅÇÒ À¯Àú µ¥ÀÌÅÍ
/// \param node ºÎ¸ð ³ëµå
/// \param listNode Àç»ðÀÔ ¸®½ºÆ® °´Ã¼
/// \return bool ¼º°øÀûÀ¸·Î »èÁ¦ÇÑ °æ¿ì¿¡´Â 0À» ¹ÝȯÇϰí, ÇØ´ç µ¥ÀÌÅ͸¦ ãÁö
/// ¸øÇÑ °æ¿ì¿¡´Â 1À» ¹ÝȯÇÑ´Ù.
bool RemoveRectRec(Rect* rect, const DATATYPE& id, Node* node, ListNode** listNode);
/// \brief ¸®½ºÆ® ³ëµå¸¦ ÇÒ´çÇÑ´Ù.
/// \return ListNode* »õ·Î ÇÒ´çÇÑ ¸®½ºÆ® ³ëµå
ListNode* AllocListNode();
/// \brief ¸®½ºÆ® ³ëµå¸¦ »èÁ¦ÇÑ´Ù.
/// \param listNode »èÁ¦ÇÒ ¸®½ºÆ® ³ëµå
void FreeListNode(ListNode* listNode);
/// \brief µÎ ¹Ù¿îµù ¹Ú½º°¡ °ãÄ¡´ÂÁöÀÇ ¿©ºÎ¸¦ ¹ÝȯÇÑ´Ù.
/// \param rectA ¹Ù¿îµù ¹Ú½º
/// \param rectB ¹Ù¿îµù ¹Ú½º
/// \return bool °ãÄ¡´Â °æ¿ì true, °ãÄ¡Áö ¾Ê´Â °æ¿ì false
bool Overlap(Rect* rectA, Rect* rectB) const;
/// \brief ³ëµå¸¦ Àç»ðÀÔ ¸®½ºÆ®¿¡´Ù Ãß°¡ÇÑ´Ù. ÇØ´ç ³ëµå¿Í ºê·£Ä¡µéÀº
/// ³ªÁß¿¡ Æ®¸®¿¡ »õ·ÎÀÌ Ãß°¡ÇÑ´Ù.
/// \param node ³ëµå
/// \param listNode ¸®½ºÆ® °´Ã¼
void ReInsert(Node* node, ListNode** listNode);
/// \brief ½ÇÁ¦ °Ë»ö ÇÔ¼ö
/// \param node °Ë»öÇÒ ³ëµå
/// \param rect ¹Ù¿îµù ¹Ú½º
/// \param foundCount ãÀº µ¥ÀÌÅÍÀÇ °¹¼ö
/// \param results ãÀº µ¥ÀÌÅ͸¦ Áý¾î³ÖÀ» Ä÷º¼Ç
/// \return bool »óÀ§ ÇÔ¼ö¿¡¼ °Ë»öÀ» °è¼ÓÇØ¾ßÇÏ´Â °æ¿ì¿¡´Â true, °Ë»öÀ»
/// Áß´ÜÇØ¾ßÇÏ´Â °æ¿ì¿¡´Â false.
bool Search(Node* node, Rect* rect, int& foundCount, RESULTS& results);
/// \brief ÇØ´çÇÏ´Â ³ëµå¿Í ÀÚ½Ä ³ëµåµéÀ» ¸ðµÎ »èÁ¦ÇÑ´Ù.
/// \param node »èÁ¦ÇÒ ³ëµå
void RemoveAllRec(Node* node);
/// \brief ¸ðµç ³ëµåµéÀ» »èÁ¦ÇÑ´Ù.
void Reset();
/// \brief Æ®¸® ¾È¿¡ ÀÖ´Â µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ ¼¾´Ù.
/// \param node ºÎ¸ð ³ëµåÀÇ Æ÷ÀÎÅÍ
/// \param count µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ Áý¾î³ÖÀ» º¯¼ö
void CountRec(Node* node, int& count);
/// \brief ½ºÆ®¸²¿¡¼ ·¹Äڵ带 ÀоîµéÀδÙ.
/// \param node ºÎ¸ð ³ëµå
/// \param stream ·¹Äڵ带 ÀоîµéÀÏ ½ºÆ®¸² °´Ã¼
/// \return bool Á¤»óÀûÀ¸·Î ·ÎµåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool LoadRec(Node* node, RTFileStream& stream);
/// \brief ½ºÆ®¸²¿¡´Ù ·¹Äڵ带 ÀúÀåÇÑ´Ù.
/// \param node ºÎ¸ð ³ëµå
/// \param stream ·¹Äڵ带 ÀúÀåÇÒ ½ºÆ®¸² °´Ã¼
/// \return bool Á¤»óÀûÀ¸·Î ÀúÀåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇѰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
bool SaveRec(Node* node, RTFileStream& stream);
};
//////////////////////////////////////////////////////////////////////////////
/// \class RTFileStream
/// \brief 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* fileName)
{
m_file = fopen(fileName, "rb");
return !m_file ? false : true;
}
bool OpenWrite(const char* fileName)
{
m_file = fopen(fileName, "wb");
return !m_file ? false : true;
}
void Close()
{
if (m_file)
{
fclose(m_file);
m_file = NULL;
}
}
template< typename TYPE >
size_t Write(const TYPE& value)
{
Assert(m_file);
return fwrite((void*)&value, sizeof(value), 1, m_file);
}
template< typename TYPE >
size_t WriteArray(const TYPE* array, int count)
{
Assert(m_file);
return fwrite((void*)array, sizeof(TYPE) * count, 1, m_file);
}
template< typename TYPE >
size_t Read(TYPE& value)
{
Assert(m_file);
return fread((void*)&value, sizeof(value), 1, m_file);
}
template< typename TYPE >
size_t ReadArray(TYPE* array, int count)
{
Assert(m_file);
return fread((void*)array, sizeof(TYPE) * count, 1, m_file);
}
};
#define RTREE_TEMPLATE template<class DATATYPE, class ELEMTYPE, int NUMDIMS, class ELEMTYPEREAL, int TMAXNODES, int TMINNODES>
#define RTREE_QUALIFIER RTree<DATATYPE, ELEMTYPE, NUMDIMS, ELEMTYPEREAL, TMAXNODES, TMINNODES>
//////////////////////////////////////////////////////////////////////////////
/// \brief »ý¼ºÀÚ
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
RTREE_QUALIFIER::RTree()
{
Assert(MAXNODES > MINNODES);
Assert(MINNODES > 0);
// À§¿¡¼µµ ¼³¸íÇßµíÀÌ, int Å©±â±îÁöÀÇ µ¥ÀÌÅ͸¸ ´Ù·ê ¼ö ÀÖ´Ù.
// ÀÚ¼¼ÇÑ °ÍÀº 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];
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ¼Ò¸êÀÚ
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
RTREE_QUALIFIER::~RTree()
{
Reset(); // Free, or reset node memory
}
//////////////////////////////////////////////////////////////////////////////
/// \brief µ¥ÀÌÅ͸¦ Áý¾î³Ö´Â´Ù.
/// \param min ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ¼Ò°ª
/// \param max ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ´ë°ª
/// \param dataId ½ÇÁ¦ µ¥ÀÌÅÍÀÇ ID. ¾ç¼ö¿©¾ß ÇÑ´Ù. 0Àº µÇ³ª À½¼ö°ªÀº
/// »ç¿ëÇÒ ¼ö ¾ø´Ù.
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
void RTREE_QUALIFIER::Insert(const ELEMTYPE min[NUMDIMS], const ELEMTYPE max[NUMDIMS], const DATATYPE& dataId)
{
#ifdef _DEBUG
for (int index=0; index<NUMDIMS; ++index)
{
Assert(min[index] <= max[index]);
}
#endif //_DEBUG
Rect rect;
for (int axis=0; axis<NUMDIMS; ++axis)
{
rect.m_min[axis] = min[axis];
rect.m_max[axis] = max[axis];
}
InsertRect(&rect, dataId, &m_root, 0);
}
//////////////////////////////////////////////////////////////////////////////
/// \brief µ¥ÀÌÅ͸¦ Á¦°ÅÇÑ´Ù.
/// \param min ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ¼Ò°ª
/// \param max ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ´ë°ª
/// \param dataId ½ÇÁ¦ µ¥ÀÌÅÍÀÇ ID. ¾ç¼ö¿©¾ß ÇÑ´Ù. 0Àº µÇ³ª À½¼ö°ªÀº
/// »ç¿ëÇÒ ¼ö ¾ø´Ù.
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
void RTREE_QUALIFIER::Remove(const ELEMTYPE min[NUMDIMS], const ELEMTYPE max[NUMDIMS], const DATATYPE& dataId)
{
#ifdef _DEBUG
for (int index=0; index<NUMDIMS; ++index)
{
Assert(min[index] <= max[index]);
}
#endif //_DEBUG
Rect rect;
for (int axis=0; axis<NUMDIMS; ++axis)
{
rect.m_min[axis] = min[axis];
rect.m_max[axis] = max[axis];
}
RemoveRect(&rect, dataId, &m_root);
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÇØ´çÇÏ´Â ¹Ù¿îµù ¹Ú½º¿¡ Æ÷ÇԵǴ ¸ðµç µ¥ÀÌÅ͵éÀ» ã´Â´Ù.
/// \param min ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ¼Ò°ª
/// \param max ¹Ù¿îµù ¹Ú½ºÀÇ ÃÖ´ë°ª
/// \param results °á°ú°ªÀ» Áý¾î³ÖÀ» Ä÷º¼Ç °´Ã¼
/// \return ãÀº µ¥ÀÌÅÍÀÇ °¹¼ö
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
int RTREE_QUALIFIER::Search(const ELEMTYPE min[NUMDIMS], const ELEMTYPE max[NUMDIMS], RESULTS& results)
{
#ifdef _DEBUG
for (int index=0; index<NUMDIMS; ++index)
{
Assert(min[index] <= max[index]);
}
#endif //_DEBUG
Rect rect;
for (int axis=0; axis<NUMDIMS; ++axis)
{
rect.m_min[axis] = min[axis];
rect.m_max[axis] = max[axis];
}
// NOTE: May want to return search result another way,
// perhaps returning the number of found elements here.
int foundCount = 0;
Search(m_root, &rect, foundCount, results);
return foundCount;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief Æ®¸® ¾È¿¡ ÀÖ´Â µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ ¹ÝȯÇÑ´Ù.
///
/// ³»ºÎÀûÀ¸·Î µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ À¯ÁöÇÏÁö ¾Ê°í, ÀÌ ÇÔ¼ö°¡ È£ÃâµÉ ¶§¸¶´Ù
/// °è»êÇϱ⠶§¹®¿¡ ´À¸®´Ù. ÀÚÁÖ È£ÃâÇÏÁö ¸» °Í.
///
/// \return int Æ®¸® ¾È¿¡ ÀÖ´Â µ¥ÀÌÅÍÀÇ °¹¼ö
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
int RTREE_QUALIFIER::Count()
{
int count = 0;
CountRec(m_root, count);
return count;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief Æ®¸® ¾È¿¡ ÀÖ´Â µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ ¼¾´Ù.
/// \param node ºÎ¸ð ³ëµåÀÇ Æ÷ÀÎÅÍ
/// \param count µ¥ÀÌÅÍÀÇ °¹¼ö¸¦ Áý¾î³ÖÀ» º¯¼ö
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
void RTREE_QUALIFIER::CountRec(Node* node, int& count)
{
if (node->IsInternalNode()) // not a leaf node
{
for (int index = 0; index < node->m_count; ++index)
{
CountRec(node->m_branch[index].m_child, count);
}
}
else // A leaf node
{
count += node->m_count;
}
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÆÄÀÏ¿¡¼ Æ®¸®¸¦ ·ÎµåÇÑ´Ù.
/// \param fileName ÆÄÀÏ À̸§
/// \return bool Á¤»óÀûÀ¸·Î ·ÎµåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
bool RTREE_QUALIFIER::Load(const char* fileName)
{
RemoveAll(); // Clear existing tree
RTFileStream stream;
if (!stream.OpenRead(fileName))
{
return false;
}
bool result = Load(stream);
stream.Close();
return result;
};
//////////////////////////////////////////////////////////////////////////////
/// \brief ½ºÆ®¸²¿¡¼ Æ®¸®¸¦ ·ÎµåÇÑ´Ù.
/// \param stream ½ºÆ®¸² °´Ã¼
/// \return bool Á¤»óÀûÀ¸·Î ·ÎµåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
bool RTREE_QUALIFIER::Load(RTFileStream& 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;
stream.Read(dataFileId);
stream.Read(dataSize);
stream.Read(dataNumDims);
stream.Read(dataElemSize);
stream.Read(dataElemRealSize);
stream.Read(dataMaxNodes);
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, stream);
}
return result;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ½ºÆ®¸²¿¡¼ ·¹Äڵ带 ÀоîµéÀδÙ.
/// \param node ºÎ¸ð ³ëµå
/// \param stream ·¹Äڵ带 ÀоîµéÀÏ ½ºÆ®¸² °´Ã¼
/// \return bool Á¤»óÀûÀ¸·Î ·ÎµåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇϰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
bool RTREE_QUALIFIER::LoadRec(Node* node, RTFileStream& stream)
{
stream.Read(node->m_level);
stream.Read(node->m_count);
if (node->IsInternalNode()) // not a leaf node
{
for (int index = 0; index < node->m_count; ++index)
{
Branch* curBranch = &node->m_branch[index];
stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS);
stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS);
curBranch->m_child = AllocNode();
LoadRec(curBranch->m_child, stream);
}
}
else // A leaf node
{
for (int index = 0; index < node->m_count; ++index)
{
Branch* curBranch = &node->m_branch[index];
stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS);
stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS);
stream.Read(curBranch->m_data);
}
}
return true; // Should do more error checking on I/O operations
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ÆÄÀÏ¿¡´Ù Æ®¸®¸¦ ÀúÀåÇÑ´Ù.
/// \param fileName ÆÄÀÏ À̸§
/// \return bool Á¤»óÀûÀ¸·Î ÀúÀåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇѰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
bool RTREE_QUALIFIER::Save(const char* fileName)
{
RTFileStream stream;
if (!stream.OpenWrite(fileName))
{
return false;
}
bool result = Save(stream);
stream.Close();
return result;
}
//////////////////////////////////////////////////////////////////////////////
/// \brief ½ºÆ®¸²¿¡´Ù Æ®¸®¸¦ ÀúÀåÇÑ´Ù.
/// \param stream ½ºÆ®¸² °´Ã¼
/// \return bool Á¤»óÀûÀ¸·Î ÀúÀåÇÑ °æ¿ì¿¡´Â true¸¦ ¹ÝȯÇѰí, ¹º°¡ ¿¡·¯°¡
/// »ý±ä °æ¿ì¿¡´Â false¸¦ ¹ÝȯÇÑ´Ù.
//////////////////////////////////////////////////////////////////////////////
RTREE_TEMPLATE
bool RTREE_QUALIFIER::Save(RTFileStream& stream)
{