Port merge lines and smooth to c++

This commit is contained in:
Nyall Dawson 2017-09-14 08:28:48 +10:00
parent 7c5521ecdf
commit 8e8f3edc55
7 changed files with 142 additions and 180 deletions

View File

@ -302,11 +302,6 @@ qgis:meancoordinates: >
If an attribute is selected in the <Unique ID field> parameters, features will be grouped according to values in this field. Instead of a single point with the center of mass of the whole layer, the output layer will contain a center of mass for the features in each category.
qgis:mergelines: >
This algorithm joins all connected parts of MultiLineString geometries into single LineString geometries.
If any parts of the input MultiLineString geometries are not connected, the resultant geometry will be a MultiLineString containing any lines which could be merged and any non-connected line parts.
qgis:mergevectorlayers: >
This algorithm combines multiple vector layers of the same geometry type into a single one.
@ -547,15 +542,6 @@ qgis:singlesidedbuffer: >
The miter limit parameter is only applicable for miter join styles, and controls the maximum distance from the buffer to use when creating a mitered join.
qgis:smoothgeometry: >
This algorithm smooths the geometries in a line or polygon layer. It creates a new layer with the same features as the ones in the input layer, but with geometries containing a higher number of vertices and corners in the geometries smoothed out.
The iterations parameter dictates how many smoothing iterations will be applied to each geometry. A higher number of iterations results in smoother geometries with the cost of greater number of nodes in the geometries.
The offset parameter controls how "tightly" the smoothed geometries follow the original geometries. Smaller values results in a tighter fit, and larger values will create a looser fit.
The maximum angle parameter can be used to prevent smoothing of nodes with large angles. Any node where the angle of the segments to either side is larger than this will not be smoothed. For example, setting the maximum angle to 90 degrees or lower would preserve right angles in the geometry.
qgis:snapgeometries: >
This algorithm snaps the geometries in a layer. Snapping can be done either to the geometries from another layer, or to geometries within the same layer.

View File

@ -1,78 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
Smooth.py
---------
Date : July 2016
Copyright : (C) 2016 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************
"""
__author__ = 'Nyall Dawson'
__date__ = 'July 2016'
__copyright__ = '(C) 2016, Nyall Dawson'
# This will get replaced with a git SHA1 when you do a git archive323
__revision__ = '$Format:%H$'
import os
from qgis.core import (QgsProcessing,
QgsWkbTypes)
from qgis.PyQt.QtGui import QIcon
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
class MergeLines(QgisFeatureBasedAlgorithm):
def icon(self):
return QIcon(os.path.join(pluginPath, 'images', 'ftools', 'to_lines.png'))
def tags(self):
return self.tr('line,merge,join,parts').split(',')
def group(self):
return self.tr('Vector geometry')
def __init__(self):
super().__init__()
def name(self):
return 'mergelines'
def displayName(self):
return self.tr('Merge lines')
def outputName(self):
return self.tr('Merged')
def outputType(self):
return QgsProcessing.TypeVectorLine
def outputWkbType(self, input_wkb):
return QgsWkbTypes.MultiLineString
def processFeature(self, feature, feedback):
input_geometry = feature.geometry()
if input_geometry:
output_geometry = input_geometry.mergeLines()
if not output_geometry:
feedback.reportError(self.tr('Error merging lines for feature {}').format(feature.id()))
feature.setGeometry(output_geometry)
return feature

View File

@ -95,7 +95,6 @@ from .LinesIntersection import LinesIntersection
from .LinesToPolygons import LinesToPolygons
from .MeanCoords import MeanCoords
from .Merge import Merge
from .MergeLines import MergeLines
from .MinimumBoundingGeometry import MinimumBoundingGeometry
from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
from .OffsetLine import OffsetLine
@ -145,7 +144,6 @@ from .ShortestPathPointToPoint import ShortestPathPointToPoint
from .SimplifyGeometries import SimplifyGeometries
from .SingleSidedBuffer import SingleSidedBuffer
from .Slope import Slope
from .Smooth import Smooth
from .SnapGeometries import SnapGeometriesToLayer
from .SpatialiteExecuteSQL import SpatialiteExecuteSQL
from .SpatialIndex import SpatialIndex
@ -235,7 +233,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
LinesToPolygons(),
MeanCoords(),
Merge(),
MergeLines(),
MinimumBoundingGeometry(),
NearestNeighbourAnalysis(),
OffsetLine(),
@ -285,7 +282,6 @@ class QGISAlgorithmProvider(QgsProcessingProvider):
SimplifyGeometries(),
SingleSidedBuffer(),
Slope(),
Smooth(),
SnapGeometriesToLayer(),
SpatialiteExecuteSQL(),
SpatialIndex(),

View File

@ -1,80 +0,0 @@
# -*- coding: utf-8 -*-
"""
***************************************************************************
Smooth.py
---------
Date : November 2015
Copyright : (C) 2015 by Nyall Dawson
Email : nyall dot dawson at gmail dot com
***************************************************************************
* *
* 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. *
* *
***************************************************************************
"""
__author__ = 'Nyall Dawson'
__date__ = 'November 2015'
__copyright__ = '(C) 2015, Nyall Dawson'
# This will get replaced with a git SHA1 when you do a git archive323
__revision__ = '$Format:%H$'
from qgis.core import (QgsProcessingException,
QgsProcessingParameterNumber)
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm
class Smooth(QgisFeatureBasedAlgorithm):
ITERATIONS = 'ITERATIONS'
MAX_ANGLE = 'MAX_ANGLE'
OFFSET = 'OFFSET'
def group(self):
return self.tr('Vector geometry')
def __init__(self):
super().__init__()
def initParameters(self, config=None):
self.addParameter(QgsProcessingParameterNumber(self.ITERATIONS,
self.tr('Iterations'),
defaultValue=1, minValue=1, maxValue=10))
self.addParameter(QgsProcessingParameterNumber(self.OFFSET,
self.tr('Offset'), QgsProcessingParameterNumber.Double,
defaultValue=0.25, minValue=0.0, maxValue=0.5))
self.addParameter(QgsProcessingParameterNumber(self.MAX_ANGLE,
self.tr('Maximum node angle to smooth'), QgsProcessingParameterNumber.Double,
defaultValue=180.0, minValue=0.0, maxValue=180.0))
def name(self):
return 'smoothgeometry'
def displayName(self):
return self.tr('Smooth geometry')
def outputName(self):
return self.tr('Smoothed')
def prepareAlgorithm(self, parameters, context, feedback):
self.iterations = self.parameterAsInt(parameters, self.ITERATIONS, context)
self.offset = self.parameterAsDouble(parameters, self.OFFSET, context)
self.max_angle = self.parameterAsDouble(parameters, self.MAX_ANGLE, context)
return True
def processFeature(self, feature, feedback):
if feature.hasGeometry():
output_geometry = feature.geometry().smooth(self.iterations, self.offset, -1, self.max_angle)
if not output_geometry:
raise QgsProcessingException(
self.tr('Error smoothing geometry'))
feature.setGeometry(output_geometry)
return feature

View File

@ -588,7 +588,7 @@ tests:
geometry:
precision: 7
- algorithm: qgis:mergelines
- algorithm: native:mergelines
name: Merge lines algorithm
params:
INPUT:
@ -1265,7 +1265,7 @@ tests:
geometry:
precision: 7
- algorithm: qgis:smoothgeometry
- algorithm: native:smoothgeometry
name: Smooth (lines)
params:
INPUT:
@ -1279,7 +1279,7 @@ tests:
name: expected/smoothed_lines.gml
type: vector
- algorithm: qgis:smoothgeometry
- algorithm: native:smoothgeometry
name: Smooth (lines, with max angle)
params:
INPUT:

View File

@ -79,6 +79,8 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsSelectByLocationAlgorithm() );
addAlgorithm( new QgsExtractByLocationAlgorithm() );
addAlgorithm( new QgsFixGeometriesAlgorithm() );
addAlgorithm( new QgsMergeLinesAlgorithm() );
addAlgorithm( new QgsSmoothAlgorithm() );
}
void QgsCentroidAlgorithm::initAlgorithm( const QVariantMap & )
@ -1665,6 +1667,89 @@ QgsFeature QgsFixGeometriesAlgorithm::processFeature( const QgsFeature &feature,
return outputFeature;
}
QString QgsMergeLinesAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm joins all connected parts of MultiLineString geometries into single LineString geometries.\n\n"
"If any parts of the input MultiLineString geometries are not connected, the resultant "
"geometry will be a MultiLineString containing any lines which could be merged and any non-connected line parts." );
}
QgsMergeLinesAlgorithm *QgsMergeLinesAlgorithm::createInstance() const
{
return new QgsMergeLinesAlgorithm();
}
QgsFeature QgsMergeLinesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback )
{
if ( !feature.hasGeometry() )
return feature;
QgsFeature out = feature;
QgsGeometry outputGeometry = feature.geometry().mergeLines();
if ( !outputGeometry )
feedback->reportError( QObject::tr( "Error merging lines for feature %1" ).arg( feature.id() ) );
out.setGeometry( outputGeometry );
return out;
}
QString QgsSmoothAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm smooths the geometries in a line or polygon layer. It creates a new layer with the "
"same features as the ones in the input layer, but with geometries containing a higher number of vertices "
"and corners in the geometries smoothed out.\n\n"
"The iterations parameter dictates how many smoothing iterations will be applied to each "
"geometry. A higher number of iterations results in smoother geometries with the cost of "
"greater number of nodes in the geometries.\n\n"
"The offset parameter controls how \"tightly\" the smoothed geometries follow the original geometries. "
"Smaller values results in a tighter fit, and larger values will create a looser fit.\n\n"
"The maximum angle parameter can be used to prevent smoothing of "
"nodes with large angles. Any node where the angle of the segments to either "
"side is larger than this will not be smoothed. For example, setting the maximum "
"angle to 90 degrees or lower would preserve right angles in the geometry." );
}
QgsSmoothAlgorithm *QgsSmoothAlgorithm::createInstance() const
{
return new QgsSmoothAlgorithm();
}
void QgsSmoothAlgorithm::initParameters( const QVariantMap & )
{
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "ITERATIONS" ),
QObject::tr( "Iterations" ), QgsProcessingParameterNumber::Integer,
1, false, 1, 10 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "OFFSET" ),
QObject::tr( "Offset" ), QgsProcessingParameterNumber::Double,
0.25, false, 0.0, 0.5 ) );
addParameter( new QgsProcessingParameterNumber( QStringLiteral( "MAX_ANGLE" ),
QObject::tr( "Maximum node angle to smooth" ), QgsProcessingParameterNumber::Double,
180.0, false, 0.0, 180.0 ) );
}
bool QgsSmoothAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
{
mIterations = parameterAsInt( parameters, QStringLiteral( "ITERATIONS" ), context );
mOffset = parameterAsDouble( parameters, QStringLiteral( "OFFSET" ), context );
mMaxAngle = parameterAsDouble( parameters, QStringLiteral( "MAX_ANGLE" ), context );
return true;
}
QgsFeature QgsSmoothAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback )
{
QgsFeature f = feature;
if ( f.hasGeometry() )
{
QgsGeometry outputGeometry = f.geometry().smooth( mIterations, mOffset, -1, mMaxAngle );
if ( !outputGeometry )
{
feedback->reportError( QObject::tr( "Error smoothing geometry %1" ).arg( feature.id() ) );
}
f.setGeometry( outputGeometry );
}
return f;
}
///@endcond

View File

@ -579,6 +579,59 @@ class QgsFixGeometriesAlgorithm : public QgsProcessingFeatureBasedAlgorithm
};
/**
* Native merge lines algorithm.
*/
class QgsMergeLinesAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{
public:
QgsMergeLinesAlgorithm() = default;
QString name() const override { return QStringLiteral( "mergelines" ); }
QString displayName() const override { return QObject::tr( "Merge lines" ); }
virtual QStringList tags() const override { return QObject::tr( "line,merge,join,parts" ).split( ',' ); }
QString group() const override { return QObject::tr( "Vector geometry" ); }
QString shortHelpString() const override;
QgsMergeLinesAlgorithm *createInstance() const override SIP_FACTORY;
protected:
QString outputName() const override { return QObject::tr( "Merged" ); }
QgsProcessing::SourceType outputLayerType() const override { return QgsProcessing::TypeVectorLine; }
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type ) const override { return QgsWkbTypes::MultiLineString; }
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
};
/**
* Native smooth algorithm.
*/
class QgsSmoothAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{
public:
QgsSmoothAlgorithm() = default;
QString name() const override { return QStringLiteral( "smoothgeometry" ); }
QString displayName() const override { return QObject::tr( "Smooth geometries" ); }
virtual QStringList tags() const override { return QObject::tr( "smooth,curve,generalize,round,bend,corners" ).split( ',' ); }
QString group() const override { return QObject::tr( "Vector geometry" ); }
QString shortHelpString() const override;
QgsSmoothAlgorithm *createInstance() const override SIP_FACTORY;
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
protected:
QString outputName() const override { return QObject::tr( "Smoothed" ); }
QgsProcessing::SourceType outputLayerType() const override { return QgsProcessing::TypeVectorLine; }
bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QgsFeature processFeature( const QgsFeature &feature, QgsProcessingFeedback *feedback ) override;
private:
int mIterations = 1;
double mOffset = 0.25;
double mMaxAngle = 0;
};
///@endcond PRIVATE
#endif // QGSNATIVEALGORITHMS_H