📄 rtree.c
字号:
sqlite3_bind_int64(pRtree->pReadRowid, 1, iRowid); if( sqlite3_step(pRtree->pReadRowid)==SQLITE_ROW ){ i64 iNode = sqlite3_column_int64(pRtree->pReadRowid, 0); rc = nodeAcquire(pRtree, iNode, 0, ppLeaf); sqlite3_reset(pRtree->pReadRowid); }else{ rc = sqlite3_reset(pRtree->pReadRowid); } return rc;}/* ** Rtree virtual table module xFilter method.*/static int rtreeFilter( sqlite3_vtab_cursor *pVtabCursor, int idxNum, const char *idxStr, int argc, sqlite3_value **argv){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; rtreeReference(pRtree); sqlite3_free(pCsr->aConstraint); pCsr->aConstraint = 0; pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ i64 iRowid = sqlite3_value_int64(argv[0]); rc = findLeafNode(pRtree, iRowid, &pLeaf); pCsr->pNode = pLeaf; if( pLeaf && rc==SQLITE_OK ){ pCsr->iCell = nodeRowidIndex(pRtree, pLeaf, iRowid); } }else{ /* Normal case - r-tree scan. Set up the RtreeCursor.aConstraint array ** with the configured constraints. */ if( argc>0 ){ pCsr->aConstraint = sqlite3_malloc(sizeof(RtreeConstraint)*argc); pCsr->nConstraint = argc; if( !pCsr->aConstraint ){ rc = SQLITE_NOMEM; }else{ assert( (idxStr==0 && argc==0) || strlen(idxStr)==argc*2 ); for(ii=0; ii<argc; ii++){ RtreeConstraint *p = &pCsr->aConstraint[ii]; p->op = idxStr[ii*2]; p->iCoord = idxStr[ii*2+1]-'a'; p->rValue = sqlite3_value_double(argv[ii]); } } } if( rc==SQLITE_OK ){ pCsr->pNode = 0; rc = nodeAcquire(pRtree, 1, 0, &pRoot); } if( rc==SQLITE_OK ){ int isEof = 1; int nCell = NCELL(pRoot); pCsr->pNode = pRoot; for(pCsr->iCell=0; rc==SQLITE_OK && pCsr->iCell<nCell; pCsr->iCell++){ assert( pCsr->pNode==pRoot ); rc = descendToCell(pRtree, pCsr, pRtree->iDepth, &isEof); if( !isEof ){ break; } } if( rc==SQLITE_OK && isEof ){ assert( pCsr->pNode==pRoot ); nodeRelease(pRtree, pRoot); pCsr->pNode = 0; } assert( rc!=SQLITE_OK || !pCsr->pNode || pCsr->iCell<NCELL(pCsr->pNode) ); } } rtreeRelease(pRtree); return rc;}/*** Rtree virtual table module xBestIndex method. There are three** table scan strategies to choose from (in order from most to ** least desirable):**** idxNum idxStr Strategy** ------------------------------------------------** 1 Unused Direct lookup by rowid.** 2 See below R-tree query.** 3 Unused Full table scan.** ------------------------------------------------**** If strategy 1 or 3 is used, then idxStr is not meaningful. If strategy** 2 is used, idxStr is formatted to contain 2 bytes for each ** constraint used. The first two bytes of idxStr correspond to ** the constraint in sqlite3_index_info.aConstraintUsage[] with** (argvIndex==1) etc.**** The first of each pair of bytes in idxStr identifies the constraint** operator as follows:**** Operator Byte Value** ----------------------** = 0x41 ('A')** <= 0x42 ('B')** < 0x43 ('C')** >= 0x44 ('D')** > 0x45 ('E')** ----------------------**** The second of each pair of bytes identifies the coordinate column** to which the constraint applies. The leftmost coordinate column** is 'a', the second from the left 'b' etc.*/static int rtreeBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){ int rc = SQLITE_OK; int ii, cCol; int iIdx = 0; char zIdxStr[RTREE_MAX_DIMENSIONS*8+1]; memset(zIdxStr, 0, sizeof(zIdxStr)); assert( pIdxInfo->idxStr==0 ); for(ii=0; ii<pIdxInfo->nConstraint; ii++){ struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii]; if( p->usable && p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_EQ ){ /* We have an equality constraint on the rowid. Use strategy 1. */ int jj; for(jj=0; jj<ii; jj++){ pIdxInfo->aConstraintUsage[jj].argvIndex = 0; pIdxInfo->aConstraintUsage[jj].omit = 0; } pIdxInfo->idxNum = 1; pIdxInfo->aConstraintUsage[ii].argvIndex = 1; pIdxInfo->aConstraintUsage[jj].omit = 1; return SQLITE_OK; } if( p->usable && p->iColumn>0 ){ u8 op = 0; switch( p->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; } if( op ){ /* Make sure this particular constraint has not been used before. ** If it has been used before, ignore it. ** ** A <= or < can be used if there is a prior >= or >. ** A >= or > can be used if there is a prior < or <=. ** A <= or < is disqualified if there is a prior <=, <, or ==. ** A >= or > is disqualified if there is a prior >=, >, or ==. ** A == is disqualifed if there is any prior constraint. */ int j, opmsk; static const unsigned char compatible[] = { 0, 0, 1, 1, 2, 2 }; assert( compatible[RTREE_EQ & 7]==0 ); assert( compatible[RTREE_LT & 7]==1 ); assert( compatible[RTREE_LE & 7]==1 ); assert( compatible[RTREE_GT & 7]==2 ); assert( compatible[RTREE_GE & 7]==2 ); cCol = p->iColumn - 1 + 'a'; opmsk = compatible[op & 7]; for(j=0; j<iIdx; j+=2){ if( zIdxStr[j+1]==cCol && (compatible[zIdxStr[j] & 7] & opmsk)!=0 ){ op = 0; break; } } } if( op ){ assert( iIdx<sizeof(zIdxStr)-1 ); zIdxStr[iIdx++] = op; zIdxStr[iIdx++] = cCol; pIdxInfo->aConstraintUsage[ii].argvIndex = (iIdx/2); pIdxInfo->aConstraintUsage[ii].omit = 1; } } } pIdxInfo->idxNum = 2; pIdxInfo->needToFreeIdxStr = 1; if( iIdx>0 && 0==(pIdxInfo->idxStr = sqlite3_mprintf("%s", zIdxStr)) ){ return SQLITE_NOMEM; } return rc;}/*** Return the N-dimensional volumn of the cell stored in *p.*/static float cellArea(Rtree *pRtree, RtreeCell *p){ float area = 1.0; int ii; for(ii=0; ii<(pRtree->nDim*2); ii+=2){ area = area * (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); } return area;}/*** Return the margin length of cell p. The margin length is the sum** of the objects size in each dimension.*/static float cellMargin(Rtree *pRtree, RtreeCell *p){ float margin = 0.0; int ii; for(ii=0; ii<(pRtree->nDim*2); ii+=2){ margin += (DCOORD(p->aCoord[ii+1]) - DCOORD(p->aCoord[ii])); } return margin;}/*** Store the union of cells p1 and p2 in p1.*/static void cellUnion(Rtree *pRtree, RtreeCell *p1, RtreeCell *p2){ int ii; if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; ii<(pRtree->nDim*2); ii+=2){ p1->aCoord[ii].f = MIN(p1->aCoord[ii].f, p2->aCoord[ii].f); p1->aCoord[ii+1].f = MAX(p1->aCoord[ii+1].f, p2->aCoord[ii+1].f); } }else{ for(ii=0; ii<(pRtree->nDim*2); ii+=2){ p1->aCoord[ii].i = MIN(p1->aCoord[ii].i, p2->aCoord[ii].i); p1->aCoord[ii+1].i = MAX(p1->aCoord[ii+1].i, p2->aCoord[ii+1].i); } }}/*** Return the amount cell p would grow by if it were unioned with pCell.*/static float cellGrowth(Rtree *pRtree, RtreeCell *p, RtreeCell *pCell){ float area; RtreeCell cell; memcpy(&cell, p, sizeof(RtreeCell)); area = cellArea(pRtree, &cell); cellUnion(pRtree, &cell, pCell); return (cellArea(pRtree, &cell)-area);}#if VARIANT_RSTARTREE_CHOOSESUBTREE || VARIANT_RSTARTREE_SPLITstatic float cellOverlap( Rtree *pRtree, RtreeCell *p, RtreeCell *aCell, int nCell, int iExclude){ int ii; float overlap = 0.0; for(ii=0; ii<nCell; ii++){ if( ii!=iExclude ){ int jj; float o = 1.0; for(jj=0; jj<(pRtree->nDim*2); jj+=2){ double x1; double x2; x1 = MAX(DCOORD(p->aCoord[jj]), DCOORD(aCell[ii].aCoord[jj])); x2 = MIN(DCOORD(p->aCoord[jj+1]), DCOORD(aCell[ii].aCoord[jj+1])); if( x2<x1 ){ o = 0.0; break; }else{ o = o * (x2-x1); } } overlap += o; } } return overlap;}#endif#if VARIANT_RSTARTREE_CHOOSESUBTREEstatic float cellOverlapEnlargement( Rtree *pRtree, RtreeCell *p, RtreeCell *pInsert, RtreeCell *aCell, int nCell, int iExclude){ float before; float after; before = cellOverlap(pRtree, p, aCell, nCell, iExclude); cellUnion(pRtree, p, pInsert); after = cellOverlap(pRtree, p, aCell, nCell, iExclude); return after-before;}#endif/*** This function implements the ChooseLeaf algorithm from Gutman[84].** ChooseSubTree in r*tree terminology.*/static int ChooseLeaf( Rtree *pRtree, /* Rtree table */ RtreeCell *pCell, /* Cell to insert into rtree */ int iHeight, /* Height of sub-tree rooted at pCell */ RtreeNode **ppLeaf /* OUT: Selected leaf page */){ int rc; int ii; RtreeNode *pNode; rc = nodeAcquire(pRtree, 1, 0, &pNode); for(ii=0; rc==SQLITE_OK && ii<(pRtree->iDepth-iHeight); ii++){ int iCell; sqlite3_int64 iBest; float fMinGrowth; float fMinArea; float fMinOverlap; int nCell = NCELL(pNode); RtreeCell cell; RtreeNode *pChild; RtreeCell *aCell = 0;#if VARIANT_RSTARTREE_CHOOSESUBTREE if( ii==(pRtree->iDepth-1) ){ int jj; aCell = sqlite3_malloc(sizeof(RtreeCell)*nCell); if( !aCell ){ rc = SQLITE_NOMEM; nodeRelease(pRtree, pNode); pNode = 0; continue; } for(jj=0; jj<nCell; jj++){ nodeGetCell(pRtree, pNode, jj, &aCell[jj]); } }#endif /* Select the child node which will be enlarged the least if pCell ** is inserted into it. Resolve ties by choosing the entry with ** the smallest area. */ for(iCell=0; iCell<nCell; iCell++){ float growth; float area; float overlap = 0.0; nodeGetCell(pRtree, pNode, iCell, &cell); growth = cellGrowth(pRtree, &cell, pCell); area = cellArea(pRtree, &cell);#if VARIANT_RSTARTREE_CHOOSESUBTREE if( ii==(pRtree->iDepth-1) ){ overlap = cellOverlapEnlargement(pRtree,&cell,pCell,aCell,nCell,iCell); }#endif if( (iCell==0) || (overlap<fMinOverlap) || (overlap==fMinOverlap && growth<fMinGrowth) || (overlap==fMinOverlap && growth==fMinGrowth && area<fMinArea) ){ fMinOverlap = overlap; fMinGrowth = growth; fMinArea = area; iBest = cell.iRowid; } } sqlite3_free(aCell); rc = nodeAcquire(pRtree, iBest, pNode, &pChild); nodeRelease(pRtree, pNode); pNode = pChild; } *ppLeaf = pNode; return rc;}/*** A cell with the same content as pCell has just been inserted into** the node pNode. This function updates the bounding box cells in** all ancestor elements.*/static void AdjustTree( Rtree *pRtree, /* Rtree table */ RtreeNode *pNode, /* Adjust ancestry of this node. */ RtreeCell *pCell /* This cell was just inserted */){ RtreeNode *p = pNode; while( p->pParent ){ RtreeCell cell; RtreeNode *pParent = p->pParent; int iCell = nodeParentIndex(pRtree, p); nodeGetCell(pRtree, pParent, iCell, &cell); if( cellGrowth(pRtree, &cell, pCell)>0.0 ){ cellUnion(pRtree, &cell, pCell); nodeOverwriteCell(pRtree, pParent, &cell, iCell); } p = pParent; }}/*** Write mapping (iRowid->iNode) to the <rtree>_rowid table.*/static int rowidWrite(Rtree *pRtree, sqlite3_int64 iRowid, sqlite3_int64 iNode){ sqlite3_bind_int64(pRtree->pWriteRowid, 1, iRowid); sqlite3_bind_int64(pRtree->pWriteRowid, 2, iNode); sqlite3_step(pRtree->pWriteRowid); return sqlite3_reset(pRtree->pWriteRowid);}/*** Write mapping (iNode->iPar) to the <rtree>_parent table.*/static int parentWrite(Rtree *pRtree, sqlite3_int64 iNode, sqlite3_int64 iPar){ sqlite3_bind_int64(pRtree->pWriteParent, 1, iNode); sqlite3_bind_int64(pRtree->pWriteParent, 2, iPar); sqlite3_step(pRtree->pWriteParent); return sqlite3_reset(pRtree->pWriteParent);}static int rtreeInsertCell(Rtree *, RtreeNode *, RtreeCell *, int);#if VARIANT_GUTTMAN_LINEAR_SPLIT/*** Implementation of the linear variant of the PickNext() function from** Guttman[84].*/static RtreeCell *LinearPickNext( Rtree *pRtree, RtreeCell *aCell, int nCell, RtreeCell *pLeftBox, RtreeCell *pRightBox, int *aiUsed){ int ii; for(ii=0; aiUsed[ii]; ii++); aiUsed[ii] = 1; return &aCell[ii];}/*** Implementation of the linear variant of the PickSeeds() function from** Guttman[84].*/static void LinearPickSeeds( Rtree *pRtree, RtreeCell *aCell, int nCell, int *piLeftSeed, int *piRightSeed){ int i; int iLeftSeed = 0; int iRightSeed = 1; float maxNormalInnerWidth = 0.0; /* Pick two "seed" cells from the array of cells. The algorithm used ** here is the LinearPickSeeds algorithm from Gutman[1984]. The ** indices of the two seed cells in the array are stored in local ** variables iLeftSeek and iRightSeed. */ for(i=0; i<pRtree->nDim; i++){ float x1 = aCell[0].aCoord[i*2]; float x2 = aCell[0].aCoord[i*2+1]; float x3 = x1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -