std::unique_ptr<QgsLineString> QgsGeometryFactory::linestringFromPolyline( const QgsPolylineXY &polyline ) { QVector< double > x; x.reserve( polyline.size() ); QVector< double > y; y.reserve( polyline.size() ); QgsPolylineXY::const_iterator it = polyline.constBegin(); for ( ; it != polyline.constEnd(); ++it ) { x << it->x(); y << it->y(); } std::unique_ptr< QgsLineString > line = qgis::make_unique< QgsLineString >( x, y ); return line; }
bool QgsGeometryValidator::ringInRing( const QgsPolylineXY &inside, const QgsPolylineXY &outside ) { for ( int i = 0; !mStop && i < inside.size(); i++ ) { if ( !pointInRing( outside, inside[i] ) ) return false; } return true; }
bool QgsGeometryValidator::pointInRing( const QgsPolylineXY &ring, const QgsPointXY &p ) { bool inside = false; int j = ring.size() - 1; for ( int i = 0; !mStop && i < ring.size(); i++ ) { if ( qgsDoubleNear( ring[i].x(), p.x() ) && qgsDoubleNear( ring[i].y(), p.y() ) ) return true; if ( ( ring[i].y() < p.y() && ring[j].y() >= p.y() ) || ( ring[j].y() < p.y() && ring[i].y() >= p.y() ) ) { if ( ring[i].x() + ( p.y() - ring[i].y() ) / ( ring[j].y() - ring[i].y() ) * ( ring[j].x() - ring[i].x() ) <= p.x() ) inside = !inside; } j = i; } return inside; }
void QgsGeometryValidator::checkRingIntersections( int p0, int i0, const QgsPolylineXY &ring0, int p1, int i1, const QgsPolylineXY &ring1 ) { for ( int i = 0; !mStop && i < ring0.size() - 1; i++ ) { QgsVector v = ring0[i + 1] - ring0[i]; for ( int j = 0; !mStop && j < ring1.size() - 1; j++ ) { QgsVector w = ring1[j + 1] - ring1[j]; QgsPointXY s; if ( intersectLines( ring0[i], v, ring1[j], w, s ) ) { double d = -distLine2Point( ring0[i], v.perpVector(), s ); if ( d >= 0 && d <= v.length() ) { d = -distLine2Point( ring1[j], w.perpVector(), s ); if ( d > 0 && d < w.length() && ring0[i + 1] != ring1[j + 1] && ring0[i + 1] != ring1[j] && ring0[i + 0] != ring1[j + 1] && ring0[i + 0] != ring1[j] ) { QString msg = QObject::tr( "segment %1 of ring %2 of polygon %3 intersects segment %4 of ring %5 of polygon %6 at %7" ) .arg( i0 ).arg( i ).arg( p0 ) .arg( i1 ).arg( j ).arg( p1 ) .arg( s.toString() ); QgsDebugMsg( msg ); emit errorFound( QgsGeometry::Error( msg, s ) ); mErrorCount++; } } } } } }
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; }
void QgsGeometryValidator::validatePolyline( int i, QgsPolylineXY line, bool ring ) { if ( ring ) { if ( line.size() < 4 ) { QString msg = QObject::tr( "ring %1 with less than four points" ).arg( i ); QgsDebugMsg( msg ); emit errorFound( QgsGeometry::Error( msg ) ); mErrorCount++; return; } if ( line[0] != line[ line.size() - 1 ] ) { QString msg = QObject::tr( "ring %1 not closed" ).arg( i ); QgsDebugMsg( msg ); emit errorFound( QgsGeometry::Error( msg ) ); mErrorCount++; return; } } else if ( line.size() < 2 ) { QString msg = QObject::tr( "line %1 with less than two points" ).arg( i ); QgsDebugMsg( msg ); emit errorFound( QgsGeometry::Error( msg ) ); mErrorCount++; return; } int j = 0; while ( j < line.size() - 1 ) { int n = 0; while ( j < line.size() - 1 && line[j] == line[j + 1] ) { line.remove( j ); n++; } if ( n > 0 ) { QString msg = QObject::tr( "line %1 contains %n duplicate node(s) at %2", "number of duplicate nodes", n ).arg( i ).arg( j ); QgsDebugMsg( msg ); emit errorFound( QgsGeometry::Error( msg, line[j] ) ); mErrorCount++; } j++; } for ( j = 0; !mStop && j < line.size() - 3; j++ ) { QgsVector v = line[j + 1] - line[j]; double vl = v.length(); int n = ( j == 0 && ring ) ? line.size() - 2 : line.size() - 1; for ( int k = j + 2; !mStop && k < n; k++ ) { QgsVector w = line[k + 1] - line[k]; QgsPointXY s; if ( !intersectLines( line[j], v, line[k], w, s ) ) continue; double d = 0.0; try { d = -distLine2Point( line[j], v.perpVector(), s ); } catch ( QgsException &e ) { Q_UNUSED( e ); QgsDebugMsg( "Error validating: " + e.what() ); continue; } if ( d < 0 || d > vl ) continue; try { d = -distLine2Point( line[k], w.perpVector(), s ); } catch ( QgsException &e ) { Q_UNUSED( e ); QgsDebugMsg( "Error validating: " + e.what() ); continue; } if ( d <= 0 || d >= w.length() ) continue; QString msg = QObject::tr( "segments %1 and %2 of line %3 intersect at %4" ).arg( j ).arg( k ).arg( i ).arg( s.toString() ); QgsDebugMsg( msg ); emit errorFound( QgsGeometry::Error( msg, s ) ); mErrorCount++; } } }
ErrorList topolTest::checkSegmentLength( double tolerance, QgsVectorLayer *layer1, QgsVectorLayer *layer2, bool isExtent ) { Q_UNUSED( layer1 ); Q_UNUSED( layer2 ); Q_UNUSED( isExtent ); int i = 0; ErrorList errorList; QgsFeature f; QList<FeatureLayer>::iterator it; QgsPolygonXY pol; QgsMultiPolygonXY mpol; QgsPolylineXY segm; QgsPolylineXY ls; QgsMultiPolylineXY mls; QList<FeatureLayer> fls; TopolErrorShort *err = nullptr; double distance; for ( it = mFeatureList1.begin(); it != mFeatureList1.end(); ++it ) { if ( !( ++i % 100 ) ) { emit progress( i ); } if ( testCanceled() ) { break; } QgsGeometry g1 = it->feature.geometry(); // switching by type here, because layer can contain both single and multi version geometries switch ( g1.wkbType() ) { case QgsWkbTypes::LineString: case QgsWkbTypes::LineString25D: ls = g1.asPolyline(); for ( int i = 1; i < ls.size(); ++i ) { distance = std::sqrt( ls[i - 1].sqrDist( ls[i] ) ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << ls[i - 1] << ls[i]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); //err = new TopolErrorShort(g1->boundingBox(), QgsGeometry::fromPolyline(segm), fls); errorList << err; //break on getting the first error break; } } break; case QgsWkbTypes::Polygon: case QgsWkbTypes::Polygon25D: pol = g1.asPolygon(); for ( int i = 0; i < pol.size(); ++i ) { for ( int j = 1; j < pol[i].size(); ++j ) { distance = std::sqrt( pol[i][j - 1].sqrDist( pol[i][j] ) ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << pol[i][j - 1] << pol[i][j]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } break; case QgsWkbTypes::MultiLineString: case QgsWkbTypes::MultiLineString25D: mls = g1.asMultiPolyline(); for ( int k = 0; k < mls.size(); ++k ) { QgsPolylineXY &ls = mls[k]; for ( int i = 1; i < ls.size(); ++i ) { distance = std::sqrt( ls[i - 1].sqrDist( ls[i] ) ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << ls[i - 1] << ls[i]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } break; case QgsWkbTypes::MultiPolygon: case QgsWkbTypes::MultiPolygon25D: mpol = g1.asMultiPolygon(); for ( int k = 0; k < mpol.size(); ++k ) { QgsPolygonXY &pol = mpol[k]; for ( int i = 0; i < pol.size(); ++i ) { for ( int j = 1; j < pol[i].size(); ++j ) { distance = pol[i][j - 1].sqrDist( pol[i][j] ); if ( distance < tolerance ) { fls.clear(); fls << *it << *it; segm.clear(); segm << pol[i][j - 1] << pol[i][j]; QgsGeometry conflict = QgsGeometry::fromPolylineXY( segm ); err = new TopolErrorShort( g1.boundingBox(), conflict, fls ); errorList << err; //break on getting the first error break; } } } } break; default: continue; } } return errorList; }