📄 mitab_mapfile.cpp
字号:
}
}
else
{
/*---------------------------------------------------------
* Failed positioning input file... CPLError has been called.
*--------------------------------------------------------*/
m_nCurObjPtr = m_nCurObjId = m_nCurObjType = -1;
return -1;
}
return 0;
}
/**********************************************************************
* TABMAPFile::UpdateMapHeaderInfo()
*
* Update .map header information (counter of objects by type and minimum
* required version) in light of a new object to be written to the file.
*
* Called only by PrepareNewObj() and by the TABCollection class.
**********************************************************************/
void TABMAPFile::UpdateMapHeaderInfo(GByte nObjType)
{
/*-----------------------------------------------------------------
* Update count of objects by type in the header block
*----------------------------------------------------------------*/
if (nObjType == TAB_GEOM_SYMBOL ||
nObjType == TAB_GEOM_FONTSYMBOL ||
nObjType == TAB_GEOM_CUSTOMSYMBOL ||
nObjType == TAB_GEOM_MULTIPOINT ||
nObjType == TAB_GEOM_V800_MULTIPOINT ||
nObjType == TAB_GEOM_SYMBOL_C ||
nObjType == TAB_GEOM_FONTSYMBOL_C ||
nObjType == TAB_GEOM_CUSTOMSYMBOL_C ||
nObjType == TAB_GEOM_MULTIPOINT_C ||
nObjType == TAB_GEOM_V800_MULTIPOINT_C )
{
m_poHeader->m_numPointObjects++;
}
else if (nObjType == TAB_GEOM_LINE ||
nObjType == TAB_GEOM_PLINE ||
nObjType == TAB_GEOM_MULTIPLINE ||
nObjType == TAB_GEOM_V450_MULTIPLINE ||
nObjType == TAB_GEOM_V800_MULTIPLINE ||
nObjType == TAB_GEOM_ARC ||
nObjType == TAB_GEOM_LINE_C ||
nObjType == TAB_GEOM_PLINE_C ||
nObjType == TAB_GEOM_MULTIPLINE_C ||
nObjType == TAB_GEOM_V450_MULTIPLINE_C ||
nObjType == TAB_GEOM_V800_MULTIPLINE_C ||
nObjType == TAB_GEOM_ARC_C)
{
m_poHeader->m_numLineObjects++;
}
else if (nObjType == TAB_GEOM_REGION ||
nObjType == TAB_GEOM_V450_REGION ||
nObjType == TAB_GEOM_V800_REGION ||
nObjType == TAB_GEOM_RECT ||
nObjType == TAB_GEOM_ROUNDRECT ||
nObjType == TAB_GEOM_ELLIPSE ||
nObjType == TAB_GEOM_REGION_C ||
nObjType == TAB_GEOM_V450_REGION_C ||
nObjType == TAB_GEOM_V800_REGION_C ||
nObjType == TAB_GEOM_RECT_C ||
nObjType == TAB_GEOM_ROUNDRECT_C ||
nObjType == TAB_GEOM_ELLIPSE_C)
{
m_poHeader->m_numRegionObjects++;
}
else if (nObjType == TAB_GEOM_TEXT ||
nObjType == TAB_GEOM_TEXT_C)
{
m_poHeader->m_numTextObjects++;
}
/*-----------------------------------------------------------------
* Check forminimum TAB file version number
*----------------------------------------------------------------*/
int nVersion = TAB_GEOM_GET_VERSION(nObjType);
if (nVersion > m_nMinTABVersion )
{
m_nMinTABVersion = nVersion;
}
}
/**********************************************************************
* TABMAPFile::PrepareNewObj()
*
* Get ready to write a new object described by poObjHdr (using the
* poObjHdr's m_nId (featureId), m_nType and IntMBR members which must
* have been set by the caller).
*
* Depending on whether "quick spatial index mode" is selected, we either:
*
* 1- Walk through the spatial index to find the best place to insert the
* new object, update the spatial index references, and prepare the object
* data block to be ready to write the object to it.
* ... or ...
* 2- 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.
*
* m_poCurObjBlock will be set to be ready to receive the new object, and
* a new block will be created if necessary (in which case the current
* block contents will be committed to disk, etc.) The actual ObjHdr
* data won't be written to m_poCurObjBlock until CommitNewObj() is called.
*
* If this object type uses coordinate blocks, then the coordinate block
* will be prepared to receive coordinates.
*
* This function will also take care of updating the .ID index entry for
* the new object.
*
* Note that object ids are positive and start at 1.
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABMAPFile::PrepareNewObj(TABMAPObjHdr *poObjHdr)
{
m_nCurObjPtr = m_nCurObjId = m_nCurObjType = -1;
if (m_eAccessMode != TABWrite ||
m_poIdIndex == NULL || m_poHeader == NULL)
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"PrepareNewObj() failed: file not opened for write access.");
return -1;
}
/*-----------------------------------------------------------------
* For objects with no geometry, we just update the .ID file and return
*----------------------------------------------------------------*/
if (poObjHdr->m_nType == TAB_GEOM_NONE)
{
m_nCurObjType = poObjHdr->m_nType;
m_nCurObjId = poObjHdr->m_nId;
m_nCurObjPtr = 0;
m_poIdIndex->SetObjPtr(m_nCurObjId, 0);
return 0;
}
/*-----------------------------------------------------------------
* Update count of objects by type in the header block and minimum
* required version.
*----------------------------------------------------------------*/
UpdateMapHeaderInfo(poObjHdr->m_nType);
/*-----------------------------------------------------------------
* Depending on the selected spatial index mode, we will either insert
* new objects via the spatial index (slower write but results in optimal
* spatial index) or directly in the current ObjBlock (faster write
* but non-optimal spatial index)
*----------------------------------------------------------------*/
if ( !m_bQuickSpatialIndexMode )
{
if (PrepareNewObjViaSpatialIndex(poObjHdr) != 0)
return -1; /* Error already reported */
}
else
{
if (PrepareNewObjViaObjBlock(poObjHdr) != 0)
return -1; /* Error already reported */
}
/*-----------------------------------------------------------------
* Prepare ObjBlock for this new object.
* Real data won't be written to the object block until CommitNewObj()
* is called.
*----------------------------------------------------------------*/
m_nCurObjPtr = m_poCurObjBlock->PrepareNewObject(poObjHdr);
if (m_nCurObjPtr < 0 )
{
CPLError(CE_Failure, CPLE_FileIO,
"Failed writing object header for feature id %d",
poObjHdr->m_nId);
return -1;
}
m_nCurObjType = poObjHdr->m_nType;
m_nCurObjId = poObjHdr->m_nId;
/*-----------------------------------------------------------------
* Update .ID Index
*----------------------------------------------------------------*/
m_poIdIndex->SetObjPtr(m_nCurObjId, m_nCurObjPtr);
/*-----------------------------------------------------------------
* Prepare Coords block...
* create a new TABMAPCoordBlock if it was not done yet.
*----------------------------------------------------------------*/
PrepareCoordBlock(m_nCurObjType, m_poCurObjBlock, &m_poCurCoordBlock);
if (CPLGetLastErrorNo() != 0 && CPLGetLastErrorType() == CE_Failure)
return -1;
return 0;
}
/**********************************************************************
* TABMAPFile::PrepareNewObjViaSpatialIndex()
*
* Used by TABMAPFile::PrepareNewObj() to walk through the spatial index
* to find the best place to insert the new object, update the spatial
* index references, and prepare the object data block to be ready to
* write the object to it.
*
* This method is used when "quick spatial index mode" is NOT selected,
* i.e. when we want to produce a file with an optimal spatial index
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABMAPFile::PrepareNewObjViaSpatialIndex(TABMAPObjHdr *poObjHdr)
{
int nObjSize;
GInt32 nObjBlockForInsert = -1;
/*-----------------------------------------------------------------
* Create spatial index if we don't have one yet.
* We do not create the index and object data blocks in the open()
* call because files that contained only "NONE" geometries ended up
* with empty object and spatial index blocks.
*----------------------------------------------------------------*/
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();
/* We'll also need to create an object data block (later) */
nObjBlockForInsert = -1;
CPLAssert(m_poCurObjBlock == NULL);
}
else
/*-----------------------------------------------------------------
* Search the spatial index to find the best place to insert this
* new object.
*----------------------------------------------------------------*/
{
nObjBlockForInsert=m_poSpIndex->ChooseLeafForInsert(poObjHdr->m_nMinX,
poObjHdr->m_nMinY,
poObjHdr->m_nMaxX,
poObjHdr->m_nMaxY);
if (nObjBlockForInsert == -1)
{
/* ChooseLeafForInsert() should not fail unless file is corrupt*/
CPLError(CE_Failure, CPLE_AssertionFailed,
"ChooseLeafForInsert() Failed?!?!");
return -1;
}
}
if (nObjBlockForInsert == -1)
{
/*-------------------------------------------------------------
* Create a new object data block from scratch
*------------------------------------------------------------*/
m_poCurObjBlock = new TABMAPObjectBlock(TABReadWrite);
int nBlockOffset = m_oBlockManager.AllocNewBlock();
m_poCurObjBlock->InitNewBlock(m_fp, 512, nBlockOffset);
/*-------------------------------------------------------------
* Insert new object block in index, based on MBR of poObjHdr
*------------------------------------------------------------*/
if (m_poSpIndex->AddEntry(poObjHdr->m_nMinX,
poObjHdr->m_nMinY,
poObjHdr->m_nMaxX,
poObjHdr->m_nMaxY,
m_poCurObjBlock->GetStartAddress()) != 0)
return -1;
m_poHeader->m_nMaxSpIndexDepth = MAX(m_poHeader->m_nMaxSpIndexDepth,
m_poSpIndex->GetCurMaxDepth()+1);
}
else
{
/*-------------------------------------------------------------
* Load existing object and Coord blocks, unless we've already
* got the right object block in memory
*------------------------------------------------------------*/
if (m_poCurObjBlock &&
m_poCurObjBlock->GetStartAddress() != nObjBlockForInsert)
{
/* Got a block in memory but it's not the right one, flush it */
if (CommitObjAndCoordBlocks(TRUE) != 0 )
return -1;
}
if (m_poCurObjBlock == NULL)
{
if (LoadObjAndCoordBlocks(nObjBlockForInsert) != 0)
return -1;
// The ObjBlock doesn't know its MBR. Get the value from the
// index and set it
GInt32 nMinX, nMinY, nMaxX, nMaxY;
m_poSpIndex->GetCurLeafEntryMBR(m_poCurObjBlock->GetStartAddress(),
nMinX, nMinY, nMaxX, nMaxY);
m_poCurObjBlock->SetMBR(nMinX, nMinY, nMaxX, nMaxY);
}
}
/*-----------------------------------------------------------------
* Fetch new object size, make sure there is enough room in obj.
* block for new object, update spatial index and split if necessary.
*----------------------------------------------------------------*/
nObjSize = m_poHeader->GetMapObjectSize(poObjHdr->m_nType);
if (m_poCurObjBlock->GetNumUnusedBytes() >= nObjSize )
{
/*-------------------------------------------------------------
* New object fits in current block, just update the spatial index
*------------------------------------------------------------*/
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -