Skip to content

Commit 8aa9a82

Browse files
committedApr 4, 2018
[FEATURE][processing] Add algorithm to swap x/y coordinate values
This algorithm swaps the X and Y coordinate values in input geometries. It can be used to repair geometries which have accidentally had their latitude and longitude values reversed.
1 parent 63c5e74 commit 8aa9a82

File tree

8 files changed

+253
-0
lines changed

8 files changed

+253
-0
lines changed
 
Binary file not shown.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://ogr.maptools.org/ swap_xy.xsd"
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy>
8+
<gml:Box>
9+
<gml:coord><gml:X>-3</gml:X><gml:Y>-1</gml:Y></gml:coord>
10+
<gml:coord><gml:X>6</gml:X><gml:Y>10</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:swap_xy fid="polys.0">
16+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>-1,-1 3,-1 3,3 2,3 2,2 -1,2 -1,-1</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
17+
<ogr:name>aaaaa</ogr:name>
18+
<ogr:intval>33</ogr:intval>
19+
<ogr:floatval>44.123456</ogr:floatval>
20+
</ogr:swap_xy>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:swap_xy fid="polys.1">
24+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,5 4,6 4,4 5,5</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
25+
<ogr:name>Aaaaa</ogr:name>
26+
<ogr:intval>-33</ogr:intval>
27+
<ogr:floatval>0</ogr:floatval>
28+
</ogr:swap_xy>
29+
</gml:featureMember>
30+
<gml:featureMember>
31+
<ogr:swap_xy fid="polys.2">
32+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>5,2 6,2 6,3 5,3 5,2</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
33+
<ogr:name>bbaaa</ogr:name>
34+
<ogr:floatval>0.123</ogr:floatval>
35+
</ogr:swap_xy>
36+
</gml:featureMember>
37+
<gml:featureMember>
38+
<ogr:swap_xy fid="polys.3">
39+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>1,6 1,10 -3,10 -3,6 1,6</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs><gml:innerBoundaryIs><gml:LinearRing><gml:coordinates>0,7 -2,7 -2,9 0,9 0,7</gml:coordinates></gml:LinearRing></gml:innerBoundaryIs></gml:Polygon></ogr:geometryProperty>
40+
<ogr:name>ASDF</ogr:name>
41+
<ogr:intval>0</ogr:intval>
42+
</ogr:swap_xy>
43+
</gml:featureMember>
44+
<gml:featureMember>
45+
<ogr:swap_xy fid="polys.4">
46+
<ogr:intval>120</ogr:intval>
47+
<ogr:floatval>-100291.43213</ogr:floatval>
48+
</ogr:swap_xy>
49+
</gml:featureMember>
50+
<gml:featureMember>
51+
<ogr:swap_xy fid="polys.5">
52+
<ogr:geometryProperty><gml:Polygon srsName="EPSG:4326"><gml:outerBoundaryIs><gml:LinearRing><gml:coordinates>2,3 1,6 -3,6 -1,2 2,2 2,3</gml:coordinates></gml:LinearRing></gml:outerBoundaryIs></gml:Polygon></ogr:geometryProperty>
53+
<ogr:name>elim</ogr:name>
54+
<ogr:intval>2</ogr:intval>
55+
<ogr:floatval>3.33</ogr:floatval>
56+
</ogr:swap_xy>
57+
</gml:featureMember>
58+
</ogr:FeatureCollection>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<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">
3+
<xs:import namespace="http://www.opengis.net/gml" schemaLocation="http://schemas.opengis.net/gml/2.1.2/feature.xsd"/>
4+
<xs:element name="FeatureCollection" type="ogr:FeatureCollectionType" substitutionGroup="gml:_FeatureCollection"/>
5+
<xs:complexType name="FeatureCollectionType">
6+
<xs:complexContent>
7+
<xs:extension base="gml:AbstractFeatureCollectionType">
8+
<xs:attribute name="lockId" type="xs:string" use="optional"/>
9+
<xs:attribute name="scope" type="xs:string" use="optional"/>
10+
</xs:extension>
11+
</xs:complexContent>
12+
</xs:complexType>
13+
<xs:element name="swap_xy" type="ogr:swap_xy_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="swap_xy_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:string">
22+
<xs:maxLength value="5"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
<xs:element name="intval" nillable="true" minOccurs="0" maxOccurs="1">
27+
<xs:simpleType>
28+
<xs:restriction base="xs:integer">
29+
<xs:totalDigits value="10"/>
30+
</xs:restriction>
31+
</xs:simpleType>
32+
</xs:element>
33+
<xs:element name="floatval" nillable="true" minOccurs="0" maxOccurs="1">
34+
<xs:simpleType>
35+
<xs:restriction base="xs:decimal">
36+
</xs:restriction>
37+
</xs:simpleType>
38+
</xs:element>
39+
</xs:sequence>
40+
</xs:extension>
41+
</xs:complexContent>
42+
</xs:complexType>
43+
</xs:schema>

‎python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4944,3 +4944,14 @@ tests:
49444944
OUTPUT:
49454945
name: expected/concave_hull_points_07.gml
49464946
type: vector
4947+
4948+
- algorithm: native:swapxy
4949+
name: Swap XY coordinates
4950+
params:
4951+
INPUT:
4952+
name: polys.gml
4953+
type: vector
4954+
results:
4955+
OUTPUT:
4956+
name: expected/swap_xy.gml
4957+
type: vector

‎src/analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ SET(QGIS_ANALYSIS_SRCS
6868
processing/qgsalgorithmsnaptogrid.cpp
6969
processing/qgsalgorithmsplitwithlines.cpp
7070
processing/qgsalgorithmstringconcatenation.cpp
71+
processing/qgsalgorithmswapxy.cpp
7172
processing/qgsalgorithmsubdivide.cpp
7273
processing/qgsalgorithmtransect.cpp
7374
processing/qgsalgorithmtransform.cpp
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/***************************************************************************
2+
qgsalgorithmswapxy.cpp
3+
------------------------
4+
begin : April 2018
5+
copyright : (C) 2018 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#include "qgsalgorithmswapxy.h"
19+
20+
///@cond PRIVATE
21+
22+
QString QgsSwapXYAlgorithm::name() const
23+
{
24+
return QStringLiteral( "swapxy" );
25+
}
26+
27+
QString QgsSwapXYAlgorithm::displayName() const
28+
{
29+
return QObject::tr( "Swap X and Y coordinates" );
30+
}
31+
32+
QStringList QgsSwapXYAlgorithm::tags() const
33+
{
34+
return QObject::tr( "invert,flip,swap,latitude,longitude" ).split( ',' );
35+
}
36+
37+
QString QgsSwapXYAlgorithm::group() const
38+
{
39+
return QObject::tr( "Vector geometry" );
40+
}
41+
42+
QString QgsSwapXYAlgorithm::groupId() const
43+
{
44+
return QStringLiteral( "vectorgeometry" );
45+
}
46+
47+
QString QgsSwapXYAlgorithm::outputName() const
48+
{
49+
return QObject::tr( "Swapped" );
50+
}
51+
52+
QString QgsSwapXYAlgorithm::shortHelpString() const
53+
{
54+
return QObject::tr( "This algorithm swaps the X and Y coordinate values in input geometries. It can be used to repair geometries "
55+
"which have accidentally had their latitude and longitude values reversed." );
56+
}
57+
58+
QgsSwapXYAlgorithm *QgsSwapXYAlgorithm::createInstance() const
59+
{
60+
return new QgsSwapXYAlgorithm();
61+
}
62+
63+
QgsFeatureList QgsSwapXYAlgorithm::processFeature( const QgsFeature &f, QgsProcessingContext &, QgsProcessingFeedback * )
64+
{
65+
QgsFeatureList list;
66+
QgsFeature feature = f;
67+
if ( feature.hasGeometry() )
68+
{
69+
QgsGeometry geom = feature.geometry();
70+
std::unique_ptr< QgsAbstractGeometry > swappedGeom( geom.constGet()->clone() );
71+
swappedGeom->swapXy();
72+
feature.setGeometry( QgsGeometry( std::move( swappedGeom ) ) );
73+
list << feature;
74+
}
75+
else
76+
{
77+
list << feature;
78+
}
79+
return list;
80+
}
81+
82+
///@endcond
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/***************************************************************************
2+
qgsalgorithmswapxy.h
3+
----------------------
4+
begin : April 2018
5+
copyright : (C) 2018 by Nyall Dawson
6+
email : nyall dot dawson at gmail dot com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
18+
#ifndef QGSALGORITHMSWAPXY_H
19+
#define QGSALGORITHMSWAPXY_H
20+
21+
#define SIP_NO_FILE
22+
23+
#include "qgis.h"
24+
#include "qgsprocessingalgorithm.h"
25+
26+
///@cond PRIVATE
27+
28+
/**
29+
* Native swap x-y coordinates algorithm.
30+
*/
31+
class QgsSwapXYAlgorithm : public QgsProcessingFeatureBasedAlgorithm
32+
{
33+
34+
public:
35+
36+
QgsSwapXYAlgorithm() = default;
37+
QString name() const override;
38+
QString displayName() const override;
39+
QStringList tags() const override;
40+
QString group() const override;
41+
QString groupId() const override;
42+
QString shortHelpString() const override;
43+
QgsSwapXYAlgorithm *createInstance() const override SIP_FACTORY;
44+
45+
protected:
46+
47+
QString outputName() const override;
48+
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
49+
50+
};
51+
52+
///@endcond PRIVATE
53+
54+
#endif // QGSALGORITHMSWAPXY_H
55+
56+

‎src/analysis/processing/qgsnativealgorithms.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
#include "qgsalgorithmsplitwithlines.h"
6767
#include "qgsalgorithmstringconcatenation.h"
6868
#include "qgsalgorithmsubdivide.h"
69+
#include "qgsalgorithmswapxy.h"
6970
#include "qgsalgorithmtransect.h"
7071
#include "qgsalgorithmtransform.h"
7172
#include "qgsalgorithmtranslate.h"
@@ -164,6 +165,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
164165
addAlgorithm( new QgsSplitWithLinesAlgorithm() );
165166
addAlgorithm( new QgsStringConcatenationAlgorithm() );
166167
addAlgorithm( new QgsSubdivideAlgorithm() );
168+
addAlgorithm( new QgsSwapXYAlgorithm() );
167169
addAlgorithm( new QgsTransectAlgorithm() );
168170
addAlgorithm( new QgsTransformAlgorithm() );
169171
addAlgorithm( new QgsTranslateAlgorithm() );

0 commit comments

Comments
 (0)
Please sign in to comment.