mirror of
https://github.com/qgis/QGIS.git
synced 2025-02-25 00:58:06 -05:00
[Geometry checker] Add self-contact check
This commit is contained in:
parent
97545901ca
commit
cad9e469bb
@ -18,6 +18,7 @@ SET (geometrychecker_SRCS
|
||||
checks/qgsgeometrycontainedcheck.cpp
|
||||
checks/qgsgeometryoverlapcheck.cpp
|
||||
checks/qgsgeometrysegmentlengthcheck.cpp
|
||||
checks/qgsgeometryselfcontactcheck.cpp
|
||||
checks/qgsgeometryselfintersectioncheck.cpp
|
||||
checks/qgsgeometrytypecheck.cpp
|
||||
ui/qgsgeometrycheckerdialog.cpp
|
||||
@ -52,6 +53,7 @@ SET (geometrychecker_MOC_HDRS
|
||||
checks/qgsgeometrycontainedcheck.h
|
||||
checks/qgsgeometryoverlapcheck.h
|
||||
checks/qgsgeometrysegmentlengthcheck.h
|
||||
checks/qgsgeometryselfcontactcheck.h
|
||||
checks/qgsgeometryselfintersectioncheck.h
|
||||
checks/qgsgeometrysliverpolygoncheck.h
|
||||
checks/qgsgeometrytypecheck.h
|
||||
|
@ -0,0 +1,101 @@
|
||||
/***************************************************************************
|
||||
* qgsgeometryselfcontactcheck.cpp *
|
||||
* ------------------- *
|
||||
* copyright : (C) 2017 by Sandro Mani / Sourcepole AG *
|
||||
* email : smani@sourcepole.ch *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgsgeometryselfcontactcheck.h"
|
||||
#include "qgsgeometryutils.h"
|
||||
#include "../utils/qgsfeaturepool.h"
|
||||
|
||||
void QgsGeometrySelfContactCheck::collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &/*messages*/, QAtomicInt *progressCounter, const QgsFeatureIds &ids ) const
|
||||
{
|
||||
const QgsFeatureIds &featureIds = ids.isEmpty() ? mFeaturePool->getFeatureIds() : ids;
|
||||
double tolerance = QgsGeometryCheckPrecision::tolerance();
|
||||
foreach ( const QgsFeatureId &featureid, featureIds )
|
||||
{
|
||||
if ( progressCounter ) progressCounter->fetchAndAddRelaxed( 1 );
|
||||
QgsFeature feature;
|
||||
if ( !mFeaturePool->get( featureid, feature ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
QgsAbstractGeometry *geom = feature.geometry().geometry();
|
||||
|
||||
for ( int iPart = 0, nParts = geom->partCount(); iPart < nParts; ++iPart )
|
||||
{
|
||||
for ( int iRing = 0, nRings = geom->ringCount( iPart ); iRing < nRings; ++iRing )
|
||||
{
|
||||
// Test for self-contacts
|
||||
int n = geom->vertexCount( iPart, iRing );
|
||||
bool isClosed = geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) == geom->vertexAt( QgsVertexId( iPart, iRing, n - 1 ) );
|
||||
|
||||
// Geometry ring without duplicate nodes
|
||||
QVector<int> vtxMap;
|
||||
QVector<QgsPointV2> ring;
|
||||
vtxMap.append( 0 );
|
||||
ring.append( geom->vertexAt( QgsVertexId( iPart, iRing, 0 ) ) );
|
||||
for ( int i = 1; i < n; ++i )
|
||||
{
|
||||
QgsPointV2 p = geom->vertexAt( QgsVertexId( iPart, iRing, i ) );
|
||||
if ( QgsGeometryUtils::sqrDistance2D( p, ring.last() ) > tolerance * tolerance )
|
||||
{
|
||||
vtxMap.append( i );
|
||||
ring.append( p );
|
||||
}
|
||||
}
|
||||
while ( QgsGeometryUtils::sqrDistance2D( ring.front(), ring.back() ) < tolerance * tolerance )
|
||||
{
|
||||
vtxMap.pop_back();
|
||||
ring.pop_back();
|
||||
}
|
||||
if ( isClosed )
|
||||
{
|
||||
vtxMap.append( n - 1 );
|
||||
ring.append( ring.front() );
|
||||
}
|
||||
n = ring.size();
|
||||
|
||||
// For each vertex, check whether it lies on a segment
|
||||
for ( int iVert = 0, nVerts = n - isClosed; iVert < nVerts; ++iVert )
|
||||
{
|
||||
const QgsPointV2 &p = ring[iVert];
|
||||
for ( int i = 0, j = 1; j < n; i = j++ )
|
||||
{
|
||||
if ( iVert == i || iVert == j || ( isClosed && iVert == 0 && j == n - 1 ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const QgsPointV2 &si = ring[i];
|
||||
const QgsPointV2 &sj = ring[j];
|
||||
QgsPointV2 q = QgsGeometryUtils::projPointOnSegment( p, si, sj );
|
||||
if ( QgsGeometryUtils::sqrDistance2D( p, q ) < tolerance * tolerance )
|
||||
{
|
||||
errors.append( new QgsGeometryCheckError( this, featureid, p, QgsVertexId( iPart, iRing, vtxMap[iVert] ) ) );
|
||||
break; // No need to report same contact on different segments multiple times
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGeometrySelfContactCheck::fixError( QgsGeometryCheckError *error, int method, int /*mergeAttributeIndex*/, Changes & /*changes*/ ) const
|
||||
{
|
||||
if ( method == NoChange )
|
||||
{
|
||||
error->setFixed( method );
|
||||
}
|
||||
else
|
||||
{
|
||||
error->setFixFailed( tr( "Unknown method" ) );
|
||||
}
|
||||
}
|
||||
|
||||
QStringList QgsGeometrySelfContactCheck::getResolutionMethods() const
|
||||
{
|
||||
static QStringList methods = QStringList() << tr( "No action" );
|
||||
return methods;
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/***************************************************************************
|
||||
* qgsgeometryselfcontactcheck.h *
|
||||
* ------------------- *
|
||||
* copyright : (C) 2017 by Sandro Mani / Sourcepole AG *
|
||||
* email : smani@sourcepole.ch *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGS_GEOMETRY_SELFCONTACT_CHECK_H
|
||||
#define QGS_GEOMETRY_SELFCONTACT_CHECK_H
|
||||
|
||||
#include "qgsgeometrycheck.h"
|
||||
|
||||
class QgsGeometrySelfContactCheck : public QgsGeometryCheck
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsGeometrySelfContactCheck( QgsFeaturePool *featurePool )
|
||||
: QgsGeometryCheck( FeatureNodeCheck, featurePool ) {}
|
||||
void collectErrors( QList<QgsGeometryCheckError *> &errors, QStringList &messages, QAtomicInt *progressCounter = 0, const QgsFeatureIds &ids = QgsFeatureIds() ) const;
|
||||
void fixError( QgsGeometryCheckError *error, int method, int, Changes & ) const;
|
||||
QStringList getResolutionMethods() const;
|
||||
QString errorDescription() const { return tr( "Self contact" ); }
|
||||
QString errorName() const { return "QgsGeometrySelfContactCheck"; }
|
||||
private:
|
||||
enum ResolutionMethod { NoChange };
|
||||
};
|
||||
|
||||
#endif // QGS_GEOMETRY_SELFCONTACT_CHECK_H
|
@ -27,6 +27,7 @@
|
||||
#include "checks/qgsgeometrymultipartcheck.h"
|
||||
#include "checks/qgsgeometryoverlapcheck.h"
|
||||
#include "checks/qgsgeometrysegmentlengthcheck.h"
|
||||
#include "checks/qgsgeometryselfcontactcheck.h"
|
||||
#include "checks/qgsgeometryselfintersectioncheck.h"
|
||||
#include "checks/qgsgeometrysliverpolygoncheck.h"
|
||||
#include "checks/qgsgeometrytypecheck.h"
|
||||
@ -357,6 +358,34 @@ REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometrySegment
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<> void QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
|
||||
{
|
||||
ui.checkBoxSelfContacts->setChecked( QgsSettings().value( sSettingsGroup + "checkSelfContacts" ).toBool() );
|
||||
}
|
||||
|
||||
template<> bool QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck>::checkApplicability( Ui::QgsGeometryCheckerSetupTab &ui, QgsWkbTypes::GeometryType geomType ) const
|
||||
{
|
||||
ui.checkBoxSelfContacts->setEnabled( geomType == QgsWkbTypes::PolygonGeometry || geomType == QgsWkbTypes::LineGeometry );
|
||||
return ui.checkBoxSelfContacts->isEnabled();
|
||||
}
|
||||
|
||||
template<> QgsGeometryCheck *QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck>::createInstance( QgsFeaturePool *featurePool, const Ui::QgsGeometryCheckerSetupTab &ui, double /*mapToLayerUnits*/ ) const
|
||||
{
|
||||
QgsSettings().setValue( sSettingsGroup + "checkSelfContacts", ui.checkBoxSelfContacts->isChecked() );
|
||||
if ( ui.checkBoxSelfContacts->isEnabled() && ui.checkBoxSelfContacts->isChecked() )
|
||||
{
|
||||
return new QgsGeometrySelfContactCheck( featurePool );
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometrySelfContactCheck> )
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<> void QgsGeometryCheckFactoryT<QgsGeometrySelfIntersectionCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
|
||||
{
|
||||
ui.checkBoxSelfIntersections->setChecked( QgsSettings().value( sSettingsGroup + "checkSelfIntersections" ).toBool() );
|
||||
|
@ -41,9 +41,9 @@
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>-301</y>
|
||||
<width>670</width>
|
||||
<height>776</height>
|
||||
<y>0</y>
|
||||
<width>626</width>
|
||||
<height>726</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
@ -117,10 +117,7 @@
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_8">
|
||||
<property name="leftMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
@ -133,7 +130,7 @@
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxSelfIntersections">
|
||||
<property name="text">
|
||||
<string>Self intersections</string>
|
||||
@ -143,7 +140,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxDuplicateNodes">
|
||||
<property name="text">
|
||||
<string>Duplicate nodes</string>
|
||||
@ -153,7 +150,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxDegeneratePolygon">
|
||||
<property name="text">
|
||||
<string>Polygon with less than 3 nodes</string>
|
||||
@ -163,6 +160,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxSelfContacts">
|
||||
<property name="text">
|
||||
<string>Self contacts</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -728,7 +735,6 @@
|
||||
<tabstop>checkBoxInputSelectedOnly</tabstop>
|
||||
<tabstop>checkBoxSelfIntersections</tabstop>
|
||||
<tabstop>checkBoxDuplicateNodes</tabstop>
|
||||
<tabstop>checkBoxDegeneratePolygon</tabstop>
|
||||
<tabstop>checkBoxPoint</tabstop>
|
||||
<tabstop>checkBoxMultipoint</tabstop>
|
||||
<tabstop>checkBoxLine</tabstop>
|
||||
|
Loading…
x
Reference in New Issue
Block a user