From 4c8af20b51c988421ecf2c239fd2e3b9a5b95dc3 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Fri, 11 Jan 2019 23:28:58 +0100 Subject: [PATCH] Add native polygonstolines algorithm --- .../processing/algs/qgis/PolygonsToLines.py | 130 --------------- .../algs/qgis/QgisAlgorithmProvider.py | 2 - src/analysis/CMakeLists.txt | 1 + .../qgsalgorithmpolygonstolines.cpp | 150 ++++++++++++++++++ .../processing/qgsalgorithmpolygonstolines.h | 63 ++++++++ .../processing/qgsnativealgorithms.cpp | 3 +- 6 files changed, 216 insertions(+), 133 deletions(-) delete mode 100644 python/plugins/processing/algs/qgis/PolygonsToLines.py create mode 100644 src/analysis/processing/qgsalgorithmpolygonstolines.cpp create mode 100644 src/analysis/processing/qgsalgorithmpolygonstolines.h diff --git a/python/plugins/processing/algs/qgis/PolygonsToLines.py b/python/plugins/processing/algs/qgis/PolygonsToLines.py deleted file mode 100644 index ac5e2430a14..00000000000 --- a/python/plugins/processing/algs/qgis/PolygonsToLines.py +++ /dev/null @@ -1,130 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - PolygonsToLines.py - --------------------- - Date : August 2012 - Copyright : (C) 2012 by Victor Olaya - Email : volayaf 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__ = 'Victor Olaya' -__date__ = 'August 2012' -__copyright__ = '(C) 2012, Victor Olaya' - -# This will get replaced with a git SHA1 when you do a git archive - -__revision__ = '$Format:%H$' - -import os - -from qgis.PyQt.QtGui import QIcon - -from qgis.core import (QgsApplication, - QgsGeometry, - QgsGeometryCollection, - QgsMultiLineString, - QgsMultiCurve, - QgsWkbTypes, - QgsProcessing) - -from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm - -pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0] - - -class PolygonsToLines(QgisFeatureBasedAlgorithm): - - def icon(self): - return QgsApplication.getThemeIcon("/algorithms/mAlgorithmPolygonToLine.svg") - - def svgIconPath(self): - return QgsApplication.iconPath("/algorithms/mAlgorithmPolygonToLine.svg") - - def tags(self): - return self.tr('line,polygon,convert').split(',') - - def group(self): - return self.tr('Vector geometry') - - def groupId(self): - return 'vectorgeometry' - - def __init__(self): - super().__init__() - - def name(self): - return 'polygonstolines' - - def displayName(self): - return self.tr('Polygons to lines') - - def outputName(self): - return self.tr('Lines') - - def outputType(self): - return QgsProcessing.TypeVectorLine - - def inputLayerTypes(self): - return [QgsProcessing.TypeVectorPolygon] - - def outputWkbType(self, input_wkb_type): - return self.convertWkbToLines(input_wkb_type) - - def processFeature(self, feature, context, feedback): - if feature.hasGeometry(): - feature.setGeometry(QgsGeometry(self.convertToLines(feature.geometry()))) - return [feature] - - def supportInPlaceEdit(self, layer): - return False - - def convertWkbToLines(self, wkb): - multi_wkb = QgsWkbTypes.NoGeometry - if QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.Polygon: - multi_wkb = QgsWkbTypes.MultiLineString - elif QgsWkbTypes.singleType(QgsWkbTypes.flatType(wkb)) == QgsWkbTypes.CurvePolygon: - multi_wkb = QgsWkbTypes.MultiCurve - if QgsWkbTypes.hasM(wkb): - multi_wkb = QgsWkbTypes.addM(multi_wkb) - if QgsWkbTypes.hasZ(wkb): - multi_wkb = QgsWkbTypes.addZ(multi_wkb) - - return multi_wkb - - def convertToLines(self, geometry): - rings = self.getRings(geometry.constGet()) - output_wkb = self.convertWkbToLines(geometry.wkbType()) - out_geom = None - if QgsWkbTypes.flatType(output_wkb) == QgsWkbTypes.MultiLineString: - out_geom = QgsMultiLineString() - else: - out_geom = QgsMultiCurve() - - for ring in rings: - out_geom.addGeometry(ring) - - return out_geom - - def getRings(self, geometry): - rings = [] - if isinstance(geometry, QgsGeometryCollection): - # collection - for i in range(geometry.numGeometries()): - rings.extend(self.getRings(geometry.geometryN(i))) - else: - # not collection - rings.append(geometry.exteriorRing().clone()) - for i in range(geometry.numInteriorRings()): - rings.append(geometry.interiorRing(i).clone()) - - return rings diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py index 9d4326f7797..c302b46b752 100644 --- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py @@ -98,7 +98,6 @@ from .PointsLayerFromTable import PointsLayerFromTable from .PointsToPaths import PointsToPaths from .PoleOfInaccessibility import PoleOfInaccessibility from .Polygonize import Polygonize -from .PolygonsToLines import PolygonsToLines from .PostGISExecuteSQL import PostGISExecuteSQL from .PostGISExecuteAndLoadSQL import PostGISExecuteAndLoadSQL from .RandomExtract import RandomExtract @@ -210,7 +209,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider): PointsToPaths(), PoleOfInaccessibility(), Polygonize(), - PolygonsToLines(), PostGISExecuteSQL(), PostGISExecuteAndLoadSQL(), RandomExtract(), diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index ea41962c4b5..e68750bf962 100644 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -73,6 +73,7 @@ SET(QGIS_ANALYSIS_SRCS processing/qgsalgorithmorientedminimumboundingbox.cpp processing/qgsalgorithmpackage.cpp processing/qgsalgorithmarrayoffsetlines.cpp + processing/qgsalgorithmpolygonstolines.cpp processing/qgsalgorithmpointonsurface.cpp processing/qgsalgorithmprojectpointcartesian.cpp processing/qgsalgorithmpromotetomultipart.cpp diff --git a/src/analysis/processing/qgsalgorithmpolygonstolines.cpp b/src/analysis/processing/qgsalgorithmpolygonstolines.cpp new file mode 100644 index 00000000000..df1d5d92220 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmpolygonstolines.cpp @@ -0,0 +1,150 @@ +/*************************************************************************** + qgsalgorithmpolygonstolines.cpp + --------------------- + begin : January 2019 + copyright : (C) 2019 by Matthias Kuhn + email : matthias@opengis.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 "qgsalgorithmpolygonstolines.h" +#include "qgsgeometrycollection.h" +#include "qgscurvepolygon.h" +#include "qgscurve.h" +#include "qgsmultilinestring.h" + +///@cond PRIVATE + +QString QgsPolygonsToLinesAlgorithm::name() const +{ + return QStringLiteral( "polygonstolines" ); +} + +QString QgsPolygonsToLinesAlgorithm::displayName() const +{ + return QObject::tr( "Polygons to lines" ); +} + +QStringList QgsPolygonsToLinesAlgorithm::tags() const +{ + return QObject::tr( "line,polygon,convert" ).split( ',' ); +} + +QString QgsPolygonsToLinesAlgorithm::group() const +{ + return QObject::tr( "Vector creation" ); +} + +QString QgsPolygonsToLinesAlgorithm::groupId() const +{ + return QStringLiteral( "vectorgeometry" ); +} + +QString QgsPolygonsToLinesAlgorithm::outputName() const +{ + return QObject::tr( "Lines" ); +} + +QString QgsPolygonsToLinesAlgorithm::shortHelpString() const +{ + return QObject::tr( "Converts polygons to lines" ); +} + +QString QgsPolygonsToLinesAlgorithm::shortDescription() const +{ + return QObject::tr( "Converts polygons to lines." ); +} + +QgsPolygonsToLinesAlgorithm *QgsPolygonsToLinesAlgorithm::createInstance() const +{ + return new QgsPolygonsToLinesAlgorithm(); +} + +QList QgsPolygonsToLinesAlgorithm::inputLayerTypes() const +{ + return QList< int >() << QgsProcessing::TypeVectorPolygon; +} + +QgsFeatureList QgsPolygonsToLinesAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback * ) +{ + QgsFeatureList result; + QgsFeature feat = feature; + if ( feat.hasGeometry() ) + feat.setGeometry( convertToLines( feat.geometry() ) ); + + result << feat; + return result; +} + +QgsGeometry QgsPolygonsToLinesAlgorithm::convertToLines( const QgsGeometry &geometry ) const +{ + auto rings = extractRings( geometry.constGet() ); + + QgsWkbTypes::Type resultType = outWkbType( geometry.wkbType() ); + + std::unique_ptr lineGeometry; + + if ( QgsWkbTypes::flatType( resultType ) == QgsWkbTypes::MultiLineString ) + lineGeometry = qgis::make_unique(); + else + lineGeometry = qgis::make_unique(); + + for ( auto ring : qgis::as_const( rings ) ) + lineGeometry->addGeometry( ring ); + + return QgsGeometry( lineGeometry.release() ); +} + +QgsWkbTypes::Type QgsPolygonsToLinesAlgorithm::outWkbType( QgsWkbTypes::Type polygonWkbType ) const +{ + QgsWkbTypes::Type wkbType = QgsWkbTypes::NoGeometry; + + if ( QgsWkbTypes::singleType( QgsWkbTypes::flatType( polygonWkbType ) ) == QgsWkbTypes::Polygon ) + wkbType = QgsWkbTypes::MultiLineString; + else if ( QgsWkbTypes::singleType( QgsWkbTypes::flatType( polygonWkbType ) ) == QgsWkbTypes::CurvePolygon ) + wkbType = QgsWkbTypes::MultiCurve; + + if ( QgsWkbTypes::hasM( polygonWkbType ) ) + wkbType = QgsWkbTypes::addM( wkbType ); + if ( QgsWkbTypes::hasZ( polygonWkbType ) ) + wkbType = QgsWkbTypes::addZ( wkbType ); + + return wkbType; +} + +QList QgsPolygonsToLinesAlgorithm::extractRings( const QgsAbstractGeometry *geom ) const +{ + QList rings; + + if ( QgsGeometryCollection *collection = qgsgeometry_cast( geom ) ) + { + for ( int i = 0; i < collection->numGeometries(); ++i ) + { + rings.append( extractRings( collection->geometryN( i ) ) ); + } + } + else if ( QgsCurvePolygon *polygon = qgsgeometry_cast( geom ) ) + { + rings.append( polygon->exteriorRing()->clone() ); + for ( int i = 0; i < polygon->numInteriorRings(); ++i ) + { + rings.append( polygon->interiorRing( i )->clone() ); + } + } + + return rings; +} + + + +///@endcond + + diff --git a/src/analysis/processing/qgsalgorithmpolygonstolines.h b/src/analysis/processing/qgsalgorithmpolygonstolines.h new file mode 100644 index 00000000000..3696a4ade74 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmpolygonstolines.h @@ -0,0 +1,63 @@ +/*************************************************************************** + qgsalgorithmpolygontolines.h + --------------------- + begin : January 2019 + copyright : (C) 2019 by Matthias Kuhn + email : matthias@opengis.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 QGSALGORITHMPOLYGONSTOLINES_H +#define QGSALGORITHMPOLYGONSTOLINES_H + +#define SIP_NO_FILE + +#include "qgis.h" +#include "qgsprocessingalgorithm.h" + +///@cond PRIVATE + +/** + * Native convert polygons to lines algorithm + */ +class QgsPolygonsToLinesAlgorithm : public QgsProcessingFeatureBasedAlgorithm +{ + + public: + + QgsPolygonsToLinesAlgorithm() = 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; + QgsPolygonsToLinesAlgorithm *createInstance() const override SIP_FACTORY; + QList inputLayerTypes() const override; + + protected: + QString outputName() const override; + QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; + + private: + QgsGeometry convertToLines( const QgsGeometry &geometry ) const; + QList extractRings( const QgsAbstractGeometry *geom ) const; + QgsWkbTypes::Type outWkbType( QgsWkbTypes::Type polygonWkbType ) const; + + friend class TestQgsProcessingAlgs; +}; + +///@endcond PRIVATE + +#endif // QGSALGORITHMPOLYGONSTOLINES_H + + diff --git a/src/analysis/processing/qgsnativealgorithms.cpp b/src/analysis/processing/qgsnativealgorithms.cpp index 474db095a12..0ac49eb12bf 100644 --- a/src/analysis/processing/qgsnativealgorithms.cpp +++ b/src/analysis/processing/qgsnativealgorithms.cpp @@ -105,7 +105,7 @@ #include "qgsalgorithmvectorize.h" #include "qgsalgorithmwedgebuffers.h" #include "qgsalgorithmzonalhistogram.h" - +#include "qgsalgorithmpolygonstolines.h" ///@cond PRIVATE @@ -243,6 +243,7 @@ void QgsNativeAlgorithms::loadAlgorithms() addAlgorithm( new QgsVariableWidthBufferByMAlgorithm() ); addAlgorithm( new QgsWedgeBuffersAlgorithm() ); addAlgorithm( new QgsZonalHistogramAlgorithm() ); + addAlgorithm( new QgsPolygonsToLinesAlgorithm() ); }