QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsalgorithmuniquevalueindex.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsalgorithmuniquevalueindex.cpp
3  ---------------------
4  begin : January 2018
5  copyright : (C) 2018 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
19 
21 
22 QString QgsAddUniqueValueIndexAlgorithm::name() const
23 {
24  return QStringLiteral( "adduniquevalueindexfield" );
25 }
26 
27 QString QgsAddUniqueValueIndexAlgorithm::displayName() const
28 {
29  return QObject::tr( "Add unique value index field" );
30 }
31 
32 QStringList QgsAddUniqueValueIndexAlgorithm::tags() const
33 {
34  return QObject::tr( "categorize,categories,category,reclassify,classes,create" ).split( ',' );
35 }
36 
37 QString QgsAddUniqueValueIndexAlgorithm::group() const
38 {
39  return QObject::tr( "Vector table" );
40 }
41 
42 QString QgsAddUniqueValueIndexAlgorithm::groupId() const
43 {
44  return QStringLiteral( "vectortable" );
45 }
46 
47 void QgsAddUniqueValueIndexAlgorithm::initAlgorithm( const QVariantMap & )
48 {
49  addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ),
50  QList< int >() << QgsProcessing::TypeVector ) );
51  addParameter( new QgsProcessingParameterField( QStringLiteral( "FIELD" ), QObject::tr( "Class field" ), QVariant(),
52  QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any ) );
53  addParameter( new QgsProcessingParameterString( QStringLiteral( "FIELD_NAME" ),
54  QObject::tr( "Output field name" ), QStringLiteral( "NUM_FIELD" ) ) );
55 
56  std::unique_ptr< QgsProcessingParameterFeatureSink > classedOutput = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral( "OUTPUT" ), QObject::tr( "Layer with index field" ), QgsProcessing::TypeVectorAnyGeometry, QVariant(), true );
57  classedOutput->setCreateByDefault( true );
58  addParameter( classedOutput.release() );
59 
60  std::unique_ptr< QgsProcessingParameterFeatureSink > summaryOutput = std::make_unique< QgsProcessingParameterFeatureSink >( QStringLiteral( "SUMMARY_OUTPUT" ), QObject::tr( "Class summary" ),
61  QgsProcessing::TypeVector, QVariant(), true );
62  summaryOutput->setCreateByDefault( false );
63  addParameter( summaryOutput.release() );
64 }
65 
66 QString QgsAddUniqueValueIndexAlgorithm::shortHelpString() const
67 {
68  return QObject::tr( "This algorithm takes a vector layer and an attribute and adds a new numeric field. Values in this field correspond to values in the specified attribute, so features with the same "
69  "value for the attribute will have the same value in the new numeric field. This creates a numeric equivalent of the specified attribute, which defines the same classes.\n\n"
70  "The new attribute is not added to the input layer but a new layer is generated instead.\n\n"
71  "Optionally, a separate table can be output which contains a summary of the class field values mapped to the new unique numeric value." );
72 }
73 
74 QgsAddUniqueValueIndexAlgorithm *QgsAddUniqueValueIndexAlgorithm::createInstance() const
75 {
76  return new QgsAddUniqueValueIndexAlgorithm();
77 }
78 
79 QVariantMap QgsAddUniqueValueIndexAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
80 {
81  std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
82  if ( !source )
83  throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
84 
85  const QString newFieldName = parameterAsString( parameters, QStringLiteral( "FIELD_NAME" ), context );
86  QgsFields fields = source->fields();
87  const QgsField newField = QgsField( newFieldName, QVariant::Int );
88  fields.append( newField );
89 
90  QString dest;
91  std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, source->wkbType(), source->sourceCrs() ) );
92 
93  const QString sourceFieldName = parameterAsString( parameters, QStringLiteral( "FIELD" ), context );
94  const int fieldIndex = source->fields().lookupField( sourceFieldName );
95  if ( fieldIndex < 0 )
96  throw QgsProcessingException( QObject::tr( "Invalid field name %1" ).arg( sourceFieldName ) );
97 
98  QString summaryDest;
99  QgsFields summaryFields;
100  summaryFields.append( newField );
101  summaryFields.append( source->fields().at( fieldIndex ) );
102  std::unique_ptr< QgsFeatureSink > summarySink( parameterAsSink( parameters, QStringLiteral( "SUMMARY_OUTPUT" ), context, summaryDest, summaryFields, QgsWkbTypes::NoGeometry ) );
103 
104  QHash< QVariant, int > classes;
105 
107 
108  const long count = source->featureCount();
109  const double step = count > 0 ? 100.0 / count : 1;
110  int current = 0;
111  QgsFeature feature;
112  while ( it.nextFeature( feature ) )
113  {
114  if ( feedback->isCanceled() )
115  {
116  break;
117  }
118 
119  QgsAttributes attributes = feature.attributes();
120  const QVariant clazz = attributes.at( fieldIndex );
121 
122  int thisValue = classes.value( clazz, -1 );
123  if ( thisValue == -1 )
124  {
125  thisValue = classes.count();
126  classes.insert( clazz, thisValue );
127  }
128 
129  if ( sink )
130  {
131  attributes.append( thisValue );
132  feature.setAttributes( attributes );
133  if ( !sink->addFeature( feature, QgsFeatureSink::FastInsert ) )
134  throw QgsProcessingException( writeFeatureError( sink.get(), parameters, QStringLiteral( "OUTPUT" ) ) );
135  }
136 
137  feedback->setProgress( current * step );
138  current++;
139  }
140 
141  if ( summarySink )
142  {
143  //generate summary table - first we make a sorted version of the classes
144  QMap< int, QVariant > sorted;
145  for ( auto classIt = classes.constBegin(); classIt != classes.constEnd(); ++classIt )
146  {
147  sorted.insert( classIt.value(), classIt.key() );
148  }
149  // now save them
150  for ( auto sortedIt = sorted.constBegin(); sortedIt != sorted.constEnd(); ++sortedIt )
151  {
152  QgsFeature f;
153  f.setAttributes( QgsAttributes() << sortedIt.key() << sortedIt.value() );
154  if ( !summarySink->addFeature( f, QgsFeatureSink::FastInsert ) )
155  throw QgsProcessingException( writeFeatureError( summarySink.get(), parameters, QStringLiteral( "SUMMARY_OUTPUT" ) ) );
156  }
157  }
158 
159  QVariantMap results;
160  if ( sink )
161  results.insert( QStringLiteral( "OUTPUT" ), dest );
162  if ( summarySink )
163  results.insert( QStringLiteral( "SUMMARY_OUTPUT" ), summaryDest );
164  return results;
165 }
166 
A vector of attributes.
Definition: qgsattributes.h:58
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
This class wraps a request for features to a vector layer (or directly its vector data provider).
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QgsAttributes attributes
Definition: qgsfeature.h:65
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
Definition: qgsfeature.cpp:153
bool isCanceled() const SIP_HOLDGIL
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition: qgsfeedback.h:63
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
Container of fields for a vector layer.
Definition: qgsfields.h:45
bool append(const QgsField &field, FieldOrigin origin=OriginProvider, int originIndex=-1)
Appends a field. The field must have unique name, otherwise it is rejected (returns false)
Definition: qgsfields.cpp:59
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Definition: qgsexception.h:83
@ FlagSkipGeometryValidityChecks
Invalid geometry checks should always be skipped. This flag can be useful for algorithms which always...
Base class for providing feedback from a processing algorithm.
An input feature source (such as vector layers) parameter for processing algorithms.
A vector layer or feature source field parameter for processing algorithms.
A string parameter for processing algorithms.
@ TypeVector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition: qgsprocessing.h:54
@ TypeVectorAnyGeometry
Any vector layer with geometry.
Definition: qgsprocessing.h:48