Skip to content

Commit c7ac866

Browse files
committedMar 21, 2019
[FEATURE] New algorithm "Add X/Y fields to layer"
Adds X and Y (or latitude/longitude) fields to a point layer. The X/Y fields can be calculated in a different CRS to the layer (e.g. creating latitude/longitude fields for a layer in a project CRS). Sponsored by SMEC/SJ
1 parent acdb368 commit c7ac866

File tree

9 files changed

+547
-0
lines changed

9 files changed

+547
-0
lines changed
 
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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/ add_xy_3857.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>0</gml:X><gml:Y>-5</gml:Y></gml:coord>
10+
<gml:coord><gml:X>8</gml:X><gml:Y>3</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:add_xy_3857 fid="points.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
<ogr:id>1</ogr:id>
18+
<ogr:id2>2</ogr:id2>
19+
<ogr:p_x>111319.4907932723</ogr:p_x>
20+
<ogr:p_y>111325.1428663849</ogr:p_y>
21+
</ogr:add_xy_3857>
22+
</gml:featureMember>
23+
<gml:featureMember>
24+
<ogr:add_xy_3857 fid="points.1">
25+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
26+
<ogr:id>2</ogr:id>
27+
<ogr:id2>1</ogr:id2>
28+
<ogr:p_x>333958.4723798198</ogr:p_x>
29+
<ogr:p_y>334111.1714019597</ogr:p_y>
30+
</ogr:add_xy_3857>
31+
</gml:featureMember>
32+
<gml:featureMember>
33+
<ogr:add_xy_3857 fid="points.2">
34+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
35+
<ogr:id>3</ogr:id>
36+
<ogr:id2>0</ogr:id2>
37+
<ogr:p_x>222638.9815865475</ogr:p_x>
38+
<ogr:p_y>222684.2085055445</ogr:p_y>
39+
</ogr:add_xy_3857>
40+
</gml:featureMember>
41+
<gml:featureMember>
42+
<ogr:add_xy_3857 fid="points.3">
43+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,2</gml:coordinates></gml:Point></ogr:geometryProperty>
44+
<ogr:id>4</ogr:id>
45+
<ogr:id2>2</ogr:id2>
46+
<ogr:p_x>556597.4539663672</ogr:p_x>
47+
<ogr:p_y>222684.2085055445</ogr:p_y>
48+
</ogr:add_xy_3857>
49+
</gml:featureMember>
50+
<gml:featureMember>
51+
<ogr:add_xy_3857 fid="points.4">
52+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4,1</gml:coordinates></gml:Point></ogr:geometryProperty>
53+
<ogr:id>5</ogr:id>
54+
<ogr:id2>1</ogr:id2>
55+
<ogr:p_x>445277.9631730949</ogr:p_x>
56+
<ogr:p_y>111325.1428663849</ogr:p_y>
57+
</ogr:add_xy_3857>
58+
</gml:featureMember>
59+
<gml:featureMember>
60+
<ogr:add_xy_3857 fid="points.5">
61+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-5</gml:coordinates></gml:Point></ogr:geometryProperty>
62+
<ogr:id>6</ogr:id>
63+
<ogr:id2>0</ogr:id2>
64+
<ogr:p_x>0.0000000000</ogr:p_x>
65+
<ogr:p_y>-557305.2572745769</ogr:p_y>
66+
</ogr:add_xy_3857>
67+
</gml:featureMember>
68+
<gml:featureMember>
69+
<ogr:add_xy_3857 fid="points.6">
70+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>8,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
71+
<ogr:id>7</ogr:id>
72+
<ogr:id2>0</ogr:id2>
73+
<ogr:p_x>890555.9263461898</ogr:p_x>
74+
<ogr:p_y>-111325.1428663860</ogr:p_y>
75+
</ogr:add_xy_3857>
76+
</gml:featureMember>
77+
<gml:featureMember>
78+
<ogr:add_xy_3857 fid="points.7">
79+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
80+
<ogr:id>8</ogr:id>
81+
<ogr:id2>0</ogr:id2>
82+
<ogr:p_x>779236.4355529146</ogr:p_x>
83+
<ogr:p_y>-111325.1428663860</ogr:p_y>
84+
</ogr:add_xy_3857>
85+
</gml:featureMember>
86+
<gml:featureMember>
87+
<ogr:add_xy_3857 fid="points.8">
88+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
89+
<ogr:id>9</ogr:id>
90+
<ogr:id2>0</ogr:id2>
91+
<ogr:p_x>0.0000000000</ogr:p_x>
92+
<ogr:p_y>-111325.1428663860</ogr:p_y>
93+
</ogr:add_xy_3857>
94+
</gml:featureMember>
95+
</ogr:FeatureCollection>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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="add_xy_3857" type="ogr:add_xy_3857_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="add_xy_3857_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="id" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:integer">
22+
<xs:totalDigits value="10"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
<xs:element name="id2" 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="p_x" nillable="true" minOccurs="0" maxOccurs="1">
34+
<xs:simpleType>
35+
<xs:restriction base="xs:decimal">
36+
<xs:totalDigits value="21"/>
37+
<xs:fractionDigits value="10"/>
38+
</xs:restriction>
39+
</xs:simpleType>
40+
</xs:element>
41+
<xs:element name="p_y" nillable="true" minOccurs="0" maxOccurs="1">
42+
<xs:simpleType>
43+
<xs:restriction base="xs:decimal">
44+
<xs:totalDigits value="21"/>
45+
<xs:fractionDigits value="10"/>
46+
</xs:restriction>
47+
</xs:simpleType>
48+
</xs:element>
49+
</xs:sequence>
50+
</xs:extension>
51+
</xs:complexContent>
52+
</xs:complexType>
53+
</xs:schema>
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
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/ add_xy_4326.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>0</gml:X><gml:Y>-5</gml:Y></gml:coord>
10+
<gml:coord><gml:X>8</gml:X><gml:Y>3</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:add_xy_4326 fid="points.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
<ogr:id>1</ogr:id>
18+
<ogr:id2>2</ogr:id2>
19+
<ogr:x>1.0000000000</ogr:x>
20+
<ogr:y>1.0000000000</ogr:y>
21+
</ogr:add_xy_4326>
22+
</gml:featureMember>
23+
<gml:featureMember>
24+
<ogr:add_xy_4326 fid="points.1">
25+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
26+
<ogr:id>2</ogr:id>
27+
<ogr:id2>1</ogr:id2>
28+
<ogr:x>3.0000000000</ogr:x>
29+
<ogr:y>3.0000000000</ogr:y>
30+
</ogr:add_xy_4326>
31+
</gml:featureMember>
32+
<gml:featureMember>
33+
<ogr:add_xy_4326 fid="points.2">
34+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
35+
<ogr:id>3</ogr:id>
36+
<ogr:id2>0</ogr:id2>
37+
<ogr:x>2.0000000000</ogr:x>
38+
<ogr:y>2.0000000000</ogr:y>
39+
</ogr:add_xy_4326>
40+
</gml:featureMember>
41+
<gml:featureMember>
42+
<ogr:add_xy_4326 fid="points.3">
43+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,2</gml:coordinates></gml:Point></ogr:geometryProperty>
44+
<ogr:id>4</ogr:id>
45+
<ogr:id2>2</ogr:id2>
46+
<ogr:x>5.0000000000</ogr:x>
47+
<ogr:y>2.0000000000</ogr:y>
48+
</ogr:add_xy_4326>
49+
</gml:featureMember>
50+
<gml:featureMember>
51+
<ogr:add_xy_4326 fid="points.4">
52+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4,1</gml:coordinates></gml:Point></ogr:geometryProperty>
53+
<ogr:id>5</ogr:id>
54+
<ogr:id2>1</ogr:id2>
55+
<ogr:x>4.0000000000</ogr:x>
56+
<ogr:y>1.0000000000</ogr:y>
57+
</ogr:add_xy_4326>
58+
</gml:featureMember>
59+
<gml:featureMember>
60+
<ogr:add_xy_4326 fid="points.5">
61+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-5</gml:coordinates></gml:Point></ogr:geometryProperty>
62+
<ogr:id>6</ogr:id>
63+
<ogr:id2>0</ogr:id2>
64+
<ogr:x>0.0000000000</ogr:x>
65+
<ogr:y>-5.0000000000</ogr:y>
66+
</ogr:add_xy_4326>
67+
</gml:featureMember>
68+
<gml:featureMember>
69+
<ogr:add_xy_4326 fid="points.6">
70+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>8,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
71+
<ogr:id>7</ogr:id>
72+
<ogr:id2>0</ogr:id2>
73+
<ogr:x>8.0000000000</ogr:x>
74+
<ogr:y>-1.0000000000</ogr:y>
75+
</ogr:add_xy_4326>
76+
</gml:featureMember>
77+
<gml:featureMember>
78+
<ogr:add_xy_4326 fid="points.7">
79+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
80+
<ogr:id>8</ogr:id>
81+
<ogr:id2>0</ogr:id2>
82+
<ogr:x>7.0000000000</ogr:x>
83+
<ogr:y>-1.0000000000</ogr:y>
84+
</ogr:add_xy_4326>
85+
</gml:featureMember>
86+
<gml:featureMember>
87+
<ogr:add_xy_4326 fid="points.8">
88+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
89+
<ogr:id>9</ogr:id>
90+
<ogr:id2>0</ogr:id2>
91+
<ogr:x>0.0000000000</ogr:x>
92+
<ogr:y>-1.0000000000</ogr:y>
93+
</ogr:add_xy_4326>
94+
</gml:featureMember>
95+
</ogr:FeatureCollection>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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="add_xy_4326" type="ogr:add_xy_4326_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="add_xy_4326_Type">
15+
<xs:complexContent>
16+
<xs:extension base="gml:AbstractFeatureType">
17+
<xs:sequence>
18+
<xs:element name="geometryProperty" type="gml:PointPropertyType" nillable="true" minOccurs="0" maxOccurs="1"/>
19+
<xs:element name="id" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:integer">
22+
<xs:totalDigits value="10"/>
23+
</xs:restriction>
24+
</xs:simpleType>
25+
</xs:element>
26+
<xs:element name="id2" 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="x" nillable="true" minOccurs="0" maxOccurs="1">
34+
<xs:simpleType>
35+
<xs:restriction base="xs:decimal">
36+
<xs:totalDigits value="21"/>
37+
<xs:fractionDigits value="10"/>
38+
</xs:restriction>
39+
</xs:simpleType>
40+
</xs:element>
41+
<xs:element name="y" nillable="true" minOccurs="0" maxOccurs="1">
42+
<xs:simpleType>
43+
<xs:restriction base="xs:decimal">
44+
<xs:totalDigits value="21"/>
45+
<xs:fractionDigits value="10"/>
46+
</xs:restriction>
47+
</xs:simpleType>
48+
</xs:element>
49+
</xs:sequence>
50+
</xs:extension>
51+
</xs:complexContent>
52+
</xs:complexType>
53+
</xs:schema>

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

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7287,4 +7287,31 @@ tests:
72877287
hash: 6c09e13126e16a267e36c79b0eeba7761422da7bd0387125f4c823e6
72887288
type: rasterhash
72897289

7290+
- algorithm: native:addxyfields
7291+
name: Add XY 4326
7292+
params:
7293+
CRS: EPSG:4326
7294+
INPUT:
7295+
name: points.gml|layername=points
7296+
type: vector
7297+
PREFIX: ''
7298+
results:
7299+
OUTPUT:
7300+
name: expected/add_xy_4326.gml
7301+
type: vector
7302+
7303+
- algorithm: native:addxyfields
7304+
name: Add XY 3785
7305+
params:
7306+
CRS: EPSG:3785
7307+
INPUT:
7308+
name: points.gml|layername=points
7309+
type: vector
7310+
PREFIX: p_
7311+
results:
7312+
OUTPUT:
7313+
name: expected/add_xy_3857.gml
7314+
type: vector
7315+
7316+
72907317
# See ../README.md for a description of the file format

‎src/analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ SET(QGIS_ANALYSIS_SRCS
2222
interpolation/Vector3D.cpp
2323

2424
processing/qgsalgorithmaddincrementalfield.cpp
25+
processing/qgsalgorithmaddxyfields.cpp
2526
processing/qgsalgorithmarraytranslatedfeatures.cpp
2627
processing/qgsalgorithmassignprojection.cpp
2728
processing/qgsalgorithmboundary.cpp
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/***************************************************************************
2+
qgsalgorithmaddixyfields.cpp
3+
-----------------------------------
4+
begin : March 2019
5+
copyright : (C) 2019 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 "qgsalgorithmaddxyfields.h"
19+
#include "qgsfeaturerequest.h"
20+
21+
///@cond PRIVATE
22+
23+
QString QgsAddXYFieldsAlgorithm::name() const
24+
{
25+
return QStringLiteral( "addxyfields" );
26+
}
27+
28+
QString QgsAddXYFieldsAlgorithm::displayName() const
29+
{
30+
return QObject::tr( "Add X/Y fields to layer" );
31+
}
32+
33+
QString QgsAddXYFieldsAlgorithm::shortHelpString() const
34+
{
35+
return QObject::tr( "Adds X and Y (or latitude/longitude) fields to a point layer. The X/Y fields can be calculated in a different CRS to the layer (e.g. creating latitude/longitude fields for a layer in a project CRS)." );
36+
}
37+
38+
QString QgsAddXYFieldsAlgorithm::shortDescription() const
39+
{
40+
return QObject::tr( "Adds X and Y (or latitude/longitude) fields to a point layer." );
41+
}
42+
43+
QStringList QgsAddXYFieldsAlgorithm::tags() const
44+
{
45+
return QObject::tr( "add,create,latitude,longitude,columns,attributes" ).split( ',' );
46+
}
47+
48+
QString QgsAddXYFieldsAlgorithm::group() const
49+
{
50+
return QObject::tr( "Vector table" );
51+
}
52+
53+
QString QgsAddXYFieldsAlgorithm::groupId() const
54+
{
55+
return QStringLiteral( "vectortable" );
56+
}
57+
58+
QString QgsAddXYFieldsAlgorithm::outputName() const
59+
{
60+
return QObject::tr( "Added fields" );
61+
}
62+
63+
QList<int> QgsAddXYFieldsAlgorithm::inputLayerTypes() const
64+
{
65+
return QList<int>() << QgsProcessing::TypeVectorPoint;
66+
}
67+
68+
QgsAddXYFieldsAlgorithm *QgsAddXYFieldsAlgorithm::createInstance() const
69+
{
70+
return new QgsAddXYFieldsAlgorithm();
71+
}
72+
73+
QgsProcessingFeatureSource::Flag QgsAddXYFieldsAlgorithm::sourceFlags() const
74+
{
75+
return QgsProcessingFeatureSource::FlagSkipGeometryValidityChecks;
76+
}
77+
78+
void QgsAddXYFieldsAlgorithm::initParameters( const QVariantMap & )
79+
{
80+
addParameter( new QgsProcessingParameterCrs( QStringLiteral( "CRS" ), QObject::tr( "Coordinate system" ), QStringLiteral( "EPSG:4326" ) ) );
81+
addParameter( new QgsProcessingParameterString( QStringLiteral( "PREFIX" ), QObject::tr( "Field prefix" ), QVariant(), false, true ) );
82+
}
83+
84+
QgsFields QgsAddXYFieldsAlgorithm::outputFields( const QgsFields &inputFields ) const
85+
{
86+
const QString xFieldName = mPrefix + 'x';
87+
const QString yFieldName = mPrefix + 'y';
88+
89+
QgsFields outFields = inputFields;
90+
outFields.append( QgsField( xFieldName, QVariant::Double, QString(), 20, 10 ) );
91+
outFields.append( QgsField( yFieldName, QVariant::Double, QString(), 20, 10 ) );
92+
return outFields;
93+
}
94+
95+
QgsCoordinateReferenceSystem QgsAddXYFieldsAlgorithm::outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const
96+
{
97+
mSourceCrs = inputCrs;
98+
return inputCrs;
99+
}
100+
101+
bool QgsAddXYFieldsAlgorithm::prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback * )
102+
{
103+
mPrefix = parameterAsString( parameters, QStringLiteral( "PREFIX" ), context );
104+
mCrs = parameterAsCrs( parameters, QStringLiteral( "CRS" ), context );
105+
return true;
106+
}
107+
108+
QgsFeatureList QgsAddXYFieldsAlgorithm::processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
109+
{
110+
if ( mTransformNeedsInitialization )
111+
{
112+
mTransform = QgsCoordinateTransform( mSourceCrs, mCrs, context.transformContext() );
113+
mTransformNeedsInitialization = false;
114+
}
115+
116+
QVariant x;
117+
QVariant y;
118+
if ( feature.hasGeometry() )
119+
{
120+
if ( feature.geometry().isMultipart() )
121+
throw QgsProcessingException( QObject::tr( "Multipoint features are not supported - please convert to single point features first." ) );
122+
123+
const QgsPointXY point = feature.geometry().asPoint();
124+
try
125+
{
126+
const QgsPointXY transformed = mTransform.transform( point );
127+
x = transformed.x();
128+
y = transformed.y();
129+
}
130+
catch ( QgsCsException & )
131+
{
132+
feedback->reportError( QObject::tr( "Could not transform point to destination CRS" ) );
133+
}
134+
}
135+
QgsFeature f = feature;
136+
QgsAttributes attributes = f.attributes();
137+
attributes << x << y;
138+
f.setAttributes( attributes );
139+
return QgsFeatureList() << f;
140+
}
141+
142+
bool QgsAddXYFieldsAlgorithm::supportInPlaceEdit( const QgsMapLayer *layer ) const
143+
{
144+
Q_UNUSED( layer );
145+
return false;
146+
}
147+
148+
///@endcond
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/***************************************************************************
2+
qgsalgorithmaddixyfields.h
3+
---------------------------------
4+
begin : March 2019
5+
copyright : (C) 2019 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 QGSALGORITHMADDXYFIELDS_H
19+
#define QGSALGORITHMADDXYFIELDS_H
20+
21+
#define SIP_NO_FILE
22+
23+
#include "qgis_sip.h"
24+
#include "qgsprocessingalgorithm.h"
25+
26+
///@cond PRIVATE
27+
28+
/**
29+
* Native add X/Y fields algorithm.
30+
*/
31+
class QgsAddXYFieldsAlgorithm : public QgsProcessingFeatureBasedAlgorithm
32+
{
33+
34+
public:
35+
36+
QgsAddXYFieldsAlgorithm() = 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+
QString shortDescription() const override;
44+
QList<int> inputLayerTypes() const override;
45+
QgsAddXYFieldsAlgorithm *createInstance() const override SIP_FACTORY;
46+
47+
protected:
48+
49+
void initParameters( const QVariantMap &configuration = QVariantMap() ) override;
50+
QString outputName() const override;
51+
QgsFields outputFields( const QgsFields &inputFields ) const override;
52+
QgsCoordinateReferenceSystem outputCrs( const QgsCoordinateReferenceSystem &inputCrs ) const override;
53+
QgsProcessingFeatureSource::Flag sourceFlags() const override;
54+
55+
bool prepareAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
56+
QgsFeatureList processFeature( const QgsFeature &feature, QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
57+
bool supportInPlaceEdit( const QgsMapLayer *layer ) const override;
58+
59+
private:
60+
61+
QString mPrefix;
62+
mutable QgsCoordinateReferenceSystem mSourceCrs;
63+
QgsCoordinateReferenceSystem mCrs;
64+
QgsCoordinateTransform mTransform;
65+
bool mTransformNeedsInitialization = true;
66+
67+
};
68+
69+
///@endcond PRIVATE
70+
71+
#endif // QGSALGORITHMADDXYFIELDS_H
72+
73+

‎src/analysis/processing/qgsnativealgorithms.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "qgsnativealgorithms.h"
1919
#include "qgsalgorithmaddincrementalfield.h"
20+
#include "qgsalgorithmaddxyfields.h"
2021
#include "qgsalgorithmarraytranslatedfeatures.h"
2122
#include "qgsalgorithmassignprojection.h"
2223
#include "qgsalgorithmboundary.h"
@@ -150,6 +151,7 @@ bool QgsNativeAlgorithms::supportsNonFileBasedOutput() const
150151
void QgsNativeAlgorithms::loadAlgorithms()
151152
{
152153
addAlgorithm( new QgsAddIncrementalFieldAlgorithm() );
154+
addAlgorithm( new QgsAddXYFieldsAlgorithm() );
153155
addAlgorithm( new QgsAddUniqueValueIndexAlgorithm() );
154156
addAlgorithm( new QgsArrayTranslatedFeaturesAlgorithm() );
155157
addAlgorithm( new QgsAssignProjectionAlgorithm() );

0 commit comments

Comments
 (0)
Please sign in to comment.