美文网首页
创建QGis的自定义DataProvider

创建QGis的自定义DataProvider

作者: NullUser | 来源:发表于2022-06-21 18:09 被阅读0次

    以TestProvider为例:

    要实现DataProvider的基本功能,需要继承4个父类:

    • QgsProviderMetadata
      QgsProviderRegistry内部以Map结构保存了QgsProvideMetadata的子类实例,每个实例关联了一个DataProvider插件。QgsProviderMetadata保存了DataProvider的key和description,提供了createProvider()接口创建DataProvider对象,同时还有encodeUri()、decodeUri()接口用于生成和解析uri字符串。
    • QgsVectorDataProvider
      QgsVectorDataProvider为DataProvider的主要实现。如获取属性字段、获取坐标参考系、读取数据等。
    • QgsAbstractFeatureSource
      QgsAbstractFeatureSource保存要素的基本信息。
    • QgsAbstractFeatureIteratorFromSource<T>
      QgsAbstractFeatureIteratorFromSource实现了对要素一些访问操作。

    1. 新建QgsTestProviderMetadata类继承QgsProviderMetadata

    class QgsTestProviderMetadata final: public QgsProviderMetadata
    {
    public:
        QgsSDEProviderMetadata();
        QgsDataProvider *createProvider( const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags() ) override;
        QVariantMap decodeUri( const QString &uri ) const override;
        QString encodeUri( const QVariantMap &parts ) const override;
        void initProvider() override;
    };
    

    1.1 基础函数实现

    1.1.1 重载函数

    1) createProvider()

    virtual QgsDataProvider *createProvider( const QString &uri,
            const QgsDataProvider::ProviderOptions &options,
            QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags() ) SIP_FACTORY;
    

    createProvider()用以创建一个dataprovider实例,实现函数时new一个自定义的dataprovider对象,然后返回即可

    QgsDataProvider *QgsTestProviderMetadata::createProvider(const QString &uri, const QgsDataProvider::ProviderOptions &options, QgsDataProvider::ReadFlags flags)
    {
      return new QgsTestProvider( uri, options, flags );
    }
    

    2) decodeUri()

    virtual QVariantMap decodeUri( const QString &uri ) const;
    

    decodeUri()解析uri字符串,并以map结构返回解析后的数据,QGis提供了QgsDataSourceUri类,某些情况下可以直接使用QgsDataSourceUri类解析和生成uri字符串,省去了自己解析字符串的操作。参考postgresprovider的uri: dbname='sdetest' host=127.0.0.1 port=5432 user='sde' password='123' table="sde"."testlayer" (shape)。如果不用QgsDataSourceUri类,也可自定义字符串格式并自行解析。

    QVariantMap QgsTestProviderMetadata::decodeUri(const QString &uri) const
    {
        const QgsDataSourceUri dsUri{ uri };
        QVariantMap uriParts;
    
        if (!dsUri.database().isEmpty())
            uriParts[QStringLiteral("dbname")] = dsUri.database();
        if (!dsUri.host().isEmpty())
            uriParts[QStringLiteral("host")] = dsUri.host();
        return uriParts;
    }
    

    3) encodeUri()

    virtual QString encodeUri( const QVariantMap &parts ) const;
    

    同理,encodeUri的实现也可以借助QgsDataSourceUri类生成uri字符串。

    QString QgsTestProviderMetadata::encodeUri(const QVariantMap &parts) const
    {
        QgsDataSourceUri dsUri;
        if (parts.contains(QStringLiteral("dbname")))
            dsUri.setDatabase(parts.value(QStringLiteral("dbname")).toString());
        if (parts.contains(QStringLiteral("port")))
            dsUri.setParam(QStringLiteral("port"), parts.value(QStringLiteral("port")).toString());
        return dsUri.uri(false);
    }
    

    4) initProvider()

    void initProvider() override;
    

    2. 新建QgsTestProvider类继承QgsVectorDataProvider

    class QgsTestProvider final: public QgsVectorDataProvider
    {
        friend class QgsTestFeatureSource;
        Q_OBJECT
    public:
        explicit QgsTestProvider( QString const &uri, const QgsDataProvider::ProviderOptions &providerOptions,
                                      QgsDataProvider::ReadFlags flags = QgsDataProvider::ReadFlags() );
        ~QgsTestProvider();
    
        virtual QgsAbstractFeatureSource *featureSource() const override;
        QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override;
        QgsWkbTypes::Type wkbType() const override;
        long long featureCount() const override;
        QgsFields fields() const override;
        QgsCoordinateReferenceSystem crs() const override;
        QgsRectangle extent() const override;
        bool isValid() const override;
        QString name() const override;
        QString description() const override;
    private:
        /**
         * Flag indicating if the layer data source is a valid PostgreSQL layer
         */
        bool mValid = false;
    
        QgsWkbTypes::Type mWkbType;
    
        QgsFields mAttributeFieds;
    
        QgsRectangle mExtent;
    
        QList<QgsFeature> mFeatures;
    };
    

    QgsTestProvider重载QgsVectorDataProvider的纯虚函数:

    • featureSource()
    • getFeatures()
    • wkbType()
    • featureCount()
    • fields()

    重载QgsDataProvider的纯虚函数:

    • crs()
    • extent()
    • isValid()
    • name()
    • description()

    2.1 基础函数实现

    2.1.1 实现QgsVectorDataProvider的纯虚函数

    1) featureSource()

    virtual QgsAbstractFeatureSource *featureSource() const = 0 SIP_FACTORY;
    

    featureSource()返回自定义的QgsTestFeatureSource对象即可,QgsTestFeatureSource继承自QgsAbstractFeatureSource

    QgsAbstractFeatureSource *QgsTestProvider::featureSource() const
    {
      return new QgsTestFeatureSource( this );
    }
    

    2) getFeatures()

    QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) const override = 0;
    

    getFeatures()返回一个迭代器,通过该迭代器遍历features,同样也需要新建类QgsTestFeatureIterator继承自QgsAbstractFeatureIteratorFromSource<QgsTestFeatureSource>

    QgsFeatureIterator QgsTestProvider::getFeatures( const QgsFeatureRequest &request ) const
    {
      QgsTestFeatureSource *featureSrc = static_cast<QgsTestFeatureSource *>( featureSource() );
      return QgsFeatureIterator( new QgsTestFeatureIterator( featureSrc, true, request ) );
    }
    

    3) wkbType()

    QgsWkbTypes::Type wkbType() const override = 0;
    

    wkbType()返回feature的类型,该类型为qgswkbtypes.h中QgsWkbTypes::Type枚举。在自定义Provider中定义一个私有变量存放该类型,则返回该变量值即可。

    QgsWkbTypes::Type QgsTestProvider::wkbType() const
    {
        return mWkbType;
    }
    

    4) featureCount()

    long long featureCount() const override = 0;
    

    返回要素数量。

    5) fields()

    QgsFields fields() const override = 0;
    

    fields()返回属性字段,QGis提供了一个QgsFields类去储存属性字段,可以在provider内定义一个该类对象为成员变量,fields()直接返回该对象即可

    QgsFields mAttributeFields;
    QgsFields QgsTestProvider::fields() const
    {
      return mAttributeFields;
    }
    

    QgsFields提供append函数添加属性字段,每个字段的具体数据由QgsField对象持有。

            QgsField f1;
            f1.setName(QStringLiteral("name"));
            f1.setType(QVariant::Int);
            f1.setTypeName(QStringLiteral("typename"));
            f1.setLength(5);
            f1.setPrecision(1);
            f1.setComment(QStringLiteral("comment"));
            mAttributeFieds.append(f1);
    

    2.1.2 还有一部分是QgsDataProvider的纯虚函数需要实现

    1) crs()

    virtual QgsCoordinateReferenceSystem crs() const = 0;
    

    crs()返回坐标参考系

    2) extent()

    virtual QgsRectangle extent() const = 0;
    

    extent()返回图层的范围,将读取到的数据以QgsRectangle对象返回,这里以一个成员变量mExtent储存数据。

    QgsRectangle QgsTestProvider::extent() const
    {
        //mExtent.setXMinimum(97.3475);
        //mExtent.setXMaximum(108.543);
        //mExtent.setYMinimum(26.0482);
        //mExtent.setYMaximum(34.3152);
        return mExtent;
    }
    

    3) isValid()

    virtual bool isValid() const = 0;
    

    isValid()返回该图层是否有效。返回自定义的成员变量即可

    bool QgsTestProvider::isValid() const
    {
      return mValid;
    }
    

    4) name()

    virtual QString name() const = 0;
    

    name()返回provider的key

    QString  QgsTestProvider::name() const
    {
        return TEXT_PROVIDER_KEY;
    }
    

    5) description()

    virtual QString description() const = 0;
    

    description()返回provider描述

    QString  QgsTestProvider::description() const
    {
        return TEXT_PROVIDER_DESCRIPTION;
    }
    

    2.1.3 重载函数

    3. 新建QgsTestFeatureSource类继承QgsAbstractFeatureSource

    class QgsTestFeatureSource final: public QgsAbstractFeatureSource
    {};
    

    3.1 基础函数实现

    3.1.1 实现QgsAbstractFeatureSource的纯虚函数

    1) getFeatures()

        virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest &request = QgsFeatureRequest() ) = 0 SIP_TRANSFERBACK;
    

    getFeatures()返回QgsFeatureIterator对象, 通过QgsFeatureIterator( QgsAbstractFeatureIterator *iter SIP_TRANSFER )构造函数创建一个有效的迭代器,构造函数实参传入自定义的FeatureIterator。

    QgsFeatureIterator QgsTestFeatureSource::getFeatures( const QgsFeatureRequest &request )
    {
      return QgsFeatureIterator( new QgsTestFeatureIterator( this, false, request ) );
    }
    

    4. 新建QgsTestFeatureIterator类继承QgsAbstractFeatureIteratorFromSource<QgsSDEFeatureSource>

    4.1 基础函数实现

    4.1.1 实现QgsAbstractFeatureIterator的纯虚函数

    1) rewind()

        virtual bool rewind() = 0;
    

    rewind()将迭代器重置到起始位置,在QgsTestFeatureIterator中定义成员变量mIterator用以遍历feature,mIterator类型可以根据储存feature的数据结构确定,以QList为例,则定义为:QList<QgsFeature>::iterator mIterator;
    mClosed变量为父类QgsAbstractFeatureIterator的成员变量,当迭代器关闭时,该变量应置为true。

    bool QgsTestFeatureIterator::rewind()
    {
        if (mClosed)
        {
            return false;
        }
    
        mIterator = mSource->mFeatures.begin();
    
        return true;
    }
    

    2) close()

        virtual bool close() = 0;
    

    close()用以关闭迭代器,函数体内直接调用父类QgsAbstractFeatureIteratorFromSource的iteratorClosed()即可

    bool QgsTestFeatureIterator::close()
    {
        if (mClosed)
        {
            return false;
        }
        iteratorClosed();
        return true;
    }
    

    查看QgsAbstractFeatureIteratorFromSource::iteratorClosed()源码可知,其也是直接调用QgsAbstractFeatureSource的iteratorClosed()函数

    template<typename T>
    class QgsAbstractFeatureIteratorFromSource : public QgsAbstractFeatureIterator
    {
      ......
      protected:
        //! to be called by from subclass in close()
        void iteratorClosed() { mSource->iteratorClosed( this ); }
      ......
    };
    

    3) fetchFeature()

    protected:
      virtual bool fetchFeature( QgsFeature &f ) = 0;
    

    fetchFeature()获取下一个feature,内部实现也是通过mIterator迭代,将获得的feature赋值给形参feature。

    bool QgsTestFeatureIterator::fetchFeature(QgsFeature &feature)
    {
        if (mClosed)
        {
            return false;
        }
    
        if (mIterator != mSource->mFeatures.end())
        {
            feature = *mIterator;
            mIterator++;
            return true;
        }
        else
        {
            close();
            return false;
        }
    }
    

    相关文章

      网友评论

          本文标题:创建QGis的自定义DataProvider

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