bool QgsGeometryGapCheck::mergeWithNeighbor( const QMap<QString, QgsFeaturePool *> &featurePools, QgsGeometryGapCheckError *err, Changes &changes, QString &errMsg ) const { double maxVal = 0.; QString mergeLayerId; QgsFeature mergeFeature; int mergePartIdx = -1; const QgsGeometry geometry = err->geometry(); const QgsAbstractGeometry *errGeometry = QgsGeometryCheckerUtils::getGeomPart( geometry.constGet(), 0 ); const auto layerIds = err->neighbors().keys(); // Search for touching neighboring geometries for ( const QString &layerId : layerIds ) { QgsFeaturePool *featurePool = featurePools.value( layerId ); std::unique_ptr<QgsAbstractGeometry> errLayerGeom( errGeometry->clone() ); QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext ); errLayerGeom->transform( ct, QgsCoordinateTransform::ReverseTransform ); const auto featureIds = err->neighbors().value( layerId ); for ( QgsFeatureId testId : featureIds ) { QgsFeature testFeature; if ( !featurePool->getFeature( testId, testFeature ) ) { continue; } QgsGeometry featureGeom = testFeature.geometry(); const QgsAbstractGeometry *testGeom = featureGeom.constGet(); for ( int iPart = 0, nParts = testGeom->partCount(); iPart < nParts; ++iPart ) { double len = QgsGeometryCheckerUtils::sharedEdgeLength( errLayerGeom.get(), QgsGeometryCheckerUtils::getGeomPart( testGeom, iPart ), mContext->reducedTolerance ); if ( len > maxVal ) { maxVal = len; mergeFeature = testFeature; mergePartIdx = iPart; mergeLayerId = layerId; } } } } if ( maxVal == 0. ) { return false; } // Merge geometries QgsFeaturePool *featurePool = featurePools[ mergeLayerId ]; std::unique_ptr<QgsAbstractGeometry> errLayerGeom( errGeometry->clone() ); QgsCoordinateTransform ct( featurePool->crs(), mContext->mapCrs, mContext->transformContext ); errLayerGeom->transform( ct, QgsCoordinateTransform::ReverseTransform ); QgsGeometry mergeFeatureGeom = mergeFeature.geometry(); const QgsAbstractGeometry *mergeGeom = mergeFeatureGeom.constGet(); std::unique_ptr< QgsGeometryEngine > geomEngine = QgsGeometryCheckerUtils::createGeomEngine( errLayerGeom.get(), mContext->reducedTolerance ); std::unique_ptr<QgsAbstractGeometry> combinedGeom( geomEngine->combine( QgsGeometryCheckerUtils::getGeomPart( mergeGeom, mergePartIdx ), &errMsg ) ); if ( !combinedGeom || combinedGeom->isEmpty() || !QgsWkbTypes::isSingleType( combinedGeom->wkbType() ) ) { return false; } // Add merged polygon to destination geometry replaceFeatureGeometryPart( featurePools, mergeLayerId, mergeFeature, mergePartIdx, combinedGeom.release(), changes ); return true; }
bool QgsGeometryAreaCheck::mergeWithNeighbor( const QString &layerId, QgsFeature &feature, int partIdx, int method, int mergeAttributeIndex, Changes &changes, QString &errMsg ) const { QgsFeaturePool *featurePool = mContext->featurePools[ layerId ]; double maxVal = 0.; QgsFeature mergeFeature; int mergePartIdx = -1; bool matchFound = false; QgsGeometry featureGeometry = feature.geometry(); const QgsAbstractGeometry *geom = featureGeometry.constGet(); // Search for touching neighboring geometries const QgsFeatureIds intersects = featurePool->getIntersects( featureGeometry.boundingBox() ); for ( QgsFeatureId testId : intersects ) { QgsFeature testFeature; if ( !featurePool->get( testId, testFeature ) ) { continue; } QgsGeometry testFeatureGeom = testFeature.geometry(); const QgsAbstractGeometry *testGeom = testFeatureGeom.constGet(); for ( int testPartIdx = 0, nTestParts = testGeom->partCount(); testPartIdx < nTestParts; ++testPartIdx ) { if ( testId == feature.id() && testPartIdx == partIdx ) { continue; } double len = QgsGeometryCheckerUtils::sharedEdgeLength( QgsGeometryCheckerUtils::getGeomPart( geom, partIdx ), QgsGeometryCheckerUtils::getGeomPart( testGeom, testPartIdx ), mContext->reducedTolerance ); if ( len > 0. ) { if ( method == MergeLongestEdge || method == MergeLargestArea ) { double val; if ( method == MergeLongestEdge ) { val = len; } else { if ( dynamic_cast<const QgsGeometryCollection *>( testGeom ) ) val = static_cast<const QgsGeometryCollection *>( testGeom )->geometryN( testPartIdx )->area(); else val = testGeom->area(); } if ( val > maxVal ) { maxVal = val; mergeFeature = testFeature; mergePartIdx = testPartIdx; } } else if ( method == MergeIdenticalAttribute ) { if ( testFeature.attribute( mergeAttributeIndex ) == feature.attribute( mergeAttributeIndex ) ) { mergeFeature = testFeature; mergePartIdx = testPartIdx; matchFound = true; break; } } } } if ( matchFound ) { break; } } if ( !matchFound && maxVal == 0. ) { return method == MergeIdenticalAttribute; } // Merge geometries QgsGeometry mergeFeatureGeom = mergeFeature.geometry(); const QgsAbstractGeometry *mergeGeom = mergeFeatureGeom.constGet(); std::unique_ptr<QgsGeometryEngine> geomEngine( QgsGeometryCheckerUtils::createGeomEngine( QgsGeometryCheckerUtils::getGeomPart( mergeGeom, mergePartIdx ), mContext->reducedTolerance ) ); QgsAbstractGeometry *combinedGeom = geomEngine->combine( QgsGeometryCheckerUtils::getGeomPart( geom, partIdx ), &errMsg ); if ( !combinedGeom || combinedGeom->isEmpty() || !QgsWkbTypes::isSingleType( combinedGeom->wkbType() ) ) { return false; } // Replace polygon in merge geometry if ( mergeFeature.id() == feature.id() && mergePartIdx > partIdx ) { --mergePartIdx; } replaceFeatureGeometryPart( layerId, mergeFeature, mergePartIdx, combinedGeom, changes ); // Remove polygon from source geometry deleteFeatureGeometryPart( layerId, feature, partIdx, changes ); return true; }
bool QgsGeometryAreaCheck::mergeWithNeighbor( QgsFeature& feature, int partIdx, int method, int mergeAttributeIndex, Changes &changes, QString& errMsg ) const { double maxVal = 0.; QgsFeature mergeFeature; int mergePartIdx = -1; bool matchFound = false; QgsAbstractGeometryV2* geom = feature.geometry()->geometry(); // Search for touching neighboring geometries foreach ( const QgsFeatureId& testId, mFeaturePool->getIntersects( feature.geometry()->boundingBox() ) ) { QgsFeature testFeature; if ( !mFeaturePool->get( testId, testFeature ) ) { continue; } QgsAbstractGeometryV2* testGeom = testFeature.geometry()->geometry(); for ( int testPartIdx = 0, nTestParts = testGeom->partCount(); testPartIdx < nTestParts; ++testPartIdx ) { if ( testId == feature.id() && testPartIdx == partIdx ) { continue; } double len = QgsGeomUtils::sharedEdgeLength( QgsGeomUtils::getGeomPart( geom, partIdx ), QgsGeomUtils::getGeomPart( testGeom, testPartIdx ), QgsGeometryCheckPrecision::reducedTolerance() ); if ( len > 0. ) { if ( method == MergeLongestEdge || method == MergeLargestArea ) { double val; if ( method == MergeLongestEdge ) { val = len; } else { if ( dynamic_cast<QgsGeometryCollectionV2*>( testGeom ) ) val = static_cast<QgsGeometryCollectionV2*>( testGeom )->geometryN( testPartIdx )->area(); else val = testGeom->area(); } if ( val > maxVal ) { maxVal = val; mergeFeature = testFeature; mergePartIdx = testPartIdx; } } else if ( method == MergeIdenticalAttribute ) { if ( testFeature.attribute( mergeAttributeIndex ) == feature.attribute( mergeAttributeIndex ) ) { mergeFeature = testFeature; mergePartIdx = testPartIdx; matchFound = true; break; } } } } if ( matchFound ) { break; } } if ( !matchFound && maxVal == 0. ) { return method == MergeIdenticalAttribute ? true : false; } // Remove polygon from source geometry deleteFeatureGeometryPart( feature, partIdx, changes ); if ( mergeFeature.id() == feature.id() && mergePartIdx > partIdx ) { --mergePartIdx; } // Merge geometries QgsAbstractGeometryV2* mergeGeom = mergeFeature.geometry()->geometry(); QgsGeometryEngine* geomEngine = QgsGeomUtils::createGeomEngine( QgsGeomUtils::getGeomPart( mergeGeom, mergePartIdx ), QgsGeometryCheckPrecision::tolerance() ); QgsAbstractGeometryV2* combinedGeom = geomEngine->combine( *QgsGeomUtils::getGeomPart( geom, partIdx ), &errMsg ); delete geomEngine; if ( !combinedGeom || combinedGeom->isEmpty() ) { return false; } replaceFeatureGeometryPart( mergeFeature, mergePartIdx, combinedGeom, changes ); return true; }