Beispiel #1
0
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;
}
Beispiel #2
0
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;
}