Skip to content

Commit

Permalink
Port Explode algorithm to new API
Browse files Browse the repository at this point in the history
Improvements:
- Keep Z/M values if present
- Add unit tests
  • Loading branch information
nyalldawson committed Jul 27, 2017
1 parent 9b3f8a8 commit 516249c
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 30 deletions.
61 changes: 33 additions & 28 deletions python/plugins/processing/algs/qgis/Explode.py
Expand Up @@ -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):
Expand All @@ -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'
Expand All @@ -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
5 changes: 3 additions & 2 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -197,7 +197,7 @@ def getAlgs(self):
# HubDistanceLines(), HubLines(),
# GeometryConvert(), FieldsCalculator(),
# JoinAttributes(),
# Explode(), FieldsPyculator(),
# FieldsPyculator(),
# EquivalentNumField(),
# StatisticsByCategories(),
# RasterLayerStatistics(), PointsDisplacement(),
Expand Down Expand Up @@ -236,6 +236,7 @@ def getAlgs(self):
Difference(),
DropGeometry(),
DropMZValues(),
Explode(),
ExportGeometryInfo(),
ExtendLines(),
ExtentFromLayer(),
Expand Down
@@ -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>
28 changes: 28 additions & 0 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -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:
Expand Down

0 comments on commit 516249c

Please sign in to comment.