QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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  const auto constVariantValues = variantValues;
132  for ( const QVariant &value : constVariantValues )
133  {
134  double val = value.toDouble( &convertOk );
135  if ( convertOk )
136  values << val;
137  else if ( value.isNull() )
138  {
139  if ( nullCount )
140  *nullCount += 1;
141  }
142  if ( feedback && feedback->isCanceled() )
143  {
144  ok = false;
145  return values;
146  }
147  }
148  return values;
149 }
150 
151 bool QgsVectorLayerUtils::valueExists( const QgsVectorLayer *layer, int fieldIndex, const QVariant &value, const QgsFeatureIds &ignoreIds )
152 {
153  if ( !layer )
154  return false;
155 
156  QgsFields fields = layer->fields();
157 
158  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
159  return false;
160 
161  QString fieldName = fields.at( fieldIndex ).name();
162 
163  // build up an optimised feature request
164  QgsFeatureRequest request;
165  request.setNoAttributes();
167 
168  // at most we need to check ignoreIds.size() + 1 - the feature not in ignoreIds is the one we're interested in
169  int limit = ignoreIds.size() + 1;
170  request.setLimit( limit );
171 
172  request.setFilterExpression( QStringLiteral( "%1=%2" ).arg( QgsExpression::quotedColumnRef( fieldName ),
173  QgsExpression::quotedValue( value ) ) );
174 
175  QgsFeature feat;
176  QgsFeatureIterator it = layer->getFeatures( request );
177  while ( it.nextFeature( feat ) )
178  {
179  if ( ignoreIds.contains( feat.id() ) )
180  continue;
181 
182  return true;
183  }
184 
185  return false;
186 }
187 
188 QVariant QgsVectorLayerUtils::createUniqueValue( const QgsVectorLayer *layer, int fieldIndex, const QVariant &seed )
189 {
190  if ( !layer )
191  return QVariant();
192 
193  QgsFields fields = layer->fields();
194 
195  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
196  return QVariant();
197 
198  QgsField field = fields.at( fieldIndex );
199 
200  if ( field.isNumeric() )
201  {
202  QVariant maxVal = layer->maximumValue( fieldIndex );
203  QVariant newVar( maxVal.toLongLong() + 1 );
204  if ( field.convertCompatible( newVar ) )
205  return newVar;
206  else
207  return QVariant();
208  }
209  else
210  {
211  switch ( field.type() )
212  {
213  case QVariant::String:
214  {
215  QString base;
216  if ( seed.isValid() )
217  base = seed.toString();
218 
219  if ( !base.isEmpty() )
220  {
221  // strip any existing _1, _2 from the seed
222  QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
223  QRegularExpressionMatch match = rx.match( base );
224  if ( match.hasMatch() )
225  {
226  base = match.captured( 1 );
227  }
228  }
229  else
230  {
231  // no base seed - fetch first value from layer
232  QgsFeatureRequest req;
233  req.setLimit( 1 );
234  req.setSubsetOfAttributes( QgsAttributeList() << fieldIndex );
236  QgsFeature f;
237  layer->getFeatures( req ).nextFeature( f );
238  base = f.attribute( fieldIndex ).toString();
239  }
240 
241  // try variants like base_1, base_2, etc until a new value found
242  QStringList vals = layer->uniqueStringsMatching( fieldIndex, base );
243 
244  // might already be unique
245  if ( !base.isEmpty() && !vals.contains( base ) )
246  return base;
247 
248  for ( int i = 1; i < 10000; ++i )
249  {
250  QString testVal = base + '_' + QString::number( i );
251  if ( !vals.contains( testVal ) )
252  return testVal;
253  }
254 
255  // failed
256  return QVariant();
257  }
258 
259  default:
260  // todo other types - dates? times?
261  break;
262  }
263  }
264 
265  return QVariant();
266 }
267 
268 QVariant QgsVectorLayerUtils::createUniqueValueFromCache( const QgsVectorLayer *layer, int fieldIndex, const QSet<QVariant> &existingValues, const QVariant &seed )
269 {
270  if ( !layer )
271  return QVariant();
272 
273  QgsFields fields = layer->fields();
274 
275  if ( fieldIndex < 0 || fieldIndex >= fields.count() )
276  return QVariant();
277 
278  QgsField field = fields.at( fieldIndex );
279 
280  if ( field.isNumeric() )
281  {
282  QVariant maxVal = existingValues.isEmpty() ? 0 : *std::max_element( existingValues.begin(), existingValues.end() );
283  QVariant newVar( maxVal.toLongLong() + 1 );
284  if ( field.convertCompatible( newVar ) )
285  return newVar;
286  else
287  return QVariant();
288  }
289  else
290  {
291  switch ( field.type() )
292  {
293  case QVariant::String:
294  {
295  QString base;
296  if ( seed.isValid() )
297  base = seed.toString();
298 
299  if ( !base.isEmpty() )
300  {
301  // strip any existing _1, _2 from the seed
302  QRegularExpression rx( QStringLiteral( "(.*)_\\d+" ) );
303  QRegularExpressionMatch match = rx.match( base );
304  if ( match.hasMatch() )
305  {
306  base = match.captured( 1 );
307  }
308  }
309  else
310  {
311  // no base seed - fetch first value from layer
312  QgsFeatureRequest req;
313  base = existingValues.isEmpty() ? QString() : existingValues.values().first().toString();
314  }
315 
316  // try variants like base_1, base_2, etc until a new value found
317  QStringList vals;
318  for ( const auto &v : qgis::as_const( existingValues ) )
319  {
320  if ( v.toString().startsWith( base ) )
321  vals.push_back( v.toString() );
322  }
323 
324  // might already be unique
325  if ( !base.isEmpty() && !vals.contains( base ) )
326  return base;
327 
328  for ( int i = 1; i < 10000; ++i )
329  {
330  QString testVal = base + '_' + QString::number( i );
331  if ( !vals.contains( testVal ) )
332  return testVal;
333  }
334 
335  // failed
336  return QVariant();
337  }
338 
339  default:
340  // todo other types - dates? times?
341  break;
342  }
343  }
344 
345  return QVariant();
346 
347 }
348 
349 bool QgsVectorLayerUtils::validateAttribute( const QgsVectorLayer *layer, const QgsFeature &feature, int attributeIndex, QStringList &errors,
351 {
352  if ( !layer )
353  return false;
354 
355  if ( attributeIndex < 0 || attributeIndex >= layer->fields().count() )
356  return false;
357 
358  QgsFields fields = layer->fields();
359  QgsField field = fields.at( attributeIndex );
360  QVariant value = feature.attribute( attributeIndex );
361  bool valid = true;
362  errors.clear();
363 
364  QgsFieldConstraints constraints = field.constraints();
365 
366  if ( constraints.constraints() & QgsFieldConstraints::ConstraintExpression && !constraints.constraintExpression().isEmpty()
369  {
371  context.setFeature( feature );
372 
373  QgsExpression expr( constraints.constraintExpression() );
374 
375  valid = expr.evaluate( &context ).toBool();
376 
377  if ( expr.hasParserError() )
378  {
379  errors << QObject::tr( "parser error: %1" ).arg( expr.parserErrorString() );
380  }
381  else if ( expr.hasEvalError() )
382  {
383  errors << QObject::tr( "evaluation error: %1" ).arg( expr.evalErrorString() );
384  }
385  else if ( !valid )
386  {
387  errors << QObject::tr( "%1 check failed" ).arg( constraints.constraintDescription() );
388  }
389  }
390 
394  {
395  bool exempt = false;
396  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
398  {
399  int providerIdx = fields.fieldOriginIndex( attributeIndex );
400  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintNotNull, value );
401  }
402 
403  if ( !exempt )
404  {
405  valid = valid && !value.isNull();
406 
407  if ( value.isNull() )
408  {
409  errors << QObject::tr( "value is NULL" );
410  }
411  }
412  }
413 
417  {
418  bool exempt = false;
419  if ( fields.fieldOrigin( attributeIndex ) == QgsFields::OriginProvider
421  {
422  int providerIdx = fields.fieldOriginIndex( attributeIndex );
423  exempt = layer->dataProvider()->skipConstraintCheck( providerIdx, QgsFieldConstraints::ConstraintUnique, value );
424  }
425 
426  if ( !exempt )
427  {
428  bool alreadyExists = QgsVectorLayerUtils::valueExists( layer, attributeIndex, value, QgsFeatureIds() << feature.id() );
429  valid = valid && !alreadyExists;
430 
431  if ( alreadyExists )
432  {
433  errors << QObject::tr( "value is not unique" );
434  }
435  }
436  }
437 
438  return valid;
439 }
440 
442  const QgsAttributeMap &attributes, QgsExpressionContext *context )
443 {
444  QgsFeatureList features { createFeatures( layer, QgsFeaturesDataList() << QgsFeatureData( geometry, attributes ), context ) };
445  return features.isEmpty() ? QgsFeature() : features.first();
446 }
447 
449 {
450  if ( !layer )
451  return QgsFeatureList();
452 
453  QgsFeatureList result;
454  result.reserve( featuresData.length() );
455 
456  QgsExpressionContext *evalContext = context;
457  std::unique_ptr< QgsExpressionContext > tempContext;
458  if ( !evalContext )
459  {
460  // no context passed, so we create a default one
462  evalContext = tempContext.get();
463  }
464 
465  QgsFields fields = layer->fields();
466 
467  // Cache unique values
468  QMap<int, QSet<QVariant>> uniqueValueCaches;
469 
470  for ( const auto &fd : qgis::as_const( featuresData ) )
471  {
472 
473  QgsFeature newFeature( fields );
474  newFeature.setValid( true );
475  newFeature.setGeometry( fd.geometry() );
476 
477  // initialize attributes
478  newFeature.initAttributes( fields.count() );
479  for ( int idx = 0; idx < fields.count(); ++idx )
480  {
481  QVariant v;
482  bool checkUnique = true;
483  const bool hasUniqueConstraint { static_cast<bool>( fields.at( idx ).constraints().constraints() & QgsFieldConstraints::ConstraintUnique ) };
484 
485  // in order of priority:
486  // 1. passed attribute value and if field does not have a unique constraint like primary key
487  if ( fd.attributes().contains( idx ) )
488  {
489  v = fd.attributes().value( idx );
490  }
491 
492  // Cache unique values
493  if ( hasUniqueConstraint && ! uniqueValueCaches.contains( idx ) )
494  {
495  // If the layer is filtered, get unique values from an unfiltered clone
496  if ( ! layer->subsetString().isEmpty() )
497  {
498  std::unique_ptr<QgsVectorLayer> unfilteredClone { layer->clone( ) };
499  unfilteredClone->setSubsetString( QString( ) );
500  uniqueValueCaches[ idx ] = unfilteredClone->uniqueValues( idx );
501  }
502  else
503  {
504  uniqueValueCaches[ idx ] = layer->uniqueValues( idx );
505  }
506  }
507 
508  // 2. client side default expression
509  // note - deliberately not using else if!
510  QgsDefaultValue defaultValueDefinition = layer->defaultValueDefinition( idx );
511  if ( ( v.isNull() || ( hasUniqueConstraint
512  && uniqueValueCaches[ idx ].contains( v ) )
513  || defaultValueDefinition.applyOnUpdate() )
514  && defaultValueDefinition.isValid() )
515  {
516  // client side default expression set - takes precedence over all. Why? Well, this is the only default
517  // which QGIS users have control over, so we assume that they're deliberately overriding any
518  // provider defaults for some good reason and we should respect that
519  v = layer->defaultValue( idx, newFeature, evalContext );
520  }
521 
522  // 3. provider side default value clause
523  // note - not an else if deliberately. Users may return null from a default value expression to fallback to provider defaults
524  if ( ( v.isNull() || ( hasUniqueConstraint
525  && uniqueValueCaches[ idx ].contains( v ) ) )
526  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
527  {
528  int providerIndex = fields.fieldOriginIndex( idx );
529  QString providerDefault = layer->dataProvider()->defaultValueClause( providerIndex );
530  if ( !providerDefault.isEmpty() )
531  {
532  v = providerDefault;
533  checkUnique = false;
534  }
535  }
536 
537  // 4. provider side default literal
538  // note - deliberately not using else if!
539  if ( ( v.isNull() || ( checkUnique && hasUniqueConstraint
540  && uniqueValueCaches[ idx ].contains( v ) ) )
541  && fields.fieldOrigin( idx ) == QgsFields::OriginProvider )
542  {
543  int providerIndex = fields.fieldOriginIndex( idx );
544  v = layer->dataProvider()->defaultValue( providerIndex );
545  if ( v.isValid() )
546  {
547  //trust that the provider default has been sensibly set not to violate any constraints
548  checkUnique = false;
549  }
550  }
551 
552  // 5. passed attribute value
553  // note - deliberately not using else if!
554  if ( v.isNull() && fd.attributes().contains( idx ) )
555  {
556  v = fd.attributes().value( idx );
557  }
558 
559  // last of all... check that unique constraints are respected
560  // we can't handle not null or expression constraints here, since there's no way to pick a sensible
561  // value if the constraint is violated
562  if ( checkUnique && hasUniqueConstraint )
563  {
564  if ( uniqueValueCaches[ idx ].contains( v ) )
565  {
566  // unique constraint violated
567  QVariant uniqueValue = QgsVectorLayerUtils::createUniqueValueFromCache( layer, idx, uniqueValueCaches[ idx ], v );
568  if ( uniqueValue.isValid() )
569  v = uniqueValue;
570  }
571  }
572  if ( hasUniqueConstraint )
573  uniqueValueCaches[ idx ].insert( v );
574  newFeature.setAttribute( idx, v );
575  }
576  result.append( newFeature );
577  }
578  return result;
579 }
580 
581 QgsFeature QgsVectorLayerUtils::duplicateFeature( QgsVectorLayer *layer, const QgsFeature &feature, QgsProject *project, int depth, QgsDuplicateFeatureContext &duplicateFeatureContext )
582 {
583  if ( !layer )
584  return QgsFeature();
585 
586  if ( !layer->isEditable() )
587  return QgsFeature();
588 
589  //get context from layer
591  context.setFeature( feature );
592 
593  QgsFeature newFeature = createFeature( layer, feature.geometry(), feature.attributes().toMap(), &context );
594 
595  const QList<QgsRelation> relations = project->relationManager()->referencedRelations( layer );
596 
597  for ( const QgsRelation &relation : relations )
598  {
599  //check if composition (and not association)
600  if ( relation.strength() == QgsRelation::Composition && depth < 1 )
601  {
602  depth++;
603  //get features connected over this relation
604  QgsFeatureIterator relatedFeaturesIt = relation.getRelatedFeatures( feature );
605  QgsFeatureIds childFeatureIds;
606  QgsFeature childFeature;
607  while ( relatedFeaturesIt.nextFeature( childFeature ) )
608  {
609  //set childlayer editable
610  relation.referencingLayer()->startEditing();
611  //change the fk of the child to the id of the new parent
612  const auto pairs = relation.fieldPairs();
613  for ( const QgsRelation::FieldPair &fieldPair : pairs )
614  {
615  childFeature.setAttribute( fieldPair.first, newFeature.attribute( fieldPair.second ) );
616  }
617  //call the function for the child
618  childFeatureIds.insert( duplicateFeature( relation.referencingLayer(), childFeature, project, depth, duplicateFeatureContext ).id() );
619  }
620 
621  //store for feedback
622  duplicateFeatureContext.setDuplicatedFeatures( relation.referencingLayer(), childFeatureIds );
623  }
624  }
625 
626  layer->addFeature( newFeature );
627 
628  return newFeature;
629 }
630 
631 std::unique_ptr<QgsVectorLayerFeatureSource> QgsVectorLayerUtils::getFeatureSource( QPointer<QgsVectorLayer> layer, QgsFeedback *feedback )
632 {
633  std::unique_ptr<QgsVectorLayerFeatureSource> featureSource;
634 
635  auto getFeatureSource = [ layer, &featureSource, feedback ]
636  {
637 #if QT_VERSION >= QT_VERSION_CHECK( 5, 10, 0 )
638  Q_ASSERT( QThread::currentThread() == qApp->thread() || feedback );
639 #else
640  Q_UNUSED( feedback )
641 #endif
642  QgsVectorLayer *lyr = layer.data();
643 
644  if ( lyr )
645  {
646  featureSource.reset( new QgsVectorLayerFeatureSource( lyr ) );
647  }
648  };
649 
651 
652  return featureSource;
653 }
654 
656 {
657  if ( !feature.fields().isEmpty() )
658  {
659  QgsAttributes attributes;
660  attributes.reserve( fields.size() );
661  // feature has a field mapping, so we can match attributes to field names
662  for ( const QgsField &field : fields )
663  {
664  int index = feature.fields().lookupField( field.name() );
665  attributes.append( index >= 0 ? feature.attribute( index ) : QVariant( field.type() ) );
666  }
667  feature.setAttributes( attributes );
668  }
669  else
670  {
671  // no field name mapping in feature, just use order
672  const int lengthDiff = feature.attributes().count() - fields.count();
673  if ( lengthDiff > 0 )
674  {
675  // truncate extra attributes
676  QgsAttributes attributes = feature.attributes().mid( 0, fields.count() );
677  feature.setAttributes( attributes );
678  }
679  else if ( lengthDiff < 0 )
680  {
681  // add missing null attributes
682  QgsAttributes attributes = feature.attributes();
683  attributes.reserve( fields.count() );
684  for ( int i = feature.attributes().count(); i < fields.count(); ++i )
685  {
686  attributes.append( QVariant( fields.at( i ).type() ) );
687  }
688  feature.setAttributes( attributes );
689  }
690  }
691  feature.setFields( fields );
692 }
693 
695 {
696  QgsWkbTypes::Type inputWkbType( layer->wkbType( ) );
697  QgsFeatureList resultFeatures;
698  QgsFeature newF( feature );
699  // Fix attributes
701  // Does geometry need transformations?
703  bool newFHasGeom = newFGeomType !=
704  QgsWkbTypes::GeometryType::UnknownGeometry &&
705  newFGeomType != QgsWkbTypes::GeometryType::NullGeometry;
706  bool layerHasGeom = inputWkbType !=
707  QgsWkbTypes::Type::NoGeometry &&
708  inputWkbType != QgsWkbTypes::Type::Unknown;
709  // Drop geometry if layer is geometry-less
710  if ( newFHasGeom && ! layerHasGeom )
711  {
712  QgsFeature _f = QgsFeature( layer->fields() );
713  _f.setAttributes( newF.attributes() );
714  resultFeatures.append( _f );
715  }
716  else
717  {
718  // Geometry need fixing
719  if ( newFHasGeom && layerHasGeom && newF.geometry().wkbType() != inputWkbType )
720  {
721  // Curved -> straight
722  if ( !QgsWkbTypes::isCurvedType( inputWkbType ) && QgsWkbTypes::isCurvedType( newF.geometry().wkbType() ) )
723  {
724  QgsGeometry newGeom( newF.geometry().constGet()->segmentize() );
725  newF.setGeometry( newGeom );
726  }
727 
728  // polygon -> line
729  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::LineGeometry &&
731  {
732  // boundary gives us a (multi)line string of exterior + interior rings
733  QgsGeometry newGeom( newF.geometry().constGet()->boundary() );
734  newF.setGeometry( newGeom );
735  }
736  // line -> polygon
739  {
740  std::unique_ptr< QgsGeometryCollection > gc( QgsGeometryFactory::createCollectionOfType( inputWkbType ) );
741  const QgsGeometry source = newF.geometry();
742  for ( auto part = source.const_parts_begin(); part != source.const_parts_end(); ++part )
743  {
744  std::unique_ptr< QgsAbstractGeometry > exterior( ( *part )->clone() );
745  if ( QgsCurve *curve = qgsgeometry_cast< QgsCurve * >( exterior.get() ) )
746  {
747  if ( QgsWkbTypes::isCurvedType( inputWkbType ) )
748  {
749  std::unique_ptr< QgsCurvePolygon > cp = qgis::make_unique< QgsCurvePolygon >();
750  cp->setExteriorRing( curve );
751  exterior.release();
752  gc->addGeometry( cp.release() );
753  }
754  else
755  {
756  std::unique_ptr< QgsPolygon > p = qgis::make_unique< QgsPolygon >();
757  p->setExteriorRing( qgsgeometry_cast< QgsLineString * >( curve ) );
758  exterior.release();
759  gc->addGeometry( p.release() );
760  }
761  }
762  }
763  QgsGeometry newGeom( std::move( gc ) );
764  newF.setGeometry( newGeom );
765  }
766 
767  // line/polygon -> points
768  if ( QgsWkbTypes::geometryType( inputWkbType ) == QgsWkbTypes::PointGeometry &&
769  ( newF.geometry().type() == QgsWkbTypes::LineGeometry ||
771  {
772  // lines/polygons to a point layer, extract all vertices
773  std::unique_ptr< QgsMultiPoint > mp = qgis::make_unique< QgsMultiPoint >();
774  const QgsGeometry source = newF.geometry();
775  QSet< QgsPoint > added;
776  for ( auto vertex = source.vertices_begin(); vertex != source.vertices_end(); ++vertex )
777  {
778  if ( added.contains( *vertex ) )
779  continue; // avoid duplicate points, e.g. start/end of rings
780  mp->addGeometry( ( *vertex ).clone() );
781  added.insert( *vertex );
782  }
783  QgsGeometry newGeom( std::move( mp ) );
784  newF.setGeometry( newGeom );
785  }
786 
787  // Single -> multi
788  if ( QgsWkbTypes::isMultiType( inputWkbType ) && ! newF.geometry().isMultipart( ) )
789  {
790  QgsGeometry newGeom( newF.geometry( ) );
791  newGeom.convertToMultiType();
792  newF.setGeometry( newGeom );
793  }
794  // Drop Z/M
795  if ( newF.geometry().constGet()->is3D() && ! QgsWkbTypes::hasZ( inputWkbType ) )
796  {
797  QgsGeometry newGeom( newF.geometry( ) );
798  newGeom.get()->dropZValue();
799  newF.setGeometry( newGeom );
800  }
801  if ( newF.geometry().constGet()->isMeasure() && ! QgsWkbTypes::hasM( inputWkbType ) )
802  {
803  QgsGeometry newGeom( newF.geometry( ) );
804  newGeom.get()->dropMValue();
805  newF.setGeometry( newGeom );
806  }
807  // Add Z/M back, set to 0
808  if ( ! newF.geometry().constGet()->is3D() && QgsWkbTypes::hasZ( inputWkbType ) )
809  {
810  QgsGeometry newGeom( newF.geometry( ) );
811  newGeom.get()->addZValue( 0.0 );
812  newF.setGeometry( newGeom );
813  }
814  if ( ! newF.geometry().constGet()->isMeasure() && QgsWkbTypes::hasM( inputWkbType ) )
815  {
816  QgsGeometry newGeom( newF.geometry( ) );
817  newGeom.get()->addMValue( 0.0 );
818  newF.setGeometry( newGeom );
819  }
820  // Multi -> single
821  if ( ! QgsWkbTypes::isMultiType( inputWkbType ) && newF.geometry().isMultipart( ) )
822  {
823  QgsGeometry newGeom( newF.geometry( ) );
824  const QgsGeometryCollection *parts( static_cast< const QgsGeometryCollection * >( newGeom.constGet() ) );
825  QgsAttributeMap attrMap;
826  for ( int j = 0; j < newF.fields().count(); j++ )
827  {
828  attrMap[j] = newF.attribute( j );
829  }
830  resultFeatures.reserve( parts->partCount() );
831  for ( int i = 0; i < parts->partCount( ); i++ )
832  {
833  QgsGeometry g( parts->geometryN( i )->clone() );
834  QgsFeature _f( createFeature( layer, g, attrMap ) );
835  resultFeatures.append( _f );
836  }
837  }
838  else
839  {
840  resultFeatures.append( newF );
841  }
842  }
843  else
844  {
845  resultFeatures.append( newF );
846  }
847  }
848  return resultFeatures;
849 }
850 
852 {
853  QgsFeatureList resultFeatures;
854  for ( const QgsFeature &f : features )
855  {
856  const QgsFeatureList features( makeFeatureCompatible( f, layer ) );
857  for ( const auto &_f : features )
858  {
859  resultFeatures.append( _f );
860  }
861  }
862  return resultFeatures;
863 }
864 
866 {
867  QList<QgsVectorLayer *> layers;
868  QMap<QgsVectorLayer *, QgsFeatureIds>::const_iterator i;
869  for ( i = mDuplicatedFeatures.begin(); i != mDuplicatedFeatures.end(); ++i )
870  layers.append( i.key() );
871  return layers;
872 }
873 
875 {
876  return mDuplicatedFeatures[layer];
877 }
878 
879 void QgsVectorLayerUtils::QgsDuplicateFeatureContext::setDuplicatedFeatures( QgsVectorLayer *layer, const QgsFeatureIds &ids )
880 {
881  mDuplicatedFeatures.insert( layer, ids );
882 }
883 /*
884 QMap<QgsVectorLayer *, QgsFeatureIds> QgsVectorLayerUtils::QgsDuplicateFeatureContext::duplicateFeatureContext() const
885 {
886  return mDuplicatedFeatures;
887 }
888 */
889 
891  mGeometry( geometry ),
892  mAttributes( attributes )
893 {}
894 
896 {
897  return mGeometry;
898 }
899 
901 {
902  return mAttributes;
903 }
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)
void setFields(const QgsFields &fields, bool initAttributes=false)
Assign a field map with the feature to allow attribute access by attribute name.
Definition: qgsfeature.cpp:162
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:560
The QgsDefaultValue class provides a container for managing client side default values for fields...
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:111
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:771
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 cancellation 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:666
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...
QString subsetString
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:139
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:609
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
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries 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:821
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:115
QgsGeometry geometry
Definition: qgsfeature.h:67
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer&#39;s data provider, it may be nullptr.
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.
QgsVectorLayer * clone() const override
Returns a new instance equivalent to this one.
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...