這篇文檔是為了說明怎樣從一個檔案裡用OGR的C++類讀取和寫入資料。強烈建議在讀此文檔之前首先閱讀介紹OGR體繫結構介紹文檔,裡面介紹了OGR裡主要的類以及他們所完成的功能。
從OGR 讀取資料 為了描述如何通過OGR讀取資料,我們編寫一個小的樣本,從OGR檔案裡讀出資料,並按照一定格式輸出。 首先我們需要註冊我們渴望讀取的所有格式。這個通過調用OGRRegisterAll()就能很容易完成,這個函數註冊了GDAL/OGR支援的所有格式。#i nclude "ogrsf_frmts.h"int main(){
OGRRegisterAll(); 下一步我們將開啟輸入的OGR資料檔案。資料檔案可以是檔案,關係型資料庫,檔案路徑,甚至可能是遠端網路服務,這點取決於我們使用的驅動。但是,資料來源的名字通常只是一個簡單的字串。既然這樣拿我們就編寫一個開啟shapefile的程式。第二個參數(FLALSE)告訴OGRSFDriverRegistrar::Open() 函數我們不需要update access。如果失敗返回NULL,並報錯。 OGRDataSource *poDS; poDS = OGRSFDriverRegistrar::Open( "point.shp", FALSE );
if( poDS == NULL )
{
printf( "Open failed.\n" );
exit( 1 );
} 一個OGRDataSource可能包含很多的層。所包含層的數量我們可以用過調OGRDataSource::GetLayerCount()得到,並且其中每一個曾我們利用索引調用OGRDataSource::GetLayer()得到。不過,我們現在利用層的名字。 OGRLayer *poLayer; poLayer = poDS->GetLayerByName( "point" ); 現在我們開始讀取層裡面的features。在開始之前我們需要指定一個attribute或者spatial filter來嚴格控制我們得到的feature。不過現在我們只是得到所有的features。 自從我們開始fresh with這個層,就沒有這麼嚴格了。很明智地我們需要調用Layer::ResetReading()來確保我們是從層的開頭開始。我們不斷地調用OGRLayer::GetNextFeature()函數來遍曆所有的features,當遍曆完所有的features後返回NULL。 OGRFeature *poFeature; poLayer->ResetReading();
while( (poFeature = poLayer->GetNextFeature()) != NULL )
{ 為了得到一個feature的所有屬性fields,調用OGRFeatureDefn將很方便。這是一個object,與層相關聯,包含所有fields的定義。我們迴圈完所有的fields,得到屬性資料並將之顯示出來。 OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
int iField; for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
{
OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn( iField ); if( poFieldDefn->GetType() == OFTInteger )
printf( "%d,", poFeature->GetFieldAsInteger( iField ) );
else if( poFieldDefn->GetType() == OFTReal )
printf( "%.3f,", poFeature->GetFieldAsDouble(iField) );
else if( poFieldDefn->GetType() == OFTString )
printf( "%s,", poFeature->GetFieldAsString(iField) );
else
printf( "%s,", poFeature->GetFieldAsString(iField) );
} 實際中field的種類比上面列出來的多,但是我們可以通過調用OGRFeature::GetFieldAsString()的方法將之統一提取出來。實際上如果我們用OGRFeature::GetFieldAsString()將會使程式更簡短。 下一步我們想從feature裡面提取出幾何(geometry)資料,並且n他的x和y座標標出。幾何資料通過統一的 OGRGeometry指標返回。然後我們確定這個幾何資料的類型,如果是點,我們將他標為點並且進行操作,如果是其他的內省我們write預留位置。 OGRGeometry *poGeometry; poGeometry = poFeature->GetGeometryRef();
if( poGeometry != NULL
&& wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
{
OGRPoint *poPoint = (OGRPoint *) poGeometry; printf( "%.3f,%3.f\n", poPoint->getX(), poPoint->getY() );
}
else
{
printf( "no point geometry\n" );
} 上面我們使用的這個wkbFlatten()宏是將一個wkbPoint25D(具有Z座標的點)轉化為基於2D的類型(wkbPoint)。對於每一個2D幾何類型都有一個2.5D的type code。但是,我們只有基於2D和3D的C++類。因此,我們的代碼可以完全處理2D或3D的例子。 注意 OGRFeature::GetGeometryRef()返回一個指向屬於OGRFeature的內部幾何資料的指標。我們並沒有實際地刪除返回的幾何資料。但是, OGRLayer::GetNextFeature()函數返回了一個現在屬於我們自身的feature的拷貝。因此,在用完之後,我們需要釋放這個feature。我們可以僅僅“delete”它,but this can cause problems in windows builds where the GDAL DLL has a different
"heap" from the main program.為了安全起見我們利用一個GDAL函數去刪除它。 OGRFeature::DestroyFeature( poFeature );
} OGRDataSource::GetLayerByName()函數返回的OGRLayer是OGRDataSource中的一個層,因此我們沒有必要刪除它,但是我們需要刪除這個資料檔案從而關閉輸入的檔案。再一次我們利用這個custom delete來避免win32 heap 問題。 OGRDataSource::DestroyDataSource( poDS );
} 以上所有的放在一起,我們的程式如下:#i nclude "ogrsf_frmts.h"int main(){
OGRRegisterAll(); OGRDataSource *poDS; poDS = OGRSFDriverRegistrar::Open( "point.shp", FALSE );
if( poDS == NULL )
{
printf( "Open failed.\n%s" );
exit( 1 );
} OGRLayer *poLayer; poLayer = poDS->GetLayerByName( "point" ); OGRFeature *poFeature; poLayer->ResetReading();
while( (poFeature = poLayer->GetNextFeature()) != NULL )
{
OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
int iField; for( iField = 0; iField < poFDefn->GetFieldCount(); iField++ )
{
OGRFieldDefn *poFieldDefn = poFDefn->GetFieldDefn( iField ); if( poFieldDefn->GetType() == OFTInteger )
printf( "%d,", poFeature->GetFieldAsInteger( iField ) );
else if( poFieldDefn->GetType() == OFTReal )
printf( "%.3f,", poFeature->GetFieldAsDouble(iField) );
else if( poFieldDefn->GetType() == OFTString )
printf( "%s,", poFeature->GetFieldAsString(iField) );
else
printf( "%s,", poFeature->GetFieldAsString(iField) );
} OGRGeometry *poGeometry; poGeometry = poFeature->GetGeometryRef();
if( poGeometry != NULL
&& wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
{
OGRPoint *poPoint = (OGRPoint *) poGeometry; printf( "%.3f,%3.f\n", poPoint->getX(), poPoint->getY() );
}
else
{
printf( "no point geometry\n" );
}
OGRFeature::DestroyFeature( poFeature );
} OGRDataSource::DestroyDataSource( poDS );
}Writing TO OGR 作為一個用OGR寫的例子,我們粗略地跟上面的程式向反。這個小程式利用OGR將從檔案輸入的用逗號分隔的值寫到一個shapefile的點檔案。 通常,我們在一開始就註冊所有的驅動,然後取得Shapefile的驅動建立我們的輸出檔案。#i nclude "ogrsf_frmts.h"int main()
{
const char *pszDriverName = "ESRI Shapefile";
OGRSFDriver *poDriver; OGRRegisterAll(); poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(
pszDriverName );
if( poDriver == NULL )
{
printf( "%s driver not available.\n", pszDriverName );
exit( 1 );
} 下一步我們建立資料檔案(DataSource)。ESRI Shapefile驅動容許我們建立一個全是shapefiles的路徑或者單獨一個shapefile檔案。在這裡我們建立一個單獨的檔案by including the extension in the name。其他類型驅動處理不一樣。第二個參數是一組參數值,但在這個例子裡我們用預設的值。參數的詳細值也隨格式的不同而不同。 OGRDataSource *poDS; poDS = poDriver->CreateDataSource( "point_out.shp", NULL );
if( poDS == NULL )
{
printf( "Creation of output file failed.\n" );
exit( 1 );
} 現在我們就可以建立輸出圖層了。由於這個例子裡只是一個單獨的檔案,因此我們也只需要建立一個層。我們通過wkPoint來指定這個層支援的幾何類型。在這個例子裡我們沒有傳遞任何座標系統資訊或者別的特殊的層的建立資訊。 OGRLayer *poLayer; poLayer = poDS->CreateLayer( "point_out", NULL, wkbPoint, NULL );
if( poLayer == NULL )
{
printf( "Layer creation failed.\n" );
exit( 1 );
} 現在層已經建立,我們需要建立任何可能出現在層裡的屬性fields。Fields必須在如何features在寫入之前加入到圖層裡面。建立field我們用包含field資訊的OGRField。在Shapefiles檔案裡,field的width和精度對於輸出的.dbf檔案非常重要。,因此我們特定設定它,儘管預設的也OK。在這個例子裡,我們只有一個attribute,名字字串associated with x和y點。 確保我們傳給CreateFidld()的OGRField模版is copied internally。我們保留這個哦oject的所有權。 OGRFieldDefn oField( "Name", OFTString ); oField.SetWidth(32); if( poLayer->CreateField( &oField ) != OGRERR_NONE )
{
printf( "Creating Name field failed.\n" );
exit( 1 );
}\編碼(encode)下面這個迴圈結構從標準輸入讀取"x,y,name"值,並分析他們。The following snipping loops reading lines of the form "x,y,name" from stdin, and parsing them. \代碼code double x, y;
char szName[33]; while( !feof(stdin)
&& fscanf( stdin, "%lf,%lf,%32s", &x, &y, szName ) == 3 )
{ 為了把一個feature寫道磁碟上,我們必須建立一個本地的OGRFeature,在試圖將之寫入圖層前設定屬性並載入幾何資訊。必須注意的是這個feature必須和將要寫入的圖層的OGRFeatureDefn給出的案例一致。 OGRFeature *poFeature; poFeature = new OGRFeature( poLayer->GetLayerDefn() );
poFeature->SetField( "Name", szName );我們建立了一個本地的幾何檔案,並且讓他直接指向feature。OGRFeature::SetGeometryDirectly()和OGRFeature::SetGeometry()的不同之處是前者給了feature對幾何資料的所有權。This is generally more efficient as it avoids an extra deep object copy of the geometry. OGRPoint *poPoint = new OGRPoint();
poPoint->setX( x );
poPoint->setY( y );
poFeature->SetGeometryDirectly( poPoint ); 現在我們就在這個檔案裡建立了一個feature,OGRLayer::CreateFeature()沒有取消對feature的擁有因此我們需要在建立完之後清除乾淨。 if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
{
printf( "Failed to create feature in shapefile.\n" );
exit( 1 );
} delete poFeature;
}Finally we need to close down the datasource in order to ensure headers are written out in an orderly way and all resources are recovered. OGRDataSource::DestroyDataSource( poDS );
}The same program all in one block looks like this: #i nclude "ogrsf_frmts.h"int main()
{
const char *pszDriverName = "ESRI Shapefile";
OGRSFDriver *poDriver; OGRRegisterAll(); poDriver = OGRSFDriverRegistrar::GetRegistrar()->GetDriverByName(
pszDriverName );
if( poDriver == NULL )
{
printf( "%s driver not available.\n", pszDriverName );
exit( 1 );
} OGRDataSource *poDS; poDS = poDriver->CreateDataSource( "point_out.shp", NULL );
if( poDS == NULL )
{
printf( "Creation of output file failed.\n" );
exit( 1 );
} OGRLayer *poLayer; poLayer = poDS->CreateLayer( "point_out", NULL, wkbPoint, NULL );
if( poLayer == NULL )
{
printf( "Layer creation failed.\n" );
exit( 1 );
} OGRFieldDefn oField( "Name", OFTString ); oField.SetWidth(32); if( poLayer->CreateField( &oField ) != OGRERR_NONE )
{
printf( "Creating Name field failed.\n" );
exit( 1 );
} double x, y;
char szName[33]; while( !feof(stdin)
&& fscanf( stdin, "%lf,%lf,%32s", &x, &y, szName ) == 3 )
{
OGRFeature *poFeature; poFeature = new OGRFeature( poLayer->GetLayerDefn() );
poFeature->SetField( "Name", szName ); OGRPoint *poPoint = new OGRPoint();
poPoint->setX( x );
poPoint->setY( y );
poFeature->SetGeometryDirectly( poPoint ); if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
{
printf( "Failed to create feature in shapefile.\n" );
exit( 1 );
} delete poFeature;
} OGRDataSource::DestroyDataSource( poDS );
}