[processing] port Polygonize algorithm to C++

This commit is contained in:
Alexander Bruy 2020-05-11 15:19:36 +03:00
parent c0e8178366
commit b4a52d38c2
6 changed files with 198 additions and 125 deletions

View File

@ -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}

View File

@ -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(),

View File

@ -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

View File

@ -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 &parameters, 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<QgsGeometry> 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

View File

@ -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 &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
};
///@endcond PRIVATE
#endif // QGSALGORITHMPOLYGONIZE_H

View File

@ -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() );