Skip to content

Commit

Permalink
[processing] Split multiparts and explode are feature based algorithms
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Feb 20, 2018
1 parent 43cd62b commit 585a4d3
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 96 deletions.
59 changes: 25 additions & 34 deletions python/plugins/processing/algs/qgis/Explode.py
Expand Up @@ -30,13 +30,11 @@
QgsFeatureSink,
QgsWkbTypes,
QgsProcessing,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsLineString)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.algs.qgis.QgisAlgorithm import QgisFeatureBasedAlgorithm


class Explode(QgisAlgorithm):
class Explode(QgisFeatureBasedAlgorithm):

INPUT = 'INPUT'
OUTPUT = 'OUTPUT'
Expand All @@ -50,43 +48,36 @@ def groupId(self):
def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Exploded'), QgsProcessing.TypeVectorLine))
def inputLayerTypes(self):
return [QgsProcessing.TypeVectorLine]

def outputName(self):
return self.tr('Exploded')

def outputWkbType(self, inputWkb):
return QgsWkbTypes.singleType(inputWkb)

def outputLayerType(self):
return QgsProcessing.TypeVectorLine

def name(self):
return 'explodelines'

def displayName(self):
return self.tr('Explode lines')

def processAlgorithm(self, parameters, context, feedback):
source = self.parameterAsSource(parameters, self.INPUT, context)
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
source.fields(), QgsWkbTypes.singleType(source.wkbType()), source.sourceCrs())

features = source.getFeatures()
total = 100.0 / source.featureCount() if source.featureCount() else 0
for current, feature in enumerate(features):
if feedback.isCanceled():
break

feedback.setProgress(int(current * total))

if not feature.hasGeometry():
sink.addFeature(feature, QgsFeatureSink.FastInsert)
continue

outFeat = QgsFeature()
inGeom = feature.geometry()
segments = self.extractAsSingleSegments(inGeom)
outFeat.setAttributes(feature.attributes())
for segment in segments:
outFeat.setGeometry(segment)
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
return {self.OUTPUT: dest_id}
def processFeature(self, feature, context, feedback):
if not feature.hasGeometry():
return [feature]

segments = self.extractAsSingleSegments(feature.geometry())
output_features = []
for segment in segments:
output_feature = QgsFeature()
output_feature.setAttributes(feature.attributes())
output_feature.setGeometry(segment)
output_features.append(output_feature)
return output_features

def extractAsSingleSegments(self, geom):
segments = []
Expand Down
84 changes: 26 additions & 58 deletions src/analysis/processing/qgsalgorithmmultiparttosinglepart.cpp
Expand Up @@ -29,6 +29,16 @@ QString QgsMultipartToSinglepartAlgorithm::displayName() const
return QObject::tr( "Multipart to singleparts" );
}

QString QgsMultipartToSinglepartAlgorithm::outputName() const
{
return QObject::tr( "Single parts" );
}

QgsWkbTypes::Type QgsMultipartToSinglepartAlgorithm::outputWkbType( QgsWkbTypes::Type inputWkbType ) const
{
return QgsWkbTypes::singleType( inputWkbType );
}

QStringList QgsMultipartToSinglepartAlgorithm::tags() const
{
return QObject::tr( "multi,single,multiple,split,dump" ).split( ',' );
Expand All @@ -44,13 +54,6 @@ QString QgsMultipartToSinglepartAlgorithm::groupId() const
return QStringLiteral( "vectorgeometry" );
}

void QgsMultipartToSinglepartAlgorithm::initAlgorithm( const QVariantMap & )
{
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );

addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Single parts" ) ) );
}

QString QgsMultipartToSinglepartAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm takes a vector layer with multipart geometries and generates a new one in which all geometries contain "
Expand All @@ -63,63 +66,28 @@ QgsMultipartToSinglepartAlgorithm *QgsMultipartToSinglepartAlgorithm::createInst
return new QgsMultipartToSinglepartAlgorithm();
}

QVariantMap QgsMultipartToSinglepartAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
QgsFeatureList QgsMultipartToSinglepartAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &, QgsProcessingFeedback * )
{
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
if ( !source )
return QVariantMap();

QgsWkbTypes::Type sinkType = QgsWkbTypes::singleType( source->wkbType() );

QString dest;
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, source->fields(),
sinkType, source->sourceCrs() ) );
if ( !sink )
return QVariantMap();
if ( !feature.hasGeometry() )
return QgsFeatureList() << feature;

long count = source->featureCount();

QgsFeature f;
QgsFeatureIterator it = source->getFeatures();

double step = count > 0 ? 100.0 / count : 1;
int current = 0;
while ( it.nextFeature( f ) )
QgsGeometry inputGeometry = feature.geometry();
QgsFeatureList outputs;
if ( inputGeometry.isMultipart() )
{
if ( feedback->isCanceled() )
{
break;
}

QgsFeature out = f;
if ( out.hasGeometry() )
const QVector<QgsGeometry> parts = inputGeometry.asGeometryCollection();
for ( const QgsGeometry &g : parts )
{
QgsGeometry inputGeometry = f.geometry();
if ( inputGeometry.isMultipart() )
{
Q_FOREACH ( const QgsGeometry &g, inputGeometry.asGeometryCollection() )
{
out.setGeometry( g );
sink->addFeature( out, QgsFeatureSink::FastInsert );
}
}
else
{
sink->addFeature( out, QgsFeatureSink::FastInsert );
}
QgsFeature out;
out.setAttributes( feature.attributes() );
out.setGeometry( g );
outputs.append( out );
}
else
{
// feature with null geometry
sink->addFeature( out, QgsFeatureSink::FastInsert );
}

feedback->setProgress( current * step );
current++;
}

QVariantMap outputs;
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
else
{
outputs.append( feature );
}
return outputs;
}

Expand Down
9 changes: 5 additions & 4 deletions src/analysis/processing/qgsalgorithmmultiparttosinglepart.h
Expand Up @@ -28,15 +28,16 @@
/**
* Native multipart to singlepart algorithm.
*/
class QgsMultipartToSinglepartAlgorithm : public QgsProcessingAlgorithm
class QgsMultipartToSinglepartAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{

public:

QgsMultipartToSinglepartAlgorithm() = default;
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
QString name() const override;
QString displayName() const override;
QString outputName() const override;
QgsWkbTypes::Type outputWkbType( QgsWkbTypes::Type inputWkbType ) const override;
QStringList tags() const override;
QString group() const override;
QString groupId() const override;
Expand All @@ -45,8 +46,8 @@ class QgsMultipartToSinglepartAlgorithm : public QgsProcessingAlgorithm

protected:

QVariantMap processAlgorithm( const QVariantMap &parameters,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
QgsFeatureList processFeature( const QgsFeature &feature,
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

};

Expand Down

0 comments on commit 585a4d3

Please sign in to comment.