static void SHPTreeNodeSearchAndDump( SHPTree * hTree, double *padfBoundsMin, double *padfBoundsMax ) { int *panHits, nShapeCount, i; /* -------------------------------------------------------------------- */ /* Perform the search for likely candidates. These are shapes */ /* that fall into a tree node whose bounding box intersects our */ /* area of interest. */ /* -------------------------------------------------------------------- */ panHits = SHPTreeFindLikelyShapes( hTree, padfBoundsMin, padfBoundsMax, &nShapeCount ); /* -------------------------------------------------------------------- */ /* Read all of these shapes, and establish whether the shape's */ /* bounding box actually intersects the area of interest. Note */ /* that the bounding box could intersect the area of interest, */ /* and the shape itself still not cross it but we don't try to */ /* address that here. */ /* -------------------------------------------------------------------- */ for( i = 0; i < nShapeCount; i++ ) { SHPObject *psObject; psObject = SHPReadObject( hTree->hSHP, panHits[i] ); if( psObject == NULL ) continue; if( !SHPCheckBoundsOverlap( padfBoundsMin, padfBoundsMax, &(psObject->dfXMin), &(psObject->dfXMax), hTree->nDimension ) ) { printf( "Shape %d: not in area of interest, but fetched.\n", panHits[i] ); } else { printf( "Shape %d: appears to be in area of interest.\n", panHits[i] ); } SHPDestroyObject( psObject ); } if( nShapeCount == 0 ) printf( "No shapes found in search.\n" ); }
void SHPAPI_CALL SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode, double * padfBoundsMin, double * padfBoundsMax, int * pnShapeCount, int * pnMaxShapes, int ** ppanShapeList ) { int i; /* -------------------------------------------------------------------- */ /* Does this node overlap the area of interest at all? If not, */ /* return without adding to the list at all. */ /* -------------------------------------------------------------------- */ if( !SHPCheckBoundsOverlap( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax, padfBoundsMin, padfBoundsMax, hTree->nDimension ) ) return; /* -------------------------------------------------------------------- */ /* Grow the list to hold the shapes on this node. */ /* -------------------------------------------------------------------- */ if( *pnShapeCount + psTreeNode->nShapeCount > *pnMaxShapes ) { *pnMaxShapes = (*pnShapeCount + psTreeNode->nShapeCount) * 2 + 20; *ppanShapeList = (int *) SfRealloc(*ppanShapeList,sizeof(int) * *pnMaxShapes); } /* -------------------------------------------------------------------- */ /* Add the local nodes shapeids to the list. */ /* -------------------------------------------------------------------- */ for( i = 0; i < psTreeNode->nShapeCount; i++ ) { (*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i]; } /* -------------------------------------------------------------------- */ /* Recurse to subnodes if they exist. */ /* -------------------------------------------------------------------- */ for( i = 0; i < psTreeNode->nSubNodes; i++ ) { if( psTreeNode->apsSubNode[i] != NULL ) SHPTreeCollectShapeIds( hTree, psTreeNode->apsSubNode[i], padfBoundsMin, padfBoundsMax, pnShapeCount, pnMaxShapes, ppanShapeList ); } }
static int SHPSearchDiskTreeNode( FILE *fp, double *padfBoundsMin, double *padfBoundsMax, int **ppanResultBuffer, int *pnBufferMax, int *pnResultCount, int bNeedSwap ) { int i; int offset; int numshapes, numsubnodes; double adfNodeBoundsMin[2], adfNodeBoundsMax[2]; /* -------------------------------------------------------------------- */ /* Read and unswap first part of node info. */ /* -------------------------------------------------------------------- */ fread( &offset, 4, 1, fp ); if ( bNeedSwap ) SwapWord ( 4, &offset ); fread( adfNodeBoundsMin, sizeof(double), 2, fp ); fread( adfNodeBoundsMax, sizeof(double), 2, fp ); if ( bNeedSwap ) { SwapWord( 8, adfNodeBoundsMin + 0 ); SwapWord( 8, adfNodeBoundsMin + 1 ); SwapWord( 8, adfNodeBoundsMax + 0 ); SwapWord( 8, adfNodeBoundsMax + 1 ); } fread( &numshapes, 4, 1, fp ); if ( bNeedSwap ) SwapWord ( 4, &numshapes ); /* -------------------------------------------------------------------- */ /* If we don't overlap this node at all, we can just fseek() */ /* pass this node info and all subnodes. */ /* -------------------------------------------------------------------- */ if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax, padfBoundsMin, padfBoundsMax, 2 ) ) { offset += numshapes*sizeof(int) + sizeof(int); fseek(fp, offset, SEEK_CUR); return TRUE; } /* -------------------------------------------------------------------- */ /* Add all the shapeids at this node to our list. */ /* -------------------------------------------------------------------- */ if(numshapes > 0) { if( *pnResultCount + numshapes > *pnBufferMax ) { *pnBufferMax = (int) ((*pnResultCount + numshapes + 100) * 1.25); *ppanResultBuffer = (int *) SfRealloc( *ppanResultBuffer, *pnBufferMax * sizeof(int) ); } fread( *ppanResultBuffer + *pnResultCount, sizeof(int), numshapes, fp ); if (bNeedSwap ) { for( i=0; i<numshapes; i++ ) SwapWord( 4, *ppanResultBuffer + *pnResultCount + i ); } *pnResultCount += numshapes; } /* -------------------------------------------------------------------- */ /* Process the subnodes. */ /* -------------------------------------------------------------------- */ fread( &numsubnodes, 4, 1, fp ); if ( bNeedSwap ) SwapWord ( 4, &numsubnodes ); for(i=0; i<numsubnodes; i++) { if( !SHPSearchDiskTreeNode( fp, padfBoundsMin, padfBoundsMax, ppanResultBuffer, pnBufferMax, pnResultCount, bNeedSwap ) ) return FALSE; } return TRUE; }
static int SHPSearchDiskTreeNode( SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, double *padfBoundsMax, int **ppanResultBuffer, int *pnBufferMax, int *pnResultCount, int bNeedSwap, int nRecLevel ) { unsigned int i; unsigned int offset; unsigned int numshapes, numsubnodes; double adfNodeBoundsMin[2], adfNodeBoundsMax[2]; int nFReadAcc; /* -------------------------------------------------------------------- */ /* Read and unswap first part of node info. */ /* -------------------------------------------------------------------- */ nFReadAcc = (int)hDiskTree->sHooks.FRead( &offset, 4, 1, hDiskTree->fpQIX ); if ( bNeedSwap ) SwapWord ( 4, &offset ); nFReadAcc += (int)hDiskTree->sHooks.FRead( adfNodeBoundsMin, sizeof(double), 2, hDiskTree->fpQIX ); nFReadAcc += (int)hDiskTree->sHooks.FRead( adfNodeBoundsMax, sizeof(double), 2, hDiskTree->fpQIX ); if ( bNeedSwap ) { SwapWord( 8, adfNodeBoundsMin + 0 ); SwapWord( 8, adfNodeBoundsMin + 1 ); SwapWord( 8, adfNodeBoundsMax + 0 ); SwapWord( 8, adfNodeBoundsMax + 1 ); } nFReadAcc += (int)hDiskTree->sHooks.FRead( &numshapes, 4, 1, hDiskTree->fpQIX ); if ( bNeedSwap ) SwapWord ( 4, &numshapes ); /* Check that we could read all previous values */ if( nFReadAcc != 1 + 2 + 2 + 1 ) { hDiskTree->sHooks.Error("I/O error"); return FALSE; } /* Sanity checks to avoid int overflows in later computation */ if( offset > INT_MAX - sizeof(int) ) { hDiskTree->sHooks.Error("Invalid value for offset"); return FALSE; } if( numshapes > (INT_MAX - offset - sizeof(int)) / sizeof(int) || numshapes > INT_MAX / sizeof(int) - *pnResultCount ) { hDiskTree->sHooks.Error("Invalid value for numshapes"); return FALSE; } /* -------------------------------------------------------------------- */ /* If we don't overlap this node at all, we can just fseek() */ /* pass this node info and all subnodes. */ /* -------------------------------------------------------------------- */ if( !SHPCheckBoundsOverlap( adfNodeBoundsMin, adfNodeBoundsMax, padfBoundsMin, padfBoundsMax, 2 ) ) { offset += numshapes*sizeof(int) + sizeof(int); hDiskTree->sHooks.FSeek(hDiskTree->fpQIX, offset, SEEK_CUR); return TRUE; } /* -------------------------------------------------------------------- */ /* Add all the shapeids at this node to our list. */ /* -------------------------------------------------------------------- */ if(numshapes > 0) { if( *pnResultCount + numshapes > *pnBufferMax ) { int* pNewBuffer; *pnBufferMax = (*pnResultCount + numshapes + 100) * 5 / 4; if( *pnBufferMax > INT_MAX / sizeof(int) ) *pnBufferMax = *pnResultCount + numshapes; pNewBuffer = (int *) SfRealloc( *ppanResultBuffer, *pnBufferMax * sizeof(int) ); if( pNewBuffer == NULL ) { hDiskTree->sHooks.Error("Out of memory error"); return FALSE; } *ppanResultBuffer = pNewBuffer; } if( hDiskTree->sHooks.FRead( *ppanResultBuffer + *pnResultCount, sizeof(int), numshapes, hDiskTree->fpQIX ) != numshapes ) { hDiskTree->sHooks.Error("I/O error"); return FALSE; } if (bNeedSwap ) { for( i=0; i<numshapes; i++ ) SwapWord( 4, *ppanResultBuffer + *pnResultCount + i ); } *pnResultCount += numshapes; } /* -------------------------------------------------------------------- */ /* Process the subnodes. */ /* -------------------------------------------------------------------- */ if( hDiskTree->sHooks.FRead( &numsubnodes, 4, 1, hDiskTree->fpQIX ) != 1 ) { hDiskTree->sHooks.Error("I/O error"); return FALSE; } if ( bNeedSwap ) SwapWord ( 4, &numsubnodes ); if( numsubnodes > 0 && nRecLevel == 32 ) { hDiskTree->sHooks.Error("Shape tree is too deep"); return FALSE; } for(i=0; i<numsubnodes; i++) { if( !SHPSearchDiskTreeNode( hDiskTree, padfBoundsMin, padfBoundsMax, ppanResultBuffer, pnBufferMax, pnResultCount, bNeedSwap, nRecLevel + 1 ) ) return FALSE; } return TRUE; }