std::unique_ptr<QgsAbstractGeometry> QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometry &geom, const QList<QgsVectorLayer *> &avoidIntersectionsLayers, const QHash<QgsVectorLayer *, QSet<QgsFeatureId> > &ignoreFeatures ) { std::unique_ptr<QgsGeometryEngine> geomEngine( QgsGeometry::createGeometryEngine( &geom ) ); if ( !geomEngine ) { return nullptr; } QgsWkbTypes::Type geomTypeBeforeModification = geom.wkbType(); //check if g has polygon type if ( QgsWkbTypes::geometryType( geomTypeBeforeModification ) != QgsWkbTypes::PolygonGeometry ) { return nullptr; } if ( avoidIntersectionsLayers.isEmpty() ) return nullptr; //no intersections stored in project does not mean error QList< QgsGeometry > nearGeometries; //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each for ( QgsVectorLayer *currentLayer : avoidIntersectionsLayers ) { QgsFeatureIds ignoreIds; QHash<QgsVectorLayer *, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.constFind( currentLayer ); if ( ignoreIt != ignoreFeatures.constEnd() ) ignoreIds = ignoreIt.value(); QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() ) .setFlags( QgsFeatureRequest::ExactIntersect ) .setSubsetOfAttributes( QgsAttributeList() ) ); QgsFeature f; while ( fi.nextFeature( f ) ) { if ( ignoreIds.contains( f.id() ) ) continue; if ( !f.hasGeometry() ) continue; nearGeometries << f.geometry(); } } if ( nearGeometries.isEmpty() ) { return nullptr; } std::unique_ptr< QgsAbstractGeometry > combinedGeometries( geomEngine->combine( nearGeometries ) ); if ( !combinedGeometries ) { return nullptr; } std::unique_ptr< QgsAbstractGeometry > diffGeom( geomEngine->difference( combinedGeometries.get() ) ); return diffGeom; }
QgsAbstractGeometryV2* QgsGeometryEditUtils::avoidIntersections( const QgsAbstractGeometryV2& geom, QMap<QgsVectorLayer*, QSet<QgsFeatureId> > ignoreFeatures ) { QScopedPointer<QgsGeometryEngine> geomEngine( QgsGeometry::createGeometryEngine( &geom ) ); if ( geomEngine.isNull() ) { return nullptr; } QgsWKBTypes::Type geomTypeBeforeModification = geom.wkbType(); //check if g has polygon type if ( QgsWKBTypes::geometryType( geomTypeBeforeModification ) != QgsWKBTypes::PolygonGeometry ) { return nullptr; } //read avoid intersections list from project properties bool listReadOk; QStringList avoidIntersectionsList = QgsProject::instance()->readListEntry( "Digitizing", "/AvoidIntersectionsList", QStringList(), &listReadOk ); if ( !listReadOk ) return nullptr; //no intersections stored in project does not mean error QList< QgsAbstractGeometryV2* > nearGeometries; //go through list, convert each layer to vector layer and call QgsVectorLayer::removePolygonIntersections for each QgsVectorLayer* currentLayer = nullptr; QStringList::const_iterator aIt = avoidIntersectionsList.constBegin(); for ( ; aIt != avoidIntersectionsList.constEnd(); ++aIt ) { currentLayer = dynamic_cast<QgsVectorLayer*>( QgsMapLayerRegistry::instance()->mapLayer( *aIt ) ); if ( currentLayer ) { QgsFeatureIds ignoreIds; QMap<QgsVectorLayer*, QSet<qint64> >::const_iterator ignoreIt = ignoreFeatures.find( currentLayer ); if ( ignoreIt != ignoreFeatures.constEnd() ) ignoreIds = ignoreIt.value(); QgsFeatureIterator fi = currentLayer->getFeatures( QgsFeatureRequest( geom.boundingBox() ) .setFlags( QgsFeatureRequest::ExactIntersect ) .setSubsetOfAttributes( QgsAttributeList() ) ); QgsFeature f; while ( fi.nextFeature( f ) ) { if ( ignoreIds.contains( f.id() ) ) continue; if ( !f.hasGeometry() ) continue; nearGeometries << f.geometry().geometry()->clone(); } } } if ( nearGeometries.isEmpty() ) { return nullptr; } QgsAbstractGeometryV2* combinedGeometries = geomEngine.data()->combine( nearGeometries ); qDeleteAll( nearGeometries ); if ( !combinedGeometries ) { return nullptr; } QgsAbstractGeometryV2* diffGeom = geomEngine.data()->difference( *combinedGeometries ); delete combinedGeometries; return diffGeom; }
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; }