LCOV - code coverage report
Current view: directory - port - cpl_quad_tree.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 220 0 0.0 %
Date: 2012-04-28 Functions: 22 0 0.0 %

       1                 : /******************************************************************************
       2                 :  * $Id: cpl_quad_tree.cpp 15067 2008-07-28 22:08:58Z rouault $
       3                 :  *
       4                 :  * Project:  CPL - Common Portability Library
       5                 :  * Purpose:  Implementation of quadtree building and searching functions.
       6                 :  *           Derived from shapelib and mapserver implementations
       7                 :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       8                 :  *           Even Rouault, <even dot rouault at mines dash paris dot org>
       9                 :  *
      10                 :  ******************************************************************************
      11                 :  * Copyright (c) 1999-2008, Frank Warmerdam
      12                 :  *
      13                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      14                 :  * copy of this software and associated documentation files (the "Software"),
      15                 :  * to deal in the Software without restriction, including without limitation
      16                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      17                 :  * and/or sell copies of the Software, and to permit persons to whom the
      18                 :  * Software is furnished to do so, subject to the following conditions:
      19                 :  *
      20                 :  * The above copyright notice and this permission notice shall be included
      21                 :  * in all copies or substantial portions of the Software.
      22                 :  *
      23                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      24                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      25                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      26                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      27                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      28                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      29                 :  * DEALINGS IN THE SOFTWARE.
      30                 :  ******************************************************************************
      31                 :  *
      32                 :  */
      33                 : 
      34                 : #include "cpl_conv.h"
      35                 : #include "cpl_quad_tree.h"
      36                 : 
      37                 : CPL_CVSID("$Id: cpl_quad_tree.cpp 15067 2008-07-28 22:08:58Z rouault $");
      38                 : 
      39                 : #define MAX_DEFAULT_TREE_DEPTH 12
      40                 : #define MAX_SUBNODES 4
      41                 : 
      42                 : typedef struct _QuadTreeNode QuadTreeNode;
      43                 : 
      44                 : struct _QuadTreeNode
      45                 : {
      46                 :   /* area covered by this psNode */
      47                 :   CPLRectObj    rect;
      48                 : 
      49                 :   /* list of shapes stored at this psNode. */
      50                 :   int           nFeatures;
      51                 :   void        **pahFeatures;
      52                 : 
      53                 :   int           nNumSubNodes;
      54                 :   QuadTreeNode *apSubNode[MAX_SUBNODES];
      55                 : };
      56                 : 
      57                 : struct _CPLQuadTree
      58                 : {
      59                 :   QuadTreeNode             *psRoot;
      60                 :   CPLQuadTreeGetBoundsFunc  pfnGetBounds;
      61                 :   int                       nFeatures;
      62                 :   int                       nMaxDepth;
      63                 :   int                       nBucketCapacity;
      64                 :   double                    dfSplitRatio;
      65                 : };
      66                 : 
      67                 : 
      68                 : static void CPLQuadTreeAddFeatureInternal(CPLQuadTree *hQuadTree,
      69                 :                                           void* hFeature,
      70                 :                                           const CPLRectObj *pRect);
      71                 : 
      72                 : /* -------------------------------------------------------------------- */
      73                 : /*      If the following is 0.5, psNodes will be split in half.  If it    */
      74                 : /*      is 0.6 then each apSubNode will contain 60% of the parent         */
      75                 : /*      psNode, with 20% representing overlap.  This can be help to       */
      76                 : /*      prevent small objects on a boundary from shifting too high      */
      77                 : /*      up the hQuadTree.                                                    */
      78                 : /* -------------------------------------------------------------------- */
      79                 : #define DEFAULT_SPLIT_RATIO  0.55
      80                 : 
      81                 : /*
      82                 : ** Returns TRUE if rectangle a is contained in rectangle b
      83                 : */
      84               0 : static CPL_INLINE int CPL_RectContained(const CPLRectObj *a, const CPLRectObj *b)
      85                 : {
      86               0 :   if(a->minx >= b->minx && a->maxx <= b->maxx)
      87               0 :     if(a->miny >= b->miny && a->maxy <= b->maxy)
      88               0 :       return(TRUE);
      89               0 :   return(FALSE);  
      90                 : }
      91                 : 
      92                 : /*
      93                 : ** Returns TRUE if rectangles a and b overlap
      94                 : */
      95               0 : static CPL_INLINE int CPL_RectOverlap(const CPLRectObj *a, const CPLRectObj *b)
      96                 : {
      97               0 :   if(a->minx > b->maxx) return(FALSE);
      98               0 :   if(a->maxx < b->minx) return(FALSE);
      99               0 :   if(a->miny > b->maxy) return(FALSE);
     100               0 :   if(a->maxy < b->miny) return(FALSE);
     101               0 :   return(TRUE);
     102                 : }
     103                 : 
     104                 : /************************************************************************/
     105                 : /*                      CPLQuadTreeNodeCreate()                         */
     106                 : /************************************************************************/
     107                 : 
     108               0 : static QuadTreeNode *CPLQuadTreeNodeCreate(const CPLRectObj* pRect)
     109                 : {
     110                 :     QuadTreeNode  *psNode;
     111                 : 
     112               0 :     psNode = (QuadTreeNode *) CPLMalloc(sizeof(QuadTreeNode));
     113                 : 
     114               0 :     psNode->nFeatures = 0;
     115               0 :     psNode->pahFeatures = NULL;
     116                 : 
     117               0 :     psNode->nNumSubNodes = 0;
     118                 : 
     119               0 :     memcpy(&(psNode->rect), pRect, sizeof(CPLRectObj));
     120                 : 
     121               0 :     return psNode;
     122                 : }
     123                 : 
     124                 : /************************************************************************/
     125                 : /*                         CPLQuadTreeCreate()                          */
     126                 : /************************************************************************/
     127                 : 
     128                 : /**
     129                 :  * Create a new quadtree
     130                 :  * 
     131                 :  * @param pGlobalBounds a pointer to the global extent of all
     132                 :  *                      the elements that will be inserted
     133                 :  * @param pfnGetBounds  a user provided function to get the bounding box of
     134                 :  *                      the inserted elements
     135                 :  *
     136                 :  * @return a newly allocated quadtree
     137                 :  */
     138                 : 
     139               0 : CPLQuadTree *CPLQuadTreeCreate(const CPLRectObj* pGlobalBounds, CPLQuadTreeGetBoundsFunc pfnGetBounds)
     140                 : {
     141                 :     CPLQuadTree *hQuadTree;
     142                 : 
     143               0 :     CPLAssert(pGlobalBounds);
     144                 : 
     145                 :     /* -------------------------------------------------------------------- */
     146                 :     /*      Allocate the hQuadTree object                                        */
     147                 :     /* -------------------------------------------------------------------- */
     148               0 :     hQuadTree = (CPLQuadTree *) CPLMalloc(sizeof(CPLQuadTree));
     149                 : 
     150               0 :     hQuadTree->nFeatures = 0;
     151               0 :     hQuadTree->pfnGetBounds = pfnGetBounds;
     152               0 :     hQuadTree->nMaxDepth = 0;
     153               0 :     hQuadTree->nBucketCapacity = 8;
     154                 : 
     155               0 :     hQuadTree->dfSplitRatio = DEFAULT_SPLIT_RATIO;
     156                 : 
     157                 :     /* -------------------------------------------------------------------- */
     158                 :     /*      Allocate the psRoot psNode.                                         */
     159                 :     /* -------------------------------------------------------------------- */
     160               0 :     hQuadTree->psRoot = CPLQuadTreeNodeCreate(pGlobalBounds);
     161                 : 
     162               0 :     return hQuadTree;
     163                 : }
     164                 : 
     165                 : /************************************************************************/
     166                 : /*                 CPLQuadTreeGetAdvisedMaxDepth()                      */
     167                 : /************************************************************************/
     168                 : 
     169                 : /**
     170                 :  * Returns the optimal depth of a quadtree to hold nExpectedFeatures
     171                 :  * 
     172                 :  * @param nExpectedFeatures the expected maximum number of elements to be inserted
     173                 :  *
     174                 :  * @return the optimal depth of a quadtree to hold nExpectedFeatures
     175                 :  */
     176                 : 
     177               0 : int CPLQuadTreeGetAdvisedMaxDepth(int nExpectedFeatures)
     178                 : {
     179                 : /* -------------------------------------------------------------------- */
     180                 : /*      Try to select a reasonable one                                  */
     181                 : /*      that implies approximately 8 shapes per node.                   */
     182                 : /* -------------------------------------------------------------------- */
     183               0 :     int nMaxDepth = 0;
     184               0 :     int nMaxNodeCount = 1;
     185                 : 
     186               0 :     while( nMaxNodeCount*4 < nExpectedFeatures )
     187                 :     {
     188               0 :         nMaxDepth += 1;
     189               0 :         nMaxNodeCount = nMaxNodeCount * 2;
     190                 :     }
     191                 : 
     192                 :     CPLDebug( "CPLQuadTree",
     193                 :                 "Estimated spatial index tree depth: %d",
     194               0 :                 nMaxDepth );
     195                 : 
     196                 :     /* NOTE: Due to problems with memory allocation for deep trees,
     197                 :         * automatically estimated depth is limited up to 12 levels.
     198                 :         * See Ticket #1594 for detailed discussion.
     199                 :         */
     200               0 :     if( nMaxDepth > MAX_DEFAULT_TREE_DEPTH )
     201                 :     {
     202               0 :         nMaxDepth = MAX_DEFAULT_TREE_DEPTH;
     203                 : 
     204                 :         CPLDebug( "CPLQuadTree",
     205                 :                     "Falling back to max number of allowed index tree levels (%d).",
     206               0 :                     MAX_DEFAULT_TREE_DEPTH );
     207                 : 
     208                 :     }
     209                 : 
     210               0 :     return nMaxDepth;
     211                 : }
     212                 : 
     213                 : /************************************************************************/
     214                 : /*                     CPLQuadTreeSetMaxDepth()                         */
     215                 : /************************************************************************/
     216                 : 
     217                 : /**
     218                 :  * Set the maximum depth of a quadtree. By default, quad trees have
     219                 :  * no maximum depth, but a maximum bucket capacity.
     220                 :  * 
     221                 :  * @param hQuadTree the quad tree
     222                 :  * @param nMaxDepth the maximum depth allowed
     223                 :  */
     224                 : 
     225               0 : void CPLQuadTreeSetMaxDepth(CPLQuadTree *hQuadTree, int nMaxDepth)
     226                 : {
     227               0 :     hQuadTree->nMaxDepth = nMaxDepth;
     228               0 : }
     229                 : 
     230                 : /************************************************************************/
     231                 : /*                   CPLQuadTreeSetBucketCapacity()                     */
     232                 : /************************************************************************/
     233                 : 
     234                 : /**
     235                 :  * Set the maximum capacity of a node of a quadtree. The default value is 8.
     236                 :  * Note that the maximum capacity will only be honoured if the features
     237                 :  * inserted have a point geometry. Otherwise it may be exceeded.
     238                 :  * 
     239                 :  * @param hQuadTree the quad tree
     240                 :  * @param nBucketCapacity the maximum capactiy of a node of a quadtree
     241                 :  */
     242                 : 
     243               0 : void CPLQuadTreeSetBucketCapacity(CPLQuadTree *hQuadTree, int nBucketCapacity)
     244                 : {
     245               0 :     hQuadTree->nBucketCapacity = nBucketCapacity;
     246               0 : }
     247                 : 
     248                 : /************************************************************************/
     249                 : /*                        CPLQuadTreeInsert()                           */
     250                 : /************************************************************************/
     251                 : 
     252                 : /**
     253                 :  * Insert a feature into a quadtree
     254                 :  * 
     255                 :  * @param hQuadTree the quad tree
     256                 :  * @param hFeature the feature to insert
     257                 :  */
     258                 : 
     259               0 : void CPLQuadTreeInsert(CPLQuadTree * hQuadTree, void* hFeature)
     260                 : {
     261                 :     CPLRectObj bounds;
     262               0 :     hQuadTree->nFeatures ++;
     263               0 :     hQuadTree->pfnGetBounds(hFeature, &bounds);
     264               0 :     CPLQuadTreeAddFeatureInternal(hQuadTree, hFeature, &bounds);
     265               0 : }
     266                 : 
     267                 : /************************************************************************/
     268                 : /*                    CPLQuadTreeNodeDestroy()                          */
     269                 : /************************************************************************/
     270                 : 
     271               0 : static void CPLQuadTreeNodeDestroy(QuadTreeNode *psNode)
     272                 : {
     273                 :     int i;
     274                 : 
     275               0 :     for(i=0; i<psNode->nNumSubNodes; i++ )
     276                 :     {
     277               0 :         if(psNode->apSubNode[i]) 
     278               0 :             CPLQuadTreeNodeDestroy(psNode->apSubNode[i]);
     279                 :     }
     280                 : 
     281               0 :     if(psNode->pahFeatures)
     282               0 :         CPLFree(psNode->pahFeatures);
     283                 : 
     284               0 :     CPLFree(psNode);
     285               0 : }
     286                 : 
     287                 : 
     288                 : /************************************************************************/
     289                 : /*                       CPLQuadTreeDestroy()                           */
     290                 : /************************************************************************/
     291                 : 
     292                 : /**
     293                 :  * Destroy a quadtree
     294                 :  * 
     295                 :  * @param hQuadTree the quad tree to destroy
     296                 :  */
     297                 : 
     298               0 : void CPLQuadTreeDestroy(CPLQuadTree *hQuadTree)
     299                 : {
     300               0 :     CPLAssert(hQuadTree);
     301               0 :     CPLQuadTreeNodeDestroy(hQuadTree->psRoot);
     302               0 :     CPLFree(hQuadTree);
     303               0 : }
     304                 : 
     305                 : 
     306                 : 
     307                 : /************************************************************************/
     308                 : /*                     CPLQuadTreeSplitBounds()                         */
     309                 : /************************************************************************/
     310                 : 
     311               0 : static void CPLQuadTreeSplitBounds( double dfSplitRatio,
     312                 :                                       const CPLRectObj *in,
     313                 :                                       CPLRectObj *out1,
     314                 :                                       CPLRectObj *out2)
     315                 : {
     316                 :   double range;
     317                 : 
     318                 :   /* -------------------------------------------------------------------- */
     319                 :   /*      The output bounds will be very similar to the input bounds,     */
     320                 :   /*      so just copy over to start.                                     */
     321                 :   /* -------------------------------------------------------------------- */
     322               0 :   memcpy(out1, in, sizeof(CPLRectObj));
     323               0 :   memcpy(out2, in, sizeof(CPLRectObj));
     324                 :   
     325                 :   /* -------------------------------------------------------------------- */
     326                 :   /*      Split in X direction.                                           */
     327                 :   /* -------------------------------------------------------------------- */
     328               0 :   if((in->maxx - in->minx) > (in->maxy - in->miny)) {
     329               0 :     range = in->maxx - in->minx;
     330                 :     
     331               0 :     out1->maxx = in->minx + range * dfSplitRatio;
     332               0 :     out2->minx = in->maxx - range * dfSplitRatio;
     333                 :   }
     334                 : 
     335                 :   /* -------------------------------------------------------------------- */
     336                 :   /*      Otherwise split in Y direction.                                 */
     337                 :   /* -------------------------------------------------------------------- */
     338                 :   else {
     339               0 :     range = in->maxy - in->miny;
     340                 :     
     341               0 :     out1->maxy = in->miny + range * dfSplitRatio;
     342               0 :     out2->miny = in->maxy - range * dfSplitRatio;
     343                 :   }
     344               0 : }
     345                 : 
     346                 : /************************************************************************/
     347                 : /*                  CPLQuadTreeNodeAddFeatureAlg1()                     */
     348                 : /************************************************************************/
     349                 : 
     350               0 : static void CPLQuadTreeNodeAddFeatureAlg1( CPLQuadTree* hQuadTree,
     351                 :                                            QuadTreeNode *psNode,
     352                 :                                            void* hFeature,
     353                 :                                            const CPLRectObj* pRect)
     354                 : {
     355                 :     int i;
     356               0 :     if (psNode->nNumSubNodes == 0)
     357                 :     {
     358                 :         /* If we have reached the max bucket capacity, try to insert */
     359                 :         /* in a subnode if possible */
     360               0 :         if (psNode->nFeatures >= hQuadTree->nBucketCapacity)
     361                 :         {
     362                 :             CPLRectObj half1, half2, quad1, quad2, quad3, quad4;
     363                 : 
     364               0 :             CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &psNode->rect, &half1, &half2);
     365               0 :             CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half1, &quad1, &quad2);
     366               0 :             CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half2, &quad3, &quad4);
     367                 : 
     368               0 :             if (CPL_RectContained(pRect, &quad1) ||
     369                 :                 CPL_RectContained(pRect, &quad2) ||
     370                 :                 CPL_RectContained(pRect, &quad3) ||
     371                 :                 CPL_RectContained(pRect, &quad4))
     372                 :             {
     373               0 :                 psNode->nNumSubNodes = 4;
     374               0 :                 psNode->apSubNode[0] = CPLQuadTreeNodeCreate(&quad1);
     375               0 :                 psNode->apSubNode[1] = CPLQuadTreeNodeCreate(&quad2);
     376               0 :                 psNode->apSubNode[2] = CPLQuadTreeNodeCreate(&quad3);
     377               0 :                 psNode->apSubNode[3] = CPLQuadTreeNodeCreate(&quad4);
     378                 : 
     379               0 :                 int oldNumFeatures = psNode->nFeatures;
     380               0 :                 void** oldFeatures = psNode->pahFeatures;
     381               0 :                 psNode->nFeatures = 0;
     382               0 :                 psNode->pahFeatures = NULL;
     383                 : 
     384                 :                 /* redispatch existing pahFeatures in apSubNodes */
     385                 :                 int i;
     386               0 :                 for(i=0;i<oldNumFeatures;i++)
     387                 :                 {
     388                 :                     CPLRectObj hFeatureBound;
     389               0 :                     hQuadTree->pfnGetBounds(oldFeatures[i], &hFeatureBound);
     390               0 :                     CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode, oldFeatures[i], &hFeatureBound);
     391                 :                 }
     392                 : 
     393               0 :                 CPLFree(oldFeatures);
     394                 : 
     395                 :                 /* recurse back on this psNode now that it has apSubNodes */
     396               0 :                 CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode, hFeature, pRect);
     397               0 :                 return;
     398                 :             }
     399                 :         }
     400                 :     }
     401                 :     else
     402                 :     {
     403                 :     /* -------------------------------------------------------------------- */
     404                 :     /*      If there are apSubNodes, then consider whether this object        */
     405                 :     /*      will fit in them.                                               */
     406                 :     /* -------------------------------------------------------------------- */
     407               0 :         for(i=0; i<psNode->nNumSubNodes; i++ )
     408                 :         {
     409               0 :             if( CPL_RectContained(pRect, &psNode->apSubNode[i]->rect))
     410                 :             {
     411               0 :                 CPLQuadTreeNodeAddFeatureAlg1( hQuadTree, psNode->apSubNode[i], hFeature, pRect);
     412               0 :                 return;
     413                 :             }
     414                 :         }
     415                 :     }
     416                 : 
     417                 : /* -------------------------------------------------------------------- */
     418                 : /*      If none of that worked, just add it to this psNodes list.         */
     419                 : /* -------------------------------------------------------------------- */
     420               0 :     psNode->nFeatures++;
     421                 : 
     422               0 :     psNode->pahFeatures = (void**) CPLRealloc( psNode->pahFeatures, sizeof(void*) * psNode->nFeatures );
     423               0 :     psNode->pahFeatures[psNode->nFeatures-1] = hFeature;
     424                 : 
     425               0 :     return ;
     426                 : }
     427                 : 
     428                 : 
     429                 : /************************************************************************/
     430                 : /*                  CPLQuadTreeNodeAddFeatureAlg2()                     */
     431                 : /************************************************************************/
     432                 : 
     433               0 : static void CPLQuadTreeNodeAddFeatureAlg2( CPLQuadTree *hQuadTree,
     434                 :                                            QuadTreeNode *psNode,
     435                 :                                            void* hFeature,
     436                 :                                            const CPLRectObj* pRect,
     437                 :                                            int nMaxDepth)
     438                 : {
     439                 :     int i;
     440                 : 
     441                 :   /* -------------------------------------------------------------------- */
     442                 :   /*      If there are apSubNodes, then consider whether this object        */
     443                 :   /*      will fit in them.                                               */
     444                 :   /* -------------------------------------------------------------------- */
     445               0 :     if( nMaxDepth > 1 && psNode->nNumSubNodes > 0 )
     446                 :     {
     447               0 :         for(i=0; i<psNode->nNumSubNodes; i++ )
     448                 :         {
     449               0 :             if( CPL_RectContained(pRect, &psNode->apSubNode[i]->rect))
     450                 :             {
     451                 :                 CPLQuadTreeNodeAddFeatureAlg2( hQuadTree, psNode->apSubNode[i],
     452               0 :                                                hFeature, pRect, nMaxDepth-1);
     453               0 :                 return;
     454                 :             }
     455                 :         }
     456                 :     }
     457                 : 
     458                 :   /* -------------------------------------------------------------------- */
     459                 :   /*      Otherwise, consider creating four apSubNodes if could fit into    */
     460                 :   /*      them, and adding to the appropriate apSubNode.                    */
     461                 :   /* -------------------------------------------------------------------- */
     462               0 :     else if( nMaxDepth > 1 && psNode->nNumSubNodes == 0 )
     463                 :     {
     464                 :         CPLRectObj half1, half2, quad1, quad2, quad3, quad4;
     465                 : 
     466               0 :         CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &psNode->rect, &half1, &half2);
     467               0 :         CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half1, &quad1, &quad2);
     468               0 :         CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half2, &quad3, &quad4);
     469                 : 
     470               0 :         if(CPL_RectContained(pRect, &quad1) ||
     471                 :         CPL_RectContained(pRect, &quad2) ||
     472                 :         CPL_RectContained(pRect, &quad3) ||
     473                 :         CPL_RectContained(pRect, &quad4))
     474                 :         {
     475               0 :             psNode->nNumSubNodes = 4;
     476               0 :             psNode->apSubNode[0] = CPLQuadTreeNodeCreate(&quad1);
     477               0 :             psNode->apSubNode[1] = CPLQuadTreeNodeCreate(&quad2);
     478               0 :             psNode->apSubNode[2] = CPLQuadTreeNodeCreate(&quad3);
     479               0 :             psNode->apSubNode[3] = CPLQuadTreeNodeCreate(&quad4);
     480                 : 
     481                 :             /* recurse back on this psNode now that it has apSubNodes */
     482               0 :             CPLQuadTreeNodeAddFeatureAlg2(hQuadTree, psNode, hFeature, pRect, nMaxDepth);
     483               0 :             return;
     484                 :         }
     485                 :     }
     486                 : 
     487                 : /* -------------------------------------------------------------------- */
     488                 : /*      If none of that worked, just add it to this psNodes list.         */
     489                 : /* -------------------------------------------------------------------- */
     490               0 :     psNode->nFeatures++;
     491                 : 
     492                 :     psNode->pahFeatures =
     493                 :             (void**) CPLRealloc( psNode->pahFeatures,
     494               0 :                                  sizeof(void*) * psNode->nFeatures );
     495               0 :     psNode->pahFeatures[psNode->nFeatures-1] = hFeature;
     496                 : }
     497                 : 
     498                 : 
     499                 : /************************************************************************/
     500                 : /*                  CPLQuadTreeAddFeatureInternal()                     */
     501                 : /************************************************************************/
     502                 : 
     503               0 : static void CPLQuadTreeAddFeatureInternal(CPLQuadTree *hQuadTree,
     504                 :                                           void* hFeature,
     505                 :                                           const CPLRectObj *pRect)
     506                 : {
     507               0 :     if (hQuadTree->nMaxDepth == 0)
     508                 :     {
     509                 :         CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, hQuadTree->psRoot,
     510               0 :                                      hFeature, pRect);
     511                 :     }
     512                 :     else
     513                 :     {
     514                 :         CPLQuadTreeNodeAddFeatureAlg2(hQuadTree, hQuadTree->psRoot,
     515               0 :                                      hFeature, pRect, hQuadTree->nMaxDepth);
     516                 :     }
     517               0 : }
     518                 : 
     519                 : /************************************************************************/
     520                 : /*                     CPLQuadTreeCollectFeatures()                     */
     521                 : /************************************************************************/
     522                 : 
     523               0 : static void CPLQuadTreeCollectFeatures(const CPLQuadTree *hQuadTree,
     524                 :                                        const QuadTreeNode *psNode,
     525                 :                                        const CPLRectObj* pAoi,
     526                 :                                        int* pnFeatureCount,
     527                 :                                        int* pnMaxFeatures,
     528                 :                                        void*** pppFeatureList)
     529                 : {
     530                 :   int i;
     531                 : 
     532                 :   /* -------------------------------------------------------------------- */
     533                 :   /*      Does this psNode overlap the area of interest at all?  If not,    */
     534                 :   /*      return without adding to the list at all.                       */
     535                 :   /* -------------------------------------------------------------------- */
     536               0 :   if(!CPL_RectOverlap(&psNode->rect, pAoi))
     537               0 :      return;
     538                 : 
     539                 : /* -------------------------------------------------------------------- */
     540                 : /*      Grow the list to hold the features on this psNode.              */
     541                 : /* -------------------------------------------------------------------- */
     542               0 :     if( *pnFeatureCount + psNode->nFeatures > *pnMaxFeatures )
     543                 :     {
     544               0 :         *pnMaxFeatures = (*pnFeatureCount + psNode->nFeatures) * 2 + 20;
     545                 :         *pppFeatureList = (void**)
     546               0 :             CPLRealloc(*pppFeatureList,sizeof(void*) * *pnMaxFeatures);
     547                 :     }
     548                 : 
     549                 :   /* -------------------------------------------------------------------- */
     550                 :   /*      Add the local features to the list.                             */
     551                 :   /* -------------------------------------------------------------------- */
     552               0 :   for(i=0; i<psNode->nFeatures; i++)
     553                 :   {
     554                 :       CPLRectObj bounds;
     555               0 :       hQuadTree->pfnGetBounds(psNode->pahFeatures[i], &bounds);
     556               0 :       if (CPL_RectOverlap(&bounds, pAoi))
     557               0 :             (*pppFeatureList)[(*pnFeatureCount)++] = psNode->pahFeatures[i];
     558                 :   }
     559                 :   
     560                 :   /* -------------------------------------------------------------------- */
     561                 :   /*      Recurse to subnodes if they exist.                              */
     562                 :   /* -------------------------------------------------------------------- */
     563               0 :   for(i=0; i<psNode->nNumSubNodes; i++)
     564                 :   {
     565               0 :       if(psNode->apSubNode[i])
     566               0 :         CPLQuadTreeCollectFeatures(hQuadTree, psNode->apSubNode[i], pAoi,
     567               0 :                                    pnFeatureCount, pnMaxFeatures, pppFeatureList);
     568                 :   }
     569                 : }
     570                 : 
     571                 : /************************************************************************/
     572                 : /*                         CPLQuadTreeSearch()                          */
     573                 : /************************************************************************/
     574                 : 
     575                 : /**
     576                 :  * Returns all the elements inserted whose bounding box intersects the
     577                 :  * provided area of interest
     578                 :  * 
     579                 :  * @param hQuadTree the quad tree
     580                 :  * @param pAoi the pointer to the area of interest
     581                 :  * @param pnFeatureCount the user data provided to the function.
     582                 :  *
     583                 :  * @return an array of features that must be freed with CPLFree
     584                 :  */
     585                 : 
     586               0 : void** CPLQuadTreeSearch(const CPLQuadTree *hQuadTree,
     587                 :                          const CPLRectObj* pAoi,
     588                 :                          int* pnFeatureCount)
     589                 : {
     590               0 :   void** ppFeatureList = NULL;
     591               0 :   int nMaxFeatures = 0;
     592               0 :   int nFeatureCount = 0;
     593                 : 
     594               0 :   CPLAssert(hQuadTree);
     595               0 :   CPLAssert(pAoi);
     596                 : 
     597               0 :   if (pnFeatureCount == NULL)
     598               0 :       pnFeatureCount = &nFeatureCount;
     599                 : 
     600               0 :   *pnFeatureCount = 0;
     601                 :   CPLQuadTreeCollectFeatures(hQuadTree, hQuadTree->psRoot, pAoi,
     602               0 :                             pnFeatureCount, &nMaxFeatures, &ppFeatureList);
     603                 : 
     604               0 :   return(ppFeatureList);
     605                 : }
     606                 : 
     607                 : /************************************************************************/
     608                 : /*                    CPLQuadTreeNodeForeach()                          */
     609                 : /************************************************************************/
     610                 : 
     611               0 : static int CPLQuadTreeNodeForeach(const QuadTreeNode *psNode,
     612                 :                                   CPLQuadTreeForeachFunc pfnForeach,
     613                 :                                   void* pUserData)
     614                 : {
     615                 :     int i;
     616               0 :     for(i=0; i<psNode->nNumSubNodes; i++ )
     617                 :     {
     618               0 :         if (CPLQuadTreeNodeForeach(psNode->apSubNode[i], pfnForeach, pUserData) == FALSE)
     619               0 :             return FALSE;
     620                 :     }
     621                 : 
     622               0 :     for(i=0; i<psNode->nFeatures; i++)
     623                 :     {
     624               0 :         if (pfnForeach(psNode->pahFeatures[i], pUserData) == FALSE)
     625               0 :             return FALSE;
     626                 :     }
     627                 : 
     628               0 :     return TRUE;
     629                 : }
     630                 : 
     631                 : /************************************************************************/
     632                 : /*                       CPLQuadTreeForeach()                           */
     633                 : /************************************************************************/
     634                 : 
     635                 : /**
     636                 :  * Walk through the quadtree and runs the provided function on all the
     637                 :  * elements
     638                 :  *
     639                 :  * This function is provided with the user_data argument of pfnForeach.
     640                 :  * It must return TRUE to go on the walk through the hash set, or FALSE to
     641                 :  * make it stop.
     642                 :  *
     643                 :  * Note : the structure of the quadtree must *NOT* be modified during the
     644                 :  * walk.
     645                 :  * 
     646                 :  * @param hQuadTree the quad tree
     647                 :  * @param pfnForeach the function called on each element.
     648                 :  * @param pUserData the user data provided to the function.
     649                 :  */
     650                 : 
     651               0 : void  CPLQuadTreeForeach(const CPLQuadTree *hQuadTree,
     652                 :                          CPLQuadTreeForeachFunc pfnForeach,
     653                 :                          void* pUserData)
     654                 : {
     655               0 :     CPLAssert(hQuadTree);
     656               0 :     CPLAssert(pfnForeach);
     657               0 :     CPLQuadTreeNodeForeach(hQuadTree->psRoot, pfnForeach, pUserData);
     658               0 : }
     659                 : 
     660                 : /************************************************************************/
     661                 : /*                       CPLQuadTreeDumpNode()                          */
     662                 : /************************************************************************/
     663                 : 
     664               0 : static void CPLQuadTreeDumpNode(const QuadTreeNode *psNode,
     665                 :                                 int nIndentLevel,
     666                 :                                 CPLQuadTreeDumpFeatureFunc pfnDumpFeatureFunc,
     667                 :                                 void* pUserData)
     668                 : {
     669                 :     int i;
     670                 :     int count;
     671               0 :     if (psNode->nNumSubNodes)
     672                 :     {
     673               0 :         for(count=nIndentLevel;--count>=0;)
     674               0 :             printf("  ");
     675               0 :         printf("SubhQuadTrees :\n");
     676               0 :         for(i=0; i<psNode->nNumSubNodes; i++ )
     677                 :         {
     678               0 :             for(count=nIndentLevel+1;--count>=0;)
     679               0 :                 printf("  ");
     680               0 :             printf("SubhQuadTree %d :\n", i+1);
     681               0 :             CPLQuadTreeDumpNode(psNode->apSubNode[i], nIndentLevel + 2,
     682               0 :                                 pfnDumpFeatureFunc, pUserData);
     683                 :         }
     684                 :     }
     685               0 :     if (psNode->nFeatures)
     686                 :     {
     687               0 :         for(count=nIndentLevel;--count>=0;)
     688               0 :             printf("  ");
     689               0 :         printf("Leaves (%d):\n", psNode->nFeatures);
     690               0 :         for(i=0; i<psNode->nFeatures; i++)
     691                 :         {
     692               0 :             if (pfnDumpFeatureFunc)
     693               0 :                 pfnDumpFeatureFunc(psNode->pahFeatures[i], nIndentLevel + 2,
     694               0 :                                    pUserData);
     695                 :             else
     696                 :             {
     697               0 :                 for(count=nIndentLevel + 1;--count>=0;)
     698               0 :                     printf("  ");
     699               0 :                 printf("%p\n", psNode->pahFeatures[i]);
     700                 :             }
     701                 :         }
     702                 :     }
     703               0 : }
     704                 : 
     705                 : /************************************************************************/
     706                 : /*                         CPLQuadTreeDump()                            */
     707                 : /************************************************************************/
     708                 : 
     709               0 : void CPLQuadTreeDump(const CPLQuadTree *hQuadTree,
     710                 :                      CPLQuadTreeDumpFeatureFunc pfnDumpFeatureFunc,
     711                 :                      void* pUserData)
     712                 : {
     713               0 :     CPLQuadTreeDumpNode(hQuadTree->psRoot, 0, pfnDumpFeatureFunc, pUserData);
     714               0 : }
     715                 : 
     716                 : /************************************************************************/
     717                 : /*                  CPLQuadTreeGetStatsNode()                           */
     718                 : /************************************************************************/
     719                 : 
     720                 : static
     721               0 : void CPLQuadTreeGetStatsNode(const QuadTreeNode *psNode,
     722                 :                              int nDepthLevel,
     723                 :                              int* pnNodeCount,
     724                 :                              int* pnMaxDepth,
     725                 :                              int* pnMaxBucketCapacity)
     726                 : {
     727                 :     int i;
     728               0 :     (*pnNodeCount) ++;
     729               0 :     if (nDepthLevel > *pnMaxDepth)
     730               0 :         *pnMaxDepth = nDepthLevel;
     731               0 :     if (psNode->nFeatures > *pnMaxBucketCapacity)
     732               0 :         *pnMaxBucketCapacity = psNode->nFeatures;
     733               0 :     for(i=0; i<psNode->nNumSubNodes; i++ )
     734                 :     {
     735               0 :         CPLQuadTreeGetStatsNode(psNode->apSubNode[i], nDepthLevel + 1,
     736               0 :                                 pnNodeCount, pnMaxDepth, pnMaxBucketCapacity);
     737                 :     }
     738               0 : }
     739                 : 
     740                 : 
     741                 : /************************************************************************/
     742                 : /*                    CPLQuadTreeGetStats()                             */
     743                 : /************************************************************************/
     744                 : 
     745               0 : void CPLQuadTreeGetStats(const CPLQuadTree *hQuadTree,
     746                 :                          int* pnFeatureCount,
     747                 :                          int* pnNodeCount,
     748                 :                          int* pnMaxDepth,
     749                 :                          int* pnMaxBucketCapacity)
     750                 : {
     751                 :     int nFeatureCount, nNodeCount, nMaxDepth, nMaxBucketCapacity;
     752               0 :     CPLAssert(hQuadTree);
     753               0 :     if (pnFeatureCount == NULL)
     754               0 :         pnFeatureCount = &nFeatureCount;
     755               0 :     if (pnNodeCount == NULL)
     756               0 :         pnNodeCount = &nNodeCount;
     757               0 :     if (pnMaxDepth == NULL)
     758               0 :         pnMaxDepth = &nMaxDepth;
     759               0 :     if (pnMaxBucketCapacity == NULL)
     760               0 :         pnMaxBucketCapacity = &nMaxBucketCapacity;
     761                 : 
     762               0 :     *pnFeatureCount = hQuadTree->nFeatures;
     763               0 :     *pnNodeCount = 0;
     764               0 :     *pnMaxDepth = 1;
     765               0 :     *pnMaxBucketCapacity = 0;
     766                 : 
     767               0 :     CPLQuadTreeGetStatsNode(hQuadTree->psRoot, 0, pnNodeCount, pnMaxDepth, pnMaxBucketCapacity);
     768               0 : }

Generated by: LCOV version 1.7