美文网首页
GDAL矢量驱动拓展

GDAL矢量驱动拓展

作者: NullUser | 来源:发表于2022-08-30 18:16 被阅读0次

    GDAL

    GDAL文档
    GDAL下载
    GDAL开发依赖下载
    GDAL是一个用于栅格和矢量地理空间数据格式的转换库,采用MIT开源许可,由开源地理空间基金会发布。它为调用程序提供了栅格抽象数据模型和矢量抽象数据模型并包含所有支持的格式。它还提供了一些实用的命令行程序用于数据转换和处理。

    OGR

    OGR是GDAL项目的一个分支,功能与GDAL类似,只不过它提供对矢量数据的读写支持,包括ESRI Shapefiles,PostGIS等。

    矢量数据模型(Vector Data Model)

    OGR为矢量数据提供了矢量数据模型。

    类概况

    • 几何图形(ogr_geometry.h):几何类(OGRGeometry等),封装了OpenGIS模型矢量数据并提供一些几何操作,以及对WKB和WKT的转换。几何图形包含了空间参考系。


      geometry模型.png
    • 空间参考(ogr_spatialref.h):OGRSpatialRefence类,封装了投影和基准的定义。
    • 要素(ogr_feature.h):OGRFeature类,封装了feature的定义,包括一个几何和属性。
    • 要素类定义(ogr_feature.h):OGRFeatureDefn类,将一组相关要素(一个Layer)的概要数据进行封装,包括了集合类型、名称、属性域定义等。
    • 图层(ogrsf_frmts.h):OGRLayer类,一个抽象基类,代表了GDALDataset中的一个要素图层。
    • 数据集(gdal_priv.h):GDALDataset类,包含一个或多个OGRLayer对象的类,其通常代表一个文件或数据库。
    • 驱动(gdal_priv.h):GDALDriver类,为特定格式提供驱动,用以打开特定格式的数据得到GDALDataset,如ESRI Shapefile、PostGIS。所有的驱动都被GDALDriverManager管理。

    体系架构:


    体系架构.png

    矢量驱动程序实现

    • 在程序中实现矢量驱动时,程序版本需与gdal库版本一致,如release版的gdal库,编译程序时也应为release版。

    通过实现特定格式的驱动,来为OGR加入新的格式支持。这需要实例化GDALDriver类并实现GDALDatasetOGRLayer的子类。GDALDriver实例需要在运行时通过GDALDriverManager进行注册。

    1.实现GDALDriver

    特定格式的驱动程序类是作为GDALDriver的实例实现的。通常会创建一个GDALDriver实例并通过GDALDeiverManager进行注册。而实例化过程由一个全局C函数进行处理。该函数由自己实现并在内部实例化一个GDALDriver对象。

    void registerOGRSPF()
    {
        if( GDALGetDriverByName("SPF") != NULL )
            return;
    
        GDALDriver *poDriver = new GDALDriver();
    
        poDriver->SetDescription("SPF");
        poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
        poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Long name for SPF driver");
        poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "spf");
        poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drv_spf.html");
    
        // 为GDALDriver设置函数指针
        poDriver->pfnOpen = OGRSPFDriverOpen;
        poDriver->pfnIdentify = OGRSPFDriverIdentify;
        poDriver->pfnCreate = OGRSPFDriverCreate;
    
        poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
    
        GetGDALDriverManager()->RegisterDriver(poDriver);
    }
    

    SetDescription("SPF")指定了驱动程序的名称。
    SetMetadataItem( const char * pszName, const char * pszValue)设置驱动的元数据信息:

    • GDAL_DCAP_VECTOR:设置为"YES"表示驱动程序将处理矢量数据。
    • GDAL_DCAP_VIRTUALIO:设置为"YES"表示驱动程序可以处理使用VSI*L GDAL API打开的文件。否则不应定义此元数据项。
    • GDAL_DMD_LONGNAME:文件格式的详细描述,长度一般在50-60个字符。(手工设置)
    • GDAL_DMD_HELPTOPIC:URL,相对于http://gdal.ogr/如果有的话, 是关于这个驱动帮助文档的名称。(可选)
    • GDAL_DMD_EXTENSION:该类型文件的扩展名。如果扩展名多于一个,则最好选择最通用的那个,或者直接为空。(可选)
    • GDAL_DMD_MIMETYPE:该格式数据的标准用途类型,例如“image/png”。(可选)
    • GDAL_DMD_CREATIONOPTIONLIST:用于描述创建时的选项。可以参考geotiff驱动的实现代码。(可选)
    • GDAL_DMD_CREATIONDATATYPES:支持创建数据集的全部类型列表。如果存在Create()方法这些类型都将被支持。如果存在CreateCopy()方法,该类型列表将是那些支持无损输出的类型。比如,一个格式使用了CreateCopy()方法,如果可以写为Float32类型,那么Byte、Int16和UInt16都应该被支持(因为它们都可以用Float32表示)

    将自定义的实现函数赋值给GDALDriver的函数指针,通过调用GDALDriver的函数指针,以下函数被具体执行:

    static GDALDataset* OGRSPFDriverOpen(GDALOpenInfo* poOpenInfo);
    static int          OGRSPFDriverIdentify(GDALOpenInfo* poOpenInfo);
    static GDALDataset* OGRSPFDriverCreate(const char* pszName, int nXSize, int nYSize,
                                        int nBands, GDALDataType eDT, char** papszOptions);
    

    Open()方法用于打开数据源并返回一个GDALDataset实例,通常被委托给实际的GDALDataset子类,即在内部调用GDALDataset子类实例的Open()方法。

    static GDALDataset *OGRSPFDriverOpen( GDALOpenInfo* poOpenInfo )
    {
        if( !OGRSPFDriverIdentify(poOpenInfo) )
            return NULL;
    
        OGRSPFDataSource *poDS = new OGRSPFDataSource();
        if( !poDS->Open(poOpenInfo->pszFilename, poOpenInfo->eAccess == GA_Update) )
        {
            delete poDS;
            return NULL;
        }
    
        return poDS;
    }
    

    Identify()方法可以对数据源进行校验,判断是否是合格数据源。

    static int OGRSPFDriverIdentify( GDALOpenInfo* poOpenInfo )
    {
        // Does this appear to be an .spf file?
        return EQUAL(CPLGetExtension(poOpenInfo->pszFilename), "spf");
    }
    

    create()在用于创建数据,如该驱动用于驱动文件类型的数据时,则可在create()中实现文件的创建。

    2.实现GDALDataset子类

    GDALDataset子类以一个vector保存多个Layer数据。

    class OGRSPFDataSource : public GDALDataset
    {
        std::vector<OGRSPFLayer*>   papoLayers;
        int                 nLayers;
    
    public:
      OGRSPFDataSource();
      ~OGRSPFDataSource();
    
        int                 Open( const char *pszFilename, int bUpdate );
    
        int                 GetLayerCount() { return nLayers; }
        OGRLayer            *GetLayer( int );
    
        int                 TestCapability( const char * ) { return FALSE; }
    };
    

    Open()方法将会访问数据源信息并创建OGRLayer的子类对象,在实现OGRLayer的子类时,访问数据源信息,并获取要素数据。

    int  OGRSPFDataSource::Open( const char *pszFilename, int bUpdate )
    {
        if( bUpdate )
        {
            CPLError(CE_Failure, CPLE_OpenFailed,
                    "Update access not supported by the SPF driver.");
            return FALSE;
        }
    
        // Create a corresponding layer.s
        nLayers = 1;
    
        papoLayers.append(new OGRSPFLayer(pszFilename));
    
        pszName = CPLStrdup(pszFilename);
    
        return TRUE;
    }
    

    3.实现OGRLayer子类

    自定义OGRSPFLayer类继承自OGRLayer。在内部拥有OGRFeatureDefn成员变量,以便访问该图层的元数据信息。

    OGRLayer中的纯虚函数有:

    • virtual void ResetReading() = 0;
    • virtual OGRFeature *GetNextFeature() CPL_WARN_UNUSED_RESULT = 0;
    • virtual OGRFeatureDefn *GetLayerDefn() = 0;
    • virtual int TestCapability( const char * ) = 0;
    class OGRSPFLayer : public OGRLayer
    {
        OGRFeatureDefn     *poFeatureDefn;
        FILE               *fp;
        int                 nNextFID;
    
    public:
        OGRSPFLayer( const char *pszFilename );
        ~OGRSPFLayer();
    
        void                ResetReading();
        OGRFeature *        GetNextFeature();
    
        OGRFeatureDefn *    GetLayerDefn() { return poFeatureDefn; }
    
        int                 TestCapability( const char * ) { return FALSE; }
    };
    

    类内部的OGRFeatureDefn将被多个OGRFeature引用,所有在该类的构造函数和析构函数中也应通过OGRFeatureDefn::Reference()OGRFeatureDefn::Release()对OGRFeatureDefn对象进行引用计数的+1和-1

    OGRSPFLayer::OGRSPFLayer( const char *pszFilename )
    {
        nNextFID = 0;
    
        poFeatureDefn = new OGRFeatureDefn(CPLGetBasename(pszFilename));
        SetDescription(poFeatureDefn->GetName());
        poFeatureDefn->Reference();
        poFeatureDefn->SetGeomType(wkbPoint);
    
        OGRFieldDefn oFieldTemplate("Name", OFTString);
    
        poFeatureDefn->AddFieldDefn(&oFieldTemplate);
    
        fp = VSIFOpenL(pszFilename, "r");
        if( fp == NULL )
            return;
    }
    OGRSPFLayer::~OGRSPFLayer()
    {
        poFeatureDefn->Release();
        if( fp != NULL )
            VSIFCloseL(fp);
    }
    

    重写GetNextFeature(),在函数体内访问数据源获取到每一个feature的信息,并创建OGRFeature对象后返回。

    OGRFeature *OGRSPFLayer::GetNextFeature()
    {
      /* 从数据源获取到下一个feature的数据 */
      ......
      {
        OGRFeature *poFeature = new OGRFeature(poFeatureDefn);
    
        poFeature->SetGeometryDirectly(new OGRPoint(dfX, dfY));
        poFeature->SetField(0, pszName);
        poFeature->SetFID(nNextFID++);
        if(/*match*/)
        {
          return poFeature;
        }
        else
        {
          delete poFeature;
        }
      }
    
    }
    

    OGRLayer基类拥有成员变量:OGRLayer::m_poFilterGeomOGRLayer::m_poAttrQuery分别对几何和属性进行过滤,以便筛选出符合要求的feature,可以在GetNextFeature()方法中进行判断:

            if( (m_poFilterGeom == NULL ||
                FilterGeometry(poFeature->GetGeometryRef())) &&
                (m_poAttrQuery == NULL ||
                m_poAttrQuery->Evaluate(poFeature)) )
                return poFeature;
    
            delete poFeature;
    

    重写OGRLayer::ResetReading(),在函数体内重置feature的索引,代表重新获取feature,与OGRLayer::GetNextFeature()联动。

    void OGRSPFLayer::ResetReading()
    {
        VSIFSeekL(fp, 0, SEEK_SET);
        nNextFID = 0;
    }
    

    4.GDALDataset虚函数

    重点实现:

    • virtual int GetLayerCount();
      获取图层数量,默认实现返回0。
    • virtual OGRLayer *GetLayer(int iLayer);
      根据下标获取图层,默认实现返回nullptr
    • virtual OGRLayer *GetLayerByName(const char *);
      根据图层名称返回图层,默认实现会根据GetLayerCount()GetLayer()遍历所有图层,并比较图层名后返回。其首先会大小写敏感判断图层名,如果没有符合的图层,会用大小写不敏感去匹配图层名。
    • virtual OGRErr DeleteLayer(int iLayer);
      根据下标删除指定图层,默认实现为空逻辑。
    • virtual void ResetReading();
      重置feature的读取为从第一个feature开始,该函数会影响GetNextFeature()
    • virtual OGRFeature* GetNextFeature( OGRLayer** ppoBelongingLayer, double* pdfProgressPct, GDALProgressFunc pfnProgress, void* pProgressData );
      通过循环图层,获取每个图层的feature,会调用图层的GetNextFeature()方法。
    • virtual int TestCapability( const char * );
      判断该数据源是否有某一功能,默认实现为返回false。传入的字符串有:
     <ul>
      <li> <b>ODsCCreateLayer</b>: True if this datasource can create new layers.<p>
      <li> <b>ODsCDeleteLayer</b>: True if this datasource can delete existing
              layers.<p>
      <li> <b>ODsCCreateGeomFieldAfterCreateLayer</b>: True if the layers of this
              datasource support CreateGeomField() just after layer creation.<p>
      <li> <b>ODsCCurveGeometries</b>: True if this datasource supports curve
              geometries.<p>
      <li> <b>ODsCTransactions</b>: True if this datasource supports (efficient)
              transactions.<p>
      <li> <b>ODsCEmulatedTransactions</b>: True if this datasource supports
              transactions through emulation.<p>
      <li> <b>ODsCRandomLayerRead</b>: True if this datasource has a dedicated
              GetNextFeature() implementation, potentially returning features from
              layers in a non sequential way.<p>
      <li> <b>ODsCRandomLayerWrite</b>: True if this datasource supports calling
             CreateFeature() on layers in a non sequential way.<p>
     </ul>o
    
    • virtual bool AddFieldDomain(std::unique_ptr<OGRFieldDomain>&& domain, std::string& failureReason);
      向数据集添加字段域,默认实现是空逻辑。
    • virtual bool DeleteFieldDomain(const std::string& name, std::string& failureReason);
      根据名称删除指定的字段域,默认实现是空逻辑。
    • virtual bool UpdateFieldDomain(std::unique_ptr<OGRFieldDomain>&& domain, std::string& failureReason);
      通过替换定义更新一个已经存在的字段域,将通过字段域的名称去匹配,默认实现是空逻辑。
    • virtual OGRLayer *ICreateLayer( const char *pszName, OGRSpatialReference *poSpatialRef = nullptr, OGRwkbGeometryType eGType = wkbUnknown, char ** papszOptions = nullptr );
      创建图层,默认实现是返回nullptr,该接口为protected。

    非重点实现:

    • virtual void FlushCache(bool bAtClosing = false);
      将所有缓存数据写入硬盘,默认实现是调用每个raster bands的FlushCache()和每个Layer的SyncToDisk()
    • virtual const OGRSpatialReference* GetSpatialRef() const;
      获取数据集的空间参考系,默认实现是返回nullptr
    • virtual CPLErr SetSpatialRef(const OGRSpatialReference* poSRS);
      为数据集设置空间参考系,默认实现为空逻辑。
    • virtual CPLErr GetGeoTransform( double * padfTransform );
    • virtual CPLErr SetGeoTransform( double * padfTransform );
    • virtual void *GetInternalHandle( const char * pszHandleName );
      获取内部特定格式的有意义句柄,默认实现返回nullptr
    • virtual GDALDriver *GetDriver(void);
      有默认实现。
    • virtual const char* GetDriverName();
      有默认实现。
    • virtual char **GetFileList(void);
    • virtual const OGRSpatialReference* GetGCPSpatialRef() const;
      返回地理转换控制点的坐标系,默认实现返回nullptr
    • virtual int GetGCPCount();
      获取地理转换控制点数量,默认实现返回0。
    • virtual const GDAL_GCP *GetGCPs();
      默认实现返回nullptr
    • virtual CPLErr SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList, const OGRSpatialReference * poGCP_SRS );
    • virtual CPLErr AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize, int nBufXSize, int nBufYSize, GDALDataType eDT, int nBandCount, int *panBandList, char **papszOptions );
    • virtual CPLErr CreateMaskBand( int nFlagsIn );
    • virtual GDALAsyncReader* BeginAsyncReader(int nXOff, int nYOff, int nXSize, int nYSize, void *pBuf, int nBufXSize, int nBufYSize, GDALDataType eBufType, int nBandCount, int* panBandMap, int nPixelSpace, int nLineSpace, int nBandSpace, char **papszOptions);
    • virtual void EndAsyncReader(GDALAsyncReader *);
    • virtual bool GetRawBinaryLayout(RawBinaryLayout&);
      获取数据集中原始二进制格式的图层,默认实现为返回空。
    • virtual void ClearStatistics();
    • virtual bool IsLayerPrivate(int iLayer) const;
      通过下标判断该图层是否是私有图层,默认实现返回false
    • virtual std::vector<std::string> GetFieldDomainNames(CSLConstList papszOptions = nullptr) const;
      返回字段域的名称列表,默认实现是从成员变量m_oMapFieldDomains中取出所有的key。
    • virtual const OGRFieldDomain* GetFieldDomain(const std::string& name) const;
      根据名称获取字段域,默认实现是从成员变量m_oMapFieldDomains中查找。
    • virtual OGRLayer *CreateLayer( const char *pszName, OGRSpatialReference *poSpatialRef = nullptr, OGRwkbGeometryType eGType = wkbUnknown, char ** papszOptions = nullptr );
      创建新图层,默认实现是委托给ICreateLayer(),而ICreateLayer()的默认实现是空逻辑。
    • virtual OGRLayer *CopyLayer( OGRLayer *poSrcLayer, const char *pszNewName, char **papszOptions = nullptr );
      复制一个已存在的图层,有默认实现,新图层的创建由ICreateLayer()完成,之后将原图层的各项数据复制给新图层。
    • virtual OGRStyleTable *GetStyleTable();
      获取数据集的样式表,默认实现是返回成员变量m_poStyleTable
    • virtual void SetStyleTableDirectly( OGRStyleTable *poStyleTable );
      直接设置样式表,默认实现是将形参直接赋值给成员变量m_poStyleTable
    • virtual void SetStyleTable(OGRStyleTable *poStyleTable);
      设置样式表,默认实现会先delete原指针,后执行OGRStyleTable::Clone()
    • virtual OGRLayer * ExecuteSQL( const char *pszStatement, OGRGeometry *poSpatialFilter, const char *pszDialect );
      对数据源执行SQL语句,返回执行后得到的图层,有默认实现。
    • virtual void ReleaseResultSet( OGRLayer * poResultsSet );
      释放ExecuteSQL()后得到的结果,默认实现是直接delete形参。
    • virtual OGRErr AbortSQL( );
    • virtual OGRErr StartTransaction(int bForce=FALSE);
    • virtual OGRErr CommitTransaction();
    • virtual OGRErr RollbackTransaction();
      以上API提供数据集级别的事务机制,可参考GDAL的RFC 54
    • virtual std::shared_ptr<GDALGroup> GetRootGroup() const;
      默认实现返回nullptr

    5.OGRLayer虚函数

    重点实现:

    • virtual OGRErr ISetFeature( OGRFeature *poFeature ) CPL_WARN_UNUSED_RESULT;
      默认实现为空逻辑,该接口为protected。
    • virtual OGRErr ICreateFeature( OGRFeature *poFeature ) CPL_WARN_UNUSED_RESULT;
      创建要素,默认实现为空逻辑,该接口为protected。
    • virtual void ResetReading() = 0;
      重置feature的遍历。
    • virtual OGRFeature *GetNextFeature() CPL_WARN_UNUSED_RESULT = 0;
      获取下一个feature。
    • virtual OGRErr DeleteFeature( GIntBig nFID ) CPL_WARN_UNUSED_RESULT;
      删除feature,默认实现为空逻辑。
    • virtual OGRFeatureDefn *GetLayerDefn() = 0;
      获取图层定义,返回的是OGRFeatureDefn 对象。
    • virtual GIntBig GetFeatureCount( int bForce = TRUE );
      获取feature数量,默认实现为遍历所有feature进行计数,计数完毕后会并调用ResetReading();
    • virtual int TestCapability( const char * ) = 0;
      验证Layer是否具有某能力,如创建feature、删除feature等。
    • virtual OGRErr Rename( const char* pszNewName ) CPL_WARN_UNUSED_RESULT;
      重命名图层,默认实现为空逻辑,根据ogrlayer.cpp中的描述,该方法的实现只存在于暴露了OLCRename能力的Layer和GDAL_DCAP_RENAME_LAYERS能力的驱动,如果数据集中已有同名Layer,应该返回False。
    • virtual OGRErr CreateField( OGRFieldDefn *poField, int bApproxOK = TRUE );
      创建域,默认实现为空逻辑。
    • virtual OGRErr DeleteField( int iField );
      删除域,默认实现为空逻辑。
    • virtual OGRErr ReorderFields( int* panMap );
      重排序域,默认实现为空逻辑。
    • virtual OGRErr AlterFieldDefn( int iField, OGRFieldDefn* poNewFieldDefn, int nFlagsIn );
      修改域定义,默认实现为空逻辑。
    • virtual OGRErr CreateGeomField( OGRGeomFieldDefn *poField, int bApproxOK = TRUE );
      创建几何域,默认实现为空逻辑。

    非重点实现:

    • virtual OGRGeometry *GetSpatialFilter();
      获取空间过滤几何,默认实现为返回成员变量m_poFilterGeom
    • virtual void SetSpatialFilter( OGRGeometry * );
      设置空间过滤,默认实现会委托给InstallFilter(),并调用ResetReading()
    • virtual void SetSpatialFilterRect( double dfMinX, double dfMinY, double dfMaxX, double dfMaxY );
      设置空间过滤矩形,默认实现会构造一个矩形后,调用SetSpatialFilter()
    • virtual OGRErr SetAttributeFilter( const char * );
      设置属性过滤,有默认实现。
    • virtual OGRErr SetNextByIndex( GIntBig nIndex );
      通过下标设置下一个返回的feature,即GetNextFeature()的返回值,有默认实现。
    • virtual OGRFeature *GetFeature( GIntBig nFID ) CPL_WARN_UNUSED_RESULT;
      根据nFID获取feature对象。有默认实现。
    • virtual const char *GetName();
      获取图层名,默认实现委托给GetLayerDefn()->GetName()
    • virtual OGRwkbGeometryType GetGeomType();
      获取几何类型,默认实现委托给GetLayerDefn()->GetGeomType()
    • virtual int FindFieldIndex( const char *pszFieldName, int bExactMatch );
      根据名称获取域下标,默认实现委托给GetLayerDefn()->GetFieldIndex( pszFieldName )
    • virtual OGRSpatialReference *GetSpatialRef();
      获取空间参考系,默认实现委托给GetLayerDefn()->GetGeomFieldDefn(0)->GetSpatialRef()
    • virtual OGRErr GetExtent(OGREnvelope *psExtent, int bForce = TRUE) CPL_WARN_UNUSED_RESULT;
      获取范围,默认实现是委托给GetExtentInternal()GetExtentInternal()会遍历feature,并汇总feature的几何后得出矩形范围,最后会调用`ResetReading()``。
    • virtual OGRErr SyncToDisk();
      将缓存数据同步到硬盘,默认实现为空逻辑。
    • virtual OGRStyleTable *GetStyleTable();
      获取样式表,默认实现为返回成员变量m_poStyleTable
    • virtual void SetStyleTableDirectly( OGRStyleTable *poStyleTable );
      直接设置样式表,默认实现为将形参赋值给成员变量m_poStyleTable
    • virtual void SetStyleTable(OGRStyleTable *poStyleTable);
      设置样式表,默认实现为delete成员变量m_poStyleTable,之后调用OGRStyleTable::Clone()
    • virtual OGRErr StartTransaction() CPL_WARN_UNUSED_RESULT;
      开启事务,默认实现为空逻辑。
    • virtual OGRErr CommitTransaction() CPL_WARN_UNUSED_RESULT;
      提交事务,默认实现为空逻辑。
    • virtual OGRErr RollbackTransaction();
      回滚,默认实现为空逻辑。
    • virtual const char *GetFIDColumn();
      获取FID列名,默认实现为返回空字符串。
    • virtual const char *GetGeometryColumn();
      获取几何列,默认实现委托给GetLayerDefn()->GetGeomFieldDefn(0)->GetNameRef()
    • virtual OGRErr SetIgnoredFields( const char **papszFields );
      设置忽略的域,有默认实现。

    相关文章

      网友评论

          本文标题:GDAL矢量驱动拓展

          本文链接:https://www.haomeiwen.com/subject/rjudnrtx.html