diff --git a/python/plugins/processing/algs/qgis/Polygonize.py b/python/plugins/processing/algs/qgis/Polygonize.py deleted file mode 100644 index 591b1c57888..00000000000 --- a/python/plugins/processing/algs/qgis/Polygonize.py +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -*************************************************************************** - Polygonize.py - --------------------- - Date : March 2013 - Copyright : (C) 2013 by Piotr Pociask - Email : ppociask at o2 dot pl -*************************************************************************** -* * -* 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__ = 'Piotr Pociask' -__date__ = 'March 2013' -__copyright__ = '(C) 2013, Piotr Pociask' - -from qgis.PyQt.QtCore import QCoreApplication -from qgis.core import (QgsFields, - QgsFeature, - QgsFeatureSink, - QgsGeometry, - QgsWkbTypes, - QgsFeatureRequest, - QgsProcessing, - QgsProcessingException, - QgsProcessingParameterFeatureSource, - QgsProcessingParameterBoolean, - QgsProcessingParameterFeatureSink) -from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm - - -class Polygonize(QgisAlgorithm): - INPUT = 'INPUT' - OUTPUT = 'OUTPUT' - KEEP_FIELDS = 'KEEP_FIELDS' - - def tags(self): - return self.tr('create,lines,polygons,convert').split(',') - - def group(self): - return self.tr('Vector geometry') - - def groupId(self): - return 'vectorgeometry' - - def __init__(self): - super().__init__() - - def initAlgorithm(self, config=None): - self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT, - self.tr('Input layer'), types=[QgsProcessing.TypeVectorLine])) - self.addParameter(QgsProcessingParameterBoolean(self.KEEP_FIELDS, - self.tr('Keep table structure of line layer'), defaultValue=False, optional=True)) - self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT, self.tr('Polygons from lines'), QgsProcessing.TypeVectorPolygon)) - - def name(self): - return 'polygonize' - - def displayName(self): - return self.tr('Polygonize') - - def processAlgorithm(self, parameters, context, feedback): - source = self.parameterAsSource(parameters, self.INPUT, context) - if source is None: - raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT)) - - if self.parameterAsBoolean(parameters, self.KEEP_FIELDS, context): - fields = source.fields() - else: - fields = QgsFields() - - (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context, - fields, QgsWkbTypes.Polygon, source.sourceCrs()) - if sink is None: - raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT)) - - allLinesList = [] - features = source.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([])) - feedback.pushInfo(QCoreApplication.translate('Polygonize', 'Processing lines…')) - total = (40.0 / source.featureCount()) if source.featureCount() else 1 - for current, inFeat in enumerate(features): - if feedback.isCanceled(): - break - - if inFeat.geometry(): - allLinesList.append(inFeat.geometry()) - feedback.setProgress(int(current * total)) - - feedback.setProgress(40) - - feedback.pushInfo(QCoreApplication.translate('Polygonize', 'Noding lines…')) - allLines = QgsGeometry.unaryUnion(allLinesList) - if feedback.isCanceled(): - return {} - - feedback.setProgress(45) - feedback.pushInfo(QCoreApplication.translate('Polygonize', 'Polygonizing…')) - polygons = QgsGeometry.polygonize([allLines]) - if polygons.isEmpty(): - feedback.reportError(self.tr('No polygons were created!')) - feedback.setProgress(50) - - if not polygons.isEmpty(): - feedback.pushInfo(QCoreApplication.translate('Polygonize', 'Saving polygons…')) - total = 50.0 / polygons.constGet().numGeometries() - for i in range(polygons.constGet().numGeometries()): - if feedback.isCanceled(): - break - - outFeat = QgsFeature() - geom = QgsGeometry(polygons.constGet().geometryN(i).clone()) - outFeat.setGeometry(geom) - sink.addFeature(outFeat, QgsFeatureSink.FastInsert) - feedback.setProgress(50 + int(current * total)) - - return {self.OUTPUT: dest_id} diff --git a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py index 55bf54d7b6e..a44bf55f7d9 100644 --- a/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py +++ b/python/plugins/processing/algs/qgis/QgisAlgorithmProvider.py @@ -63,7 +63,6 @@ from .PointsDisplacement import PointsDisplacement from .PointsFromLines import PointsFromLines from .PointsToPaths import PointsToPaths from .PolarPlot import PolarPlot -from .Polygonize import Polygonize from .PostGISExecuteAndLoadSQL import PostGISExecuteAndLoadSQL from .RandomExtractWithinSubsets import RandomExtractWithinSubsets from .RandomPointsAlongLines import RandomPointsAlongLines @@ -141,7 +140,6 @@ class QgisAlgorithmProvider(QgsProcessingProvider): PointsFromLines(), PointsToPaths(), PolarPlot(), - Polygonize(), PostGISExecuteAndLoadSQL(), RandomExtractWithinSubsets(), RandomPointsAlongLines(), diff --git a/src/analysis/CMakeLists.txt b/src/analysis/CMakeLists.txt index a8327ed982f..ad044f67255 100644 --- a/src/analysis/CMakeLists.txt +++ b/src/analysis/CMakeLists.txt @@ -110,6 +110,7 @@ SET(QGIS_ANALYSIS_SRCS processing/qgsalgorithmpointsalonggeometry.cpp processing/qgsalgorithmpointslayerfromtable.cpp processing/qgsalgorithmpoleofinaccessibility.cpp + processing/qgsalgorithmpolygonize.cpp processing/qgsalgorithmprojectpointcartesian.cpp processing/qgsalgorithmpromotetomultipart.cpp processing/qgsalgorithmraiseexception.cpp diff --git a/src/analysis/processing/qgsalgorithmpolygonize.cpp b/src/analysis/processing/qgsalgorithmpolygonize.cpp new file mode 100644 index 00000000000..04d3459d088 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmpolygonize.cpp @@ -0,0 +1,141 @@ +/*************************************************************************** + qgsalgorithmdpolygonize.cpp + --------------------- + begin : May 2020 + copyright : (C) 2020 by Alexander Bruy + email : alexander dot bruy 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 "qgsalgorithmpolygonize.h" +#include "qgsgeometrycollection.h" + +///@cond PRIVATE + +QString QgsPolygonizeAlgorithm::name() const +{ + return QStringLiteral( "polygonize" ); +} + +QString QgsPolygonizeAlgorithm::displayName() const +{ + return QObject::tr( "Polygonize" ); +} + +QString QgsPolygonizeAlgorithm::shortHelpString() const +{ + return QObject::tr( "Creates a polygon layer from the input lines layer." ); +} + +QStringList QgsPolygonizeAlgorithm::tags() const +{ + return QObject::tr( "create,lines,polygons,convert" ).split( ',' ); +} + +QString QgsPolygonizeAlgorithm::group() const +{ + return QObject::tr( "Vector geometry" ); +} + +QString QgsPolygonizeAlgorithm::groupId() const +{ + return QStringLiteral( "vectorgeometry" ); +} + +void QgsPolygonizeAlgorithm::initAlgorithm( const QVariantMap & ) +{ + addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), + QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorLine ) ); + addParameter( new QgsProcessingParameterBoolean( QStringLiteral( "KEEP_FIELDS" ), + QObject::tr( "Keep fields from the input layer" ), false, true ) ); + addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), + QObject::tr( "Polygons" ), QgsProcessing::TypeVectorPolygon ) ); + addOutput( new QgsProcessingOutputNumber( QStringLiteral( "NUM_POLYGONS" ), QObject::tr( "Number of polygons" ) ) ); +} + +QgsPolygonizeAlgorithm *QgsPolygonizeAlgorithm::createInstance() const +{ + return new QgsPolygonizeAlgorithm(); +} + +QVariantMap QgsPolygonizeAlgorithm::processAlgorithm( const QVariantMap ¶meters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) +{ + std::unique_ptr< QgsProcessingFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) ); + if ( !source ) + throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) ); + + QgsFields fields = QgsFields(); + if ( parameterAsBoolean( parameters, QStringLiteral( "KEEP_FIELDS" ), context ) ) + fields = source->fields(); + + QString dest; + std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, QgsWkbTypes::Polygon, source->sourceCrs() ) ); + if ( !sink ) + throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) ); + + int polygonCount = 0; + + feedback->pushInfo( QObject::tr( "Collecting lines…" ) ); + int i = 0; + double step = source->featureCount() > 0 ? 40.0 / source->featureCount() : 1; + QgsFeature f; + QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest().setNoAttributes() ); + QVector linesList; + linesList.reserve( source->featureCount() ); + while ( features.nextFeature( f ) ) + { + if ( feedback->isCanceled() ) + break; + + if ( f.hasGeometry() ) + linesList << f.geometry(); + + feedback->setProgress( i * step ); + } + feedback->setProgress( 40 ); + + feedback->pushInfo( QObject::tr( "Noding lines…" ) ); + QgsGeometry lines = QgsGeometry::unaryUnion( linesList ); + if ( feedback->isCanceled() ) + return QVariantMap(); + feedback->setProgress( 45 ); + + feedback->pushInfo( QObject::tr( "Polygonizing…" ) ); + QgsGeometry polygons = QgsGeometry::polygonize( QVector< QgsGeometry >() << lines ); + if ( polygons.isEmpty() ) + feedback->reportError( QObject::tr( "No polygons were created." ) ); + + feedback->setProgress( 50 ); + + if ( !polygons.isEmpty() ) + { + const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( polygons.constGet() ); + step = collection->numGeometries() > 0 ? 50.0 / collection->numGeometries() : 1; + for ( int part = 0; part < collection->numGeometries(); ++part ) + { + if ( feedback->isCanceled() ) + break; + + QgsFeature outFeat; + outFeat.setGeometry( QgsGeometry( collection->geometryN( part )->clone() ) ); + sink->addFeature( outFeat, QgsFeatureSink::FastInsert ); + feedback->setProgress( 50 + i * step ); + polygonCount += 1; + } + } + + QVariantMap outputs; + outputs.insert( QStringLiteral( "OUTPUT" ), dest ); + outputs.insert( QStringLiteral( "NUM_POLYGONS" ), polygonCount ); + return outputs; +} + +///@endcond diff --git a/src/analysis/processing/qgsalgorithmpolygonize.h b/src/analysis/processing/qgsalgorithmpolygonize.h new file mode 100644 index 00000000000..d723b6bb307 --- /dev/null +++ b/src/analysis/processing/qgsalgorithmpolygonize.h @@ -0,0 +1,54 @@ +/*************************************************************************** + qgsalgorithmpolygonize.h + --------------------- + begin : May 2020 + copyright : (C) 2020 by Alexander Bruy + email : alexander dot bruy 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 QGSALGORITHMPOLYGONIZE_H +#define QGSALGORITHMPOLYGONIZE_H + +#define SIP_NO_FILE + +#include "qgis_sip.h" +#include "qgsprocessingalgorithm.h" + +///@cond PRIVATE + +/** + * Native polygonize algorithm. + */ +class QgsPolygonizeAlgorithm : public QgsProcessingAlgorithm +{ + + public: + + QgsPolygonizeAlgorithm() = default; + void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override; + QString name() const override; + QString displayName() const override; + QStringList tags() const override; + QString group() const override; + QString groupId() const override; + QString shortHelpString() const override; + QgsPolygonizeAlgorithm *createInstance() const override SIP_FACTORY; + + protected: + + QVariantMap processAlgorithm( const QVariantMap ¶meters, + QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override; +}; + +///@endcond PRIVATE + +#endif // QGSALGORITHMPOLYGONIZE_H diff --git a/src/analysis/processing/qgsnativealgorithms.cpp b/src/analysis/processing/qgsnativealgorithms.cpp index 6774351825e..62760bf9102 100644 --- a/src/analysis/processing/qgsnativealgorithms.cpp +++ b/src/analysis/processing/qgsnativealgorithms.cpp @@ -104,6 +104,7 @@ #include "qgsalgorithmpointsalonggeometry.h" #include "qgsalgorithmpointslayerfromtable.h" #include "qgsalgorithmpoleofinaccessibility.h" +#include "qgsalgorithmpolygonize.h" #include "qgsalgorithmprojectpointcartesian.h" #include "qgsalgorithmpromotetomultipart.h" #include "qgsalgorithmraiseexception.h" @@ -313,6 +314,7 @@ void QgsNativeAlgorithms::loadAlgorithms() addAlgorithm( new QgsPointsAlongGeometryAlgorithm() ); addAlgorithm( new QgsPointsLayerFromTableAlgorithm() ); addAlgorithm( new QgsPoleOfInaccessibilityAlgorithm() ); + addAlgorithm( new QgsPolygonizeAlgorithm() ); addAlgorithm( new QgsProjectPointCartesianAlgorithm() ); addAlgorithm( new QgsPromoteToMultipartAlgorithm() ); addAlgorithm( new QgsRaiseExceptionAlgorithm() );