ultimatepp/bazaar/plugin/gdal/port/cpl_quad_tree.cpp
cxl 23ff1e7e82 .gdal moved to bazaar
git-svn-id: svn://ultimatepp.org/upp/trunk@9273 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2015-12-07 13:36:24 +00:00

852 lines
32 KiB
C++

/******************************************************************************
* $Id: cpl_quad_tree.cpp 27044 2014-03-16 23:41:27Z rouault $
*
* Project: CPL - Common Portability Library
* Purpose: Implementation of quadtree building and searching functions.
* Derived from shapelib and mapserver implementations
* Author: Frank Warmerdam, warmerdam@pobox.com
* Even Rouault, <even dot rouault at mines dash paris dot org>
*
******************************************************************************
* Copyright (c) 1999-2008, Frank Warmerdam
* Copyright (c) 2008-2014, Even Rouault <even dot rouault at mines-paris dot org>
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
*/
#include "cpl_conv.h"
#include "cpl_quad_tree.h"
CPL_CVSID("$Id: cpl_quad_tree.cpp 27044 2014-03-16 23:41:27Z rouault $");
#define MAX_DEFAULT_TREE_DEPTH 12
#define MAX_SUBNODES 4
typedef struct _QuadTreeNode QuadTreeNode;
struct _QuadTreeNode
{
/* area covered by this psNode */
CPLRectObj rect;
int nFeatures; /* number of shapes stored at this psNode. */
int nNumSubNodes; /* number of active subnodes */
void **pahFeatures; /* list of shapes stored at this psNode. */
CPLRectObj *pasBounds;
QuadTreeNode *apSubNode[MAX_SUBNODES];
};
struct _CPLQuadTree
{
QuadTreeNode *psRoot;
CPLQuadTreeGetBoundsFunc pfnGetBounds;
int nFeatures;
int nMaxDepth;
int nBucketCapacity;
double dfSplitRatio;
};
static void CPLQuadTreeAddFeatureInternal(CPLQuadTree *hQuadTree,
void* hFeature,
const CPLRectObj *pRect);
/* -------------------------------------------------------------------- */
/* If the following is 0.5, psNodes will be split in half. If it */
/* is 0.6 then each apSubNode will contain 60% of the parent */
/* psNode, with 20% representing overlap. This can be help to */
/* prevent small objects on a boundary from shifting too high */
/* up the hQuadTree. */
/* -------------------------------------------------------------------- */
#define DEFAULT_SPLIT_RATIO 0.55
/*
** Returns TRUE if rectangle a is contained in rectangle b
*/
static CPL_INLINE int CPL_RectContained(const CPLRectObj *a, const CPLRectObj *b)
{
if(a->minx >= b->minx && a->maxx <= b->maxx)
if(a->miny >= b->miny && a->maxy <= b->maxy)
return(TRUE);
return(FALSE);
}
/*
** Returns TRUE if rectangles a and b overlap
*/
static CPL_INLINE int CPL_RectOverlap(const CPLRectObj *a, const CPLRectObj *b)
{
if(a->minx > b->maxx) return(FALSE);
if(a->maxx < b->minx) return(FALSE);
if(a->miny > b->maxy) return(FALSE);
if(a->maxy < b->miny) return(FALSE);
return(TRUE);
}
/************************************************************************/
/* CPLQuadTreeNodeCreate() */
/************************************************************************/
static QuadTreeNode *CPLQuadTreeNodeCreate(const CPLRectObj* pRect)
{
QuadTreeNode *psNode;
psNode = (QuadTreeNode *) CPLMalloc(sizeof(QuadTreeNode));
psNode->nFeatures = 0;
psNode->pahFeatures = NULL;
psNode->pasBounds = NULL;
psNode->nNumSubNodes = 0;
memcpy(&(psNode->rect), pRect, sizeof(CPLRectObj));
return psNode;
}
/************************************************************************/
/* CPLQuadTreeCreate() */
/************************************************************************/
/**
* Create a new quadtree
*
* @param pGlobalBounds a pointer to the global extent of all
* the elements that will be inserted
* @param pfnGetBounds a user provided function to get the bounding box of
* the inserted elements. If it is set to NULL, then
* CPLQuadTreeInsertWithBounds() must be used, and
* extra memory will be used to keep features bounds in the
* quad tree.
*
* @return a newly allocated quadtree
*/
CPLQuadTree *CPLQuadTreeCreate(const CPLRectObj* pGlobalBounds, CPLQuadTreeGetBoundsFunc pfnGetBounds)
{
CPLQuadTree *hQuadTree;
CPLAssert(pGlobalBounds);
/* -------------------------------------------------------------------- */
/* Allocate the hQuadTree object */
/* -------------------------------------------------------------------- */
hQuadTree = (CPLQuadTree *) CPLMalloc(sizeof(CPLQuadTree));
hQuadTree->nFeatures = 0;
hQuadTree->pfnGetBounds = pfnGetBounds;
hQuadTree->nMaxDepth = 0;
hQuadTree->nBucketCapacity = 8;
hQuadTree->dfSplitRatio = DEFAULT_SPLIT_RATIO;
/* -------------------------------------------------------------------- */
/* Allocate the psRoot psNode. */
/* -------------------------------------------------------------------- */
hQuadTree->psRoot = CPLQuadTreeNodeCreate(pGlobalBounds);
return hQuadTree;
}
/************************************************************************/
/* CPLQuadTreeGetAdvisedMaxDepth() */
/************************************************************************/
/**
* Returns the optimal depth of a quadtree to hold nExpectedFeatures
*
* @param nExpectedFeatures the expected maximum number of elements to be inserted
*
* @return the optimal depth of a quadtree to hold nExpectedFeatures
*/
int CPLQuadTreeGetAdvisedMaxDepth(int nExpectedFeatures)
{
/* -------------------------------------------------------------------- */
/* Try to select a reasonable one */
/* that implies approximately 8 shapes per node. */
/* -------------------------------------------------------------------- */
int nMaxDepth = 0;
int nMaxNodeCount = 1;
while( nMaxNodeCount*4 < nExpectedFeatures )
{
nMaxDepth += 1;
nMaxNodeCount = nMaxNodeCount * 2;
}
CPLDebug( "CPLQuadTree",
"Estimated spatial index tree depth: %d",
nMaxDepth );
/* NOTE: Due to problems with memory allocation for deep trees,
* automatically estimated depth is limited up to 12 levels.
* See Ticket #1594 for detailed discussion.
*/
if( nMaxDepth > MAX_DEFAULT_TREE_DEPTH )
{
nMaxDepth = MAX_DEFAULT_TREE_DEPTH;
CPLDebug( "CPLQuadTree",
"Falling back to max number of allowed index tree levels (%d).",
MAX_DEFAULT_TREE_DEPTH );
}
return nMaxDepth;
}
/************************************************************************/
/* CPLQuadTreeSetMaxDepth() */
/************************************************************************/
/**
* Set the maximum depth of a quadtree. By default, quad trees have
* no maximum depth, but a maximum bucket capacity.
*
* @param hQuadTree the quad tree
* @param nMaxDepth the maximum depth allowed
*/
void CPLQuadTreeSetMaxDepth(CPLQuadTree *hQuadTree, int nMaxDepth)
{
hQuadTree->nMaxDepth = nMaxDepth;
}
/************************************************************************/
/* CPLQuadTreeSetBucketCapacity() */
/************************************************************************/
/**
* Set the maximum capacity of a node of a quadtree. The default value is 8.
* Note that the maximum capacity will only be honoured if the features
* inserted have a point geometry. Otherwise it may be exceeded.
*
* @param hQuadTree the quad tree
* @param nBucketCapacity the maximum capactiy of a node of a quadtree
*/
void CPLQuadTreeSetBucketCapacity(CPLQuadTree *hQuadTree, int nBucketCapacity)
{
if( nBucketCapacity > 0 )
hQuadTree->nBucketCapacity = nBucketCapacity;
}
/************************************************************************/
/* CPLQuadTreeInsert() */
/************************************************************************/
/**
* Insert a feature into a quadtree
*
* @param hQuadTree the quad tree
* @param hFeature the feature to insert
*/
void CPLQuadTreeInsert(CPLQuadTree * hQuadTree, void* hFeature)
{
CPLRectObj bounds;
if( hQuadTree->pfnGetBounds == NULL )
{
CPLError(CE_Failure, CPLE_AppDefined,
"hQuadTree->pfnGetBounds == NULL");
return;
}
hQuadTree->nFeatures ++;
hQuadTree->pfnGetBounds(hFeature, &bounds);
CPLQuadTreeAddFeatureInternal(hQuadTree, hFeature, &bounds);
}
/************************************************************************/
/* CPLQuadTreeInsertWithBounds() */
/************************************************************************/
/**
* Insert a feature into a quadtree
*
* @param hQuadTree the quad tree
* @param hFeature the feature to insert
* @param psBounds bounds of the feature
*/
void CPLQuadTreeInsertWithBounds(CPLQuadTree *hQuadTree,
void* hFeature,
const CPLRectObj* psBounds)
{
hQuadTree->nFeatures ++;
CPLQuadTreeAddFeatureInternal(hQuadTree, hFeature, psBounds);
}
/************************************************************************/
/* CPLQuadTreeNodeDestroy() */
/************************************************************************/
static void CPLQuadTreeNodeDestroy(QuadTreeNode *psNode)
{
int i;
for(i=0; i<psNode->nNumSubNodes; i++ )
{
if(psNode->apSubNode[i])
CPLQuadTreeNodeDestroy(psNode->apSubNode[i]);
}
if(psNode->pahFeatures)
{
CPLFree(psNode->pahFeatures);
CPLFree(psNode->pasBounds);
}
CPLFree(psNode);
}
/************************************************************************/
/* CPLQuadTreeDestroy() */
/************************************************************************/
/**
* Destroy a quadtree
*
* @param hQuadTree the quad tree to destroy
*/
void CPLQuadTreeDestroy(CPLQuadTree *hQuadTree)
{
CPLAssert(hQuadTree);
CPLQuadTreeNodeDestroy(hQuadTree->psRoot);
CPLFree(hQuadTree);
}
/************************************************************************/
/* CPLQuadTreeSplitBounds() */
/************************************************************************/
static void CPLQuadTreeSplitBounds( double dfSplitRatio,
const CPLRectObj *in,
CPLRectObj *out1,
CPLRectObj *out2)
{
double range;
/* -------------------------------------------------------------------- */
/* The output bounds will be very similar to the input bounds, */
/* so just copy over to start. */
/* -------------------------------------------------------------------- */
memcpy(out1, in, sizeof(CPLRectObj));
memcpy(out2, in, sizeof(CPLRectObj));
/* -------------------------------------------------------------------- */
/* Split in X direction. */
/* -------------------------------------------------------------------- */
if((in->maxx - in->minx) > (in->maxy - in->miny)) {
range = in->maxx - in->minx;
out1->maxx = in->minx + range * dfSplitRatio;
out2->minx = in->maxx - range * dfSplitRatio;
}
/* -------------------------------------------------------------------- */
/* Otherwise split in Y direction. */
/* -------------------------------------------------------------------- */
else {
range = in->maxy - in->miny;
out1->maxy = in->miny + range * dfSplitRatio;
out2->miny = in->maxy - range * dfSplitRatio;
}
}
/************************************************************************/
/* CPLQuadTreeNodeAddFeatureAlg1() */
/************************************************************************/
static void CPLQuadTreeNodeAddFeatureAlg1( CPLQuadTree* hQuadTree,
QuadTreeNode *psNode,
void* hFeature,
const CPLRectObj* pRect)
{
int i;
if (psNode->nNumSubNodes == 0)
{
/* If we have reached the max bucket capacity, try to insert */
/* in a subnode if possible */
if (psNode->nFeatures >= hQuadTree->nBucketCapacity)
{
CPLRectObj half1, half2, quad1, quad2, quad3, quad4;
CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &psNode->rect, &half1, &half2);
CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half1, &quad1, &quad2);
CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half2, &quad3, &quad4);
if (memcmp(&psNode->rect, &quad1, sizeof(CPLRectObj)) != 0 &&
memcmp(&psNode->rect, &quad2, sizeof(CPLRectObj)) != 0 &&
memcmp(&psNode->rect, &quad3, sizeof(CPLRectObj)) != 0 &&
memcmp(&psNode->rect, &quad4, sizeof(CPLRectObj)) != 0 &&
(CPL_RectContained(pRect, &quad1) ||
CPL_RectContained(pRect, &quad2) ||
CPL_RectContained(pRect, &quad3) ||
CPL_RectContained(pRect, &quad4)))
{
psNode->nNumSubNodes = 4;
psNode->apSubNode[0] = CPLQuadTreeNodeCreate(&quad1);
psNode->apSubNode[1] = CPLQuadTreeNodeCreate(&quad2);
psNode->apSubNode[2] = CPLQuadTreeNodeCreate(&quad3);
psNode->apSubNode[3] = CPLQuadTreeNodeCreate(&quad4);
int oldNumFeatures = psNode->nFeatures;
void** oldFeatures = psNode->pahFeatures;
CPLRectObj* pasOldBounds = psNode->pasBounds;
psNode->nFeatures = 0;
psNode->pahFeatures = NULL;
psNode->pasBounds = NULL;
/* redispatch existing pahFeatures in apSubNodes */
int i;
for(i=0;i<oldNumFeatures;i++)
{
if( hQuadTree->pfnGetBounds == NULL )
CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode, oldFeatures[i], &pasOldBounds[i]);
else
{
CPLRectObj bounds;
hQuadTree->pfnGetBounds(oldFeatures[i], &bounds);
CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode, oldFeatures[i], &bounds);
}
}
CPLFree(oldFeatures);
CPLFree(pasOldBounds);
/* recurse back on this psNode now that it has apSubNodes */
CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode, hFeature, pRect);
return;
}
}
}
else
{
/* -------------------------------------------------------------------- */
/* If there are apSubNodes, then consider whether this object */
/* will fit in them. */
/* -------------------------------------------------------------------- */
for(i=0; i<psNode->nNumSubNodes; i++ )
{
if( CPL_RectContained(pRect, &psNode->apSubNode[i]->rect))
{
CPLQuadTreeNodeAddFeatureAlg1( hQuadTree, psNode->apSubNode[i], hFeature, pRect);
return;
}
}
}
/* -------------------------------------------------------------------- */
/* If none of that worked, just add it to this psNodes list. */
/* -------------------------------------------------------------------- */
psNode->nFeatures++;
if( psNode->nFeatures == 1 )
{
CPLAssert( psNode->pahFeatures == NULL );
psNode->pahFeatures = (void**) CPLMalloc( hQuadTree->nBucketCapacity * sizeof(void*) );
if( hQuadTree->pfnGetBounds == NULL )
psNode->pasBounds = (CPLRectObj*) CPLMalloc( hQuadTree->nBucketCapacity * sizeof(CPLRectObj) );
}
else if( psNode->nFeatures > hQuadTree->nBucketCapacity )
{
psNode->pahFeatures = (void**) CPLRealloc( psNode->pahFeatures, sizeof(void*) * psNode->nFeatures );
if( hQuadTree->pfnGetBounds == NULL )
psNode->pasBounds = (CPLRectObj*) CPLRealloc( psNode->pasBounds, sizeof(CPLRectObj) * psNode->nFeatures );
}
psNode->pahFeatures[psNode->nFeatures-1] = hFeature;
if( hQuadTree->pfnGetBounds == NULL )
psNode->pasBounds[psNode->nFeatures-1] = *pRect;
return ;
}
/************************************************************************/
/* CPLQuadTreeNodeAddFeatureAlg2() */
/************************************************************************/
static void CPLQuadTreeNodeAddFeatureAlg2( CPLQuadTree *hQuadTree,
QuadTreeNode *psNode,
void* hFeature,
const CPLRectObj* pRect,
int nMaxDepth)
{
int i;
/* -------------------------------------------------------------------- */
/* If there are apSubNodes, then consider whether this object */
/* will fit in them. */
/* -------------------------------------------------------------------- */
if( nMaxDepth > 1 && psNode->nNumSubNodes > 0 )
{
for(i=0; i<psNode->nNumSubNodes; i++ )
{
if( CPL_RectContained(pRect, &psNode->apSubNode[i]->rect))
{
CPLQuadTreeNodeAddFeatureAlg2( hQuadTree, psNode->apSubNode[i],
hFeature, pRect, nMaxDepth-1);
return;
}
}
}
/* -------------------------------------------------------------------- */
/* Otherwise, consider creating four apSubNodes if could fit into */
/* them, and adding to the appropriate apSubNode. */
/* -------------------------------------------------------------------- */
else if( nMaxDepth > 1 && psNode->nNumSubNodes == 0 )
{
CPLRectObj half1, half2, quad1, quad2, quad3, quad4;
CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &psNode->rect, &half1, &half2);
CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half1, &quad1, &quad2);
CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half2, &quad3, &quad4);
if( memcmp(&psNode->rect, &quad1, sizeof(CPLRectObj)) != 0 &&
memcmp(&psNode->rect, &quad2, sizeof(CPLRectObj)) != 0 &&
memcmp(&psNode->rect, &quad3, sizeof(CPLRectObj)) != 0 &&
memcmp(&psNode->rect, &quad4, sizeof(CPLRectObj)) != 0 &&
(CPL_RectContained(pRect, &quad1) ||
CPL_RectContained(pRect, &quad2) ||
CPL_RectContained(pRect, &quad3) ||
CPL_RectContained(pRect, &quad4)) )
{
psNode->nNumSubNodes = 4;
psNode->apSubNode[0] = CPLQuadTreeNodeCreate(&quad1);
psNode->apSubNode[1] = CPLQuadTreeNodeCreate(&quad2);
psNode->apSubNode[2] = CPLQuadTreeNodeCreate(&quad3);
psNode->apSubNode[3] = CPLQuadTreeNodeCreate(&quad4);
/* recurse back on this psNode now that it has apSubNodes */
CPLQuadTreeNodeAddFeatureAlg2(hQuadTree, psNode, hFeature, pRect, nMaxDepth);
return;
}
}
/* -------------------------------------------------------------------- */
/* If none of that worked, just add it to this psNodes list. */
/* -------------------------------------------------------------------- */
psNode->nFeatures++;
psNode->pahFeatures =
(void**) CPLRealloc( psNode->pahFeatures,
sizeof(void*) * psNode->nFeatures );
if( hQuadTree->pfnGetBounds == NULL )
{
psNode->pasBounds =
(CPLRectObj*) CPLRealloc( psNode->pasBounds,
sizeof(CPLRectObj) * psNode->nFeatures );
}
psNode->pahFeatures[psNode->nFeatures-1] = hFeature;
if( hQuadTree->pfnGetBounds == NULL )
{
psNode->pasBounds[psNode->nFeatures-1] = *pRect;
}
}
/************************************************************************/
/* CPLQuadTreeAddFeatureInternal() */
/************************************************************************/
static void CPLQuadTreeAddFeatureInternal(CPLQuadTree *hQuadTree,
void* hFeature,
const CPLRectObj *pRect)
{
if (hQuadTree->nMaxDepth == 0)
{
CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, hQuadTree->psRoot,
hFeature, pRect);
}
else
{
CPLQuadTreeNodeAddFeatureAlg2(hQuadTree, hQuadTree->psRoot,
hFeature, pRect, hQuadTree->nMaxDepth);
}
}
/************************************************************************/
/* CPLQuadTreeCollectFeatures() */
/************************************************************************/
static void CPLQuadTreeCollectFeatures(const CPLQuadTree *hQuadTree,
const QuadTreeNode *psNode,
const CPLRectObj* pAoi,
int* pnFeatureCount,
int* pnMaxFeatures,
void*** pppFeatureList)
{
int i;
/* -------------------------------------------------------------------- */
/* Does this psNode overlap the area of interest at all? If not, */
/* return without adding to the list at all. */
/* -------------------------------------------------------------------- */
if(!CPL_RectOverlap(&psNode->rect, pAoi))
return;
/* -------------------------------------------------------------------- */
/* Grow the list to hold the features on this psNode. */
/* -------------------------------------------------------------------- */
if( *pnFeatureCount + psNode->nFeatures > *pnMaxFeatures )
{
*pnMaxFeatures = (*pnFeatureCount + psNode->nFeatures) * 2 + 20;
*pppFeatureList = (void**)
CPLRealloc(*pppFeatureList,sizeof(void*) * *pnMaxFeatures);
}
/* -------------------------------------------------------------------- */
/* Add the local features to the list. */
/* -------------------------------------------------------------------- */
for(i=0; i<psNode->nFeatures; i++)
{
if( hQuadTree->pfnGetBounds == NULL )
{
if (CPL_RectOverlap(&psNode->pasBounds[i], pAoi))
(*pppFeatureList)[(*pnFeatureCount)++] = psNode->pahFeatures[i];
}
else
{
CPLRectObj bounds;
hQuadTree->pfnGetBounds(psNode->pahFeatures[i], &bounds);
if (CPL_RectOverlap(&bounds, pAoi))
(*pppFeatureList)[(*pnFeatureCount)++] = psNode->pahFeatures[i];
}
}
/* -------------------------------------------------------------------- */
/* Recurse to subnodes if they exist. */
/* -------------------------------------------------------------------- */
for(i=0; i<psNode->nNumSubNodes; i++)
{
if(psNode->apSubNode[i])
CPLQuadTreeCollectFeatures(hQuadTree, psNode->apSubNode[i], pAoi,
pnFeatureCount, pnMaxFeatures, pppFeatureList);
}
}
/************************************************************************/
/* CPLQuadTreeSearch() */
/************************************************************************/
/**
* Returns all the elements inserted whose bounding box intersects the
* provided area of interest
*
* @param hQuadTree the quad tree
* @param pAoi the pointer to the area of interest
* @param pnFeatureCount the user data provided to the function.
*
* @return an array of features that must be freed with CPLFree
*/
void** CPLQuadTreeSearch(const CPLQuadTree *hQuadTree,
const CPLRectObj* pAoi,
int* pnFeatureCount)
{
void** ppFeatureList = NULL;
int nMaxFeatures = 0;
int nFeatureCount = 0;
CPLAssert(hQuadTree);
CPLAssert(pAoi);
if (pnFeatureCount == NULL)
pnFeatureCount = &nFeatureCount;
*pnFeatureCount = 0;
CPLQuadTreeCollectFeatures(hQuadTree, hQuadTree->psRoot, pAoi,
pnFeatureCount, &nMaxFeatures, &ppFeatureList);
return(ppFeatureList);
}
/************************************************************************/
/* CPLQuadTreeNodeForeach() */
/************************************************************************/
static int CPLQuadTreeNodeForeach(const QuadTreeNode *psNode,
CPLQuadTreeForeachFunc pfnForeach,
void* pUserData)
{
int i;
for(i=0; i<psNode->nNumSubNodes; i++ )
{
if (CPLQuadTreeNodeForeach(psNode->apSubNode[i], pfnForeach, pUserData) == FALSE)
return FALSE;
}
for(i=0; i<psNode->nFeatures; i++)
{
if (pfnForeach(psNode->pahFeatures[i], pUserData) == FALSE)
return FALSE;
}
return TRUE;
}
/************************************************************************/
/* CPLQuadTreeForeach() */
/************************************************************************/
/**
* Walk through the quadtree and runs the provided function on all the
* elements
*
* This function is provided with the user_data argument of pfnForeach.
* It must return TRUE to go on the walk through the hash set, or FALSE to
* make it stop.
*
* Note : the structure of the quadtree must *NOT* be modified during the
* walk.
*
* @param hQuadTree the quad tree
* @param pfnForeach the function called on each element.
* @param pUserData the user data provided to the function.
*/
void CPLQuadTreeForeach(const CPLQuadTree *hQuadTree,
CPLQuadTreeForeachFunc pfnForeach,
void* pUserData)
{
CPLAssert(hQuadTree);
CPLAssert(pfnForeach);
CPLQuadTreeNodeForeach(hQuadTree->psRoot, pfnForeach, pUserData);
}
/************************************************************************/
/* CPLQuadTreeDumpNode() */
/************************************************************************/
static void CPLQuadTreeDumpNode(const QuadTreeNode *psNode,
int nIndentLevel,
CPLQuadTreeDumpFeatureFunc pfnDumpFeatureFunc,
void* pUserData)
{
int i;
int count;
if (psNode->nNumSubNodes)
{
for(count=nIndentLevel;--count>=0;)
printf(" ");
printf("SubhQuadTrees :\n");
for(i=0; i<psNode->nNumSubNodes; i++ )
{
for(count=nIndentLevel+1;--count>=0;)
printf(" ");
printf("SubhQuadTree %d :\n", i+1);
CPLQuadTreeDumpNode(psNode->apSubNode[i], nIndentLevel + 2,
pfnDumpFeatureFunc, pUserData);
}
}
if (psNode->nFeatures)
{
for(count=nIndentLevel;--count>=0;)
printf(" ");
printf("Leaves (%d):\n", psNode->nFeatures);
for(i=0; i<psNode->nFeatures; i++)
{
if (pfnDumpFeatureFunc)
pfnDumpFeatureFunc(psNode->pahFeatures[i], nIndentLevel + 2,
pUserData);
else
{
for(count=nIndentLevel + 1;--count>=0;)
printf(" ");
printf("%p\n", psNode->pahFeatures[i]);
}
}
}
}
/************************************************************************/
/* CPLQuadTreeDump() */
/************************************************************************/
void CPLQuadTreeDump(const CPLQuadTree *hQuadTree,
CPLQuadTreeDumpFeatureFunc pfnDumpFeatureFunc,
void* pUserData)
{
CPLQuadTreeDumpNode(hQuadTree->psRoot, 0, pfnDumpFeatureFunc, pUserData);
}
/************************************************************************/
/* CPLQuadTreeGetStatsNode() */
/************************************************************************/
static
void CPLQuadTreeGetStatsNode(const QuadTreeNode *psNode,
int nDepthLevel,
int* pnNodeCount,
int* pnMaxDepth,
int* pnMaxBucketCapacity)
{
int i;
(*pnNodeCount) ++;
if (nDepthLevel > *pnMaxDepth)
*pnMaxDepth = nDepthLevel;
if (psNode->nFeatures > *pnMaxBucketCapacity)
*pnMaxBucketCapacity = psNode->nFeatures;
for(i=0; i<psNode->nNumSubNodes; i++ )
{
CPLQuadTreeGetStatsNode(psNode->apSubNode[i], nDepthLevel + 1,
pnNodeCount, pnMaxDepth, pnMaxBucketCapacity);
}
}
/************************************************************************/
/* CPLQuadTreeGetStats() */
/************************************************************************/
void CPLQuadTreeGetStats(const CPLQuadTree *hQuadTree,
int* pnFeatureCount,
int* pnNodeCount,
int* pnMaxDepth,
int* pnMaxBucketCapacity)
{
int nFeatureCount, nNodeCount, nMaxDepth, nMaxBucketCapacity;
CPLAssert(hQuadTree);
if (pnFeatureCount == NULL)
pnFeatureCount = &nFeatureCount;
if (pnNodeCount == NULL)
pnNodeCount = &nNodeCount;
if (pnMaxDepth == NULL)
pnMaxDepth = &nMaxDepth;
if (pnMaxBucketCapacity == NULL)
pnMaxBucketCapacity = &nMaxBucketCapacity;
*pnFeatureCount = hQuadTree->nFeatures;
*pnNodeCount = 0;
*pnMaxDepth = 1;
*pnMaxBucketCapacity = 0;
CPLQuadTreeGetStatsNode(hQuadTree->psRoot, 0, pnNodeCount, pnMaxDepth, pnMaxBucketCapacity);
}