mirror of
https://github.com/qgis/QGIS.git
synced 2025-03-23 00:05:43 -04:00
[Geometry checker] Add line intersection check
This commit is contained in:
parent
b5208c04df
commit
3842f42a6e
@ -15,6 +15,7 @@ SET (geometrychecker_SRCS
|
||||
checks/qgsgeometrycheck.cpp
|
||||
checks/qgsgeometrygapcheck.cpp
|
||||
checks/qgsgeometryholecheck.cpp
|
||||
checks/qgsgeometrylineintersectioncheck.cpp
|
||||
checks/qgsgeometrymultipartcheck.cpp
|
||||
checks/qgsgeometrycontainedcheck.cpp
|
||||
checks/qgsgeometryoverlapcheck.cpp
|
||||
@ -53,6 +54,7 @@ SET (geometrychecker_MOC_HDRS
|
||||
checks/qgsgeometryduplicatenodescheck.h
|
||||
checks/qgsgeometrygapcheck.h
|
||||
checks/qgsgeometryholecheck.h
|
||||
checks/qgsgeometrylineintersectioncheck.h
|
||||
checks/qgsgeometrymultipartcheck.h
|
||||
checks/qgsgeometrycontainedcheck.h
|
||||
checks/qgsgeometryoverlapcheck.h
|
||||
|
@ -0,0 +1,79 @@
|
||||
/***************************************************************************
|
||||
qgsgeometrylineintersectioncheck.cpp
|
||||
---------------------
|
||||
begin : June 2017
|
||||
copyright : (C) 2017 by Sandro Mani / Sourcepole AG
|
||||
email : smani at sourcepole dot ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsgeometrylineintersectioncheck.h"
|
||||
#include "qgslinestring.h"
|
||||
|
||||
void QgsGeometryLineIntersectionCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QMap<QString, QgsFeatureIds> &ids ) const
|
||||
{
|
||||
QMap<QString, QgsFeatureIds> featureIds = ids.isEmpty() ? allLayerFeatureIds() : ids;
|
||||
QgsGeometryCheckerUtils::LayerFeatures layerFeatures( mContext->featurePools, featureIds, mCompatibleGeometryTypes, progressCounter, true );
|
||||
for ( const QgsGeometryCheckerUtils::LayerFeature &layerFeature : layerFeatures )
|
||||
{
|
||||
const QgsAbstractGeometry *geom = layerFeature.geometry();
|
||||
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
|
||||
{
|
||||
const QgsLineString *line = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( geom, iPart ) );
|
||||
if ( !line )
|
||||
{
|
||||
// Should not happen
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether the line intersects with any other lines
|
||||
QgsGeometryCheckerUtils::LayerFeatures checkFeatures( mContext->featurePools, featureIds.keys(), line->boundingBox(), {QgsWkbTypes::LineGeometry} );
|
||||
for ( const QgsGeometryCheckerUtils::LayerFeature &checkFeature : checkFeatures )
|
||||
{
|
||||
if ( checkFeature.feature().id() == layerFeature.feature().id() )
|
||||
{
|
||||
// Skip current feature
|
||||
continue;
|
||||
}
|
||||
const QgsAbstractGeometry *testGeom = checkFeature.geometry();
|
||||
for ( int jPart = 0, mParts = testGeom->partCount(); jPart < mParts; ++jPart )
|
||||
{
|
||||
const QgsLineString *testLine = dynamic_cast<const QgsLineString *>( QgsGeometryCheckerUtils::getGeomPart( testGeom, jPart ) );
|
||||
if ( !testLine )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QgsPoint inter;
|
||||
if ( QgsGeometryCheckerUtils::linesIntersect( line, testLine, mContext->tolerance, inter ) )
|
||||
{
|
||||
errors.append( new QgsGeometryCheckError( this, layerFeature, inter ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGeometryLineIntersectionCheck::fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> & /*mergeAttributeIndices*/, Changes & /*changes*/ ) const
|
||||
{
|
||||
if ( method == NoChange )
|
||||
{
|
||||
error->setFixed( method );
|
||||
}
|
||||
else
|
||||
{
|
||||
error->setFixFailed( tr( "Unknown method" ) );
|
||||
}
|
||||
}
|
||||
|
||||
QStringList QgsGeometryLineIntersectionCheck::getResolutionMethods() const
|
||||
{
|
||||
static QStringList methods = QStringList() << tr( "No action" );
|
||||
return methods;
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/***************************************************************************
|
||||
qgsgeometrylineintersectioncheck.h
|
||||
---------------------
|
||||
begin : June 2017
|
||||
copyright : (C) 2017 by Sandro Mani / Sourcepole AG
|
||||
email : smani at sourcepole dot ch
|
||||
***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSGEOMETRYLINEINTERSECTIONCHECK_H
|
||||
#define QGSGEOMETRYLINEINTERSECTIONCHECK_H
|
||||
|
||||
#include "qgsgeometrycheck.h"
|
||||
|
||||
class QgsGeometryLineIntersectionCheck : public QgsGeometryCheck
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsGeometryLineIntersectionCheck( QgsGeometryCheckerContext *context )
|
||||
: QgsGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry}, context )
|
||||
{}
|
||||
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = nullptr, const QMap<QString, QgsFeatureIds> &ids = QMap<QString, QgsFeatureIds>() ) const override;
|
||||
void fixError( QgsGeometryCheckError *error, int method, const QMap<QString, int> &mergeAttributeIndices, Changes &changes ) const override;
|
||||
QStringList getResolutionMethods() const override;
|
||||
QString errorDescription() const override { return tr( "Intersection" ); }
|
||||
QString errorName() const override { return QStringLiteral( "QgsGeometryLineIntersectionCheck" ); }
|
||||
private:
|
||||
enum ResolutionMethod { NoChange };
|
||||
};
|
||||
|
||||
#endif // QGSGEOMETRYLINEINTERSECTIONCHECK_H
|
@ -25,6 +25,7 @@
|
||||
#include "checks/qgsgeometryduplicatenodescheck.h"
|
||||
#include "checks/qgsgeometrygapcheck.h"
|
||||
#include "checks/qgsgeometryholecheck.h"
|
||||
#include "checks/qgsgeometrylineintersectioncheck.h"
|
||||
#include "checks/qgsgeometrymultipartcheck.h"
|
||||
#include "checks/qgsgeometryoverlapcheck.h"
|
||||
#include "checks/qgsgeometrypointcoveredbylinecheck.h"
|
||||
@ -299,6 +300,35 @@ REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometryHoleChe
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<> void QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
|
||||
{
|
||||
ui.checkLineIntersection->setChecked( QgsSettings().value( sSettingsGroup + "checkLineIntersection" ).toBool() );
|
||||
}
|
||||
|
||||
template<> bool QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck>::checkApplicability( Ui::QgsGeometryCheckerSetupTab &ui, int /*nPoint*/, int nLineString, int /*nPolygon*/ ) const
|
||||
{
|
||||
ui.checkLineIntersection->setEnabled( nLineString > 0 );
|
||||
return ui.checkLineIntersection->isEnabled();
|
||||
}
|
||||
|
||||
template<> QgsGeometryCheck *QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck>::createInstance( QgsGeometryCheckerContext *context, const Ui::QgsGeometryCheckerSetupTab &ui ) const
|
||||
{
|
||||
QgsSettings().setValue( sSettingsGroup + "checkLineIntersection", ui.checkLineIntersection->isChecked() );
|
||||
if ( ui.checkLineIntersection->isEnabled() && ui.checkLineIntersection->isChecked() )
|
||||
{
|
||||
return new QgsGeometryLineIntersectionCheck( context );
|
||||
}
|
||||
else
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometryLineIntersectionCheck> )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
template<> void QgsGeometryCheckFactoryT<QgsGeometryMultipartCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
|
||||
{
|
||||
ui.checkBoxMultipart->setChecked( QgsSettings().value( sSettingsGroup + "checkMultipart" ).toBool() );
|
||||
|
@ -43,7 +43,7 @@
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>626</width>
|
||||
<height>895</height>
|
||||
<height>918</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
@ -511,6 +511,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="checkLineIntersection">
|
||||
<property name="text">
|
||||
<string>Lines must not intersect</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxDuplicates">
|
||||
<property name="text">
|
||||
@ -535,7 +542,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<item row="8" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><i>Note: Topology checks are performed in the current map CRS.</i></string>
|
||||
@ -552,7 +559,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="checkPointCoveredByLine">
|
||||
<property name="text">
|
||||
<string>Points must be covered by lines</string>
|
||||
|
@ -222,6 +222,25 @@ namespace QgsGeometryCheckerUtils
|
||||
return false;
|
||||
}
|
||||
|
||||
bool linesIntersect( const QgsLineString *line1, const QgsLineString *line2, double tol, QgsPoint &inter )
|
||||
{
|
||||
for ( int i = 0, n = line1->vertexCount() - 1; i < n; ++i )
|
||||
{
|
||||
for ( int j = 0, m = line2->vertexCount() - 1; j < m; ++j )
|
||||
{
|
||||
QgsPoint p1 = line1->vertexAt( QgsVertexId( 0, 0, i ) );
|
||||
QgsPoint p2 = line1->vertexAt( QgsVertexId( 0, 0, i + 1 ) );
|
||||
QgsPoint q1 = line1->vertexAt( QgsVertexId( 0, 0, j ) );
|
||||
QgsPoint q2 = line1->vertexAt( QgsVertexId( 0, 0, j + 1 ) );
|
||||
if ( QgsGeometryUtils::segmentIntersection( p1, p2, q1, q2, inter, tol ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
double sharedEdgeLength( const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol )
|
||||
{
|
||||
double len = 0;
|
||||
|
@ -128,6 +128,8 @@ namespace QgsGeometryCheckerUtils
|
||||
|
||||
bool pointOnLine( const QgsPoint &p, const QgsLineString *line, double tol, bool excludeExtremities = false );
|
||||
|
||||
bool linesIntersect( const QgsLineString *line1, const QgsLineString *line2, double tol, QgsPoint &inter );
|
||||
|
||||
double sharedEdgeLength( const QgsAbstractGeometry *geom1, const QgsAbstractGeometry *geom2, double tol );
|
||||
|
||||
/**
|
||||
|
Loading…
x
Reference in New Issue
Block a user