Port processing combineFields to c++

This commit is contained in:
Nyall Dawson 2017-09-21 15:28:22 +10:00
parent cf636dcafa
commit c41dca937c
11 changed files with 100 additions and 31 deletions

View File

@ -193,6 +193,15 @@ class QgsProcessingUtils
:rtype: str
%End
static QgsFields combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB );
%Docstring
Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
Duplicate field names will be altered to "name_2", "name_3", etc, finding the first
non-duplicate name.
:rtype: QgsFields
%End
};
class QgsProcessingFeatureSource : QgsFeatureSource

View File

@ -37,7 +37,8 @@ from qgis.core import (QgsFeature,
QgsProcessingParameterField,
QgsProcessingParameterFeatureSink,
QgsProcessingException,
QgsExpression)
QgsExpression,
QgsProcessingUtils)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.tools import vector
@ -89,7 +90,7 @@ class HubLines(QgisAlgorithm):
field_spoke = self.parameterAsString(parameters, self.SPOKE_FIELD, context)
field_spoke_index = hub_source.fields().lookupField(field_spoke)
fields = vector.combineFields(hub_source.fields(), spoke_source.fields())
fields = QgsProcessingUtils.combineFields(hub_source.fields(), spoke_source.fields())
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.LineString, hub_source.sourceCrs())

View File

@ -82,7 +82,7 @@ class JoinAttributes(QgisAlgorithm):
joinField1Index = input.fields().lookupField(field)
joinField2Index = input2.fields().lookupField(field2)
outFields = vector.combineFields(input.fields(), input2.fields())
outFields = QgsProcessingUtils.combineFields(input.fields(), input2.fields())
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
outFields, input.wkbType(), input.sourceCrs())

View File

@ -37,6 +37,7 @@ from qgis.core import (QgsFields,
QgsFeatureRequest,
QgsGeometry,
QgsProcessing,
QgsProcessingUtils,
QgsProcessingParameterBoolean,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
@ -148,7 +149,7 @@ class SpatialJoin(QgisAlgorithm):
if idx >= 0:
fields_to_join.append(join_source.fields().at(idx))
out_fields = vector.combineFields(source_fields, fields_to_join)
out_fields = QgsProcessingUtils.combineFields(source_fields, fields_to_join)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
out_fields, source.wkbType(), source.sourceCrs())

View File

@ -43,6 +43,7 @@ from qgis.core import (NULL,
QgsDateTimeStatisticalSummary,
QgsStringStatisticalSummary,
QgsProcessing,
QgsProcessingUtils,
QgsProcessingParameterBoolean,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterEnum,
@ -247,7 +248,7 @@ class SpatialJoinSummary(QgisAlgorithm):
else:
addFieldKeepType(join_field, f[0])
out_fields = vector.combineFields(source_fields, fields_to_join)
out_fields = QgsProcessingUtils.combineFields(source_fields, fields_to_join)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
out_fields, source.wkbType(), source.sourceCrs())

View File

@ -36,6 +36,7 @@ from qgis.core import (QgsFeature,
NULL,
QgsWkbTypes,
QgsMessageLog,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsSpatialIndex)
@ -79,7 +80,7 @@ class SymmetricalDifference(QgisAlgorithm):
sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)
geomType = QgsWkbTypes.multiType(sourceA.wkbType())
fields = vector.combineFields(sourceA.fields(), sourceB.fields())
fields = QgsProcessingUtils.combineFields(sourceA.fields(), sourceB.fields())
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, sourceA.sourceCrs())

View File

@ -34,7 +34,7 @@ from qgis.core import (QgsFeatureRequest,
QgsFeatureSink,
QgsGeometry,
QgsWkbTypes,
QgsMessageLog,
QgsProcessingUtils,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsSpatialIndex)
@ -79,7 +79,7 @@ class Union(QgisAlgorithm):
sourceB = self.parameterAsSource(parameters, self.OVERLAY, context)
geomType = QgsWkbTypes.multiType(sourceA.wkbType())
fields = vector.combineFields(sourceA.fields(), sourceB.fields())
fields = QgsProcessingUtils.combineFields(sourceA.fields(), sourceB.fields())
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, geomType, sourceA.sourceCrs())

View File

@ -174,29 +174,6 @@ def extractPoints(geom):
return points
def combineFields(fieldsA, fieldsB):
"""Create single field map from two input field maps.
"""
fields = []
fields.extend(fieldsA)
namesA = [str(f.name()).lower() for f in fieldsA]
for field in fieldsB:
name = str(field.name()).lower()
if name in namesA:
idx = 2
newName = name + '_' + str(idx)
while newName in namesA:
idx += 1
newName = name + '_' + str(idx)
field = QgsField(newName, field.type(), field.typeName())
fields.append(field)
real_fields = QgsFields()
for f in fields:
real_fields.append(f)
return real_fields
def checkMinDistance(point, index, distance, points):
"""Check if distance from given point to all other points is greater
than given value.

View File

@ -555,6 +555,41 @@ QString QgsProcessingUtils::convertToCompatibleFormat( const QgsVectorLayer *vl,
}
}
QgsFields QgsProcessingUtils::combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB )
{
QgsFields outFields = fieldsA;
QSet< QString > usedNames;
for ( const QgsField &f : fieldsA )
{
usedNames.insert( f.name().toLower() );
}
for ( const QgsField &f : fieldsB )
{
if ( usedNames.contains( f.name().toLower() ) )
{
int idx = 2;
QString newName = f.name() + '_' + QString::number( idx );
while ( usedNames.contains( newName.toLower() ) )
{
idx++;
newName = f.name() + '_' + QString::number( idx );
}
QgsField newField = f;
newField.setName( newName );
outFields.append( newField );
usedNames.insert( newName.toLower() );
}
else
{
usedNames.insert( f.name().toLower() );
outFields.append( f );
}
}
return outFields;
}
//
// QgsProcessingFeatureSource

View File

@ -224,6 +224,14 @@ class CORE_EXPORT QgsProcessingUtils
QgsProcessingContext &context,
QgsProcessingFeedback *feedback );
/**
* Combines two field lists, avoiding duplicate field names (in a case-insensitive manner).
*
* Duplicate field names will be altered to "name_2", "name_3", etc, finding the first
* non-duplicate name.
*/
static QgsFields combineFields( const QgsFields &fieldsA, const QgsFields &fieldsB );
private:
static bool canUseLayer( const QgsRasterLayer *layer );

View File

@ -352,6 +352,7 @@ class TestQgsProcessing: public QObject
void tempUtils();
void convertCompatible();
void create();
void combineFields();
private:
@ -5443,5 +5444,40 @@ void TestQgsProcessing::create()
QCOMPARE( newInstance->provider(), &p );
}
void TestQgsProcessing::combineFields()
{
QgsFields a;
QgsFields b;
// combine empty fields
QgsFields res = QgsProcessingUtils::combineFields( a, b );
QVERIFY( res.isEmpty() );
// fields in a
a.append( QgsField( "name" ) );
res = QgsProcessingUtils::combineFields( a, b );
QCOMPARE( res.count(), 1 );
QCOMPARE( res.at( 0 ).name(), QStringLiteral( "name" ) );
b.append( QgsField( "name" ) );
res = QgsProcessingUtils::combineFields( a, b );
QCOMPARE( res.count(), 2 );
QCOMPARE( res.at( 0 ).name(), QStringLiteral( "name" ) );
QCOMPARE( res.at( 1 ).name(), QStringLiteral( "name_2" ) );
a.append( QgsField( "NEW" ) );
res = QgsProcessingUtils::combineFields( a, b );
QCOMPARE( res.count(), 3 );
QCOMPARE( res.at( 0 ).name(), QStringLiteral( "name" ) );
QCOMPARE( res.at( 1 ).name(), QStringLiteral( "NEW" ) );
QCOMPARE( res.at( 2 ).name(), QStringLiteral( "name_2" ) );
b.append( QgsField( "new" ) );
res = QgsProcessingUtils::combineFields( a, b );
QCOMPARE( res.count(), 4 );
QCOMPARE( res.at( 0 ).name(), QStringLiteral( "name" ) );
QCOMPARE( res.at( 1 ).name(), QStringLiteral( "NEW" ) );
QCOMPARE( res.at( 2 ).name(), QStringLiteral( "name_2" ) );
QCOMPARE( res.at( 3 ).name(), QStringLiteral( "new_2" ) );
}
QGSTEST_MAIN( TestQgsProcessing )
#include "testqgsprocessing.moc"