Skip to content

Commit

Permalink
Moved new snapping alg as another mode of "Snap geometries" processin…
Browse files Browse the repository at this point in the history
…g alg
  • Loading branch information
wonder-sk committed Sep 13, 2018
1 parent cef3395 commit 1af35b2
Show file tree
Hide file tree
Showing 10 changed files with 145 additions and 137 deletions.
1 change: 1 addition & 0 deletions python/analysis/analysis_auto.sip
Expand Up @@ -13,6 +13,7 @@
%Include auto_generated/raster/qgsrastercalcnode.sip
%Include auto_generated/raster/qgstotalcurvaturefilter.sip
%Include auto_generated/vector/qgsgeometrysnapper.sip
%Include auto_generated/vector/qgsgeometrysnappersinglesource.sip
%Include auto_generated/vector/qgszonalstatistics.sip
%Include auto_generated/interpolation/qgsinterpolator.sip
%Include auto_generated/interpolation/qgsgridfilewriter.sip
Expand Down
@@ -0,0 +1,52 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/analysis/vector/qgsgeometrysnappersinglesource.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/




class QgsGeometrySnapperSingleSource
{
%Docstring

Makes sure that any two vertices of the vector layer are at least at distance given by the threshold value.
The algorithm moves nearby vertices to one location and adds vertices to segments that are passing around other
vertices within the threshold. It does not remove any vertices. Also, it does not modify geometries unless
needed (it does not snap coordinates to a grid).

This algorithm comes handy when doing vector overlay operations such as intersection, union or difference
to prevent possible topological errors caused by numerical errors if coordinates are very close to each other.

After running the algorithm some previously valid geometries may become invalid and therefore it may be useful
to run Fix geometries algorithm afterwards.

.. note::

Originally ported from GRASS implementation of Vect_snap_lines_list()

.. versionadded:: 3.4
%End

%TypeHeaderCode
#include "qgsgeometrysnappersinglesource.h"
%End
public:

static int run( const QgsFeatureSource &source, QgsFeatureSink &sink, double thresh, QgsFeedback *feedback );
%Docstring
Run the algorithm on given source and output results to the sink, using threshold value in the source's map units.
Returns number of modified geometries.
%End
};

/************************************************************************
* This file has been generated automatically from *
* *
* src/analysis/vector/qgsgeometrysnappersinglesource.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
11 changes: 10 additions & 1 deletion python/plugins/processing/algs/qgis/SnapGeometries.py
Expand Up @@ -26,6 +26,7 @@
__revision__ = '$Format:%H$'

from qgis.analysis import (QgsGeometrySnapper,
QgsGeometrySnapperSingleSource,
QgsInternalGeometrySnapper)
from qgis.core import (QgsFeatureSink,
QgsProcessing,
Expand Down Expand Up @@ -71,7 +72,8 @@ def initAlgorithm(self, config=None):
self.tr('Prefer closest point, don\'t insert new vertices'),
self.tr('Move end points only, prefer aligning nodes'),
self.tr('Move end points only, prefer closest point'),
self.tr('Snap end points to end points only')]
self.tr('Snap end points to end points only'),
self.tr('Snap to anchor nodes (single layer only)')]
self.addParameter(QgsProcessingParameterEnum(
self.BEHAVIOR,
self.tr('Behavior'),
Expand Down Expand Up @@ -106,6 +108,9 @@ def processAlgorithm(self, parameters, context, feedback):
total = 100.0 / source.featureCount() if source.featureCount() else 0

if parameters[self.INPUT] != parameters[self.REFERENCE_LAYER]:
if mode == 7:
raise QgsProcessingException(self.tr('This mode applies when the input and reference layer are the same.'))

snapper = QgsGeometrySnapper(reference_source)
processed = 0
for f in features:
Expand All @@ -119,6 +124,10 @@ def processAlgorithm(self, parameters, context, feedback):
sink.addFeature(f)
processed += 1
feedback.setProgress(processed * total)
elif mode == 7:
# input layer == ref layer
modified_count = QgsGeometrySnapperSingleSource.run(source, sink, tolerance, feedback)
feedback.pushInfo(self.tr('Snapped {} geometries.').format(modified_count))
else:
# snapping internally
snapper = QgsInternalGeometrySnapper(tolerance, mode)
Expand Down
Binary file not shown.
28 changes: 16 additions & 12 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -2045,6 +2045,22 @@ tests:
name: expected/snap_internal.gml
type: vector

- algorithm: qgis:snapgeometries
name: Test Snap Geometries (to each other)
params:
BEHAVIOR: '7'
INPUT:
name: custom/snap_geometries.geojson
type: vector
REFERENCE_LAYER:
name: custom/snap_geometries.geojson
type: vector
TOLERANCE: 0.5
results:
OUTPUT:
name: expected/snap_geometries.gml
type: vector

- algorithm: qgis:poleofinaccessibility
name: Pole of inaccessibility (polygons)
params:
Expand Down Expand Up @@ -5586,18 +5602,6 @@ tests:
fields:
fid: skip

- algorithm: native:snap
name: Test Snap Geometries (to each other)
params:
INPUT:
name: custom/snap_geometries.geojson
type: vector
THRESHOLD: 0.5
results:
OUTPUT:
name: expected/snap_geometries.gml
type: vector

- algorithm: native:taperedbuffer
name: Tapered buffers (lines)
params:
Expand Down
3 changes: 2 additions & 1 deletion src/analysis/CMakeLists.txt
Expand Up @@ -85,7 +85,6 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmshortestpathpointtopoint.cpp
processing/qgsalgorithmsimplify.cpp
processing/qgsalgorithmsmooth.cpp
processing/qgsalgorithmsnapgeometries.cpp
processing/qgsalgorithmsnaptogrid.cpp
processing/qgsalgorithmsplitwithlines.cpp
processing/qgsalgorithmstringconcatenation.cpp
Expand Down Expand Up @@ -124,6 +123,7 @@ SET(QGIS_ANALYSIS_SRCS
raster/qgsrastermatrix.cpp
vector/mersenne-twister.cpp
vector/qgsgeometrysnapper.cpp
vector/qgsgeometrysnappersinglesource.cpp
vector/qgszonalstatistics.cpp

network/qgsgraph.cpp
Expand Down Expand Up @@ -232,6 +232,7 @@ SET(QGIS_ANALYSIS_HDRS

vector/mersenne-twister.h
vector/qgsgeometrysnapper.h
vector/qgsgeometrysnappersinglesource.h
vector/qgszonalstatistics.h
vector/geometry_checker/qgsgeometrycheckerutils.h
vector/geometry_checker/qgsfeaturepool.h
Expand Down
45 changes: 0 additions & 45 deletions src/analysis/processing/qgsalgorithmsnapgeometries.h

This file was deleted.

2 changes: 0 additions & 2 deletions src/analysis/processing/qgsnativealgorithms.cpp
Expand Up @@ -82,7 +82,6 @@
#include "qgsalgorithmshortestpathpointtopoint.h"
#include "qgsalgorithmsimplify.h"
#include "qgsalgorithmsmooth.h"
#include "qgsalgorithmsnapgeometries.h"
#include "qgsalgorithmsnaptogrid.h"
#include "qgsalgorithmsplitwithlines.h"
#include "qgsalgorithmstringconcatenation.h"
Expand Down Expand Up @@ -213,7 +212,6 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsShortestPathPointToPointAlgorithm() );
addAlgorithm( new QgsSimplifyAlgorithm() );
addAlgorithm( new QgsSmoothAlgorithm() );
addAlgorithm( new QgsSnapGeometriesAlgorithm() );
addAlgorithm( new QgsSnapToGridAlgorithm() );
addAlgorithm( new QgsSplitWithLinesAlgorithm() );
addAlgorithm( new QgsStringConcatenationAlgorithm() );
Expand Down
@@ -1,5 +1,5 @@
/***************************************************************************
qgsalgorithmsnapgeometries.cpp
qgsgeometrysnappersinglesource.cpp
---------------------
Date : May 2018
Copyright : (C) 2018 by Martin Dobias
Expand All @@ -13,81 +13,17 @@
* *
***************************************************************************/

#include "qgsalgorithmsnapgeometries.h"
#include "qgsgeometrysnappersinglesource.h"

#include "qgsfeatureiterator.h"
#include "qgsfeaturesink.h"
#include "qgsfeaturesource.h"
#include "qgsfeedback.h"
#include "qgsgeometrycollection.h"
#include "qgsgeometryutils.h"
#include "qgslinestring.h"
#include "qgspolygon.h"

///@cond PRIVATE

QString QgsSnapGeometriesAlgorithm::name() const
{
return QStringLiteral( "snap" );
}

QString QgsSnapGeometriesAlgorithm::displayName() const
{
return QObject::tr( "Snap geometries" );
}

QString QgsSnapGeometriesAlgorithm::group() const
{
return QObject::tr( "Vector geometry" );
}

QString QgsSnapGeometriesAlgorithm::groupId() const
{
return QStringLiteral( "vectorgeometry" );
}

QString QgsSnapGeometriesAlgorithm::shortHelpString() const
{
return QObject::tr( "Makes sure that any two vertices of the vector layer are at least at distance given by the threshold value. "
"The algorithm moves nearby vertices to one location and adds vertices to segments that are passing around other "
"vertices within the threshold. It does not remove any vertices. Also, it does not modify geometries unless "
"needed (it does not snap coordinates to a grid).\n\n"
"This algorithm comes handy when doing vector overlay operations such as intersection, union or difference "
"to prevent possible topological errors caused by numerical errors if coordinates are very close to each other.\n\n"
"After running the algorithm some previously valid geometries may become invalid and therefore it may be useful "
"to run Fix geometries algorithm afterwards." );
}

QgsProcessingAlgorithm *QgsSnapGeometriesAlgorithm::createInstance() const
{
return new QgsSnapGeometriesAlgorithm();
}

void QgsSnapGeometriesAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "THRESHOLD" ), QObject::tr( "Threshold" ), QgsProcessingParameterNumber::Double, 0.01 ) );
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Output layer" ) ) );
}

QVariantMap QgsSnapGeometriesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
{
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );

double thresh = parameterAsDouble( parameters, QStringLiteral( "THRESHOLD" ), context );

QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(), source->wkbType(), source->sourceCrs() ) );
if ( !sink )
throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );

QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );

// now go and snap vertices of geometries of source together
run( *source.get(), *sink.get(), thresh, feedback );

return outputs;
}

#include "qgsspatialindex.h"

//! record about vertex coordinates and index of anchor to which it is snapped
typedef struct
Expand All @@ -113,7 +49,7 @@ typedef struct
} AnchorAlongSegment;


static void buildSnapIndex( QgsFeatureIterator &fi, QgsSpatialIndex &index, QVector<AnchorPoint> &pnts, QgsProcessingFeedback *feedback, int &count, int totalCount )
static void buildSnapIndex( QgsFeatureIterator &fi, QgsSpatialIndex &index, QVector<AnchorPoint> &pnts, QgsFeedback *feedback, int &count, int totalCount )
{
QgsFeature f;
int pntId = 0;
Expand Down Expand Up @@ -362,7 +298,7 @@ static bool snapGeometry( QgsAbstractGeometry *g, QgsSpatialIndex &index, QVecto
}


void QgsSnapGeometriesAlgorithm::run( const QgsFeatureSource &source, QgsFeatureSink &sink, double thresh, QgsProcessingFeedback *feedback )
int QgsGeometrySnapperSingleSource::run(const QgsFeatureSource &source, QgsFeatureSink &sink, double thresh, QgsFeedback *feedback)
{
// the logic here comes from GRASS implementation of Vect_snap_lines_list()

Expand Down Expand Up @@ -405,7 +341,5 @@ void QgsSnapGeometriesAlgorithm::run( const QgsFeatureSource &source, QgsFeature
feedback->setProgress( 100. * count / totalCount );
}

feedback->pushInfo( QObject::tr( "Snapped %1 geometries." ).arg( modified ) );
return modified;
}

///@endcond PRIVATE

0 comments on commit 1af35b2

Please sign in to comment.