28 : mGeometry( geometry )
47 void QgsGeometryValidator::checkRingIntersections(
int partIndex0,
int ringIndex0,
const QgsCurve *ring0,
int partIndex1,
int ringIndex1,
const QgsCurve *ring1 )
49 const QgsLineString *ringLine0 = qgsgeometry_cast< const QgsLineString * >( ring0 );
50 std::unique_ptr< QgsLineString > segmentisedRing0;
53 segmentisedRing0.reset( qgsgeometry_cast< QgsLineString * >( ring0->
segmentize() ) );
54 ringLine0 = segmentisedRing0.get();
57 const QgsLineString *ringLine1 = qgsgeometry_cast< const QgsLineString * >( ring1 );
58 std::unique_ptr< QgsLineString > segmentisedRing1;
61 segmentisedRing1.reset( qgsgeometry_cast< QgsLineString * >( ring1->
segmentize() ) );
62 ringLine1 = segmentisedRing1.get();
65 Q_ASSERT( ringLine0 );
66 Q_ASSERT( ringLine1 );
68 for (
int i = 0; !mStop && i < ringLine0->
numPoints() - 1; i++ )
70 const double ring0XAti = ringLine0->
xAt( i );
71 const double ring0YAti = ringLine0->
yAt( i );
72 const QgsVector v( ringLine0->
xAt( i + 1 ) - ring0XAti, ringLine0->
yAt( i + 1 ) - ring0YAti );
74 for (
int j = 0; !mStop && j < ringLine1->
numPoints() - 1; j++ )
76 const double ring1XAtj = ringLine1->
xAt( j );
77 const double ring1YAtj = ringLine1->
yAt( j );
78 const QgsVector w( ringLine1->
xAt( j + 1 ) - ring1XAtj, ringLine1->
yAt( j + 1 ) - ring1YAtj );
82 if ( intersectLines( ring0XAti, ring0YAti, v, ring1XAtj, ring1YAtj, w, sX, sY ) )
84 double d = -distLine2Point( ring0XAti, ring0YAti, v.perpVector(), sX, sY );
86 if ( d >= 0 && d <= v.length() )
88 d = -distLine2Point( ring1XAtj, ring1YAtj, w.perpVector(), sX, sY );
89 if ( d > 0 && d < w.length() &&
93 const QString msg = QObject::tr(
"segment %1 of ring %2 of polygon %3 intersects segment %4 of ring %5 of polygon %6 at %7, %8" )
94 .arg( i ).arg( ringIndex0 ).arg( partIndex0 )
95 .arg( j ).arg( ringIndex1 ).arg( partIndex1 )
106 void QgsGeometryValidator::validatePolyline(
int i,
const QgsLineString *line,
bool ring )
115 const QString msg = QObject::tr(
"ring %1 with less than four points" ).arg( i );
129 msg = QObject::tr(
"ring %1 not closed, Z mismatch: %2 vs %3" ).arg( i ).arg( startPoint.
z() ).arg( endPoint.
z() );
133 msg = QObject::tr(
"ring %1 not closed" ).arg( i );
143 const QString msg = QObject::tr(
"line %1 with less than two points" ).arg( i );
150 std::unique_ptr< QgsLineString > noDupes;
155 if ( !duplicateNodes.empty() )
157 noDupes.reset( line->
clone() );
158 for (
int j = duplicateNodes.size() - 1; j >= 0; j-- )
160 const QgsVertexId duplicateVertex = duplicateNodes.at( j );
161 const QgsPointXY duplicationLocation = noDupes->vertexAt( duplicateVertex );
162 noDupes->deleteVertex( duplicateVertex );
166 for (
int k = j - 1; k >= 0; k-- )
168 const QgsVertexId prevDupe = duplicateNodes.at( k );
183 const QString msg = QObject::tr(
"line %1 contains %n duplicate node(s) starting at vertex %2",
"number of duplicate nodes", n + 1 ).arg( i + 1 ).arg( duplicateVertex.
vertex - n + 1 );
188 line = noDupes.get();
191 for (
int j = 0; !mStop && j < line->
numPoints() - 3; j++ )
193 const double xAtJ = line->
xAt( j );
194 const double yAtJ = line->
yAt( j );
195 const QgsVector v( line->
xAt( j + 1 ) - xAtJ, line->
yAt( j + 1 ) - yAtJ );
196 const double vl = v.length();
200 for (
int k = j + 2; !mStop && k < n; k++ )
202 const double xAtK = line->
xAt( k );
203 const double yAtK = line->
yAt( k );
205 const QgsVector w( line->
xAt( k + 1 ) - xAtK, line->
yAt( k + 1 ) - yAtK );
209 if ( !intersectLines( xAtJ, yAtJ, v, xAtK, yAtK, w, sX, sY ) )
215 d = -distLine2Point( xAtJ, yAtJ, v.perpVector(), sX, sY );
223 if ( d < 0 || d > vl )
228 d = -distLine2Point( xAtK, yAtK, w.perpVector(), sX, sY );
237 if ( d <= 0 || d >= w.length() )
240 const 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 );
248 void QgsGeometryValidator::validatePolygon(
int partIndex,
const QgsCurvePolygon *polygon )
255 const QString msg = QObject::tr(
"ring %1 of polygon %2 not in exterior ring" ).arg( i + 1 ).arg( partIndex );
267 checkRingIntersections( partIndex, i + 1, polygon->
interiorRing( i ),
273 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( polygon->
exteriorRing() ),
true );
276 validatePolyline( i + 1, qgsgeometry_cast< const QgsLineString * >( polygon->
interiorRing( i ) ),
true );
290 case Qgis::GeometryValidationEngine::Geos:
301 if ( !
geos.isValid( &error,
true, &errorLoc ) )
319 case Qgis::GeometryValidationEngine::QgisInternal:
328 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( mGeometry.
constGet() ) );
334 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
335 validatePolyline( i, qgsgeometry_cast< const QgsLineString * >( collection->
geometryN( i ) ) );
341 validatePolygon( 0, qgsgeometry_cast< const QgsCurvePolygon * >( mGeometry.
constGet() ) );
348 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
349 validatePolygon( i, qgsgeometry_cast< const QgsCurvePolygon * >( collection->
geometryN( i ) ) );
351 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
361 for (
int j = i + 1; !mStop && j < collection->
numGeometries(); j++ )
404 else if ( mErrorCount > 0 )
406 emit
validationFinished( QObject::tr(
"Geometry has %n error(s).",
nullptr, mErrorCount ) );
436 double QgsGeometryValidator::distLine2Point(
double px,
double py,
QgsVector v,
double qX,
double qY )
438 const double l = v.
length();
444 return ( v.
x() * ( qY - py ) - v.
y() * ( qX - px ) ) / l;
447 bool QgsGeometryValidator::intersectLines(
double px,
double py,
QgsVector v,
double qx,
double qy,
QgsVector w,
double &sX,
double &sY )
449 const double d = v.
y() * w.
x() - v.
x() * w.
y();
454 const double dx = qx - px;
455 const double dy = qy - py;
456 const double k = ( dy * w.
x() - dx * w.
y() ) / d;
464 bool QgsGeometryValidator::pointInRing(
const QgsCurve *ring,
double pX,
double pY )
472 for (
int i = 0; !mStop && i < ring->
numPoints(); i++ )
474 const double xAti = ring->
xAt( i );
475 const double yAti = ring->
yAt( i );
476 const double xAtj = ring->
xAt( j );
477 const double yAtj = ring->
yAt( j );
482 if ( ( yAti < pY && yAtj >= pY ) ||
483 ( yAtj < pY && yAti >= pY ) )
485 if ( xAti + ( pY - yAti ) / ( yAtj - yAti ) * ( xAtj - xAti ) <= pX )
495 bool QgsGeometryValidator::ringInRing(
const QgsCurve *inside,
const QgsCurve *outside )
500 for (
int i = 0; !mStop && i < inside->
numPoints(); i++ )
502 if ( !pointInRing( outside, inside->
xAt( i ), inside->
yAt( i ) ) )