QuadTree内存索引

来源:互联网 发布:成睿进销存软件 编辑:程序博客网 时间:2024/06/05 10:03

#ifndef SHAPEFILE_H_INCLUDED
#define SHAPEFILE_H_INCLUDED


#include <stdio.h>

typedef LONG OBJTYPE;

/* this can be two or four for binary or quad tree */
#define MAX_SUBNODE    4

/* upper limit of tree levels for automatic estimation */
#define MAX_DEFAULT_TREE_DEPTH 12

typedef struct qtree_box
{
    double minx;
    double maxx;
    double miny;
    double maxy;
} QTreeBox;


typedef struct sdx_tree_node
{
    QTreeBox    box;

    LONG        nShapeCapacity;
    LONG        nShapeCount;
    OBJTYPE        *pShapes;

    int            nSubNodes;
    struct sdx_tree_node *pSubNodes[MAX_SUBNODE];
   
} SDXTreeNode;

typedef struct
{
    int        nMaxDepth;
    int        nDimension;
    int     nTotalCount;
   
    SDXTreeNode    *psRoot;
} SDXTree;

SDXTree * SDX_CreateTree( QTreeBox *box, int nDimension, int nMaxDepth );
void SDX_DestroyTree( SDXTree * hTree );

int    SDX_TreeAddShape( SDXTree * hTree, OBJTYPE obj);
int    SDX_TreeRemoveShape( SDXTree * hTree, OBJTYPE obj );

void SDX_TreeTrimExtraNodes( SDXTree * hTree );

OBJTYPE  *SDX_TreeFindLikelyShapes( SDXTree * hTree, QTreeBox *box, OBJTYPE * );
int  SDX_CheckBoundsOverlap( QTreeBox &src, QTreeBox *dest, OBJTYPE );


#endif /* ndef SHAPEFILE_H_INCLUDED */

 

 

 

 

 

 

 

 

#include "stdafx.h"
#include "quadtree.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#ifndef TRUE
#  define TRUE 1
#  define FALSE 0
#endif

static int bBigEndian = 0;


/* -------------------------------------------------------------------- */
/*      If the following is 0.5, nodes will be split in half.  If it    */
/*      is 0.6 then each subnode will contain 60% of the parent         */
/*      node, with 20% representing overlap.  This can be help to       */
/*      prevent small objects on a boundary from shifting too high      */
/*      up the tree.                                                    */
/* -------------------------------------------------------------------- */

#define SHP_SPLIT_RATIO    0.55

static void * SDX_SfRealloc( void * pMem, int nNewSize )

{
    if( pMem == NULL )
        return( (void *) malloc(nNewSize) );
    else
        return( (void *) realloc(pMem,nNewSize) );
}

//  If no max depth was defined, try to select a reasonable one
//  that implies approximately 8 shapes per node.         
int SDX_GetDefaultDepth(int count)
{
    int    nMaxNodeCount = 1;
    int nMaxDepth = 0;

    while( nMaxNodeCount*4 < count )
    {
        nMaxDepth += 1;
        nMaxNodeCount = nMaxNodeCount * 2;
    }

    return nMaxDepth;
}

static SDXTreeNode *SDX_TreeNodeCreate( QTreeBox *box )
{
    if (NULL==box)
        return NULL;

    SDXTreeNode    *pTreeNode;
    pTreeNode = (SDXTreeNode *) malloc(sizeof(SDXTreeNode));
    if( NULL == pTreeNode )
    {
        return NULL;
    }

    pTreeNode->box            = *box;
    pTreeNode->nShapeCount    = 0;
    pTreeNode->nShapeCapacity= 0;
    pTreeNode->pShapes        = NULL;
    pTreeNode->nSubNodes    = 0;

    return pTreeNode;
}

SDXTree * SDX_CreateTree( QTreeBox *box, int nDimension, int nMaxDepth )
{
    SDXTree    *psTree;
    psTree = (SDXTree *) malloc(sizeof(SDXTree));
    if( NULL == psTree )
    {
        return NULL;
    }

    psTree->nMaxDepth    = nMaxDepth;
    psTree->nDimension    = nDimension;
    psTree->nTotalCount = 0;


    if( psTree->nMaxDepth > MAX_DEFAULT_TREE_DEPTH || psTree->nMaxDepth==0)
    {
        psTree->nMaxDepth = MAX_DEFAULT_TREE_DEPTH;

    }

    psTree->psRoot = SDX_TreeNodeCreate( box );
    if( NULL == psTree->psRoot )
    {
        return NULL;
    }

    return psTree;
}

static void SDX_DestroyTreeNode( SDXTreeNode * pTreeNode )
{
    if ( NULL == pTreeNode )
        return;

    int    i;
    for( i = 0; i < pTreeNode->nSubNodes; i++ )
    {
        if( pTreeNode->pSubNodes[i] != NULL )
            SDX_DestroyTreeNode( pTreeNode->pSubNodes[i] );
    }
   
    if( pTreeNode->pShapes != NULL )
        free( pTreeNode->pShapes );

    free( pTreeNode );
}

void SHPDestroyTree( SDXTree * psTree )
{
    SDX_DestroyTreeNode( psTree->psRoot );
    free( psTree );
}

int SHPCheckBoundsOverlap( QTreeBox *src, QTreeBox *dest, int nDimension )
{
    if (2==nDimension)
    {
        if (src->minx>dest->maxy || src->maxx<dest->minx
            || src->miny>dest->maxy || src->maxy<dest->miny)
            return FALSE;
        else
            return TRUE;
    }

    return FALSE;
}
                       
// src contains dest ?
static BOOL SHPCheckContained( QTreeBox *src, QTreeBox *dest, int nDimension )
{
    if( dest->minx< src->minx || dest->maxx>src->maxx
        || dest->miny< src->miny || dest->maxy>src->maxy )
        return FALSE;
   
    return TRUE;
}

// Split a region into two subregion evenly, cutting along the longest dimension.                                             */
void SHPTreeSplitBounds( QTreeBox *src, QTreeBox *dest)
{
    if (NULL==dest || NULL==src)
        return;

    memcpy( dest, src, sizeof(QTreeBox) );
    memcpy( dest+1, src, sizeof(QTreeBox) );
   
    // Split in X direction.
    double xDelta = src->maxx-src->minx;
    double yDelta = src->maxy-src->miny;
    if( xDelta > yDelta )
    {
        dest[0].maxx = src->minx + xDelta * SHP_SPLIT_RATIO;
        dest[1].minx = src->maxx - xDelta * SHP_SPLIT_RATIO;
    }
    // Split in X direction.
    else
    {
        dest[0].maxy = src->miny + yDelta * SHP_SPLIT_RATIO;
        dest[1].miny = src->maxy - yDelta * SHP_SPLIT_RATIO;
    }
}

static int SDX_TreeNodeAddShape( SDXTreeNode * pTreeNode, QTreeBox *box, OBJTYPE obj,
                       int nMaxDepth, int nDimension )
{
    int        i;
   
    // If there are subnodes, then consider wether this object will fit in them.
    if( nMaxDepth > 1 && pTreeNode->nSubNodes > 0 )
    {
        for( i = 0; i < pTreeNode->nSubNodes; i++ )
        {
            if( SHPCheckContained( &(pTreeNode->pSubNodes[i]->box), box, nDimension) )
            {
                return SDX_TreeNodeAddShape( pTreeNode->pSubNodes[i], box, obj, nMaxDepth-1, nDimension );
            }
        }
    }

    else if( nMaxDepth > 1 && pTreeNode->nSubNodes == 0 )
    {
        QTreeBox boxH[2];
        QTreeBox box1[2];
        QTreeBox box2[2];

        SHPTreeSplitBounds( &(pTreeNode->box), boxH);

        SHPTreeSplitBounds( &(boxH[0]), box1 );
        SHPTreeSplitBounds( &(boxH[1]), box2 );


        if( SHPCheckContained( &(box1[0]), box, nDimension )
            || SHPCheckContained( &(box1[1]), box, nDimension)
            || SHPCheckContained( &(box2[0]), box, nDimension )
            || SHPCheckContained( &(box2[1]), box, nDimension ) )
        {
            pTreeNode->nSubNodes = 4;
            pTreeNode->pSubNodes[0] = SDX_TreeNodeCreate( &(box1[0]) );
            pTreeNode->pSubNodes[1] = SDX_TreeNodeCreate( &(box1[1]) );
            pTreeNode->pSubNodes[2] = SDX_TreeNodeCreate( &(box2[0]) );
            pTreeNode->pSubNodes[3] = SDX_TreeNodeCreate( &(box2[1]) );

            /* recurse back on this node now that it has subnodes */
            return( SDX_TreeNodeAddShape( pTreeNode, box, obj, nMaxDepth, nDimension ) );
        }
    }



//   If none of that worked, just add it to this nodes list.
    pTreeNode->nShapeCount++;

    if ( pTreeNode->nShapeCapacity < pTreeNode->nShapeCount )
    {
        pTreeNode->pShapes = (LONG *) SDX_SfRealloc( pTreeNode->pShapes, sizeof(OBJTYPE) * (pTreeNode->nShapeCapacity+16) );
        pTreeNode->pShapes[pTreeNode->nShapeCount-1] = obj;
    }

    return TRUE;
}

//  Work function implementing SDX_TreeFindLikelyShapes() on a tree node by tree node basis
void SDX_TreeCollectShapes( SDXTree *hTree, SDXTreeNode * pTreeNode,
                        QTreeBox *box,
                        int * pnShapeCount, int * pnMaxShapes,
                        OBJTYPE ** 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( &(pTreeNode->box), box, hTree->nDimension ) )
        return;


//        Grow the list to hold the shapes on this node
    if( *pnShapeCount + pTreeNode->nShapeCount > *pnMaxShapes )
    {
        *pnMaxShapes = (*pnShapeCount + pTreeNode->nShapeCount) * 2 + 20;
        *ppanShapeList = (OBJTYPE *)
            SDX_SfRealloc(*ppanShapeList,sizeof(OBJTYPE) * *pnMaxShapes);
    }


//    Add the local nodes shapeids to the list
    for( i = 0; i < pTreeNode->nShapeCount; i++ )
    {
        (*ppanShapeList)[(*pnShapeCount)++] = pTreeNode->pShapes[i];
    }
   
//    Recurse to subnodes if they exist
    for( i = 0; i < pTreeNode->nSubNodes; i++ )
    {
        if( pTreeNode->pSubNodes[i] != NULL )
            SDX_TreeCollectShapes( hTree, pTreeNode->pSubNodes[i],
                                    box,
                                    pnShapeCount, pnMaxShapes,
                                    ppanShapeList );
    }
}

/************************************************************************/
/*                      SDX_TreeFindLikelyShapes()                       */
/*                                                                      */
/*      Find all shapes within tree nodes for which the tree node       */
/*      bounding box overlaps the search box.  The return value is      */
/*      an array of shapeids terminated by a -1.  The shapeids will     */
/*      be in order, as hopefully this will result in faster (more      */
/*      sequential) reading from the file.                              */
/************************************************************************/

/* helper for qsort */
static int
compare_ints( const void * a, const void * b)
{
    return (*(int*)a) - (*(int*)b);
}

OBJTYPE * SDX_TreeFindLikelyShapes( SDXTree * hTree,
                         QTreeBox *box, int * pnShapeCount )

{
    OBJTYPE    *panShapeList=NULL;
    int nMaxShapes = 0;

   *pnShapeCount = 0;

    SDX_TreeCollectShapes( hTree, hTree->psRoot,
                            box,
                            pnShapeCount, &nMaxShapes,
                            &panShapeList );


    return panShapeList;
}

// This is the recurve version of SDX_TreeTrimExtraNodes() that walks the tree cleaning it up.
static int SDX_TreeNodeTrim( SDXTreeNode * pTreeNode )

{
    int        i;

/* -------------------------------------------------------------------- */
/*      Trim subtrees, and free subnodes that come back empty.          */
/* -------------------------------------------------------------------- */
    for( i = 0; i < pTreeNode->nSubNodes; i++ )
    {
        if( SDX_TreeNodeTrim( pTreeNode->pSubNodes[i] ) )
        {
            SDX_DestroyTreeNode( pTreeNode->pSubNodes[i] );

            pTreeNode->pSubNodes[i] =
                pTreeNode->pSubNodes[pTreeNode->nSubNodes-1];

            pTreeNode->nSubNodes--;

            i--; /* process the new occupant of this subnode entry */
        }
    }

    return( pTreeNode->nSubNodes == 0 && pTreeNode->nShapeCount == 0 );
}

// Trim empty nodes from the tree.  Note that we never trim an empty root node
void SDX_TreeTrimExtraNodes( SDXTree * hTree )

{
    SDX_TreeNodeTrim( hTree->psRoot );
}

/************************************************************************/
/*                              SwapWord()                              */
/*                                                                      */
/*      Swap a 2, 4 or 8 byte word.                                     */
/************************************************************************/

static void SwapWord( int length, void * wordP )
{
    int        i;
    unsigned char    temp;

    for( i=0; i < length/2; i++ )
    {
    temp = ((unsigned char *) wordP)[i];
    ((unsigned char *)wordP)[i] = ((unsigned char *) wordP)[length-i-1];
    ((unsigned char *) wordP)[length-i-1] = temp;
    }
}