25 : mGeometry( geometry )
44 void QgsGeometryValidator::checkRingIntersections(
int partIndex0,
int ringIndex0,
const QgsLineString *ring0,
int partIndex1,
int ringIndex1,
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() &&
71 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" )
72 .arg( i ).arg( ringIndex0 ).arg( partIndex0 )
73 .arg( j ).arg( ringIndex1 ).arg( partIndex1 )
84 void QgsGeometryValidator::validatePolyline(
int i,
const QgsLineString *line,
bool ring )
93 QString msg = QObject::tr(
"ring %1 with less than four points" ).arg( i );
107 msg = QObject::tr(
"ring %1 not closed, Z mismatch: %2 vs %3" ).arg( i ).arg( startPoint.
z() ).arg( endPoint.
z() );
111 msg = QObject::tr(
"ring %1 not closed" ).arg( i );
121 QString msg = QObject::tr(
"line %1 with less than two points" ).arg( i );
128 std::unique_ptr< QgsLineString > noDupes;
133 if ( !duplicateNodes.empty() )
135 noDupes.reset( line->
clone() );
136 for (
int j = duplicateNodes.size() - 1; j >= 0; j-- )
138 const QgsVertexId duplicateVertex = duplicateNodes.at( j );
139 const QgsPointXY duplicationLocation = noDupes->vertexAt( duplicateVertex );
140 noDupes->deleteVertex( duplicateVertex );
144 for (
int k = j - 1; k >= 0; k-- )
146 const QgsVertexId prevDupe = duplicateNodes.at( k );
161 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 );
166 line = noDupes.get();
169 for (
int j = 0; !mStop && j < line->
numPoints() - 3; j++ )
171 const double xAtJ = line->
xAt( j );
172 const double yAtJ = line->
yAt( j );
174 double vl = v.length();
178 for (
int k = j + 2; !mStop && k < n; k++ )
180 const double xAtK = line->
xAt( k );
181 const double yAtK = line->
yAt( k );
187 if ( !intersectLines( xAtJ, yAtJ, v, xAtK, yAtK, w, sX, sY ) )
193 d = -distLine2Point( xAtJ, yAtJ, v.perpVector(), sX, sY );
201 if ( d < 0 || d > vl )
206 d = -distLine2Point( xAtK, yAtK, w.perpVector(), sX, sY );
215 if ( d <= 0 || d >= w.length() )
218 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 );
226 void QgsGeometryValidator::validatePolygon(
int partIndex,
const QgsPolygon *polygon )
233 QString msg = QObject::tr(
"ring %1 of polygon %2 not in exterior ring" ).arg( i + 1 ).arg( partIndex );
245 checkRingIntersections( partIndex, i + 1, qgsgeometry_cast< QgsLineString * >( polygon->
interiorRing( i ) ),
246 partIndex, j + 1, qgsgeometry_cast< QgsLineString * >( polygon->
interiorRing( j ) ) );
251 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( polygon->
exteriorRing() ),
true );
254 validatePolyline( i + 1, qgsgeometry_cast< const QgsLineString * >( polygon->
interiorRing( i ) ),
true );
279 if ( !
geos.isValid( &error,
true, &errorLoc ) )
306 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( mGeometry.
constGet() ) );
312 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
313 validatePolyline( i, qgsgeometry_cast< const QgsLineString * >( collection->
geometryN( i ) ) );
318 validatePolygon( 0, qgsgeometry_cast< const QgsPolygon * >( mGeometry.
constGet() ) );
324 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
325 validatePolygon( i, qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( i ) ) );
327 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
329 const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( i ) );
337 for (
int j = i + 1; !mStop && j < collection->
numGeometries(); j++ )
339 const QgsPolygon *poly2 = qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( j ) );
343 if ( ringInRing( qgsgeometry_cast< const QgsLineString * >( poly->
exteriorRing() ),
344 qgsgeometry_cast< const QgsLineString * >( poly2->
exteriorRing() ) ) )
357 checkRingIntersections( i, 0, qgsgeometry_cast< const QgsLineString * >( poly->
exteriorRing() ),
358 j, 0, qgsgeometry_cast< const QgsLineString * >( poly2->
exteriorRing() ) );
380 else if ( mErrorCount > 0 )
382 emit
validationFinished( QObject::tr(
"Geometry has %1 errors." ).arg( mErrorCount ) );
412 double QgsGeometryValidator::distLine2Point(
double px,
double py,
QgsVector v,
double qX,
double qY )
414 const double l = v.
length();
420 return ( v.
x() * ( qY - py ) - v.
y() * ( qX - px ) ) / l;
423 bool QgsGeometryValidator::intersectLines(
double px,
double py,
QgsVector v,
double qx,
double qy,
QgsVector w,
double &sX,
double &sY )
425 double d = v.
y() * w.
x() - v.
x() * w.
y();
432 double k = ( dy * w.
x() - dx * w.
y() ) / d;
440 bool QgsGeometryValidator::pointInRing(
const QgsLineString *ring,
double pX,
double pY )
448 for (
int i = 0; !mStop && i < ring->
numPoints(); i++ )
450 const double xAti = ring->
xAt( i );
451 const double yAti = ring->
yAt( i );
452 const double xAtj = ring->
xAt( j );
453 const double yAtj = ring->
yAt( j );
458 if ( ( yAti < pY && yAtj >= pY ) ||
459 ( yAtj < pY && yAti >= pY ) )
461 if ( xAti + ( pY - yAti ) / ( yAtj - yAti ) * ( xAtj - xAti ) <= pX )
476 for (
int i = 0; !mStop && i < inside->
numPoints(); i++ )
478 if ( !pointInRing( outside, inside->
xAt( i ), inside->
yAt( i ) ) )
bool is3D() const SIP_HOLDGIL
Returns true if the geometry is 3D and contains a z-value.
virtual bool isEmpty() const
Returns true if the geometry is empty.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns the WKB type of the geometry.
const QgsCurve * interiorRing(int i) const SIP_HOLDGIL
Retrieves an interior ring from the curve polygon.
const QgsCurve * exteriorRing() const SIP_HOLDGIL
Returns the curve polygon's exterior ring.
int numInteriorRings() const SIP_HOLDGIL
Returns the number of interior rings contained with the curve polygon.
QgsRectangle boundingBox() const override
Returns the minimal bounding box for the geometry.
Defines a QGIS exception class.
int numGeometries() const SIP_HOLDGIL
Returns the number of geometries within the collection.
const QgsAbstractGeometry * geometryN(int n) const
Returns a const reference to a geometry from within the collection.
void validationFinished(const QString &summary)
Sent when the validation is finished.
void errorFound(const QgsGeometry::Error &error)
Sent when an error has been found during the validation process.
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 addError(const QgsGeometry::Error &)
~QgsGeometryValidator() override
QgsGeometryValidator(const QgsGeometry &geometry, QVector< QgsGeometry::Error > *errors=nullptr, QgsGeometry::ValidationMethod method=QgsGeometry::ValidatorQgisInternal)
Constructor for QgsGeometryValidator.
A geometry is the spatial representation of a feature.
const QgsAbstractGeometry * constGet() const SIP_HOLDGIL
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
QgsWkbTypes::Type wkbType() const SIP_HOLDGIL
Returns type of the geometry as a WKB type (point / linestring / polygon etc.)
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
ValidationMethod
Available methods for validating geometries.
@ ValidatorQgisInternal
Use internal QgsGeometryValidator method.
@ ValidatorGeos
Use GEOS validation methods.
Does vector analysis using the geos library and handles import, export, exception handling*.
Line string geometry type, with support for z-dimension and m-values.
QgsPoint startPoint() const override SIP_HOLDGIL
Returns the starting point of the curve.
bool isClosed() const override SIP_HOLDGIL
Returns true if the curve is closed.
QgsPoint endPoint() const override SIP_HOLDGIL
Returns the end point of the curve.
int numPoints() const override SIP_HOLDGIL
Returns the number of points in the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the line string.
bool isClosed2D() const override SIP_HOLDGIL
Returns true if the curve is closed.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
QVector< QgsVertexId > collectDuplicateNodes(double epsilon=4 *std::numeric_limits< double >::epsilon(), bool useZValues=false) const
Returns a list of any duplicate nodes contained in the geometry, within the specified tolerance.
QgsLineString * clone() const override
Clones the geometry by performing a deep copy.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
A class to represent a 2D point.
Point geometry type, with support for z-dimension and m-values.
QgsPoint vertexAt(QgsVertexId) const override
Returns the point corresponding to a specified vertex id.
bool deleteVertex(QgsVertexId position) override
Deletes a vertex within the geometry.
bool contains(const QgsRectangle &rect) const SIP_HOLDGIL
Returns true when rectangle contains other rectangle.
A class to represent a vector.
double y() const SIP_HOLDGIL
Returns the vector's y-component.
double x() const SIP_HOLDGIL
Returns the vector's x-component.
double length() const SIP_HOLDGIL
Returns the length of the vector.
static GeometryType geometryType(Type type) SIP_HOLDGIL
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Type flatType(Type type) SIP_HOLDGIL
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
#define QgsDebugMsgLevel(str, level)
Utility class for identifying a unique vertex within a geometry.