makeFeatureCompatible on a single input feature

This commit is contained in:
Alessandro Pasotti 2018-09-24 12:13:11 +02:00
parent 7e8592bca2
commit 8d82ce86cc
3 changed files with 78 additions and 30 deletions

View File

@ -177,8 +177,26 @@ are padded with NULL values to match the required length).
.. versionadded:: 3.4 .. versionadded:: 3.4
%End %End
static const QgsFeatureList makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer &layer );
%Docstring
Converts input ``feature`` to be compatible with the given ``layer``.
static QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer &layer ); This function returns a new list of transformed features compatible with the input
layer, note that the number of features returned might be greater than one.
The following operations will be performed to convert the input features:
- convert single geometries to multi part
- drop additional attributes
- drop geometry if layer is geometry-less
- add missing attribute fields
- add back M/Z values (initialized to 0)
- drop Z/M
- convert multi part geometries to single part
.. versionadded:: 3.4
%End
static const QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer &layer );
%Docstring %Docstring
Converts input ``features`` to be compatible with the given ``layer``. Converts input ``features`` to be compatible with the given ``layer``.

View File

@ -561,31 +561,30 @@ void QgsVectorLayerUtils::matchAttributesToFields( QgsFeature &feature, const Qg
} }
} }
QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer &layer ) const QgsFeatureList QgsVectorLayerUtils::makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer &layer )
{ {
QgsWkbTypes::Type inputWkbType( layer.wkbType( ) ); QgsWkbTypes::Type inputWkbType( layer.wkbType( ) );
QgsFeatureList resultFeatures; QgsFeatureList resultFeatures;
for ( const QgsFeature &f : features ) QgsFeature newF( feature );
// Fix attributes
QgsVectorLayerUtils::matchAttributesToFields( newF, layer.fields( ) );
// Does geometry need tranformations?
QgsWkbTypes::GeometryType newFGeomType( QgsWkbTypes::geometryType( newF.geometry().wkbType() ) );
bool newFHasGeom = newFGeomType !=
QgsWkbTypes::GeometryType::UnknownGeometry &&
newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
bool layerHasGeom = inputWkbType !=
QgsWkbTypes::Type::NoGeometry &&
inputWkbType != QgsWkbTypes::Type::Unknown;
// Drop geometry if layer is geometry-less
if ( newFHasGeom && ! layerHasGeom )
{
QgsFeature _f = QgsFeature( layer.fields() );
_f.setAttributes( newF.attributes() );
resultFeatures.append( _f );
}
else
{ {
QgsFeature newF( f );
// Fix attributes
QgsVectorLayerUtils::matchAttributesToFields( newF, layer.fields( ) );
// Does geometry need tranformations?
QgsWkbTypes::GeometryType newFGeomType( QgsWkbTypes::geometryType( newF.geometry().wkbType() ) );
bool newFHasGeom = newFGeomType !=
QgsWkbTypes::GeometryType::UnknownGeometry &&
newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
bool layerHasGeom = inputWkbType !=
QgsWkbTypes::Type::NoGeometry &&
inputWkbType != QgsWkbTypes::Type::Unknown;
// Drop geometry if layer is geometry-less
if ( newFHasGeom && ! layerHasGeom )
{
QgsFeature _f = QgsFeature( layer.fields() );
_f.setAttributes( newF.attributes() );
resultFeatures.append( _f );
continue; // Skip the rest
}
// Geometry need fixing // Geometry need fixing
if ( newFHasGeom && layerHasGeom && newF.geometry().wkbType() != inputWkbType ) if ( newFHasGeom && layerHasGeom && newF.geometry().wkbType() != inputWkbType )
{ {
@ -627,15 +626,15 @@ QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList
{ {
QgsGeometry newGeom( newF.geometry( ) ); QgsGeometry newGeom( newF.geometry( ) );
const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) ); const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
QgsAttributeMap attrMap;
for ( int j = 0; j < newF.fields().count(); j++ )
{
attrMap[j] = newF.attribute( j );
}
for ( int i = 0; i < parts->partCount( ); i++ ) for ( int i = 0; i < parts->partCount( ); i++ )
{ {
QgsGeometry g( parts->geometryN( i )->clone() ); QgsGeometry g( parts->geometryN( i )->clone() );
QgsAttributeMap attrMap; QgsFeature _f( createFeature( &layer, g, attrMap ) );
for ( int j = 0; j < newF.fields().count(); j++ )
{
attrMap[j] = newF.attribute( j );
}
QgsFeature _f( QgsVectorLayerUtils::createFeature( &layer, g, attrMap ) );
resultFeatures.append( _f ); resultFeatures.append( _f );
} }
} }
@ -649,7 +648,20 @@ QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList
resultFeatures.append( newF ); resultFeatures.append( newF );
} }
} }
return resultFeatures; return resultFeatures;
}
const QgsFeatureList QgsVectorLayerUtils::makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer &layer )
{
QgsFeatureList resultFeatures;
for ( const QgsFeature &f : features )
{
for ( const auto &_f : makeFeatureCompatible( f, layer ) )
{
resultFeatures.append( _f );
}
}
return resultFeatures;
} }
QList<QgsVectorLayer *> QgsVectorLayerUtils::QgsDuplicateFeatureContext::layers() const QList<QgsVectorLayer *> QgsVectorLayerUtils::QgsDuplicateFeatureContext::layers() const

View File

@ -188,6 +188,24 @@ class CORE_EXPORT QgsVectorLayerUtils
*/ */
static void matchAttributesToFields( QgsFeature &feature, const QgsFields &fields ); static void matchAttributesToFields( QgsFeature &feature, const QgsFields &fields );
/**
* Converts input \a feature to be compatible with the given \a layer.
*
* This function returns a new list of transformed features compatible with the input
* layer, note that the number of features returned might be greater than one.
*
* The following operations will be performed to convert the input features:
* - convert single geometries to multi part
* - drop additional attributes
* - drop geometry if layer is geometry-less
* - add missing attribute fields
* - add back M/Z values (initialized to 0)
* - drop Z/M
* - convert multi part geometries to single part
*
* \since QGIS 3.4
*/
static const QgsFeatureList makeFeatureCompatible( const QgsFeature &feature, const QgsVectorLayer &layer );
/** /**
* Converts input \a features to be compatible with the given \a layer. * Converts input \a features to be compatible with the given \a layer.
@ -207,7 +225,7 @@ class CORE_EXPORT QgsVectorLayerUtils
* *
* \since QGIS 3.4 * \since QGIS 3.4
*/ */
static QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer &layer ); static const QgsFeatureList makeFeaturesCompatible( const QgsFeatureList &features, const QgsVectorLayer &layer );
}; };