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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1612 - (show 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 /******************************************************************************
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