diff --git a/python/plugins/processing/algs/help/qgis.yaml b/python/plugins/processing/algs/help/qgis.yaml index 8311e28b27a..7179cc9f8ba 100644 --- a/python/plugins/processing/algs/help/qgis.yaml +++ b/python/plugins/processing/algs/help/qgis.yaml @@ -280,15 +280,6 @@ qgis:numberofuniquevaluesinclasses: > The resulting layer contains the same features as the input layer, but with an additional attribute containing the count of unique values for that class. -qgis:offsetline: > - This algorithm offsets lines by a specified distance. Positive distances will offset lines to the left, and negative distances will offset to the right of lines. - - The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets. - - The join style parameter specifies whether round, miter or beveled joins should be used when offsetting corners in a line. - - The miter limit parameter is only applicable for miter join styles, and controls the maximum distance from the offset curve to use when creating a mitered join. - qgis:minimalenclosingcircle: > This algorithm takes a vector layer and generate a new one with the minimum enclosing circle that covers all the input features. diff --git a/python/plugins/processing/algs/qgis/OffsetLine.py b/python/plugins/processing/algs/qgis/OffsetLine.py deleted file mode 100644 index 14f9376e47f..00000000000 --- a/python/plugins/processing/algs/qgis/OffsetLine.py +++ /dev/null @@ -1,117 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - OffsetLine.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 (QgsFeatureSink, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterNumber, - QgsProcessingParameterDistance, - QgsProcessingParameterEnum, - QgsProcessingParameterFeatureSink) - -from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm - -pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] - - -class OffsetLine(QgisFeatureBasedAlgorithm): - - DISTANCE = 'DISTANCE' - SEGMENTS = 'SEGMENTS' - JOIN_STYLE = 'JOIN_STYLE' - MITER_LIMIT = 'MITER_LIMIT' - - def group(self): - return self.tr('Vector geometry') - - def groupId(self): - return 'vectorgeometry' - - def __init__(self): - super().__init__() - - self.distance = None - self.segments = None - self.join_style = None - self.miter_limit = None - - def initParameters(self, config=None): - self.addParameter(QgsProcessingParameterDistance(self.DISTANCE, - self.tr('Distance'), - defaultValue=10.0, - parentParameterName='INPUT')) - self.addParameter(QgsProcessingParameterNumber(self.SEGMENTS, - self.tr('Segments'), - type=QgsProcessingParameterNumber.Integer, - minValue=1, defaultValue=8)) - self.join_styles = [self.tr('Round'), - 'Miter', - 'Bevel'] - self.addParameter(QgsProcessingParameterEnum( - self.JOIN_STYLE, - self.tr('Join style'), - options=self.join_styles)) - self.addParameter(QgsProcessingParameterNumber(self.MITER_LIMIT, - self.tr('Miter limit'), type=QgsProcessingParameterNumber.Double, - minValue=1, defaultValue=2)) - - def name(self): - return 'offsetline' - - def displayName(self): - return self.tr('Offset line') - - def outputName(self): - return self.tr('Offset') - - def inputLayerTypes(self): - return [QgsProcessing.TypeVectorLine] - - def outputType(self): - return QgsProcessing.TypeVectorLine - - def prepareAlgorithm(self, parameters, context, feedback): - self.distance = self.parameterAsDouble(parameters, self.DISTANCE, context) - self.segments = self.parameterAsInt(parameters, self.SEGMENTS, context) - self.join_style = self.parameterAsEnum(parameters, self.JOIN_STYLE, context) + 1 - self.miter_limit = self.parameterAsDouble(parameters, self.MITER_LIMIT, context) - return True - - def processFeature(self, feature, context, feedback): - input_geometry = feature.geometry() - if input_geometry: - output_geometry = input_geometry.offsetCurve(self.distance, self.segments, self.join_style, self.miter_limit) - if not output_geometry: - raise QgsProcessingException( - self.tr('Error calculating line offset')) - - feature.setGeometry(output_geometry) - - return [feature] diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py index 03512ec3bc4..8bc08d0c9f6 100644 --- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py @@ -86,7 +86,6 @@ from .KeepNBiggestParts import KeepNBiggestParts from .LinesToPolygons import LinesToPolygons from .MinimumBoundingGeometry import MinimumBoundingGeometry from .NearestNeighbourAnalysis import NearestNeighbourAnalysis -from .OffsetLine import OffsetLine from .Orthogonalize import Orthogonalize from .PointDistance import PointDistance from .PointsAlongGeometry import PointsAlongGeometry @@ -201,7 +200,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider): LinesToPolygons(), MinimumBoundingGeometry(), NearestNeighbourAnalysis(), - OffsetLine(), Orthogonalize(), PointDistance(), PointsAlongGeometry(), diff --git a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml index 287e9385d16..88b1caabab9 100644 --- a/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml +++ b/python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml @@ -984,7 +984,7 @@ tests: name: expected/reverse_multiline.gml type: vector - - algorithm: qgis:offsetline + - algorithm: native:offsetline name: Offset line positive params: DISTANCE: 1.0 @@ -1002,7 +1002,7 @@ tests: geometry: precision: 7 - - algorithm: qgis:offsetline + - algorithm: native:offsetline name: Offset line negative params: DISTANCE: -1.0 @@ -1020,7 +1020,7 @@ tests: geometry: precision: 7 - - algorithm: qgis:offsetline + - algorithm: native:offsetline name: Offset line miter params: DISTANCE: 1.0 @@ -1038,7 +1038,7 @@ tests: geometry: precision: 7 - - algorithm: qgis:offsetline + - algorithm: native:offsetline name: Offset line bevel params: DISTANCE: 1.0 @@ -1056,7 +1056,7 @@ tests: geometry: precision: 7 - - algorithm: qgis:offsetline + - algorithm: native:offsetline name: Offset multilines params: DISTANCE: 1.0 diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index 45861b9b63b..d8127d99e43 100755 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -58,6 +58,7 @@ SET(QGIS_ANALYSIS_SRCS processing/qgsalgorithmminimumenclosingcircle.cpp processing/qgsalgorithmmultiparttosinglepart.cpp processing/qgsalgorithmmultiringconstantbuffer.cpp + processing/qgsalgorithmoffsetlines.cpp processing/qgsalgorithmorderbyexpression.cpp processing/qgsalgorithmorientedminimumboundingbox.cpp processing/qgsalgorithmpackage.cpp diff --git a/src/analysis/processing/qgsalgorithmoffsetlines.cpp b/src/analysis/processing/qgsalgorithmoffsetlines.cpp new file mode 100644 index 00000000000..624b12e0c1e --- /dev/null +++ b/src/analysis/processing/qgsalgorithmoffsetlines.cpp @@ -0,0 +1,139 @@ +/*************************************************************************** + qgsalgorithmoffsetlines.cpp + --------------------- + begin : July 2018 + copyright : (C) 2018 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. * + * * + ***************************************************************************/ + +#include "qgsalgorithmoffsetlines.h" + +///@cond PRIVATE + +QString QgsOffsetLinesAlgorithm::name() const +{ + return QStringLiteral( "offsetline" ); +} + +QString QgsOffsetLinesAlgorithm::displayName() const +{ + return QObject::tr( "Offset lines" ); +} + +QStringList QgsOffsetLinesAlgorithm::tags() const +{ + return QObject::tr( "offset,linestring" ).split( ',' ); +} + +QString QgsOffsetLinesAlgorithm::group() const +{ + return QObject::tr( "Vector geometry" ); +} + +QString QgsOffsetLinesAlgorithm::groupId() const +{ + return QStringLiteral( "vectorgeometry" ); +} + +QString QgsOffsetLinesAlgorithm::outputName() const +{ + return QObject::tr( "Offset" ); +} + +QString QgsOffsetLinesAlgorithm::shortHelpString() const +{ + return QObject::tr( "This algorithm offsets lines by a specified distance. Positive distances will offset lines to the left, and negative distances " + "will offset to the right of lines.\n\n" + "The segments parameter controls the number of line segments to use to approximate a quarter circle when creating rounded offsets.\n\n" + "The join style parameter specifies whether round, miter or beveled joins should be used when offsetting corners in a line.\n\n" + "The miter limit parameter is only applicable for miter join styles, and controls the maximum distance from the offset curve to " + "use when creating a mitered join." ); +} + +QString QgsOffsetLinesAlgorithm::shortDescription() const +{ + return QObject::tr( "Offsets lines by a specified distance." ); +} + +QgsOffsetLinesAlgorithm *QgsOffsetLinesAlgorithm::createInstance() const +{ + return new QgsOffsetLinesAlgorithm(); +} + +void QgsOffsetLinesAlgorithm::initParameters( const QVariantMap & ) +{ + std::unique_ptr< QgsProcessingParameterDistance > offset = qgis::make_unique< QgsProcessingParameterDistance >( QStringLiteral( "DISTANCE" ), + QObject::tr( "Distance" ), + 10.0, QStringLiteral( "INPUT" ) ); + offset->setIsDynamic( true ); + offset->setDynamicPropertyDefinition( QgsPropertyDefinition( QStringLiteral( "DISTANCE" ), QObject::tr( "Distance" ), QgsPropertyDefinition::Double ) ); + offset->setDynamicLayerParameterName( QStringLiteral( "INPUT" ) ); + addParameter( offset.release() ); + + auto segmentParam = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "SEGMENTS" ), QObject::tr( "Segments" ), QgsProcessingParameterNumber::Integer, 8, false, 1 ); + addParameter( segmentParam.release() ); + + auto joinStyleParam = qgis::make_unique< QgsProcessingParameterEnum>( QStringLiteral( "JOIN_STYLE" ), QObject::tr( "Join style" ), QStringList() << QObject::tr( "Round" ) << QObject::tr( "Miter" ) << QObject::tr( "Bevel" ), false, 0 ); + addParameter( joinStyleParam.release() ); + + auto miterLimitParam = qgis::make_unique< QgsProcessingParameterNumber >( QStringLiteral( "MITER_LIMIT" ), QObject::tr( "Miter limit" ), QgsProcessingParameterNumber::Double, 2, false, 1 ); + addParameter( miterLimitParam.release() ); +} + +QList QgsOffsetLinesAlgorithm::inputLayerTypes() const +{ + return QList< int >() << QgsProcessing::TypeVectorLine; +} + +QgsProcessing::SourceType QgsOffsetLinesAlgorithm::outputLayerType() const +{ + return QgsProcessing::TypeVectorLine; +} + +bool QgsOffsetLinesAlgorithm::prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback * ) +{ + mOffset = parameterAsDouble( parameters, QStringLiteral( "DISTANCE" ), context ); + mDynamicOffset = QgsProcessingParameters::isDynamic( parameters, QStringLiteral( "DISTANCE" ) ); + if ( mDynamicOffset ) + mOffsetProperty = parameters.value( QStringLiteral( "DISTANCE" ) ).value< QgsProperty >(); + + mSegments = parameterAsInt( parameters, QStringLiteral( "SEGMENTS" ), context ); + mJoinStyle = static_cast< QgsGeometry::JoinStyle>( 1 + parameterAsInt( parameters, QStringLiteral( "JOIN_STYLE" ), context ) ); + mMiterLimit = parameterAsDouble( parameters, QStringLiteral( "MITER_LIMIT" ), context ); + + return true; +} + +QgsFeatureList QgsOffsetLinesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * ) +{ + if ( feature.hasGeometry() ) + { + QgsFeature f = feature; + const QgsGeometry geometry = feature.geometry(); + + double offset = mOffset; + if ( mDynamicOffset ) + offset = mOffsetProperty.valueAsDouble( context.expressionContext(), offset ); + + const QgsGeometry offsetGeometry = geometry.offsetCurve( offset, mSegments, mJoinStyle, mMiterLimit ); + f.setGeometry( offsetGeometry ); + return QgsFeatureList() << f; + } + else + { + return QgsFeatureList() << feature; + } +} + +///@endcond + + diff --git a/src/analysis/processing/qgsalgorithmoffsetlines.h b/src/analysis/processing/qgsalgorithmoffsetlines.h new file mode 100644 index 00000000000..7d837ab8cd1 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmoffsetlines.h @@ -0,0 +1,72 @@ +/*************************************************************************** + qgsalgorithmoffsetlines.h + --------------------- + begin : July 2018 + copyright : (C) 2018 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. * + * * + ***************************************************************************/ + +#ifndef QGSALGORITHMOFFSETLINES_H +#define QGSALGORITHMOFFSETLINES_H + +#define SIP_NO_FILE + +#include "qgis.h" +#include "qgsprocessingalgorithm.h" + +///@cond PRIVATE + +/** + * Native offset lines algorithm. + */ +class QgsOffsetLinesAlgorithm : public QgsProcessingFeatureBasedAlgorithm +{ + + public: + + QgsOffsetLinesAlgorithm() = default; + QString name() const override; + QString displayName() const override; + QStringList tags() const override; + QString group() const override; + QString groupId() const override; + QString shortHelpString() const override; + QString shortDescription() const override; + QgsOffsetLinesAlgorithm *createInstance() const override SIP_FACTORY; + void initParameters( const QVariantMap &configuration = QVariantMap() ) override; + QList inputLayerTypes() const override; + QgsProcessing::SourceType outputLayerType() const override; + + protected: + QString outputName() const override; + bool prepareAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + + private: + + double mOffset = 0.0; + bool mDynamicOffset = false; + QgsProperty mOffsetProperty; + + int mSegments = 8; + QgsGeometry::JoinStyle mJoinStyle = QgsGeometry::JoinStyleRound; + double mMiterLimit = 2; + + +}; + + +///@endcond PRIVATE + +#endif // QGSALGORITHMOFFSETLINES_H + + diff --git a/src/analysis/processing/qgsnativealgorithms.cpp b/src/analysis/processing/qgsnativealgorithms.cpp index 4f144d4bb0d..31f878e6df8 100644 --- a/src/analysis/processing/qgsnativealgorithms.cpp +++ b/src/analysis/processing/qgsnativealgorithms.cpp @@ -55,6 +55,7 @@ #include "qgsalgorithmminimumenclosingcircle.h" #include "qgsalgorithmmultiparttosinglepart.h" #include "qgsalgorithmmultiringconstantbuffer.h" +#include "qgsalgorithmoffsetlines.h" #include "qgsalgorithmorderbyexpression.h" #include "qgsalgorithmorientedminimumboundingbox.h" #include "qgsalgorithmpackage.h" @@ -171,6 +172,7 @@ void QgsNativeAlgorithms::loadAlgorithms() addAlgorithm( new QgsMinimumEnclosingCircleAlgorithm() ); addAlgorithm( new QgsMultipartToSinglepartAlgorithm() ); addAlgorithm( new QgsMultiRingConstantBufferAlgorithm() ); + addAlgorithm( new QgsOffsetLinesAlgorithm() ); addAlgorithm( new QgsOrderByExpressionAlgorithm() ); addAlgorithm( new QgsOrientedMinimumBoundingBoxAlgorithm() ); addAlgorithm( new QgsPackageAlgorithm() );