Skip to content

Commit

Permalink
[FEATURE][processing] Add algorithm to swap x/y coordinate values
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nyalldawson committed Apr 4, 2018
1 parent 63c5e74 commit 8aa9a82
Show file tree
Hide file tree
Showing 8 changed files with 253 additions and 0 deletions.
Binary file not shown.
58 changes: 58 additions & 0 deletions python/plugins/processing/tests/testdata/expected/swap_xy.gml
Original file line number Original file line Diff line number Diff line change
@@ -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/ swap_xy.xsd"
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy>
<gml:Box>
<gml:coord><gml:X>-3</gml:X><gml:Y>-1</gml:Y></gml:coord>
<gml:coord><gml:X>6</gml:X><gml:Y>10</gml:Y></gml:coord>
</gml:Box>
</gml:boundedBy>

<gml:featureMember>
<ogr:swap_xy fid="polys.0">
<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>
<ogr:name>aaaaa</ogr:name>
<ogr:intval>33</ogr:intval>
<ogr:floatval>44.123456</ogr:floatval>
</ogr:swap_xy>
</gml:featureMember>
<gml:featureMember>
<ogr:swap_xy fid="polys.1">
<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>
<ogr:name>Aaaaa</ogr:name>
<ogr:intval>-33</ogr:intval>
<ogr:floatval>0</ogr:floatval>
</ogr:swap_xy>
</gml:featureMember>
<gml:featureMember>
<ogr:swap_xy fid="polys.2">
<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>
<ogr:name>bbaaa</ogr:name>
<ogr:floatval>0.123</ogr:floatval>
</ogr:swap_xy>
</gml:featureMember>
<gml:featureMember>
<ogr:swap_xy fid="polys.3">
<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>
<ogr:name>ASDF</ogr:name>
<ogr:intval>0</ogr:intval>
</ogr:swap_xy>
</gml:featureMember>
<gml:featureMember>
<ogr:swap_xy fid="polys.4">
<ogr:intval>120</ogr:intval>
<ogr:floatval>-100291.43213</ogr:floatval>
</ogr:swap_xy>
</gml:featureMember>
<gml:featureMember>
<ogr:swap_xy fid="polys.5">
<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>
<ogr:name>elim</ogr:name>
<ogr:intval>2</ogr:intval>
<ogr:floatval>3.33</ogr:floatval>
</ogr:swap_xy>
</gml:featureMember>
</ogr:FeatureCollection>
43 changes: 43 additions & 0 deletions python/plugins/processing/tests/testdata/expected/swap_xy.xsd
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,43 @@
<?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="swap_xy" type="ogr:swap_xy_Type" substitutionGroup="gml:_Feature"/>
<xs:complexType name="swap_xy_Type">
<xs:complexContent>
<xs:extension base="gml:AbstractFeatureType">
<xs:sequence>
<xs:element name="geometryProperty" type="gml:PolygonPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
<xs:element name="name" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="intval" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:totalDigits value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="floatval" nillable="true" minOccurs="0" maxOccurs="1">
<xs:simpleType>
<xs:restriction base="xs:decimal">
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
</xs:schema>
11 changes: 11 additions & 0 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -4944,3 +4944,14 @@ tests:
OUTPUT: OUTPUT:
name: expected/concave_hull_points_07.gml name: expected/concave_hull_points_07.gml
type: vector type: vector

- algorithm: native:swapxy
name: Swap XY coordinates
params:
INPUT:
name: polys.gml
type: vector
results:
OUTPUT:
name: expected/swap_xy.gml
type: vector
1 change: 1 addition & 0 deletions src/analysis/CMakeLists.txt
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ SET(QGIS_ANALYSIS_SRCS
processing/qgsalgorithmsnaptogrid.cpp processing/qgsalgorithmsnaptogrid.cpp
processing/qgsalgorithmsplitwithlines.cpp processing/qgsalgorithmsplitwithlines.cpp
processing/qgsalgorithmstringconcatenation.cpp processing/qgsalgorithmstringconcatenation.cpp
processing/qgsalgorithmswapxy.cpp
processing/qgsalgorithmsubdivide.cpp processing/qgsalgorithmsubdivide.cpp
processing/qgsalgorithmtransect.cpp processing/qgsalgorithmtransect.cpp
processing/qgsalgorithmtransform.cpp processing/qgsalgorithmtransform.cpp
Expand Down
82 changes: 82 additions & 0 deletions src/analysis/processing/qgsalgorithmswapxy.cpp
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,82 @@
/***************************************************************************
qgsalgorithmswapxy.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 "qgsalgorithmswapxy.h"

///@cond PRIVATE

QString QgsSwapXYAlgorithm::name() const
{
return QStringLiteral( "swapxy" );
}

QString QgsSwapXYAlgorithm::displayName() const
{
return QObject::tr( "Swap X and Y coordinates" );
}

QStringList QgsSwapXYAlgorithm::tags() const
{
return QObject::tr( "invert,flip,swap,latitude,longitude" ).split( ',' );
}

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

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

QString QgsSwapXYAlgorithm::outputName() const
{
return QObject::tr( "Swapped" );
}

QString QgsSwapXYAlgorithm::shortHelpString() const
{
return QObject::tr( "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." );
}

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

QgsFeatureList QgsSwapXYAlgorithm::processFeature( const QgsFeature &f, QgsProcessingContext &, QgsProcessingFeedback * )
{
QgsFeatureList list;
QgsFeature feature = f;
if ( feature.hasGeometry() )
{
QgsGeometry geom = feature.geometry();
std::unique_ptr< QgsAbstractGeometry > swappedGeom( geom.constGet()->clone() );
swappedGeom->swapXy();
feature.setGeometry( QgsGeometry( std::move( swappedGeom ) ) );
list << feature;
}
else
{
list << feature;
}
return list;
}

///@endcond
56 changes: 56 additions & 0 deletions src/analysis/processing/qgsalgorithmswapxy.h
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,56 @@
/***************************************************************************
qgsalgorithmswapxy.h
----------------------
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. *
* *
***************************************************************************/

#ifndef QGSALGORITHMSWAPXY_H
#define QGSALGORITHMSWAPXY_H

#define SIP_NO_FILE

#include "qgis.h"
#include "qgsprocessingalgorithm.h"

///@cond PRIVATE

/**
* Native swap x-y coordinates algorithm.
*/
class QgsSwapXYAlgorithm : public QgsProcessingFeatureBasedAlgorithm
{

public:

QgsSwapXYAlgorithm() = default;
QString name() const override;
QString displayName() const override;
QStringList tags() const override;
QString group() const override;
QString groupId() const override;
QString shortHelpString() const override;
QgsSwapXYAlgorithm *createInstance() const override SIP_FACTORY;

protected:

QString outputName() const override;
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;

};

///@endcond PRIVATE

#endif // QGSALGORITHMSWAPXY_H


2 changes: 2 additions & 0 deletions src/analysis/processing/qgsnativealgorithms.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#include "qgsalgorithmsplitwithlines.h" #include "qgsalgorithmsplitwithlines.h"
#include "qgsalgorithmstringconcatenation.h" #include "qgsalgorithmstringconcatenation.h"
#include "qgsalgorithmsubdivide.h" #include "qgsalgorithmsubdivide.h"
#include "qgsalgorithmswapxy.h"
#include "qgsalgorithmtransect.h" #include "qgsalgorithmtransect.h"
#include "qgsalgorithmtransform.h" #include "qgsalgorithmtransform.h"
#include "qgsalgorithmtranslate.h" #include "qgsalgorithmtranslate.h"
Expand Down Expand Up @@ -164,6 +165,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
addAlgorithm( new QgsSplitWithLinesAlgorithm() ); addAlgorithm( new QgsSplitWithLinesAlgorithm() );
addAlgorithm( new QgsStringConcatenationAlgorithm() ); addAlgorithm( new QgsStringConcatenationAlgorithm() );
addAlgorithm( new QgsSubdivideAlgorithm() ); addAlgorithm( new QgsSubdivideAlgorithm() );
addAlgorithm( new QgsSwapXYAlgorithm() );
addAlgorithm( new QgsTransectAlgorithm() ); addAlgorithm( new QgsTransectAlgorithm() );
addAlgorithm( new QgsTransformAlgorithm() ); addAlgorithm( new QgsTransformAlgorithm() );
addAlgorithm( new QgsTranslateAlgorithm() ); addAlgorithm( new QgsTranslateAlgorithm() );
Expand Down

0 comments on commit 8aa9a82

Please sign in to comment.