四叉树空间索引原理及其实现
2014-12-24 09:11
260 查看
四叉树索引的基本思想是将地理空间递归划分为不同层次的树结构。它将已知范围的空间等分成四个相等的子空间,如此递归下去,直至树的层次达到一定深度或者满足某种要求后停止分割。四叉树的结构比较简单,并且当空间数据对象分布比较均匀时,具有比较高的空间数据插入和查询效率,因此四叉树是GIS中常用的空间索引之一。常规四叉树的结构如图所示,地理空间对象都存储在叶子节点上,中间节点以及根节点不存储地理空间对象。
四叉树示意图
四叉树对于区域查询,效率比较高。但如果空间对象分布不均匀,随着地理空间对象的不断插入,四叉树的层次会不断地加深,将形成一棵严重不平衡的四叉树,那么每次查询的深度将大大的增多,从而导致查询效率的急剧下降。
本节将介绍一种改进的四叉树索引结构。四叉树结构是自顶向下逐步划分的一种树状的层次结构。传统的四叉树索引存在着以下几个缺点:
(1)空间实体只能存储在叶子节点中,中间节点以及根节点不能存储空间实体信息,随着空间对象的不断插入,最终会导致四叉树树的层次比较深,在进行空间数据窗口查询的时候效率会比较低下。
(2)同一个地理实体在四叉树的分裂过程中极有可能存储在多个节点中,这样就导致了索引存储空间的浪费。
(3)由于地理空间对象可能分布不均衡,这样会导致常规四叉树生成一棵极为不平衡的树,这样也会造成树结构的不平衡以及存储空间的浪费。
相应的改进方法,将地理实体信息存储在完全包含它的最小矩形节点中,不存储在它的父节点中,每个地理实体只在树中存储一次,避免存储空间的浪费。首先生成满四叉树,避免在地理实体插入时需要重新分配内存,加快插入的速度,最后将空的节点所占内存空间释放掉。改进后的四叉树结构如下图所示。四叉树的深度一般取经验值4-7之间为最佳。
图改进的四叉树结构
为了维护空间索引与对存储在文件或数据库中的空间数据的一致性,作者设计了如下的数据结构支持四叉树的操作。
(1)四分区域标识
分别定义了一个平面区域的四个子区域索引号,右上为第一象限0,左上为第二象限1,左下为第三象限2,右下为第四象限3。
typedef enum
{
UR = 0,// UR第一象限
UL = 1, // UL为第二象限
LL = 2, // LL为第三象限
LR = 3 // LR为第四象限
}QuadrantEnum;
(2)空间对象数据结构
空间对象数据结构是对地理空间对象的近似,在空间索引中,相当一部分都是采用MBR作为近似。
/*空间对象MBR信息*/
typedef struct SHPMBRInfo
{
int nID; //空间对象ID号
MapRect Box; //空间对象MBR范围坐标
}SHPMBRInfo;
nID是空间对象的标识号,Box是空间对象的最小外包矩形(MBR)。
(3)四叉树节点数据结构
四叉树节点是四叉树结构的主要组成部分,主要用于存储空间对象的标识号和MBR,也是四叉树算法操作的主要部分。
/*四叉树节点类型结构*/
typedef struct QuadNode
{
MapRect Box; //节点所代表的矩形区域
int nShpCount; //节点所包含的所有空间对象个数
SHPMBRInfo* pShapeObj; //空间对象指针数组
int nChildCount; //子节点个数
QuadNode *children[4]; //指向节点的四个孩子
}QuadNode;
Box是代表四叉树对应区域的最小外包矩形,上一层的节点的最小外包矩形包含下一层最小外包矩形区域;nShpCount代表本节点包含的空间对象的个数;pShapeObj代表指向空间对象存储地址的首地址,同一个节点的空间对象在内存中连续存储;nChildCount代表节点拥有的子节点的数目;children是指向孩子节点指针的数组。
上述理论部分都都讲的差不多了,下面就贴上我的C语言实现版本代码。
头文件如下:
源文件如下:
代码有点长,有需要的朋友可以借鉴并自己优化。
四叉树示意图
四叉树对于区域查询,效率比较高。但如果空间对象分布不均匀,随着地理空间对象的不断插入,四叉树的层次会不断地加深,将形成一棵严重不平衡的四叉树,那么每次查询的深度将大大的增多,从而导致查询效率的急剧下降。
本节将介绍一种改进的四叉树索引结构。四叉树结构是自顶向下逐步划分的一种树状的层次结构。传统的四叉树索引存在着以下几个缺点:
(1)空间实体只能存储在叶子节点中,中间节点以及根节点不能存储空间实体信息,随着空间对象的不断插入,最终会导致四叉树树的层次比较深,在进行空间数据窗口查询的时候效率会比较低下。
(2)同一个地理实体在四叉树的分裂过程中极有可能存储在多个节点中,这样就导致了索引存储空间的浪费。
(3)由于地理空间对象可能分布不均衡,这样会导致常规四叉树生成一棵极为不平衡的树,这样也会造成树结构的不平衡以及存储空间的浪费。
相应的改进方法,将地理实体信息存储在完全包含它的最小矩形节点中,不存储在它的父节点中,每个地理实体只在树中存储一次,避免存储空间的浪费。首先生成满四叉树,避免在地理实体插入时需要重新分配内存,加快插入的速度,最后将空的节点所占内存空间释放掉。改进后的四叉树结构如下图所示。四叉树的深度一般取经验值4-7之间为最佳。
图改进的四叉树结构
为了维护空间索引与对存储在文件或数据库中的空间数据的一致性,作者设计了如下的数据结构支持四叉树的操作。
(1)四分区域标识
分别定义了一个平面区域的四个子区域索引号,右上为第一象限0,左上为第二象限1,左下为第三象限2,右下为第四象限3。
typedef enum
{
UR = 0,// UR第一象限
UL = 1, // UL为第二象限
LL = 2, // LL为第三象限
LR = 3 // LR为第四象限
}QuadrantEnum;
(2)空间对象数据结构
空间对象数据结构是对地理空间对象的近似,在空间索引中,相当一部分都是采用MBR作为近似。
/*空间对象MBR信息*/
typedef struct SHPMBRInfo
{
int nID; //空间对象ID号
MapRect Box; //空间对象MBR范围坐标
}SHPMBRInfo;
nID是空间对象的标识号,Box是空间对象的最小外包矩形(MBR)。
(3)四叉树节点数据结构
四叉树节点是四叉树结构的主要组成部分,主要用于存储空间对象的标识号和MBR,也是四叉树算法操作的主要部分。
/*四叉树节点类型结构*/
typedef struct QuadNode
{
MapRect Box; //节点所代表的矩形区域
int nShpCount; //节点所包含的所有空间对象个数
SHPMBRInfo* pShapeObj; //空间对象指针数组
int nChildCount; //子节点个数
QuadNode *children[4]; //指向节点的四个孩子
}QuadNode;
Box是代表四叉树对应区域的最小外包矩形,上一层的节点的最小外包矩形包含下一层最小外包矩形区域;nShpCount代表本节点包含的空间对象的个数;pShapeObj代表指向空间对象存储地址的首地址,同一个节点的空间对象在内存中连续存储;nChildCount代表节点拥有的子节点的数目;children是指向孩子节点指针的数组。
上述理论部分都都讲的差不多了,下面就贴上我的C语言实现版本代码。
头文件如下:
#pragma once #include <vector> #include "ogrsf_frmts.h" #include "ogr_core.h" using namespace std; #ifndef _POINTD #define _POINTD typedef struct tagPOINTD { double x; double y; }POINTD; #endif // _POINTD /* 一个矩形区域的象限划分:: UL(1) | UR(0) ----------|----------- LL(2) | LR(3) 以下对该象限类型的枚举 */ typedef enum { UR = 0, UL = 1, LL = 2, LR = 3 }QuadrantEnum; /*空间对象MBR信息*/ typedef struct SHPMBRInfo { long nID; //空间对象ID号 OGREnvelope envelope; //空间对象MBR范围坐标 }SHPMBRInfo; /* 四叉树节点类型结构 */ typedef struct QuadNode { OGREnvelope envelope; //节点所代表的矩形区域 int nShpCount; //节点所包含的所有空间对象个数 SHPMBRInfo* pShapeObj; //空间对象指针数组 int nChildCount; //子节点个数 QuadNode *children[4]; //指向节点的四个孩子 }QuadNode; /* 四叉树类型结构 */ typedef struct quadtree_t { QuadNode *root; int depth; // 四叉树的深度 }QuadTree; //初始化四叉树节点 QuadNode *InitQuadNode(); //层次创建四叉树方法(满四叉树) void CreateQuadTree(int depth,OGRLayer *poLayer,QuadTree* pQuadTree); //创建各个分支 void CreateQuadBranch(int depth,OGREnvelope &rect,QuadNode** node); //构建四叉树空间索引 void BuildQuadTree(OGRLayer*poLayer,QuadTree* pQuadTree); //四叉树索引查询(矩形查询) void SearchQuadTree(QuadNode* node,OGREnvelope &queryRect,vector<long>& ItemSearched); //四叉树索引查询(矩形查询)并行查询 void SearchQuadTreePara(vector<QuadNode*> resNodes,OGREnvelope &queryRect,vector<long>& ItemSearched); //四叉树的查询(点查询) void PtSearchQTree(QuadNode* node,double cx,double cy,vector<long>& ItemSearched); //将指定的空间对象插入到四叉树中 void Insert(long key,OGREnvelope &itemRect,QuadNode* pNode); //将指定的空间对象插入到四叉树中 void InsertQuad(long key,OGREnvelope &itemRect,QuadNode* pNode); //将指定的空间对象插入到四叉树中 void InsertQuad2(long key,OGREnvelope &itemRect,QuadNode* pNode); //判断一个节点是否是叶子节点 bool IsQuadLeaf(QuadNode* node); //删除多余的节点 bool DelFalseNode(QuadNode* node); //四叉树遍历(所有要素) void TraversalQuadTree(QuadNode* quadTree,vector<long>& resVec); //四叉树遍历(所有节点) void TraversalQuadTree(QuadNode* quadTree,vector<QuadNode*>& arrNode); //释放树的内存空间 void ReleaseQuadTree(QuadNode** quadTree); //计算四叉树所占的字节的大小 long CalByteQuadTree(QuadNode* quadTree,long& nSize); void split(OGREnvelope origin,OGREnvelope target[]); bool IsPointInRect(OGREnvelope envelope,POINTD point); bool IsPointInRect(OGREnvelope envelope,double cx,double cy);
源文件如下:
<pre name="code" class="cpp">#include "StdAfx.h" #include <assert.h> #include <algorithm> #include <deque> #include "QuadTree.h" QuadNode *InitQuadNode() { QuadNode *node = new QuadNode; node->envelope.MaxX = 0; node->envelope.MaxY = 0; node->envelope.MinX = 0; node->envelope.MinY = 0; for (int i = 0; i < 4; i ++) { node->children[i] = NULL; } node->nChildCount = 0; node->nShpCount = 0; node->pShapeObj = NULL; return node; } void CreateQuadTree(int depth,OGRLayer *poLayer,QuadTree* pQuadTree) { pQuadTree->depth = depth; OGREnvelope env; //整个图层的MBR poLayer->GetExtent(&env); OGREnvelope rect; rect.MinX = env.MinX; rect.MinY = env.MinY; rect.MaxX = env.MaxX; rect.MaxY = env.MaxY; //创建各个分支 CreateQuadBranch(depth,rect,&(pQuadTree->root)); int nCount = poLayer->GetFeatureCount(); OGRFeature **pFeatureClass = new OGRFeature*[nCount]; for (int i = 0; i < poLayer->GetFeatureCount(); ++i) { pFeatureClass[i] = poLayer->GetFeature(i); } //插入各个要素 OGREnvelope envObj; //空间对象的MBR //#pragma omp parallel for for (int i = 0; i < nCount; ++i) { pFeatureClass[i]->GetGeometryRef()->getEnvelope(&envObj); rect.MinX = envObj.MinX; rect.MinY = envObj.MinY; rect.MaxX = envObj.MaxX; rect.MaxY = envObj.MaxY; InsertQuad(i,rect,pQuadTree->root); } //DelFalseNode(pQuadTree->root); } void CreateQuadBranch(int depth,OGREnvelope &rect,QuadNode** node) { if (depth != 0) { *node = InitQuadNode(); //创建树根 QuadNode *pNode = *node; pNode->envelope = rect; pNode->nChildCount = 4; OGREnvelope boxs[4]; split(pNode->envelope,boxs); for (int i = 0; i < 4; ++i) { //创建四个节点并插入相应的MBR pNode->children[i] = InitQuadNode(); pNode->children[i]->envelope = boxs[i]; CreateQuadBranch(depth-1,boxs[i],&(pNode->children[i])); } } } void BuildQuadTree(OGRLayer *poLayer,QuadTree* pQuadTree) { assert(poLayer); OGREnvelope env; //整个图层的MBR poLayer->GetExtent(&env); pQuadTree->root = InitQuadNode(); QuadNode* rootNode = pQuadTree->root; rootNode->envelope.MinX = env.MinX; rootNode->envelope.MinY = env.MinY; rootNode->envelope.MaxX = env.MaxX; rootNode->envelope.MaxY = env.MaxY; //设置树的深度( 根据等比数列的求和公式) //pQuadTree->depth = log(poLayer->GetFeatureCount()*3/8.0+1)/log(4.0); int nCount = poLayer->GetFeatureCount(); OGREnvelope envObj; //空间对象的MBR for (int i = 0; i < nCount; ++i) { poLayer->GetFeature(i)->GetGeometryRef()->getEnvelope(&envObj); InsertQuad2(i,envObj,rootNode); printf("Shape:%d\n",i); } DelFalseNode(pQuadTree->root); } void SearchQuadTree(QuadNode* node,OGREnvelope &queryRect,vector<long>& ItemSearched) { assert(node); //int coreNum = omp_get_num_procs(); //vector<int> * pResArr = new vector<int>[coreNum]; if (NULL != node) { for (int i = 0; i < node->nShpCount; ++i) { if (queryRect.Contains(node->pShapeObj[i].envelope) || queryRect.Intersects(node->pShapeObj[i].envelope)) { ItemSearched.push_back(node->pShapeObj[i].nID); } } //并行搜索四个孩子节点 /*#pragma omp parallel sections { #pragma omp section if ((node->children[0] != NULL) && (node->children[0]->Box.Contains(queryRect) || node->children[0]->Box.Intersects(queryRect))) { int tid = omp_get_thread_num(); SearchQuadTree(node->children[0],queryRect,pResArr[tid]); } #pragma omp section if ((node->children[1] != NULL) && (node->children[1]->Box.Contains(queryRect) || node->children[1]->Box.Intersects(queryRect))) { int tid = omp_get_thread_num(); SearchQuadTree(node->children[1],queryRect,pResArr[tid]); } #pragma omp section if ((node->children[2] != NULL) && (node->children[2]->Box.Contains(queryRect) || node->children[2]->Box.Intersects(queryRect))) { int tid = omp_get_thread_num(); SearchQuadTree(node->children[2],queryRect,pResArr[tid]); } #pragma omp section if ((node->children[3] != NULL) && (node->children[3]->Box.Contains(queryRect) || node->children[3]->Box.Intersects(queryRect))) { int tid = omp_get_thread_num(); SearchQuadTree(node->children[3],queryRect,pResArr[tid]); } }*/ for (int i = 0; i < 4; ++i) { if ((node->children[i] != NULL) && (node->children[i]->envelope.Contains(queryRect) || node->children[i]->envelope.Intersects(queryRect))) { SearchQuadTree(node->children[i],queryRect,ItemSearched); //node = node->children[i]; //非递归 } } } /*for (int i = 0 ; i < coreNum; i ++) { ItemSearched.insert(ItemSearched.end(),pResArr[i].begin(),pResArr[i].end()); }*/ } void SearchQuadTreePara(vector<QuadNode*> resNodes,OGREnvelope &queryRect,vector<long>& ItemSearched) { // int coreNum = omp_get_num_procs(); // omp_set_num_threads(coreNum); // vector<int>* searchArrs = new vector<int>[coreNum]; // for (int i = 0; i < coreNum; i ++) // { // searchArrs[i].clear(); // } // // #pragma omp parallel for // for (int i = 0; i < (int)resNodes.size(); i ++) // { // int tid = omp_get_thread_num(); // for (int j = 0; j < resNodes[i]->nShpCount; j ++) // { // if (queryRect.Contains(resNodes[i]->pShapeObj[j].envelope) // || queryRect.Intersects(resNodes[i]->pShapeObj[j].envelope)) // { // searchArrs[tid].push_back(resNodes[i]->pShapeObj[j].nID); // } // } // } // // for (int i = 0; i < coreNum; i ++) // { // ItemSearched.insert(ItemSearched.end(), // searchArrs[i].begin(),searchArrs[i].end()); // } // // delete [] searchArrs; // searchArrs = NULL; vector<long> searchArrs; for (int i = 0; i < (int)resNodes.size(); ++i) { for (int j = 0; j < resNodes[i]->nShpCount; ++j) { if (queryRect.Contains(resNodes[i]->pShapeObj[j].envelope) || queryRect.Intersects(resNodes[i]->pShapeObj[j].envelope)) { searchArrs.push_back(resNodes[i]->pShapeObj[j].nID); } } } ItemSearched.insert(ItemSearched.end(), searchArrs.begin(),searchArrs.end()); } void PtSearchQTree(QuadNode* node,double cx,double cy,vector<long>& ItemSearched) { assert(node); if (node->nShpCount >0) //节点 { for (int i = 0; i < node->nShpCount; ++i) { if (IsPointInRect(node->pShapeObj[i].envelope,cx,cy)) { ItemSearched.push_back(node->pShapeObj[i].nID); } } } else if (node->nChildCount >0) //子节点 { for (int i = 0; i < 4; ++i) { if (IsPointInRect(node->children[i]->envelope,cx,cy)) { PtSearchQTree(node->children[i],cx,cy,ItemSearched); } } } //找出重复元素的位置 sort(ItemSearched.begin(),ItemSearched.end()); //先排序,默认升序 vector<long>::iterator unique_iter = unique(ItemSearched.begin(),ItemSearched.end()); ItemSearched.erase(unique_iter,ItemSearched.end()); } void Insert(long key, OGREnvelope &itemRect,QuadNode* pNode) { QuadNode *node = pNode; //保留根节点副本 SHPMBRInfo pShpInfo; //节点有孩子 if (0 < node->nChildCount) { for (int i = 0; i < 4; ++i) { //如果包含或相交,则将节点插入到此节点 if (node->children[i]->envelope.Contains(itemRect) || node->children[i]->envelope.Intersects(itemRect)) { //node = node->children[i]; Insert(key,itemRect,node->children[i]); } } } else if (1 == node->nShpCount)//如果当前节点存在一个子节点时 { OGREnvelope boxs[4]; split(node->envelope,boxs); //创建四个节点并插入相应的MBR node->children[UR] = InitQuadNode(); node->children[UL] = InitQuadNode(); node->children[LL] = InitQuadNode(); node->children[LR] = InitQuadNode(); node->children[UR]->envelope = boxs[0]; node->children[UL]->envelope = boxs[1]; node->children[LL]->envelope = boxs[2]; node->children[LR]->envelope = boxs[3]; node->nChildCount = 4; for (int i = 0; i < 4; ++i) { //将当前节点中的要素移动到相应的子节点中 for (int j = 0; j < node->nShpCount; j ++) { if (node->children[i]->envelope.Contains(node->pShapeObj[j].envelope) || node->children[i]->envelope.Intersects(node->pShapeObj[j].envelope)) { ++node->children[i]->nShpCount; node->children[i]->pShapeObj = (SHPMBRInfo*)malloc(node->children[i]->nShpCount*sizeof(SHPMBRInfo)); memcpy(node->children[i]->pShapeObj,&(node->pShapeObj[j]),sizeof(SHPMBRInfo)); free(node->pShapeObj); node->pShapeObj = NULL; node->nShpCount = 0; } } } for (int i = 0; i < 4; i ++) { //如果包含或相交,则将节点插入到此节点 if (node->children[i]->envelope.Contains(itemRect) || node->children[i]->envelope.Intersects(itemRect)) { pShpInfo.envelope = itemRect; pShpInfo.nID = key; if (node->children[i]->nShpCount == 0) //如果之前没有节点 { ++node->children[i]->nShpCount; node->children[i]->pShapeObj = (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->children[i]->nShpCount); } else if (node->children[i]->nShpCount > 0) { ++node->children[i]->nShpCount; node->children[i]->pShapeObj = (SHPMBRInfo *)realloc(node->children[i]->pShapeObj, sizeof(SHPMBRInfo)*node->children[i]->nShpCount); } memcpy(node->children[i]->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo)); } } } else if (0 == node->nShpCount)//当前节点没有空间对象 { ++node->nShpCount; node->pShapeObj = (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount); pShpInfo.envelope = itemRect; pShpInfo.nID = key; memcpy(node->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo)); } } void InsertQuad(long key,OGREnvelope &itemRect,QuadNode* pNode) { assert(pNode != NULL); if (!IsQuadLeaf(pNode)) //非叶子节点 { int nCorver = 0; //跨越的子节点个数 int iIndex = -1; //被哪个子节点完全包含的索引号 for (int i = 0; i < 4; ++i) { if (pNode->children[i]->envelope.Contains(itemRect) && pNode->envelope.Contains(itemRect)) { ++nCorver; iIndex = i; } } //如果被某一个子节点包含,则进入该子节点 if (/*pNode->Box.Contains(itemRect) || pNode->Box.Intersects(itemRect)*/1 <= nCorver) { InsertQuad(key,itemRect,pNode->children[iIndex]); } //如果跨越了多个子节点,直接放在这个节点中 else if (nCorver == 0) { if (pNode->nShpCount == 0) //如果之前没有节点 { ++pNode->nShpCount; pNode->pShapeObj = (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*pNode->nShpCount); } else { ++pNode->nShpCount; pNode->pShapeObj = (SHPMBRInfo *)realloc(pNode->pShapeObj,sizeof(SHPMBRInfo)*pNode->nShpCount); } SHPMBRInfo pShpInfo; pShpInfo.envelope = itemRect; pShpInfo.nID = key; memcpy(pNode->pShapeObj+pNode->nShpCount-1,&pShpInfo,sizeof(SHPMBRInfo)); } } else if (IsQuadLeaf(pNode))//如果是叶子节点,直接放进去 { if (pNode->nShpCount == 0) //如果之前没有节点 { ++pNode->nShpCount; pNode->pShapeObj = (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*pNode->nShpCount); } else { ++pNode->nShpCount; pNode->pShapeObj = (SHPMBRInfo *)realloc(pNode->pShapeObj,sizeof(SHPMBRInfo)*pNode->nShpCount); } SHPMBRInfo pShpInfo; pShpInfo.envelope = itemRect; pShpInfo.nID = key; memcpy(pNode->pShapeObj+pNode->nShpCount-1,&pShpInfo,sizeof(SHPMBRInfo)); } } void InsertQuad2(long key,OGREnvelope &itemRect,QuadNode* pNode) { QuadNode *node = pNode; //保留根节点副本 SHPMBRInfo pShpInfo; //节点有孩子 if (0 < node->nChildCount) { for (int i = 0; i < 4; ++i) { //如果包含或相交,则将节点插入到此节点 if (node->children[i]->envelope.Contains(itemRect) || node->children[i]->envelope.Intersects(itemRect)) { //node = node->children[i]; Insert(key,itemRect,node->children[i]); } } } else if (0 == node->nChildCount)//如果当前节点存在一个子节点时 { OGREnvelope boxs[4]; split(node->envelope,boxs); int cnt = -1; for (int i = 0; i < 4; ++i) { //如果包含或相交,则将节点插入到此节点 if (boxs[i].Contains(itemRect)) { cnt = i; break; } } //如果有一个矩形包含此对象,则创建四个孩子节点 if (cnt > -1) { for (int i = 0; i < 4; ++i) { //创建四个节点并插入相应的MBR node->children[i] = InitQuadNode(); node->children[i]->envelope = boxs[i]; } node->nChildCount = 4; InsertQuad2(key,itemRect,node->children[cnt]); //递归 } else if (cnt == -1)//如果都不包含,则直接将对象插入此节点 { if (node->nShpCount == 0) //如果之前没有节点 { ++node->nShpCount; node->pShapeObj = (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount); } else if (node->nShpCount > 0) { ++node->nShpCount; node->pShapeObj = (SHPMBRInfo *)realloc(node->pShapeObj,sizeof(SHPMBRInfo)*node->nShpCount); } pShpInfo.envelope = itemRect; pShpInfo.nID = key; memcpy(node->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo)); } } //当前节点没有空间对象 /*else if (0 == node->nShpCount) { node->nShpCount += 1; node->pShapeObj = (SHPMBRInfo*)malloc(sizeof(SHPMBRInfo)*node->nShpCount); pShpInfo.Box = itemRect; pShpInfo.nID = key; memcpy(node->pShapeObj,&pShpInfo,sizeof(SHPMBRInfo)); }*/ } bool IsQuadLeaf(QuadNode* node) { if (NULL == node) { return 1; } for (int i = 0; i < 4; ++i) { if (node->children[i] != NULL) { return 0; } } return true; } bool DelFalseNode(QuadNode* node) { //如果没有子节点且没有要素 if (node->nChildCount ==0 && node->nShpCount == 0) { ReleaseQuadTree(&node); } else if (node->nChildCount > 0)//如果有子节点 { for (int i = 0; i < 4; ++i) { DelFalseNode(node->children[i]); } } return true; } void TraversalQuadTree(QuadNode* quadTree,vector<long>& resVec) { QuadNode *node = quadTree; int i = 0; if (NULL != node) { //将本节点中的空间对象存储数组中 for (i = 0; i < node->nShpCount; ++i) { resVec.push_back((node->pShapeObj+i)->nID); } //遍历孩子节点 for (i = 0; i < node->nChildCount; ++i) { if (node->children[i] != NULL) { TraversalQuadTree(node->children[i],resVec); } } } } void TraversalQuadTree(QuadNode* quadTree,vector<QuadNode*>& arrNode) { deque<QuadNode*> nodeQueue; if (quadTree != NULL) { nodeQueue.push_back(quadTree); while (!nodeQueue.empty()) { QuadNode* queueHead = nodeQueue.at(0); //取队列头结点 arrNode.push_back(queueHead); nodeQueue.pop_front(); for (int i = 0; i < 4; ++i) { if (queueHead->children[i] != NULL) { nodeQueue.push_back(queueHead->children[i]); } } } } } void ReleaseQuadTree(QuadNode** quadTree) { int i = 0; QuadNode* node = *quadTree; if (NULL == node) { return; } else { for (i = 0; i < 4; ++i) { ReleaseQuadTree(&node->children[i]); } free(node); node = NULL; } node = NULL; } long CalByteQuadTree(QuadNode* quadTree,long& nSize) { if (quadTree != NULL) { nSize += sizeof(QuadNode)+quadTree->nChildCount*sizeof(SHPMBRInfo); for (int i = 0; i < 4; ++i) { if (quadTree->children[i] != NULL) { nSize += CalByteQuadTree(quadTree->children[i],nSize); } } } return 1; } void split( OGREnvelope origin,OGREnvelope target[] ) { double width = origin.MaxX-origin.MinX; double height = origin.MaxY-origin.MinY; target[0].MinX = target[1].MaxX = target[2].MaxX = target[3].MinX = origin.MinX+width/2; target[0].MaxX = target[3].MaxX = origin.MaxX; target[1].MinX = target[2].MinX = origin.MinX; target[0].MaxY = target[1].MaxY = target[2].MinY = target[3].MinY = origin.MinY+height/2; target[0].MinY = target[1].MinY = origin.MinY; target[2].MaxY = target[3].MaxY = origin.MaxY; } bool IsPointInRect( OGREnvelope envelope,POINTD point ) { if (envelope.MinX > point.x || envelope.MaxX < point.x || envelope.MinY > point.y || envelope.MaxY < point.y) { return false; } return true; } bool IsPointInRect( OGREnvelope envelope,double cx,double cy ) { if (envelope.MinX > cx || envelope.MaxX < cx || envelope.MinY > cy || envelope.MaxY < cy) { return false; } return true; }
代码有点长,有需要的朋友可以借鉴并自己优化。
相关文章推荐
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现 && 递归遍历叶节点并输出至数组
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 四叉树空间索引原理及其实现
- 一种简单的嵌入式字库设计及其实现原理
- Yale CAS实现原理及其基础协议
- Yale CAS实现原理及其基础协议
- 射频卡多线程读写原理及其实现
- Yale CAS实现原理及其基础协议
- 仿基因编程原理及其C++实现
- Java对象池技术原理及其实现