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 );
102 QString msg = QObject::tr(
"ring %1 not closed" ).arg( i );
111 QString msg = QObject::tr(
"line %1 with less than two points" ).arg( i );
118 std::unique_ptr< QgsLineString > noDupes;
123 if ( !duplicateNodes.empty() )
125 noDupes.reset( line->
clone() );
126 for (
int j = duplicateNodes.size() - 1; j >= 0; j-- )
128 const QgsVertexId duplicateVertex = duplicateNodes.at( j );
129 const QgsPointXY duplicationLocation = noDupes->vertexAt( duplicateVertex );
130 noDupes->deleteVertex( duplicateVertex );
134 for (
int k = j - 1; k >= 0; k-- )
136 const QgsVertexId prevDupe = duplicateNodes.at( k );
151 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 );
156 line = noDupes.get();
159 for (
int j = 0; !mStop && j < line->
numPoints() - 3; j++ )
161 const double xAtJ = line->
xAt( j );
162 const double yAtJ = line->
yAt( j );
164 double vl = v.length();
168 for (
int k = j + 2; !mStop && k < n; k++ )
170 const double xAtK = line->
xAt( k );
171 const double yAtK = line->
yAt( k );
177 if ( !intersectLines( xAtJ, yAtJ, v, xAtK, yAtK, w, sX, sY ) )
183 d = -distLine2Point( xAtJ, yAtJ, v.perpVector(), sX, sY );
191 if ( d < 0 || d > vl )
196 d = -distLine2Point( xAtK, yAtK, w.perpVector(), sX, sY );
205 if ( d <= 0 || d >= w.length() )
208 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 );
216 void QgsGeometryValidator::validatePolygon(
int partIndex,
const QgsPolygon *polygon )
223 QString msg = QObject::tr(
"ring %1 of polygon %2 not in exterior ring" ).arg( i + 1 ).arg( partIndex );
235 checkRingIntersections( partIndex, i + 1, qgsgeometry_cast< QgsLineString * >( polygon->
interiorRing( i ) ),
236 partIndex, j + 1, qgsgeometry_cast< QgsLineString * >( polygon->
interiorRing( j ) ) );
241 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( polygon->
exteriorRing() ),
true );
244 validatePolyline( i + 1, qgsgeometry_cast< const QgsLineString * >( polygon->
interiorRing( i ) ),
true );
269 if ( !
geos.isValid( &error,
true, &errorLoc ) )
296 validatePolyline( 0, qgsgeometry_cast< const QgsLineString * >( mGeometry.
constGet() ) );
302 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
303 validatePolyline( i, qgsgeometry_cast< const QgsLineString * >( collection->
geometryN( i ) ) );
308 validatePolygon( 0, qgsgeometry_cast< const QgsPolygon * >( mGeometry.
constGet() ) );
314 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
315 validatePolygon( i, qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( i ) ) );
317 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
319 const QgsPolygon *poly = qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( i ) );
327 for (
int j = i + 1; !mStop && j < collection->
numGeometries(); j++ )
329 const QgsPolygon *poly2 = qgsgeometry_cast< const QgsPolygon * >( collection->
geometryN( j ) );
333 if ( ringInRing( qgsgeometry_cast< const QgsLineString * >( poly->
exteriorRing() ),
334 qgsgeometry_cast< const QgsLineString * >( poly2->
exteriorRing() ) ) )
347 checkRingIntersections( i, 0, qgsgeometry_cast< const QgsLineString * >( poly->
exteriorRing() ),
348 j, 0, qgsgeometry_cast< const QgsLineString * >( poly2->
exteriorRing() ) );
370 else if ( mErrorCount > 0 )
372 emit
validationFinished( QObject::tr(
"Geometry has %1 errors." ).arg( mErrorCount ) );
402 double QgsGeometryValidator::distLine2Point(
double px,
double py,
QgsVector v,
double qX,
double qY )
404 const double l = v.
length();
410 return ( v.
x() * ( qY - py ) - v.
y() * ( qX - px ) ) / l;
413 bool QgsGeometryValidator::intersectLines(
double px,
double py,
QgsVector v,
double qx,
double qy,
QgsVector w,
double &sX,
double &sY )
415 double d = v.
y() * w.
x() - v.
x() * w.
y();
422 double k = ( dy * w.
x() - dx * w.
y() ) / d;
430 bool QgsGeometryValidator::pointInRing(
const QgsLineString *ring,
double pX,
double pY )
438 for (
int i = 0; !mStop && i < ring->
numPoints(); i++ )
440 const double xAti = ring->
xAt( i );
441 const double yAti = ring->
yAt( i );
442 const double xAtj = ring->
xAt( j );
443 const double yAtj = ring->
yAt( j );
448 if ( ( yAti < pY && yAtj >= pY ) ||
449 ( yAtj < pY && yAti >= pY ) )
451 if ( xAti + ( pY - yAti ) / ( yAtj - yAti ) * ( xAtj - xAti ) <= pX )
466 for (
int i = 0; !mStop && i < inside->
numPoints(); i++ )
468 if ( !pointInRing( outside, inside->
xAt( i ), inside->
yAt( i ) ) )
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.
virtual bool isClosed() const SIP_HOLDGIL
Returns true if the curve is closed.
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.
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.
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
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.