ErrorList topolTest::checkMultipart( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer2 ); Q_UNUSED( layer1 ); Q_UNUSED( isExtent ); int i = 0; ErrorList errorList; QList<FeatureLayer>::Iterator it; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) emit progress( ++i ); if ( testCanceled() ) break; QgsGeometry g = it->feature.geometry(); if ( g.isNull() ) { QgsMessageLog::logMessage( tr( "Missing geometry in multipart check." ), tr( "Topology plugin" ) ); continue; } if ( !_canExportToGeos( g ) ) continue; if ( g.isMultipart() ) { QgsRectangle r = g.boundingBox(); QList<FeatureLayer> fls; fls << *it << *it; TopolErroMultiPart *err = new TopolErroMultiPart( r, g, fls ); errorList << err; } } return errorList; }
ErrorList topolTest::checkPolygonContainsPoint( double tolerance, QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( tolerance ); Q_UNUSED( isExtent ); int i = 0; ErrorList errorList; if ( layer1->geometryType() != QgsWkbTypes::PolygonGeometry ) { return errorList; } if ( layer2->geometryType() != QgsWkbTypes::PointGeometry ) { return errorList; } QgsSpatialIndex *index = mLayerIndexes[layer2->id()]; 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.constEnd(); bool touched = 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 ( g1.contains( g2 ) ) { touched = true; break; } } if ( !touched ) { QList<FeatureLayer> fls; fls << *it << *it; //bb.scale(10); TopolErrorPolygonContainsPoint *err = new TopolErrorPolygonContainsPoint( bb, g1, fls ); errorList << err; } } return errorList; }
ErrorList topolTest::checkPointCoveredByLineEnds( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { int i = 0; ErrorList errorList; if ( layer1->geometryType() != QgsWkbTypes::PointGeometry ) { return errorList; } if ( layer2->geometryType() != QgsWkbTypes::LineGeometry ) { 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(); QgsRectangle bb = g1.boundingBox(); QList<QgsFeatureId> crossingIds; crossingIds = index->intersects( bb ); QList<QgsFeatureId>::ConstIterator cit = crossingIds.constBegin(); QList<QgsFeatureId>::ConstIterator crossingIdsEnd = crossingIds.constEnd(); bool touched = 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; } QgsPolylineXY g2Line = g2.asPolyline(); QgsGeometry startPoint = QgsGeometry::fromPointXY( g2Line.at( 0 ) ); QgsGeometry endPoint = QgsGeometry::fromPointXY( g2Line.last() ); touched = g1.intersects( startPoint ) || g1.intersects( endPoint ); if ( touched ) { break; } } if ( !touched ) { QgsGeometry conflictGeom = g1; if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflictGeom ) ) { continue; } } QList<FeatureLayer> fls; fls << *it << *it; //bb.scale(10); TopolErrorPointNotCoveredByLineEnds *err = new TopolErrorPointNotCoveredByLineEnds( bb, conflictGeom, fls ); errorList << err; } } return errorList; }
ErrorList topolTest::checkPseudos( QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer2 ); int i = 0; ErrorList errorList; QgsFeature f; if ( layer1->geometryType() != QgsWkbTypes::LineGeometry ) { return errorList; } QList<FeatureLayer>::iterator it; qDebug() << mFeatureList1.count(); QgsPointXY startPoint; QgsPointXY endPoint; std::multimap<QgsPointXY, QgsFeatureId, PointComparer> endVerticesMap; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) emit progress( i ); if ( testCanceled() ) break; QgsGeometry g1 = it->feature.geometry(); if ( g1.isNull() ) { QgsMessageLog::logMessage( tr( "Skipping invalid first geometry in pseudo line test." ), tr( "Topology plugin" ) ); continue; } if ( !_canExportToGeos( g1 ) ) { QgsMessageLog::logMessage( tr( "Failed to import first geometry into GEOS in pseudo line test." ), tr( "Topology plugin" ) ); continue; } if ( g1.isMultipart() ) { QgsMultiPolylineXY lines = g1.asMultiPolyline(); for ( int m = 0; m < lines.count(); m++ ) { QgsPolylineXY line = lines[m]; startPoint = line[0]; endPoint = line[line.size() - 1]; endVerticesMap.insert( std::pair<QgsPointXY, QgsFeatureId>( startPoint, it->feature.id() ) ); endVerticesMap.insert( std::pair<QgsPointXY, QgsFeatureId>( endPoint, it->feature.id() ) ); } } else { QgsPolylineXY polyline = g1.asPolyline(); startPoint = polyline[0]; endPoint = polyline[polyline.size() - 1]; endVerticesMap.insert( std::pair<QgsPointXY, QgsFeatureId>( startPoint, it->feature.id() ) ); endVerticesMap.insert( std::pair<QgsPointXY, QgsFeatureId>( endPoint, it->feature.id() ) ); } } QgsGeometry canvasExtentPoly = QgsGeometry::fromWkt( qgsInterface->mapCanvas()->extent().asWktPolygon() ); for ( std::multimap<QgsPointXY, QgsFeatureId, PointComparer>::iterator pointIt = endVerticesMap.begin(), end = endVerticesMap.end(); pointIt != end; pointIt = endVerticesMap.upper_bound( pointIt->first ) ) { QgsPointXY p = pointIt->first; QgsFeatureId k = pointIt->second; size_t repetitions = endVerticesMap.count( p ); if ( repetitions == 2 ) { QgsGeometry conflictGeom = QgsGeometry::fromPointXY( p ); if ( isExtent ) { if ( canvasExtentPoly.disjoint( conflictGeom ) ) { continue; } } QgsRectangle bBox = conflictGeom.boundingBox(); QgsFeature feat; FeatureLayer ftrLayer1; //need to fetch attributes?? being safe side by fetching.. layer1->getFeatures( QgsFeatureRequest().setFilterFid( k ) ).nextFeature( feat ); ftrLayer1.feature = feat; ftrLayer1.layer = layer1; QList<FeatureLayer> errorFtrLayers; errorFtrLayers << ftrLayer1 << ftrLayer1; TopolErrorPseudos *err = new TopolErrorPseudos( bBox, conflictGeom, errorFtrLayers ); errorList << err; } } 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::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::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; }