Skip to content

Commit 795c27f

Browse files
authored
Merge pull request #8125 from elpaso/bugfix-20020-paste-geometry-collapsed-features
Show a warning when pasted feature geometry collapsed
2 parents b4a2218 + dbfbcca commit 795c27f

File tree

1 file changed

+31
-59
lines changed

1 file changed

+31
-59
lines changed

src/app/qgisapp.cpp

+31-59
Original file line numberDiff line numberDiff line change
@@ -8634,69 +8634,36 @@ void QgisApp::pasteFromClipboard( QgsMapLayer *destinationLayer )
86348634
pasteVectorLayer->beginEditCommand( tr( "Features pasted" ) );
86358635
QgsFeatureList features = clipboard()->transformedCopyOf( pasteVectorLayer->crs(), pasteVectorLayer->fields() );
86368636
int nTotalFeatures = features.count();
8637-
8638-
QHash<int, int> remap;
8639-
QgsFields fields = clipboard()->fields();
8640-
for ( int idx = 0; idx < fields.count(); ++idx )
8641-
{
8642-
int dst = pasteVectorLayer->fields().lookupField( fields.at( idx ).name() );
8643-
if ( dst < 0 )
8644-
continue;
8645-
8646-
remap.insert( idx, dst );
8647-
}
8648-
86498637
QgsExpressionContext context = pasteVectorLayer->createExpressionContext();
86508638

8651-
8639+
QgsFeatureList compatibleFeatures( QgsVectorLayerUtils::makeFeaturesCompatible( features, pasteVectorLayer ) );
86528640
QgsFeatureList newFeatures;
8653-
QgsFeatureList::const_iterator featureIt = features.constBegin();
8654-
while ( featureIt != features.constEnd() )
8655-
{
8656-
QgsAttributes srcAttr = featureIt->attributes();
8657-
QgsAttributeMap dstAttr;
8641+
// Count collapsed geometries
8642+
int invalidGeometriesCount = 0;
86588643

8659-
for ( int src = 0; src < srcAttr.count(); ++src )
8660-
{
8661-
int dst = remap.value( src, -1 );
8662-
if ( dst < 0 )
8663-
continue;
8644+
for ( const auto &feature : qgis::as_const( compatibleFeatures ) )
8645+
{
86648646

8665-
dstAttr[ dst ] = srcAttr.at( src );
8666-
}
8647+
QgsGeometry geom = feature.geometry();
86678648

8668-
QgsGeometry geom = featureIt->geometry();
8669-
if ( featureIt->hasGeometry() )
8649+
if ( !( geom.isEmpty() || geom.isNull( ) ) )
86708650
{
8671-
// convert geometry to match destination layer
8672-
QgsWkbTypes::GeometryType destType = pasteVectorLayer->geometryType();
8673-
bool destIsMulti = QgsWkbTypes::isMultiType( pasteVectorLayer->wkbType() );
8674-
if ( pasteVectorLayer->dataProvider() &&
8675-
!pasteVectorLayer->dataProvider()->doesStrictFeatureTypeCheck() )
8676-
{
8677-
// force destination to multi if provider doesn't do a feature strict check
8678-
destIsMulti = true;
8679-
}
8680-
8681-
if ( destType != QgsWkbTypes::UnknownGeometry )
8682-
{
8683-
QgsGeometry newGeometry = geom.convertToType( destType, destIsMulti );
8684-
if ( newGeometry.isNull() )
8685-
{
8686-
continue;
8687-
}
8688-
geom = newGeometry;
8689-
}
86908651
// avoid intersection if enabled in digitize settings
86918652
geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
8653+
// Count collapsed geometries
8654+
if ( geom.isEmpty() || geom.isNull( ) )
8655+
invalidGeometriesCount++;
86928656
}
86938657

8658+
QgsAttributeMap attrMap;
8659+
for ( int i = 0; i < feature.fields().count(); i++ )
8660+
{
8661+
attrMap[i] = feature.attribute( i );
8662+
}
86948663
// now create new feature using pasted feature as a template. This automatically handles default
86958664
// values and field constraints
8696-
newFeatures << QgsVectorLayerUtils::createFeature( pasteVectorLayer, geom, dstAttr, &context );
8697-
++featureIt;
8665+
newFeatures << QgsVectorLayerUtils::createFeature( pasteVectorLayer, geom, attrMap, &context );
86988666
}
8699-
87008667
pasteVectorLayer->addFeatures( newFeatures );
87018668
QgsFeatureIds newIds;
87028669
for ( const QgsFeature &f : qgis::as_const( newFeatures ) )
@@ -8710,26 +8677,31 @@ void QgisApp::pasteFromClipboard( QgsMapLayer *destinationLayer )
87108677
pasteVectorLayer->updateExtents();
87118678

87128679
int nCopiedFeatures = features.count();
8680+
Qgis::MessageLevel level = ( nCopiedFeatures == 0 || nCopiedFeatures < nTotalFeatures || invalidGeometriesCount > 0 ) ? Qgis::Warning : Qgis::Info;
8681+
QString message;
87138682
if ( nCopiedFeatures == 0 )
87148683
{
8715-
messageBar()->pushMessage( tr( "Paste features" ),
8716-
tr( "no features could be successfully pasted." ),
8717-
Qgis::Warning, messageTimeout() );
8718-
8684+
message = tr( "No features could be successfully pasted." );
87198685
}
87208686
else if ( nCopiedFeatures == nTotalFeatures )
87218687
{
8722-
messageBar()->pushMessage( tr( "Paste features" ),
8723-
tr( "%1 features were successfully pasted." ).arg( nCopiedFeatures ),
8724-
Qgis::Info, messageTimeout() );
8688+
message = tr( "%1 features were successfully pasted." ).arg( nCopiedFeatures );
87258689
}
87268690
else
87278691
{
8728-
messageBar()->pushMessage( tr( "Paste features" ),
8729-
tr( "%1 of %2 features could be successfully pasted." ).arg( nCopiedFeatures ).arg( nTotalFeatures ),
8730-
Qgis::Warning, messageTimeout() );
8692+
message = tr( "%1 of %2 features could be successfully pasted." ).arg( nCopiedFeatures ).arg( nTotalFeatures );
87318693
}
87328694

8695+
// warn the user if the pasted features have invalid geometries
8696+
if ( invalidGeometriesCount > 0 )
8697+
message += invalidGeometriesCount == 1 ? tr( " Geometry collapsed due to intersection avoidance." ) :
8698+
tr( "%1 geometries collapsed due to intersection avoidance." )
8699+
.arg( invalidGeometriesCount );
8700+
8701+
messageBar()->pushMessage( tr( "Paste features" ),
8702+
message,
8703+
level, messageTimeout() );
8704+
87338705
pasteVectorLayer->triggerRepaint();
87348706
}
87358707

0 commit comments

Comments
 (0)