Skip to content
Permalink
Browse files

[processing] Port Explode Lines to c++

Aside from the performance benefits, the Python version of this
algorithm occasionally fails on Travis with odd errors. Hopefully
by porting to c++ it will fix these, or at least give useful
debug information in the event of a fail.

Also add support for curved input geometries.
  • Loading branch information
nyalldawson committed Apr 6, 2018
1 parent fa051d5 commit 1942854166cbb34664374019f3c50409e80e5e88
@@ -157,9 +157,6 @@ qgis:eliminateselectedpolygons: >
This algorithm combines selected polygons of the input layer with certain adjacent polygons by erasing their common boundary. The adjacent polygon can be either the one with the largest or smallest area or the one sharing the largest common boundary with the polygon to be eliminated. The selected features will always be eliminated whether the option "Use only selected features" is set or not.
Eliminate is normally used to get rid of sliver polygons, i.e. tiny polygons that are a result of polygon intersection processes where boundaries of the inputs are similar but not identical.

qgis:explodelines: >
This algorithm takes a lines layer and creates a new one in which each line is replaced by a set of lines representing the segments in the original line. Each line in the resulting layer contains only a start and an end point, with no intermediate nodes between them.

qgis:exportaddgeometrycolumns: >
This algorithm computes geometric properties of the features in a vector layer. It generates a new vector layer with the same content as the input one, but with additional attributes in its attributes table, containing geometric measurements.

This file was deleted.

@@ -60,7 +60,6 @@
from .Difference import Difference
from .EliminateSelection import EliminateSelection
from .ExecuteSQL import ExecuteSQL
from .Explode import Explode
from .ExportGeometryInfo import ExportGeometryInfo
from .ExtendLines import ExtendLines
from .ExtentFromLayer import ExtentFromLayer
@@ -180,7 +179,6 @@ def getAlgs(self):
Difference(),
EliminateSelection(),
ExecuteSQL(),
Explode(),
ExportGeometryInfo(),
ExtendLines(),
ExtentFromLayer(),
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137,298.257223563]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]]
@@ -0,0 +1 @@
GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],AUTHORITY["EPSG","6326"]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],AUTHORITY["EPSG","4326"]]
Binary file not shown.
Binary file not shown.
@@ -3477,7 +3477,7 @@ tests:
name: expected/voronoi_buffer.gml
type: vector

- algorithm: qgis:explodelines
- algorithm: native:explodelines
name: Explode lines
params:
INPUT:
@@ -3491,7 +3491,7 @@ tests:
fields:
fid: skip

- algorithm: qgis:explodelines
- algorithm: native:explodelines
name: Explode multilines
params:
INPUT:
@@ -3505,6 +3505,17 @@ tests:
fields:
fid: skip

- algorithm: native:explodelines
name: Explode compound curves
params:
INPUT:
name: custom/circular_strings.gpkg|layername=circular_strings_with_line
type: vector
results:
OUTPUT:
name: expected/explode_compound_curve.shp
type: vector

- algorithm: qgis:findprojection
name: Find projection
params:
@@ -30,6 +30,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmdissolve.cpp
processing/qgsalgorithmdropgeometry.cpp
processing/qgsalgorithmdropmzvalues.cpp
processing/qgsalgorithmexplode.cpp
processing/qgsalgorithmextenttolayer.cpp
processing/qgsalgorithmextractbyattribute.cpp
processing/qgsalgorithmextractbyexpression.cpp
@@ -0,0 +1,201 @@
/***************************************************************************
qgsalgorithmexplode.cpp
---------------------
begin : April 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 "qgsalgorithmexplode.h"
#include "qgscurve.h"
#include "qgslinestring.h"
#include "qgscircularstring.h"
#include "qgscompoundcurve.h"
#include "qgsgeometrycollection.h"

///@cond PRIVATE

QString QgsExplodeAlgorithm::name() const
{
return QStringLiteral( "explodelines" );
}

QString QgsExplodeAlgorithm::displayName() const
{
return QObject::tr( "Explode lines" );
}

QStringList QgsExplodeAlgorithm::tags() const
{
return QObject::tr( "segments,parts" ).split( ',' );
}

QString QgsExplodeAlgorithm::group() const
{
return QObject::tr( "Vector geometry" );
}

QString QgsExplodeAlgorithm::groupId() const
{
return QStringLiteral( "vectorgeometry" );
}

QString QgsExplodeAlgorithm::shortHelpString() const
{
return QObject::tr( "This algorithm takes a lines layer and creates a new one in which each line is replaced by a set of "
"lines representing the segments in the original line. Each line in the resulting layer contains only a "
"start and an end point, with no intermediate nodes between them.\n\n"
"If the input layer consists of CircularStrings or CompoundCurves, the output layer will be of the "
"same type and contain only single curve segments." );
}

QList<int> QgsExplodeAlgorithm::inputLayerTypes() const
{
return QList<int>() << QgsProcessing::TypeVectorLine;
}

QgsProcessing::SourceType QgsExplodeAlgorithm::outputLayerType() const
{
return QgsProcessing::TypeVectorLine;
}

QgsExplodeAlgorithm *QgsExplodeAlgorithm::createInstance() const
{
return new QgsExplodeAlgorithm();
}

QString QgsExplodeAlgorithm::outputName() const
{
return QObject::tr( "Exploded" );
}

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

QgsFeatureList QgsExplodeAlgorithm::processFeature( const QgsFeature &f, QgsProcessingContext &, QgsProcessingFeedback * )
{
if ( !f.hasGeometry() )
{
return QgsFeatureList() << f;
}
else
{
const std::vector<QgsGeometry> parts = extractAsParts( f.geometry() );
QgsFeature outputFeature;
QgsFeatureList features;
features.reserve( parts.size() );
for ( const QgsGeometry &part : parts )
{
outputFeature.setAttributes( f.attributes() );
outputFeature.setGeometry( part );
features << outputFeature;
}
return features;
}
}

std::vector<QgsGeometry> QgsExplodeAlgorithm::extractAsParts( const QgsGeometry &geometry ) const
{
if ( geometry.isMultipart() )
{
std::vector<QgsGeometry> parts;
const QgsGeometryCollection *collection = qgsgeometry_cast< const QgsGeometryCollection * >( geometry.constGet() );
for ( int part = 0; part < collection->numGeometries(); ++part )
{
std::vector<QgsGeometry> segments = curveAsSingleSegments( qgsgeometry_cast< const QgsCurve * >( collection->geometryN( part ) ) );
parts.reserve( parts.size() + segments.size() );
std::move( std::begin( segments ), std::end( segments ), std::back_inserter( parts ) );
}
return parts;
}
else
{
return curveAsSingleSegments( qgsgeometry_cast< const QgsCurve * >( geometry.constGet() ) );
}
}

std::vector<QgsGeometry> QgsExplodeAlgorithm::curveAsSingleSegments( const QgsCurve *curve, bool useCompoundCurves ) const
{
std::vector<QgsGeometry> parts;
switch ( QgsWkbTypes::flatType( curve->wkbType() ) )
{
case QgsWkbTypes::LineString:
{
const QgsLineString *line = qgsgeometry_cast< const QgsLineString * >( curve );
for ( int i = 0; i < line->numPoints() - 1; ++i )
{
QgsPoint ptA = line->pointN( i );
QgsPoint ptB = line->pointN( i + 1 );
std::unique_ptr< QgsLineString > ls = qgis::make_unique< QgsLineString >( QVector< QgsPoint >() << ptA << ptB );
if ( !useCompoundCurves )
{
parts.emplace_back( QgsGeometry( std::move( ls ) ) );
}
else
{
std::unique_ptr< QgsCompoundCurve > cc = qgis::make_unique< QgsCompoundCurve >();
cc->addCurve( ls.release() );
parts.emplace_back( QgsGeometry( std::move( cc ) ) );
}
}
break;
}

case QgsWkbTypes::CircularString:
{
const QgsCircularString *string = qgsgeometry_cast< const QgsCircularString * >( curve );
for ( int i = 0; i < string->numPoints() - 2; i += 2 )
{
QgsPoint ptA = string->pointN( i );
QgsPoint ptB = string->pointN( i + 1 );
QgsPoint ptC = string->pointN( i + 2 );
std::unique_ptr< QgsCircularString > cs = qgis::make_unique< QgsCircularString >();
cs->setPoints( QgsPointSequence() << ptA << ptB << ptC );
if ( !useCompoundCurves )
{
parts.emplace_back( QgsGeometry( std::move( cs ) ) );
}
else
{
std::unique_ptr< QgsCompoundCurve > cc = qgis::make_unique< QgsCompoundCurve >();
cc->addCurve( cs.release() );
parts.emplace_back( QgsGeometry( std::move( cc ) ) );
}
}
break;
}

case QgsWkbTypes::CompoundCurve:
{
const QgsCompoundCurve *compoundCurve = qgsgeometry_cast< QgsCompoundCurve * >( curve );
for ( int i = 0; i < compoundCurve->nCurves(); ++i )
{
std::vector<QgsGeometry> segments = curveAsSingleSegments( compoundCurve->curveAt( i ), true );
parts.reserve( parts.size() + segments.size() );
std::move( std::begin( segments ), std::end( segments ), std::back_inserter( parts ) );
}
break;
}

default:
break;

}
return parts;
}

///@endcond



0 comments on commit 1942854

Please sign in to comment.
You can’t perform that action at this time.