Skip to content
Permalink
Browse files

Port Explode algorithm to new API

Improvements:
- Keep Z/M values if present
- Add unit tests
  • Loading branch information
nyalldawson committed Jul 27, 2017
1 parent 9b3f8a8 commit 516249cea761793f0574b1ec7f5380ec80344679
@@ -30,12 +30,11 @@
QgsGeometry,
QgsFeatureSink,
QgsWkbTypes,
QgsApplication,
QgsProcessingUtils)
QgsProcessing,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsLineString)
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.outputs import OutputVector
from processing.tools import dataobjects


class Explode(QgisAlgorithm):
@@ -50,10 +49,10 @@ def __init__(self):
super().__init__()

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT,
self.tr('Input layer'),
[dataobjects.TYPE_VECTOR_LINE]))
self.addOutput(OutputVector(self.OUTPUT, self.tr('Exploded'), datatype=[dataobjects.TYPE_VECTOR_LINE]))
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer'), [QgsProcessing.TypeVectorLine]))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('Exploded'), QgsProcessing.TypeVectorLine))

def name(self):
return 'explodelines'
@@ -62,40 +61,46 @@ def displayName(self):
return self.tr('Explode lines')

def processAlgorithm(self, parameters, context, feedback):
vlayer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT), context)
output = self.getOutputFromName(self.OUTPUT)
fields = vlayer.fields()
writer = output.getVectorWriter(fields, QgsWkbTypes.LineString, vlayer.crs(), context)
outFeat = QgsFeature()
features = QgsProcessingUtils.getFeatures(vlayer, context)
total = 100.0 / vlayer.featureCount() if vlayer.featureCount() else 0
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()
atMap = feature.attributes()
segments = self.extractAsSingleSegments(inGeom)
outFeat.setAttributes(atMap)
outFeat.setAttributes(feature.attributes())
for segment in segments:
outFeat.setGeometry(segment)
writer.addFeature(outFeat, QgsFeatureSink.FastInsert)
del writer
sink.addFeature(outFeat, QgsFeatureSink.FastInsert)
return {self.OUTPUT: dest_id}

def extractAsSingleSegments(self, geom):
segments = []
if geom.isMultipart():
multi = geom.asMultiPolyline()
for polyline in multi:
segments.extend(self.getPolylineAsSingleSegments(polyline))
for part in range(geom.geometry().numGeometries()):
segments.extend(self.getPolylineAsSingleSegments(geom.geometry().geometryN(part)))
else:
segments.extend(self.getPolylineAsSingleSegments(
geom.asPolyline()))
geom.geometry()))
return segments

def getPolylineAsSingleSegments(self, polyline):
segments = []
for i in range(len(polyline) - 1):
ptA = polyline[i]
ptB = polyline[i + 1]
segment = QgsGeometry.fromPolyline([ptA, ptB])
for i in range(polyline.numPoints() - 1):
ptA = polyline.pointN(i)
ptB = polyline.pointN(i + 1)
segment = QgsGeometry(QgsLineString([ptA, ptB]))
segments.append(segment)
return segments
@@ -57,6 +57,7 @@
from .Difference import Difference
from .DropGeometry import DropGeometry
from .DropMZValues import DropMZValues
from .Explode import Explode
from .ExportGeometryInfo import ExportGeometryInfo
from .ExtendLines import ExtendLines
from .ExtentFromLayer import ExtentFromLayer
@@ -142,7 +143,6 @@
# from .StatisticsByCategories import StatisticsByCategories
# from .EquivalentNumField import EquivalentNumField
# from .FieldsCalculator import FieldsCalculator
# from .Explode import Explode
# from .FieldPyculator import FieldsPyculator
# from .JoinAttributes import JoinAttributes
# from .CreateConstantRaster import CreateConstantRaster
@@ -197,7 +197,7 @@ def getAlgs(self):
# HubDistanceLines(), HubLines(),
# GeometryConvert(), FieldsCalculator(),
# JoinAttributes(),
# Explode(), FieldsPyculator(),
# FieldsPyculator(),
# EquivalentNumField(),
# StatisticsByCategories(),
# RasterLayerStatistics(), PointsDisplacement(),
@@ -236,6 +236,7 @@ def getAlgs(self):
Difference(),
DropGeometry(),
DropMZValues(),
Explode(),
ExportGeometryInfo(),
ExtendLines(),
ExtentFromLayer(),
@@ -0,0 +1,16 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>explode_lines</Name>
<ElementPath>explode_lines</ElementPath>
<!--LINESTRING-->
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>11</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>11.00000</ExtentXMax>
<ExtentYMin>-3.00000</ExtentYMin>
<ExtentYMax>5.00000</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ explode_lines.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-3</gml:Y></gml:coord>
<gml:coord><gml:X>11</gml:X><gml:Y>5</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:explode_lines fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,2 9,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>9,2 9,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>9,3 11,5</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.4">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 1,-1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,0 2,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.6">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,2 3,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.7">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,2 3,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.8">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,1 5,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.9">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>7,-3 10,-3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.10">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>6,-3 10,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_lines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_lines fid="lines.11">
</ogr:explode_lines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,16 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>explode_multilines</Name>
<ElementPath>explode_multilines</ElementPath>
<!--LINESTRING-->
<GeometryType>2</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>9</FeatureCount>
<ExtentXMin>-1.00000</ExtentXMin>
<ExtentXMax>5.58042</ExtentXMax>
<ExtentYMin>-1.00000</ExtentYMin>
<ExtentYMax>4.11977</ExtentYMax>
</DatasetSpecificInfo>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ explode_multilines.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-1</gml:X><gml:Y>-1</gml:Y></gml:coord>
<gml:coord><gml:X>5.58042226487524</gml:X><gml:Y>4.119769673704415</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:explode_multilines fid="lines.1">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>-1,-1 1,-1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.2">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,1 5,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.3">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>5.02418426103647,2.4147792706334 5,1</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.4">
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.5">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,0 2,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.6">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2,2 3,2</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.7">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,2 3,3</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.8">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>2.94433781190019,4.04721689059501 5.4595009596929,4.11976967370441</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
<gml:featureMember>
<ogr:explode_multilines fid="lines.9">
<ogr:geometryProperty><gml:LineString srsName="EPSG:4326"><gml:coordinates>3,3 5.58042226487524,2.9468330134357</gml:coordinates></gml:LineString></ogr:geometryProperty>
</ogr:explode_multilines>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -2428,6 +2428,34 @@ tests:
name: expected/voronoi_buffer.gml
type: vector

- algorithm: qgis:explodelines
name: Explode lines
params:
INPUT:
name: lines.gml
type: vector
results:
OUTPUT:
name: expected/explode_lines.gml
type: vector
compare:
fields:
fid: skip

- algorithm: qgis:explodelines
name: Explode multilines
params:
INPUT:
name: multilines.gml
type: vector
results:
OUTPUT:
name: expected/explode_multilines.gml
type: vector
compare:
fields:
fid: skip

# - algorithm: qgis:findprojection
# name: Find projection
# params:

0 comments on commit 516249c

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