📄 mitab_mapfile.cpp
字号:
}
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 + -