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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26