root/trunk/gdal/ogr/ogrsf_frmts/shape/shptree.c

Revision 15720, 38.6 kB (checked in by warmerdam, 1 week ago)

upgraded from shapelib (#2610)

  • Property svn:eol-style set to native
Line 
1 /******************************************************************************
2  * $Id: shptree.c,v 1.12 2008/11/12 15:39:50 fwarmerdam Exp $
3  *
4  * Project:  Shapelib
5  * Purpose:  Implementation of quadtree building and searching functions.
6  * Author:   Frank Warmerdam, warmerdam@pobox.com
7  *
8  ******************************************************************************
9  * Copyright (c) 1999, Frank Warmerdam
10  *
11  * This software is available under the following "MIT Style" license,
12  * or at the option of the licensee under the LGPL (see LICENSE.LGPL).  This
13  * option is discussed in more detail in shapelib.html.
14  *
15  * --
16  *
17  * Permission is hereby granted, free of charge, to any person obtaining a
18  * copy of this software and associated documentation files (the "Software"),
19  * to deal in the Software without restriction, including without limitation
20  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21  * and/or sell copies of the Software, and to permit persons to whom the
22  * Software is furnished to do so, subject to the following conditions:
23  *
24  * The above copyright notice and this permission notice shall be included
25  * in all copies or substantial portions of the Software.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33  * DEALINGS IN THE SOFTWARE.
34  ******************************************************************************
35  *
36  * $Log: shptree.c,v $
37  * Revision 1.12  2008/11/12 15:39:50  fwarmerdam
38  * improve safety in face of buggy .shp file.
39  *
40  * Revision 1.11  2007/10/27 03:31:14  fwarmerdam
41  * limit default depth of tree to 12 levels (gdal ticket #1594)
42  *
43  * Revision 1.10  2005/01/03 22:30:13  fwarmerdam
44  * added support for saved quadtrees
45  *
46  * Revision 1.9  2003/01/28 15:53:41  warmerda
47  * Avoid build warnings.
48  *
49  * Revision 1.8  2002/05/07 13:07:45  warmerda
50  * use qsort() - patch from Bernhard Herzog
51  *
52  * Revision 1.7  2002/01/15 14:36:07  warmerda
53  * updated email address
54  *
55  * Revision 1.6  2001/05/23 13:36:52  warmerda
56  * added use of SHPAPI_CALL
57  *
58  * Revision 1.5  1999/11/05 14:12:05  warmerda
59  * updated license terms
60  *
61  * Revision 1.4  1999/06/02 18:24:21  warmerda
62  * added trimming code
63  *
64  * Revision 1.3  1999/06/02 17:56:12  warmerda
65  * added quad'' subnode support for trees
66  *
67  * Revision 1.2  1999/05/18 19:11:11  warmerda
68  * Added example searching capability
69  *
70  * Revision 1.1  1999/05/18 17:49:20  warmerda
71  * New
72  *
73  */
74
75 #include "shapefil.h"
76
77 #include <math.h>
78 #include <assert.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #ifdef USE_CPL
82 #include <cpl_error.h>
83 #endif
84
85 SHP_CVSID("$Id: shptree.c,v 1.12 2008/11/12 15:39:50 fwarmerdam Exp $")
86
87 #ifndef TRUE
88 define TRUE 1
89 define FALSE 0
90 #endif
91
92 static int bBigEndian = 0;
93
94
95 /* -------------------------------------------------------------------- */
96 /*      If the following is 0.5, nodes will be split in half.  If it    */
97 /*      is 0.6 then each subnode will contain 60% of the parent         */
98 /*      node, with 20% representing overlap.  This can be help to       */
99 /*      prevent small objects on a boundary from shifting too high      */
100 /*      up the tree.                                                    */
101 /* -------------------------------------------------------------------- */
102
103 #define SHP_SPLIT_RATIO 0.55
104
105 /************************************************************************/
106 /*                             SfRealloc()                              */
107 /*                                                                      */
108 /*      A realloc cover function that will access a NULL pointer as     */
109 /*      a valid input.                                                  */
110 /************************************************************************/
111
112 static void * SfRealloc( void * pMem, int nNewSize )
113
114 {
115     if( pMem == NULL )
116         return( (void *) malloc(nNewSize) );
117     else
118         return( (void *) realloc(pMem,nNewSize) );
119 }
120
121 /************************************************************************/
122 /*                          SHPTreeNodeInit()                           */
123 /*                                                                      */
124 /*      Initialize a tree node.                                         */
125 /************************************************************************/
126
127 static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin,
128                                        double * padfBoundsMax )
129
130 {
131     SHPTreeNode *psTreeNode;
132
133     psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode));
134         if( NULL == psTreeNode )
135         {
136 #ifdef USE_CPL
137                 CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
138 #endif
139                 return NULL;
140         }
141
142     psTreeNode->nShapeCount = 0;
143     psTreeNode->panShapeIds = NULL;
144     psTreeNode->papsShapeObj = NULL;
145
146     psTreeNode->nSubNodes = 0;
147
148     if( padfBoundsMin != NULL )
149         memcpy( psTreeNode->adfBoundsMin, padfBoundsMin, sizeof(double) * 4 );
150
151     if( padfBoundsMax != NULL )
152         memcpy( psTreeNode->adfBoundsMax, padfBoundsMax, sizeof(double) * 4 );
153
154     return psTreeNode;
155 }
156
157
158 /************************************************************************/
159 /*                           SHPCreateTree()                            */
160 /************************************************************************/
161
162 SHPTree SHPAPI_CALL1(*)
163 SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
164                double *padfBoundsMin, double *padfBoundsMax )
165
166 {
167     SHPTree     *psTree;
168
169     if( padfBoundsMin == NULL && hSHP == NULL )
170         return NULL;
171
172 /* -------------------------------------------------------------------- */
173 /*      Allocate the tree object                                        */
174 /* -------------------------------------------------------------------- */
175     psTree = (SHPTree *) malloc(sizeof(SHPTree));
176         if( NULL == psTree )
177         {
178 #ifdef USE_CPL
179                 CPLError( CE_Fatal, CPLE_OutOfMemory, "Memory allocation failure");
180 #endif
181                 return NULL;
182         }
183
184     psTree->hSHP = hSHP;
185     psTree->nMaxDepth = nMaxDepth;
186     psTree->nDimension = nDimension;
187     psTree->nTotalCount = 0;
188
189 /* -------------------------------------------------------------------- */
190 /*      If no max depth was defined, try to select a reasonable one     */
191 /*      that implies approximately 8 shapes per node.                   */
192 /* -------------------------------------------------------------------- */
193     if( psTree->nMaxDepth == 0 && hSHP != NULL )
194     {
195         int     nMaxNodeCount = 1;
196         int     nShapeCount;
197
198         SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
199         while( nMaxNodeCount*4 < nShapeCount )
200         {
201             psTree->nMaxDepth += 1;
202             nMaxNodeCount = nMaxNodeCount * 2;
203         }
204
205 #ifdef USE_CPL
206         CPLDebug( "Shape",
207                   "Estimated spatial index tree depth: %d",
208                   psTree->nMaxDepth );
209 #endif
210
211         /* NOTE: Due to problems with memory allocation for deep trees,
212          * automatically estimated depth is limited up to 12 levels.
213          * See Ticket #1594 for detailed discussion.
214          */
215         if( psTree->nMaxDepth > MAX_DEFAULT_TREE_DEPTH )
216         {
217             psTree->nMaxDepth = MAX_DEFAULT_TREE_DEPTH;
218
219 #ifdef USE_CPL
220         CPLDebug( "Shape",
221                   "Falling back to max number of allowed index tree levels (%d).",
222                   MAX_DEFAULT_TREE_DEPTH );
223 #endif
224         }
225     }
226
227 /* -------------------------------------------------------------------- */
228 /*      Allocate the root node.                                         */
229 /* -------------------------------------------------------------------- */
230     psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax );
231         if( NULL == psTree->psRoot )
232         {
233                 return NULL;
234         }
235
236 /* -------------------------------------------------------------------- */
237 /*      Assign the bounds to the root node.  If none are passed in,     */
238 /*      use the bounds of the provided file otherwise the create        */
239 /*      function will have already set the bounds.                      */
240 /* -------------------------------------------------------------------- */
241         assert( NULL != psTree );
242         assert( NULL != psTree->psRoot );
243        
244         if( padfBoundsMin == NULL )
245     {
246         SHPGetInfo( hSHP, NULL, NULL,
247                     psTree->psRoot->adfBoundsMin,
248                     psTree->psRoot->adfBoundsMax );
249     }
250
251 /* -------------------------------------------------------------------- */
252 /*      If we have a file, insert all it's shapes into the tree.        */
253 /* -------------------------------------------------------------------- */
254     if( hSHP != NULL )
255     {
256         int     iShape, nShapeCount;
257        
258         SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
259
260         for( iShape = 0; iShape < nShapeCount; iShape++ )
261         {
262             SHPObject   *psShape;
263            
264             psShape = SHPReadObject( hSHP, iShape );
265             if( psShape != NULL )
266             {
267                 SHPTreeAddShapeId( psTree, psShape );
268                 SHPDestroyObject( psShape );
269             }
270         }
271     }       
272
273     return psTree;
274 }
275
276 /************************************************************************/
277 /*                         SHPDestroyTreeNode()                         */
278 /************************************************************************/
279
280 static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode )
281
282 {
283     int         i;
284    
285         assert( NULL != psTreeNode );
286
287     for( i = 0; i < psTreeNode->nSubNodes; i++ )
288     {
289         if( psTreeNode->apsSubNode[i] != NULL )
290             SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
291     }
292    
293     if( psTreeNode->panShapeIds != NULL )
294         free( psTreeNode->panShapeIds );
295
296     if( psTreeNode->papsShapeObj != NULL )
297     {
298         for( i = 0; i < psTreeNode->nShapeCount; i++ )
299         {
300             if( psTreeNode->papsShapeObj[i] != NULL )
301                 SHPDestroyObject( psTreeNode->papsShapeObj[i] );
302         }
303
304         free( psTreeNode->papsShapeObj );
305     }
306
307     free( psTreeNode );
308 }
309
310 /************************************************************************/
311 /*                           SHPDestroyTree()                           */
312 /************************************************************************/
313
314 void SHPAPI_CALL
315 SHPDestroyTree( SHPTree * psTree )
316
317 {
318     SHPDestroyTreeNode( psTree->psRoot );
319     free( psTree );
320 }
321
322 /************************************************************************/
323 /*                       SHPCheckBoundsOverlap()                        */
324 /*                                                                      */
325 /*      Do the given boxes overlap at all?                              */
326 /************************************************************************/
327
328 int SHPAPI_CALL
329 SHPCheckBoundsOverlap( double * padfBox1Min, double * padfBox1Max,
330                        double * padfBox2Min, double * padfBox2Max,
331                        int nDimension )
332
333 {
334     int         iDim;
335
336     for( iDim = 0; iDim < nDimension; iDim++ )
337     {
338         if( padfBox2Max[iDim] < padfBox1Min[iDim] )
339             return FALSE;
340        
341         if( padfBox1Max[iDim] < padfBox2Min[iDim] )
342             return FALSE;
343     }
344
345     return TRUE;
346 }
347
348 /************************************************************************/
349 /*                      SHPCheckObjectContained()                       */
350 /*                                                                      */
351 /*      Does the given shape fit within the indicated extents?          */
352 /************************************************************************/
353
354 static int SHPCheckObjectContained( SHPObject * psObject, int nDimension,
355                            double * padfBoundsMin, double * padfBoundsMax )
356
357 {
358     if( psObject->dfXMin < padfBoundsMin[0]
359         || psObject->dfXMax > padfBoundsMax[0] )
360         return FALSE;
361    
362     if( psObject->dfYMin < padfBoundsMin[1]
363         || psObject->dfYMax > padfBoundsMax[1] )
364         return FALSE;
365
366     if( nDimension == 2 )
367         return TRUE;
368    
369     if( psObject->dfZMin < padfBoundsMin[2]
370         || psObject->dfZMax < padfBoundsMax[2] )
371         return FALSE;
372        
373     if( nDimension == 3 )
374         return TRUE;
375
376     if( psObject->dfMMin < padfBoundsMin[3]
377         || psObject->dfMMax < padfBoundsMax[3] )
378         return FALSE;
379
380     return TRUE;
381 }
382
383 /************************************************************************/
384 /*                         SHPTreeSplitBounds()                         */
385 /*                                                                      */
386 /*      Split a region into two subregion evenly, cutting along the     */
387 /*      longest dimension.                                              */
388 /************************************************************************/
389
390 void SHPAPI_CALL
391 SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn,
392                     double *padfBoundsMin1, double * padfBoundsMax1,
393                     double *padfBoundsMin2, double * padfBoundsMax2 )
394
395 {
396 /* -------------------------------------------------------------------- */
397 /*      The output bounds will be very similar to the input bounds,     */
398 /*      so just copy over to start.                                     */
399 /* -------------------------------------------------------------------- */
400     memcpy( padfBoundsMin1, padfBoundsMinIn, sizeof(double) * 4 );
401     memcpy( padfBoundsMax1, padfBoundsMaxIn, sizeof(double) * 4 );
402     memcpy( padfBoundsMin2, padfBoundsMinIn, sizeof(double) * 4 );
403     memcpy( padfBoundsMax2, padfBoundsMaxIn, sizeof(double) * 4 );
404    
405 /* -------------------------------------------------------------------- */
406 /*      Split in X direction.                                           */
407 /* -------------------------------------------------------------------- */
408     if( (padfBoundsMaxIn[0] - padfBoundsMinIn[0])
409                                 > (padfBoundsMaxIn[1] - padfBoundsMinIn[1]) )
410     {
411         double  dfRange = padfBoundsMaxIn[0] - padfBoundsMinIn[0];
412
413         padfBoundsMax1[0] = padfBoundsMinIn[0] + dfRange * SHP_SPLIT_RATIO;
414         padfBoundsMin2[0] = padfBoundsMaxIn[0] - dfRange * SHP_SPLIT_RATIO;
415     }
416
417 /* -------------------------------------------------------------------- */
418 /*      Otherwise split in Y direction.                                 */
419 /* -------------------------------------------------------------------- */
420     else
421     {
422         double  dfRange = padfBoundsMaxIn[1] - padfBoundsMinIn[1];
423
424         padfBoundsMax1[1] = padfBoundsMinIn[1] + dfRange * SHP_SPLIT_RATIO;
425         padfBoundsMin2[1] = padfBoundsMaxIn[1] - dfRange * SHP_SPLIT_RATIO;
426     }
427 }
428
429 /************************************************************************/
430 /*                       SHPTreeNodeAddShapeId()                        */
431 /************************************************************************/
432
433 static int
434 SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject,
435                        int nMaxDepth, int nDimension )
436
437 {
438     int         i;
439    
440 /* -------------------------------------------------------------------- */
441 /*      If there are subnodes, then consider wiether this object        */
442 /*      will fit in them.                                               */
443 /* -------------------------------------------------------------------- */
444     if( nMaxDepth > 1 && psTreeNode->nSubNodes > 0 )
445     {
446         for( i = 0; i < psTreeNode->nSubNodes; i++ )
447         {
448             if( SHPCheckObjectContained(psObject, nDimension,
449                                       psTreeNode->apsSubNode[i]->adfBoundsMin,
450                                       psTreeNode->apsSubNode[i]->adfBoundsMax))
451             {
452                 return SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[i],
453                                               psObject, nMaxDepth-1,
454                                               nDimension );
455             }
456         }
457     }
458
459 /* -------------------------------------------------------------------- */
460 /*      Otherwise, consider creating four subnodes if could fit into    */
461 /*      them, and adding to the appropriate subnode.                    */
462 /* -------------------------------------------------------------------- */
463 #if MAX_SUBNODE == 4
464     else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
465     {
466         double  adfBoundsMinH1[4], adfBoundsMaxH1[4];
467         double  adfBoundsMinH2[4], adfBoundsMaxH2[4];
468         double  adfBoundsMin1[4], adfBoundsMax1[4];
469         double  adfBoundsMin2[4], adfBoundsMax2[4];
470         double  adfBoundsMin3[4], adfBoundsMax3[4];
471         double  adfBoundsMin4[4], adfBoundsMax4[4];
472
473         SHPTreeSplitBounds( psTreeNode->adfBoundsMin,
474                             psTreeNode->adfBoundsMax,
475                             adfBoundsMinH1, adfBoundsMaxH1,
476                             adfBoundsMinH2, adfBoundsMaxH2 );
477
478         SHPTreeSplitBounds( adfBoundsMinH1, adfBoundsMaxH1,
479                             adfBoundsMin1, adfBoundsMax1,
480                             adfBoundsMin2, adfBoundsMax2 );
481
482         SHPTreeSplitBounds( adfBoundsMinH2, adfBoundsMaxH2,
483                             adfBoundsMin3, adfBoundsMax3,
484                             adfBoundsMin4, adfBoundsMax4 );
485
486         if( SHPCheckObjectContained(psObject, nDimension,
487                                     adfBoundsMin1, adfBoundsMax1)
488             || SHPCheckObjectContained(psObject, nDimension,
489                                     adfBoundsMin2, adfBoundsMax2)
490             || SHPCheckObjectContained(psObject, nDimension,
491                                     adfBoundsMin3, adfBoundsMax3)
492             || SHPCheckObjectContained(psObject, nDimension,
493                                     adfBoundsMin4, adfBoundsMax4) )
494         {
495             psTreeNode->nSubNodes = 4;
496             psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
497                                                            adfBoundsMax1 );
498             psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
499                                                            adfBoundsMax2 );
500             psTreeNode->apsSubNode[2] = SHPTreeNodeCreate( adfBoundsMin3,
501                                                            adfBoundsMax3 );
502             psTreeNode->apsSubNode[3] = SHPTreeNodeCreate( adfBoundsMin4,
503                                                            adfBoundsMax4 );
504
505             /* recurse back on this node now that it has subnodes */
506             return( SHPTreeNodeAddShapeId( psTreeNode, psObject,
507                                            nMaxDepth, nDimension ) );
508         }
509     }
510 #endif /* MAX_SUBNODE == 4 */
511
512 /* -------------------------------------------------------------------- */
513 /*      Otherwise, consider creating two subnodes if could fit into     */
514 /*      them, and adding to the appropriate subnode.                    */
515 /* -------------------------------------------------------------------- */
516 #if MAX_SUBNODE == 2
517     else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
518     {
519         double  adfBoundsMin1[4], adfBoundsMax1[4];
520         double  adfBoundsMin2[4], adfBoundsMax2[4];
521
522         SHPTreeSplitBounds( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax,
523                             adfBoundsMin1, adfBoundsMax1,
524                             adfBoundsMin2, adfBoundsMax2 );
525
526         if( SHPCheckObjectContained(psObject, nDimension,
527                                  adfBoundsMin1, adfBoundsMax1))
528         {
529             psTreeNode->nSubNodes = 2;
530             psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
531                                                            adfBoundsMax1 );
532             psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
533                                                            adfBoundsMax2 );
534
535             return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[0], psObject,
536                                            nMaxDepth - 1, nDimension ) );
537         }
538         else if( SHPCheckObjectContained(psObject, nDimension,
539                                          adfBoundsMin2, adfBoundsMax2) )
540         {
541             psTreeNode->nSubNodes = 2;
542             psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
543                                                            adfBoundsMax1 );
544             psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
545                                                            adfBoundsMax2 );
546
547             return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[1], psObject,
548                                            nMaxDepth - 1, nDimension ) );
549         }
550     }
551 #endif /* MAX_SUBNODE == 2 */
552
553 /* -------------------------------------------------------------------- */
554 /*      If none of that worked, just add it to this nodes list.         */
555 /* -------------------------------------------------------------------- */
556     psTreeNode->nShapeCount++;
557
558     psTreeNode->panShapeIds = (int *)
559         SfRealloc( psTreeNode->panShapeIds,
560                    sizeof(int) * psTreeNode->nShapeCount );
561     psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId;
562
563     if( psTreeNode->papsShapeObj != NULL )
564     {
565         psTreeNode->papsShapeObj = (SHPObject **)
566             SfRealloc( psTreeNode->papsShapeObj,
567                        sizeof(void *) * psTreeNode->nShapeCount );
568         psTreeNode->papsShapeObj[psTreeNode->nShapeCount-1] = NULL;
569     }
570
571     return TRUE;
572 }
573
574 /************************************************************************/
575 /*                         SHPTreeAddShapeId()                          */
576 /*                                                                      */
577 /*      Add a shape to the tree, but don't keep a pointer to the        */
578 /*      object data, just keep the shapeid.                             */
579 /************************************************************************/
580
581 int SHPAPI_CALL
582 SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject )
583
584 {
585     psTree->nTotalCount++;
586
587     return( SHPTreeNodeAddShapeId( psTree->psRoot, psObject,
588                                    psTree->nMaxDepth, psTree->nDimension ) );
589 }
590
591 /************************************************************************/
592 /*                      SHPTreeCollectShapesIds()                       */
593 /*                                                                      */
594 /*      Work function implementing SHPTreeFindLikelyShapes() on a       */
595 /*      tree node by tree node basis.                                   */
596 /************************************************************************/
597
598 void SHPAPI_CALL
599 SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode,
600                         double * padfBoundsMin, double * padfBoundsMax,
601                         int * pnShapeCount, int * pnMaxShapes,
602                         int ** ppanShapeList )
603
604 {
605     int         i;
606    
607 /* -------------------------------------------------------------------- */
608 /*      Does this node overlap the area of interest at all?  If not,    */
609 /*      return without adding to the list at all.                       */
610 /* -------------------------------------------------------------------- */
611     if( !SHPCheckBoundsOverlap( psTreeNode->adfBoundsMin,
612                                 psTreeNode->adfBoundsMax,
613                                 padfBoundsMin,
614                                 padfBoundsMax,
615                                 hTree->nDimension ) )
616         return;
617
618 /* -------------------------------------------------------------------- */
619 /*      Grow the list to hold the shapes on this node.                  */
620 /* -------------------------------------------------------------------- */
621     if( *pnShapeCount + psTreeNode->nShapeCount > *pnMaxShapes )
622     {
623         *pnMaxShapes = (*pnShapeCount + psTreeNode->nShapeCount) * 2 + 20;
624         *ppanShapeList = (int *)
625             SfRealloc(*ppanShapeList,sizeof(int) * *pnMaxShapes);
626     }
627
628 /* -------------------------------------------------------------------- */
629 /*      Add the local nodes shapeids to the list.                       */
630 /* -------------------------------------------------------------------- */
631     for( i = 0; i < psTreeNode->nShapeCount; i++ )
632     {
633         (*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i];
634     }
635    
636 /* -------------------------------------------------------------------- */
637 /*      Recurse to subnodes if they exist.                              */
638 /* -------------------------------------------------------------------- */
639     for( i = 0; i < psTreeNode->nSubNodes; i++ )
640     {
641         if( psTreeNode->apsSubNode[i] != NULL )
642             SHPTreeCollectShapeIds( hTree, psTreeNode->apsSubNode[i],
643                                     padfBoundsMin, padfBoundsMax,
644                                     pnShapeCount, pnMaxShapes,
645                                     ppanShapeList );
646     }
647 }
648
649 /************************************************************************/
650 /*                      SHPTreeFindLikelyShapes()                       */
651 /*                                                                      */
652 /*      Find all shapes within tree nodes for which the tree node       */
653 /*      bounding box overlaps the search box.  The return value is      */
654 /*      an array of shapeids terminated by a -1.  The shapeids will     */
655 /*      be in order, as hopefully this will result in faster (more      */
656 /*      sequential) reading from the file.                              */
657 /************************************************************************/
658
659 /* helper for qsort */
660 static int
661 compare_ints( const void * a, const void * b)
662 {
663     return (*(int*)a) - (*(int*)b);
664 }
665
666 int SHPAPI_CALL1(*)
667 SHPTreeFindLikelyShapes( SHPTree * hTree,
668                          double * padfBoundsMin, double * padfBoundsMax,
669                          int * pnShapeCount )
670
671 {
672     int *panShapeList=NULL, nMaxShapes = 0;
673
674 /* -------------------------------------------------------------------- */
675 /*      Perform the search by recursive descent.                        */
676 /* -------------------------------------------------------------------- */
677     *pnShapeCount = 0;
678
679     SHPTreeCollectShapeIds( hTree, hTree->psRoot,
680                             padfBoundsMin, padfBoundsMax,
681                             pnShapeCount, &nMaxShapes,
682                             &panShapeList );
683
684 /* -------------------------------------------------------------------- */
685 /*      Sort the id array                                               */
686 /* -------------------------------------------------------------------- */
687
688     qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints);
689
690     return panShapeList;
691 }
692
693 /************************************************************************/
694 /*                          SHPTreeNodeTrim()                           */
695 /*                                                                      */
696 /*      This is the recurve version of SHPTreeTrimExtraNodes() that     */
697 /*      walks the tree cleaning it up.                                  */
698 /************************************************************************/
699
700 static int SHPTreeNodeTrim( SHPTreeNode * psTreeNode )
701
702 {
703     int         i;
704
705 /* -------------------------------------------------------------------- */
706 /*      Trim subtrees, and free subnodes that come back empty.          */
707 /* -------------------------------------------------------------------- */
708     for( i = 0; i < psTreeNode->nSubNodes; i++ )
709     {
710         if( SHPTreeNodeTrim( psTreeNode->apsSubNode[i] ) )
711         {
712             SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
713
714             psTreeNode->apsSubNode[i] =
715                 psTreeNode->apsSubNode[psTreeNode->nSubNodes-1];
716
717             psTreeNode->nSubNodes--;
718
719             i--; /* process the new occupant of this subnode entry */
720         }
721     }
722
723 /* -------------------------------------------------------------------- */
724 /*      We should be trimmed if we have no subnodes, and no shapes.     */
725 /* -------------------------------------------------------------------- */
726     return( psTreeNode->nSubNodes == 0 && psTreeNode->nShapeCount == 0 );
727 }
728
729 /************************************************************************/
730 /*                       SHPTreeTrimExtraNodes()                        */
731 /*                                                                      */
732 /*      Trim empty nodes from the tree.  Note that we never trim an     */
733 /*      empty root node.                                                */
734 /************************************************************************/
735
736 void SHPAPI_CALL
737 SHPTreeTrimExtraNodes( SHPTree * hTree )
738
739 {
740     SHPTreeNodeTrim( hTree->psRoot );
741 }
742
743 /************************************************************************/
744 /*                              SwapWord()                              */
745 /*                                                                      */
746 /*      Swap a 2, 4 or 8 byte word.                                     */
747 /************************************************************************/
748
749 static void SwapWord( int length, void * wordP )
750
751 {
752     int         i;
753     unsigned char       temp;
754
755     for( i=0; i < length/2; i++ )
756     {
757         temp = ((unsigned char *) wordP)[i];
758         ((unsigned char *)wordP)[i] = ((unsigned char *) wordP)[length-i-1];
759         ((unsigned char *) wordP)[length-i-1] = temp;
760     }
761 }
762
763 /************************************************************************/
764 /*                       SHPSearchDiskTreeNode()                        */
765 /************************************************************************/
766
767 static int
768 SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax,
769                        int **ppanResultBuffer, int *pnBufferMax,
770                        int *pnResultCount, int bNeedSwap )
771
772 {
773     int i;
774     int offset;
775     int numshapes, numsubnodes;
776     double adfNodeBoundsMin[2], adfNodeBoundsMax[2];
777
778 /* -------------------------------------------------------------------- */
779 /*      Read and unswap first part of node info.                        */
780 /* -------------------------------------------------------------------- */
781     fread( &offset, 4, 1, fp );
782     if ( bNeedSwap ) SwapWord ( 4, &offset );
783
784     fread( adfNodeBoundsMin, sizeof(double), 2, fp );
785     fread( adfNodeBoundsMax, sizeof(double), 2, fp );
786     if ( bNeedSwap )
787     {
788         SwapWord( 8, adfNodeBoundsMin + 0 );
789         SwapWord( 8, adfNodeBoundsMin + 1 );
790         SwapWord( 8, adfNodeBoundsMax + 0 );
791         SwapWord( 8, adfNodeBoundsMax + 1 );
792     }
793      
794     fread( &numshapes, 4, 1, fp );
795     if ( bNeedSwap ) SwapWord ( 4, &numshapes );
796
797 /* -------------------------------------------------------------------- */
798 /*      If we don't overlap this node at all, we can just fseek()       */
799 /*      pass this node info and all subnodes.                           */
800 /* -------------------------------------------------------------------- */
801     if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax,
802                                 padfBoundsMin, padfBoundsMax, 2 ) )
803     {
804         offset += numshapes*sizeof(int) + sizeof(int);
805         fseek(fp, offset, SEEK_CUR);
806         return TRUE;
807     }
808
809 /* -------------------------------------------------------------------- */
810 /*      Add all the shapeids at this node to our list.                  */
811 /* -------------------------------------------------------------------- */
812     if(numshapes > 0)
813     {
814         if( *pnResultCount + numshapes > *pnBufferMax )
815         {
816             *pnBufferMax = (int) ((*pnResultCount + numshapes + 100) * 1.25);
817             *ppanResultBuffer = (int *)
818                 SfRealloc( *ppanResultBuffer, *pnBufferMax * sizeof(int) );
819         }
820
821         fread( *ppanResultBuffer + *pnResultCount,
822                sizeof(int), numshapes, fp );
823
824         if (bNeedSwap )
825         {
826             for( i=0; i<numshapes; i++ )
827                 SwapWord( 4, *ppanResultBuffer + *pnResultCount + i );
828         }
829
830         *pnResultCount += numshapes;
831     }
832
833 /* -------------------------------------------------------------------- */
834 /*      Process the subnodes.                                           */
835 /* -------------------------------------------------------------------- */
836     fread( &numsubnodes, 4, 1, fp );
837     if ( bNeedSwap  ) SwapWord ( 4, &numsubnodes );
838
839     for(i=0; i<numsubnodes; i++)
840   &n