Skip to content
Permalink
Browse files

[Geometry checker] Add line layer intersection check

  • Loading branch information
manisandro committed Oct 23, 2017
1 parent e4de3a8 commit bd8028e6f52e482f3e4139cb1767f0ca41cfc1a3
@@ -16,6 +16,7 @@ SET (geometrychecker_SRCS
checks/qgsgeometrygapcheck.cpp
checks/qgsgeometryholecheck.cpp
checks/qgsgeometrylineintersectioncheck.cpp
checks/qgsgeometrylinelayerintersectioncheck.cpp
checks/qgsgeometrymultipartcheck.cpp
checks/qgsgeometrycontainedcheck.cpp
checks/qgsgeometryoverlapcheck.cpp
@@ -55,6 +56,7 @@ SET (geometrychecker_MOC_HDRS
checks/qgsgeometrygapcheck.h
checks/qgsgeometryholecheck.h
checks/qgsgeometrylineintersectioncheck.h
checks/qgsgeometrylinelayerintersectioncheck.h
checks/qgsgeometrymultipartcheck.h
checks/qgsgeometrycontainedcheck.h
checks/qgsgeometryoverlapcheck.h
@@ -0,0 +1,102 @@
/***************************************************************************
qgsgeometrylinelayerintersectioncheck.cpp
---------------------
begin : September 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 "qgsgeometrylinelayerintersectioncheck.h"
#include "qgspolygon.h"
#include "qgslinestring.h"
#include "utils/qgsfeaturepool.h"

void QgsGeometryLineLayerIntersectionCheck::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 features of the specified layer
QgsGeometryCheckerUtils::LayerFeatures checkFeatures( mContext->featurePools, QStringList() << mCheckLayer, line->boundingBox(), {QgsWkbTypes::LineGeometry, QgsWkbTypes::PolygonGeometry} );
for ( const QgsGeometryCheckerUtils::LayerFeature &checkFeature : checkFeatures )
{
if ( checkFeature == layerFeature )
{
// Skip current feature
continue;
}
const QgsAbstractGeometry *testGeom = checkFeature.geometry();
for ( int jPart = 0, mParts = testGeom->partCount(); jPart < mParts; ++jPart )
{
QgsPoint inter;
const QgsAbstractGeometry *part = QgsGeometryCheckerUtils::getGeomPart( testGeom, jPart );
if ( const QgsLineString *testLine = dynamic_cast<const QgsLineString *>( part ) )
{
if ( QgsGeometryCheckerUtils::linesIntersect( line, testLine, mContext->tolerance, inter ) )
{
errors.append( new QgsGeometryCheckError( this, layerFeature, inter ) );
}
}
else if ( const QgsPolygonV2 *polygon = dynamic_cast<const QgsPolygonV2 *>( part ) )
{
QList<const QgsLineString *> rings;
if ( const QgsLineString *exterior = dynamic_cast<const QgsLineString *>( polygon->exteriorRing() ) )
{
rings.append( exterior );
}
for ( int iInt = 0, nInt = polygon->numInteriorRings(); iInt < nInt; ++iInt )
{
if ( const QgsLineString *interior = dynamic_cast<const QgsLineString *>( polygon->interiorRing( iInt ) ) )
{
rings.append( interior );
}
}
for ( const QgsLineString *ring : rings )
{
if ( QgsGeometryCheckerUtils::linesIntersect( ring, testLine, mContext->tolerance, inter ) )
{
errors.append( new QgsGeometryCheckError( this, layerFeature, inter ) );
}
}
}
}
}
}
}
}

void QgsGeometryLineLayerIntersectionCheck::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 QgsGeometryLineLayerIntersectionCheck::getResolutionMethods() const
{
static QStringList methods = QStringList() << tr( "No action" );
return methods;
}
@@ -0,0 +1,39 @@
/***************************************************************************
qgsgeometrylinelayerintersectioncheck.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 QGSGEOMETRYLINELAYERINTERSECTIONCHECK_H
#define QGSGEOMETRYLINELAYERINTERSECTIONCHECK_H

#include "qgsgeometrycheck.h"

class QgsGeometryLineLayerIntersectionCheck : public QgsGeometryCheck
{
Q_OBJECT

public:
QgsGeometryLineLayerIntersectionCheck( QgsGeometryCheckerContext *context, const QString &checkLayer )
: QgsGeometryCheck( FeatureNodeCheck, {QgsWkbTypes::LineGeometry}, context ), mCheckLayer( checkLayer )
{}
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( "QgsGeometryLineLayerIntersectionCheck" ); }
private:
enum ResolutionMethod { NoChange };
QString mCheckLayer;
};

#endif // QGSGEOMETRYLINELAYERINTERSECTIONCHECK_H
@@ -26,6 +26,7 @@
#include "checks/qgsgeometrygapcheck.h"
#include "checks/qgsgeometryholecheck.h"
#include "checks/qgsgeometrylineintersectioncheck.h"
#include "checks/qgsgeometrylinelayerintersectioncheck.h"
#include "checks/qgsgeometrymultipartcheck.h"
#include "checks/qgsgeometryoverlapcheck.h"
#include "checks/qgsgeometrypointcoveredbylinecheck.h"
@@ -331,6 +332,34 @@ REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometryLineInt

///////////////////////////////////////////////////////////////////////////////

template<> void QgsGeometryCheckFactoryT<QgsGeometryLineLayerIntersectionCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
{
ui.checkLineLayerIntersection->setChecked( QgsSettings().value( sSettingsGroup + "checkLineLayerIntersection" ).toBool() );
}

template<> bool QgsGeometryCheckFactoryT<QgsGeometryLineLayerIntersectionCheck>::checkApplicability( Ui::QgsGeometryCheckerSetupTab &ui, int /*nPoint*/, int nLineString, int /*nPolygon*/ ) const
{
ui.checkLineLayerIntersection->setEnabled( nLineString > 0 );
ui.comboLineLayerIntersection->setEnabled( nLineString > 0 );
return ui.checkLineLayerIntersection->isEnabled();
}

template<> QgsGeometryCheck *QgsGeometryCheckFactoryT<QgsGeometryLineLayerIntersectionCheck>::createInstance( QgsGeometryCheckerContext *context, const Ui::QgsGeometryCheckerSetupTab &ui ) const
{
QgsSettings().setValue( sSettingsGroup + "checkLineLayerIntersection", ui.checkLineLayerIntersection->isChecked() );
if ( ui.checkLineLayerIntersection->isEnabled() && ui.checkLineLayerIntersection->isChecked() )
{
return new QgsGeometryLineLayerIntersectionCheck( context, ui.comboLineLayerIntersection->currentData().toString() );
}
else
{
return nullptr;
}
}

REGISTER_QGS_GEOMETRY_CHECK_FACTORY( QgsGeometryCheckFactoryT<QgsGeometryLineLayerIntersectionCheck> )

///////////////////////////////////////////////////////////////////////////////

template<> void QgsGeometryCheckFactoryT<QgsGeometryMultipartCheck>::restorePrevious( Ui::QgsGeometryCheckerSetupTab &ui ) const
{
@@ -78,6 +78,7 @@ QgsGeometryCheckerSetupTab::QgsGeometryCheckerSetupTab( QgisInterface *iface, QD
connect( ui.lineEditOutputDirectory, &QLineEdit::textChanged, this, &QgsGeometryCheckerSetupTab::validateInput );
connect( ui.checkBoxSliverPolygons, &QAbstractButton::toggled, ui.widgetSliverThreshold, &QWidget::setEnabled );
connect( ui.checkBoxSliverArea, &QAbstractButton::toggled, ui.doubleSpinBoxSliverArea, &QWidget::setEnabled );
connect( ui.checkLineLayerIntersection, &QAbstractButton::toggled, ui.comboLineLayerIntersection, &QComboBox::setEnabled );

for ( const QgsGeometryCheckFactory *factory : QgsGeometryCheckFactoryRegistry::getCheckFactories() )
{
@@ -103,6 +104,7 @@ void QgsGeometryCheckerSetupTab::updateLayers()
}
}
ui.listWidgetInputLayers->clear();
ui.comboLineLayerIntersection->clear();

// Collect layers
for ( QgsVectorLayer *layer : QgsProject::instance()->layers<QgsVectorLayer *>() )
@@ -116,10 +118,12 @@ void QgsGeometryCheckerSetupTab::updateLayers()
else if ( layer->geometryType() == QgsWkbTypes::LineGeometry )
{
item->setIcon( QgsApplication::getThemeIcon( "/mIconLineLayer.svg" ) );
ui.comboLineLayerIntersection->addItem( layer->name(), layer->id() );
}
else if ( layer->geometryType() == QgsWkbTypes::PolygonGeometry )
{
item->setIcon( QgsApplication::getThemeIcon( "/mIconPolygonLayer.svg" ) );
ui.comboLineLayerIntersection->addItem( layer->name(), layer->id() );
}
else
{
@@ -420,6 +424,15 @@ void QgsGeometryCheckerSetupTab::runChecks()
QgsCoordinateTransform layerToMapTransform = QgsCoordinateTransformCache::instance()->transform( layer->crs().authid(), mIface->mapCanvas()->mapSettings().destinationCrs().authid() );
featurePools.insert( layer->id(), new QgsFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) );
}
// LineLayerIntersection check is enabled, make sure there is also a feature pool for that layer
if ( ui.checkLineLayerIntersection->isChecked() && !featurePools.keys().contains( ui.comboLineLayerIntersection->currentData().toString() ) )
{
QgsVectorLayer *layer = dynamic_cast<QgsVectorLayer *>( QgsProject::instance()->mapLayer( ui.comboLineLayerIntersection->currentData().toString() ) );
Q_ASSERT( layer );
double layerToMapUntis = mIface->mapCanvas()->mapSettings().layerToMapUnits( layer );
QgsCoordinateTransform layerToMapTransform = QgsCoordinateTransformCache::instance()->transform( layer->crs().authid(), mIface->mapCanvas()->mapSettings().destinationCrs().authid() );
featurePools.insert( layer->id(), new QgsFeaturePool( layer, layerToMapUntis, layerToMapTransform, selectedOnly ) );
}

QgsGeometryCheckerContext *context = new QgsGeometryCheckerContext( ui.spinBoxTolerance->value(), mIface->mapCanvas()->mapSettings().destinationCrs().authid(), featurePools );

@@ -41,9 +41,9 @@
<property name="geometry">
<rect>
<x>0</x>
<y>-215</y>
<y>-222</y>
<width>626</width>
<height>966</height>
<height>991</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_4">
@@ -514,7 +514,7 @@
<item row="6" column="0">
<widget class="QCheckBox" name="checkLineIntersection">
<property name="text">
<string>Lines must not intersect</string>
<string>Lines must not intersect any other lines</string>
</property>
</widget>
</item>
@@ -573,6 +573,20 @@
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="checkLineLayerIntersection">
<property name="text">
<string>Lines must not intersect with features of layer</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="comboLineLayerIntersection">
<property name="enabled">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>

0 comments on commit bd8028e

Please sign in to comment.
You can’t perform that action at this time.