Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #4560 from alexbruy/processing-singletomulti
[processing] handle NULL values in the single to multi algorithm (fix #15822)
  • Loading branch information
alexbruy committed May 16, 2017
2 parents 8b263e4 + e4d745f commit 4dab1f8
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 17 deletions.
27 changes: 20 additions & 7 deletions python/plugins/processing/algs/qgis/SinglePartsToMultiparts.py
Expand Up @@ -29,7 +29,7 @@

from qgis.PyQt.QtGui import QIcon

from qgis.core import QGis, QgsFeature, QgsGeometry
from qgis.core import QGis, QgsFeature, QgsGeometry, NULL

from processing.core.GeoAlgorithm import GeoAlgorithm
from processing.core.GeoAlgorithmExecutionException import GeoAlgorithmExecutionException
Expand Down Expand Up @@ -80,14 +80,26 @@ def processAlgorithm(self, progress):
current = 0
features = vector.features(layer)
total = 100.0 / (len(features) * len(unique))

nullFeatures = []
if not len(unique) == layer.featureCount():
for i in unique:
multi_feature = []
first = True
multi_feature = []
features = vector.features(layer)
for inFeat in features:
atMap = inFeat.attributes()
idVar = atMap[index]
if idVar in [None, NULL] and inFeat.id() not in nullFeatures:
nullFeatures.append(inFeat.id())
outGeom = QgsGeometry(inFeat.geometry())
outFeat.setAttributes(atMap)
outFeat.setGeometry(outGeom)
writer.addFeature(outFeat)
current += 1
progress.setPercentage(int(current * total))
continue

if unicode(idVar).strip() == unicode(i).strip():
if first:
attrs = atMap
Expand All @@ -100,11 +112,12 @@ def processAlgorithm(self, progress):
current += 1
progress.setPercentage(int(current * total))

outFeat.setAttributes(attrs)
outGeom = QgsGeometry(self.convertGeometry(multi_feature,
vType))
outFeat.setGeometry(outGeom)
writer.addFeature(outFeat)
if len(multi_feature) > 0:
outGeom = QgsGeometry(
self.convertGeometry(multi_feature, vType))
outFeat.setGeometry(outGeom)
outFeat.setAttributes(attrs)
writer.addFeature(outFeat)

del writer
else:
Expand Down
@@ -0,0 +1,21 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>single_part_poly</Name>
<ElementPath>single_part_poly</ElementPath>
<!--POLYGON-->
<GeometryType>3</GeometryType>
<SRSName>EPSG:4326</SRSName>
<DatasetSpecificInfo>
<FeatureCount>7</FeatureCount>
<ExtentXMin>0.21020</ExtentXMin>
<ExtentXMax>8.96288</ExtentXMax>
<ExtentYMin>-5.48232</ExtentYMin>
<ExtentYMax>7.16399</ExtentYMax>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>id</Name>
<ElementPath>id</ElementPath>
<Type>Integer</Type>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>0.2101967462686566</gml:X><gml:Y>-5.482323358208955</gml:Y></gml:coord>
<gml:coord><gml:X>8.962880985074626</gml:X><gml:Y>7.163993643533122</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:single_part_poly fid="single_part_poly.0">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0.80194134384858,7.16399364353312 0.672499728706625,4.76932376340694 5.20295625867508,4.2839177066246 5.26276665671642,6.74081294029851 0.80194134384858,7.16399364353312</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id></ogr:id>
</ogr:single_part_poly>
</gml:featureMember>
<gml:featureMember>
<ogr:single_part_poly fid="single_part_poly.1">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6.30900588059701,4.21452798507463 6.00278952238806,2.60689210447761 8.4525203880597,1.81583317910448 8.96288098507463,4.26556404477612 8.24837614925373,7.04702929850746 6.30900588059701,4.21452798507463</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>1</ogr:id>
</ogr:single_part_poly>
</gml:featureMember>
<gml:featureMember>
<ogr:single_part_poly fid="single_part_poly.2">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3.96134713432836,1.68824302985075 3.93582910447761,-1.14425828358209 8.27389417910448,-1.50151070149254 8.120786,0.64200380597015 3.96134713432836,1.68824302985075</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>1</ogr:id>
</ogr:single_part_poly>
</gml:featureMember>
<gml:featureMember>
<ogr:single_part_poly fid="single_part_poly.3">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1.69024247761194,3.0406986119403 1.9454227761194,1.48409879104478 3.47650456716418,2.47930195522388 3.45098653731343,3.52554117910448 1.69024247761194,3.0406986119403</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>2</ogr:id>
</ogr:single_part_poly>
</gml:featureMember>
<gml:featureMember>
<ogr:single_part_poly fid="single_part_poly.4">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1.46058020895522,-2.93052037313433 2.40474731343284,-5.48232335820895 6.02830755223881,-4.35953004477612 6.411078,-2.57326795522388 1.46058020895522,-2.93052037313433</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>2</ogr:id>
</ogr:single_part_poly>
</gml:featureMember>
<gml:featureMember>
<ogr:single_part_poly fid="single_part_poly.5">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0.592967194029851,-0.17457314925373 1.58817035820896,-2.06290735820895 2.37922928358209,-1.3739205522388 2.63440958208955,0.284751388059703 0.592967194029851,-0.17457314925373</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>3</ogr:id>
</ogr:single_part_poly>
</gml:featureMember>
<gml:featureMember>
<ogr:single_part_poly fid="single_part_poly.6">
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0.210196746268657,2.19860362686567 0.439859014925373,1.05029228358209 1.15436385074627,1.02477425373134 0.720557343283582,4.0359017761194 0.210196746268657,2.19860362686567</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
<ogr:id>4</ogr:id>
</ogr:single_part_poly>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ogr.maptools.org/ single_to_multi.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>0.210196746268657</gml:X><gml:Y>-5.48232335820895</gml:Y></gml:coord>
<gml:coord><gml:X>8.96288098507463</gml:X><gml:Y>7.16399364353312</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:single_to_multi fid="single_part_poly.0">
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0.80194134384858,7.16399364353312 0.672499728706625,4.76932376340694 5.20295625867508,4.2839177066246 5.26276665671642,6.74081294029851 0.80194134384858,7.16399364353312</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
</ogr:single_to_multi>
</gml:featureMember>
<gml:featureMember>
<ogr:single_to_multi fid="single_part_poly.1">
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>6.30900588059701,4.21452798507463 6.00278952238806,2.60689210447761 8.4525203880597,1.81583317910448 8.96288098507463,4.26556404477612 8.24837614925373,7.04702929850746 6.30900588059701,4.21452798507463</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>3.96134713432836,1.68824302985075 3.93582910447761,-1.14425828358209 8.27389417910448,-1.50151070149254 8.120786,0.64200380597015 3.96134713432836,1.68824302985075</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
<ogr:id>1</ogr:id>
</ogr:single_to_multi>
</gml:featureMember>
<gml:featureMember>
<ogr:single_to_multi fid="single_part_poly.3">
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1.69024247761194,3.0406986119403 1.9454227761194,1.48409879104478 3.47650456716418,2.47930195522388 3.45098653731343,3.52554117910448 1.69024247761194,3.0406986119403</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1.46058020895522,-2.93052037313433 2.40474731343284,-5.48232335820895 6.02830755223881,-4.35953004477612 6.411078,-2.57326795522388 1.46058020895522,-2.93052037313433</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
<ogr:id>2</ogr:id>
</ogr:single_to_multi>
</gml:featureMember>
<gml:featureMember>
<ogr:single_to_multi fid="single_part_poly.5">
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0.592967194029851,-0.17457314925373 1.58817035820896,-2.06290735820895 2.37922928358209,-1.3739205522388 2.63440958208955,0.284751388059703 0.592967194029851,-0.17457314925373</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
<ogr:id>3</ogr:id>
</ogr:single_to_multi>
</gml:featureMember>
<gml:featureMember>
<ogr:single_to_multi fid="single_part_poly.6">
<ogr:geometryProperty><gml:MultiPolygon srsName="EPSG:4326"><gml:polygonMember><gml:Polygon><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>0.210196746268657,2.19860362686567 0.439859014925373,1.05029228358209 1.15436385074627,1.02477425373134 0.720557343283582,4.0359017761194 0.210196746268657,2.19860362686567</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></gml:polygonMember></gml:MultiPolygon></ogr:geometryProperty>
<ogr:id>4</ogr:id>
</ogr:single_to_multi>
</gml:featureMember>
</ogr:FeatureCollection>
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://ogr.maptools.org/" xmlns:ogr="http://ogr.maptools.org/" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:gml="http://www.opengis.net/gml" elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
<xs:complexType name="FeatureCollectionType">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureCollectionType">
<xs:attribute name="lockId" type="xs:string" use="optional"/>
<xs:attribute name="scope" type="xs:string" use="optional"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:element name="single_to_multi" type="ogr:single_to_multi_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="single_to_multi_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:MultiPolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="id" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
32 changes: 22 additions & 10 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Expand Up @@ -23,7 +23,7 @@ tests:
OUTPUT:
name: expected/polys_deleteholes.gml
type: vector

- algorithm: qgis:clip
name: Clip lines by polygons
params:
Expand All @@ -37,8 +37,8 @@ tests:
OUTPUT:
name: expected/clip_lines_by_polygon.gml
type: vector


- algorithm: qgis:clip
name: Clip lines by multipolygon
params:
Expand All @@ -52,7 +52,7 @@ tests:
OUTPUT:
name: expected/clip_lines_by_multipolygon.gml
type: vector

- algorithm: qgis:clip
name: Clip polygons by multipolygons
params:
Expand All @@ -66,7 +66,7 @@ tests:
OUTPUT:
name: expected/clip_polys_by_multipolygon.gml
type: vector

- algorithm: qgis:clip
name: Clip multipolygons by polygons
params:
Expand All @@ -80,7 +80,7 @@ tests:
OUTPUT:
name: expected/clip_multipolygons_by_polygons.gml
type: vector

- algorithm: qgis:clip
name: Clip points by polygons
params:
Expand All @@ -94,7 +94,7 @@ tests:
OUTPUT:
name: expected/clip_points_by_polygons.gml
type: vector

- algorithm: qgis:clip
name: Clip points by multipolygons
params:
Expand All @@ -108,8 +108,8 @@ tests:
OUTPUT:
name: expected/clip_points_by_multipolygons.gml
type: vector


# These datasets should produce a geometry collection and not a polygon only
# dataset. If the algorithm is fixed, a new test should be introduced to
# check this behavior.
Expand Down Expand Up @@ -440,7 +440,7 @@ tests:
OUTPUT:
name: expected/multi_to_single.gml
type: vector

- algorithm: qgis:boundingboxes
name: Bounding boxes for lines
params:
Expand Down Expand Up @@ -602,3 +602,15 @@ tests:
# (features could be written in different order and still being correct output)
# - geometry equality comparison instead of WKT string comparison
# (geometries could different order of coordinate but still being correct output)

- algorithm: qgis:singlepartstomultipart
name: Singleparts to multiparts
params:
INPUT:
name: custom/single_part_poly.gml
type: vector
FIELD: id
results:
OUTPUT:
name: expected/single_to_multi.gml
type: vector

0 comments on commit 4dab1f8

Please sign in to comment.