ErrorList topolTest::checkOverlapWithLayer( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { int i = 0; ErrorList errorList; bool skipItself = layer1 == layer2; QgsSpatialIndex *index = mLayerIndexes[layer2->id()]; QgsGeometry canvasExtentPoly = QgsGeometry::fromWkt( qgsInterface->mapCanvas()->extent().asWktPolygon() ); QList<FeatureLayer>::iterator it; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) emit progress( i ); if ( testCanceled() ) break; QgsGeometry g1 = it->feature.geometry(); QgsRectangle bb = g1.boundingBox(); QList<QgsFeatureId> crossingIds; crossingIds = index->intersects( bb ); QList<QgsFeatureId>::ConstIterator cit = crossingIds.begin(); QList<QgsFeatureId>::ConstIterator crossingIdsEnd = crossingIds.end(); for ( ; cit != crossingIdsEnd; ++cit ) { QgsFeature &f = mFeatureMap2[*cit].feature; QgsGeometry g2 = f.geometry(); // skip itself, when invoked with the same layer if ( skipItself && f.id() == it->feature.id() ) continue; if ( g2.isNull() ) { QgsMessageLog::logMessage( tr( "Second geometry missing." ), tr( "Topology plugin" ) ); continue; } if ( g1.overlaps( g2 ) ) { QgsRectangle r = bb; QgsRectangle r2 = g2.boundingBox(); r.combineExtentWith( r2 ); QgsGeometry conflictGeom = g1.intersection( g2 ); // could this for some reason return NULL? if ( conflictGeom.isNull() ) { continue; } if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflictGeom ) ) { continue; } if ( canvasExtentPoly.crosses( conflictGeom ) ) { conflictGeom = conflictGeom.intersection( canvasExtentPoly ); } } //c = new QgsGeometry; QList<FeatureLayer> fls; FeatureLayer fl; fl.feature = f; fl.layer = layer2; fls << *it << fl; TopolErrorIntersection *err = new TopolErrorIntersection( r, conflictGeom, fls ); errorList << err; } } } return errorList; }
ErrorList topolTest::checkOverlaps( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer2 ); int i = 0; ErrorList errorList; // could be enabled for lines and points too // so duplicate rule may be removed? if ( layer1->geometryType() != QgsWkbTypes::PolygonGeometry ) { return errorList; } QList<QgsFeatureId> *duplicateIds = new QList<QgsFeatureId>(); QgsSpatialIndex *index = mLayerIndexes[layer1->id()]; if ( !index ) { qDebug() << "no index present"; delete duplicateIds; return errorList; } QMap<QgsFeatureId, FeatureLayer>::const_iterator it; for ( it = mFeatureMap2.constBegin(); it != mFeatureMap2.constEnd(); ++it ) { if ( !( ++i % 100 ) ) emit progress( i ); QgsFeatureId currentId = it->feature.id(); if ( duplicateIds->contains( currentId ) ) { //is already a duplicate geometry..skip.. continue; } if ( testCanceled() ) break; QgsGeometry g1 = it->feature.geometry(); if ( !g1.isGeosValid() ) { qDebug() << "invalid geometry(g1) found..skipping.." << it->feature.id(); continue; } QgsRectangle bb = g1.boundingBox(); QList<QgsFeatureId> crossingIds; crossingIds = index->intersects( bb ); QList<QgsFeatureId>::ConstIterator cit = crossingIds.begin(); QList<QgsFeatureId>::ConstIterator crossingIdsEnd = crossingIds.end(); bool duplicate = false; QgsGeometry canvasExtentPoly = QgsGeometry::fromWkt( qgsInterface->mapCanvas()->extent().asWktPolygon() ); for ( ; cit != crossingIdsEnd; ++cit ) { duplicate = false; // skip itself if ( mFeatureMap2[*cit].feature.id() == it->feature.id() ) continue; QgsGeometry g2 = mFeatureMap2[*cit].feature.geometry(); if ( g2.isNull() ) { QgsMessageLog::logMessage( tr( "Invalid second geometry in overlaps test." ), tr( "Topology plugin" ) ); continue; } if ( !_canExportToGeos( g2 ) ) { QgsMessageLog::logMessage( tr( "Failed to import second geometry into GEOS in overlaps test." ), tr( "Topology plugin" ) ); continue; } if ( !g2.isGeosValid() ) { QgsMessageLog::logMessage( tr( "Skipping invalid second geometry of feature %1 in overlaps test." ).arg( it->feature.id() ), tr( "Topology plugin" ) ); continue; } qDebug() << "checking overlap for" << it->feature.id(); if ( g1.overlaps( g2 ) ) { duplicate = true; duplicateIds->append( mFeatureMap2[*cit].feature.id() ); } if ( duplicate ) { QList<FeatureLayer> fls; fls << *it << *it; QgsGeometry conflictGeom = g1.intersection( g2 ); if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflictGeom ) ) { continue; } if ( canvasExtentPoly.crosses( conflictGeom ) ) { conflictGeom = conflictGeom.intersection( canvasExtentPoly ); } } TopolErrorOverlaps *err = new TopolErrorOverlaps( bb, conflictGeom, fls ); errorList << err; } } } delete duplicateIds; return errorList; }
ErrorList topolTest::checkGaps( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer2 ); int i = 0; ErrorList errorList; GEOSContextHandle_t geosctxt = QgsGeos::getGEOSHandler(); // could be enabled for lines and points too // so duplicate rule may be removed? if ( layer1->geometryType() != QgsWkbTypes::PolygonGeometry ) { return errorList; } QList<FeatureLayer>::iterator it; QgsGeometry g1; QList<GEOSGeometry *> geomList; qDebug() << mFeatureList1.count() << " features in list!"; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { qDebug() << "reading features-" << i; if ( !( ++i % 100 ) ) { emit progress( i ); } if ( testCanceled() ) { break; } g1 = it->feature.geometry(); if ( g1.isNull() ) { continue; } if ( !_canExportToGeos( g1 ) ) { continue; } if ( !g1.isGeosValid() ) { qDebug() << "invalid geometry found..skipping.." << it->feature.id(); continue; } if ( g1.isMultipart() ) { QgsMultiPolygonXY polys = g1.asMultiPolygon(); for ( int m = 0; m < polys.count(); m++ ) { QgsPolygonXY polygon = polys[m]; QgsGeometry polyGeom = QgsGeometry::fromPolygonXY( polygon ); geomList.push_back( QgsGeos::asGeos( polyGeom ).release() ); } } else { geomList.push_back( QgsGeos::asGeos( g1 ).release() ); } } GEOSGeometry **geomArray = new GEOSGeometry*[geomList.size()]; for ( int i = 0; i < geomList.size(); ++i ) { //qDebug() << "filling geometry array-" << i; geomArray[i] = geomList.at( i ); } qDebug() << "creating geometry collection-"; if ( geomList.isEmpty() ) { //qDebug() << "geometry list is empty!"; delete [] geomArray; return errorList; } GEOSGeometry *collection = nullptr; collection = GEOSGeom_createCollection_r( geosctxt, GEOS_MULTIPOLYGON, geomArray, geomList.size() ); qDebug() << "performing cascaded union..might take time..-"; GEOSGeometry *unionGeom = GEOSUnionCascaded_r( geosctxt, collection ); //delete[] geomArray; QgsGeometry test = QgsGeos::geometryFromGeos( unionGeom ); //qDebug() << "wktmerged - " << test.exportToWkt(); QString extentWkt = test.boundingBox().asWktPolygon(); QgsGeometry extentGeom = QgsGeometry::fromWkt( extentWkt ); QgsGeometry bufferExtent = extentGeom.buffer( 2, 3 ); //qDebug() << "extent wkt - " << bufferExtent->exportToWkt(); QgsGeometry diffGeoms = bufferExtent.difference( test ); if ( !diffGeoms ) { qDebug() << "difference result 0-"; return errorList; } //qDebug() << "difference gometry - " << diffGeoms->exportToWkt(); QVector<QgsGeometry> geomColl = diffGeoms.asGeometryCollection(); QgsGeometry canvasExtentPoly = QgsGeometry::fromWkt( qgsInterface->mapCanvas()->extent().asWktPolygon() ); for ( int i = 1; i < geomColl.count() ; ++i ) { QgsGeometry conflictGeom = geomColl[i]; if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflictGeom ) ) { continue; } if ( canvasExtentPoly.crosses( conflictGeom ) ) { conflictGeom = conflictGeom.intersection( canvasExtentPoly ); } } QgsRectangle bBox = conflictGeom.boundingBox(); FeatureLayer ftrLayer1; ftrLayer1.layer = layer1; QList<FeatureLayer> errorFtrLayers; errorFtrLayers << ftrLayer1 << ftrLayer1; TopolErrorGaps *err = new TopolErrorGaps( bBox, conflictGeom, errorFtrLayers ); errorList << err; } return errorList; }
ErrorList topolTest::checkDuplicates( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer2 ); //TODO: multilines - check all separate pieces int i = 0; ErrorList errorList; QList<QgsFeatureId> duplicateIds; QgsSpatialIndex *index = mLayerIndexes[layer1->id()]; QgsGeometry canvasExtentPoly = QgsGeometry::fromWkt( qgsInterface->mapCanvas()->extent().asWktPolygon() ); QMap<QgsFeatureId, FeatureLayer>::const_iterator it; for ( it = mFeatureMap2.constBegin(); it != mFeatureMap2.constEnd(); ++it ) { if ( !( ++i % 100 ) ) emit progress( i ); QgsFeatureId currentId = it->feature.id(); if ( duplicateIds.contains( currentId ) ) { //is already a duplicate geometry..skip.. continue; } if ( testCanceled() ) break; QgsGeometry g1 = it->feature.geometry(); QgsRectangle bb = g1.boundingBox(); QList<QgsFeatureId> crossingIds; crossingIds = index->intersects( bb ); QList<QgsFeatureId>::ConstIterator cit = crossingIds.constBegin(); QList<QgsFeatureId>::ConstIterator crossingIdsEnd = crossingIds.constEnd(); bool duplicate = false; for ( ; cit != crossingIdsEnd; ++cit ) { duplicate = false; // skip itself if ( mFeatureMap2[*cit].feature.id() == it->feature.id() ) continue; QgsGeometry g2 = mFeatureMap2[*cit].feature.geometry(); if ( g2.isNull() ) { QgsMessageLog::logMessage( tr( "Invalid second geometry in duplicate geometry test." ), tr( "Topology plugin" ) ); continue; } if ( !_canExportToGeos( g2 ) ) { QgsMessageLog::logMessage( tr( "Failed to import second geometry into GEOS in duplicate geometry test." ), tr( "Topology plugin" ) ); continue; } if ( g1.isGeosEqual( g2 ) ) { duplicate = true; duplicateIds.append( mFeatureMap2[*cit].feature.id() ); } if ( duplicate ) { QList<FeatureLayer> fls; fls << *it << *it; QgsGeometry conflict( g1 ); if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflict ) ) { continue; } if ( canvasExtentPoly.crosses( conflict ) ) { conflict = conflict.intersection( canvasExtentPoly ); } } TopolErrorDuplicates *err = new TopolErrorDuplicates( bb, conflict, fls ); errorList << err; } } } return errorList; }
ErrorList topolTest::checkyLineEndsCoveredByPoints( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { int i = 0; ErrorList errorList; if ( layer1->geometryType() != QgsWkbTypes::LineGeometry ) { return errorList; } if ( layer2->geometryType() != QgsWkbTypes::PointGeometry ) { return errorList; } QgsSpatialIndex *index = mLayerIndexes[layer2->id()]; QgsGeometry canvasExtentPoly = QgsGeometry::fromWkt( qgsInterface->mapCanvas()->extent().asWktPolygon() ); QList<FeatureLayer>::Iterator it; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) emit progress( i ); if ( testCanceled() ) break; QgsGeometry g1 = it->feature.geometry(); QgsPolylineXY g1Polyline = g1.asPolyline(); QgsGeometry startPoint = QgsGeometry::fromPointXY( g1Polyline.at( 0 ) ); QgsGeometry endPoint = QgsGeometry::fromPointXY( g1Polyline.last() ); QgsRectangle bb = g1.boundingBox(); QList<QgsFeatureId> crossingIds; crossingIds = index->intersects( bb ); QList<QgsFeatureId>::ConstIterator cit = crossingIds.begin(); QList<QgsFeatureId>::ConstIterator crossingIdsEnd = crossingIds.end(); bool touched = false; bool touchStartPoint = false; bool touchEndPoint = false; for ( ; cit != crossingIdsEnd; ++cit ) { QgsFeature &f = mFeatureMap2[*cit].feature; QgsGeometry g2 = f.geometry(); if ( g2.isNull() || !_canExportToGeos( g2 ) ) { QgsMessageLog::logMessage( tr( "Second geometry missing or GEOS import failed." ), tr( "Topology plugin" ) ); continue; } if ( g2.intersects( startPoint ) ) { touchStartPoint = true; } if ( g2.intersects( endPoint ) ) { touchEndPoint = true; } if ( touchStartPoint && touchEndPoint ) { touched = true; break; } } if ( !touched ) { QgsGeometry conflictGeom = g1; if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflictGeom ) ) { continue; } if ( canvasExtentPoly.crosses( conflictGeom ) ) { conflictGeom = conflictGeom.intersection( canvasExtentPoly ); } } QList<FeatureLayer> fls; fls << *it << *it; //bb.scale(10); TopolErrorLineEndsNotCoveredByPoints *err = new TopolErrorLineEndsNotCoveredByPoints( bb, conflictGeom, fls ); errorList << err; } } return errorList; }
ErrorList topolTest::checkDuplicates( double tolerance, QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( tolerance ); Q_UNUSED( layer2 ); //TODO: multilines - check all separate pieces int i = 0; ErrorList errorList; QList<QgsFeatureId> duplicateIds; QgsSpatialIndex* index = mLayerIndexes[layer1->id()]; QgsGeometry* canvasExtentPoly = QgsGeometry::fromWkt( theQgsInterface->mapCanvas()->extent().asWktPolygon() ); QMap<QgsFeatureId, FeatureLayer>::Iterator it; QMap<QgsFeatureId, FeatureLayer>::ConstIterator FeatureListEnd = mFeatureMap2.end(); for ( it = mFeatureMap2.begin(); it != FeatureListEnd; ++it ) { if ( !( ++i % 100 ) ) emit progress( i ); QgsFeatureId currentId = it->feature.id(); if ( duplicateIds.contains( currentId ) ) { //is already a duplicate geometry..skip.. continue; } if ( testCancelled() ) break; QgsGeometry* g1 = it->feature.geometry(); QgsRectangle bb = g1->boundingBox(); QList<QgsFeatureId> crossingIds; crossingIds = index->intersects( bb ); QList<QgsFeatureId>::Iterator cit = crossingIds.begin(); QList<QgsFeatureId>::ConstIterator crossingIdsEnd = crossingIds.end(); bool duplicate = false; for ( ; cit != crossingIdsEnd; ++cit ) { duplicate = false; // skip itself if ( mFeatureMap2[*cit].feature.id() == it->feature.id() ) continue; const QgsGeometry* g2 = mFeatureMap2[*cit].feature.constGeometry(); if ( !g2 ) { QgsMessageLog::logMessage( tr( "Invalid second geometry in duplicate geometry test." ), tr( "Topology plugin" ) ); continue; } if ( !g2->asGeos() ) { QgsMessageLog::logMessage( tr( "Failed to import second geometry into GEOS in duplicate geometry test." ), tr( "Topology plugin" ) ); continue; } if ( g1->equals( g2 ) ) { duplicate = true; duplicateIds.append( mFeatureMap2[*cit].feature.id() ); } if ( duplicate ) { QList<FeatureLayer> fls; fls << *it << *it; QScopedPointer<QgsGeometry> conflict( new QgsGeometry( *g1 ) ); if ( isExtent ) { if ( canvasExtentPoly->disjoint( conflict.data() ) ) { continue; } if ( canvasExtentPoly->crosses( conflict.data() ) ) { conflict.reset( conflict->intersection( canvasExtentPoly ) ); } } TopolErrorDuplicates* err = new TopolErrorDuplicates( bb, conflict.take(), fls ); errorList << err; } } } delete canvasExtentPoly; return errorList; }
ErrorList topolTest::checkyLineEndsCoveredByPoints( double tolerance, QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( tolerance ); int i = 0; ErrorList errorList; if ( layer1->geometryType() != QGis::Line ) { return errorList; } if ( layer2->geometryType() != QGis::Point ) { return errorList; } QgsSpatialIndex* index = mLayerIndexes[layer2->id()]; QgsGeometry* canvasExtentPoly = QgsGeometry::fromWkt( theQgsInterface->mapCanvas()->extent().asWktPolygon() ); QList<FeatureLayer>::Iterator it; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) emit progress( i ); if ( testCancelled() ) break; QgsGeometry* g1 = it->feature.geometry(); QgsGeometry* startPoint = QgsGeometry::fromPoint( g1->asPolyline().first() ); QgsGeometry* endPoint = QgsGeometry::fromPoint( g1->asPolyline().last() ); QgsRectangle bb = g1->boundingBox(); QList<QgsFeatureId> crossingIds; crossingIds = index->intersects( bb ); QList<QgsFeatureId>::Iterator cit = crossingIds.begin(); QList<QgsFeatureId>::ConstIterator crossingIdsEnd = crossingIds.end(); bool touched = false; bool touchStartPoint = false; bool touchEndPoint = false; for ( ; cit != crossingIdsEnd; ++cit ) { QgsFeature& f = mFeatureMap2[*cit].feature; const QgsGeometry* g2 = f.constGeometry(); if ( !g2 || !g2->asGeos() ) { QgsMessageLog::logMessage( tr( "Second geometry missing or GEOS import failed." ), tr( "Topology plugin" ) ); continue; } if ( g2->intersects( startPoint ) ) { touchStartPoint = true; } if ( g2->intersects( endPoint ) ) { touchEndPoint = true; } if ( touchStartPoint && touchEndPoint ) { touched = true; break; } } delete startPoint; delete endPoint; if ( !touched ) { QScopedPointer<QgsGeometry> conflictGeom( new QgsGeometry( *g1 ) ); if ( isExtent ) { if ( canvasExtentPoly->disjoint( conflictGeom.data() ) ) { continue; } if ( canvasExtentPoly->crosses( conflictGeom.data() ) ) { conflictGeom.reset( conflictGeom->intersection( canvasExtentPoly ) ); } } QList<FeatureLayer> fls; fls << *it << *it; //bb.scale(10); TopolErrorLineEndsNotCoveredByPoints* err = new TopolErrorLineEndsNotCoveredByPoints( bb, conflictGeom.take(), fls ); errorList << err; } } delete canvasExtentPoly; return errorList; }
bool QgsSpatialFilter::evaluate( const QgsFeature& f ) const { if ( !mGeom ) { return true; } QgsGeometry* geom = ( new QgsFeature( f ) )->geometry(); switch ( mSpatialType ) { case BBOX: return geom->intersects( mGeom->boundingBox() ); break; case CONTAINS: return geom->contains( mGeom ); break; case CROSSES: return geom->crosses( mGeom ); break; case DISJOINT: return geom->disjoint( mGeom ); break; case EQUALS: return geom->equals( mGeom ); break; case INTERSECTS: return geom->intersects( mGeom ); break; case OVERLAPS: return geom->overlaps( mGeom ); break; case TOUCHES: return geom->touches( mGeom ); break; case WITHIN: return geom->within( mGeom ); break; case UNKNOWN: default: break; } return false; }