27#include "moc_qgsgeometryvalidator.cpp"
30 : mGeometry( geometry )
46void QgsGeometryValidator::checkRingIntersections(
int partIndex0,
int ringIndex0,
const QgsCurve *ring0,
int partIndex1,
int ringIndex1,
const QgsCurve *ring1 )
49 std::unique_ptr< QgsLineString > segmentisedRing0;
53 ringLine0 = segmentisedRing0.get();
57 std::unique_ptr< QgsLineString > segmentisedRing1;
61 ringLine1 = segmentisedRing1.get();
64 Q_ASSERT( ringLine0 );
65 Q_ASSERT( ringLine1 );
67 for (
int i = 0; !mStop && i < ringLine0->
numPoints() - 1; i++ )
69 const double ring0XAti = ringLine0->
xAt( i );
70 const double ring0YAti = ringLine0->
yAt( i );
71 const QgsVector v( ringLine0->
xAt( i + 1 ) - ring0XAti, ringLine0->
yAt( i + 1 ) - ring0YAti );
73 for (
int j = 0; !mStop && j < ringLine1->
numPoints() - 1; j++ )
75 const double ring1XAtj = ringLine1->
xAt( j );
76 const double ring1YAtj = ringLine1->
yAt( j );
77 const QgsVector w( ringLine1->
xAt( j + 1 ) - ring1XAtj, ringLine1->
yAt( j + 1 ) - ring1YAtj );
81 if ( intersectLines( ring0XAti, ring0YAti, v, ring1XAtj, ring1YAtj, w, sX, sY ) )
83 double d = -distLine2Point( ring0XAti, ring0YAti, v.perpVector(), sX, sY );
85 if ( d >= 0 && d <= v.length() )
87 d = -distLine2Point( ring1XAtj, ring1YAtj, w.perpVector(), sX, sY );
90 && ringLine0->
pointN( i + 1 ) != ringLine1->
pointN( j + 1 )
92 && ringLine0->
pointN( i + 0 ) != ringLine1->
pointN( j + 1 )
93 && ringLine0->
pointN( i + 0 ) != ringLine1->
pointN( j ) )
95 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" )
104 emit
errorFound( QgsGeometry::Error( msg, QgsPointXY( sX, sY ) ) );
113void QgsGeometryValidator::validatePolyline(
int i,
const QgsLineString *line,
bool ring )
122 const QString msg = QObject::tr(
"ring %1 with less than four points" ).arg( i );
131 const QgsPoint startPoint = line->
startPoint();
132 const QgsPoint endPoint = line->
endPoint();
136 msg = QObject::tr(
"ring %1 not closed, Z mismatch: %2 vs %3" ).arg( i ).arg( startPoint.
z() ).arg( endPoint.
z() );
140 msg = QObject::tr(
"ring %1 not closed" ).arg( i );
143 emit
errorFound( QgsGeometry::Error( msg, QgsPointXY( startPoint.
x(), startPoint.
y() ) ) );
150 const QString msg = QObject::tr(
"line %1 with less than two points" ).arg( i );
157 std::unique_ptr< QgsLineString > noDupes;
162 if ( !duplicateNodes.empty() )
164 noDupes.reset( line->
clone() );
165 for (
int j = duplicateNodes.size() - 1; j >= 0; j-- )
167 const QgsVertexId duplicateVertex = duplicateNodes.at( j );
168 const QgsPointXY duplicationLocation = noDupes->vertexAt( duplicateVertex );
169 noDupes->deleteVertex( duplicateVertex );
173 for (
int k = j - 1; k >= 0; k-- )
175 const QgsVertexId prevDupe = duplicateNodes.at( k );
176 const QgsPoint prevPoint = noDupes->vertexAt( prevDupe );
179 noDupes->deleteVertex( prevDupe );
190 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 );
192 emit
errorFound( QgsGeometry::Error( msg, duplicationLocation ) );
195 line = noDupes.get();
199 for (
int j = 0; !mStop && j < line->
numPoints() - 3; j++ )
202 for (
int k = j + 2; !mStop && k < n; k++ )
204 double intersectionPointX = std::numeric_limits<double>::quiet_NaN();
205 double intersectionPointY = std::numeric_limits<double>::quiet_NaN();
206 bool isIntersection =
false;
207 if ( QgsGeometryUtilsBase::
208 segmentIntersection( line->
xAt( j ), line->
yAt( j ), line->
xAt( j + 1 ), line->
yAt( j + 1 ), line->
xAt( k ), line->
yAt( k ), line->
xAt( k + 1 ), line->
yAt( k + 1 ), intersectionPointX, intersectionPointY, isIntersection ) )
210 const QString msg = QObject::tr(
"segments %1 and %2 of line %3 intersect at %4, %5" ).arg( j ).arg( k ).arg( i ).arg( intersectionPointX ).arg( intersectionPointY );
212 emit
errorFound( QgsGeometry::Error( msg, QgsPointXY( intersectionPointX, intersectionPointY ) ) );
219void QgsGeometryValidator::validatePolygon(
int partIndex,
const QgsCurvePolygon *polygon )
226 const QString msg = QObject::tr(
"ring %1 of polygon %2 not in exterior ring" ).arg( i + 1 ).arg( partIndex );
228 const QgsCurve *interiorRing = polygon->
interiorRing( i );
244 checkRingIntersections( partIndex, i + 1, polygon->
interiorRing( i ), partIndex, j + 1, polygon->
interiorRing( j ) );
259 if ( mGeometry.isNull() )
277 if ( !
geos.isValid( &error,
true, &errorLoc ) )
310 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
330 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
333 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
343 for (
int j = i + 1; !mStop && j < collection->
numGeometries(); j++ )
383 else if ( mErrorCount > 0 )
385 emit
validationFinished( QObject::tr(
"Geometry has %n error(s).",
nullptr, mErrorCount ) );
415double QgsGeometryValidator::distLine2Point(
double px,
double py,
QgsVector v,
double qX,
double qY )
417 const double l = v.
length();
423 return ( v.
x() * ( qY - py ) - v.
y() * ( qX - px ) ) / l;
426bool QgsGeometryValidator::intersectLines(
double px,
double py,
QgsVector v,
double qx,
double qy,
QgsVector w,
double &sX,
double &sY )
428 const double d = v.
y() * w.
x() - v.
x() * w.
y();
433 const double dx = qx - px;
434 const double dy = qy - py;
435 const double k = ( dy * w.
x() - dx * w.
y() ) / d;
443bool QgsGeometryValidator::pointInRing(
const QgsCurve *ring,
double pX,
double pY )
451 for (
int i = 0; !mStop && i < ring->
numPoints(); i++ )
453 const double xAti = ring->
xAt( i );
454 const double yAti = ring->
yAt( i );
455 const double xAtj = ring->
xAt( j );
456 const double yAtj = ring->
yAt( j );
461 if ( ( yAti < pY && yAtj >= pY ) || ( yAtj < pY && yAti >= pY ) )
463 if ( xAti + ( pY - yAti ) / ( yAtj - yAti ) * ( xAtj - xAti ) <= pX )
473bool QgsGeometryValidator::ringInRing(
const QgsCurve *inside,
const QgsCurve *outside )
478 for (
int i = 0; !mStop && i < inside->
numPoints(); i++ )
480 if ( !pointInRing( outside, inside->
xAt( i ), inside->
yAt( i ) ) )
GeometryValidationEngine
Available engines for validating geometries.
@ QgisInternal
Use internal QgsGeometryValidator method.
@ Geos
Use GEOS validation methods.
QFlags< GeosCreationFlag > GeosCreationFlags
Geos geometry creation behavior flags.
@ MultiPolygon
MultiPolygon.
@ MultiLineString
MultiLineString.
@ CurvePolygon
CurvePolygon.
@ MultiSurface
MultiSurface.
virtual QgsRectangle boundingBox() const
Returns the minimal bounding box for the geometry.
bool is3D() const
Returns true if the geometry is 3D and contains a z-value.
virtual bool isEmpty() const
Returns true if the geometry is empty.
Curve polygon geometry type.
int numInteriorRings() const
Returns the number of interior rings contained with the curve polygon.
const QgsCurve * exteriorRing() const
Returns the curve polygon's exterior ring.
const QgsCurve * interiorRing(int i) const
Retrieves an interior ring from the curve polygon.
Abstract base class for curved geometry type.
virtual int numPoints() const =0
Returns the number of points in the curve.
QgsCurve * segmentize(double tolerance=M_PI_2/90, SegmentationToleranceType toleranceType=MaximumAngle) const override
Returns a geometry without curves.
virtual double xAt(int index) const =0
Returns the x-coordinate of the specified node in the line string.
virtual QgsPoint startPoint() const =0
Returns the starting point of the curve.
virtual double yAt(int index) const =0
Returns the y-coordinate of the specified node in the line string.
Defines a QGIS exception class.
int numGeometries() const
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.
QgsGeometryValidator(const QgsGeometry &geometry, QVector< QgsGeometry::Error > *errors=nullptr, Qgis::GeometryValidationEngine method=Qgis::GeometryValidationEngine::QgisInternal)
Constructor for QgsGeometryValidator.
static void validateGeometry(const QgsGeometry &geometry, QVector< QgsGeometry::Error > &errors, Qgis::GeometryValidationEngine method=Qgis::GeometryValidationEngine::QgisInternal)
Validate geometry and produce a list of geometry errors.
void addError(const QgsGeometry::Error &)
~QgsGeometryValidator() override
A geometry is the spatial representation of a feature.
QgsPointXY asPoint() const
Returns the contents of the geometry as a 2-dimensional point.
Does vector analysis using the GEOS library and handles import, export, and exception handling.
Line string geometry type, with support for z-dimension and m-values.
bool isClosed() const override
Returns true if the curve is closed.
QgsPoint startPoint() const override
Returns the starting point of the curve.
int numPoints() const override
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.
QgsPoint endPoint() const override
Returns the end point of the curve.
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.
bool isClosed2D() const override
Returns true if the curve is closed.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
Represent a 2-dimensional vector.
double y() const
Returns the vector's y-component.
double x() const
Returns the vector's x-component.
double length() const
Returns the length of the vector.
static Qgis::GeometryType geometryType(Qgis::WkbType type)
Returns the geometry type for a WKB type, e.g., both MultiPolygon and CurvePolygon would have a Polyg...
static Qgis::WkbType flatType(Qgis::WkbType type)
Returns the flat type for a WKB type.
Contains geos related utilities and functions.
QString qgsEnumValueToKey(const T &value, bool *returnOk=nullptr)
Returns the value for the given key of an enum.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference).
T qgsgeometry_cast(QgsAbstractGeometry *geom)
#define QgsDebugMsgLevel(str, level)