Skip to content

Commit

Permalink
Port Find Projection alg to new API
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nyalldawson committed Aug 20, 2017
1 parent a56725f commit cfb926a
Show file tree
Hide file tree
Showing 5 changed files with 131 additions and 58 deletions.
93 changes: 50 additions & 43 deletions python/plugins/processing/algs/qgis/FindProjection.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,32 @@
__revision__ = '$Format:%H$'

import os
import codecs

from qgis.core import (QgsApplication,
QgsGeometry,
from qgis.core import (QgsGeometry,
QgsFeature,
QgsFeatureSink,
QgsRectangle,
QgsField,
QgsFields,
QgsCoordinateReferenceSystem,
QgsCoordinateTransform,
QgsProcessingUtils)
QgsWkbTypes,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterExtent,
QgsProcessingParameterCrs,
QgsProcessingParameterFeatureSink)
from qgis.PyQt.QtCore import QVariant

from processing.algs.qgis.QgisAlgorithm import QgisAlgorithm
from processing.core.parameters import ParameterVector
from processing.core.parameters import ParameterCrs
from processing.core.parameters import ParameterExtent
from processing.core.outputs import OutputHTML

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


class FindProjection(QgisAlgorithm):

INPUT_LAYER = 'INPUT_LAYER'
INPUT = 'INPUT'
TARGET_AREA = 'TARGET_AREA'
TARGET_AREA_CRS = 'TARGET_AREA_CRS'
OUTPUT_HTML_FILE = 'OUTPUT_HTML_FILE'
OUTPUT = 'OUTPUT'

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

def initAlgorithm(self, config=None):
self.addParameter(ParameterVector(self.INPUT_LAYER,
self.tr('Input layer')))
extent_parameter = ParameterExtent(self.TARGET_AREA,
self.tr('Target area for layer'),
self.INPUT_LAYER)
extent_parameter.skip_crs_check = True
self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,
self.tr('Input layer')))
extent_parameter = QgsProcessingParameterExtent(self.TARGET_AREA,
self.tr('Target area for layer'))
#extent_parameter.skip_crs_check = True
self.addParameter(extent_parameter)
self.addParameter(ParameterCrs(self.TARGET_AREA_CRS, 'Target area CRS'))
self.addParameter(QgsProcessingParameterCrs(self.TARGET_AREA_CRS, 'Target area CRS'))

self.addOutput(OutputHTML(self.OUTPUT_HTML_FILE,
self.tr('Candidates')))
self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,
self.tr('CRS candidates')))

def name(self):
return 'findprojection'
Expand All @@ -81,27 +81,34 @@ def displayName(self):
return self.tr('Find projection')

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

extent = self.getParameterValue(self.TARGET_AREA).split(',')
if not extent:
extent = QgsProcessingUtils.combineLayerExtents([layer])
target_crs = QgsCoordinateReferenceSystem(self.getParameterValue(self.TARGET_AREA_CRS))
extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context)
target_crs = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context)

target_geom = QgsGeometry.fromRect(QgsRectangle(float(extent[0]), float(extent[2]),
float(extent[1]), float(extent[3])))
target_geom = QgsGeometry.fromRect(extent)

output_file = self.getOutputValue(self.OUTPUT_HTML_FILE)
fields = QgsFields()
fields.append(QgsField('auth_id', QVariant.String, '', 20))

(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())

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

layer_bounds = QgsGeometry.fromRect(layer.extent())
layer_bounds = QgsGeometry.fromRect(source.sourceExtent())

crses_to_check = QgsCoordinateReferenceSystem.validSrsIds()
total = 100.0 / len(crses_to_check)

found_results = 0

results = []
for current, srs_id in enumerate(crses_to_check):
if feedback.isCanceled():
break

for srs_id in QgsCoordinateReferenceSystem.validSrsIds():
candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id)
if not candidate_crs.isValid():
continue
Expand All @@ -115,15 +122,15 @@ def processAlgorithm(self, parameters, context, feedback):
continue

if engine.intersects(transformed_bounds.geometry()):
results.append(candidate_crs.authid())

self.createHTML(output_file, results)

def createHTML(self, outputFile, candidates):
with codecs.open(outputFile, 'w', encoding='utf-8') as f:
f.write('<html><head>\n')
f.write('<meta http-equiv="Content-Type" content="text/html; \
charset=utf-8" /></head><body>\n')
for c in candidates:
f.write('<p>' + c + '</p>\n')
f.write('</body></html>\n')
feedback.pushInfo(self.tr('Found candidate CRS: {}').format(candidate_crs.authid()))
f = QgsFeature(fields)
f.setAttributes([candidate_crs.authid()])
sink.addFeature(f, QgsFeatureSink.FastInsert)
found_results += 1

feedback.setProgress(int(current * total))

if found_results == 0:
feedback.reportError(self.tr('No matching projections found'))

return {self.OUTPUT: dest_id}
5 changes: 3 additions & 2 deletions python/plugins/processing/algs/qgis/QGISAlgorithmProvider.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
from .FieldPyculator import FieldsPyculator
from .FieldsCalculator import FieldsCalculator
from .FieldsMapper import FieldsMapper
from .FindProjection import FindProjection
from .FixedDistanceBuffer import FixedDistanceBuffer
from .FixGeometry import FixGeometry
from .GeometryByExpression import GeometryByExpression
Expand Down Expand Up @@ -172,7 +173,6 @@
# from .DefineProjection import DefineProjection
# from .RasterCalculator import RasterCalculator
# from .ExecuteSQL import ExecuteSQL
# from .FindProjection import FindProjection

pluginPath = os.path.normpath(os.path.join(
os.path.split(os.path.dirname(__file__))[0], os.pardir))
Expand All @@ -194,7 +194,7 @@ def getAlgs(self):
# SelectByAttributeSum()
# DefineProjection(),
# RasterCalculator(),
# ExecuteSQL(), FindProjection(),
# ExecuteSQL(),
# ]
algs = [AddTableField(),
Aggregate(),
Expand Down Expand Up @@ -229,6 +229,7 @@ def getAlgs(self):
FieldsCalculator(),
FieldsMapper(),
FieldsPyculator(),
FindProjection(),
FixedDistanceBuffer(),
FixGeometry(),
GeometryByExpression(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<GMLFeatureClassList>
<GMLFeatureClass>
<Name>projection_candidates</Name>
<ElementPath>projection_candidates</ElementPath>
<GeometryType>100</GeometryType>
<DatasetSpecificInfo>
<FeatureCount>8</FeatureCount>
</DatasetSpecificInfo>
<PropertyDefn>
<Name>auth_id</Name>
<ElementPath>auth_id</ElementPath>
<Type>String</Type>
<Width>14</Width>
</PropertyDefn>
</GMLFeatureClass>
</GMLFeatureClassList>
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8" ?>
<ogr:FeatureCollection
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=""
xmlns:ogr="http://ogr.maptools.org/"
xmlns:gml="http://www.opengis.net/gml">
<gml:boundedBy><gml:null>missing</gml:null></gml:boundedBy>

<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.0">
<ogr:auth_id>EPSG:20256</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.1">
<ogr:auth_id>EPSG:20356</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.2">
<ogr:auth_id>EPSG:28356</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.3">
<ogr:auth_id>EPSG:32356</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.4">
<ogr:auth_id>EPSG:32556</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.5">
<ogr:auth_id>EPSG:32756</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.6">
<ogr:auth_id>IGNF:UTM56SW84</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
<gml:featureMember>
<ogr:projection_candidates fid="projection_candidates.7">
<ogr:auth_id>EPSG:5552</ogr:auth_id>
</ogr:projection_candidates>
</gml:featureMember>
</ogr:FeatureCollection>
26 changes: 13 additions & 13 deletions python/plugins/processing/tests/testdata/qgis_algorithm_tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2827,19 +2827,19 @@ tests:
fields:
fid: skip

# - algorithm: qgis:findprojection
# name: Find projection
# params:
# INPUT_LAYER:
# name: custom/find_projection.gml
# type: vector
# TARGET_AREA: 151.1198,151.1368,-33.9118,-33.9003
# TARGET_AREA_CRS: EPSG:4326
# results:
# OUTPUT_HTML_FILE:
# name: expected/find_projection.html
# type: file
#
- algorithm: qgis:findprojection
name: Find projection
params:
INPUT:
name: custom/find_projection.gml
type: vector
TARGET_AREA: 151.1198,151.1368,-33.9118,-33.9003
TARGET_AREA_CRS: EPSG:4326
results:
OUTPUT:
name: expected/projection_candidates.gml
type: vector

- algorithm: qgis:polygonfromlayerextent
name: Standard polygon from layer extent
params:
Expand Down

0 comments on commit cfb926a

Please sign in to comment.