⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mitab_mapfile.cpp

📁 mitab,读取MapInfo的地图文件
💻 CPP
📖 第 1 页 / 共 5 页
字号:
    }
    else
    {
        /*-------------------------------------------------------------
         * OK, the new object won't fit in the current block, need to split
         * and update index.
         * Split() does its job so that the current obj block will remain 
         * the best candidate to receive the new object. It also flushes 
         * everything to disk and will update m_poCurCoordBlock to point to
         * the last coord block in the chain, ready to accept new data
         *------------------------------------------------------------*/
        TABMAPObjectBlock *poNewObjBlock;
        poNewObjBlock= SplitObjBlock(poObjHdr, nObjSize);

        if (poNewObjBlock == NULL)
            return -1;  /* Split failed, error already reported. */

        /*-------------------------------------------------------------
         * Update index with info about m_poCurObjectBlock *first*
         * This is important since UpdateLeafEntry() needs the chain of
         * index nodes preloaded by ChooseLeafEntry() in order to do its job
         *------------------------------------------------------------*/
        GInt32 nMinX, nMinY, nMaxX, nMaxY;
        m_poCurObjBlock->GetMBR(nMinX, nMinY, nMaxX, nMaxY);

        /* Need to calculate the enlarged MBR that includes new object */
        nMinX = MIN(nMinX, poObjHdr->m_nMinX);
        nMinY = MIN(nMinY, poObjHdr->m_nMinY);
        nMaxX = MAX(nMaxX, poObjHdr->m_nMaxX);
        nMaxY = MAX(nMaxY, poObjHdr->m_nMaxY);

        if (m_poSpIndex->UpdateLeafEntry(m_poCurObjBlock->GetStartAddress(),
                                         nMinX, nMinY, nMaxX, nMaxY) != 0)
            return -1;

        /*-------------------------------------------------------------
         * Add new obj block to index
         *------------------------------------------------------------*/
        poNewObjBlock->GetMBR(nMinX, nMinY, nMaxX, nMaxY);

        if (m_poSpIndex->AddEntry(nMinX, nMinY, nMaxX, nMaxY,
                                  poNewObjBlock->GetStartAddress()) != 0)
            return -1;
        m_poHeader->m_nMaxSpIndexDepth = MAX(m_poHeader->m_nMaxSpIndexDepth,
                                             m_poSpIndex->GetCurMaxDepth()+1);

        /*-------------------------------------------------------------
         * Delete second object block, no need to commit to file first since
         * it's already been committed to disk by Split()
         *------------------------------------------------------------*/
        delete poNewObjBlock;
    }

    return 0;
}

/**********************************************************************
 *                   TABMAPFile::PrepareNewObjViaObjBlock()
 *
 * Used by TABMAPFile::PrepareNewObj() to prepare the current object 
 * data block to be ready to write the object to it. If the object block 
 * is full then it is inserted in the spatial index and committed to disk,
 * and a new obj block is created.
 *
 * This method is used when "quick spatial index mode" is selected,
 * i.e. faster write, but non-optimal spatial index.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int   TABMAPFile::PrepareNewObjViaObjBlock(TABMAPObjHdr *poObjHdr)
{
    int nObjSize;

    /*-------------------------------------------------------------
     * We will need an object block... check if it exists and
     * create it if it has not been created yet (first time for this file).
     * We do not create the object block in the open() call because
     * files that contained only "NONE" geometries ended up with empty
     * object and spatial index blocks.
     * Note: A coord block will be created only if needed later.
     *------------------------------------------------------------*/
    if (m_poCurObjBlock == NULL)
    {
        m_poCurObjBlock = new TABMAPObjectBlock(m_eAccessMode);

        int nBlockOffset = m_oBlockManager.AllocNewBlock();

        m_poCurObjBlock->InitNewBlock(m_fp, 512, nBlockOffset);

        // The reference to the first object block should 
        // actually go through the index blocks... this will be 
        // updated when file is closed.
        m_poHeader->m_nFirstIndexBlock = nBlockOffset;
    }

    /*-----------------------------------------------------------------
     * Fetch new object size, make sure there is enough room in obj. 
     * block for new object, and save/create a new one if necessary.
     *----------------------------------------------------------------*/
    nObjSize = m_poHeader->GetMapObjectSize(poObjHdr->m_nType);
    if (m_poCurObjBlock->GetNumUnusedBytes() < nObjSize )
    {
        /*-------------------------------------------------------------
         * OK, the new object won't fit in the current block. Add the
         * current block to the spatial index, commit it to disk and init
         * a new block
         *------------------------------------------------------------*/
        CommitObjAndCoordBlocks(FALSE);

        if (m_poCurObjBlock->InitNewBlock(m_fp,512,
                                  m_oBlockManager.AllocNewBlock())!=0)
            return -1; /* Error already reported */

        /*-------------------------------------------------------------
         * Coord block has been committed to disk but not deleted.
         * Delete it to require the creation of a new coord block chain
         * as needed.
         *-------------------------------------------------------------*/
        if (m_poCurCoordBlock)
        {
            delete m_poCurCoordBlock;
            m_poCurCoordBlock = NULL;
        }

    }

    return 0;
}

/**********************************************************************
 *                   TABMAPFile::CommitNewObj()
 *
 * Commit object header data to the ObjBlock. Should be called after 
 * PrepareNewObj, once all members of the ObjHdr have been set.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int   TABMAPFile::CommitNewObj(TABMAPObjHdr *poObjHdr)
{
    return m_poCurObjBlock->CommitNewObject(poObjHdr);
}


/**********************************************************************
 *                   TABMAPFile::CommitObjAndCoordBlocks()
 *
 * Commit the TABMAPObjBlock and TABMAPCoordBlock to disk.
 *
 * The objects are deleted from memory if bDeleteObjects==TRUE.
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int TABMAPFile::CommitObjAndCoordBlocks(GBool bDeleteObjects /*=FALSE*/)
{
    int nStatus = 0;

    /*-----------------------------------------------------------------
     * First check that a objBlock has been created.  It is possible to have
     * no object block in files that contain only "NONE" geometries.
     *----------------------------------------------------------------*/
    if (m_poCurObjBlock == NULL)
        return 0; 

    if (m_eAccessMode != TABWrite)
    {
        CPLError(CE_Failure, CPLE_AssertionFailed,
                 "CommitObjAndCoordBlocks() failed: file not opened for write access.");
        return -1;
    }

    /*-----------------------------------------------------------------
     * We need to flush the coord block if there was one
     * since a list of coord blocks can belong to only one obj. block
     *----------------------------------------------------------------*/
    if (m_poCurCoordBlock)
    {
        // Update the m_nMaxCoordBufSize member in the header block
        //
        int nTotalCoordSize = m_poCurCoordBlock->GetNumBlocksInChain()*512;
        if (nTotalCoordSize > m_poHeader->m_nMaxCoordBufSize)
            m_poHeader->m_nMaxCoordBufSize = nTotalCoordSize;

        // Update the references to this coord block in the MAPObjBlock
        //
        m_poCurObjBlock->AddCoordBlockRef(m_poCurCoordBlock->
                                                         GetStartAddress());
        nStatus = m_poCurCoordBlock->CommitToFile();

        if (bDeleteObjects)
        {
            delete m_poCurCoordBlock;
            m_poCurCoordBlock = NULL;
        }
    }

    /*-----------------------------------------------------------------
     * Commit the obj block
     *----------------------------------------------------------------*/
    if (nStatus == 0)
    {
        nStatus = m_poCurObjBlock->CommitToFile();
    }


    /*-----------------------------------------------------------------
     * Update the spatial index ** only in "quick spatial index" mode ** 
     * In the (default) optimized spatial index mode, the spatial index 
     * is already maintained up to date as part of inserting the objects in
     * PrepareNewObj().
     *
     * Spatial index will be created here if it was not done yet.
     *----------------------------------------------------------------*/
    if (nStatus == 0 && m_bQuickSpatialIndexMode)
    {
        GInt32 nXMin, nYMin, nXMax, nYMax;

        if (m_poSpIndex == NULL)
        {
            // Spatial Index not created yet...
            m_poSpIndex = new TABMAPIndexBlock(m_eAccessMode);

            m_poSpIndex->InitNewBlock(m_fp, 512, 
                                      m_oBlockManager.AllocNewBlock());
            m_poSpIndex->SetMAPBlockManagerRef(&m_oBlockManager);

            m_poHeader->m_nFirstIndexBlock = m_poSpIndex->GetNodeBlockPtr();
        }

        m_poCurObjBlock->GetMBR(nXMin, nYMin, nXMax, nYMax);
        nStatus = m_poSpIndex->AddEntry(nXMin, nYMin, nXMax, nYMax,
                                        m_poCurObjBlock->GetStartAddress());

        m_poHeader->m_nMaxSpIndexDepth = MAX(m_poHeader->m_nMaxSpIndexDepth,
                                             m_poSpIndex->GetCurMaxDepth()+1);
    }

    /*-----------------------------------------------------------------
     * Delete obj block only if requested
     *----------------------------------------------------------------*/
    if (bDeleteObjects)
    {
        delete m_poCurObjBlock;
        m_poCurObjBlock = NULL;
    }

    return nStatus;
}

/**********************************************************************
 *                   TABMAPFile::LoadObjAndCoordBlocks()
 *
 * Load the TABMAPObjBlock at specified address and corresponding 
 * TABMAPCoordBlock, ready to write new objects to them.
 *
 * It is assumed that pre-existing m_poCurObjBlock and m_poCurCoordBlock 
 * have been flushed to disk already using CommitObjAndCoordBlocks()
 *
 * Returns 0 on success, -1 on error.
 **********************************************************************/
int TABMAPFile::LoadObjAndCoordBlocks(GInt32 nBlockPtr)
{
    TABRawBinBlock *poBlock = NULL;

    /*-----------------------------------------------------------------
     * In Write mode, if an object block is already in memory then flush it
     *----------------------------------------------------------------*/
    if (m_eAccessMode == TABWrite && m_poCurObjBlock != NULL)
    {
        int nStatus = CommitObjAndCoordBlocks(TRUE);
        if (nStatus != 0)
            return nStatus;
    }

    /*-----------------------------------------------------------------
     * Load Obj Block
     *----------------------------------------------------------------*/
    if ((poBlock = TABCreateMAPBlockFromFile(m_fp, 
                                             nBlockPtr,
                                             512, TRUE, TABReadWrite)) &&
        poBlock->GetBlockClass() == TABMAP_OBJECT_BLOCK)
    {
        m_poCurObjBlock = (TABMAPObjectBlock*)poBlock;
        poBlock = NULL;
    }
    else
    {
        CPLError(CE_Failure, CPLE_FileIO,
                 "LoadObjAndCoordBlocks() failed for object block at %d.", 
                 nBlockPtr);
        return -1;
    }

    /*-----------------------------------------------------------------
     * Load the last coord block in the chain
     *----------------------------------------------------------------*/
    if (m_poCurObjBlock->GetLastCoordBlockAddress() == 0)
    {
        m_poCurCoordBlock = NULL;
    }
    else if ((poBlock = TABCreateMAPBlockFromFile(m_fp, 
                                   m_poCurObjBlock->GetLastCoordBlockAddress(),
                                                  512, TRUE, TABReadWrite)) &&
             poBlock->GetBlockClass() == TABMAP_COORD_BLOCK)
    {
        m_poCurCoordBlock = (TABMAPCoordBlock*)poBlock;
        m_poCurCoordBlock->SetMAPBlockManagerRef(&m_oBlockManager);
        poBlock = NULL;
    }
    else
    {
        CPLError(CE_Failure, CPLE_FileIO,
                 "LoadObjAndCoordBlocks() failed for coord block at %d.", 
                 m_poCurObjBlock->GetLastCoordBlockAddress());
        return -1;
    }

    return 0;
}

/**********************************************************************
 *                   TABMAPFile::SplitObjBlock()
 *
 * Split m_poCurObjBlock using Guttman algorithm.
 *
 * SplitObjBlock() doe its job so that the current obj block will remain 
 * the best candidate to receive the new object to add. It also flushes
 * everything to disk and will update m_poCurCoordBlock to point to the 
 * last coord block in the chain, ready to accept new data
 *
 * Updates to the spatial index are left to the caller.
 *
 * Returns the TABMAPObjBlock of the second block for use by the caller
 * in updating the spatial index, or NULL in case of error.
 **********************

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -