LCOV - code coverage report
Current view: top level - port - cpl_quad_tree.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 325 406 80.0 %
Date: 2024-11-21 22:18:42 Functions: 25 29 86.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL - Common Portability Library
       4             :  * Purpose:  Implementation of quadtree building and searching functions.
       5             :  *           Derived from shapelib and mapserver implementations
       6             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       7             :  *           Even Rouault, <even dot rouault at spatialys.com>
       8             :  *
       9             :  ******************************************************************************
      10             :  * Copyright (c) 1999-2008, Frank Warmerdam
      11             :  * Copyright (c) 2008-2014, Even Rouault <even dot rouault at spatialys.com>
      12             :  *
      13             :  * SPDX-License-Identifier: MIT
      14             :  ******************************************************************************
      15             :  */
      16             : 
      17             : #include "cpl_port.h"
      18             : #include "cpl_quad_tree.h"
      19             : 
      20             : #include <algorithm>
      21             : #include <cstdio>
      22             : #include <cstring>
      23             : 
      24             : #include "cpl_conv.h"
      25             : #include "cpl_error.h"
      26             : 
      27             : constexpr int MAX_DEFAULT_TREE_DEPTH = 12;
      28             : constexpr int MAX_SUBNODES = 4;
      29             : 
      30             : typedef struct _QuadTreeNode QuadTreeNode;
      31             : 
      32             : struct _QuadTreeNode
      33             : {
      34             :     /* area covered by this psNode */
      35             :     CPLRectObj rect;
      36             : 
      37             :     int nFeatures; /* number of shapes stored at this psNode. */
      38             : 
      39             :     int nNumSubNodes; /* number of active subnodes */
      40             : 
      41             :     void **pahFeatures; /* list of shapes stored at this psNode. */
      42             :     CPLRectObj *pasBounds;
      43             : 
      44             :     QuadTreeNode *apSubNode[MAX_SUBNODES];
      45             : };
      46             : 
      47             : struct _CPLQuadTree
      48             : {
      49             :     QuadTreeNode *psRoot;
      50             :     CPLQuadTreeGetBoundsFunc pfnGetBounds;
      51             :     CPLQuadTreeGetBoundsExFunc pfnGetBoundsEx;
      52             :     void *pUserData;
      53             :     int nFeatures;
      54             :     int nMaxDepth;
      55             :     int nBucketCapacity;
      56             :     double dfSplitRatio;
      57             :     bool bForceUseOfSubNodes;
      58             : };
      59             : 
      60             : static void CPLQuadTreeAddFeatureInternal(CPLQuadTree *hQuadTree,
      61             :                                           void *hFeature,
      62             :                                           const CPLRectObj *pRect);
      63             : static void CPLQuadTreeNodeDestroy(QuadTreeNode *psNode);
      64             : 
      65             : /* -------------------------------------------------------------------- */
      66             : /*      If the following is 0.5, psNodes will be split in half.  If it  */
      67             : /*      is 0.6 then each apSubNode will contain 60% of the parent       */
      68             : /*      psNode, with 20% representing overlap.  This can be help to     */
      69             : /*      prevent small objects on a boundary from shifting too high      */
      70             : /*      up the hQuadTree.                                               */
      71             : /* -------------------------------------------------------------------- */
      72             : constexpr double DEFAULT_SPLIT_RATIO = 0.55;
      73             : 
      74             : /*
      75             : ** Returns TRUE if rectangle a is contained in rectangle b
      76             : */
      77     2194240 : static CPL_INLINE bool CPL_RectContained(const CPLRectObj *a,
      78             :                                          const CPLRectObj *b)
      79             : {
      80     3426080 :     return a->minx >= b->minx && a->maxx <= b->maxx && a->miny >= b->miny &&
      81     3426080 :            a->maxy <= b->maxy;
      82             : }
      83             : 
      84             : /*
      85             : ** Returns TRUE if rectangles a and b overlap
      86             : */
      87    22142300 : static CPL_INLINE bool CPL_RectOverlap(const CPLRectObj *a, const CPLRectObj *b)
      88             : {
      89    22142300 :     if (a->minx > b->maxx)
      90     7152900 :         return false;
      91    14989400 :     if (a->maxx < b->minx)
      92     6506440 :         return false;
      93     8482940 :     if (a->miny > b->maxy)
      94     1876610 :         return false;
      95     6606330 :     if (a->maxy < b->miny)
      96     1839330 :         return false;
      97     4767000 :     return true;
      98             : }
      99             : 
     100             : /************************************************************************/
     101             : /*                      CPLQuadTreeNodeCreate()                         */
     102             : /************************************************************************/
     103             : 
     104       42762 : static QuadTreeNode *CPLQuadTreeNodeCreate(const CPLRectObj *pRect)
     105             : {
     106             :     QuadTreeNode *psNode =
     107       42762 :         static_cast<QuadTreeNode *>(CPLMalloc(sizeof(QuadTreeNode)));
     108             : 
     109       42762 :     psNode->nFeatures = 0;
     110       42762 :     psNode->pahFeatures = nullptr;
     111       42762 :     psNode->pasBounds = nullptr;
     112             : 
     113       42762 :     psNode->nNumSubNodes = 0;
     114             : 
     115       42762 :     memcpy(&(psNode->rect), pRect, sizeof(CPLRectObj));
     116             : 
     117       42762 :     return psNode;
     118             : }
     119             : 
     120             : /************************************************************************/
     121             : /*                         CPLQuadTreeCreate()                          */
     122             : /************************************************************************/
     123             : 
     124             : /**
     125             :  * Create a new quadtree
     126             :  *
     127             :  * @param pGlobalBounds a pointer to the global extent of all
     128             :  *                      the elements that will be inserted
     129             :  * @param pfnGetBounds  a user provided function to get the bounding box of
     130             :  *                      the inserted elements. If it is set to NULL, then
     131             :  *                      CPLQuadTreeInsertWithBounds() must be used, and
     132             :  *                      extra memory will be used to keep features bounds in the
     133             :  *                      quad tree.
     134             :  *
     135             :  * @return a newly allocated quadtree
     136             :  */
     137             : 
     138         310 : CPLQuadTree *CPLQuadTreeCreate(const CPLRectObj *pGlobalBounds,
     139             :                                CPLQuadTreeGetBoundsFunc pfnGetBounds)
     140             : {
     141         310 :     CPLAssert(pGlobalBounds);
     142             : 
     143             :     /* -------------------------------------------------------------------- */
     144             :     /*      Allocate the hQuadTree object                                   */
     145             :     /* -------------------------------------------------------------------- */
     146             :     CPLQuadTree *hQuadTree =
     147         310 :         static_cast<CPLQuadTree *>(CPLMalloc(sizeof(CPLQuadTree)));
     148             : 
     149         310 :     hQuadTree->nFeatures = 0;
     150         310 :     hQuadTree->pfnGetBounds = pfnGetBounds;
     151         310 :     hQuadTree->pfnGetBoundsEx = nullptr;
     152         310 :     hQuadTree->nMaxDepth = 0;
     153         310 :     hQuadTree->nBucketCapacity = 8;
     154             : 
     155         310 :     hQuadTree->dfSplitRatio = DEFAULT_SPLIT_RATIO;
     156         310 :     hQuadTree->bForceUseOfSubNodes = false;
     157             : 
     158             :     /* -------------------------------------------------------------------- */
     159             :     /*      Allocate the psRoot psNode.                                     */
     160             :     /* -------------------------------------------------------------------- */
     161         310 :     hQuadTree->psRoot = CPLQuadTreeNodeCreate(pGlobalBounds);
     162             : 
     163         310 :     hQuadTree->pUserData = nullptr;
     164             : 
     165         310 :     return hQuadTree;
     166             : }
     167             : 
     168             : /************************************************************************/
     169             : /*                         CPLQuadTreeCreateEx()                        */
     170             : /************************************************************************/
     171             : 
     172             : /**
     173             :  * Create a new quadtree
     174             :  *
     175             :  * @param pGlobalBounds a pointer to the global extent of all
     176             :  *                      the elements that will be inserted
     177             :  * @param pfnGetBoundsEx  a user provided function to get the bounding box of
     178             :  *                      the inserted elements. If it is set to NULL, then
     179             :  *                      CPLQuadTreeInsertWithBounds() must be used, and
     180             :  *                      extra memory will be used to keep features bounds in the
     181             :  *                      quad tree.
     182             :  * @param pUserData     user data passed to pfnGetBoundsEx
     183             :  *
     184             :  * @return a newly allocated quadtree
     185             :  */
     186             : 
     187           4 : CPLQuadTree *CPLQuadTreeCreateEx(const CPLRectObj *pGlobalBounds,
     188             :                                  CPLQuadTreeGetBoundsExFunc pfnGetBoundsEx,
     189             :                                  void *pUserData)
     190             : {
     191           4 :     CPLAssert(pGlobalBounds);
     192             : 
     193             :     /* -------------------------------------------------------------------- */
     194             :     /*      Allocate the hQuadTree object                                   */
     195             :     /* -------------------------------------------------------------------- */
     196             :     CPLQuadTree *hQuadTree =
     197           4 :         static_cast<CPLQuadTree *>(CPLMalloc(sizeof(CPLQuadTree)));
     198             : 
     199           4 :     hQuadTree->nFeatures = 0;
     200           4 :     hQuadTree->pfnGetBounds = nullptr;
     201           4 :     hQuadTree->pfnGetBoundsEx = pfnGetBoundsEx;
     202           4 :     hQuadTree->nMaxDepth = 0;
     203           4 :     hQuadTree->nBucketCapacity = 8;
     204             : 
     205           4 :     hQuadTree->dfSplitRatio = DEFAULT_SPLIT_RATIO;
     206           4 :     hQuadTree->bForceUseOfSubNodes = false;
     207             : 
     208             :     /* -------------------------------------------------------------------- */
     209             :     /*      Allocate the psRoot psNode.                                     */
     210             :     /* -------------------------------------------------------------------- */
     211           4 :     hQuadTree->psRoot = CPLQuadTreeNodeCreate(pGlobalBounds);
     212             : 
     213           4 :     hQuadTree->pUserData = pUserData;
     214             : 
     215           4 :     return hQuadTree;
     216             : }
     217             : 
     218             : /************************************************************************/
     219             : /*                 CPLQuadTreeGetAdvisedMaxDepth()                      */
     220             : /************************************************************************/
     221             : 
     222             : /**
     223             :  * Returns the optimal depth of a quadtree to hold nExpectedFeatures
     224             :  *
     225             :  * @param nExpectedFeatures the expected maximum number of elements to be
     226             :  * inserted.
     227             :  *
     228             :  * @return the optimal depth of a quadtree to hold nExpectedFeatures
     229             :  */
     230             : 
     231         123 : int CPLQuadTreeGetAdvisedMaxDepth(int nExpectedFeatures)
     232             : {
     233             :     /* -------------------------------------------------------------------- */
     234             :     /*      Try to select a reasonable one                                  */
     235             :     /*      that implies approximately 8 shapes per node.                   */
     236             :     /* -------------------------------------------------------------------- */
     237         123 :     int nMaxDepth = 0;
     238         123 :     int nMaxNodeCount = 1;
     239             : 
     240         138 :     while (nMaxNodeCount < nExpectedFeatures / 4)
     241             :     {
     242          15 :         nMaxDepth += 1;
     243          15 :         nMaxNodeCount = nMaxNodeCount * 2;
     244             :     }
     245             : 
     246         123 :     CPLDebug("CPLQuadTree", "Estimated spatial index tree depth: %d",
     247             :              nMaxDepth);
     248             : 
     249             :     /* NOTE: Due to problems with memory allocation for deep trees,
     250             :      * automatically estimated depth is limited up to 12 levels.
     251             :      * See Ticket #1594 for detailed discussion.
     252             :      */
     253         123 :     if (nMaxDepth > MAX_DEFAULT_TREE_DEPTH)
     254             :     {
     255           0 :         nMaxDepth = MAX_DEFAULT_TREE_DEPTH;
     256             : 
     257           0 :         CPLDebug("CPLQuadTree",
     258             :                  "Falling back to max number of allowed index tree "
     259             :                  "levels (%d).",
     260             :                  MAX_DEFAULT_TREE_DEPTH);
     261             :     }
     262             : 
     263         123 :     return nMaxDepth;
     264             : }
     265             : 
     266             : /************************************************************************/
     267             : /*                     CPLQuadTreeSetMaxDepth()                         */
     268             : /************************************************************************/
     269             : 
     270             : /**
     271             :  * Set the maximum depth of a quadtree. By default, quad trees have
     272             :  * no maximum depth, but a maximum bucket capacity.
     273             :  *
     274             :  * @param hQuadTree the quad tree
     275             :  * @param nMaxDepth the maximum depth allowed
     276             :  */
     277             : 
     278         123 : void CPLQuadTreeSetMaxDepth(CPLQuadTree *hQuadTree, int nMaxDepth)
     279             : {
     280         123 :     hQuadTree->nMaxDepth = nMaxDepth;
     281         123 : }
     282             : 
     283             : /************************************************************************/
     284             : /*                   CPLQuadTreeSetBucketCapacity()                     */
     285             : /************************************************************************/
     286             : 
     287             : /**
     288             :  * Set the maximum capacity of a node of a quadtree. The default value is 8.
     289             :  * Note that the maximum capacity will only be honoured if the features
     290             :  * inserted have a point geometry. Otherwise it may be exceeded.
     291             :  *
     292             :  * @param hQuadTree the quad tree
     293             :  * @param nBucketCapacity the maximum capacity of a node of a quadtree
     294             :  */
     295             : 
     296           1 : void CPLQuadTreeSetBucketCapacity(CPLQuadTree *hQuadTree, int nBucketCapacity)
     297             : {
     298           1 :     if (nBucketCapacity > 0)
     299           1 :         hQuadTree->nBucketCapacity = nBucketCapacity;
     300           1 : }
     301             : 
     302             : /***********************************************************************/
     303             : /*                   CPLQuadTreeForceUseOfSubNodes()                   */
     304             : /************************************************************************/
     305             : 
     306             : /**
     307             :  * Force the quadtree to insert as much as possible a feature whose bbox
     308             :  * spread over multiple subnodes into those subnodes, rather than in the
     309             :  * list of features attached to the node.
     310             :  *
     311             :  * @param hQuadTree the quad tree
     312             :  */
     313             : 
     314           4 : void CPLQuadTreeForceUseOfSubNodes(CPLQuadTree *hQuadTree)
     315             : {
     316           4 :     hQuadTree->bForceUseOfSubNodes = true;
     317           4 : }
     318             : 
     319             : /************************************************************************/
     320             : /*                        CPLQuadTreeInsert()                           */
     321             : /************************************************************************/
     322             : 
     323             : /**
     324             :  * Insert a feature into a quadtree
     325             :  *
     326             :  * @param hQuadTree the quad tree
     327             :  * @param hFeature the feature to insert
     328             :  */
     329             : 
     330       29118 : void CPLQuadTreeInsert(CPLQuadTree *hQuadTree, void *hFeature)
     331             : {
     332       29118 :     if (hQuadTree->pfnGetBounds == nullptr &&
     333        1062 :         hQuadTree->pfnGetBoundsEx == nullptr)
     334             :     {
     335           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     336             :                  "hQuadTree->pfnGetBounds == NULL");
     337           0 :         return;
     338             :     }
     339       29118 :     hQuadTree->nFeatures++;
     340             :     CPLRectObj bounds;
     341       29118 :     if (hQuadTree->pfnGetBoundsEx)
     342        1062 :         hQuadTree->pfnGetBoundsEx(hFeature, hQuadTree->pUserData, &bounds);
     343             :     else
     344       28056 :         hQuadTree->pfnGetBounds(hFeature, &bounds);
     345       29118 :     CPLQuadTreeAddFeatureInternal(hQuadTree, hFeature, &bounds);
     346             : }
     347             : 
     348             : /************************************************************************/
     349             : /*                        CPLQuadTreeInsertWithBounds()                 */
     350             : /************************************************************************/
     351             : 
     352             : /**
     353             :  * Insert a feature into a quadtree
     354             :  *
     355             :  * @param hQuadTree the quad tree
     356             :  * @param hFeature the feature to insert
     357             :  * @param psBounds bounds of the feature
     358             :  */
     359       94988 : void CPLQuadTreeInsertWithBounds(CPLQuadTree *hQuadTree, void *hFeature,
     360             :                                  const CPLRectObj *psBounds)
     361             : {
     362       94988 :     hQuadTree->nFeatures++;
     363       94988 :     CPLQuadTreeAddFeatureInternal(hQuadTree, hFeature, psBounds);
     364       94988 : }
     365             : 
     366             : /************************************************************************/
     367             : /*                            CPLQuadTreeRemove()                       */
     368             : /************************************************************************/
     369             : 
     370       24011 : static bool CPLQuadTreeRemoveInternal(QuadTreeNode *psNode, void *hFeature,
     371             :                                       const CPLRectObj *psBounds)
     372             : {
     373       24011 :     bool bRemoved = false;
     374             : 
     375      480605 :     for (int i = 0; i < psNode->nFeatures; i++)
     376             :     {
     377      458617 :         if (psNode->pahFeatures[i] == hFeature)
     378             :         {
     379        2023 :             if (i < psNode->nFeatures - 1)
     380             :             {
     381        1901 :                 memmove(psNode->pahFeatures + i, psNode->pahFeatures + i + 1,
     382        1901 :                         (psNode->nFeatures - 1 - i) * sizeof(void *));
     383        1901 :                 if (psNode->pasBounds)
     384             :                 {
     385        1901 :                     memmove(psNode->pasBounds + i, psNode->pasBounds + i + 1,
     386        1901 :                             (psNode->nFeatures - 1 - i) * sizeof(CPLRectObj));
     387             :                 }
     388             :             }
     389        2023 :             bRemoved = true;
     390        2023 :             psNode->nFeatures--;
     391        2023 :             break;
     392             :         }
     393             :     }
     394       24011 :     if (psNode->nFeatures == 0 && psNode->pahFeatures != nullptr)
     395             :     {
     396         122 :         CPLFree(psNode->pahFeatures);
     397         122 :         CPLFree(psNode->pasBounds);
     398         122 :         psNode->pahFeatures = nullptr;
     399         122 :         psNode->pasBounds = nullptr;
     400             :     }
     401             : 
     402             :     /* -------------------------------------------------------------------- */
     403             :     /*      Recurse to subnodes if they exist.                              */
     404             :     /* -------------------------------------------------------------------- */
     405       62797 :     for (int i = 0; i < psNode->nNumSubNodes; i++)
     406             :     {
     407       77572 :         if (psNode->apSubNode[i] &&
     408       38786 :             CPL_RectOverlap(&(psNode->apSubNode[i]->rect), psBounds))
     409             :         {
     410       21988 :             bRemoved |= CPLQuadTreeRemoveInternal(psNode->apSubNode[i],
     411             :                                                   hFeature, psBounds);
     412             : 
     413       21988 :             if (psNode->apSubNode[i]->nFeatures == 0 &&
     414         646 :                 psNode->apSubNode[i]->nNumSubNodes == 0)
     415             :             {
     416         120 :                 CPLQuadTreeNodeDestroy(psNode->apSubNode[i]);
     417         120 :                 if (i < psNode->nNumSubNodes - 1)
     418             :                 {
     419          77 :                     memmove(psNode->apSubNode + i, psNode->apSubNode + i + 1,
     420          77 :                             (psNode->nNumSubNodes - 1 - i) *
     421             :                                 sizeof(QuadTreeNode *));
     422             :                 }
     423         120 :                 i--;
     424         120 :                 psNode->nNumSubNodes--;
     425             :             }
     426             :         }
     427             :     }
     428             : 
     429       24011 :     return bRemoved;
     430             : }
     431             : 
     432             : /**
     433             :  * Remove a feature from a quadtree.
     434             :  *
     435             :  * Currently the quadtree is not re-balanced.
     436             :  *
     437             :  * @param hQuadTree the quad tree
     438             :  * @param hFeature the feature to remove
     439             :  * @param psBounds bounds of the feature (or NULL if pfnGetBounds has been
     440             :  * filled)
     441             :  */
     442        2023 : void CPLQuadTreeRemove(CPLQuadTree *hQuadTree, void *hFeature,
     443             :                        const CPLRectObj *psBounds)
     444             : {
     445        2023 :     if (psBounds == nullptr && hQuadTree->pfnGetBounds == nullptr &&
     446           0 :         hQuadTree->pfnGetBoundsEx == nullptr)
     447             :     {
     448           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     449             :                  "hQuadTree->pfnGetBounds == NULL");
     450           0 :         return;
     451             :     }
     452             :     CPLRectObj bounds;  // keep variable in this outer scope
     453        2023 :     if (psBounds == nullptr)
     454             :     {
     455           0 :         if (hQuadTree->pfnGetBoundsEx)
     456           0 :             hQuadTree->pfnGetBoundsEx(hFeature, hQuadTree->pUserData, &bounds);
     457             :         else
     458           0 :             hQuadTree->pfnGetBounds(hFeature, &bounds);
     459           0 :         psBounds = &bounds;
     460             :     }
     461        2023 :     if (CPLQuadTreeRemoveInternal(hQuadTree->psRoot, hFeature, psBounds))
     462             :     {
     463        2023 :         hQuadTree->nFeatures--;
     464             :     }
     465             : }
     466             : 
     467             : /************************************************************************/
     468             : /*                    CPLQuadTreeNodeDestroy()                          */
     469             : /************************************************************************/
     470             : 
     471       42762 : static void CPLQuadTreeNodeDestroy(QuadTreeNode *psNode)
     472             : {
     473       85090 :     for (int i = 0; i < psNode->nNumSubNodes; i++)
     474             :     {
     475       42328 :         if (psNode->apSubNode[i])
     476       42328 :             CPLQuadTreeNodeDestroy(psNode->apSubNode[i]);
     477             :     }
     478             : 
     479       42762 :     if (psNode->pahFeatures)
     480             :     {
     481       29865 :         CPLFree(psNode->pahFeatures);
     482       29865 :         CPLFree(psNode->pasBounds);
     483             :     }
     484             : 
     485       42762 :     CPLFree(psNode);
     486       42762 : }
     487             : 
     488             : /************************************************************************/
     489             : /*                       CPLQuadTreeDestroy()                           */
     490             : /************************************************************************/
     491             : 
     492             : /**
     493             :  * Destroy a quadtree
     494             :  *
     495             :  * @param hQuadTree the quad tree to destroy
     496             :  */
     497             : 
     498         314 : void CPLQuadTreeDestroy(CPLQuadTree *hQuadTree)
     499             : {
     500         314 :     CPLAssert(hQuadTree);
     501         314 :     CPLQuadTreeNodeDestroy(hQuadTree->psRoot);
     502         314 :     CPLFree(hQuadTree);
     503         314 : }
     504             : 
     505             : /************************************************************************/
     506             : /*                     CPLQuadTreeSplitBounds()                         */
     507             : /************************************************************************/
     508             : 
     509       47439 : static void CPLQuadTreeSplitBounds(double dfSplitRatio, const CPLRectObj *in,
     510             :                                    CPLRectObj *out1, CPLRectObj *out2)
     511             : {
     512             :     /* -------------------------------------------------------------------- */
     513             :     /*      The output bounds will be very similar to the input bounds,     */
     514             :     /*      so just copy over to start.                                     */
     515             :     /* -------------------------------------------------------------------- */
     516       47439 :     memcpy(out1, in, sizeof(CPLRectObj));
     517       47439 :     memcpy(out2, in, sizeof(CPLRectObj));
     518             : 
     519             :     /* -------------------------------------------------------------------- */
     520             :     /*      Split in X direction.                                           */
     521             :     /* -------------------------------------------------------------------- */
     522       47439 :     if ((in->maxx - in->minx) > (in->maxy - in->miny))
     523             :     {
     524       20369 :         const double range = in->maxx - in->minx;
     525             : 
     526       20369 :         out1->maxx = in->minx + range * dfSplitRatio;
     527       20369 :         out2->minx = in->maxx - range * dfSplitRatio;
     528             :     }
     529             : 
     530             :     /* -------------------------------------------------------------------- */
     531             :     /*      Otherwise split in Y direction.                                 */
     532             :     /* -------------------------------------------------------------------- */
     533             :     else
     534             :     {
     535       27070 :         const double range = in->maxy - in->miny;
     536             : 
     537       27070 :         out1->maxy = in->miny + range * dfSplitRatio;
     538       27070 :         out2->miny = in->maxy - range * dfSplitRatio;
     539             :     }
     540       47439 : }
     541             : 
     542             : /************************************************************************/
     543             : /*                  CPLQuadTreeNodeAddFeatureAlg1()                     */
     544             : /************************************************************************/
     545             : 
     546      985922 : static void CPLQuadTreeNodeAddFeatureAlg1(CPLQuadTree *hQuadTree,
     547             :                                           QuadTreeNode *psNode, void *hFeature,
     548             :                                           const CPLRectObj *pRect)
     549             : {
     550      985922 :     if (psNode->nNumSubNodes == 0)
     551             :     {
     552             :         // If we have reached the max bucket capacity, try to insert
     553             :         // in a subnode if possible.
     554      195634 :         if (psNode->nFeatures >= hQuadTree->nBucketCapacity)
     555             :         {
     556       15811 :             CPLRectObj half1 = {0.0, 0.0, 0.0, 0.0};
     557       15811 :             CPLRectObj half2 = {0.0, 0.0, 0.0, 0.0};
     558       15811 :             CPLRectObj quad1 = {0.0, 0.0, 0.0, 0.0};
     559       15811 :             CPLRectObj quad2 = {0.0, 0.0, 0.0, 0.0};
     560       15811 :             CPLRectObj quad3 = {0.0, 0.0, 0.0, 0.0};
     561       15811 :             CPLRectObj quad4 = {0.0, 0.0, 0.0, 0.0};
     562             : 
     563       15811 :             CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &psNode->rect,
     564             :                                    &half1, &half2);
     565       15811 :             CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half1, &quad1,
     566             :                                    &quad2);
     567       15811 :             CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half2, &quad3,
     568             :                                    &quad4);
     569             : 
     570       47433 :             if (memcmp(&psNode->rect, &quad1, sizeof(CPLRectObj)) != 0 &&
     571       15811 :                 memcmp(&psNode->rect, &quad2, sizeof(CPLRectObj)) != 0 &&
     572       15811 :                 memcmp(&psNode->rect, &quad3, sizeof(CPLRectObj)) != 0 &&
     573       47433 :                 memcmp(&psNode->rect, &quad4, sizeof(CPLRectObj)) != 0 &&
     574       31514 :                 (hQuadTree->bForceUseOfSubNodes ||
     575       30327 :                  CPL_RectContained(pRect, &quad1) ||
     576       27029 :                  CPL_RectContained(pRect, &quad2) ||
     577       21917 :                  CPL_RectContained(pRect, &quad3) ||
     578        9512 :                  CPL_RectContained(pRect, &quad4)))
     579             :             {
     580       10610 :                 psNode->nNumSubNodes = 4;
     581       10610 :                 psNode->apSubNode[0] = CPLQuadTreeNodeCreate(&quad1);
     582       10610 :                 psNode->apSubNode[1] = CPLQuadTreeNodeCreate(&quad2);
     583       10610 :                 psNode->apSubNode[2] = CPLQuadTreeNodeCreate(&quad3);
     584       10610 :                 psNode->apSubNode[3] = CPLQuadTreeNodeCreate(&quad4);
     585             : 
     586       10610 :                 const int oldNumFeatures = psNode->nFeatures;
     587       10610 :                 void **oldFeatures = psNode->pahFeatures;
     588       10610 :                 CPLRectObj *pasOldBounds = psNode->pasBounds;
     589       10610 :                 psNode->nFeatures = 0;
     590       10610 :                 psNode->pahFeatures = nullptr;
     591       10610 :                 psNode->pasBounds = nullptr;
     592             : 
     593             :                 // Redispatch existing pahFeatures in apSubNodes.
     594       97783 :                 for (int i = 0; i < oldNumFeatures; i++)
     595             :                 {
     596       87173 :                     if (hQuadTree->pfnGetBounds == nullptr &&
     597       64017 :                         hQuadTree->pfnGetBoundsEx == nullptr)
     598       63153 :                         CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode,
     599       63153 :                                                       oldFeatures[i],
     600       63153 :                                                       &pasOldBounds[i]);
     601             :                     else
     602             :                     {
     603             :                         CPLRectObj bounds;
     604       24020 :                         if (hQuadTree->pfnGetBoundsEx)
     605         864 :                             hQuadTree->pfnGetBoundsEx(
     606         864 :                                 oldFeatures[i], hQuadTree->pUserData, &bounds);
     607             :                         else
     608       23156 :                             hQuadTree->pfnGetBounds(oldFeatures[i], &bounds);
     609       24020 :                         CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode,
     610       24020 :                                                       oldFeatures[i], &bounds);
     611             :                     }
     612             :                 }
     613             : 
     614       10610 :                 CPLFree(oldFeatures);
     615       10610 :                 CPLFree(pasOldBounds);
     616             : 
     617             :                 /* recurse back on this psNode now that it has apSubNodes */
     618       10610 :                 CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode, hFeature,
     619             :                                               pRect);
     620       10610 :                 return;
     621             :             }
     622             :         }
     623             :     }
     624             :     else
     625             :     {
     626             :         /* --------------------------------------------------------------------
     627             :          */
     628             :         /*      If there are apSubNodes, then consider whether this object */
     629             :         /*      will fit in them. */
     630             :         /* --------------------------------------------------------------------
     631             :          */
     632     2169020 :         for (int i = 0; i < psNode->nNumSubNodes; i++)
     633             :         {
     634     2141990 :             if (CPL_RectContained(pRect, &psNode->apSubNode[i]->rect))
     635             :             {
     636      763251 :                 CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, psNode->apSubNode[i],
     637             :                                               hFeature, pRect);
     638      763251 :                 return;
     639             :             }
     640             :         }
     641       27037 :         if (hQuadTree->bForceUseOfSubNodes)
     642             :         {
     643             :             bool overlaps[4];
     644         576 :             bool overlapAll = true;
     645        2880 :             for (int i = 0; i < psNode->nNumSubNodes; i++)
     646             :             {
     647        2304 :                 overlaps[i] =
     648        2304 :                     CPL_RectOverlap(pRect, &psNode->apSubNode[i]->rect);
     649        2304 :                 if (!overlaps[i])
     650        1142 :                     overlapAll = false;
     651             :             }
     652         576 :             if (!overlapAll)
     653             :             {
     654        2440 :                 for (int i = 0; i < psNode->nNumSubNodes; i++)
     655             :                 {
     656        1952 :                     if (overlaps[i])
     657             :                     {
     658             :                         CPLRectObj intersection;
     659         810 :                         intersection.minx = std::max(
     660         810 :                             pRect->minx, psNode->apSubNode[i]->rect.minx);
     661         810 :                         intersection.miny = std::max(
     662         810 :                             pRect->miny, psNode->apSubNode[i]->rect.miny);
     663         810 :                         intersection.maxx = std::min(
     664         810 :                             pRect->maxx, psNode->apSubNode[i]->rect.maxx);
     665         810 :                         intersection.maxy = std::min(
     666         810 :                             pRect->maxy, psNode->apSubNode[i]->rect.maxy);
     667         810 :                         CPLQuadTreeNodeAddFeatureAlg1(hQuadTree,
     668             :                                                       psNode->apSubNode[i],
     669             :                                                       hFeature, &intersection);
     670             :                     }
     671             :                 }
     672         488 :                 return;
     673             :             }
     674             :         }
     675             :     }
     676             : 
     677             :     /* -------------------------------------------------------------------- */
     678             :     /*      If none of that worked, just add it to this psNodes list.         */
     679             :     /* -------------------------------------------------------------------- */
     680      211573 :     psNode->nFeatures++;
     681             : 
     682      211573 :     if (psNode->nFeatures == 1)
     683             :     {
     684       40593 :         CPLAssert(psNode->pahFeatures == nullptr);
     685       40593 :         psNode->pahFeatures = static_cast<void **>(
     686       40593 :             CPLMalloc(hQuadTree->nBucketCapacity * sizeof(void *)));
     687       40593 :         if (hQuadTree->pfnGetBounds == nullptr &&
     688       29605 :             hQuadTree->pfnGetBoundsEx == nullptr)
     689       29099 :             psNode->pasBounds = static_cast<CPLRectObj *>(
     690       29099 :                 CPLMalloc(hQuadTree->nBucketCapacity * sizeof(CPLRectObj)));
     691             :     }
     692      170980 :     else if (psNode->nFeatures > hQuadTree->nBucketCapacity)
     693             :     {
     694       17024 :         psNode->pahFeatures = static_cast<void **>(CPLRealloc(
     695        8512 :             psNode->pahFeatures, sizeof(void *) * psNode->nFeatures));
     696        8512 :         if (hQuadTree->pfnGetBounds == nullptr &&
     697        8512 :             hQuadTree->pfnGetBoundsEx == nullptr)
     698        8512 :             psNode->pasBounds = static_cast<CPLRectObj *>(CPLRealloc(
     699        8512 :                 psNode->pasBounds, sizeof(CPLRectObj) * psNode->nFeatures));
     700             :     }
     701      211573 :     psNode->pahFeatures[psNode->nFeatures - 1] = hFeature;
     702      211573 :     if (hQuadTree->pfnGetBounds == nullptr &&
     703      160361 :         hQuadTree->pfnGetBoundsEx == nullptr)
     704      158113 :         psNode->pasBounds[psNode->nFeatures - 1] = *pRect;
     705             : 
     706      211573 :     return;
     707             : }
     708             : 
     709             : /************************************************************************/
     710             : /*                  CPLQuadTreeNodeAddFeatureAlg2()                     */
     711             : /************************************************************************/
     712             : 
     713          32 : static void CPLQuadTreeNodeAddFeatureAlg2(CPLQuadTree *hQuadTree,
     714             :                                           QuadTreeNode *psNode, void *hFeature,
     715             :                                           const CPLRectObj *pRect,
     716             :                                           int nMaxDepth)
     717             : {
     718             :     /* -------------------------------------------------------------------- */
     719             :     /*      If there are apSubNodes, then consider whether this object      */
     720             :     /*      will fit in them.                                               */
     721             :     /* -------------------------------------------------------------------- */
     722          32 :     if (nMaxDepth > 1 && psNode->nNumSubNodes > 0)
     723             :     {
     724           2 :         for (int i = 0; i < psNode->nNumSubNodes; i++)
     725             :         {
     726           2 :             if (CPL_RectContained(pRect, &psNode->apSubNode[i]->rect))
     727             :             {
     728           2 :                 CPLQuadTreeNodeAddFeatureAlg2(hQuadTree, psNode->apSubNode[i],
     729             :                                               hFeature, pRect, nMaxDepth - 1);
     730           2 :                 return;
     731             :             }
     732           0 :         }
     733             :     }
     734             : 
     735             :     /* -------------------------------------------------------------------- */
     736             :     /*      Otherwise, consider creating four apSubNodes if could fit into  */
     737             :     /*      them, and adding to the appropriate apSubNode.                  */
     738             :     /* -------------------------------------------------------------------- */
     739          30 :     else if (nMaxDepth > 1 && psNode->nNumSubNodes == 0)
     740             :     {
     741             :         CPLRectObj half1, half2, quad1, quad2, quad3, quad4;
     742             : 
     743           2 :         CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &psNode->rect, &half1,
     744             :                                &half2);
     745           2 :         CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half1, &quad1, &quad2);
     746           2 :         CPLQuadTreeSplitBounds(hQuadTree->dfSplitRatio, &half2, &quad3, &quad4);
     747             : 
     748           6 :         if (memcmp(&psNode->rect, &quad1, sizeof(CPLRectObj)) != 0 &&
     749           2 :             memcmp(&psNode->rect, &quad2, sizeof(CPLRectObj)) != 0 &&
     750           2 :             memcmp(&psNode->rect, &quad3, sizeof(CPLRectObj)) != 0 &&
     751           6 :             memcmp(&psNode->rect, &quad4, sizeof(CPLRectObj)) != 0 &&
     752           2 :             (CPL_RectContained(pRect, &quad1) ||
     753           0 :              CPL_RectContained(pRect, &quad2) ||
     754           0 :              CPL_RectContained(pRect, &quad3) ||
     755           0 :              CPL_RectContained(pRect, &quad4)))
     756             :         {
     757           2 :             psNode->nNumSubNodes = 4;
     758           2 :             psNode->apSubNode[0] = CPLQuadTreeNodeCreate(&quad1);
     759           2 :             psNode->apSubNode[1] = CPLQuadTreeNodeCreate(&quad2);
     760           2 :             psNode->apSubNode[2] = CPLQuadTreeNodeCreate(&quad3);
     761           2 :             psNode->apSubNode[3] = CPLQuadTreeNodeCreate(&quad4);
     762             : 
     763             :             /* recurse back on this psNode now that it has apSubNodes */
     764           2 :             CPLQuadTreeNodeAddFeatureAlg2(hQuadTree, psNode, hFeature, pRect,
     765             :                                           nMaxDepth);
     766           2 :             return;
     767             :         }
     768             :     }
     769             : 
     770             :     /* -------------------------------------------------------------------- */
     771             :     /*      If none of that worked, just add it to this psNodes list.       */
     772             :     /* -------------------------------------------------------------------- */
     773          28 :     psNode->nFeatures++;
     774             : 
     775          28 :     psNode->pahFeatures = static_cast<void **>(
     776          28 :         CPLRealloc(psNode->pahFeatures, sizeof(void *) * psNode->nFeatures));
     777          28 :     if (hQuadTree->pfnGetBounds == nullptr &&
     778          28 :         hQuadTree->pfnGetBoundsEx == nullptr)
     779             :     {
     780          28 :         psNode->pasBounds = static_cast<CPLRectObj *>(CPLRealloc(
     781          28 :             psNode->pasBounds, sizeof(CPLRectObj) * psNode->nFeatures));
     782             :     }
     783          28 :     psNode->pahFeatures[psNode->nFeatures - 1] = hFeature;
     784          28 :     if (hQuadTree->pfnGetBounds == nullptr &&
     785          28 :         hQuadTree->pfnGetBoundsEx == nullptr)
     786             :     {
     787          28 :         psNode->pasBounds[psNode->nFeatures - 1] = *pRect;
     788             :     }
     789             : }
     790             : 
     791             : /************************************************************************/
     792             : /*                  CPLQuadTreeAddFeatureInternal()                     */
     793             : /************************************************************************/
     794             : 
     795      124106 : static void CPLQuadTreeAddFeatureInternal(CPLQuadTree *hQuadTree,
     796             :                                           void *hFeature,
     797             :                                           const CPLRectObj *pRect)
     798             : {
     799      124106 :     if (hQuadTree->nMaxDepth == 0)
     800             :     {
     801      124078 :         CPLQuadTreeNodeAddFeatureAlg1(hQuadTree, hQuadTree->psRoot, hFeature,
     802             :                                       pRect);
     803             :     }
     804             :     else
     805             :     {
     806          28 :         CPLQuadTreeNodeAddFeatureAlg2(hQuadTree, hQuadTree->psRoot, hFeature,
     807             :                                       pRect, hQuadTree->nMaxDepth);
     808             :     }
     809      124106 : }
     810             : 
     811             : /************************************************************************/
     812             : /*                     CPLQuadTreeCollectFeatures()                     */
     813             : /************************************************************************/
     814             : 
     815    10493100 : static void CPLQuadTreeCollectFeatures(const CPLQuadTree *hQuadTree,
     816             :                                        const QuadTreeNode *psNode,
     817             :                                        const CPLRectObj *pAoi,
     818             :                                        int *pnFeatureCount, int *pnMaxFeatures,
     819             :                                        void ***pppFeatureList)
     820             : {
     821             :     /* -------------------------------------------------------------------- */
     822             :     /*      Does this psNode overlap the area of interest at all?  If not,  */
     823             :     /*      return without adding to the list at all.                       */
     824             :     /* -------------------------------------------------------------------- */
     825    10493100 :     if (!CPL_RectOverlap(&psNode->rect, pAoi))
     826     6809400 :         return;
     827             : 
     828             :     /* -------------------------------------------------------------------- */
     829             :     /*      Grow the list to hold the features on this psNode.              */
     830             :     /* -------------------------------------------------------------------- */
     831     3682030 :     if (*pnFeatureCount + psNode->nFeatures > *pnMaxFeatures)
     832             :     {
     833             :         // TODO(schwehr): Symbolic constant.
     834      251230 :         *pnMaxFeatures = (*pnFeatureCount + psNode->nFeatures) * 2 + 20;
     835      251207 :         *pppFeatureList = static_cast<void **>(
     836      251230 :             CPLRealloc(*pppFeatureList, sizeof(void *) * *pnMaxFeatures));
     837             :     }
     838             : 
     839             :     /* -------------------------------------------------------------------- */
     840             :     /*      Add the local features to the list.                             */
     841             :     /* -------------------------------------------------------------------- */
     842    15343000 :     for (int i = 0; i < psNode->nFeatures; i++)
     843             :     {
     844    11658000 :         if (hQuadTree->pfnGetBounds == nullptr &&
     845    10991100 :             hQuadTree->pfnGetBoundsEx == nullptr)
     846             :         {
     847    10990900 :             if (CPL_RectOverlap(&psNode->pasBounds[i], pAoi))
     848      803651 :                 (*pppFeatureList)[(*pnFeatureCount)++] = psNode->pahFeatures[i];
     849             :         }
     850             :         else
     851             :         {
     852             :             CPLRectObj bounds;
     853      667085 :             if (hQuadTree->pfnGetBoundsEx)
     854         188 :                 hQuadTree->pfnGetBoundsEx(psNode->pahFeatures[i],
     855         188 :                                           hQuadTree->pUserData, &bounds);
     856             :             else
     857      666897 :                 hQuadTree->pfnGetBounds(psNode->pahFeatures[i], &bounds);
     858             : 
     859      691378 :             if (CPL_RectOverlap(&bounds, pAoi))
     860      363234 :                 (*pppFeatureList)[(*pnFeatureCount)++] = psNode->pahFeatures[i];
     861             :         }
     862             :     }
     863             : 
     864             :     /* -------------------------------------------------------------------- */
     865             :     /*      Recurse to subnodes if they exist.                              */
     866             :     /* -------------------------------------------------------------------- */
     867    13941000 :     for (int i = 0; i < psNode->nNumSubNodes; i++)
     868             :     {
     869    10251000 :         if (psNode->apSubNode[i])
     870    10254500 :             CPLQuadTreeCollectFeatures(hQuadTree, psNode->apSubNode[i], pAoi,
     871             :                                        pnFeatureCount, pnMaxFeatures,
     872             :                                        pppFeatureList);
     873             :     }
     874             : }
     875             : 
     876             : /************************************************************************/
     877             : /*                         CPLQuadTreeSearch()                          */
     878             : /************************************************************************/
     879             : 
     880             : /**
     881             :  * Returns all the elements inserted whose bounding box intersects the
     882             :  * provided area of interest
     883             :  *
     884             :  * @param hQuadTree the quad tree
     885             :  * @param pAoi the pointer to the area of interest
     886             :  * @param pnFeatureCount the user data provided to the function.
     887             :  *
     888             :  * @return an array of features that must be freed with CPLFree
     889             :  */
     890             : 
     891      245273 : void **CPLQuadTreeSearch(const CPLQuadTree *hQuadTree, const CPLRectObj *pAoi,
     892             :                          int *pnFeatureCount)
     893             : {
     894      245273 :     CPLAssert(hQuadTree);
     895      245273 :     CPLAssert(pAoi);
     896             : 
     897      245273 :     int nFeatureCount = 0;
     898      245273 :     if (pnFeatureCount == nullptr)
     899           0 :         pnFeatureCount = &nFeatureCount;
     900             : 
     901      245273 :     *pnFeatureCount = 0;
     902             : 
     903      245273 :     int nMaxFeatures = 0;
     904      245273 :     void **ppFeatureList = nullptr;
     905      245273 :     CPLQuadTreeCollectFeatures(hQuadTree, hQuadTree->psRoot, pAoi,
     906             :                                pnFeatureCount, &nMaxFeatures, &ppFeatureList);
     907             : 
     908      245211 :     return ppFeatureList;
     909             : }
     910             : 
     911             : /************************************************************************/
     912             : /*                         CPLQuadTreeHasMatch()                        */
     913             : /************************************************************************/
     914             : 
     915         419 : static bool CPLQuadTreeHasMatch(const CPLQuadTree *hQuadTree,
     916             :                                 const QuadTreeNode *psNode,
     917             :                                 const CPLRectObj *pAoi)
     918             : {
     919             :     /* -------------------------------------------------------------------- */
     920             :     /*      Does this psNode overlap the area of interest at all?           */
     921             :     /* -------------------------------------------------------------------- */
     922         419 :     if (!CPL_RectOverlap(&psNode->rect, pAoi))
     923           0 :         return false;
     924             : 
     925             :     /* -------------------------------------------------------------------- */
     926             :     /*      Check the local features.                                       */
     927             :     /* -------------------------------------------------------------------- */
     928       10864 :     for (int i = 0; i < psNode->nFeatures; i++)
     929             :     {
     930       10451 :         if (hQuadTree->pfnGetBounds == nullptr &&
     931       10451 :             hQuadTree->pfnGetBoundsEx == nullptr)
     932             :         {
     933       10451 :             if (CPL_RectOverlap(&psNode->pasBounds[i], pAoi))
     934           6 :                 return true;
     935             :         }
     936             :         else
     937             :         {
     938             :             CPLRectObj bounds;
     939           0 :             if (hQuadTree->pfnGetBoundsEx)
     940           0 :                 hQuadTree->pfnGetBoundsEx(psNode->pahFeatures[i],
     941           0 :                                           hQuadTree->pUserData, &bounds);
     942             :             else
     943           0 :                 hQuadTree->pfnGetBounds(psNode->pahFeatures[i], &bounds);
     944             : 
     945           0 :             if (CPL_RectOverlap(&bounds, pAoi))
     946           0 :                 return true;
     947             :         }
     948             :     }
     949             : 
     950             :     /* -------------------------------------------------------------------- */
     951             :     /*      Recurse to subnodes if they exist.                              */
     952             :     /* -------------------------------------------------------------------- */
     953         413 :     for (int i = 0; i < psNode->nNumSubNodes; i++)
     954             :     {
     955           0 :         if (psNode->apSubNode[i])
     956             :         {
     957           0 :             if (CPLQuadTreeHasMatch(hQuadTree, psNode->apSubNode[i], pAoi))
     958             :             {
     959           0 :                 return true;
     960             :             }
     961             :         }
     962             :     }
     963             : 
     964         413 :     return false;
     965             : }
     966             : 
     967             : /**
     968             :  * Returns whether the quadtree has at least one element whose bounding box
     969             :  * intersects the provided area of interest
     970             :  *
     971             :  * @param hQuadTree the quad tree
     972             :  * @param pAoi the pointer to the area of interest
     973             :  */
     974             : 
     975         419 : bool CPLQuadTreeHasMatch(const CPLQuadTree *hQuadTree, const CPLRectObj *pAoi)
     976             : {
     977         419 :     CPLAssert(hQuadTree);
     978         419 :     CPLAssert(pAoi);
     979             : 
     980         419 :     return CPLQuadTreeHasMatch(hQuadTree, hQuadTree->psRoot, pAoi);
     981             : }
     982             : 
     983             : /************************************************************************/
     984             : /*                    CPLQuadTreeNodeForeach()                          */
     985             : /************************************************************************/
     986             : 
     987          25 : static bool CPLQuadTreeNodeForeach(const QuadTreeNode *psNode,
     988             :                                    CPLQuadTreeForeachFunc pfnForeach,
     989             :                                    void *pUserData)
     990             : {
     991          49 :     for (int i = 0; i < psNode->nNumSubNodes; i++)
     992             :     {
     993          24 :         if (!CPLQuadTreeNodeForeach(psNode->apSubNode[i], pfnForeach,
     994             :                                     pUserData))
     995           0 :             return false;
     996             :     }
     997             : 
     998          50 :     for (int i = 0; i < psNode->nFeatures; i++)
     999             :     {
    1000          25 :         if (pfnForeach(psNode->pahFeatures[i], pUserData) == FALSE)
    1001           0 :             return false;
    1002             :     }
    1003             : 
    1004          25 :     return true;
    1005             : }
    1006             : 
    1007             : /************************************************************************/
    1008             : /*                       CPLQuadTreeForeach()                           */
    1009             : /************************************************************************/
    1010             : 
    1011             : /**
    1012             :  * Walk through the quadtree and runs the provided function on all the
    1013             :  * elements
    1014             :  *
    1015             :  * This function is provided with the user_data argument of pfnForeach.
    1016             :  * It must return TRUE to go on the walk through the hash set, or FALSE to
    1017             :  * make it stop.
    1018             :  *
    1019             :  * Note : the structure of the quadtree must *NOT* be modified during the
    1020             :  * walk.
    1021             :  *
    1022             :  * @param hQuadTree the quad tree
    1023             :  * @param pfnForeach the function called on each element.
    1024             :  * @param pUserData the user data provided to the function.
    1025             :  */
    1026             : 
    1027           1 : void CPLQuadTreeForeach(const CPLQuadTree *hQuadTree,
    1028             :                         CPLQuadTreeForeachFunc pfnForeach, void *pUserData)
    1029             : {
    1030           1 :     CPLAssert(hQuadTree);
    1031           1 :     CPLAssert(pfnForeach);
    1032           1 :     CPLQuadTreeNodeForeach(hQuadTree->psRoot, pfnForeach, pUserData);
    1033           1 : }
    1034             : 
    1035             : /************************************************************************/
    1036             : /*                       CPLQuadTreeDumpNode()                          */
    1037             : /************************************************************************/
    1038             : 
    1039           0 : static void CPLQuadTreeDumpNode(const QuadTreeNode *psNode, int nIndentLevel,
    1040             :                                 CPLQuadTreeDumpFeatureFunc pfnDumpFeatureFunc,
    1041             :                                 void *pUserData)
    1042             : {
    1043           0 :     if (psNode->nNumSubNodes)
    1044             :     {
    1045           0 :         for (int count = nIndentLevel; --count >= 0;)
    1046             :         {
    1047           0 :             printf("  "); /*ok*/
    1048             :         }
    1049           0 :         printf("SubhQuadTrees :\n"); /*ok*/
    1050           0 :         for (int i = 0; i < psNode->nNumSubNodes; i++)
    1051             :         {
    1052           0 :             for (int count = nIndentLevel + 1; --count >= 0;)
    1053             :             {
    1054           0 :                 printf("  "); /*ok*/
    1055             :             }
    1056           0 :             printf("SubhQuadTree %d :\n", i + 1); /*ok*/
    1057           0 :             CPLQuadTreeDumpNode(psNode->apSubNode[i], nIndentLevel + 2,
    1058             :                                 pfnDumpFeatureFunc, pUserData);
    1059             :         }
    1060             :     }
    1061           0 :     if (psNode->nFeatures)
    1062             :     {
    1063           0 :         for (int count = nIndentLevel; --count >= 0;)
    1064           0 :             printf("  ");                            /*ok*/
    1065           0 :         printf("Leaves (%d):\n", psNode->nFeatures); /*ok*/
    1066           0 :         for (int i = 0; i < psNode->nFeatures; i++)
    1067             :         {
    1068           0 :             if (pfnDumpFeatureFunc)
    1069             :             {
    1070           0 :                 pfnDumpFeatureFunc(psNode->pahFeatures[i], nIndentLevel + 2,
    1071             :                                    pUserData);
    1072             :             }
    1073             :             else
    1074             :             {
    1075           0 :                 for (int count = nIndentLevel + 1; --count >= 0;)
    1076             :                 {
    1077           0 :                     printf("  "); /*ok*/
    1078             :                 }
    1079           0 :                 printf("%p\n", psNode->pahFeatures[i]); /*ok*/
    1080             :             }
    1081             :         }
    1082             :     }
    1083           0 : }
    1084             : 
    1085             : /************************************************************************/
    1086             : /*                         CPLQuadTreeDump()                            */
    1087             : /************************************************************************/
    1088             : 
    1089             : /** Dump quad tree */
    1090           0 : void CPLQuadTreeDump(const CPLQuadTree *hQuadTree,
    1091             :                      CPLQuadTreeDumpFeatureFunc pfnDumpFeatureFunc,
    1092             :                      void *pUserData)
    1093             : {
    1094           0 :     CPLQuadTreeDumpNode(hQuadTree->psRoot, 0, pfnDumpFeatureFunc, pUserData);
    1095           0 : }
    1096             : 
    1097             : /************************************************************************/
    1098             : /*                  CPLQuadTreeGetStatsNode()                           */
    1099             : /************************************************************************/
    1100             : 
    1101           0 : static void CPLQuadTreeGetStatsNode(const QuadTreeNode *psNode, int nDepthLevel,
    1102             :                                     int *pnNodeCount, int *pnMaxDepth,
    1103             :                                     int *pnMaxBucketCapacity)
    1104             : {
    1105           0 :     (*pnNodeCount)++;
    1106           0 :     if (nDepthLevel > *pnMaxDepth)
    1107           0 :         *pnMaxDepth = nDepthLevel;
    1108           0 :     if (psNode->nFeatures > *pnMaxBucketCapacity)
    1109           0 :         *pnMaxBucketCapacity = psNode->nFeatures;
    1110             : 
    1111           0 :     for (int i = 0; i < psNode->nNumSubNodes; i++)
    1112             :     {
    1113           0 :         CPLQuadTreeGetStatsNode(psNode->apSubNode[i], nDepthLevel + 1,
    1114             :                                 pnNodeCount, pnMaxDepth, pnMaxBucketCapacity);
    1115             :     }
    1116           0 : }
    1117             : 
    1118             : /************************************************************************/
    1119             : /*                    CPLQuadTreeGetStats()                             */
    1120             : /************************************************************************/
    1121             : 
    1122             : /** Get stats */
    1123           0 : void CPLQuadTreeGetStats(const CPLQuadTree *hQuadTree, int *pnFeatureCount,
    1124             :                          int *pnNodeCount, int *pnMaxDepth,
    1125             :                          int *pnMaxBucketCapacity)
    1126             : {
    1127           0 :     CPLAssert(hQuadTree);
    1128             : 
    1129           0 :     int nFeatureCount = 0;
    1130           0 :     if (pnFeatureCount == nullptr)
    1131           0 :         pnFeatureCount = &nFeatureCount;
    1132           0 :     int nNodeCount = 0;
    1133           0 :     if (pnNodeCount == nullptr)
    1134           0 :         pnNodeCount = &nNodeCount;
    1135           0 :     int nMaxDepth = 0;
    1136           0 :     if (pnMaxDepth == nullptr)
    1137           0 :         pnMaxDepth = &nMaxDepth;
    1138           0 :     int nMaxBucketCapacity = 0;
    1139           0 :     if (pnMaxBucketCapacity == nullptr)
    1140           0 :         pnMaxBucketCapacity = &nMaxBucketCapacity;
    1141             : 
    1142           0 :     *pnFeatureCount = hQuadTree->nFeatures;
    1143           0 :     *pnNodeCount = 0;
    1144           0 :     *pnMaxDepth = 1;
    1145           0 :     *pnMaxBucketCapacity = 0;
    1146             : 
    1147           0 :     CPLQuadTreeGetStatsNode(hQuadTree->psRoot, 0, pnNodeCount, pnMaxDepth,
    1148             :                             pnMaxBucketCapacity);
    1149             : 
    1150             :     // TODO(schwehr): If any of the pointers were set to local vars,
    1151             :     // do they need to be reset to a nullptr?
    1152           0 : }

Generated by: LCOV version 1.14