Exemplo n.º 1
0
/**********************************************************************
 *                   TABMAPIndexBlock::SplitRootNode()
 *
 * (private method)
 *
 * Split a Root Node.
 * First, a level of nodes must be added to the tree, then the contents
 * of what used to be the root node is moved 1 level down and then that
 * node is split like a regular node.
 *
 * Returns 0 on success, -1 on error
 **********************************************************************/
int TABMAPIndexBlock::SplitRootNode(int nNewEntryX, int nNewEntryY)
{
    CPLAssert(m_poBlockManagerRef);
    CPLAssert(m_poParentRef == NULL);

    /*-----------------------------------------------------------------
     * Since a root note cannot be split, we add a level of nodes
     * under it and we'll do the split at that level.
     *----------------------------------------------------------------*/
    TABMAPIndexBlock *poNewNode = new TABMAPIndexBlock(m_eAccess);

    if (poNewNode->InitNewBlock(m_fp, 512, 
                                m_poBlockManagerRef->AllocNewBlock()) != 0)
    {
        return -1;
    }
    poNewNode->SetMAPBlockManagerRef(m_poBlockManagerRef);

    // Move all entries to the new child
    int nSrcEntries = m_numEntries;
    m_numEntries = 0;
    for(int iEntry=0; iEntry<nSrcEntries; iEntry++)
    {
        poNewNode->InsertEntry(m_asEntries[iEntry].XMin, 
                               m_asEntries[iEntry].YMin,
                               m_asEntries[iEntry].XMax, 
                               m_asEntries[iEntry].YMax,
                               m_asEntries[iEntry].nBlockPtr);
    }
    
    /*-----------------------------------------------------------------
     * Transfer current child object to new node.
     *----------------------------------------------------------------*/
    if (m_poCurChild)
    {
        poNewNode->SetCurChildRef(m_poCurChild, m_nCurChildIndex);
        m_poCurChild->SetParentRef(poNewNode);
        m_poCurChild = NULL;
        m_nCurChildIndex = -1;
    }

    /*-----------------------------------------------------------------
     * Place info about new child in current node.
     *----------------------------------------------------------------*/
    poNewNode->RecomputeMBR();
    int nMinX, nMinY, nMaxX, nMaxY;
    poNewNode->GetMBR(nMinX, nMinY, nMaxX, nMaxY);
    InsertEntry(nMinX, nMinY, nMaxX, nMaxY, poNewNode->GetNodeBlockPtr());

    /*-----------------------------------------------------------------
     * Keep a reference to the new child
     *----------------------------------------------------------------*/
    poNewNode->SetParentRef(this);
    m_poCurChild = poNewNode;
    m_nCurChildIndex = m_numEntries -1;

    /*-----------------------------------------------------------------
     * And finally force the child to split itself
     *----------------------------------------------------------------*/
    return m_poCurChild->SplitNode(nNewEntryX, nNewEntryY);
}
Exemplo 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;
}