mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-07 00:15:48 -04:00
[FEATURE][API] Add new QgsFeatureSink subclass QgsRemappingProxyFeatureSink
This sink allows for transformation of incoming features to match the requirements of storing in an existing destination layer, e.g. by reprojecting the features to the destination's CRS, by coercing geometries to the format required by the destination sink, and by mapping field values from the source to the destination.
This commit is contained in:
parent
78c86ef6ca
commit
93f714d233
170
python/core/auto_generated/qgsremappingproxyfeaturesink.sip.in
Normal file
170
python/core/auto_generated/qgsremappingproxyfeaturesink.sip.in
Normal file
@ -0,0 +1,170 @@
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsremappingproxyfeaturesink.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsRemappingSinkDefinition
|
||||
{
|
||||
%Docstring
|
||||
Defines the parameters used to remap features when creating a QgsRemappingProxyFeatureSink.
|
||||
|
||||
The definition includes parameters required to correctly map incoming features to the structure
|
||||
of the destination sink, e.g. information about how to create output field values and how to transform
|
||||
geometries to match the destination CRS.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsremappingproxyfeaturesink.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QMap< QString, QgsProperty > fieldMap() const;
|
||||
%Docstring
|
||||
Returns the field mapping, which defines how to map the values from incoming features to destination
|
||||
field values.
|
||||
|
||||
Field values are mapped using a QgsProperty source object, which allows either direct field value to field value
|
||||
mapping or use of QgsExpression expressions to transform values to the destination field.
|
||||
|
||||
.. seealso:: :py:func:`setFieldMap`
|
||||
|
||||
.. seealso:: :py:func:`addMappedField`
|
||||
%End
|
||||
|
||||
void setFieldMap( const QMap< QString, QgsProperty > &map );
|
||||
%Docstring
|
||||
Sets the field mapping, which defines how to map the values from incoming features to destination
|
||||
field values.
|
||||
|
||||
Field values are mapped using a QgsProperty source object, which allows either direct field value to field value
|
||||
mapping or use of QgsExpression expressions to transform values to the destination field.
|
||||
|
||||
.. seealso:: :py:func:`fieldMap`
|
||||
|
||||
.. seealso:: :py:func:`addMappedField`
|
||||
%End
|
||||
|
||||
void addMappedField( const QString &destinationField, const QgsProperty &property );
|
||||
%Docstring
|
||||
Adds a mapping for a destination field.
|
||||
|
||||
Field values are mapped using a QgsProperty source object, which allows either direct field value to field value
|
||||
mapping or use of QgsExpression expressions to transform values to the destination field.
|
||||
|
||||
.. seealso:: :py:func:`setFieldMap`
|
||||
|
||||
.. seealso:: :py:func:`fieldMap`
|
||||
%End
|
||||
|
||||
QgsCoordinateTransform transform() const;
|
||||
%Docstring
|
||||
Returns the transform used for reprojecting incoming features to the sink's destination CRS.
|
||||
|
||||
.. seealso:: :py:func:`setTransform`
|
||||
%End
|
||||
|
||||
void setTransform( const QgsCoordinateTransform &transform );
|
||||
%Docstring
|
||||
Sets the ``transform`` used for reprojecting incoming features to the sink's destination CRS.
|
||||
|
||||
.. seealso:: :py:func:`transform`
|
||||
%End
|
||||
|
||||
QgsWkbTypes::Type destinationWkbType() const;
|
||||
%Docstring
|
||||
Returns the WKB geometry type for the destination.
|
||||
|
||||
.. seealso:: :py:func:`setDestinationWkbType`
|
||||
%End
|
||||
|
||||
void setDestinationWkbType( QgsWkbTypes::Type type );
|
||||
%Docstring
|
||||
Sets the WKB geometry ``type`` for the destination.
|
||||
|
||||
.. seealso:: :py:func:`setDestinationWkbType`
|
||||
%End
|
||||
|
||||
QgsFields destinationFields() const;
|
||||
%Docstring
|
||||
Returns the fields for the destination sink.
|
||||
|
||||
.. seealso:: :py:func:`setDestinationFields`
|
||||
%End
|
||||
|
||||
void setDestinationFields( const QgsFields &fields );
|
||||
%Docstring
|
||||
Sets the ``fields`` for the destination sink.
|
||||
|
||||
.. seealso:: :py:func:`destinationFields`
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
class QgsRemappingProxyFeatureSink : QgsFeatureSink
|
||||
{
|
||||
%Docstring
|
||||
A QgsFeatureSink which proxies incoming features to a destination feature sink, after applying
|
||||
transformations and field value mappings.
|
||||
|
||||
This sink allows for transformation of incoming features to match the requirements of storing
|
||||
in an existing destination layer, e.g. by reprojecting the features to the destination's CRS
|
||||
and by coercing geometries to the format required by the destination sink.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgsremappingproxyfeaturesink.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsRemappingProxyFeatureSink( const QgsRemappingSinkDefinition &mappingDefinition, QgsFeatureSink *sink );
|
||||
%Docstring
|
||||
Constructor for QgsRemappingProxyFeatureSink, using the specified ``mappingDefinition``
|
||||
to manipulate features before sending them to the destination ``sink``.
|
||||
%End
|
||||
|
||||
void setExpressionContext( const QgsExpressionContext &context );
|
||||
%Docstring
|
||||
Sets the expression ``context`` to use when evaluating mapped field values.
|
||||
%End
|
||||
|
||||
QgsFeatureList remapFeature( const QgsFeature &feature ) const;
|
||||
%Docstring
|
||||
Remaps a ``feature`` to a set of features compatible with the destination sink.
|
||||
%End
|
||||
|
||||
virtual bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = 0 );
|
||||
|
||||
virtual bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = 0 );
|
||||
|
||||
virtual bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = 0 );
|
||||
|
||||
|
||||
QgsFeatureSink *destinationSink();
|
||||
%Docstring
|
||||
Returns the destination QgsFeatureSink which the proxy will forward features to.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
* *
|
||||
* src/core/qgsremappingproxyfeaturesink.h *
|
||||
* *
|
||||
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
|
||||
************************************************************************/
|
@ -175,6 +175,7 @@
|
||||
%Include auto_generated/qgsreadwritelocker.sip
|
||||
%Include auto_generated/qgsrelation.sip
|
||||
%Include auto_generated/qgsrelationcontext.sip
|
||||
%Include auto_generated/qgsremappingproxyfeaturesink.sip
|
||||
%Include auto_generated/qgsrelationmanager.sip
|
||||
%Include auto_generated/qgsrenderchecker.sip
|
||||
%Include auto_generated/qgsrendercontext.sip
|
||||
|
@ -369,6 +369,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsrelationcontext.cpp
|
||||
qgsweakrelation.cpp
|
||||
qgsrelationmanager.cpp
|
||||
qgsremappingproxyfeaturesink.cpp
|
||||
qgsrenderchecker.cpp
|
||||
qgsrendercontext.cpp
|
||||
qgsrunprocess.cpp
|
||||
@ -910,6 +911,7 @@ SET(QGIS_CORE_HDRS
|
||||
qgsreadwritelocker.h
|
||||
qgsrelation.h
|
||||
qgsrelationcontext.h
|
||||
qgsremappingproxyfeaturesink.h
|
||||
qgsweakrelation.h
|
||||
qgsrelationmanager.h
|
||||
qgsrenderchecker.h
|
||||
|
@ -1313,12 +1313,20 @@ json QgsGeometry::asJsonObject( int precision ) const
|
||||
QVector<QgsGeometry> QgsGeometry::coerceToType( const QgsWkbTypes::Type type ) const
|
||||
{
|
||||
QVector< QgsGeometry > res;
|
||||
if ( wkbType() == type )
|
||||
if ( isNull() )
|
||||
return res;
|
||||
|
||||
if ( wkbType() == type || type == QgsWkbTypes::Unknown )
|
||||
{
|
||||
res << *this;
|
||||
return res;
|
||||
}
|
||||
|
||||
if ( type == QgsWkbTypes::NoGeometry )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
QgsGeometry newGeom = *this;
|
||||
|
||||
// Curved -> straight
|
||||
|
119
src/core/qgsremappingproxyfeaturesink.cpp
Normal file
119
src/core/qgsremappingproxyfeaturesink.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/***************************************************************************
|
||||
qgsremappingproxyfeaturesink.cpp
|
||||
----------------------
|
||||
begin : April 2020
|
||||
copyright : (C) 2020 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsremappingproxyfeaturesink.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
QgsRemappingProxyFeatureSink::QgsRemappingProxyFeatureSink( const QgsRemappingSinkDefinition &mappingDefinition, QgsFeatureSink *sink )
|
||||
: QgsFeatureSink()
|
||||
, mDefinition( mappingDefinition )
|
||||
, mSink( sink )
|
||||
{}
|
||||
|
||||
void QgsRemappingProxyFeatureSink::setExpressionContext( const QgsExpressionContext &context )
|
||||
{
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
QgsFeatureList QgsRemappingProxyFeatureSink::remapFeature( const QgsFeature &feature ) const
|
||||
{
|
||||
QgsFeatureList res;
|
||||
|
||||
mContext.setFeature( feature );
|
||||
|
||||
// remap fields first
|
||||
QgsFeature f;
|
||||
f.setFields( mDefinition.destinationFields(), true );
|
||||
QgsAttributes attributes;
|
||||
const QMap< QString, QgsProperty > fieldMap = mDefinition.fieldMap();
|
||||
for ( const QgsField &field : mDefinition.destinationFields() )
|
||||
{
|
||||
if ( fieldMap.contains( field.name() ) )
|
||||
{
|
||||
attributes.append( fieldMap.value( field.name() ).value( mContext ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
attributes.append( QVariant() );
|
||||
}
|
||||
}
|
||||
f.setAttributes( attributes );
|
||||
|
||||
// make geometries compatible, and reproject if necessary
|
||||
if ( feature.hasGeometry() )
|
||||
{
|
||||
const QVector< QgsGeometry > geometries = feature.geometry().coerceToType( mDefinition.destinationWkbType() );
|
||||
if ( !geometries.isEmpty() )
|
||||
{
|
||||
res.reserve( geometries.size() );
|
||||
for ( const QgsGeometry &geometry : geometries )
|
||||
{
|
||||
QgsFeature featurePart = f;
|
||||
|
||||
QgsGeometry reproject = geometry;
|
||||
try
|
||||
{
|
||||
reproject.transform( mDefinition.transform() );
|
||||
featurePart.setGeometry( reproject );
|
||||
}
|
||||
catch ( QgsCsException & )
|
||||
{
|
||||
QgsLogger::warning( QObject::tr( "Error reprojecting feature geometry" ) );
|
||||
featurePart.clearGeometry();
|
||||
}
|
||||
res << featurePart;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
f.clearGeometry();
|
||||
res << f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
res << f;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool QgsRemappingProxyFeatureSink::addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags )
|
||||
{
|
||||
QgsFeatureList features = remapFeature( feature );
|
||||
return mSink->addFeatures( features, flags );
|
||||
}
|
||||
|
||||
bool QgsRemappingProxyFeatureSink::addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags )
|
||||
{
|
||||
bool res = true;
|
||||
for ( QgsFeature &f : features )
|
||||
{
|
||||
res = addFeature( f, flags ) && res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool QgsRemappingProxyFeatureSink::addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags )
|
||||
{
|
||||
QgsFeature f;
|
||||
bool res = true;
|
||||
while ( iterator.nextFeature( f ) )
|
||||
{
|
||||
res = addFeature( f, flags ) && res;
|
||||
}
|
||||
return res;
|
||||
}
|
183
src/core/qgsremappingproxyfeaturesink.h
Normal file
183
src/core/qgsremappingproxyfeaturesink.h
Normal file
@ -0,0 +1,183 @@
|
||||
/***************************************************************************
|
||||
qgsremappingproxyfeaturesink.h
|
||||
----------------------
|
||||
begin : April 2020
|
||||
copyright : (C) 2020 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSREMAPPINGPROXYFEATURESINK_H
|
||||
#define QGSREMAPPINGPROXYFEATURESINK_H
|
||||
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsfeaturesink.h"
|
||||
#include "qgsproperty.h"
|
||||
|
||||
/**
|
||||
* \class QgsRemappingSinkDefinition
|
||||
* \ingroup core
|
||||
* Defines the parameters used to remap features when creating a QgsRemappingProxyFeatureSink.
|
||||
*
|
||||
* The definition includes parameters required to correctly map incoming features to the structure
|
||||
* of the destination sink, e.g. information about how to create output field values and how to transform
|
||||
* geometries to match the destination CRS.
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class CORE_EXPORT QgsRemappingSinkDefinition
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Returns the field mapping, which defines how to map the values from incoming features to destination
|
||||
* field values.
|
||||
*
|
||||
* Field values are mapped using a QgsProperty source object, which allows either direct field value to field value
|
||||
* mapping or use of QgsExpression expressions to transform values to the destination field.
|
||||
*
|
||||
* \see setFieldMap()
|
||||
* \see addMappedField()
|
||||
*/
|
||||
QMap< QString, QgsProperty > fieldMap() const { return mFieldMap; }
|
||||
|
||||
/**
|
||||
* Sets the field mapping, which defines how to map the values from incoming features to destination
|
||||
* field values.
|
||||
*
|
||||
* Field values are mapped using a QgsProperty source object, which allows either direct field value to field value
|
||||
* mapping or use of QgsExpression expressions to transform values to the destination field.
|
||||
*
|
||||
* \see fieldMap()
|
||||
* \see addMappedField()
|
||||
*/
|
||||
void setFieldMap( const QMap< QString, QgsProperty > &map ) { mFieldMap = map; }
|
||||
|
||||
/**
|
||||
* Adds a mapping for a destination field.
|
||||
*
|
||||
* Field values are mapped using a QgsProperty source object, which allows either direct field value to field value
|
||||
* mapping or use of QgsExpression expressions to transform values to the destination field.
|
||||
*
|
||||
* \see setFieldMap()
|
||||
* \see fieldMap()
|
||||
*/
|
||||
void addMappedField( const QString &destinationField, const QgsProperty &property ) { mFieldMap.insert( destinationField, property ); }
|
||||
|
||||
/**
|
||||
* Returns the transform used for reprojecting incoming features to the sink's destination CRS.
|
||||
*
|
||||
* \see setTransform()
|
||||
*/
|
||||
QgsCoordinateTransform transform() const { return mTransform; }
|
||||
|
||||
/**
|
||||
* Sets the \a transform used for reprojecting incoming features to the sink's destination CRS.
|
||||
*
|
||||
* \see transform()
|
||||
*/
|
||||
void setTransform( const QgsCoordinateTransform &transform ) { mTransform = transform; }
|
||||
|
||||
/**
|
||||
* Returns the WKB geometry type for the destination.
|
||||
*
|
||||
* \see setDestinationWkbType()
|
||||
*/
|
||||
QgsWkbTypes::Type destinationWkbType() const { return mDestinationWkbType; }
|
||||
|
||||
/**
|
||||
* Sets the WKB geometry \a type for the destination.
|
||||
*
|
||||
* \see setDestinationWkbType()
|
||||
*/
|
||||
void setDestinationWkbType( QgsWkbTypes::Type type ) { mDestinationWkbType = type; }
|
||||
|
||||
/**
|
||||
* Returns the fields for the destination sink.
|
||||
*
|
||||
* \see setDestinationFields()
|
||||
*/
|
||||
QgsFields destinationFields() const { return mDestinationFields; }
|
||||
|
||||
/**
|
||||
* Sets the \a fields for the destination sink.
|
||||
*
|
||||
* \see destinationFields()
|
||||
*/
|
||||
void setDestinationFields( const QgsFields &fields ) { mDestinationFields = fields; }
|
||||
|
||||
private:
|
||||
|
||||
QMap< QString, QgsProperty > mFieldMap;
|
||||
|
||||
QgsCoordinateTransform mTransform;
|
||||
|
||||
QgsWkbTypes::Type mDestinationWkbType = QgsWkbTypes::Unknown;
|
||||
|
||||
QgsFields mDestinationFields;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \class QgsRemappingProxyFeatureSink
|
||||
* \ingroup core
|
||||
* A QgsFeatureSink which proxies incoming features to a destination feature sink, after applying
|
||||
* transformations and field value mappings.
|
||||
*
|
||||
* This sink allows for transformation of incoming features to match the requirements of storing
|
||||
* in an existing destination layer, e.g. by reprojecting the features to the destination's CRS
|
||||
* and by coercing geometries to the format required by the destination sink.
|
||||
*
|
||||
* \since QGIS 3.14
|
||||
*/
|
||||
class CORE_EXPORT QgsRemappingProxyFeatureSink : public QgsFeatureSink
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsRemappingProxyFeatureSink, using the specified \a mappingDefinition
|
||||
* to manipulate features before sending them to the destination \a sink.
|
||||
*/
|
||||
QgsRemappingProxyFeatureSink( const QgsRemappingSinkDefinition &mappingDefinition, QgsFeatureSink *sink );
|
||||
|
||||
/**
|
||||
* Sets the expression \a context to use when evaluating mapped field values.
|
||||
*/
|
||||
void setExpressionContext( const QgsExpressionContext &context );
|
||||
|
||||
/**
|
||||
* Remaps a \a feature to a set of features compatible with the destination sink.
|
||||
*/
|
||||
QgsFeatureList remapFeature( const QgsFeature &feature ) const;
|
||||
|
||||
bool addFeature( QgsFeature &feature, QgsFeatureSink::Flags flags = nullptr ) override;
|
||||
bool addFeatures( QgsFeatureList &features, QgsFeatureSink::Flags flags = nullptr ) override;
|
||||
bool addFeatures( QgsFeatureIterator &iterator, QgsFeatureSink::Flags flags = nullptr ) override;
|
||||
|
||||
/**
|
||||
* Returns the destination QgsFeatureSink which the proxy will forward features to.
|
||||
*/
|
||||
QgsFeatureSink *destinationSink() { return mSink; }
|
||||
|
||||
private:
|
||||
|
||||
QgsRemappingSinkDefinition mDefinition;
|
||||
QgsFeatureSink *mSink = nullptr;
|
||||
mutable QgsExpressionContext mContext;
|
||||
};
|
||||
|
||||
#endif // QGSREMAPPINGPROXYFEATURESINK_H
|
||||
|
||||
|
||||
|
||||
|
@ -21,7 +21,16 @@ from qgis.core import (QgsFeatureStore,
|
||||
QgsField,
|
||||
QgsFields,
|
||||
QgsCoordinateReferenceSystem,
|
||||
QgsProxyFeatureSink)
|
||||
QgsProxyFeatureSink,
|
||||
QgsRemappingProxyFeatureSink,
|
||||
QgsRemappingSinkDefinition,
|
||||
QgsWkbTypes,
|
||||
QgsCoordinateTransform,
|
||||
QgsProject,
|
||||
QgsProperty,
|
||||
QgsExpressionContext,
|
||||
QgsExpressionContextScope
|
||||
)
|
||||
from qgis.PyQt.QtCore import QVariant
|
||||
from qgis.testing import start_app, unittest
|
||||
start_app()
|
||||
@ -94,6 +103,71 @@ class TestQgsFeatureSink(unittest.TestCase):
|
||||
self.assertEqual(store.features()[1]['fldtxt'], 'test2')
|
||||
self.assertEqual(store.features()[2]['fldtxt'], 'test3')
|
||||
|
||||
def testRemappingSink(self):
|
||||
"""
|
||||
Test remapping features
|
||||
"""
|
||||
fields = QgsFields()
|
||||
fields.append(QgsField('fldtxt', QVariant.String))
|
||||
fields.append(QgsField('fldint', QVariant.Int))
|
||||
fields.append(QgsField('fldtxt2', QVariant.String))
|
||||
|
||||
store = QgsFeatureStore(fields, QgsCoordinateReferenceSystem('EPSG:3857'))
|
||||
|
||||
mapping_def = QgsRemappingSinkDefinition()
|
||||
mapping_def.setDestinationWkbType(QgsWkbTypes.Point)
|
||||
self.assertEqual(mapping_def.destinationWkbType(), QgsWkbTypes.Point)
|
||||
mapping_def.setTransform(QgsCoordinateTransform(QgsCoordinateReferenceSystem('EPSG:4326'), QgsCoordinateReferenceSystem('EPSG:3857'), QgsProject.instance()))
|
||||
self.assertEqual(mapping_def.transform().sourceCrs().authid(), 'EPSG:4326')
|
||||
self.assertEqual(mapping_def.transform().destinationCrs().authid(), 'EPSG:3857')
|
||||
mapping_def.setDestinationFields(fields)
|
||||
self.assertEqual(mapping_def.destinationFields(), fields)
|
||||
mapping_def.addMappedField('fldtxt2', QgsProperty.fromField('fld1'))
|
||||
mapping_def.addMappedField('fldint', QgsProperty.fromExpression('@myval * fldint'))
|
||||
|
||||
self.assertEqual(mapping_def.fieldMap()['fldtxt2'].field(), 'fld1')
|
||||
self.assertEqual(mapping_def.fieldMap()['fldint'].expressionString(), '@myval * fldint')
|
||||
|
||||
proxy = QgsRemappingProxyFeatureSink(mapping_def, store)
|
||||
self.assertEqual(proxy.destinationSink(), store)
|
||||
|
||||
self.assertEqual(len(store), 0)
|
||||
|
||||
incoming_fields = QgsFields()
|
||||
incoming_fields.append(QgsField('fld1', QVariant.String))
|
||||
incoming_fields.append(QgsField('fldint', QVariant.Int))
|
||||
|
||||
context = QgsExpressionContext()
|
||||
scope = QgsExpressionContextScope()
|
||||
scope.setVariable('myval', 2)
|
||||
context.appendScope(scope)
|
||||
context.setFields(incoming_fields)
|
||||
proxy.setExpressionContext(context)
|
||||
|
||||
f = QgsFeature()
|
||||
f.setFields(incoming_fields)
|
||||
f.setAttributes(["test", 123])
|
||||
f.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(1, 2)))
|
||||
self.assertTrue(proxy.addFeature(f))
|
||||
self.assertEqual(len(store), 1)
|
||||
self.assertEqual(store.features()[0].geometry().asWkt(1), 'Point (111319.5 222684.2)')
|
||||
self.assertEqual(store.features()[0].attributes(), [None, 246, 'test'])
|
||||
|
||||
f2 = QgsFeature()
|
||||
f2.setAttributes(["test2", 457])
|
||||
f2.setGeometry(QgsGeometry.fromWkt('LineString( 1 1, 2 2)'))
|
||||
f3 = QgsFeature()
|
||||
f3.setAttributes(["test3", 888])
|
||||
f3.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(3, 4)))
|
||||
self.assertTrue(proxy.addFeatures([f2, f3]))
|
||||
self.assertEqual(len(store), 4)
|
||||
self.assertEqual(store.features()[1].attributes(), [None, 914, 'test2'])
|
||||
self.assertEqual(store.features()[2].attributes(), [None, 914, 'test2'])
|
||||
self.assertEqual(store.features()[3].attributes(), [None, 1776, 'test3'])
|
||||
self.assertEqual(store.features()[1].geometry().asWkt(1), 'Point (111319.5 111325.1)')
|
||||
self.assertEqual(store.features()[2].geometry().asWkt(1), 'Point (222639 222684.2)')
|
||||
self.assertEqual(store.features()[3].geometry().asWkt(1), 'Point (333958.5 445640.1)')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user