31using namespace Qt::StringLiterals;
37#include "moc_qgsgeometryvalidator.cpp"
40 : mGeometry( geometry )
56void QgsGeometryValidator::checkRingIntersections(
int partIndex0,
int ringIndex0,
const QgsCurve *ring0,
int partIndex1,
int ringIndex1,
const QgsCurve *ring1 )
59 std::unique_ptr< QgsLineString > segmentisedRing0;
63 ringLine0 = segmentisedRing0.get();
67 std::unique_ptr< QgsLineString > segmentisedRing1;
71 ringLine1 = segmentisedRing1.get();
74 Q_ASSERT( ringLine0 );
75 Q_ASSERT( ringLine1 );
77 for (
int i = 0; !mStop && i < ringLine0->
numPoints() - 1; i++ )
79 const double ring0XAti = ringLine0->
xAt( i );
80 const double ring0YAti = ringLine0->
yAt( i );
81 const QgsVector v( ringLine0->
xAt( i + 1 ) - ring0XAti, ringLine0->
yAt( i + 1 ) - ring0YAti );
83 for (
int j = 0; !mStop && j < ringLine1->
numPoints() - 1; j++ )
85 const double ring1XAtj = ringLine1->
xAt( j );
86 const double ring1YAtj = ringLine1->
yAt( j );
87 const QgsVector w( ringLine1->
xAt( j + 1 ) - ring1XAtj, ringLine1->
yAt( j + 1 ) - ring1YAtj );
91 if ( intersectLines( ring0XAti, ring0YAti, v, ring1XAtj, ring1YAtj, w, sX, sY ) )
93 double d = -distLine2Point( ring0XAti, ring0YAti, v.perpVector(), sX, sY );
95 if ( d >= 0 && d <= v.length() )
97 d = -distLine2Point( ring1XAtj, ring1YAtj, w.perpVector(), sX, sY );
100 && ringLine0->
pointN( i + 1 ) != ringLine1->
pointN( j + 1 )
102 && ringLine0->
pointN( i + 0 ) != ringLine1->
pointN( j + 1 )
103 && ringLine0->
pointN( i + 0 ) != ringLine1->
pointN( j ) )
105 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" )
114 emit
errorFound( QgsGeometry::Error( msg, QgsPointXY( sX, sY ) ) );
123void QgsGeometryValidator::validatePolyline(
int i,
const QgsLineString *line,
bool ring )
132 const QString msg = QObject::tr(
"ring %1 with less than four points" ).arg( i );
141 const QgsPoint startPoint = line->
startPoint();
142 const QgsPoint endPoint = line->
endPoint();
146 msg = QObject::tr(
"ring %1 not closed, Z mismatch: %2 vs %3" ).arg( i ).arg( startPoint.
z() ).arg( endPoint.
z() );
150 msg = QObject::tr(
"ring %1 not closed" ).arg( i );
153 emit
errorFound( QgsGeometry::Error( msg, QgsPointXY( startPoint.
x(), startPoint.
y() ) ) );
160 const QString msg = QObject::tr(
"line %1 with less than two points" ).arg( i );
167 std::unique_ptr< QgsLineString > noDupes;
172 if ( !duplicateNodes.empty() )
174 noDupes.reset( line->
clone() );
175 for (
int j = duplicateNodes.size() - 1; j >= 0; j-- )
177 const QgsVertexId duplicateVertex = duplicateNodes.at( j );
178 const QgsPointXY duplicationLocation = noDupes->vertexAt( duplicateVertex );
179 noDupes->deleteVertex( duplicateVertex );
183 for (
int k = j - 1; k >= 0; k-- )
185 const QgsVertexId prevDupe = duplicateNodes.at( k );
186 const QgsPoint prevPoint = noDupes->vertexAt( prevDupe );
189 noDupes->deleteVertex( prevDupe );
200 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 );
202 emit
errorFound( QgsGeometry::Error( msg, duplicationLocation ) );
205 line = noDupes.get();
209 for (
int j = 0; !mStop && j < line->
numPoints() - 3; j++ )
212 for (
int k = j + 2; !mStop && k < n; k++ )
214 double intersectionPointX = std::numeric_limits<double>::quiet_NaN();
215 double intersectionPointY = std::numeric_limits<double>::quiet_NaN();
216 bool isIntersection =
false;
217 if ( QgsGeometryUtilsBase::
218 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 ) )
220 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 );
222 emit
errorFound( QgsGeometry::Error( msg, QgsPointXY( intersectionPointX, intersectionPointY ) ) );
229void QgsGeometryValidator::validatePolygon(
int partIndex,
const QgsCurvePolygon *polygon )
236 const QString msg = QObject::tr(
"ring %1 of polygon %2 not in exterior ring" ).arg( i + 1 ).arg( partIndex );
238 const QgsCurve *interiorRing = polygon->
interiorRing( i );
254 checkRingIntersections( partIndex, i + 1, polygon->
interiorRing( i ), partIndex, j + 1, polygon->
interiorRing( j ) );
269 if ( mGeometry.isNull() )
287 if ( !
geos.isValid( &error,
true, &errorLoc ) )
320 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
340 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
343 for (
int i = 0; !mStop && i < collection->
numGeometries(); i++ )
353 for (
int j = i + 1; !mStop && j < collection->
numGeometries(); j++ )
393 else if ( mErrorCount > 0 )
395 emit
validationFinished( QObject::tr(
"Geometry has %n error(s).",
nullptr, mErrorCount ) );
415 const QgsSfcgalGeometry sfcgalGeom( mGeometry.constGet() );
416 if ( !QgsSfcgalEngine::isValid( sfcgalGeom.sfcgalGeometry().get(),
nullptr, &errorMsg, &errorLoc ) )
431 QgsDebugError( u
"Cannot use SFCGAL validation method in this QGIS build."_s );
458double QgsGeometryValidator::distLine2Point(
double px,
double py,
QgsVector v,
double qX,
double qY )
460 const double l = v.
length();
466 return ( v.
x() * ( qY - py ) - v.
y() * ( qX - px ) ) / l;
469bool QgsGeometryValidator::intersectLines(
double px,
double py,
QgsVector v,
double qx,
double qy,
QgsVector w,
double &sX,
double &sY )
471 const double d = v.
y() * w.
x() - v.
x() * w.
y();
476 const double dx = qx - px;
477 const double dy = qy - py;
478 const double k = ( dy * w.
x() - dx * w.
y() ) / d;
486bool QgsGeometryValidator::pointInRing(
const QgsCurve *ring,
double pX,
double pY )
494 for (
int i = 0; !mStop && i < ring->
numPoints(); i++ )
496 const double xAti = ring->
xAt( i );
497 const double yAti = ring->
yAt( i );
498 const double xAtj = ring->
xAt( j );
499 const double yAtj = ring->
yAt( j );
504 if ( ( yAti < pY && yAtj >= pY ) || ( yAtj < pY && yAti >= pY ) )
506 if ( xAti + ( pY - yAti ) / ( yAtj - yAti ) * ( xAtj - xAti ) <= pX )
516bool QgsGeometryValidator::ringInRing(
const QgsCurve *inside,
const QgsCurve *outside )
521 for (
int i = 0; !mStop && i < inside->
numPoints(); i++ )
523 if ( !pointInRing( outside, inside->
xAt( i ), inside->
yAt( i ) ) )
GeometryValidationEngine
Available engines for validating geometries.
@ QgisInternal
Use internal QgsGeometryValidator method.
@ Sfcgal
Use SFCGAL validation methods. Only available for QGIS builds with SFCGAL support enabled.
@ 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
static Qgis::GeometryValidationEngine defaultValidationEngine()
Returns the geometry validation engine configured in the application settings.
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.
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.
bool contains(const QgsRectangle &rect) const
Returns true when rectangle contains other rectangle.
static const QgsSettingsEntryInteger * settingsDigitizingValidateGeometries
Settings entry digitizing validate geometries.
double yAt(int index) const override
Returns the y-coordinate of the specified node in the line string.
int numPoints() const override
Returns the number of points in the curve.
double xAt(int index) const override
Returns the x-coordinate of the specified node in the line string.
QgsPoint startPoint() const override
Returns the starting point of the curve.
QgsPoint endPoint() const override
Returns the end point of the curve.
QgsPoint pointN(int i) const
Returns the specified point from inside the simple curve.
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)
#define QgsDebugError(str)