Skip to content
Permalink
Browse files

Merge pull request #8125 from elpaso/bugfix-20020-paste-geometry-coll…

…apsed-features

Show a warning when pasted feature geometry collapsed
  • Loading branch information
elpaso committed Oct 9, 2018
2 parents b4a2218 + dbfbcca commit 795c27fe9fd1c7157a73c39d293d83f7d6c87a74
Showing with 31 additions and 59 deletions.
  1. +31 −59 src/app/qgisapp.cpp
@@ -8634,69 +8634,36 @@ void QgisApp::pasteFromClipboard( QgsMapLayer *destinationLayer )
pasteVectorLayer->beginEditCommand( tr( "Features pasted" ) );
QgsFeatureList features = clipboard()->transformedCopyOf( pasteVectorLayer->crs(), pasteVectorLayer->fields() );
int nTotalFeatures = features.count();

QHash<int, int> remap;
QgsFields fields = clipboard()->fields();
for ( int idx = 0; idx < fields.count(); ++idx )
{
int dst = pasteVectorLayer->fields().lookupField( fields.at( idx ).name() );
if ( dst < 0 )
continue;

remap.insert( idx, dst );
}

QgsExpressionContext context = pasteVectorLayer->createExpressionContext();


QgsFeatureList compatibleFeatures( QgsVectorLayerUtils::makeFeaturesCompatible( features, pasteVectorLayer ) );
QgsFeatureList newFeatures;
QgsFeatureList::const_iterator featureIt = features.constBegin();
while ( featureIt != features.constEnd() )
{
QgsAttributes srcAttr = featureIt->attributes();
QgsAttributeMap dstAttr;
// Count collapsed geometries
int invalidGeometriesCount = 0;

for ( int src = 0; src < srcAttr.count(); ++src )
{
int dst = remap.value( src, -1 );
if ( dst < 0 )
continue;
for ( const auto &feature : qgis::as_const( compatibleFeatures ) )
{

dstAttr[ dst ] = srcAttr.at( src );
}
QgsGeometry geom = feature.geometry();

QgsGeometry geom = featureIt->geometry();
if ( featureIt->hasGeometry() )
if ( !( geom.isEmpty() || geom.isNull( ) ) )
{
// convert geometry to match destination layer
QgsWkbTypes::GeometryType destType = pasteVectorLayer->geometryType();
bool destIsMulti = QgsWkbTypes::isMultiType( pasteVectorLayer->wkbType() );
if ( pasteVectorLayer->dataProvider() &&
!pasteVectorLayer->dataProvider()->doesStrictFeatureTypeCheck() )
{
// force destination to multi if provider doesn't do a feature strict check
destIsMulti = true;
}

if ( destType != QgsWkbTypes::UnknownGeometry )
{
QgsGeometry newGeometry = geom.convertToType( destType, destIsMulti );
if ( newGeometry.isNull() )
{
continue;
}
geom = newGeometry;
}
// avoid intersection if enabled in digitize settings
geom.avoidIntersections( QgsProject::instance()->avoidIntersectionsLayers() );
// Count collapsed geometries
if ( geom.isEmpty() || geom.isNull( ) )
invalidGeometriesCount++;
}

QgsAttributeMap attrMap;
for ( int i = 0; i < feature.fields().count(); i++ )
{
attrMap[i] = feature.attribute( i );
}
// now create new feature using pasted feature as a template. This automatically handles default
// values and field constraints
newFeatures << QgsVectorLayerUtils::createFeature( pasteVectorLayer, geom, dstAttr, &context );
++featureIt;
newFeatures << QgsVectorLayerUtils::createFeature( pasteVectorLayer, geom, attrMap, &context );
}

pasteVectorLayer->addFeatures( newFeatures );
QgsFeatureIds newIds;
for ( const QgsFeature &f : qgis::as_const( newFeatures ) )
@@ -8710,26 +8677,31 @@ void QgisApp::pasteFromClipboard( QgsMapLayer *destinationLayer )
pasteVectorLayer->updateExtents();

int nCopiedFeatures = features.count();
Qgis::MessageLevel level = ( nCopiedFeatures == 0 || nCopiedFeatures < nTotalFeatures || invalidGeometriesCount > 0 ) ? Qgis::Warning : Qgis::Info;
QString message;
if ( nCopiedFeatures == 0 )
{
messageBar()->pushMessage( tr( "Paste features" ),
tr( "no features could be successfully pasted." ),
Qgis::Warning, messageTimeout() );

message = tr( "No features could be successfully pasted." );
}
else if ( nCopiedFeatures == nTotalFeatures )
{
messageBar()->pushMessage( tr( "Paste features" ),
tr( "%1 features were successfully pasted." ).arg( nCopiedFeatures ),
Qgis::Info, messageTimeout() );
message = tr( "%1 features were successfully pasted." ).arg( nCopiedFeatures );
}
else
{
messageBar()->pushMessage( tr( "Paste features" ),
tr( "%1 of %2 features could be successfully pasted." ).arg( nCopiedFeatures ).arg( nTotalFeatures ),
Qgis::Warning, messageTimeout() );
message = tr( "%1 of %2 features could be successfully pasted." ).arg( nCopiedFeatures ).arg( nTotalFeatures );
}

// warn the user if the pasted features have invalid geometries
if ( invalidGeometriesCount > 0 )
message += invalidGeometriesCount == 1 ? tr( " Geometry collapsed due to intersection avoidance." ) :
tr( "%1 geometries collapsed due to intersection avoidance." )
.arg( invalidGeometriesCount );

messageBar()->pushMessage( tr( "Paste features" ),
message,
level, messageTimeout() );

pasteVectorLayer->triggerRepaint();
}

0 comments on commit 795c27f

Please sign in to comment.
You can’t perform that action at this time.