最近在使用GDAL創建PCIDSK格式的矢量數據,發現創建點和線的矢量數據都沒問題,創建面狀的只有屬性表沒有圖形。在GDAL官網說明也寫的是支持的,地址爲:http://www.gdal.org/frmt_pcidsk.html。
實在沒辦法,翻看GDAL源碼才發現,SetFeature的時候,只寫了wkbPoint和wkbLineString類型,其他的加了句Debug代碼如下:
CPLDebug( "PCIDSK", "Unsupported geometry type in SetFeature(): %s",
poGeometry->getGeometryName() );
這也太……沒辦法只好自己研究研究補齊了。通過查看GDAL讀取發現,對於面狀的矢量,PCIDSK在矢量段裏面的屬性表裏面多存了一個字段,叫RingStart,類型爲IntList,用來存儲多邊形中各個環的起始點號。對於PCIDSK的矢量數據,所有的點都是存儲在一個大的數組裏面的,對於多邊形而言,可能有多個環組成,這些環裏面所有的點全部都存在一個數組中,如何來區分每個環的頂點座標,就需要通過RingStart裏面的值來進行分割。知道了存儲的原理,那麼就按照這個原理將寫多邊形的部分補上就可以了。修改後的代碼如下:
else if( wkbFlatten(poGeometry->getGeometryType()) == wkbPolygon )
{
OGRPolygon *poPoly = (OGRPolygon *) poGeometry;
int nRingSize = poPoly->getNumInteriorRings();
std::vector<PCIDSK::int32> anRingStart;
anRingStart.resize(nRingSize+1);
OGRLinearRing *poRing = NULL;
poRing = poPoly->getExteriorRing();
anRingStart[0] = poRing->getNumPoints();
aoVertices.resize(poRing->getNumPoints());
for(int i = 0; i < aoVertices.size(); i++ )
{
aoVertices[i].x = poRing->getX(i);
aoVertices[i].y = poRing->getY(i);
aoVertices[i].z = poRing->getZ(i);
}
for (int iRing=0; iRing < nRingSize; iRing++)
{
int nCurrentStart = aoVertices.size();
poRing = poPoly->getInteriorRing(iRing);
anRingStart[iRing+1] = nCurrentStart + poRing->getNumPoints();
aoVertices.resize(nCurrentStart + poRing->getNumPoints());
for(int i = nCurrentStart; i < aoVertices.size(); i++ )
{
aoVertices[i].x = poRing->getX(i-nCurrentStart);
aoVertices[i].y = poRing->getY(i-nCurrentStart);
aoVertices[i].z = poRing->getZ(i-nCurrentStart);
}
}
if(iRingStartField == -1)
{
iRingStartField = poVecSeg->GetFieldCount();
//poVecSeg->AddField( "RingStart", PCIDSK::FieldTypeCountedInt, "", "" );
OGRFieldDefn oField( "RingStart", OFTIntegerList );
//oField.SetWidth(100);
CreateField( &oField );
}
std::vector<PCIDSK::ShapeField> aoShapeFields;
poVecSeg->GetFields(id, aoShapeFields);
aoShapeFields[iRingStartField].SetValue(anRingStart);
poVecSeg->SetFields( id, aoShapeFields );
}
修改完之後,重新編譯GDAL就可以了。
=======================修改於2015年1月9日========================
通過上面的代碼是可以生成一個面狀的pix文件,使用GDAL打開也沒問題,但是使用Focus或者MosaicTool打開的時候會造成這兩個程序崩潰,同時屬性值顯示會有一定點問題。今天再仔細查看了下讀取部分的代碼,發現對於沒有內環的多邊形,也就是說一個Feature裏面只有一個多邊形的時候,不需要寫RingStart這個屬性值,只有含油內環的時候,也就是多邊形中有內環的時候才需要,所以將上面的代碼修改爲下面的代碼:
else if( wkbFlatten(poGeometry->getGeometryType()) == wkbPolygon )
{
OGRPolygon *poPoly = (OGRPolygon *) poGeometry;
OGRLinearRing *poRing = NULL;
poRing = poPoly->getExteriorRing();
aoVertices.resize(poRing->getNumPoints());
for(int i = 0; i < aoVertices.size(); i++ )
{
aoVertices[i].x = poRing->getX(i);
aoVertices[i].y = poRing->getY(i);
aoVertices[i].z = poRing->getZ(i);
}
int nRingSize = poPoly->getNumInteriorRings();
if(nRingSize > 0 )
{
std::vector<PCIDSK::int32> anRingStart;
anRingStart.resize(nRingSize+1);
anRingStart[0] = poRing->getNumPoints();
for (int iRing=0; iRing < nRingSize; iRing++)
{
int nCurrentStart = aoVertices.size();
poRing = poPoly->getInteriorRing(iRing);
anRingStart[iRing+1] = nCurrentStart + poRing->getNumPoints();
aoVertices.resize(nCurrentStart + poRing->getNumPoints());
for(int i = nCurrentStart; i < aoVertices.size(); i++ )
{
aoVertices[i].x = poRing->getX(i-nCurrentStart);
aoVertices[i].y = poRing->getY(i-nCurrentStart);
aoVertices[i].z = poRing->getZ(i-nCurrentStart);
}
}
if(iRingStartField == -1)
{
iRingStartField = poVecSeg->GetFieldCount();
OGRFieldDefn oField( "RingStart", OFTIntegerList );
CreateField( &oField );
}
std::vector<PCIDSK::ShapeField> aoShapeFields;
poVecSeg->GetFields(id, aoShapeFields);
aoShapeFields[iRingStartField].SetValue(anRingStart);
poVecSeg->SetFields( id, aoShapeFields );
}
}
通過測試發現,這下生成的使用Foucs和MosaicTool可以正常打開,程序也不會出現崩潰的情況,但是屬性值顯示仍然有點小問題,不過已經不影響使用了。