• OGR API 使用向导


    翻译:柴树杉(chaishushan@gmail.com)
    原文:http://www.gdal.org/ogr/ogr_apitut.html

    该文档讲述了怎么样用OGR的类读/写一个文件。其中侧重介绍了OGR中一些比较关键类的用法。

    用OGR读

    为了演示怎么用OGR读数据,我们创建了一个小程序:从数据源中读point层, 然后用逗号分隔格式输出到stdout。开始的时候一般需要注册所有格式的驱动, 可以通过调用OGRRegisterAll()函数实现。

    #include "ogrsf_frmts.h"
    
    int main()
    
    {
            OGRRegisterAll();
    

    接下来需要打开用于输入的数据源(Datasources)。Datasources可以是文件、RDBMSes、 目录中的所有文件或者是被连接到本机的 web地址。通常,datasource都对应一个字符串 的名字。在这个例子中,我们将要打开一个名point.shp为的shapefile格式的文件。 第二个参数FALSE表示OGRSFDriverRegistrar::Open()方法并不需要更新的权限。 如果操作失败,则会返回NULL,我们则简单输出失败的信息。

        OGRDataSource       *poDS;
    
        poDS = OGRSFDriverRegistrar::Open( "point.shp", FALSE );
        if( poDS == NULL )
        {
            printf( "Open failed.\n" );
            exit( 1 );
        }
    

    一个OGRDataSource一般含有许多层(layer)。OGRDataSource::GetLayerCount() 可以返回 OGRDataSource中层的总数目。OGRDataSource::GetLayer()可以通过层 的索引编号获取一个层。当然,这个例子中我们是通过层的名字访问层。

        OGRLayer  *poLayer;
    
        poLayer = poDS->GetLayerByName( "point" );
    

    现在我们可以从获取的层中读取各种实体了(feature)。在读之前,我们可以设置 一个过滤器,那样的话后面顺序返回的将都是没有被过滤的实体。这里我们是获取层 中所有的实体。

    在我们从层中读实体之前需要调用OGRLayer::ResetReading()函数重新设置读操作 (即定位到开头)。然后OGRLayer::GetNextFeature()依次返回下一个实体,如果 返回NULL的话表示全部读完。

        OGRFeature *poFeature;
    
        poLayer->ResetReading();
        while( (poFeature = poLayer->GetNextFeature()) != NULL )
        {
    

    为了获取实体的每个属性字段的信息,可以获取OGRFeatureDefn。OGRFeatureDefn是 一个和当前层相关的对象,它包含了该层中定义的所有属性字段。我们循环访问所有的 属性字段,并且输出每个字段对应的值。

            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) );
            }
    

    这里只有很少的几种字段类型。并且任何类型的字段都可以用OGRFeature::GetFieldAsString()方法获取。接下来我们从实体中导出集合图元,并且输出点图元的坐标。几何图元以OGRGeometry 指针的方式返回。我们可以判断几何图元的类型,如果是点则输出坐标,如果不是则输出提示信息。

            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的类型。 每个2D的集合图元类型都对应一个 2.5D的编码,然而这里只有一个C++类用于处理2D和3D 情形,因此我们在代码中可能需要对2D或3D情形做适当的处理。

    需要注意的是OGRFeature::GetGeometryRef()返回的是OGRFeature中数据的的指针, 因此用完之后我们不能删除 poGeometry指针对应内容。但是OGRLayer::GetNextFeature() 返回的是层中当前实体的一个拷贝,因此在使用完 poFeature之后必须手工释放。 释放poFeature不能直接delete,正确的方式是用OGR提供的 OGRFeature::DestroyFeature()函数释放。

            OGRFeature::DestroyFeature( poFeature );
        }
    

    OGRDataSource::GetLayerByName() 返回的OGRLayer是OGRDataSource中数据的引用, 因此我们可以不用delete它。但是我们需要删除OGRDataSource本身,这样才会关闭文件。 同样,我们用OGRFeature::DestroyFeature()函数删除poDS(delete poDS在win32系统 上可能出现问题)。

        OGRDataSource::DestroyDataSource( poDS );
    }
    

    所有的程序合到一起如下:

    #include "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 );
    }
    

    用OGR写

    作为用OGR写数据的例子,下面的程序中stdin顺序读以逗号分割的点坐标,然后保存 到point_out.shp文件。和写一样,在程序开头需要注册所有的驱动。然后我们获取 一个相应格式的驱动用于创建输出文件。

    #include "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。 这里,我们通过指定.shp扩展名表示创建一个单一的shapefile。其他格式的驱动调用规则 可能并不相同。第二个参数是一个选项列表(是一个以NULL结尾的字符串数组), 这里我们采用默认选项。选项列表的规则根据格式的不同而不同。

        OGRDataSource *poDS;
    
        poDS = poDriver->CreateDataSource( "point_out.shp", NULL );
        if( poDS == NULL )
        {
            printf( "Creation of output file failed.\n" );
            exit( 1 );
        }
    

    现在我们创建一个用于输出的层。在这个程序中,因为datasource只对应一个单一的 文件,因此只能创建一个层。参数wkbPoint表示该曾需要支持的类型。在该程序中, 同样不能指定任何坐标系统或者其他特殊的选项。

        OGRLayer *poLayer;
    
        poLayer = poDS->CreateLayer( "point_out", NULL, wkbPoint, NULL );
        if( poLayer == NULL )
        {
            printf( "Layer creation failed.\n" );
            exit( 1 );
        }
    

    层被创建之后,我们可以为层定义任何需要的属性字段。属性字段必须在任何 实体添加到层之前被写入。我们创建一个属性字段对象,并且初始化。在 Shapefiles中, width和precision是比较重要的被创建在.dbf文件中,这里我们对它单独设置。 在这个程序中我们只创建了一个属性,即点的名字。

    需要注意的是CreateField()将OGRField重新复制了一份,因此我们仍然持有oField的所有权。

        OGRFieldDefn oField( "Name", OFTString );
    
        oField.SetWidth(32);
    
        if( poLayer->CreateField( &oField ) != OGRERR_NONE )
        {
            printf( "Creating Name field failed.\n" );
            exit( 1 );
        }
    \encode
    
    下面从stdin中循环读取"x,y,name"格式的点信息。
    
    \code
        double x, y;
        char szName[33];
    
        while( !feof(stdin) 
               && fscanf( stdin, "%lf,%lf,%32s", &x, &y, szName ) == 3 )
        {
    

    为了将feature写入磁盘,我们需要创建一个OGRFeature对象,并且和层对应的属性 帮定(即需要和OGRFeatureDefn关联)。然后设置feature的相关属性。

            OGRFeature *poFeature;
    
            poFeature = new OGRFeature( poLayer->GetLayerDefn() );
            poFeature->SetField( "Name", szName );
    

    现在我们创建一个具体的几何图元,然后将它的拷贝指定给feature。 OGRFeature::SetGeometryDirectly()OGRFeature::SetGeometry()函数的不同 是SetGeometryDirectly函数将几何图元的所有全给予feature。

            OGRPoint pt;
            pt.setX( x );
            pt.setY( y );
            
            poFeature->SetGeometry( &pt ); 
    

    创建一个feature。OGRLayer::CreateFeature()只是重新复制了一个feature,因此 操作完成后需要清除feature对象。

            if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
            {
               printf( "Failed to create feature in shapefile.\n" );
               exit( 1 );
            }
            
            OGRFeature::DestroyFeature( poFeature );
       }
    

    最后释放datasource资源,刷新所有的写操作。

        OGRDataSource::DestroyDataSource( poDS );
    }
    

    所有的程序合到一起如下:

    #include "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 pt;
            
            pt.setX( x );
            pt.setY( y );
     
            poFeature->SetGeometry( &pt ); 
    
            if( poLayer->CreateFeature( poFeature ) != OGRERR_NONE )
            {
               printf( "Failed to create feature in shapefile.\n" );
               exit( 1 );
            }
    
             OGRFeature::DestroyFeature( poFeature );
        }
    
        OGRDataSource::DestroyDataSource( poDS );
    }
    
  • 相关阅读:
    _00020 妳那伊抹微笑_谁的异常最诡异第一期之 SqlServer RSA premaster secret error
    &lt;&lt;Python基础教程&gt;&gt;学习笔记 | 第12章 | 图形用户界面
    ubuntu 14.04 桌面版关闭图形界面
    (一)简单工厂模式
    JS学习笔记-数据类型
    【C#】报表制作&lt;机房重构&gt;
    [leetcode][math] Add Digits
    hibernate(三) 一对多映射关系
    hibernate(二)一级缓存和三种状态解析
    Hibernate(五)之一对多&多对一映射关系
  • 原文地址:https://www.cnblogs.com/bigbigtree/p/2278721.html
Copyright © 2020-2023  润新知