23 : mGeometry( geometry )
42 void QgsGeometryValidator::checkRingIntersections(
46 for (
int i = 0; !mStop && i < ring0.size() - 1; i++ )
50 for (
int j = 0; !mStop && j < ring1.size() - 1; j++ )
55 if ( intersectLines( ring0[i], v, ring1[j], w, s ) )
57 double d = -distLine2Point( ring0[i], v.
perpVector(), s );
59 if ( d >= 0 && d <= v.
length() )
61 d = -distLine2Point( ring1[j], w.
perpVector(), s );
62 if ( d > 0 && d < w.
length() &&
63 ring0[i + 1] != ring1[j + 1] && ring0[i + 1] != ring1[j] &&
64 ring0[i + 0] != ring1[j + 1] && ring0[i + 0] != ring1[j] )
66 QString msg = QObject::tr(
"segment %1 of ring %2 of polygon %3 intersects segment %4 of ring %5 of polygon %6 at %7" )
67 .arg( i0 ).arg( i ).arg( p0 )
68 .arg( i1 ).arg( j ).arg( p1 )
80 void QgsGeometryValidator::validatePolyline(
int i,
QgsPolylineXY line,
bool ring )
84 if ( line.size() < 4 )
86 QString msg = QObject::tr(
"ring %1 with less than four points" ).arg( i );
93 if ( line[0] != line[ line.size() - 1 ] )
95 QString msg = QObject::tr(
"ring %1 not closed" ).arg( i );
102 else if ( line.size() < 2 )
104 QString msg = QObject::tr(
"line %1 with less than two points" ).arg( i );
112 while ( j < line.size() - 1 )
115 while ( j < line.size() - 1 && line[j] == line[j + 1] )
123 QString msg = QObject::tr(
"line %1 contains %n duplicate node(s) at %2",
"number of duplicate nodes", n ).arg( i ).arg( j );
132 for ( j = 0; !mStop && j < line.size() - 3; j++ )
137 int n = ( j == 0 && ring ) ? line.size() - 2 : line.size() - 1;
139 for (
int k = j + 2; !mStop && k < n; k++ )
144 if ( !intersectLines( line[j], v, line[k], w, s ) )
150 d = -distLine2Point( line[j], v.
perpVector(), s );
158 if ( d < 0 || d > vl )
163 d = -distLine2Point( line[k], w.
perpVector(), s );
172 if ( d <= 0 || d >= w.
length() )
175 QString msg = QObject::tr(
"segments %1 and %2 of line %3 intersect at %4" ).arg( j ).arg( k ).arg( i ).arg( s.
toString() );
183 void QgsGeometryValidator::validatePolygon(
int idx,
const QgsPolygonXY &polygon )
186 for (
int i = 1; !mStop && i < polygon.size(); i++ )
188 if ( !ringInRing( polygon[i], polygon[0] ) )
190 QString msg = QObject::tr(
"Ring %1 of polygon %2 not in exterior ring" ).arg( i ).arg( idx );
198 for (
int i = 1; !mStop && i < polygon.size(); i++ )
200 for (
int j = i + 1; !mStop && j < polygon.size(); j++ )
202 checkRingIntersections( idx, i, polygon[i], idx, j, polygon[j] );
207 for (
int i = 0; !mStop && i < polygon.size(); i++ )
209 validatePolyline( i, polygon[i],
true );
229 GEOSGeometry *g1 =
nullptr;
230 char res = GEOSisValidDetail_r( handle, g0.get(), GEOSVALID_ALLOW_SELFTOUCHING_RING_FORMING_HOLE, &r, &g1 );
235 if ( translatedErrors.empty() )
238 translatedErrors.insert( QStringLiteral(
"topology validation error" ), QObject::tr(
"Topology validation error",
"GEOS Error" ) );
239 translatedErrors.insert( QStringLiteral(
"repeated point" ), QObject::tr(
"Repeated point",
"GEOS Error" ) );
240 translatedErrors.insert( QStringLiteral(
"hole lies outside shell" ), QObject::tr(
"Hole lies outside shell",
"GEOS Error" ) );
241 translatedErrors.insert( QStringLiteral(
"holes are nested" ), QObject::tr(
"Holes are nested",
"GEOS Error" ) );
242 translatedErrors.insert( QStringLiteral(
"interior is disconnected" ), QObject::tr(
"Interior is disconnected",
"GEOS Error" ) );
243 translatedErrors.insert( QStringLiteral(
"self-intersection" ), QObject::tr(
"Self-intersection",
"GEOS Error" ) );
244 translatedErrors.insert( QStringLiteral(
"ring self-intersection" ), QObject::tr(
"Ring self-intersection",
"GEOS Error" ) );
245 translatedErrors.insert( QStringLiteral(
"nested shells" ), QObject::tr(
"Nested shells",
"GEOS Error" ) );
246 translatedErrors.insert( QStringLiteral(
"duplicate rings" ), QObject::tr(
"Duplicate rings",
"GEOS Error" ) );
247 translatedErrors.insert( QStringLiteral(
"too few points in geometry component" ), QObject::tr(
"Too few points in geometry component",
"GEOS Error" ) );
248 translatedErrors.insert( QStringLiteral(
"invalid coordinate" ), QObject::tr(
"Invalid coordinate",
"GEOS Error" ) );
249 translatedErrors.insert( QStringLiteral(
"ring is not closed" ), QObject::tr(
"Ring is not closed",
"GEOS Error" ) );
252 const QString errorMsg( r );
253 const QString translatedErrorMsg = translatedErrors.value( errorMsg.toLower(), errorMsg );
257 const GEOSCoordSequence *cs = GEOSGeom_getCoordSeq_r( handle, g1 );
260 if ( GEOSCoordSeq_getSize_r( handle, cs, &n ) && n == 1 )
263 GEOSCoordSeq_getX_r( handle, cs, 0, &x );
264 GEOSCoordSeq_getY_r( handle, cs, 0, &y );
270 GEOSGeom_destroy_r( handle, g1 );
278 GEOSFree_r( handle, r );
292 validatePolyline( 0, mGeometry.
asPolyline() );
297 for (
int i = 0; !mStop && i < mp.size(); i++ )
298 validatePolyline( i, mp[i] );
302 validatePolygon( 0, mGeometry.
asPolygon() );
307 for (
int i = 0; !mStop && i < mp.size(); i++ )
309 validatePolygon( i, mp[i] );
312 for (
int i = 0; !mStop && i < mp.size(); i++ )
314 if ( mp[i].isEmpty() )
321 for (
int j = i + 1; !mStop && j < mp.size(); j++ )
323 if ( mp[j].isEmpty() )
326 if ( ringInRing( mp[i][0], mp[j][0] ) )
331 else if ( ringInRing( mp[j][0], mp[i][0] ) )
338 checkRingIntersections( i, 0, mp[i][0], j, 0, mp[j][0] );
354 else if ( mErrorCount > 0 )
356 emit
validationFinished( QObject::tr(
"Geometry has %1 errors." ).arg( mErrorCount ) );
393 return ( v.
x() * ( q.
y() - p.
y() ) - v.
y() * ( q.
x() - p.
x() ) ) / v.
length();
398 double d = v.
y() * w.
x() - v.
x() * w.
y();
403 double dx = q.
x() - p.
x();
404 double dy = q.
y() - p.
y();
405 double k = ( dy * w.
x() - dx * w.
y() ) / d;
415 int j = ring.size() - 1;
417 for (
int i = 0; !mStop && i < ring.size(); i++ )
422 if ( ( ring[i].y() < p.
y() && ring[j].y() >= p.
y() ) ||
423 ( ring[j].y() < p.
y() && ring[i].y() >= p.
y() ) )
425 if ( ring[i].x() + ( p.
y() - ring[i].y() ) / ( ring[j].y() - ring[i].y() ) * ( ring[j].x() - ring[i].x() ) <= p.
x() )
437 for (
int i = 0; !mStop && i < inside.size(); i++ )
439 if ( !pointInRing( outside, inside[i] ) )
static void validateGeometry(const QgsGeometry &geometry, QVector< QgsGeometry::Error > &errors, QgsGeometry::ValidationMethod method=QgsGeometry::ValidatorQgisInternal)
Validate geometry and produce a list of geometry errors.
void validationFinished(const QString &summary)
Sent when the validation is finished.
Use GEOS validation methods.
void addError(const QgsGeometry::Error &)
QgsWkbTypes::Type wkbType() const
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
A class to represent a 2D point.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QVector< QgsPolylineXY > QgsPolygonXY
Polygon: first item of the list is outer ring, inner rings (if any) start from second item...
A geometry is the spatial representation of a feature.
QString toString(int precision=-1) const
Returns a string representation of the point (x, y) with a preset precision.
~QgsGeometryValidator() override
QMap< QString, QString > QgsStringMap
QVector< QgsPolygonXY > QgsMultiPolygonXY
A collection of QgsPolygons that share a common collection of attributes.
static GEOSContextHandle_t getGEOSHandler()
QVector< QgsPolylineXY > QgsMultiPolylineXY
A collection of QgsPolylines that share a common collection of attributes.
QgsMultiPolylineXY asMultiPolyline() const
Returns the contents of the geometry as a multi-linestring.
Type
The WKB type describes the number of dimensions a geometry has.
QgsPolygonXY asPolygon() const
Returns the contents of the geometry as a polygon.
std::unique_ptr< GEOSGeometry, GeosDeleter > unique_ptr
Scoped GEOS pointer.
Use internal QgsGeometryValidator method.
double length() const
Returns the length of the vector.
A class to represent a vector.
QgsGeometryValidator(const QgsGeometry &geometry, QVector< QgsGeometry::Error > *errors=nullptr, QgsGeometry::ValidationMethod method=QgsGeometry::ValidatorQgisInternal)
Constructor for QgsGeometryValidator.
QVector< QgsPointXY > QgsPolylineXY
Polyline as represented as a vector of two-dimensional points.
QgsVector perpVector() const
Returns the perpendicular vector to this vector (rotated 90 degrees counter-clockwise) ...
static geos::unique_ptr asGeos(const QgsGeometry &geometry, double precision=0)
Returns a geos geometry - caller takes ownership of the object (should be deleted with GEOSGeom_destr...
ValidationMethod
Available methods for validating geometries.
QgsPolylineXY asPolyline() const
Returns the contents of the geometry as a polyline.
double x() const
Returns the vector's x-component.
static Type flatType(Type type)
Returns the flat type for a WKB type.
QgsMultiPolygonXY asMultiPolygon() const
Returns the contents of the geometry as a multi-polygon.
double y() const
Returns the vector's y-component.
Defines a QGIS exception class.
void errorFound(const QgsGeometry::Error &error)
Sent when an error has been found during the validation process.