QGIS API Documentation  3.6.0-Noosa (5873452)
qgsvectorlayerutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsvectorlayerutils.cpp
3  -----------------------
4  Date : October 2016
5  Copyright : (C) 2016 by Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <QRegularExpression>
17 
18 #include "qgsexpressioncontext.h"
19 #include "qgsfeatureiterator.h"
20 #include "qgsfeaturerequest.h"
21 #include "qgsvectorlayerutils.h"
22 #include "qgsvectordataprovider.h"
23 #include "qgsproject.h"
24 #include "qgsrelationmanager.h"
25 #include "qgsfeedback.h"
26 #include "qgsvectorlayer.h"
27 #include "qgsthreadingutils.h"
28 #include "qgsgeometrycollection.h"
30 #include "qgsmultisurface.h"
31 #include "qgsgeometryfactory.h"
32 #include "qgscurvepolygon.h"
33 #include "qgspolygon.h"
34 #include "qgslinestring.h"
35 #include "qgsmultipoint.h"
36 
37 QgsFeatureIterator QgsVectorLayerUtils::getValuesIterator( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly )
38 {
39  std::unique_ptr<QgsExpression> expression;
40  QgsExpressionContext context;
41 
42  int attrNum = layer->fields().lookupField( fieldOrExpression );
43  if ( attrNum == -1 )
44  {
45  // try to use expression
46  expression.reset( new QgsExpression( fieldOrExpression ) );
48 
49  if ( expression->hasParserError() || !expression->prepare( &context ) )
50  {
51  ok = false;
52  return QgsFeatureIterator();
53  }
54  }
55 
56  QSet<QString> lst;
57  if ( !expression )
58  lst.insert( fieldOrExpression );
59  else
60  lst = expression->referencedColumns();
61 
63  .setFlags( ( expression && expression->needsGeometry() ) ?
66  .setSubsetOfAttributes( lst, layer->fields() );
67 
68  ok = true;
69  if ( !selectedOnly )
70  {
71  return layer->getFeatures( request );
72  }
73  else
74  {
75  return layer->getSelectedFeatures( request );
76  }
77 }
78 
79 QList<QVariant> QgsVectorLayerUtils::getValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, QgsFeedback *feedback )
80 {
81  QList<QVariant> values;
82  QgsFeatureIterator fit = getValuesIterator( layer, fieldOrExpression, ok, selectedOnly );
83  if ( ok )
84  {
85  std::unique_ptr<QgsExpression> expression;
86  QgsExpressionContext context;
87 
88  int attrNum = layer->fields().lookupField( fieldOrExpression );
89  if ( attrNum == -1 )
90  {
91  // use expression, already validated in the getValuesIterator() function
92  expression.reset( new QgsExpression( fieldOrExpression ) );
94  }
95 
96  QgsFeature f;
97  while ( fit.nextFeature( f ) )
98  {
99  if ( expression )
100  {
101  context.setFeature( f );
102  QVariant v = expression->evaluate( &context );
103  values << v;
104  }
105  else
106  {
107  values << f.attribute( attrNum );
108  }
109  if ( feedback && feedback->isCanceled() )
110  {
111  ok = false;
112  return values;
113  }
114  }
115  }
116  return values;
117 }
118 
119 QList<double> QgsVectorLayerUtils::getDoubleValues( const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly, int *nullCount, QgsFeedback *feedback )
120 {
121  QList<double> values;
122 
123  if ( nullCount )
124  *nullCount = 0;
125 
126  QList<QVariant> variantValues = getValues( layer, fieldOrExpression, ok, selectedOnly, feedback );
127  if ( !ok )
128  return values;
129 
130  bool convertOk;
131  Q_FOREACH ( const QVariant &value, variantValues )
132  {
133  double val = value.toDouble( &convertOk );
134  if ( convertOk )
135  values << val;
136  else if ( value.isNull() )
137  {
138  if ( nullCount )
139  *nullCount += 1;
140  }
141  if ( feedback && feedback->isCanceled() )
142  {
143  ok = false;
144  return values;
145  }
146  }
147  return values;
148 }
149 
150 bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds )
151 {
152  if ( !layer )
153  return false;
154 
155  QgsFields fields = layer->fields();
156 
157  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
158  return false;
159 
160  QString fieldName = fields.at( fieldIndex ).name();
161 
162  // build up an optimised feature request
163  QgsFeatureRequest request;
164  request.setNoAttributes();
166 
167  // at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
168  int limit = ignoreIds.size() + 1;
169  request.setLimit( limit );
170 
171  request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
172  QgsExpression::quotedValue( value ) ) );
173 
174  QgsFeature feat;
175  QgsFeatureIterator it = layer->getFeatures( request );
176  while ( it.nextFeature( feat ) )
177  {
178  if ( ignoreIds.contains( feat.id() ) )
179  continue;
180 
181  return true;
182  }
183 
184  return false;
185 }
186 
187 QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed )
188 {
189  if ( !layer )
190  return QVariant();
191 
192  QgsFields fields = layer->fields();
193 
194  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
195  return QVariant();
196 
197  QgsField field = fields.at( fieldIndex );
198 
199  if ( field.isNumeric() )
200  {
201  QVariant maxVal = layer->maximumValue( fieldIndex );
202  QVariant newVar( maxVal.toLongLong() + 1 );
203  if ( field.convertCompatible( newVar ) )
204  return newVar;
205  else
206  return QVariant();
207  }
208  else
209  {
210  switch ( field.type() )
211  {
212  case QVariant::String:
213  {
214  QString base;
215  if ( seed.isValid() )
216  base = seed.toString();
217 
218  if ( !base.isEmpty() )
219  {
220  // strip any existing _1, _2 from the seed
221  QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
222  QRegularExpressionMatch match = rx.match( base );
223  if ( match.hasMatch() )
224  {
225  base = match.captured( 1 );
226  }
227  }
228  else
229  {
230  // no base seed - fetch first value from layer
231  QgsFeatureRequest req;
232  req.setLimit( 1 );
233  req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
235  QgsFeature f;
236  layer->getFeatures( req ).nextFeature( f );
237  base = f.attribute( fieldIndex ).toString();
238  }
239 
240  // try variants like base_1, base_2, etc until a new value found
241  QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
242 
243  // might already be unique
244  if ( !base.isEmpty() && !vals.contains( base ) )
245  return base;
246 
247  for ( int i = 1; i < 10000; ++i )
248  {
249  QString testVal = base + '_' + QString::number( i );
250  if ( !vals.contains( testVal ) )
251  return testVal;
252  }
253 
254  // failed
255  return QVariant();
256  }
257 
258  default:
259  // todo other types - dates? times?
260  break;
261  }
262  }
263 
264  return QVariant();
265 }
266 
267 QVariant QgsVectorLayerUtils::createUniqueValueFromCache( const QgsVectorLayer *layer, int fieldIndex, const QSet<QVariant> &existingValues, const QVariant &seed )
268 {
269  if ( !layer )
270  return QVariant();
271 
272  QgsFields fields = layer->fields();
273 
274  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
275  return QVariant();
276 
277  QgsField field = fields.at( fieldIndex );
278 
279  if ( field.isNumeric() )
280  {
281  QVariant maxVal = existingValues.isEmpty() ? 0 : *std::max_element( existingValues.begin(), existingValues.end() );
282  QVariant newVar( maxVal.toLongLong() + 1 );
283  if ( field.convertCompatible( newVar ) )
284  return newVar;
285  else
286  return QVariant();
287  }
288  else
289  {
290  switch ( field.type() )
291  {
292  case QVariant::String:
293  {
294  QString base;
295  if ( seed.isValid() )
296  base = seed.toString();
297 
298  if ( !base.isEmpty() )
299  {
300  // strip any existing _1, _2 from the seed
301  QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
302  QRegularExpressionMatch match = rx.match( base );
303  if ( match.hasMatch() )
304  {
305  base = match.captured( 1 );
306  }
307  }
308  else
309  {
310  // no base seed - fetch first value from layer
311  QgsFeatureRequest req;
312  base = existingValues.isEmpty() ? QString() : existingValues.values().first().toString();
313  }
314 
315  // try variants like base_1, base_2, etc until a new value found
316  QStringList vals;
317  for ( const auto &v : qgis::as_const( existingValues ) )
318  {
319  if ( v.toString().startsWith( base ) )
320  vals.push_back( v.toString() );
321  }
322 
323  // might already be unique
324  if ( !base.isEmpty() && !vals.contains( base ) )
325  return base;
326 
327  for ( int i = 1; i < 10000; ++i )
328  {
329  QString testVal = base + '_' + QString::number( i );
330  if ( !vals.contains( testVal ) )
331  return testVal;
332  }
333 
334  // failed
335  return QVariant();
336  }
337 
338  default:
339  // todo other types - dates? times?
340  break;
341  }
342  }
343 
344  return QVariant();
345 
346 }
347 
348 bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors,
350 {
351  if ( !layer )
352  return false;
353 
354  if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
355  return false;
356 
357  QgsFields fields = layer->fields();
358  QgsField field = fields.at( attributeIndex );
359  QVariant value = feature.attribute( attributeIndex );
360  bool valid = true;
361  errors.clear();
362 
363  QgsFieldConstraints constraints = field.constraints();
364 
365  if ( constraints.constraints() & QgsFieldConstraints::ConstraintExpression && !constraints.constraintExpression().isEmpty()
368  {
370  context.setFeature( feature );
371 
372  QgsExpression expr( constraints.constraintExpression() );
373 
374  valid = expr.evaluate( &context ).toBool();
375 
376  if ( expr.hasParserError() )
377  {
378  errors << QObject::tr( "parser error: %1" ).arg( expr.parserErrorString() );
379  }
380  else if ( expr.hasEvalError() )
381  {
382  errors << QObject::tr( "evaluation error: %1" ).arg( expr.evalErrorString() );
383  }
384  else if ( !valid )
385  {
386  errors << QObject::tr( "%1 check failed" ).arg( constraints.constraintDescription() );
387  }
388  }
389 
393  {
394  bool exempt = false;
395  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
397  {
398  int providerIdx = fields.fieldOriginIndex( attributeIndex );
399  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintNotNull, value );
400  }
401 
402  if ( !exempt )
403  {
404  valid = valid && !value.isNull();
405 
406  if ( value.isNull() )
407  {
408  errors << QObject::tr( "value is NULL" );
409  }
410  }
411  }
412 
416  {
417  bool exempt = false;
418  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
420  {
421  int providerIdx = fields.fieldOriginIndex( attributeIndex );
422  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintUnique, value );
423  }
424 
425  if ( !exempt )
426  {
427  bool alreadyExists = QgsVectorLayerUtils::valueExists( layer, attributeIndex, value, QgsFeatureIds() << feature.id() );
428  valid = valid && !alreadyExists;
429 
430  if ( alreadyExists )
431  {
432  errors << QObject::tr( "value is not unique" );
433  }
434  }
435  }
436 
437  return valid;
438 }
439 
441  const QgsAttributeMap &attributes, QgsExpressionContext *context )
442 {
443  QgsFeatureList features { createFeatures( layer, QgsFeaturesDataList() << QgsFeatureData( geometry, attributes ), context ) };
444  return features.isEmpty() ? QgsFeature() : features.first();
445 }
446 
448 {
449  if ( !layer )
450  return QgsFeatureList();
451 
452  QgsFeatureList result;
453  result.reserve( featuresData.length() );
454 
455  QgsExpressionContext *evalContext = context;
456  std::unique_ptr< QgsExpressionContext > tempContext;
457  if ( !evalContext )
458  {
459  // no context passed, so we create a default one
461  evalContext = tempContext.get();
462  }
463 
464  QgsFields fields = layer->fields();
465 
466  // Cache unique values
467  QMap<int, QSet<QVariant>> uniqueValueCaches;
468 
469  for ( const auto &fd : qgis::as_const( featuresData ) )
470  {
471 
472  QgsFeature newFeature( fields );
473  newFeature.setValid( true );
474  newFeature.setGeometry( fd.geometry() );
475 
476  // initialize attributes
477  newFeature.initAttributes( fields.count() );
478  for ( int idx = 0; idx < fields.count(); ++idx )
479  {
480  QVariant v;
481  bool checkUnique = true;
482  const bool hasUniqueConstraint { static_cast<bool>( fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique ) };
483 
484  // in order of priority:
485  // 1. passed attribute value and if field does not have a unique constraint like primary key
486  if ( fd.attributes().contains( idx ) )
487  {
488  v = fd.attributes().value( idx );
489  }
490 
491  // Cache unique values
492  if ( hasUniqueConstraint && ! uniqueValueCaches.contains( idx ) )
493  uniqueValueCaches[ idx ] = layer->uniqueValues( idx );
494 
495  // 2. client side default expression
496  // note - deliberately not using else if!
497  if ( ( v.isNull() || ( hasUniqueConstraint
498  && uniqueValueCaches[ idx ].contains( v ) ) )
499  && layer->defaultValueDefinition( idx ).isValid() )
500  {
501  // client side default expression set - takes precedence over all. Why? Well, this is the only default
502  // which QGIS users have control over, so we assume that they're deliberately overriding any
503  // provider defaults for some good reason and we should respect that
504  v = layer->defaultValue( idx, newFeature, evalContext );
505  }
506 
507  // 3. provider side default value clause
508  // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
509  if ( ( v.isNull() || ( hasUniqueConstraint
510  && uniqueValueCaches[ idx ].contains( v ) ) )
511  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
512  {
513  int providerIndex = fields.fieldOriginIndex( idx );
514  QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
515  if ( !providerDefault.isEmpty() )
516  {
517  v = providerDefault;
518  checkUnique = false;
519  }
520  }
521 
522  // 4. provider side default literal
523  // note - deliberately not using else if!
524  if ( ( v.isNull() || ( checkUnique && hasUniqueConstraint
525  && uniqueValueCaches[ idx ].contains( v ) ) )
526  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
527  {
528  int providerIndex = fields.fieldOriginIndex( idx );
529  v = layer->dataProvider()->defaultValue( providerIndex );
530  if ( v.isValid() )
531  {
532  //trust that the provider default has been sensibly set not to violate any constraints
533  checkUnique = false;
534  }
535  }
536 
537  // 5. passed attribute value
538  // note - deliberately not using else if!
539  if ( v.isNull() && fd.attributes().contains( idx ) )
540  {
541  v = fd.attributes().value( idx );
542  }
543 
544  // last of all... check that unique constraints are respected
545  // we can't handle not null or expression constraints here, since there's no way to pick a sensible
546  // value if the constraint is violated
547  if ( checkUnique && hasUniqueConstraint )
548  {
549  if ( uniqueValueCaches[ idx ].contains( v ) )
550  {
551  // unique constraint violated
552  QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValueFromCache( layer, idx, uniqueValueCaches[ idx ], v );
553  if ( uniqueValue.isValid() )
554  v = uniqueValue;
555  }
556  }
557  if ( hasUniqueConstraint )
558  uniqueValueCaches[ idx ].insert( v );
559  newFeature.setAttribute( idx, v );
560  }
561  result.append( newFeature );
562  }
563  return result;
564 }
565 
566 QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext )
567 {
568  if ( !layer )
569  return QgsFeature();
570 
571  if ( !layer->isEditable() )
572  return QgsFeature();
573 
574  //get context from layer
576  context.setFeature( feature );
577 
578  QgsFeature newFeature = createFeature( layer, feature.geometry(), feature.attributes().toMap(), &context );
579 
580  const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
581 
582  for ( const QgsRelation &relation : relations )
583  {
584  //check if composition (and not association)
585  if ( relation.strength() == QgsRelation::Composition && depth < 1 )
586  {
587  depth++;
588  //get features connected over this relation
589  QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
590  QgsFeatureIds childFeatureIds;
591  QgsFeature childFeature;
592  while ( relatedFeaturesIt.nextFeature( childFeature ) )
593  {
594  //set childlayer editable
595  relation.referencingLayer()->startEditing();
596  //change the fk of the child to the id of the new parent
597  const auto pairs = relation.fieldPairs();
598  for ( const QgsRelation::FieldPair &fieldPair : pairs )
599  {
600  childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
601  }
602  //call the function for the child
603  childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, depth, duplicateFeatureContext ).id() );
604  }
605 
606  //store for feedback
607  duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
608  }
609  }
610 
611  layer->addFeature( newFeature );
612 
613  return newFeature;
614 }
615 
616 std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
617 {
618  std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
619 
620  auto getFeatureSource = [ layer, &featureSource, feedback ]
621  {
622 #if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
623  Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
624 #else
625  Q_UNUSED( feedback )
626 #endif
627  QgsVectorLayer *lyr = layer.data();
628 
629  if ( lyr )
630  {
631  featureSource.reset( new QgsVectorLayerFeatureSource( lyr ) );
632  }
633  };
634 
636 
637  return featureSource;
638 }
639 
641 {
642  if ( !feature.fields().isEmpty() )
643  {
644  QgsAttributes attributes;
645  attributes.reserve( fields.size() );
646  // feature has a field mapping, so we can match attributes to field names
647  for ( const QgsField &field : fields )
648  {
649  int index = feature.fields().lookupField( field.name() );
650  attributes.append( index >= 0 ? feature.attribute( index ) : QVariant( field.type() ) );
651  }
652  feature.setAttributes( attributes );
653  }
654  else
655  {
656  // no field name mapping in feature, just use order
657  const int lengthDiff = feature.attributes().count() - fields.count();
658  if ( lengthDiff > 0 )
659  {
660  // truncate extra attributes
661  QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
662  feature.setAttributes( attributes );
663  }
664  else if ( lengthDiff < 0 )
665  {
666  // add missing null attributes
667  QgsAttributes attributes = feature.attributes();
668  attributes.reserve( fields.count() );
669  for ( int i = feature.attributes().count(); i < fields.count(); ++i )
670  {
671  attributes.append( QVariant( fields.at( i ).type() ) );
672  }
673  feature.setAttributes( attributes );
674  }
675  }
676 }
677 
679 {
680  QgsWkbTypes::Type inputWkbType( layer->wkbType( ) );
681  QgsFeatureList resultFeatures;
682  QgsFeature newF( feature );
683  // Fix attributes
685  // Does geometry need transformations?
687  bool newFHasGeom = newFGeomType !=
688  QgsWkbTypes::GeometryType::UnknownGeometry &&
689  newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
690  bool layerHasGeom = inputWkbType !=
691  QgsWkbTypes::Type::NoGeometry &&
692  inputWkbType != QgsWkbTypes::Type::Unknown;
693  // Drop geometry if layer is geometry-less
694  if ( newFHasGeom && ! layerHasGeom )
695  {
696  QgsFeature _f = QgsFeature( layer->fields() );
697  _f.setAttributes( newF.attributes() );
698  resultFeatures.append( _f );
699  }
700  else
701  {
702  // Geometry need fixing
703  if ( newFHasGeom && layerHasGeom && newF.geometry().wkbType() != inputWkbType )
704  {
705  // Curved -> straight
706  if ( !QgsWkbTypes::isCurvedType( inputWkbType ) && QgsWkbTypes::isCurvedType( newF.geometry().wkbType() ) )
707  {
708  QgsGeometry newGeom( newF.geometry().constGet()->segmentize() );
709  newF.setGeometry( newGeom );
710  }
711 
712  // polygon -> line
713  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::LineGeometry &&
715  {
716  // boundary gives us a (multi)line string of exterior + interior rings
717  QgsGeometry newGeom( newF.geometry().constGet()->boundary() );
718  newF.setGeometry( newGeom );
719  }
720  // line -> polygon
723  {
724  std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( inputWkbType ) );
725  const QgsGeometry source = newF.geometry();
726  for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
727  {
728  std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
729  if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
730  {
731  if ( QgsWkbTypes::isCurvedType( inputWkbType ) )
732  {
733  std::unique_ptr< QgsCurvePolygon > cp = qgis::make_unique< QgsCurvePolygon >();
734  cp->setExteriorRing( curve );
735  exterior.release();
736  gc->addGeometry( cp.release() );
737  }
738  else
739  {
740  std::unique_ptr< QgsPolygon > p = qgis::make_unique< QgsPolygon >();
741  p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
742  exterior.release();
743  gc->addGeometry( p.release() );
744  }
745  }
746  }
747  QgsGeometry newGeom( std::move( gc ) );
748  newF.setGeometry( newGeom );
749  }
750 
751  // line/polygon -> points
752  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::PointGeometry &&
753  ( newF.geometry().type() == QgsWkbTypes::LineGeometry ||
755  {
756  // lines/polygons to a point layer, extract all vertices
757  std::unique_ptr< QgsMultiPoint > mp = qgis::make_unique< QgsMultiPoint >();
758  const QgsGeometry source = newF.geometry();
759  QSet< QgsPoint > added;
760  for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
761  {
762  if ( added.contains( *vertex ) )
763  continue; // avoid duplicate points, e.g. start/end of rings
764  mp->addGeometry( ( *vertex ).clone() );
765  added.insert( *vertex );
766  }
767  QgsGeometry newGeom( std::move( mp ) );
768  newF.setGeometry( newGeom );
769  }
770 
771  // Single -> multi
772  if ( QgsWkbTypes::isMultiType( inputWkbType ) && ! newF.geometry().isMultipart( ) )
773  {
774  QgsGeometry newGeom( newF.geometry( ) );
775  newGeom.convertToMultiType();
776  newF.setGeometry( newGeom );
777  }
778  // Drop Z/M
779  if ( newF.geometry().constGet()->is3D() && ! QgsWkbTypes::hasZ( inputWkbType ) )
780  {
781  QgsGeometry newGeom( newF.geometry( ) );
782  newGeom.get()->dropZValue();
783  newF.setGeometry( newGeom );
784  }
785  if ( newF.geometry().constGet()->isMeasure() && ! QgsWkbTypes::hasM( inputWkbType ) )
786  {
787  QgsGeometry newGeom( newF.geometry( ) );
788  newGeom.get()->dropMValue();
789  newF.setGeometry( newGeom );
790  }
791  // Add Z/M back, set to 0
792  if ( ! newF.geometry().constGet()->is3D() && QgsWkbTypes::hasZ( inputWkbType ) )
793  {
794  QgsGeometry newGeom( newF.geometry( ) );
795  newGeom.get()->addZValue( 0.0 );
796  newF.setGeometry( newGeom );
797  }
798  if ( ! newF.geometry().constGet()->isMeasure() && QgsWkbTypes::hasM( inputWkbType ) )
799  {
800  QgsGeometry newGeom( newF.geometry( ) );
801  newGeom.get()->addMValue( 0.0 );
802  newF.setGeometry( newGeom );
803  }
804  // Multi -> single
805  if ( ! QgsWkbTypes::isMultiType( inputWkbType ) && newF.geometry().isMultipart( ) )
806  {
807  QgsGeometry newGeom( newF.geometry( ) );
808  const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
809  QgsAttributeMap attrMap;
810  for ( int j = 0; j < newF.fields().count(); j++ )
811  {
812  attrMap[j] = newF.attribute( j );
813  }
814  resultFeatures.reserve( parts->partCount() );
815  for ( int i = 0; i < parts->partCount( ); i++ )
816  {
817  QgsGeometry g( parts->geometryN( i )->clone() );
818  QgsFeature _f( createFeature( layer, g, attrMap ) );
819  resultFeatures.append( _f );
820  }
821  }
822  else
823  {
824  resultFeatures.append( newF );
825  }
826  }
827  else
828  {
829  resultFeatures.append( newF );
830  }
831  }
832  return resultFeatures;
833 }
834 
836 {
837  QgsFeatureList resultFeatures;
838  for ( const QgsFeature &f : features )
839  {
840  const QgsFeatureList features( makeFeatureCompatible( f, layer ) );
841  for ( const auto &_f : features )
842  {
843  resultFeatures.append( _f );
844  }
845  }
846  return resultFeatures;
847 }
848 
850 {
851  QList<QgsVectorLayer *> layers;
852  QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
853  for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
854  layers.append( i.key() );
855  return layers;
856 }
857 
859 {
860  return mDuplicatedFeatures[layer];
861 }
862 
863 void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
864 {
865  mDuplicatedFeatures.insert( layer, ids );
866 }
867 /*
868 QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
869 {
870  return mDuplicatedFeatures;
871 }
872 */
873 
875  mGeometry( geometry ),
876  mAttributes( attributes )
877 {}
878 
880 {
881  return mGeometry;
882 }
883 
885 {
886  return mAttributes;
887 }
bool isMeasure() const
Returns true if the geometry contains m values.
int lookupField(const QString &fieldName) const
Looks up field&#39;s index from the field name.
Definition: qgsfields.cpp:324
Class for parsing and evaluation of expressions (formerly called "search strings").
QgsFeatureId id
Definition: qgsfeature.h:64
Wrapper for iterator of features from vector data provider or vector layer.
QSet< QgsFeatureId > QgsFeatureIds
Definition: qgsfeatureid.h:34
static bool valueExists(const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds=QgsFeatureIds())
Returns true if the specified value already exists within a field.
int size() const
Returns number of items.
Definition: qgsfields.cpp:138
FieldOrigin fieldOrigin(int fieldIdx) const
Gets field&#39;s origin (value from an enumeration)
Definition: qgsfields.cpp:189
static QString quotedColumnRef(QString name)
Returns a quoted column reference (in double quotes)
bool isMultipart() const
Returns true if WKB of the geometry is of WKBMulti* type.
ConstraintStrength constraintStrength(Constraint constraint) const
Returns the strength of a field constraint, or ConstraintStrengthNotSet if the constraint is not pres...
QString name
Definition: qgsfield.h:58
bool isValid() const
Returns if this default value should be applied.
static std::unique_ptr< QgsVectorLayerFeatureSource > getFeatureSource(QPointer< QgsVectorLayer > layer, QgsFeedback *feedback=nullptr)
Gets the feature source from a QgsVectorLayer pointer.
static bool isMultiType(Type type)
Returns true if the WKB type is a multi type.
Definition: qgswkbtypes.h:559
Contains mainly the QMap with QgsVectorLayer and QgsFeatureIds do list all the duplicated features...
QList< QgsVectorLayer * > layers() const
Returns all the layers on which features have been duplicated.
QgsWkbTypes::Type wkbType() const FINAL
Returns the WKBType or WKBUnknown in case of error.
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
QList< QgsFeature > QgsFeatureList
Definition: qgsfeature.h:571
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
ConstraintOrigin
Origin of constraints.
static QList< double > getDoubleValues(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly=false, int *nullCount=nullptr, QgsFeedback *feedback=nullptr)
Fetches all double values from a specified field name or expression.
QgsAbstractGeometry::const_part_iterator const_parts_end() const
Returns STL-style iterator pointing to the imaginary part after the last part of the geometry...
QgsAbstractGeometry::const_part_iterator const_parts_begin() const
Returns STL-style const iterator pointing to the first part of the geometry.
static QgsFeatureList createFeatures(const QgsVectorLayer *layer, const QgsFeaturesDataList &featuresData, QgsExpressionContext *context=nullptr)
Creates a set of new features ready for insertion into a layer.
QVariant evaluate()
Evaluate the feature and return the result.
QgsFeatureRequest & setSubsetOfAttributes(const QgsAttributeList &attrs)
Set a subset of attributes that will be fetched.
bool convertCompatible(QVariant &v) const
Converts the provided variant to a compatible format.
Definition: qgsfield.cpp:281
static std::unique_ptr< QgsGeometryCollection > createCollectionOfType(QgsWkbTypes::Type type)
Returns a new geometry collection matching a specified WKB type.
Container of fields for a vector layer.
Definition: qgsfields.h:42
virtual bool addMValue(double mValue=0)=0
Adds a measure to the geometry, initialized to a preset value.
A geometry is the spatial representation of a feature.
Definition: qgsgeometry.h:106
void setAttributes(const QgsAttributes &attrs)
Sets the feature&#39;s attributes.
Definition: qgsfeature.cpp:127
bool setAttribute(int field, const QVariant &attr)
Set an attribute&#39;s value by field index.
Definition: qgsfeature.cpp:211
static QList< QVariant > getValues(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly=false, QgsFeedback *feedback=nullptr)
Fetches all values from a specified field name or expression.
virtual QgsAbstractGeometry * boundary() const =0
Returns the closure of the combinatorial boundary of the geometry (ie the topological boundary of the...
Stores information about constraints which may be present on a field.
Field comes from the underlying data provider of the vector layer (originIndex = index in provider&#39;s ...
Definition: qgsfields.h:49
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:55
static bool validateAttribute(const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors, QgsFieldConstraints::ConstraintStrength strength=QgsFieldConstraints::ConstraintStrengthNotSet, QgsFieldConstraints::ConstraintOrigin origin=QgsFieldConstraints::ConstraintOriginNotSet)
Tests an attribute value to check whether it passes all constraints which are present on the correspo...
QgsFields fields
Definition: qgsfeature.h:66
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
static bool hasZ(Type type)
Tests whether a WKB type contains the z-dimension.
Definition: qgswkbtypes.h:770
static QgsFeatureIterator getValuesIterator(const QgsVectorLayer *layer, const QString &fieldOrExpression, bool &ok, bool selectedOnly)
Create a feature iterator for a specified field name or expression.
Constraint was set at data provider.
Field has an expression constraint set. See constraintExpression().
QgsField at(int i) const
Gets field at particular index (must be in range 0..N-1)
Definition: qgsfields.cpp:163
int fieldOriginIndex(int fieldIdx) const
Gets field&#39;s origin index (its meaning is specific to each type of origin)
Definition: qgsfields.cpp:197
Base class for feedback objects to be used for cancelation of something running in a worker thread...
Definition: qgsfeedback.h:44
virtual bool skipConstraintCheck(int fieldIndex, QgsFieldConstraints::Constraint constraint, const QVariant &value=QVariant()) const
Returns true if a constraint check should be skipped for a specified field (e.g., if the value return...
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QgsFeatureRequest & setFilterExpression(const QString &expression)
Set the filter expression.
Type
The WKB type describes the number of dimensions a geometry has.
Definition: qgswkbtypes.h:68
QStringList uniqueStringsMatching(int index, const QString &substring, int limit=-1, QgsFeedback *feedback=nullptr) const
Returns unique string values of an attribute which contain a specified subset string.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
Defines a relation between matching fields of the two involved tables of a relation.
Definition: qgsrelation.h:74
static void matchAttributesToFields(QgsFeature &feature, const QgsFields &fields)
Matches the attributes in feature to the specified fields.
static QVariant createUniqueValueFromCache(const QgsVectorLayer *layer, int fieldIndex, const QSet< QVariant > &existingValues, const QVariant &seed=QVariant())
Returns a new attribute value for the specified field index which is guaranteed to be unique within r...
Geometry collection.
QgsFeatureIterator getSelectedFeatures(QgsFeatureRequest request=QgsFeatureRequest()) const
Returns an iterator of the selected features.
QgsFeatureRequest & setNoAttributes()
Set that no attributes will be fetched.
QgsFeatureData(const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap())
Constructs a new QgsFeatureData with given geometry and attributes.
QString constraintDescription() const
Returns the descriptive name for the constraint expression.
void initAttributes(int fieldCount)
Initialize this feature with the given number of fields.
Definition: qgsfeature.cpp:202
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsAttributeMap attributes() const
Returns attributes.
static QgsFeature createFeature(const QgsVectorLayer *layer, const QgsGeometry &geometry=QgsGeometry(), const QgsAttributeMap &attributes=QgsAttributeMap(), QgsExpressionContext *context=nullptr)
Creates a new feature ready for insertion into a layer.
Encapsulate geometry and attributes for new features, to be passed to createFeatures.
void seed(uint32_t value)
QMap< int, QVariant > QgsAttributeMap
Definition: qgsattributes.h:38
static GeometryType geometryType(Type type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
Definition: qgswkbtypes.h:665
This class wraps a request for features to a vector layer (or directly its vector data provider)...
virtual QString defaultValueClause(int fieldIndex) const
Returns any default value clauses which are present at the provider for a specified field index...
Reads and writes project states.
Definition: qgsproject.h:89
QgsAttributeMap toMap() const
Returns a QgsAttributeMap of the attribute values.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer&#39;s project and layer.
Abstract base class for curved geometry type.
Definition: qgscurve.h:35
QList< QgsRelation > referencedRelations(QgsVectorLayer *layer=nullptr) const
Gets all relations where this layer is the referenced part (i.e.
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:48
QgsRelationManager relationManager
Definition: qgsproject.h:100
QgsExpressionContext createExpressionContext() const FINAL
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static bool runOnMainThread(const Func &func, QgsFeedback *feedback=nullptr)
Guarantees that func is executed on the main thread.
static QgsFeatureList makeFeaturesCompatible(const QgsFeatureList &features, const QgsVectorLayer *layer)
Converts input features to be compatible with the given layer.
Partial snapshot of vector layer&#39;s state (only the members necessary for access to features) ...
QgsAbstractGeometry * get()
Returns a modifiable (non-const) reference to the underlying abstract geometry primitive.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QVariant createUniqueValue(const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed=QVariant())
Returns a new attribute value for the specified field index which is guaranteed to be unique...
QgsGeometry geometry() const
Returns geometry.
GeometryType
The geometry types are used to group QgsWkbTypes::Type in a coarse way.
Definition: qgswkbtypes.h:138
void setValid(bool validity)
Sets the validity of the feature.
Definition: qgsfeature.cpp:188
QgsDefaultValue defaultValueDefinition(int index) const
Returns the definition of the expression used when calculating the default value for a field...
QgsFieldConstraints constraints
Definition: qgsfield.h:61
bool convertToMultiType()
Converts single type geometry into multitype geometry e.g.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition: qgsfeedback.h:54
QSet< QVariant > uniqueValues(int fieldIndex, int limit=-1) const FINAL
Calculates a list of unique values contained within an attribute in the layer.
ConstraintStrength
Strength of constraints.
static QgsFeature duplicateFeature(QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext)
Duplicates a feature and it&#39;s children (one level deep).
static bool isCurvedType(Type type)
Returns true if the WKB type is a curved type or can contain curved geometries.
Definition: qgswkbtypes.h:608
virtual bool addZValue(double zValue=0)=0
Adds a z-dimension to the geometry, initialized to a preset value.
QgsFeatureIds duplicatedFeatures(QgsVectorLayer *layer) const
Returns the duplicated features in the given layer.
void setGeometry(const QgsGeometry &geometry)
Set the feature&#39;s geometry.
Definition: qgsfeature.cpp:137
bool addFeature(QgsFeature &feature, QgsFeatureSink::Flags flags=nullptr) FINAL
Adds a single feature to the sink.
QgsFeatureRequest & setLimit(long limit)
Set the maximum number of features to request.
bool isEmpty() const
Checks whether the container is empty.
Definition: qgsfields.cpp:128
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Query the layer for features specified in request.
bool isNumeric
Definition: qgsfield.h:52
static bool hasM(Type type)
Tests whether a WKB type contains m values.
Definition: qgswkbtypes.h:820
ConstraintOrigin constraintOrigin(Constraint constraint) const
Returns the origin of a field constraint, or ConstraintOriginNotSet if the constraint is not present ...
void appendScopes(const QList< QgsExpressionContextScope *> &scopes)
Appends a list of scopes to the end of the context.
QgsWkbTypes::GeometryType type
Definition: qgsgeometry.h:110
QgsGeometry geometry
Definition: qgsfeature.h:67
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be null.
QList< int > QgsAttributeList
Definition: qgsfield.h:27
virtual bool dropMValue()=0
Drops any measure values which exist in the geometry.
bool nextFeature(QgsFeature &f)
static QString quotedValue(const QVariant &value)
Returns a string representation of a literal value, including appropriate quotations where required...
QString constraintExpression() const
Returns the constraint expression for the field, if set.
static QgsFeatureList makeFeatureCompatible(const QgsFeature &feature, const QgsVectorLayer *layer)
Converts input feature to be compatible with the given layer.
Geometry is not required. It may still be returned if e.g. required for a filter condition.
A vector of attributes.
Definition: qgsattributes.h:57
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error...
Represents a vector layer which manages a vector based data sets.
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:262
virtual QgsAbstractGeometry * segmentize(double tolerance=M_PI/180., SegmentationToleranceType toleranceType=MaximumAngle) const
Returns a version of the geometry without curves.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
QVariant::Type type
Definition: qgsfield.h:56
virtual bool dropZValue()=0
Drops any z-dimensions which exist in the geometry.
QgsAttributes attributes
Definition: qgsfeature.h:65
Fix relation, related elements are part of the parent and a parent copy will copy any children or del...
Definition: qgsrelation.h:60
QList< QgsVectorLayerUtils::QgsFeatureData > QgsFeaturesDataList
Alias for list of QgsFeatureData.
QgsFeatureRequest & setFlags(QgsFeatureRequest::Flags flags)
Sets flags that affect how features will be fetched.
QVariant defaultValue(int index, const QgsFeature &feature=QgsFeature(), QgsExpressionContext *context=nullptr) const
Returns the calculated default value for the specified field index.
Field must have a unique value.
virtual QVariant defaultValue(int fieldIndex) const
Returns any literal default values which are present at the provider for a specified field index...