int* SBNSearchDiskTreeInteger( SBNSearchHandle hSBN, int bMinX, int bMinY, int bMaxX, int bMaxY, int *pnShapeCount ) { SearchStruct sSearch; int bRet; *pnShapeCount = 0; if( bMinX > bMaxX || bMinY > bMaxY ) return NULL; if( bMaxX < 0 || bMaxY < 0 || bMinX > 255 || bMinX > 255 ) return NULL; if( hSBN->nShapeCount == 0 ) return NULL; /* -------------------------------------------------------------------- */ /* Run the search. */ /* -------------------------------------------------------------------- */ sSearch.hSBN = hSBN; sSearch.bMinX = (coord) (bMinX >= 0 ? bMinX : 0); sSearch.bMinY = (coord) (bMinY >= 0 ? bMinY : 0); sSearch.bMaxX = (coord) (bMaxX <= 255 ? bMaxX : 255); sSearch.bMaxY = (coord) (bMaxY <= 255 ? bMaxY : 255); sSearch.nShapeCount = 0; sSearch.nShapeAlloc = 0; sSearch.panShapeId = NULL; #ifdef DEBUG_IO sSearch.nBytesRead = 0; #endif bRet = SBNSearchDiskInternal(&sSearch, 0, 0, 0, 0, 255, 255); #ifdef DEBUG_IO hSBN->nTotalBytesRead += sSearch.nBytesRead; /* printf("nBytesRead = %d\n", sSearch.nBytesRead); */ #endif if( !bRet ) { if( sSearch.panShapeId != NULL ) free( sSearch.panShapeId ); *pnShapeCount = 0; return NULL; } *pnShapeCount = sSearch.nShapeCount; /* -------------------------------------------------------------------- */ /* Sort the id array */ /* -------------------------------------------------------------------- */ qsort(sSearch.panShapeId, *pnShapeCount, sizeof(int), compare_ints); /* To distinguish between empty intersection from error case */ if( sSearch.panShapeId == NULL ) sSearch.panShapeId = (int*) calloc(1, sizeof(int)); return sSearch.panShapeId; }
static int SBNSearchDiskInternal( SearchStruct* psSearch, int nDepth, int nNodeId, coord bNodeMinX, coord bNodeMinY, coord bNodeMaxX, coord bNodeMaxY ) { SBNSearchHandle hSBN; SBNNodeDescriptor* psNode; coord bSearchMinX = psSearch->bMinX; coord bSearchMinY = psSearch->bMinY; coord bSearchMaxX = psSearch->bMaxX; coord bSearchMaxY = psSearch->bMaxY; hSBN = psSearch->hSBN; psNode = &(hSBN->pasNodeDescriptor[nNodeId]); /* -------------------------------------------------------------------- */ /* Check if this node contains shapes that intersect the search */ /* bounding box. */ /* -------------------------------------------------------------------- */ if ( psNode->bBBoxInit && !(SEARCH_BB_INTERSECTS(psNode->bMinX, psNode->bMinY, psNode->bMaxX, psNode->bMaxY)) ) { /* No intersection, then don't try to read the shapes attached */ /* to this node */ } /* -------------------------------------------------------------------- */ /* If this node contains shapes that are cached, then read them. */ /* -------------------------------------------------------------------- */ else if (psNode->pabyShapeDesc != NULL) { int j; uchar* pabyShapeDesc = psNode->pabyShapeDesc; /* printf("nNodeId = %d, nDepth = %d\n", nNodeId, nDepth); */ for(j = 0; j < psNode->nShapeCount; j++) { coord bMinX = pabyShapeDesc[0]; coord bMinY = pabyShapeDesc[1]; coord bMaxX = pabyShapeDesc[2]; coord bMaxY = pabyShapeDesc[3]; if( SEARCH_BB_INTERSECTS(bMinX, bMinY, bMaxX, bMaxY) ) { int nShapeId; nShapeId = READ_MSB_INT(pabyShapeDesc + 4); /* Caution : we count shape id starting from 0, and not 1 */ nShapeId --; /*printf("shape=%d, minx=%d, miny=%d, maxx=%d, maxy=%d\n", nShapeId, bMinX, bMinY, bMaxX, bMaxY);*/ if( !SBNAddShapeId( psSearch, nShapeId ) ) return FALSE; } pabyShapeDesc += 8; } } /* -------------------------------------------------------------------- */ /* If the node has attached shapes (that are not (yet) cached), */ /* then retrieve them from disk. */ /* -------------------------------------------------------------------- */ else if (psNode->nBinCount > 0) { uchar abyBinHeader[8]; int nBinSize, nShapes; int nShapeCountAcc = 0; int i, j; /* printf("nNodeId = %d, nDepth = %d\n", nNodeId, nDepth); */ hSBN->sHooks.FSeek(hSBN->fpSBN, psNode->nBinOffset, SEEK_SET); if (nDepth < CACHED_DEPTH_LIMIT) psNode->pabyShapeDesc = (uchar*) malloc(psNode->nShapeCount * 8); for(i = 0; i < psNode->nBinCount; i++) { uchar* pabyBinShape; #ifdef DEBUG_IO psSearch->nBytesRead += 8; #endif if( hSBN->sHooks.FRead(abyBinHeader, 8, 1, hSBN->fpSBN) != 1) { hSBN->sHooks.Error( "I/O error" ); free(psNode->pabyShapeDesc); psNode->pabyShapeDesc = NULL; return FALSE; } if ( READ_MSB_INT(abyBinHeader + 0) != psNode->nBinStart + i ) { hSBN->sHooks.Error( "Unexpected bin id" ); free(psNode->pabyShapeDesc); psNode->pabyShapeDesc = NULL; return FALSE; } nBinSize = READ_MSB_INT(abyBinHeader + 4); nBinSize *= 2; /* 16-bit words */ nShapes = nBinSize / 8; /* Bins are always limited to 100 features */ if( (nBinSize % 8) != 0 || nShapes <= 0 || nShapes > 100) { hSBN->sHooks.Error( "Unexpected bin size" ); free(psNode->pabyShapeDesc); psNode->pabyShapeDesc = NULL; return FALSE; } if( nShapeCountAcc + nShapes > psNode->nShapeCount) { free(psNode->pabyShapeDesc); psNode->pabyShapeDesc = NULL; hSBN->sHooks.Error( "Inconsistant shape count for bin" ); return FALSE; } if (nDepth < CACHED_DEPTH_LIMIT && psNode->pabyShapeDesc != NULL) { pabyBinShape = psNode->pabyShapeDesc + nShapeCountAcc * 8; } else { pabyBinShape = psSearch->abyBinShape; } #ifdef DEBUG_IO psSearch->nBytesRead += nBinSize; #endif if (hSBN->sHooks.FRead(pabyBinShape, nBinSize, 1, hSBN->fpSBN) != 1) { hSBN->sHooks.Error( "I/O error" ); free(psNode->pabyShapeDesc); psNode->pabyShapeDesc = NULL; return FALSE; } nShapeCountAcc += nShapes; if (i == 0 && !psNode->bBBoxInit) { psNode->bMinX = pabyBinShape[0]; psNode->bMinY = pabyBinShape[1]; psNode->bMaxX = pabyBinShape[2]; psNode->bMaxY = pabyBinShape[3]; } for(j = 0; j < nShapes; j++) { coord bMinX = pabyBinShape[0]; coord bMinY = pabyBinShape[1]; coord bMaxX = pabyBinShape[2]; coord bMaxY = pabyBinShape[3]; if( !psNode->bBBoxInit ) { #ifdef sanity_checks /* -------------------------------------------------------------------- */ /* Those tests only check that the shape bounding box in the bin */ /* are consistant (self-consistant and consistant with the node */ /* they are attached to). They are optional however (as far as */ /* the safety of runtime is concerned at least). */ /* -------------------------------------------------------------------- */ if( !(((bMinX < bMaxX || (bMinX == 0 && bMaxX == 0) || (bMinX == 255 && bMaxX == 255))) && ((bMinY < bMaxY || (bMinY == 0 && bMaxY == 0) || (bMinY == 255 && bMaxY == 255)))) || bMaxX < bNodeMinX || bMaxY < bNodeMinY || bMinX > bNodeMaxX || bMinY > bNodeMaxY ) { /*printf("shape %d %d %d %d\n", bMinX, bMinY, bMaxX, bMaxY); printf("node %d %d %d %d\n", bNodeMinX, bNodeMinY, bNodeMaxX, bNodeMaxY);*/ hSBN->sHooks.Error( "Invalid shape bounding box in bin" ); free(psNode->pabyShapeDesc); psNode->pabyShapeDesc = NULL; return FALSE; } #endif if (bMinX < psNode->bMinX) psNode->bMinX = bMinX; if (bMinY < psNode->bMinY) psNode->bMinY = bMinY; if (bMaxX > psNode->bMaxX) psNode->bMaxX = bMaxX; if (bMaxY > psNode->bMaxY) psNode->bMaxY = bMaxY; } if( SEARCH_BB_INTERSECTS(bMinX, bMinY, bMaxX, bMaxY) ) { int nShapeId; nShapeId = READ_MSB_INT(pabyBinShape + 4); /* Caution : we count shape id starting from 0, and not 1 */ nShapeId --; /*printf("shape=%d, minx=%d, miny=%d, maxx=%d, maxy=%d\n", nShapeId, bMinX, bMinY, bMaxX, bMaxY);*/ if( !SBNAddShapeId( psSearch, nShapeId ) ) return FALSE; } pabyBinShape += 8; } } if( nShapeCountAcc != psNode->nShapeCount) { free(psNode->pabyShapeDesc); psNode->pabyShapeDesc = NULL; hSBN->sHooks.Error( "Inconsistant shape count for bin" ); return FALSE; } psNode->bBBoxInit = TRUE; } /* -------------------------------------------------------------------- */ /* Look up in child nodes. */ /* -------------------------------------------------------------------- */ if( nDepth + 1 < hSBN->nMaxDepth ) { nNodeId = nNodeId * 2 + 1; if( (nDepth % 2) == 0 ) /* x split */ { coord bMid = (coord) (1 + ((int)bNodeMinX + bNodeMaxX) / 2); if( bSearchMinX <= bMid - 1 && !SBNSearchDiskInternal( psSearch, nDepth + 1, nNodeId + 1, bNodeMinX, bNodeMinY, bMid - 1, bNodeMaxY ) ) { return FALSE; } if( bSearchMaxX >= bMid && !SBNSearchDiskInternal( psSearch, nDepth + 1, nNodeId, bMid, bNodeMinY, bNodeMaxX, bNodeMaxY ) ) { return FALSE; } } else /* y split */ { coord bMid = (coord) (1 + ((int)bNodeMinY + bNodeMaxY) / 2); if( bSearchMinY <= bMid - 1 && !SBNSearchDiskInternal( psSearch, nDepth + 1, nNodeId + 1, bNodeMinX, bNodeMinY, bNodeMaxX, bMid - 1 ) ) { return FALSE; } if( bSearchMaxY >= bMid && !SBNSearchDiskInternal( psSearch, nDepth + 1, nNodeId, bNodeMinX, bMid, bNodeMaxX, bNodeMaxY ) ) { return FALSE; } } } return TRUE; }