Skip to content

Commit cfb926a

Browse files
committed
Port Find Projection alg to new API
Also modify alg to export a vector table of candidates instead of a HTML list, since a vector table is more useful inside of models and can be used for further analysis steps.
1 parent a56725f commit cfb926a

File tree

5 files changed

+131
-58
lines changed

5 files changed

+131
-58
lines changed

python/plugins/processing/algs/qgis/FindProjection.py

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,32 @@
2626
__revision__ = '$Format:%H$'
2727

2828
import os
29-
import codecs
3029

31-
from qgis.core import (QgsApplication,
32-
QgsGeometry,
30+
from qgis.core import (QgsGeometry,
31+
QgsFeature,
3332
QgsFeatureSink,
34-
QgsRectangle,
33+
QgsField,
34+
QgsFields,
3535
QgsCoordinateReferenceSystem,
3636
QgsCoordinateTransform,
37-
QgsProcessingUtils)
37+
QgsWkbTypes,
38+
QgsProcessingParameterFeatureSource,
39+
QgsProcessingParameterExtent,
40+
QgsProcessingParameterCrs,
41+
QgsProcessingParameterFeatureSink)
42+
from qgis.PyQt.QtCore import QVariant
3843

3944
from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
40-
from processing.core.parameters import ParameterVector
41-
from processing.core.parameters import ParameterCrs
42-
from processing.core.parameters import ParameterExtent
43-
from processing.core.outputs import OutputHTML
4445

4546
pluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]
4647

4748

4849
class FindProjection(QgisAlgorithm):
4950

50-
INPUT_LAYER = 'INPUT_LAYER'
51+
INPUT = 'INPUT'
5152
TARGET_AREA = 'TARGET_AREA'
5253
TARGET_AREA_CRS = 'TARGET_AREA_CRS'
53-
OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE'
54+
OUTPUT = 'OUTPUT'
5455

5556
def tags(self):
5657
return self.tr('crs,srs,coordinate,reference,system,guess,estimate,finder,determine').split(',')
@@ -62,17 +63,16 @@ def __init__(self):
6263
super().__init__()
6364

6465
def initAlgorithm(self, config=None):
65-
self.addParameter(ParameterVector(self.INPUT_LAYER,
66-
self.tr('Input layer')))
67-
extent_parameter = ParameterExtent(self.TARGET_AREA,
68-
self.tr('Target area for layer'),
69-
self.INPUT_LAYER)
70-
extent_parameter.skip_crs_check = True
66+
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
67+
self.tr('Input layer')))
68+
extent_parameter = QgsProcessingParameterExtent(self.TARGET_AREA,
69+
self.tr('Target area for layer'))
70+
#extent_parameter.skip_crs_check = True
7171
self.addParameter(extent_parameter)
72-
self.addParameter(ParameterCrs(self.TARGET_AREA_CRS, 'Target area CRS'))
72+
self.addParameter(QgsProcessingParameterCrs(self.TARGET_AREA_CRS, 'Target area CRS'))
7373

74-
self.addOutput(OutputHTML(self.OUTPUT_HTML_FILE,
75-
self.tr('Candidates')))
74+
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
75+
self.tr('CRS candidates')))
7676

7777
def name(self):
7878
return 'findprojection'
@@ -81,27 +81,34 @@ def displayName(self):
8181
return self.tr('Find projection')
8282

8383
def processAlgorithm(self, parameters, context, feedback):
84-
layer = QgsProcessingUtils.mapLayerFromString(self.getParameterValue(self.INPUT_LAYER), context)
84+
source = self.parameterAsSource(parameters, self.INPUT, context)
8585

86-
extent = self.getParameterValue(self.TARGET_AREA).split(',')
87-
if not extent:
88-
extent = QgsProcessingUtils.combineLayerExtents([layer])
89-
target_crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.TARGET_AREA_CRS))
86+
extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context)
87+
target_crs = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context)
9088

91-
target_geom = QgsGeometry.fromRect(QgsRectangle(float(extent[0]), float(extent[2]),
92-
float(extent[1]), float(extent[3])))
89+
target_geom = QgsGeometry.fromRect(extent)
9390

94-
output_file = self.getOutputValue(self.OUTPUT_HTML_FILE)
91+
fields = QgsFields()
92+
fields.append(QgsField('auth_id', QVariant.String, '', 20))
93+
94+
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
95+
fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())
9596

9697
# make intersection tests nice and fast
9798
engine = QgsGeometry.createGeometryEngine(target_geom.geometry())
9899
engine.prepareGeometry()
99100

100-
layer_bounds = QgsGeometry.fromRect(layer.extent())
101+
layer_bounds = QgsGeometry.fromRect(source.sourceExtent())
102+
103+
crses_to_check = QgsCoordinateReferenceSystem.validSrsIds()
104+
total = 100.0 / len(crses_to_check)
105+
106+
found_results = 0
101107

102-
results = []
108+
for current, srs_id in enumerate(crses_to_check):
109+
if feedback.isCanceled():
110+
break
103111

104-
for srs_id in QgsCoordinateReferenceSystem.validSrsIds():
105112
candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id)
106113
if not candidate_crs.isValid():
107114
continue
@@ -115,15 +122,15 @@ def processAlgorithm(self, parameters, context, feedback):
115122
continue
116123

117124
if engine.intersects(transformed_bounds.geometry()):
118-
results.append(candidate_crs.authid())
119-
120-
self.createHTML(output_file, results)
121-
122-
def createHTML(self, outputFile, candidates):
123-
with codecs.open(outputFile, 'w', encoding='utf-8') as f:
124-
f.write('<html><head>\n')
125-
f.write('<meta http-equiv="Content-Type" content="text/html; \
126-
charset=utf-8" /></head><body>\n')
127-
for c in candidates:
128-
f.write('<p>' + c + '</p>\n')
129-
f.write('</body></html>\n')
125+
feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid()))
126+
f = QgsFeature(fields)
127+
f.setAttributes([candidate_crs.authid()])
128+
sink.addFeature(f, QgsFeatureSink.FastInsert)
129+
found_results += 1
130+
131+
feedback.setProgress(int(current * total))
132+
133+
if found_results == 0:
134+
feedback.reportError(self.tr('No matching projections found'))
135+
136+
return {self.OUTPUT: dest_id}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
from .FieldPyculator import FieldsPyculator
7474
from .FieldsCalculator import FieldsCalculator
7575
from .FieldsMapper import FieldsMapper
76+
from .FindProjection import FindProjection
7677
from .FixedDistanceBuffer import FixedDistanceBuffer
7778
from .FixGeometry import FixGeometry
7879
from .GeometryByExpression import GeometryByExpression
@@ -172,7 +173,6 @@
172173
# from .DefineProjection import DefineProjection
173174
# from .RasterCalculator import RasterCalculator
174175
# from .ExecuteSQL import ExecuteSQL
175-
# from .FindProjection import FindProjection
176176

177177
pluginPath = os.path.normpath(os.path.join(
178178
os.path.split(os.path.dirname(__file__))[0], os.pardir))
@@ -194,7 +194,7 @@ def getAlgs(self):
194194
# SelectByAttributeSum()
195195
# DefineProjection(),
196196
# RasterCalculator(),
197-
# ExecuteSQL(), FindProjection(),
197+
# ExecuteSQL(),
198198
# ]
199199
algs = [AddTableField(),
200200
Aggregate(),
@@ -229,6 +229,7 @@ def getAlgs(self):
229229
FieldsCalculator(),
230230
FieldsMapper(),
231231
FieldsPyculator(),
232+
FindProjection(),
232233
FixedDistanceBuffer(),
233234
FixGeometry(),
234235
GeometryByExpression(),
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<GMLFeatureClassList>
2+
<GMLFeatureClass>
3+
<Name>projection_candidates</Name>
4+
<ElementPath>projection_candidates</ElementPath>
5+
<GeometryType>100</GeometryType>
6+
<DatasetSpecificInfo>
7+
<FeatureCount>8</FeatureCount>
8+
</DatasetSpecificInfo>
9+
<PropertyDefn>
10+
<Name>auth_id</Name>
11+
<ElementPath>auth_id</ElementPath>
12+
<Type>String</Type>
13+
<Width>14</Width>
14+
</PropertyDefn>
15+
</GMLFeatureClass>
16+
</GMLFeatureClassList>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ogr:FeatureCollection
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation=""
5+
xmlns:ogr="http://ogr.maptools.org/"
6+
xmlns:gml="http://www.opengis.net/gml">
7+
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>
8+
9+
<gml:featureMember>
10+
<ogr:projection_candidates fid="projection_candidates.0">
11+
<ogr:auth_id>EPSG:20256</ogr:auth_id>
12+
</ogr:projection_candidates>
13+
</gml:featureMember>
14+
<gml:featureMember>
15+
<ogr:projection_candidates fid="projection_candidates.1">
16+
<ogr:auth_id>EPSG:20356</ogr:auth_id>
17+
</ogr:projection_candidates>
18+
</gml:featureMember>
19+
<gml:featureMember>
20+
<ogr:projection_candidates fid="projection_candidates.2">
21+
<ogr:auth_id>EPSG:28356</ogr:auth_id>
22+
</ogr:projection_candidates>
23+
</gml:featureMember>
24+
<gml:featureMember>
25+
<ogr:projection_candidates fid="projection_candidates.3">
26+
<ogr:auth_id>EPSG:32356</ogr:auth_id>
27+
</ogr:projection_candidates>
28+
</gml:featureMember>
29+
<gml:featureMember>
30+
<ogr:projection_candidates fid="projection_candidates.4">
31+
<ogr:auth_id>EPSG:32556</ogr:auth_id>
32+
</ogr:projection_candidates>
33+
</gml:featureMember>
34+
<gml:featureMember>
35+
<ogr:projection_candidates fid="projection_candidates.5">
36+
<ogr:auth_id>EPSG:32756</ogr:auth_id>
37+
</ogr:projection_candidates>
38+
</gml:featureMember>
39+
<gml:featureMember>
40+
<ogr:projection_candidates fid="projection_candidates.6">
41+
<ogr:auth_id>IGNF:UTM56SW84</ogr:auth_id>
42+
</ogr:projection_candidates>
43+
</gml:featureMember>
44+
<gml:featureMember>
45+
<ogr:projection_candidates fid="projection_candidates.7">
46+
<ogr:auth_id>EPSG:5552</ogr:auth_id>
47+
</ogr:projection_candidates>
48+
</gml:featureMember>
49+
</ogr:FeatureCollection>

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

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2827,19 +2827,19 @@ tests:
28272827
fields:
28282828
fid: skip
28292829

2830-
# - algorithm: qgis:findprojection
2831-
# name: Find projection
2832-
# params:
2833-
# INPUT_LAYER:
2834-
# name: custom/find_projection.gml
2835-
# type: vector
2836-
# TARGET_AREA: 151.1198,151.1368,-33.9118,-33.9003
2837-
# TARGET_AREA_CRS: EPSG:4326
2838-
# results:
2839-
# OUTPUT_HTML_FILE:
2840-
# name: expected/find_projection.html
2841-
# type: file
2842-
#
2830+
- algorithm: qgis:findprojection
2831+
name: Find projection
2832+
params:
2833+
INPUT:
2834+
name: custom/find_projection.gml
2835+
type: vector
2836+
TARGET_AREA: 151.1198,151.1368,-33.9118,-33.9003
2837+
TARGET_AREA_CRS: EPSG:4326
2838+
results:
2839+
OUTPUT:
2840+
name: expected/projection_candidates.gml
2841+
type: vector
2842+
28432843
- algorithm: qgis:polygonfromlayerextent
28442844
name: Standard polygon from layer extent
28452845
params:

0 commit comments

Comments
 (0)