25 : mGeometry( geometry )
44 void QgsGeometryValidator::checkRingIntersections(
int p0,
int i0,
const QgsLineString *ring0,
int p1,
int i1,
const QgsLineString *ring1 )
46 for (
int i = 0; !mStop && i < ring0->
numPoints() - 1; i++ )
48 const double ring0XAti = ring0->
xAt( i );
49 const double ring0YAti = ring0->
yAt( i );
50 QgsVector v( ring0->
xAt( i + 1 ) - ring0XAti, ring0->
yAt( i + 1 ) - ring0YAti );
52 for (
int j = 0; !mStop && j < ring1->
numPoints() - 1; j++ )
54 const double ring1XAtj = ring1->
xAt( j );
55 const double ring1YAtj = ring1->
yAt( j );
56 QgsVector w( ring1->
xAt( j + 1 ) - ring1XAtj, ring1->
yAt( j + 1 ) - ring1YAtj );
60 if ( intersectLines( ring0XAti, ring0YAti, v, ring1XAtj, ring1YAtj, w, sX, sY ) )
62 double d = -distLine2Point( ring0XAti, ring0YAti, v.perpVector(), sX, sY );
64 if ( d >= 0 && d <= v.length() )
66 d = -distLine2Point( ring1XAtj, ring1YAtj, w.perpVector(), sX, sY );
67 if ( d > 0 && d < w.length() &&
68 ring0[i + 1] != ring1[j + 1] && ring0[i + 1] != ring1[j] &&
69 ring0[i + 0] != ring1[j + 1] && ring0[i + 0] != ring1[j] )
71 QString msg = QObject::tr(
"segment %1 of ring %2 of polygon %3 intersects segment %4 of ring %5 of polygon %6 at %7, %8" )
72 .arg( i0 ).arg( i ).arg( p0 )
73 .arg( i1 ).arg( j ).arg( p1 )
85 void QgsGeometryValidator::validatePolyline(
int i,
const QgsLineString *line,
bool ring )
94 QString msg = QObject::tr(
"ring %1 with less than four points" ).arg( i );
103 QString msg = QObject::tr(
"ring %1 not closed" ).arg( i );
112 QString msg = QObject::tr(
"line %1 with less than two points" ).arg( i );
119 std::unique_ptr< QgsLineString > noDupes;
124 if ( !duplicateNodes.empty() )
126 noDupes.reset( line->
clone() );
127 for (
int j = duplicateNodes.size() - 1; j >= 0; j-- )
129 const QgsVertexId duplicateVertex = duplicateNodes.at( j );
130 const QgsPointXY duplicationLocation = noDupes->vertexAt( duplicateVertex );
131 noDupes->deleteVertex( duplicateVertex );
135 for (
int k = j - 1; k >= 0; k-- )
137 const QgsVertexId prevDupe = duplicateNodes.at( k );
152 QString msg = QObject::tr(
"line %1 contains %n duplicate nodes starting at vertex %2",
"number of duplicate nodes", n + 1 ).arg( i + 1 ).arg( duplicateVertex.
vertex - n + 1 );
157 line = noDupes.get();
160 for (
int j = 0; !mStop && j < line->
numPoints() - 3; j++ )
162 const double xAtJ = line->
xAt( j );
163 const double yAtJ = line->
yAt( j );
165 double vl = v.length();
169 for (
int k = j + 2; !mStop && k < n; k++ )
171 const double xAtK = line->
xAt( k );
172 const double yAtK = line->
yAt( k );
178 if ( !intersectLines( xAtJ, yAtJ, v, xAtK, yAtK, w, sX, sY ) )
184 d = -distLine2Point( xAtJ, yAtJ, v.perpVector(), sX, sY );
192 if ( d < 0 || d > vl )
197 d = -distLine2Point( xAtK, yAtK, w.perpVector(), sX, sY );
206 if ( d <= 0 || d >= w.length() )
209 QString msg = QObject::tr(
"segments %1 and %2 of line %3 intersect at %4, %5" ).arg( j ).arg( k ).arg( i ).arg( sX ).arg( sY );
217 void QgsGeometryValidator::validatePolygon(
int idx,
const QgsPolygon *polygon )
224 QString msg = QObject::tr(
"ring %1 of polygon %2 not in exterior ring" ).arg( i + 1 ).arg( idx );
236 checkRingIntersections( idx, i + 1, qgsgeometry_cast< QgsLineString * >( polygon->
interiorRing( i ) ),
237 idx, j + 1, qgsgeometry_cast< QgsLineString * >( polygon->
interiorRing( j ) ) );
242 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( polygon->
exteriorRing() ),
true );
245 validatePolyline( i + 1, qgsgeometry_cast< const QgsLineString * >( polygon->
interiorRing( i ) ),
true );
270 if ( !
geos.isValid( &error,
true, &errorLoc ) )
297 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( mGeometry.
constGet() ) );
303 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
304 validatePolyline( i, qgsgeometry_cast< const QgsLineString * >( collection->
geometryN( i ) ) );
309 validatePolygon( 0, qgsgeometry_cast< const QgsPolygon * >( mGeometry.
constGet() ) );
315 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
316 validatePolygon( i, qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( i ) ) );
318 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
320 const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( i ) );
328 for (
int j = i + 1; !mStop && j < collection->
numGeometries(); j++ )
330 const QgsPolygon *poly2 = qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( j ) );
334 if ( ringInRing( qgsgeometry_cast< const QgsLineString * >( poly->
exteriorRing() ),
335 qgsgeometry_cast< const QgsLineString * >( poly2->
exteriorRing() ) ) )
348 checkRingIntersections( i, 0, qgsgeometry_cast< const QgsLineString * >( poly->
exteriorRing() ),
349 j, 0, qgsgeometry_cast< const QgsLineString * >( poly2->
exteriorRing() ) );
371 else if ( mErrorCount > 0 )
373 emit
validationFinished( QObject::tr(
"Geometry has %1 errors." ).arg( mErrorCount ) );
403 double QgsGeometryValidator::distLine2Point(
double px,
double py,
QgsVector v,
double qX,
double qY )
405 const double l = v.
length();
411 return ( v.
x() * ( qY - py ) - v.
y() * ( qX - px ) ) / l;
414 bool QgsGeometryValidator::intersectLines(
double px,
double py,
QgsVector v,
double qx,
double qy,
QgsVector w,
double &sX,
double &sY )
416 double d = v.
y() * w.
x() - v.
x() * w.
y();
423 double k = ( dy * w.
x() - dx * w.
y() ) / d;
431 bool QgsGeometryValidator::pointInRing(
const QgsLineString *ring,
double pX,
double pY )
439 for (
int i = 0; !mStop && i < ring->
numPoints(); i++ )
441 const double xAti = ring->
xAt( i );
442 const double yAti = ring->
yAt( i );
443 const double xAtj = ring->
xAt( j );
444 const double yAtj = ring->
yAt( j );
449 if ( ( yAti < pY && yAtj >= pY ) ||
450 ( yAtj < pY && yAti >= pY ) )
452 if ( xAti + ( pY - yAti ) / ( yAtj - yAti ) * ( xAtj - xAti ) <= pX )
467 for (
int i = 0; !mStop && i < inside->
numPoints(); i++ )
469 if ( !pointInRing( outside, inside->
xAt( i ), inside->
yAt( i ) ) )