📄 rtree.c
字号:
float x4 = x2; int jj; int iCellLeft = 0; int iCellRight = 0; for(jj=1; jj<nCell; jj++){ float left = aCell[jj].aCoord[i*2]; float right = aCell[jj].aCoord[i*2+1]; if( left<x1 ) x1 = left; if( right>x4 ) x4 = right; if( left>x3 ){ x3 = left; iCellRight = jj; } if( right<x2 ){ x2 = right; iCellLeft = jj; } } if( x4!=x1 ){ float normalwidth = (x3 - x2) / (x4 - x1); if( normalwidth>maxNormalInnerWidth ){ iLeftSeed = iCellLeft; iRightSeed = iCellRight; } } } *piLeftSeed = iLeftSeed; *piRightSeed = iRightSeed;}#endif /* VARIANT_GUTTMAN_LINEAR_SPLIT */#if VARIANT_GUTTMAN_QUADRATIC_SPLIT/*** Implementation of the quadratic variant of the PickNext() function from** Guttman[84].*/static RtreeCell *QuadraticPickNext( Rtree *pRtree, RtreeCell *aCell, int nCell, RtreeCell *pLeftBox, RtreeCell *pRightBox, int *aiUsed){ #define FABS(a) ((a)<0.0?-1.0*(a):(a)) int iSelect = -1; float fDiff; int ii; for(ii=0; ii<nCell; ii++){ if( aiUsed[ii]==0 ){ float left = cellGrowth(pRtree, pLeftBox, &aCell[ii]); float right = cellGrowth(pRtree, pLeftBox, &aCell[ii]); float diff = FABS(right-left); if( iSelect<0 || diff>fDiff ){ fDiff = diff; iSelect = ii; } } } aiUsed[iSelect] = 1; return &aCell[iSelect];}/*** Implementation of the quadratic variant of the PickSeeds() function from** Guttman[84].*/static void QuadraticPickSeeds( Rtree *pRtree, RtreeCell *aCell, int nCell, int *piLeftSeed, int *piRightSeed){ int ii; int jj; int iLeftSeed = 0; int iRightSeed = 1; float fWaste = 0.0; for(ii=0; ii<nCell; ii++){ for(jj=ii+1; jj<nCell; jj++){ float right = cellArea(pRtree, &aCell[jj]); float growth = cellGrowth(pRtree, &aCell[ii], &aCell[jj]); float waste = growth - right; if( waste>fWaste ){ iLeftSeed = ii; iRightSeed = jj; fWaste = waste; } } } *piLeftSeed = iLeftSeed; *piRightSeed = iRightSeed;}#endif /* VARIANT_GUTTMAN_QUADRATIC_SPLIT *//*** Arguments aIdx, aDistance and aSpare all point to arrays of size** nIdx. The aIdx array contains the set of integers from 0 to ** (nIdx-1) in no particular order. This function sorts the values** in aIdx according to the indexed values in aDistance. For** example, assuming the inputs:**** aIdx = { 0, 1, 2, 3 }** aDistance = { 5.0, 2.0, 7.0, 6.0 }**** this function sets the aIdx array to contain:**** aIdx = { 0, 1, 2, 3 }**** The aSpare array is used as temporary working space by the** sorting algorithm.*/static void SortByDistance( int *aIdx, int nIdx, float *aDistance, int *aSpare){ if( nIdx>1 ){ int iLeft = 0; int iRight = 0; int nLeft = nIdx/2; int nRight = nIdx-nLeft; int *aLeft = aIdx; int *aRight = &aIdx[nLeft]; SortByDistance(aLeft, nLeft, aDistance, aSpare); SortByDistance(aRight, nRight, aDistance, aSpare); memcpy(aSpare, aLeft, sizeof(int)*nLeft); aLeft = aSpare; while( iLeft<nLeft || iRight<nRight ){ if( iLeft==nLeft ){ aIdx[iLeft+iRight] = aRight[iRight]; iRight++; }else if( iRight==nRight ){ aIdx[iLeft+iRight] = aLeft[iLeft]; iLeft++; }else{ float fLeft = aDistance[aLeft[iLeft]]; float fRight = aDistance[aRight[iRight]]; if( fLeft<fRight ){ aIdx[iLeft+iRight] = aLeft[iLeft]; iLeft++; }else{ aIdx[iLeft+iRight] = aRight[iRight]; iRight++; } } }#if 0 /* Check that the sort worked */ { int jj; for(jj=1; jj<nIdx; jj++){ float left = aDistance[aIdx[jj-1]]; float right = aDistance[aIdx[jj]]; assert( left<=right ); } }#endif }}/*** Arguments aIdx, aCell and aSpare all point to arrays of size** nIdx. The aIdx array contains the set of integers from 0 to ** (nIdx-1) in no particular order. This function sorts the values** in aIdx according to dimension iDim of the cells in aCell. The** minimum value of dimension iDim is considered first, the** maximum used to break ties.**** The aSpare array is used as temporary working space by the** sorting algorithm.*/static void SortByDimension( Rtree *pRtree, int *aIdx, int nIdx, int iDim, RtreeCell *aCell, int *aSpare){ if( nIdx>1 ){ int iLeft = 0; int iRight = 0; int nLeft = nIdx/2; int nRight = nIdx-nLeft; int *aLeft = aIdx; int *aRight = &aIdx[nLeft]; SortByDimension(pRtree, aLeft, nLeft, iDim, aCell, aSpare); SortByDimension(pRtree, aRight, nRight, iDim, aCell, aSpare); memcpy(aSpare, aLeft, sizeof(int)*nLeft); aLeft = aSpare; while( iLeft<nLeft || iRight<nRight ){ double xleft1 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2]); double xleft2 = DCOORD(aCell[aLeft[iLeft]].aCoord[iDim*2+1]); double xright1 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2]); double xright2 = DCOORD(aCell[aRight[iRight]].aCoord[iDim*2+1]); if( (iLeft!=nLeft) && ((iRight==nRight) || (xleft1<xright1) || (xleft1==xright1 && xleft2<xright2) )){ aIdx[iLeft+iRight] = aLeft[iLeft]; iLeft++; }else{ aIdx[iLeft+iRight] = aRight[iRight]; iRight++; } }#if 0 /* Check that the sort worked */ { int jj; for(jj=1; jj<nIdx; jj++){ float xleft1 = aCell[aIdx[jj-1]].aCoord[iDim*2]; float xleft2 = aCell[aIdx[jj-1]].aCoord[iDim*2+1]; float xright1 = aCell[aIdx[jj]].aCoord[iDim*2]; float xright2 = aCell[aIdx[jj]].aCoord[iDim*2+1]; assert( xleft1<=xright1 && (xleft1<xright1 || xleft2<=xright2) ); } }#endif }}#if VARIANT_RSTARTREE_SPLIT/*** Implementation of the R*-tree variant of SplitNode from Beckman[1990].*/static int splitNodeStartree( Rtree *pRtree, RtreeCell *aCell, int nCell, RtreeNode *pLeft, RtreeNode *pRight, RtreeCell *pBboxLeft, RtreeCell *pBboxRight){ int **aaSorted; int *aSpare; int ii; int iBestDim; int iBestSplit; float fBestMargin; int nByte = (pRtree->nDim+1)*(sizeof(int*)+nCell*sizeof(int)); aaSorted = (int **)sqlite3_malloc(nByte); if( !aaSorted ){ return SQLITE_NOMEM; } aSpare = &((int *)&aaSorted[pRtree->nDim])[pRtree->nDim*nCell]; memset(aaSorted, 0, nByte); for(ii=0; ii<pRtree->nDim; ii++){ int jj; aaSorted[ii] = &((int *)&aaSorted[pRtree->nDim])[ii*nCell]; for(jj=0; jj<nCell; jj++){ aaSorted[ii][jj] = jj; } SortByDimension(pRtree, aaSorted[ii], nCell, ii, aCell, aSpare); } for(ii=0; ii<pRtree->nDim; ii++){ float margin = 0.0; float fBestOverlap; float fBestArea; int iBestLeft; int nLeft; for( nLeft=RTREE_MINCELLS(pRtree); nLeft<=(nCell-RTREE_MINCELLS(pRtree)); nLeft++ ){ RtreeCell left; RtreeCell right; int kk; float overlap; float area; memcpy(&left, &aCell[aaSorted[ii][0]], sizeof(RtreeCell)); memcpy(&right, &aCell[aaSorted[ii][nCell-1]], sizeof(RtreeCell)); for(kk=1; kk<(nCell-1); kk++){ if( kk<nLeft ){ cellUnion(pRtree, &left, &aCell[aaSorted[ii][kk]]); }else{ cellUnion(pRtree, &right, &aCell[aaSorted[ii][kk]]); } } margin += cellMargin(pRtree, &left); margin += cellMargin(pRtree, &right); overlap = cellOverlap(pRtree, &left, &right, 1, -1); area = cellArea(pRtree, &left) + cellArea(pRtree, &right); if( (nLeft==RTREE_MINCELLS(pRtree)) || (overlap<fBestOverlap) || (overlap==fBestOverlap && area<fBestArea) ){ iBestLeft = nLeft; fBestOverlap = overlap; fBestArea = area; } } if( ii==0 || margin<fBestMargin ){ iBestDim = ii; fBestMargin = margin; iBestSplit = iBestLeft; } } memcpy(pBboxLeft, &aCell[aaSorted[iBestDim][0]], sizeof(RtreeCell)); memcpy(pBboxRight, &aCell[aaSorted[iBestDim][iBestSplit]], sizeof(RtreeCell)); for(ii=0; ii<nCell; ii++){ RtreeNode *pTarget = (ii<iBestSplit)?pLeft:pRight; RtreeCell *pBbox = (ii<iBestSplit)?pBboxLeft:pBboxRight; RtreeCell *pCell = &aCell[aaSorted[iBestDim][ii]]; nodeInsertCell(pRtree, pTarget, pCell); cellUnion(pRtree, pBbox, pCell); } sqlite3_free(aaSorted); return SQLITE_OK;}#endif#if VARIANT_GUTTMAN_SPLIT/*** Implementation of the regular R-tree SplitNode from Guttman[1984].*/static int splitNodeGuttman( Rtree *pRtree, RtreeCell *aCell, int nCell, RtreeNode *pLeft, RtreeNode *pRight, RtreeCell *pBboxLeft, RtreeCell *pBboxRight){ int iLeftSeed = 0; int iRightSeed = 1; int *aiUsed; int i; aiUsed = sqlite3_malloc(sizeof(int)*nCell); memset(aiUsed, 0, sizeof(int)*nCell); PickSeeds(pRtree, aCell, nCell, &iLeftSeed, &iRightSeed); memcpy(pBboxLeft, &aCell[iLeftSeed], sizeof(RtreeCell)); memcpy(pBboxRight, &aCell[iRightSeed], sizeof(RtreeCell)); nodeInsertCell(pRtree, pLeft, &aCell[iLeftSeed]); nodeInsertCell(pRtree, pRight, &aCell[iRightSeed]); aiUsed[iLeftSeed] = 1; aiUsed[iRightSeed] = 1; for(i=nCell-2; i>0; i--){ RtreeCell *pNext; pNext = PickNext(pRtree, aCell, nCell, pBboxLeft, pBboxRight, aiUsed); float diff = cellGrowth(pRtree, pBboxLeft, pNext) - cellGrowth(pRtree, pBboxRight, pNext) ; if( (RTREE_MINCELLS(pRtree)-NCELL(pRight)==i) || (diff>0.0 && (RTREE_MINCELLS(pRtree)-NCELL(pLeft)!=i)) ){ nodeInsertCell(pRtree, pRight, pNext); cellUnion(pRtree, pBboxRight, pNext); }else{ nodeInsertCell(pRtree, pLeft, pNext); cellUnion(pRtree, pBboxLeft, pNext); } } sqlite3_free(aiUsed); return SQLITE_OK;}#endifstatic int updateMapping( Rtree *pRtree, i64 iRowid, RtreeNode *pNode, int iHeight){ int (*xSetMapping)(Rtree *, sqlite3_int64, sqlite3_int64); xSetMapping = ((iHeight==0)?rowidWrite:parentWrite); if( iHeight>0 ){ RtreeNode *pChild = nodeHashLookup(pRtree, iRowid); if( pChild ){ nodeRelease(pRtree, pChild->pParent); nodeReference(pNode); pChild->pParent = pNode; } } return xSetMapping(pRtree, iRowid, pNode->iNode);}static int SplitNode( Rtree *pRtree, RtreeNode *pNode, RtreeCell *pCell, int iHeight){ int i; int newCellIsRight = 0; int rc = SQLITE_OK; int nCell = NCELL(pNode); RtreeCell *aCell; int *aiUsed; RtreeNode *pLeft = 0; RtreeNode *pRight = 0; RtreeCell leftbbox; RtreeCell rightbbox; /* Allocate an array and populate it with a copy of pCell and ** all cells from node pLeft. Then zero the original node. */ aCell = sqlite3_malloc((sizeof(RtreeCell)+sizeof(int))*(nCell+1)); if( !aCell ){ rc = SQLITE_NOMEM; goto splitnode_out; } aiUsed = (int *)&aCell[nCell+1]; memset(aiUsed, 0, sizeof(int)*(nCell+1)); for(i=0; i<nCell; i++){ nodeGetCell(pRtree, pNode, i, &aCell[i]); } nodeZero(pRtree, pNode); memcpy(&aCell[nCell], pCell, sizeof(RtreeCell)); nCell++; if( pNode->iNode==1 ){ pRight = nodeNew(pRtree, pNode, 1); pLeft = nodeNew(pRtree, pNode, 1); pRtree->iDepth++; pNode->isDirty = 1; writeInt16(pNode->zData, pRtree->iDepth); }else{ pLeft = pNode; pRight = nodeNew(pRtree, pLeft->pParent, 1); nodeReference(pLeft); } if( !pLeft || !pRight ){ rc = SQLITE_NOMEM; goto splitnode_out; } memset(pLeft->zData, 0, pRtree->iNodeSize); memset(pRight->zData, 0, pRtree->iNodeSize); rc = AssignCells(pRtree, aCell, nCell, pLeft, pRight, &leftbbox, &rightbbox); if( rc!=SQLITE_OK ){ goto splitnode_out; } /* Ensure both child nodes have node numbers assigned to them. */ if( (0==pRight->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pRight))) || (0==pLeft->iNode && SQLITE_OK!=(rc = nodeWrite(pRtree, pLeft))) ){ goto splitnode_out;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -