Skip to content

Commit 53aba61

Browse files
authoredSep 23, 2017
Merge pull request #5241 from nyalldawson/clean_code
[processing] Code cleanups
2 parents e3f128b + 5a802b5 commit 53aba61

16 files changed

+539
-293
lines changed
 

‎python/plugins/processing/algs/help/qgis.yaml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -294,14 +294,6 @@ qgis:listuniquevalues: >
294294

295295
qgis:meanandstandarddeviationplot:
296296

297-
298-
qgis:meancoordinates: >
299-
This algorithm computes a point layer with the center of mass of geometries in an input layer.
300-
301-
An attribute can be specified as containing weights to be applied to each feature when computing the center of mass.
302-
303-
If an attribute is selected in the <Unique ID field> parameters, features will be grouped according to values in this field. Instead of a single point with the center of mass of the whole layer, the output layer will contain a center of mass for the features in each category.
304-
305297
qgis:mergevectorlayers: >
306298
This algorithm combines multiple vector layers of the same geometry type into a single one.
307299

‎python/plugins/processing/algs/qgis/ExportGeometryInfo.py

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,11 @@
3232

3333
from qgis.core import (QgsCoordinateTransform,
3434
QgsField,
35+
QgsFields,
3536
QgsWkbTypes,
3637
QgsFeatureSink,
3738
QgsDistanceArea,
39+
QgsProcessingUtils,
3840
QgsProcessingParameterFeatureSource,
3941
QgsProcessingParameterEnum,
4042
QgsProcessingParameterFeatureSink)
@@ -89,28 +91,23 @@ def processAlgorithm(self, parameters, context, feedback):
8991
wkb_type = source.wkbType()
9092
fields = source.fields()
9193

94+
new_fields = QgsFields()
9295
if QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.PolygonGeometry:
93-
areaName = vector.createUniqueFieldName('area', fields)
94-
fields.append(QgsField(areaName, QVariant.Double))
95-
perimeterName = vector.createUniqueFieldName('perimeter', fields)
96-
fields.append(QgsField(perimeterName, QVariant.Double))
96+
new_fields.append(QgsField('area', QVariant.Double))
97+
new_fields.append(QgsField('perimeter', QVariant.Double))
9798
elif QgsWkbTypes.geometryType(wkb_type) == QgsWkbTypes.LineGeometry:
98-
lengthName = vector.createUniqueFieldName('length', fields)
99-
fields.append(QgsField(lengthName, QVariant.Double))
99+
new_fields.append(QgsField('length', QVariant.Double))
100100
else:
101-
xName = vector.createUniqueFieldName('xcoord', fields)
102-
fields.append(QgsField(xName, QVariant.Double))
103-
yName = vector.createUniqueFieldName('ycoord', fields)
104-
fields.append(QgsField(yName, QVariant.Double))
101+
new_fields.append(QgsField('xcoord', QVariant.Double))
102+
new_fields.append(QgsField('ycoord', QVariant.Double))
105103
if QgsWkbTypes.hasZ(source.wkbType()):
106104
self.export_z = True
107-
zName = vector.createUniqueFieldName('zcoord', fields)
108-
fields.append(QgsField(zName, QVariant.Double))
105+
new_fields.append(QgsField('zcoord', QVariant.Double))
109106
if QgsWkbTypes.hasM(source.wkbType()):
110107
self.export_m = True
111-
zName = vector.createUniqueFieldName('mvalue', fields)
112-
fields.append(QgsField(zName, QVariant.Double))
108+
new_fields.append(QgsField('mvalue', QVariant.Double))
113109

110+
fields = QgsProcessingUtils.combineFields(fields, new_fields)
114111
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
115112
fields, wkb_type, source.sourceCrs())
116113

‎python/plugins/processing/algs/qgis/Intersection.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
QgsProcessingParameterFeatureSource,
4040
QgsProcessingParameterFeatureSink,
4141
QgsSpatialIndex,
42-
QgsProcessingParameterField)
42+
QgsProcessingParameterField,
43+
QgsProcessingUtils)
4344

4445
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
4546
from processing.tools import vector
@@ -122,12 +123,10 @@ def processAlgorithm(self, parameters, context, feedback):
122123
fieldListB = sourceB.fields()
123124
field_indices_b = [i for i in range(0, fieldListB.count())]
124125

125-
fieldListB = vector.testForUniqueness(fieldListA, fieldListB)
126-
for b in fieldListB:
127-
fieldListA.append(b)
126+
output_fields = QgsProcessingUtils.combineFields(fieldListA, fieldListB)
128127

129128
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
130-
fieldListA, geomType, sourceA.sourceCrs())
129+
output_fields, geomType, sourceA.sourceCrs())
131130

132131
outFeat = QgsFeature()
133132
indexB = QgsSpatialIndex(sourceB.getFeatures(QgsFeatureRequest().setSubsetOfAttributes([]).setDestinationCrs(sourceA.sourceCrs())), feedback)

‎python/plugins/processing/algs/qgis/MeanCoords.py

Lines changed: 0 additions & 177 deletions
This file was deleted.

‎python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
from .Intersection import Intersection
9393
from .JoinAttributes import JoinAttributes
9494
from .LinesToPolygons import LinesToPolygons
95-
from .MeanCoords import MeanCoords
9695
from .Merge import Merge
9796
from .MinimumBoundingGeometry import MinimumBoundingGeometry
9897
from .NearestNeighbourAnalysis import NearestNeighbourAnalysis
@@ -226,7 +225,6 @@ def getAlgs(self):
226225
Intersection(),
227226
JoinAttributes(),
228227
LinesToPolygons(),
229-
MeanCoords(),
230228
Merge(),
231229
MinimumBoundingGeometry(),
232230
NearestNeighbourAnalysis(),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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/ mean_coordinates_unique_grouped.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.2</gml:Y></gml:coord>
10+
<gml:coord><gml:X>3.5</gml:X><gml:Y>2</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:mean_coordinates_unique_grouped fid="mean_coordinates_unique_grouped.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.0,1.5</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
<ogr:MEAN_X>3.000000000000000</ogr:MEAN_X>
18+
<ogr:MEAN_Y>1.500000000000000</ogr:MEAN_Y>
19+
<ogr:id2>2</ogr:id2>
20+
</ogr:mean_coordinates_unique_grouped>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:mean_coordinates_unique_grouped fid="mean_coordinates_unique_grouped.1">
24+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.4,-1.2</gml:coordinates></gml:Point></ogr:geometryProperty>
25+
<ogr:MEAN_X>3.400000000000000</ogr:MEAN_X>
26+
<ogr:MEAN_Y>-1.200000000000000</ogr:MEAN_Y>
27+
<ogr:id2>0</ogr:id2>
28+
</ogr:mean_coordinates_unique_grouped>
29+
</gml:featureMember>
30+
<gml:featureMember>
31+
<ogr:mean_coordinates_unique_grouped fid="mean_coordinates_unique_grouped.2">
32+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.5,2.0</gml:coordinates></gml:Point></ogr:geometryProperty>
33+
<ogr:MEAN_X>3.500000000000000</ogr:MEAN_X>
34+
<ogr:MEAN_Y>2.000000000000000</ogr:MEAN_Y>
35+
<ogr:id2>1</ogr:id2>
36+
</ogr:mean_coordinates_unique_grouped>
37+
</gml:featureMember>
38+
</ogr:FeatureCollection>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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="mean_coordinates_unique_grouped" type="ogr:mean_coordinates_unique_grouped_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="mean_coordinates_unique_grouped_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="MEAN_X" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:decimal">
22+
<xs:totalDigits value="25"/>
23+
<xs:fractionDigits value="15"/>
24+
</xs:restriction>
25+
</xs:simpleType>
26+
</xs:element>
27+
<xs:element name="MEAN_Y" nillable="true" minOccurs="0" maxOccurs="1">
28+
<xs:simpleType>
29+
<xs:restriction base="xs:decimal">
30+
<xs:totalDigits value="25"/>
31+
<xs:fractionDigits value="15"/>
32+
</xs:restriction>
33+
</xs:simpleType>
34+
</xs:element>
35+
<xs:element name="id2" nillable="true" minOccurs="0" maxOccurs="1">
36+
<xs:simpleType>
37+
<xs:restriction base="xs:integer">
38+
<xs:totalDigits value="10"/>
39+
</xs:restriction>
40+
</xs:simpleType>
41+
</xs:element>
42+
</xs:sequence>
43+
</xs:extension>
44+
</xs:complexContent>
45+
</xs:complexType>
46+
</xs:schema>
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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/ mean_coordinates_unique_grouped_2.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:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3,3</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
<ogr:MEAN_X>3.000000000000000</ogr:MEAN_X>
18+
<ogr:MEAN_Y>3.000000000000000</ogr:MEAN_Y>
19+
<ogr:id>2</ogr:id>
20+
</ogr:mean_coordinates_unique_grouped_2>
21+
</gml:featureMember>
22+
<gml:featureMember>
23+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.1">
24+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>2,2</gml:coordinates></gml:Point></ogr:geometryProperty>
25+
<ogr:MEAN_X>2.000000000000000</ogr:MEAN_X>
26+
<ogr:MEAN_Y>2.000000000000000</ogr:MEAN_Y>
27+
<ogr:id>3</ogr:id>
28+
</ogr:mean_coordinates_unique_grouped_2>
29+
</gml:featureMember>
30+
<gml:featureMember>
31+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.2">
32+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>5,2</gml:coordinates></gml:Point></ogr:geometryProperty>
33+
<ogr:MEAN_X>5.000000000000000</ogr:MEAN_X>
34+
<ogr:MEAN_Y>2.000000000000000</ogr:MEAN_Y>
35+
<ogr:id>4</ogr:id>
36+
</ogr:mean_coordinates_unique_grouped_2>
37+
</gml:featureMember>
38+
<gml:featureMember>
39+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.3">
40+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>4,1</gml:coordinates></gml:Point></ogr:geometryProperty>
41+
<ogr:MEAN_X>4.000000000000000</ogr:MEAN_X>
42+
<ogr:MEAN_Y>1.000000000000000</ogr:MEAN_Y>
43+
<ogr:id>5</ogr:id>
44+
</ogr:mean_coordinates_unique_grouped_2>
45+
</gml:featureMember>
46+
<gml:featureMember>
47+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.4">
48+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-5</gml:coordinates></gml:Point></ogr:geometryProperty>
49+
<ogr:MEAN_X>0.000000000000000</ogr:MEAN_X>
50+
<ogr:MEAN_Y>-5.000000000000000</ogr:MEAN_Y>
51+
<ogr:id>6</ogr:id>
52+
</ogr:mean_coordinates_unique_grouped_2>
53+
</gml:featureMember>
54+
<gml:featureMember>
55+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.5">
56+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>8,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
57+
<ogr:MEAN_X>8.000000000000000</ogr:MEAN_X>
58+
<ogr:MEAN_Y>-1.000000000000000</ogr:MEAN_Y>
59+
<ogr:id>7</ogr:id>
60+
</ogr:mean_coordinates_unique_grouped_2>
61+
</gml:featureMember>
62+
<gml:featureMember>
63+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.6">
64+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>7,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
65+
<ogr:MEAN_X>7.000000000000000</ogr:MEAN_X>
66+
<ogr:MEAN_Y>-1.000000000000000</ogr:MEAN_Y>
67+
<ogr:id>8</ogr:id>
68+
</ogr:mean_coordinates_unique_grouped_2>
69+
</gml:featureMember>
70+
<gml:featureMember>
71+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.7">
72+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>0,-1</gml:coordinates></gml:Point></ogr:geometryProperty>
73+
<ogr:MEAN_X>0.000000000000000</ogr:MEAN_X>
74+
<ogr:MEAN_Y>-1.000000000000000</ogr:MEAN_Y>
75+
<ogr:id>9</ogr:id>
76+
</ogr:mean_coordinates_unique_grouped_2>
77+
</gml:featureMember>
78+
<gml:featureMember>
79+
<ogr:mean_coordinates_unique_grouped_2 fid="mean_coordinates_unique_grouped_2.8">
80+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>1,1</gml:coordinates></gml:Point></ogr:geometryProperty>
81+
<ogr:MEAN_X>1.000000000000000</ogr:MEAN_X>
82+
<ogr:MEAN_Y>1.000000000000000</ogr:MEAN_Y>
83+
<ogr:id>1</ogr:id>
84+
</ogr:mean_coordinates_unique_grouped_2>
85+
</gml:featureMember>
86+
</ogr:FeatureCollection>
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
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="mean_coordinates_unique_grouped_2" type="ogr:mean_coordinates_unique_grouped_2_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="mean_coordinates_unique_grouped_2_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="MEAN_X" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:decimal">
22+
<xs:totalDigits value="25"/>
23+
<xs:fractionDigits value="15"/>
24+
</xs:restriction>
25+
</xs:simpleType>
26+
</xs:element>
27+
<xs:element name="MEAN_Y" nillable="true" minOccurs="0" maxOccurs="1">
28+
<xs:simpleType>
29+
<xs:restriction base="xs:decimal">
30+
<xs:totalDigits value="25"/>
31+
<xs:fractionDigits value="15"/>
32+
</xs:restriction>
33+
</xs:simpleType>
34+
</xs:element>
35+
<xs:element name="id" nillable="true" minOccurs="0" maxOccurs="1">
36+
<xs:simpleType>
37+
<xs:restriction base="xs:integer">
38+
<xs:totalDigits value="10"/>
39+
</xs:restriction>
40+
</xs:simpleType>
41+
</xs:element>
42+
</xs:sequence>
43+
</xs:extension>
44+
</xs:complexContent>
45+
</xs:complexType>
46+
</xs:schema>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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/ unique_coordinates_weight.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.666666666666667</gml:X><gml:Y>-0.6222222222222222</gml:Y></gml:coord>
10+
<gml:coord><gml:X>3.666666666666667</gml:X><gml:Y>-0.6222222222222222</gml:Y></gml:coord>
11+
</gml:Box>
12+
</gml:boundedBy>
13+
14+
<gml:featureMember>
15+
<ogr:unique_coordinates_weight fid="unique_coordinates_weight.0">
16+
<ogr:geometryProperty><gml:Point srsName="EPSG:4326"><gml:coordinates>3.66666666666667,-0.622222222222222</gml:coordinates></gml:Point></ogr:geometryProperty>
17+
<ogr:MEAN_X>3.666666666666667</ogr:MEAN_X>
18+
<ogr:MEAN_Y>-0.622222222222222</ogr:MEAN_Y>
19+
</ogr:unique_coordinates_weight>
20+
</gml:featureMember>
21+
</ogr:FeatureCollection>
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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="unique_coordinates_weight" type="ogr:unique_coordinates_weight_Type" substitutionGroup="gml:_Feature"/>
14+
<xs:complexType name="unique_coordinates_weight_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="MEAN_X" nillable="true" minOccurs="0" maxOccurs="1">
20+
<xs:simpleType>
21+
<xs:restriction base="xs:decimal">
22+
<xs:totalDigits value="25"/>
23+
<xs:fractionDigits value="15"/>
24+
</xs:restriction>
25+
</xs:simpleType>
26+
</xs:element>
27+
<xs:element name="MEAN_Y" nillable="true" minOccurs="0" maxOccurs="1">
28+
<xs:simpleType>
29+
<xs:restriction base="xs:decimal">
30+
<xs:totalDigits value="25"/>
31+
<xs:fractionDigits value="15"/>
32+
</xs:restriction>
33+
</xs:simpleType>
34+
</xs:element>
35+
</xs:sequence>
36+
</xs:extension>
37+
</xs:complexContent>
38+
</xs:complexType>
39+
</xs:schema>

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

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2665,7 +2665,7 @@ tests:
26652665
name: expected/points_along_lines.gml
26662666
type: vector
26672667

2668-
- algorithm: qgis:meancoordinates
2668+
- algorithm: native:meancoordinates
26692669
name: standard mean coordinates
26702670
params:
26712671
INPUT:
@@ -2676,6 +2676,53 @@ tests:
26762676
name: expected/mean_coordinates.gml
26772677
type: vector
26782678

2679+
- algorithm: native:meancoordinates
2680+
name: Mean coordinates, multiple grouped
2681+
params:
2682+
INPUT:
2683+
name: points.gml
2684+
type: vector
2685+
UID: id2
2686+
results:
2687+
OUTPUT:
2688+
name: expected/mean_coordinates_unique_grouped.gml
2689+
type: vector
2690+
pk: id2
2691+
compare:
2692+
fields:
2693+
fid: skip
2694+
2695+
- algorithm: native:meancoordinates
2696+
name: Mean coordinates, unique field
2697+
params:
2698+
INPUT:
2699+
name: points.gml
2700+
type: vector
2701+
UID: id
2702+
results:
2703+
OUTPUT:
2704+
name: expected/mean_coordinates_unique_grouped_2.gml
2705+
type: vector
2706+
pk: id
2707+
compare:
2708+
fields:
2709+
fid: skip
2710+
2711+
- algorithm: native:meancoordinates
2712+
name: Mean coordinates, weighted
2713+
params:
2714+
INPUT:
2715+
name: points.gml
2716+
type: vector
2717+
WEIGHT: id
2718+
results:
2719+
OUTPUT:
2720+
name: expected/unique_coordinates_weight.gml
2721+
type: vector
2722+
compare:
2723+
fields:
2724+
fid: skip
2725+
26792726
- algorithm: native:collect
26802727
name: single part to multipart
26812728
params:

‎python/plugins/processing/tools/vector.py

Lines changed: 2 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,8 @@
2727

2828
import csv
2929

30-
from qgis.PyQt.QtCore import QVariant
31-
from qgis.core import (QgsFields,
32-
QgsField,
33-
QgsGeometry,
34-
QgsWkbTypes,
35-
QgsFeatureRequest,
36-
QgsPointXY)
30+
from qgis.core import (QgsWkbTypes,
31+
QgsFeatureRequest)
3732

3833

3934
def resolveFieldIndex(source, attr):
@@ -95,85 +90,6 @@ def values(source, *attributes):
9590
return ret
9691

9792

98-
def testForUniqueness(fieldList1, fieldList2):
99-
'''Returns a modified version of fieldList2, removing naming
100-
collisions with fieldList1.'''
101-
changed = True
102-
while changed:
103-
changed = False
104-
for i in range(0, len(fieldList1)):
105-
for j in range(0, len(fieldList2)):
106-
if fieldList1[i].name() == fieldList2[j].name():
107-
field = fieldList2[j]
108-
name = createUniqueFieldName(field.name(), fieldList1)
109-
fieldList2[j] = QgsField(name, field.type(), len=field.length(), prec=field.precision(), comment=field.comment())
110-
changed = True
111-
return fieldList2
112-
113-
114-
def createUniqueFieldName(fieldName, fieldList):
115-
def nextname(name):
116-
num = 1
117-
while True:
118-
returnname = '{name}_{num}'.format(name=name[:8], num=num)
119-
yield returnname
120-
num += 1
121-
122-
def found(name):
123-
return any(f.name() == name for f in fieldList)
124-
125-
shortName = fieldName[:10]
126-
127-
if not fieldList:
128-
return shortName
129-
130-
if not found(shortName):
131-
return shortName
132-
133-
for newname in nextname(shortName):
134-
if not found(newname):
135-
return newname
136-
137-
138-
def findOrCreateField(layer, fieldList, fieldName, fieldLen=24, fieldPrec=15):
139-
idx = layer.fields().lookupField(fieldName)
140-
if idx == -1:
141-
fn = createUniqueFieldName(fieldName, fieldList)
142-
field = QgsField(fn, QVariant.Double, '', fieldLen, fieldPrec)
143-
idx = len(fieldList)
144-
fieldList.append(field)
145-
146-
return (idx, fieldList)
147-
148-
149-
def extractPoints(geom):
150-
points = []
151-
if geom.type() == QgsWkbTypes.PointGeometry:
152-
if geom.isMultipart():
153-
points = geom.asMultiPoint()
154-
else:
155-
points.append(geom.asPoint())
156-
elif geom.type() == QgsWkbTypes.LineGeometry:
157-
if geom.isMultipart():
158-
lines = geom.asMultiPolyline()
159-
for line in lines:
160-
points.extend(line)
161-
else:
162-
points = geom.asPolyline()
163-
elif geom.type() == QgsWkbTypes.PolygonGeometry:
164-
if geom.isMultipart():
165-
polygons = geom.asMultiPolygon()
166-
for poly in polygons:
167-
for line in poly:
168-
points.extend(line)
169-
else:
170-
polygon = geom.asPolygon()
171-
for line in polygon:
172-
points.extend(line)
173-
174-
return points
175-
176-
17793
def checkMinDistance(point, index, distance, points):
17894
"""Check if distance from given point to all other points is greater
17995
than given value.

‎src/core/processing/qgsnativealgorithms.cpp

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ void QgsNativeAlgorithms::loadAlgorithms()
8787
addAlgorithm( new QgsExtentToLayerAlgorithm() );
8888
addAlgorithm( new QgsLineIntersectionAlgorithm() );
8989
addAlgorithm( new QgsSplitWithLinesAlgorithm() );
90+
addAlgorithm( new QgsMeanCoordinatesAlgorithm() );
9091
}
9192

9293
void QgsSaveSelectedFeatures::initAlgorithm( const QVariantMap & )
@@ -2412,6 +2413,179 @@ QVariantMap QgsSplitWithLinesAlgorithm::processAlgorithm( const QVariantMap &par
24122413
}
24132414

24142415

2416+
void QgsMeanCoordinatesAlgorithm::initAlgorithm( const QVariantMap & )
2417+
{
2418+
addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ),
2419+
QObject::tr( "Input layer" ), QList< int >() << QgsProcessing::TypeVectorAnyGeometry ) );
2420+
addParameter( new QgsProcessingParameterField( QStringLiteral( "WEIGHT" ), QObject::tr( "Weight field" ),
2421+
QVariant(), QStringLiteral( "INPUT" ),
2422+
QgsProcessingParameterField::Numeric, false, true ) );
2423+
addParameter( new QgsProcessingParameterField( QStringLiteral( "UID" ),
2424+
QObject::tr( "Unique ID field" ), QVariant(),
2425+
QStringLiteral( "INPUT" ), QgsProcessingParameterField::Any, false, true ) );
2426+
addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "Mean coordinates" ), QgsProcessing::TypeVectorPoint ) );
2427+
}
2428+
2429+
QString QgsMeanCoordinatesAlgorithm::shortHelpString() const
2430+
{
2431+
return QObject::tr( "This algorithm computes a point layer with the center of mass of geometries in an input layer.\n\n"
2432+
"An attribute can be specified as containing weights to be applied to each feature when computing the center of mass.\n\n"
2433+
"If an attribute is selected in the <Unique ID field> parameter, features will be grouped according "
2434+
"to values in this field. Instead of a single point with the center of mass of the whole layer, "
2435+
"the output layer will contain a center of mass for the features in each category." );
2436+
}
2437+
2438+
QgsMeanCoordinatesAlgorithm *QgsMeanCoordinatesAlgorithm::createInstance() const
2439+
{
2440+
return new QgsMeanCoordinatesAlgorithm();
2441+
}
2442+
2443+
QVariantMap QgsMeanCoordinatesAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
2444+
{
2445+
std::unique_ptr< QgsFeatureSource > source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
2446+
if ( !source )
2447+
return QVariantMap();
2448+
2449+
QString weightFieldName = parameterAsString( parameters, QStringLiteral( "WEIGHT" ), context );
2450+
QString uniqueFieldName = parameterAsString( parameters, QStringLiteral( "UID" ), context );
2451+
2452+
QgsAttributeList attributes;
2453+
int weightIndex = -1;
2454+
if ( !weightFieldName.isEmpty() )
2455+
{
2456+
weightIndex = source->fields().lookupField( weightFieldName );
2457+
if ( weightIndex >= 0 )
2458+
attributes.append( weightIndex );
2459+
}
2460+
2461+
int uniqueFieldIndex = -1;
2462+
if ( !uniqueFieldName.isEmpty() )
2463+
{
2464+
uniqueFieldIndex = source->fields().lookupField( uniqueFieldName );
2465+
if ( uniqueFieldIndex >= 0 )
2466+
attributes.append( uniqueFieldIndex );
2467+
}
2468+
2469+
QgsFields fields;
2470+
fields.append( QgsField( QStringLiteral( "MEAN_X" ), QVariant::Double, QString(), 24, 15 ) );
2471+
fields.append( QgsField( QStringLiteral( "MEAN_Y" ), QVariant::Double, QString(), 24, 15 ) );
2472+
if ( uniqueFieldIndex >= 0 )
2473+
{
2474+
QgsField uniqueField = source->fields().at( uniqueFieldIndex );
2475+
fields.append( uniqueField );
2476+
}
2477+
2478+
QString dest;
2479+
std::unique_ptr< QgsFeatureSink > sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields,
2480+
QgsWkbTypes::Point, source->sourceCrs() ) );
2481+
if ( !sink )
2482+
return QVariantMap();
2483+
2484+
QgsFeatureIterator features = source->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( attributes ) );
2485+
2486+
double step = source->featureCount() > 0 ? 50.0 / source->featureCount() : 1;
2487+
int i = 0;
2488+
QgsFeature feat;
2489+
2490+
QHash< QVariant, QList< double > > means;
2491+
while ( features.nextFeature( feat ) )
2492+
{
2493+
i++;
2494+
if ( feedback->isCanceled() )
2495+
{
2496+
break;
2497+
}
2498+
2499+
feedback->setProgress( i * step );
2500+
if ( !feat.hasGeometry() )
2501+
continue;
2502+
2503+
2504+
QVariant featureClass;
2505+
if ( uniqueFieldIndex >= 0 )
2506+
{
2507+
featureClass = feat.attribute( uniqueFieldIndex );
2508+
}
2509+
else
2510+
{
2511+
featureClass = QStringLiteral( "#####singleclass#####" );
2512+
}
2513+
2514+
double weight = 1;
2515+
if ( weightIndex >= 0 )
2516+
{
2517+
bool ok = false;
2518+
weight = feat.attribute( weightIndex ).toDouble( &ok );
2519+
if ( !ok )
2520+
weight = 1.0;
2521+
}
2522+
2523+
if ( weight < 0 )
2524+
{
2525+
throw QgsProcessingException( QObject::tr( "Negative weight value found. Please fix your data and try again." ) );
2526+
}
2527+
2528+
QList< double > values = means.value( featureClass );
2529+
double cx = 0;
2530+
double cy = 0;
2531+
double totalWeight = 0;
2532+
if ( !values.empty() )
2533+
{
2534+
cx = values.at( 0 );
2535+
cy = values.at( 1 );
2536+
totalWeight = values.at( 2 );
2537+
}
2538+
2539+
QgsVertexId vid;
2540+
QgsPoint pt;
2541+
const QgsAbstractGeometry *g = feat.geometry().geometry();
2542+
// NOTE - should this be including the duplicate nodes for closed rings? currently it is,
2543+
// but I suspect that the expected behavior would be to NOT include these
2544+
while ( g->nextVertex( vid, pt ) )
2545+
{
2546+
cx += pt.x() * weight;
2547+
cy += pt.y() * weight;
2548+
totalWeight += weight;
2549+
}
2550+
2551+
means[featureClass] = QList< double >() << cx << cy << totalWeight;
2552+
}
2553+
2554+
i = 0;
2555+
step = !means.empty() ? 50.0 / means.count() : 1;
2556+
for ( auto it = means.constBegin(); it != means.constEnd(); ++it )
2557+
{
2558+
i++;
2559+
if ( feedback->isCanceled() )
2560+
{
2561+
break;
2562+
}
2563+
2564+
feedback->setProgress( 50 + i * step );
2565+
if ( qgsDoubleNear( it.value().at( 2 ), 0 ) )
2566+
continue;
2567+
2568+
QgsFeature outFeat;
2569+
double cx = it.value().at( 0 ) / it.value().at( 2 );
2570+
double cy = it.value().at( 1 ) / it.value().at( 2 );
2571+
2572+
QgsPointXY meanPoint( cx, cy );
2573+
outFeat.setGeometry( QgsGeometry::fromPoint( meanPoint ) );
2574+
2575+
QgsAttributes attributes;
2576+
attributes << cx << cy;
2577+
if ( uniqueFieldIndex >= 0 )
2578+
attributes.append( it.key() );
2579+
2580+
outFeat.setAttributes( attributes );
2581+
sink->addFeature( outFeat, QgsFeatureSink::FastInsert );
2582+
}
2583+
2584+
QVariantMap outputs;
2585+
outputs.insert( QStringLiteral( "OUTPUT" ), dest );
2586+
return outputs;
2587+
}
2588+
24152589
///@endcond
24162590

24172591

‎src/core/processing/qgsnativealgorithms.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,6 +786,30 @@ class QgsSplitWithLinesAlgorithm : public QgsProcessingAlgorithm
786786

787787
};
788788

789+
/**
790+
* Native mean coordinates algorithm.
791+
*/
792+
class QgsMeanCoordinatesAlgorithm : public QgsProcessingAlgorithm
793+
{
794+
795+
public:
796+
797+
QgsMeanCoordinatesAlgorithm() = default;
798+
void initAlgorithm( const QVariantMap &configuration = QVariantMap() ) override;
799+
QString name() const override { return QStringLiteral( "meancoordinates" ); }
800+
QString displayName() const override { return QObject::tr( "Mean coordinate(s)" ); }
801+
virtual QStringList tags() const override { return QObject::tr( "mean,average,coordinate" ).split( ',' ); }
802+
QString group() const override { return QObject::tr( "Vector analysis" ); }
803+
QString shortHelpString() const override;
804+
QgsMeanCoordinatesAlgorithm *createInstance() const override SIP_FACTORY;
805+
806+
protected:
807+
808+
virtual QVariantMap processAlgorithm( const QVariantMap &parameters,
809+
QgsProcessingContext &context, QgsProcessingFeedback *feedback ) override;
810+
811+
};
812+
789813
///@endcond PRIVATE
790814

791815
#endif // QGSNATIVEALGORITHMS_H

0 commit comments

Comments
 (0)
Please sign in to comment.