Ejemplo n.º 1
0
static void DumpBlocks( TABMAPFile *poMF, int nFileOffset )

{
    TABRawBinBlock *poBlock;
    
    poBlock = poMF->GetIndexObjectBlock( nFileOffset );
    if( poBlock == NULL )
        return;

    if( poBlock->GetBlockType() == TABMAP_INDEX_BLOCK )
    {
        TABMAPIndexBlock *poIndexBlock = (TABMAPIndexBlock *) poBlock;
        int i;

#ifdef DEBUG
        poIndexBlock->Dump( stdout );
#else
        printf("poIndexBlock->Dump() available inly with -DDEBUG\n");
#endif

        for( i = 0; i < poIndexBlock->GetNumEntries(); i++ )
        {
            TABMAPIndexEntry *poEntry = poIndexBlock->GetEntry( i );

            DumpBlocks( poMF, poEntry->nBlockPtr );
        }
    }
    else if( poBlock->GetBlockType() == TABMAP_OBJECT_BLOCK )
    {
        TABMAPObjectBlock *poObjectBlock = (TABMAPObjectBlock *) poBlock;

#ifdef DEBUG
        poObjectBlock->Dump( stdout );
#else
        printf("poObjectBlock->Dump() available inly with -DDEBUG\n");
#endif
    }
}
Ejemplo n.º 2
0
/**********************************************************************
 *                   TABMAPIndexBlock::SplitNode()
 *
 * Split current Node, update the references in the parent node, etc.
 * Note that Root Nodes cannot be split using this method... SplitRootNode()
 * should be used instead.
 *
 * nNewEntryX, nNewEntryY are the coord. of the center of the new entry that 
 * will be added after the split.  The split is done so that the current
 * node will be the one in which the new object should be stored.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int     TABMAPIndexBlock::SplitNode(int nNewEntryX, int nNewEntryY)
{
    int nSrcEntries = m_numEntries;
    int nWidth, nHeight, nCenterX1, nCenterY1, nCenterX2, nCenterY2;

    CPLAssert(m_poBlockManagerRef);

    /*-----------------------------------------------------------------
     * Create a 2nd node, and assign both nodes a MBR that is half
     * of the biggest dimension (width or height) of the current node's MBR
     *
     * We also want to keep this node's current child in here.
     * Since splitting happens only during an addentry() operation and 
     * then both the current child and nNewEntryX/Y should fit in the same
     * area.
     *----------------------------------------------------------------*/
    TABMAPIndexBlock *poNewNode = new TABMAPIndexBlock(m_eAccess);
    if (poNewNode->InitNewBlock(m_fp, 512, 
                                m_poBlockManagerRef->AllocNewBlock()) != 0)
    {
        return -1;
    }
    poNewNode->SetMAPBlockManagerRef(m_poBlockManagerRef);


    nWidth = ABS(m_nMaxX - m_nMinX);
    nHeight = ABS(m_nMaxY - m_nMinY);

    if (nWidth > nHeight)
    {
        // Split node horizontally
        nCenterY1 = nCenterY2 = m_nMinY + nHeight/2;

        if (nNewEntryX < (m_nMinX + m_nMaxX)/2)
        {
            nCenterX1 = m_nMinX + nWidth/4;
            nCenterX2 = m_nMaxX - nWidth/4;
        }
        else
        {
            nCenterX2 = m_nMinX + nWidth/4;
            nCenterX1 = m_nMaxX - nWidth/4;
        }
    }
    else
    {
        // Split node vertically
        nCenterX1 = nCenterX2 = m_nMinX + nWidth/2;

        if (nNewEntryY < (m_nMinY + m_nMaxY)/2)
        {
            nCenterY1 = m_nMinY + nHeight/4;
            nCenterY2 = m_nMaxY - nHeight/4;
        }
        else
        {
            nCenterY2 = m_nMinY + nHeight/4;
            nCenterY1 = m_nMaxY - nHeight/4;
        }
    }

    /*-----------------------------------------------------------------
     * Go through all entries and assign them to one of the 2 nodes.
     *
     * Criteria is that entries are assigned to the node in which their
     * center falls.
     *
     * Hummm... this does not prevent the possibility that one of the
     * 2 nodes might end up empty at the end.
     *----------------------------------------------------------------*/
    m_numEntries = 0;
    for(int iEntry=0; iEntry<nSrcEntries; iEntry++)
    {
        int nEntryCenterX = (m_asEntries[iEntry].XMax +
                             m_asEntries[iEntry].XMin) / 2;
        int nEntryCenterY = (m_asEntries[iEntry].YMax +
                             m_asEntries[iEntry].YMin) / 2;

        if (iEntry == m_nCurChildIndex ||
            (nWidth > nHeight && 
             ABS(nEntryCenterX-nCenterX1) < ABS(nEntryCenterX-nCenterX2)) ||
            (nWidth <= nHeight &&
             ABS(nEntryCenterY-nCenterY1) < ABS(nEntryCenterY-nCenterY2) ) )
        {
            // This entry stays in current node.
            InsertEntry(m_asEntries[iEntry].XMin, m_asEntries[iEntry].YMin,
                        m_asEntries[iEntry].XMax, m_asEntries[iEntry].YMax,
                        m_asEntries[iEntry].nBlockPtr);

            // We have to keep track of new m_nCurChildIndex value
            if (iEntry == m_nCurChildIndex) 
            {
                m_nCurChildIndex = m_numEntries-1;
            }
        }
        else
        {
            // This entry goes in the new node.
            poNewNode->InsertEntry(m_asEntries[iEntry].XMin, 
                                   m_asEntries[iEntry].YMin,
                                   m_asEntries[iEntry].XMax, 
                                   m_asEntries[iEntry].YMax,
                                   m_asEntries[iEntry].nBlockPtr);
        }
    }

    /*-----------------------------------------------------------------
     * If no entry was moved to second node, then move ALL entries except
     * the current child to the second node... this way current node will
     * have room for a new entry when this function exits.
     *----------------------------------------------------------------*/
    if (poNewNode->GetNumEntries() == 0)
    {
        nSrcEntries = m_numEntries;
        m_numEntries = 0;
        for(int iEntry=0; iEntry<nSrcEntries; iEntry++)
        {
            if (iEntry == m_nCurChildIndex)
            {
                // Keep current child in current node
                InsertEntry(m_asEntries[iEntry].XMin, 
                            m_asEntries[iEntry].YMin,
                            m_asEntries[iEntry].XMax,
                            m_asEntries[iEntry].YMax,
                            m_asEntries[iEntry].nBlockPtr);
                m_nCurChildIndex = m_numEntries-1;
            }
            else
            {
                // All other entries go to second node
                poNewNode->InsertEntry(m_asEntries[iEntry].XMin, 
                                       m_asEntries[iEntry].YMin,
                                       m_asEntries[iEntry].XMax, 
                                       m_asEntries[iEntry].YMax,
                                       m_asEntries[iEntry].nBlockPtr);
            }
        }
    }

    /*-----------------------------------------------------------------
     * Recompute MBR and update current node info in parent
     *----------------------------------------------------------------*/
    RecomputeMBR();
    poNewNode->RecomputeMBR();

    /*-----------------------------------------------------------------
     * Add second node info to parent and then flush it to disk.
     * This may trigger splitting of parent
     *----------------------------------------------------------------*/
    CPLAssert(m_poParentRef);
    int nMinX, nMinY, nMaxX, nMaxY;
    poNewNode->GetMBR(nMinX, nMinY, nMaxX, nMaxY);
    m_poParentRef->AddEntry(nMinX, nMinY, nMaxX, nMaxY,
                            poNewNode->GetNodeBlockPtr(), TRUE);
    poNewNode->CommitToFile();
    delete poNewNode;

    return 0;
}