void QgsGeometryContainedCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const { QgsGeometryContainedCheckError *containerError = static_cast<QgsGeometryContainedCheckError *>( error ); QgsFeaturePool *featurePoolA = mContext->featurePools[ error->layerId() ]; QgsFeaturePool *featurePoolB = mContext->featurePools[ containerError->containingFeature().first ]; QgsFeature featureA; QgsFeature featureB; if ( !featurePoolA->get( error->featureId(), featureA ) || !featurePoolB->get( containerError->containingFeature().second, featureB ) ) { error->setObsolete(); return; } // Check if error still applies QgsGeometryCheckerUtils::LayerFeature layerFeatureA( featurePoolA, featureA, true ); QgsGeometryCheckerUtils::LayerFeature layerFeatureB( featurePoolB, featureB, true ); std::unique_ptr< QgsGeometryEngine > geomEngineA = QgsGeometryCheckerUtils::createGeomEngine( layerFeatureA.geometry(), mContext->tolerance ); std::unique_ptr< QgsGeometryEngine > geomEngineB = QgsGeometryCheckerUtils::createGeomEngine( layerFeatureB.geometry(), mContext->tolerance ); if ( !( geomEngineB->contains( layerFeatureA.geometry() ) && !geomEngineA->contains( layerFeatureB.geometry() ) ) ) { error->setObsolete(); return; } // Fix error if ( method == NoChange ) { error->setFixed( method ); } else if ( method == Delete ) { changes[error->layerId()][featureA.id()].append( Change( ChangeFeature, ChangeRemoved ) ); featurePoolA->deleteFeature( featureA.id() ); error->setFixed( method ); } else { error->setFixFailed( tr( "Unknown method" ) ); } }
void QgsGeometryOverlapCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes &changes ) const { QString errMsg; QgsGeometryOverlapCheckError *overlapError = static_cast<QgsGeometryOverlapCheckError *>( error ); QgsFeaturePool *featurePoolA = mContext->featurePools[ overlapError->layerId() ]; QgsFeaturePool *featurePoolB = mContext->featurePools[ overlapError->overlappedFeature().first ]; QgsFeature featureA; QgsFeature featureB; if ( !featurePoolA->get( overlapError->featureId(), featureA ) || !featurePoolB->get( overlapError->overlappedFeature().second, featureB ) ) { error->setObsolete(); return; } // Check if error still applies QgsGeometryCheckerUtils::LayerFeature layerFeatureA( featurePoolA, featureA, true ); QgsGeometryCheckerUtils::LayerFeature layerFeatureB( featurePoolB, featureB, true ); std::unique_ptr< QgsGeometryEngine > geomEngineA = QgsGeometryCheckerUtils::createGeomEngine( layerFeatureA.geometry(), mContext->reducedTolerance ); if ( !geomEngineA->overlaps( layerFeatureB.geometry() ) ) { error->setObsolete(); return; } std::unique_ptr< QgsAbstractGeometry > interGeom( geomEngineA->intersection( layerFeatureB.geometry(), &errMsg ) ); if ( !interGeom ) { error->setFixFailed( tr( "Failed to compute intersection between overlapping features: %1" ).arg( errMsg ) ); return; } // Search which overlap part this error parametrizes (using fuzzy-matching of the area and centroid...) QgsAbstractGeometry *interPart = nullptr; for ( int iPart = 0, nParts = interGeom->partCount(); iPart < nParts; ++iPart ) { QgsAbstractGeometry *part = QgsGeometryCheckerUtils::getGeomPart( interGeom.get(), iPart ); if ( std::fabs( part->area() - overlapError->value().toDouble() ) < mContext->reducedTolerance && QgsGeometryCheckerUtils::pointsFuzzyEqual( part->centroid(), overlapError->location(), mContext->reducedTolerance ) ) { interPart = part; break; } } if ( !interPart || interPart->isEmpty() ) { error->setObsolete(); return; } // Fix error if ( method == NoChange ) { error->setFixed( method ); } else if ( method == Subtract ) { std::unique_ptr< QgsAbstractGeometry > diff1( geomEngineA->difference( interPart, &errMsg ) ); if ( !diff1 || diff1->isEmpty() ) { diff1.reset(); } else { QgsGeometryCheckerUtils::filter1DTypes( diff1.get() ); } std::unique_ptr< QgsGeometryEngine > geomEngineB = QgsGeometryCheckerUtils::createGeomEngine( layerFeatureB.geometry(), mContext->reducedTolerance ); std::unique_ptr< QgsAbstractGeometry > diff2( geomEngineB->difference( interPart, &errMsg ) ); if ( !diff2 || diff2->isEmpty() ) { diff2.reset(); } else { QgsGeometryCheckerUtils::filter1DTypes( diff2.get() ); } double shared1 = diff1 ? QgsGeometryCheckerUtils::sharedEdgeLength( diff1.get(), interPart, mContext->reducedTolerance ) : 0; double shared2 = diff2 ? QgsGeometryCheckerUtils::sharedEdgeLength( diff2.get(), interPart, mContext->reducedTolerance ) : 0; if ( !diff1 || !diff2 || shared1 == 0. || shared2 == 0. ) { error->setFixFailed( tr( "Could not find shared edges between intersection and overlapping features" ) ); } else { if ( shared1 < shared2 ) { diff1->transform( featurePoolA->getLayerToMapTransform(), QgsCoordinateTransform::ReverseTransform ); featureA.setGeometry( QgsGeometry( std::move( diff1 ) ) ); changes[error->layerId()][featureA.id()].append( Change( ChangeFeature, ChangeChanged ) ); featurePoolA->updateFeature( featureA ); } else { diff2->transform( featurePoolB->getLayerToMapTransform(), QgsCoordinateTransform::ReverseTransform ); featureB.setGeometry( QgsGeometry( std::move( diff2 ) ) ); changes[overlapError->overlappedFeature().first][featureB.id()].append( Change( ChangeFeature, ChangeChanged ) ); featurePoolB->updateFeature( featureB ); } error->setFixed( method ); } } else { error->setFixFailed( tr( "Unknown method" ) ); } }