/[thuban]/branches/WIP-pyshapelib-bramz/libraries/shapelib/shptree.c
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/libraries/shapelib/shptree.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1612 - (hide annotations)
Tue Aug 19 21:29:25 2003 UTC (21 years, 6 months ago) by jan
Original Path: trunk/thuban/libraries/shapelib/shptree.c
File MIME type: text/plain
File size: 27614 byte(s)
These files have been moved here from thuban/extensions/shapelib/
See there in the Attic for the older history.

1 jan 1612 /******************************************************************************
2     * $Id$
3     *
4     * Project: Shapelib
5     * Purpose: Implementation of quadtree building and searching functions.
6     * Author: Frank Warmerdam, [email protected]
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$
37     * Revision 1.1 2003/08/19 21:29:25 jan
38     * These files have been moved here from thuban/extensions/shapelib/
39     * See there in the Attic for the older history.
40     *
41     * Revision 1.2 2002/05/08 13:48:43 bh
42     * * extensions/shapelib/shptree.c (compare_ints): Make arguments
43     * const void * as in the qsort prototype
44     * (SHPTreeFindLikelyShapes): Remove some unused variables.
45     *
46     * Revision 1.1 2002/05/07 14:09:34 bh
47     * * extensions/shapelib/shptree.c: Modified version of shptree.c of
48     * shapelib 1.2.9. The only real difference is the use of qsort
49     * instead of a bubble sort implementation
50     *
51     * Revision 1.6 2001/05/23 13:36:52 warmerda
52     * added use of SHPAPI_CALL
53     *
54     * Revision 1.5 1999/11/05 14:12:05 warmerda
55     * updated license terms
56     *
57     * Revision 1.4 1999/06/02 18:24:21 warmerda
58     * added trimming code
59     *
60     * Revision 1.3 1999/06/02 17:56:12 warmerda
61     * added quad'' subnode support for trees
62     *
63     * Revision 1.2 1999/05/18 19:11:11 warmerda
64     * Added example searching capability
65     *
66     * Revision 1.1 1999/05/18 17:49:20 warmerda
67     * New
68     *
69     */
70    
71     static char rcsid[] =
72     "$Id$";
73    
74     #include "shapefil.h"
75    
76     #include <math.h>
77     #include <assert.h>
78    
79     #include <stdlib.h>
80    
81     #ifndef TRUE
82     # define TRUE 1
83     # define FALSE 0
84     #endif
85    
86    
87     /* -------------------------------------------------------------------- */
88     /* If the following is 0.5, nodes will be split in half. If it */
89     /* is 0.6 then each subnode will contain 60% of the parent */
90     /* node, with 20% representing overlap. This can be help to */
91     /* prevent small objects on a boundary from shifting too high */
92     /* up the tree. */
93     /* -------------------------------------------------------------------- */
94    
95     #define SHP_SPLIT_RATIO 0.55
96    
97     /************************************************************************/
98     /* SfRealloc() */
99     /* */
100     /* A realloc cover function that will access a NULL pointer as */
101     /* a valid input. */
102     /************************************************************************/
103    
104     static void * SfRealloc( void * pMem, int nNewSize )
105    
106     {
107     if( pMem == NULL )
108     return( (void *) malloc(nNewSize) );
109     else
110     return( (void *) realloc(pMem,nNewSize) );
111     }
112    
113     /************************************************************************/
114     /* SHPTreeNodeInit() */
115     /* */
116     /* Initialize a tree node. */
117     /************************************************************************/
118    
119     static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin,
120     double * padfBoundsMax )
121    
122     {
123     SHPTreeNode *psTreeNode;
124    
125     psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode));
126    
127     psTreeNode->nShapeCount = 0;
128     psTreeNode->panShapeIds = NULL;
129     psTreeNode->papsShapeObj = NULL;
130    
131     psTreeNode->nSubNodes = 0;
132    
133     if( padfBoundsMin != NULL )
134     memcpy( psTreeNode->adfBoundsMin, padfBoundsMin, sizeof(double) * 4 );
135    
136     if( padfBoundsMax != NULL )
137     memcpy( psTreeNode->adfBoundsMax, padfBoundsMax, sizeof(double) * 4 );
138    
139     return psTreeNode;
140     }
141    
142    
143     /************************************************************************/
144     /* SHPCreateTree() */
145     /************************************************************************/
146    
147     SHPTree SHPAPI_CALL1(*)
148     SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
149     double *padfBoundsMin, double *padfBoundsMax )
150    
151     {
152     SHPTree *psTree;
153    
154     if( padfBoundsMin == NULL && hSHP == NULL )
155     return NULL;
156    
157     /* -------------------------------------------------------------------- */
158     /* Allocate the tree object */
159     /* -------------------------------------------------------------------- */
160     psTree = (SHPTree *) malloc(sizeof(SHPTree));
161    
162     psTree->hSHP = hSHP;
163     psTree->nMaxDepth = nMaxDepth;
164     psTree->nDimension = nDimension;
165    
166     /* -------------------------------------------------------------------- */
167     /* If no max depth was defined, try to select a reasonable one */
168     /* that implies approximately 8 shapes per node. */
169     /* -------------------------------------------------------------------- */
170     if( psTree->nMaxDepth == 0 && hSHP != NULL )
171     {
172     int nMaxNodeCount = 1;
173     int nShapeCount;
174    
175     SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
176     while( nMaxNodeCount*4 < nShapeCount )
177     {
178     psTree->nMaxDepth += 1;
179     nMaxNodeCount = nMaxNodeCount * 2;
180     }
181     }
182    
183     /* -------------------------------------------------------------------- */
184     /* Allocate the root node. */
185     /* -------------------------------------------------------------------- */
186     psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax );
187    
188     /* -------------------------------------------------------------------- */
189     /* Assign the bounds to the root node. If none are passed in, */
190     /* use the bounds of the provided file otherwise the create */
191     /* function will have already set the bounds. */
192     /* -------------------------------------------------------------------- */
193     if( padfBoundsMin == NULL )
194     {
195     SHPGetInfo( hSHP, NULL, NULL,
196     psTree->psRoot->adfBoundsMin,
197     psTree->psRoot->adfBoundsMax );
198     }
199    
200     /* -------------------------------------------------------------------- */
201     /* If we have a file, insert all it's shapes into the tree. */
202     /* -------------------------------------------------------------------- */
203     if( hSHP != NULL )
204     {
205     int iShape, nShapeCount;
206    
207     SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
208    
209     for( iShape = 0; iShape < nShapeCount; iShape++ )
210     {
211     SHPObject *psShape;
212    
213     psShape = SHPReadObject( hSHP, iShape );
214     SHPTreeAddShapeId( psTree, psShape );
215     SHPDestroyObject( psShape );
216     }
217     }
218    
219     return psTree;
220     }
221    
222     /************************************************************************/
223     /* SHPDestroyTreeNode() */
224     /************************************************************************/
225    
226     static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode )
227    
228     {
229     int i;
230    
231     for( i = 0; i < psTreeNode->nSubNodes; i++ )
232     {
233     if( psTreeNode->apsSubNode[i] != NULL )
234     SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
235     }
236    
237     if( psTreeNode->panShapeIds != NULL )
238     free( psTreeNode->panShapeIds );
239    
240     if( psTreeNode->papsShapeObj != NULL )
241     {
242     for( i = 0; i < psTreeNode->nShapeCount; i++ )
243     {
244     if( psTreeNode->papsShapeObj[i] != NULL )
245     SHPDestroyObject( psTreeNode->papsShapeObj[i] );
246     }
247    
248     free( psTreeNode->papsShapeObj );
249     }
250    
251     free( psTreeNode );
252     }
253    
254     /************************************************************************/
255     /* SHPDestroyTree() */
256     /************************************************************************/
257    
258     void SHPAPI_CALL
259     SHPDestroyTree( SHPTree * psTree )
260    
261     {
262     SHPDestroyTreeNode( psTree->psRoot );
263     free( psTree );
264     }
265    
266     /************************************************************************/
267     /* SHPCheckBoundsOverlap() */
268     /* */
269     /* Do the given boxes overlap at all? */
270     /************************************************************************/
271    
272     int SHPAPI_CALL
273     SHPCheckBoundsOverlap( double * padfBox1Min, double * padfBox1Max,
274     double * padfBox2Min, double * padfBox2Max,
275     int nDimension )
276    
277     {
278     int iDim;
279    
280     for( iDim = 0; iDim < nDimension; iDim++ )
281     {
282     if( padfBox2Max[iDim] < padfBox1Min[iDim] )
283     return FALSE;
284    
285     if( padfBox1Max[iDim] < padfBox2Min[iDim] )
286     return FALSE;
287     }
288    
289     return TRUE;
290     }
291    
292     /************************************************************************/
293     /* SHPCheckObjectContained() */
294     /* */
295     /* Does the given shape fit within the indicated extents? */
296     /************************************************************************/
297    
298     static int SHPCheckObjectContained( SHPObject * psObject, int nDimension,
299     double * padfBoundsMin, double * padfBoundsMax )
300    
301     {
302     if( psObject->dfXMin < padfBoundsMin[0]
303     || psObject->dfXMax > padfBoundsMax[0] )
304     return FALSE;
305    
306     if( psObject->dfYMin < padfBoundsMin[1]
307     || psObject->dfYMax > padfBoundsMax[1] )
308     return FALSE;
309    
310     if( nDimension == 2 )
311     return TRUE;
312    
313     if( psObject->dfZMin < padfBoundsMin[2]
314     || psObject->dfZMax < padfBoundsMax[2] )
315     return FALSE;
316    
317     if( nDimension == 3 )
318     return TRUE;
319    
320     if( psObject->dfMMin < padfBoundsMin[3]
321     || psObject->dfMMax < padfBoundsMax[3] )
322     return FALSE;
323    
324     return TRUE;
325     }
326    
327     /************************************************************************/
328     /* SHPTreeSplitBounds() */
329     /* */
330     /* Split a region into two subregion evenly, cutting along the */
331     /* longest dimension. */
332     /************************************************************************/
333    
334     void SHPAPI_CALL
335     SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn,
336     double *padfBoundsMin1, double * padfBoundsMax1,
337     double *padfBoundsMin2, double * padfBoundsMax2 )
338    
339     {
340     /* -------------------------------------------------------------------- */
341     /* The output bounds will be very similar to the input bounds, */
342     /* so just copy over to start. */
343     /* -------------------------------------------------------------------- */
344     memcpy( padfBoundsMin1, padfBoundsMinIn, sizeof(double) * 4 );
345     memcpy( padfBoundsMax1, padfBoundsMaxIn, sizeof(double) * 4 );
346     memcpy( padfBoundsMin2, padfBoundsMinIn, sizeof(double) * 4 );
347     memcpy( padfBoundsMax2, padfBoundsMaxIn, sizeof(double) * 4 );
348    
349     /* -------------------------------------------------------------------- */
350     /* Split in X direction. */
351     /* -------------------------------------------------------------------- */
352     if( (padfBoundsMaxIn[0] - padfBoundsMinIn[0])
353     > (padfBoundsMaxIn[1] - padfBoundsMinIn[1]) )
354     {
355     double dfRange = padfBoundsMaxIn[0] - padfBoundsMinIn[0];
356    
357     padfBoundsMax1[0] = padfBoundsMinIn[0] + dfRange * SHP_SPLIT_RATIO;
358     padfBoundsMin2[0] = padfBoundsMaxIn[0] - dfRange * SHP_SPLIT_RATIO;
359     }
360    
361     /* -------------------------------------------------------------------- */
362     /* Otherwise split in Y direction. */
363     /* -------------------------------------------------------------------- */
364     else
365     {
366     double dfRange = padfBoundsMaxIn[1] - padfBoundsMinIn[1];
367    
368     padfBoundsMax1[1] = padfBoundsMinIn[1] + dfRange * SHP_SPLIT_RATIO;
369     padfBoundsMin2[1] = padfBoundsMaxIn[1] - dfRange * SHP_SPLIT_RATIO;
370     }
371     }
372    
373     /************************************************************************/
374     /* SHPTreeNodeAddShapeId() */
375     /************************************************************************/
376    
377     static int
378     SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject,
379     int nMaxDepth, int nDimension )
380    
381     {
382     int i;
383    
384     /* -------------------------------------------------------------------- */
385     /* If there are subnodes, then consider wiether this object */
386     /* will fit in them. */
387     /* -------------------------------------------------------------------- */
388     if( nMaxDepth > 1 && psTreeNode->nSubNodes > 0 )
389     {
390     for( i = 0; i < psTreeNode->nSubNodes; i++ )
391     {
392     if( SHPCheckObjectContained(psObject, nDimension,
393     psTreeNode->apsSubNode[i]->adfBoundsMin,
394     psTreeNode->apsSubNode[i]->adfBoundsMax))
395     {
396     return SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[i],
397     psObject, nMaxDepth-1,
398     nDimension );
399     }
400     }
401     }
402    
403     /* -------------------------------------------------------------------- */
404     /* Otherwise, consider creating four subnodes if could fit into */
405     /* them, and adding to the appropriate subnode. */
406     /* -------------------------------------------------------------------- */
407     #if MAX_SUBNODE == 4
408     else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
409     {
410     double adfBoundsMinH1[4], adfBoundsMaxH1[4];
411     double adfBoundsMinH2[4], adfBoundsMaxH2[4];
412     double adfBoundsMin1[4], adfBoundsMax1[4];
413     double adfBoundsMin2[4], adfBoundsMax2[4];
414     double adfBoundsMin3[4], adfBoundsMax3[4];
415     double adfBoundsMin4[4], adfBoundsMax4[4];
416    
417     SHPTreeSplitBounds( psTreeNode->adfBoundsMin,
418     psTreeNode->adfBoundsMax,
419     adfBoundsMinH1, adfBoundsMaxH1,
420     adfBoundsMinH2, adfBoundsMaxH2 );
421    
422     SHPTreeSplitBounds( adfBoundsMinH1, adfBoundsMaxH1,
423     adfBoundsMin1, adfBoundsMax1,
424     adfBoundsMin2, adfBoundsMax2 );
425    
426     SHPTreeSplitBounds( adfBoundsMinH2, adfBoundsMaxH2,
427     adfBoundsMin3, adfBoundsMax3,
428     adfBoundsMin4, adfBoundsMax4 );
429    
430     if( SHPCheckObjectContained(psObject, nDimension,
431     adfBoundsMin1, adfBoundsMax1)
432     || SHPCheckObjectContained(psObject, nDimension,
433     adfBoundsMin2, adfBoundsMax2)
434     || SHPCheckObjectContained(psObject, nDimension,
435     adfBoundsMin3, adfBoundsMax3)
436     || SHPCheckObjectContained(psObject, nDimension,
437     adfBoundsMin4, adfBoundsMax4) )
438     {
439     psTreeNode->nSubNodes = 4;
440     psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
441     adfBoundsMax1 );
442     psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
443     adfBoundsMax2 );
444     psTreeNode->apsSubNode[2] = SHPTreeNodeCreate( adfBoundsMin3,
445     adfBoundsMax3 );
446     psTreeNode->apsSubNode[3] = SHPTreeNodeCreate( adfBoundsMin4,
447     adfBoundsMax4 );
448    
449     /* recurse back on this node now that it has subnodes */
450     return( SHPTreeNodeAddShapeId( psTreeNode, psObject,
451     nMaxDepth, nDimension ) );
452     }
453     }
454     #endif /* MAX_SUBNODE == 4 */
455    
456     /* -------------------------------------------------------------------- */
457     /* Otherwise, consider creating two subnodes if could fit into */
458     /* them, and adding to the appropriate subnode. */
459     /* -------------------------------------------------------------------- */
460     #if MAX_SUBNODE == 2
461     else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
462     {
463     double adfBoundsMin1[4], adfBoundsMax1[4];
464     double adfBoundsMin2[4], adfBoundsMax2[4];
465    
466     SHPTreeSplitBounds( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax,
467     adfBoundsMin1, adfBoundsMax1,
468     adfBoundsMin2, adfBoundsMax2 );
469    
470     if( SHPCheckObjectContained(psObject, nDimension,
471     adfBoundsMin1, adfBoundsMax1))
472     {
473     psTreeNode->nSubNodes = 2;
474     psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
475     adfBoundsMax1 );
476     psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
477     adfBoundsMax2 );
478    
479     return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[0], psObject,
480     nMaxDepth - 1, nDimension ) );
481     }
482     else if( SHPCheckObjectContained(psObject, nDimension,
483     adfBoundsMin2, adfBoundsMax2) )
484     {
485     psTreeNode->nSubNodes = 2;
486     psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
487     adfBoundsMax1 );
488     psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
489     adfBoundsMax2 );
490    
491     return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[1], psObject,
492     nMaxDepth - 1, nDimension ) );
493     }
494     }
495     #endif /* MAX_SUBNODE == 2 */
496    
497     /* -------------------------------------------------------------------- */
498     /* If none of that worked, just add it to this nodes list. */
499     /* -------------------------------------------------------------------- */
500     psTreeNode->nShapeCount++;
501    
502     psTreeNode->panShapeIds =
503     SfRealloc( psTreeNode->panShapeIds,
504     sizeof(int) * psTreeNode->nShapeCount );
505     psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId;
506    
507     if( psTreeNode->papsShapeObj != NULL )
508     {
509     psTreeNode->papsShapeObj =
510     SfRealloc( psTreeNode->papsShapeObj,
511     sizeof(void *) * psTreeNode->nShapeCount );
512     psTreeNode->papsShapeObj[psTreeNode->nShapeCount-1] = NULL;
513     }
514    
515     return TRUE;
516     }
517    
518     /************************************************************************/
519     /* SHPTreeAddShapeId() */
520     /* */
521     /* Add a shape to the tree, but don't keep a pointer to the */
522     /* object data, just keep the shapeid. */
523     /************************************************************************/
524    
525     int SHPAPI_CALL
526     SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject )
527    
528     {
529     return( SHPTreeNodeAddShapeId( psTree->psRoot, psObject,
530     psTree->nMaxDepth, psTree->nDimension ) );
531     }
532    
533     /************************************************************************/
534     /* SHPTreeCollectShapesIds() */
535     /* */
536     /* Work function implementing SHPTreeFindLikelyShapes() on a */
537     /* tree node by tree node basis. */
538     /************************************************************************/
539    
540     void SHPAPI_CALL
541     SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode,
542     double * padfBoundsMin, double * padfBoundsMax,
543     int * pnShapeCount, int * pnMaxShapes,
544     int ** ppanShapeList )
545    
546     {
547     int i;
548    
549     /* -------------------------------------------------------------------- */
550     /* Does this node overlap the area of interest at all? If not, */
551     /* return without adding to the list at all. */
552     /* -------------------------------------------------------------------- */
553     if( !SHPCheckBoundsOverlap( psTreeNode->adfBoundsMin,
554     psTreeNode->adfBoundsMax,
555     padfBoundsMin,
556     padfBoundsMax,
557     hTree->nDimension ) )
558     return;
559    
560     /* -------------------------------------------------------------------- */
561     /* Grow the list to hold the shapes on this node. */
562     /* -------------------------------------------------------------------- */
563     if( *pnShapeCount + psTreeNode->nShapeCount > *pnMaxShapes )
564     {
565     *pnMaxShapes = (*pnShapeCount + psTreeNode->nShapeCount) * 2 + 20;
566     *ppanShapeList = (int *)
567     SfRealloc(*ppanShapeList,sizeof(int) * *pnMaxShapes);
568     }
569    
570     /* -------------------------------------------------------------------- */
571     /* Add the local nodes shapeids to the list. */
572     /* -------------------------------------------------------------------- */
573     for( i = 0; i < psTreeNode->nShapeCount; i++ )
574     {
575     (*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i];
576     }
577    
578     /* -------------------------------------------------------------------- */
579     /* Recurse to subnodes if they exist. */
580     /* -------------------------------------------------------------------- */
581     for( i = 0; i < psTreeNode->nSubNodes; i++ )
582     {
583     if( psTreeNode->apsSubNode[i] != NULL )
584     SHPTreeCollectShapeIds( hTree, psTreeNode->apsSubNode[i],
585     padfBoundsMin, padfBoundsMax,
586     pnShapeCount, pnMaxShapes,
587     ppanShapeList );
588     }
589     }
590    
591     /************************************************************************/
592     /* SHPTreeFindLikelyShapes() */
593     /* */
594     /* Find all shapes within tree nodes for which the tree node */
595     /* bounding box overlaps the search box. The return value is */
596     /* an array of shapeids terminated by a -1. The shapeids will */
597     /* be in order, as hopefully this will result in faster (more */
598     /* sequential) reading from the file. */
599     /************************************************************************/
600    
601     /* helper for qsort */
602     static int
603     compare_ints(const void * a, const void * b)
604     {
605     return (*(int*)a) - (*(int*)b);
606     }
607    
608     int SHPAPI_CALL1(*)
609     SHPTreeFindLikelyShapes( SHPTree * hTree,
610     double * padfBoundsMin, double * padfBoundsMax,
611     int * pnShapeCount )
612    
613     {
614     int *panShapeList=NULL, nMaxShapes = 0;
615    
616     /* -------------------------------------------------------------------- */
617     /* Perform the search by recursive descent. */
618     /* -------------------------------------------------------------------- */
619     *pnShapeCount = 0;
620    
621     SHPTreeCollectShapeIds( hTree, hTree->psRoot,
622     padfBoundsMin, padfBoundsMax,
623     pnShapeCount, &nMaxShapes,
624     &panShapeList );
625    
626     /* -------------------------------------------------------------------- */
627     /* Sort the id array */
628     /* -------------------------------------------------------------------- */
629    
630     qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints);
631    
632     return panShapeList;
633     }
634    
635     /************************************************************************/
636     /* SHPTreeNodeTrim() */
637     /* */
638     /* This is the recurve version of SHPTreeTrimExtraNodes() that */
639     /* walks the tree cleaning it up. */
640     /************************************************************************/
641    
642     static int SHPTreeNodeTrim( SHPTreeNode * psTreeNode )
643    
644     {
645     int i;
646    
647     /* -------------------------------------------------------------------- */
648     /* Trim subtrees, and free subnodes that come back empty. */
649     /* -------------------------------------------------------------------- */
650     for( i = 0; i < psTreeNode->nSubNodes; i++ )
651     {
652     if( SHPTreeNodeTrim( psTreeNode->apsSubNode[i] ) )
653     {
654     SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
655    
656     psTreeNode->apsSubNode[i] =
657     psTreeNode->apsSubNode[psTreeNode->nSubNodes-1];
658    
659     psTreeNode->nSubNodes--;
660    
661     i--; /* process the new occupant of this subnode entry */
662     }
663     }
664    
665     /* -------------------------------------------------------------------- */
666     /* We should be trimmed if we have no subnodes, and no shapes. */
667     /* -------------------------------------------------------------------- */
668     return( psTreeNode->nSubNodes == 0 && psTreeNode->nShapeCount == 0 );
669     }
670    
671     /************************************************************************/
672     /* SHPTreeTrimExtraNodes() */
673     /* */
674     /* Trim empty nodes from the tree. Note that we never trim an */
675     /* empty root node. */
676     /************************************************************************/
677    
678     void SHPAPI_CALL
679     SHPTreeTrimExtraNodes( SHPTree * hTree )
680    
681     {
682     SHPTreeNodeTrim( hTree->psRoot );
683     }
684    

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26