void QgsGeometryLineIntersectionCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const { QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids; QgsGeometryCheckerUtils::LayerFeatures layerFeaturesA( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, true ); QList<QString> layerIds = featureIds.keys(); for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeatureA : layerFeaturesA ) { // Ensure each pair of layers only gets compared once: remove the current layer from the layerIds, but add it to the layerList for layerFeaturesB layerIds.removeOne( layerFeatureA.layer().id() ); const QgsAbstractGeometry *geom = layerFeatureA.geometry(); for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart ) { const QgsLineString *line = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( geom, iPart ) ); if ( !line ) { // Should not happen continue; } // Check whether the line intersects with any other lines QgsGeometryCheckerUtils::LayerFeatures layerFeaturesB( mContext->featurePools, QList<QString>() << layerFeatureA.layer().id() << layerIds, line->boundingBox(), {QgsWkbTypes::LineGeometry} ); for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeatureB : layerFeaturesB ) { // > : only report intersections within same layer once if ( layerFeatureA.layer().id() == layerFeatureB.layer().id() && layerFeatureB.feature().id() > layerFeatureA.feature().id() ) { continue; } const QgsAbstractGeometry *testGeom = layerFeatureB.geometry(); for ( int jPart = 0, mParts = testGeom->partCount(); jPart < mParts; ++jPart ) { // Skip current feature part, only report intersections within same part once if ( layerFeatureB.feature().id() == layerFeatureA.feature().id() && iPart >= jPart ) { continue; } const QgsLineString *testLine = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( testGeom, jPart ) ); if ( !testLine ) { continue; } const QList< QgsPoint > intersections = QgsGeometryCheckerUtils::lineIntersections( line, testLine, mContext->tolerance ); for ( const QgsPoint &inter : intersections ) { errors.append( new QgsGeometryCheckError( this, layerFeatureA, inter, QgsVertexId( iPart ), layerFeatureB.id() ) ); } } } } } }
void QgsGeometryOverlapCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const { double overlapThreshold = mThresholdMapUnits; QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids; QgsGeometryCheckerUtils::LayerFeatures layerFeaturesA( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, true ); QList<QString> layerIds = featureIds.keys(); for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeatureA : layerFeaturesA ) { // Ensure each pair of layers only gets compared once: remove the current layer from the layerIds, but add it to the layerList for layerFeaturesB layerIds.removeOne( layerFeatureA.layer().id() ); QgsRectangle bboxA = layerFeatureA.geometry()->boundingBox(); std::unique_ptr< QgsGeometryEngine > geomEngineA = QgsGeometryCheckerUtils::createGeomEngine( layerFeatureA.geometry(), mContext->tolerance ); if ( !geomEngineA->isValid() ) { messages.append( tr( "Overlap check failed for (%1): the geometry is invalid" ).arg( layerFeatureA.id() ) ); continue; } QgsGeometryCheckerUtils::LayerFeatures layerFeaturesB( mContext->featurePools, QList<QString>() << layerFeatureA.layer().id() << layerIds, bboxA, mCompatibleGeometryTypes ); for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeatureB : layerFeaturesB ) { // > : only report overlaps within same layer once if ( layerFeatureA.layer().id() == layerFeatureB.layer().id() && layerFeatureB.feature().id() >= layerFeatureA.feature().id() ) { continue; } QString errMsg; if ( geomEngineA->overlaps( layerFeatureB.geometry(), &errMsg ) ) { QgsAbstractGeometry *interGeom = geomEngineA->intersection( layerFeatureB.geometry() ); if ( interGeom && !interGeom->isEmpty() ) { QgsGeometryCheckerUtils::filter1DTypes( interGeom ); for ( int iPart = 0, nParts = interGeom->partCount(); iPart < nParts; ++iPart ) { QgsAbstractGeometry *interPart = QgsGeometryCheckerUtils::getGeomPart( interGeom, iPart ); double area = interPart->area(); if ( area > mContext->reducedTolerance && area < overlapThreshold ) { errors.append( new QgsGeometryOverlapCheckError( this, layerFeatureA, interPart->clone(), interPart->centroid(), area, layerFeatureB ) ); } } } else if ( !errMsg.isEmpty() ) { messages.append( tr( "Overlap check between features %1 and %2 %3" ).arg( layerFeatureA.id() ).arg( layerFeatureB.id() ).arg( errMsg ) ); } delete interGeom; } } } }
void QgsGeometryContainedCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const { QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids; QgsGeometryCheckerUtils::LayerFeatures layerFeaturesA( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, true ); for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeatureA : layerFeaturesA ) { QgsRectangle bboxA = layerFeatureA.geometry()->boundingBox(); std::unique_ptr< QgsGeometryEngine > geomEngineA = QgsGeometryCheckerUtils::createGeomEngine( layerFeatureA.geometry(), mContext->tolerance ); if ( !geomEngineA->isValid() ) { messages.append( tr( "Contained check failed for (%1): the geometry is invalid" ).arg( layerFeatureA.id() ) ); continue; } QgsGeometryCheckerUtils::LayerFeatures layerFeaturesB( mContext->featurePools, featureIds.keys(), bboxA, mCompatibleGeometryTypes ); for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeatureB : layerFeaturesB ) { if ( layerFeatureA == layerFeatureB ) { continue; } std::unique_ptr< QgsGeometryEngine > geomEngineB = QgsGeometryCheckerUtils::createGeomEngine( layerFeatureB.geometry(), mContext->tolerance ); if ( !geomEngineB->isValid() ) { messages.append( tr( "Contained check failed for (%1): the geometry is invalid" ).arg( layerFeatureB.id() ) ); continue; } QString errMsg; // If A contains B and B contains A, it would mean that the geometries are identical, which is covered by the duplicate check if ( geomEngineA->contains( layerFeatureB.geometry(), &errMsg ) && !geomEngineB->contains( layerFeatureA.geometry(), &errMsg ) && errMsg.isEmpty() ) { errors.append( new QgsGeometryContainedCheckError( this, layerFeatureB, layerFeatureB.geometry()->centroid(), layerFeatureA ) ); } else if ( !errMsg.isEmpty() ) { messages.append( tr( "Contained check failed for (%1, %2): %3" ).arg( layerFeatureB.id(), layerFeatureA.id(), errMsg ) ); } } } }