| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | """***************************************************************************    FindProjection.py    -----------------    Date                 : February 2017    Copyright            : (C) 2017 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.                                   **                                                                         ****************************************************************************"""__author__ = 'Nyall Dawson'__date__ = 'February 2017'__copyright__ = '(C) 2017, Nyall Dawson'import osfrom qgis.core import (QgsGeometry,                       QgsFeature,                       QgsFeatureSink,                       QgsField,                       QgsFields,                       QgsCoordinateReferenceSystem,                       QgsCoordinateTransform,                       QgsCoordinateTransformContext,                       QgsWkbTypes,                       QgsProcessingException,                       QgsProcessingParameterFeatureSource,                       QgsProcessingParameterExtent,                       QgsProcessingParameterCrs,                       QgsProcessingParameterFeatureSink,                       QgsProcessingParameterDefinition)from qgis.PyQt.QtCore import QVariantfrom processing.algs.qgis.QgisAlgorithm import QgisAlgorithmpluginPath = os.path.split(os.path.split(os.path.dirname(__file__))[0])[0]class FindProjection(QgisAlgorithm):    INPUT = 'INPUT'    TARGET_AREA = 'TARGET_AREA'    TARGET_AREA_CRS = 'TARGET_AREA_CRS'    OUTPUT = 'OUTPUT'    def tags(self):        return self.tr('crs,srs,coordinate,reference,system,guess,estimate,finder,determine').split(',')    def group(self):        return self.tr('Vector general')    def groupId(self):        return 'vectorgeneral'    def __init__(self):        super().__init__()    def initAlgorithm(self, config=None):        self.addParameter(QgsProcessingParameterFeatureSource(self.INPUT,                                                              self.tr('Input layer')))        extent_parameter = QgsProcessingParameterExtent(self.TARGET_AREA,                                                        self.tr('Target area for layer'))        self.addParameter(extent_parameter)        # deprecated        crs_param = QgsProcessingParameterCrs(self.TARGET_AREA_CRS, 'Target area CRS', optional=True)        crs_param.setFlags(crs_param.flags() | QgsProcessingParameterDefinition.FlagHidden)        self.addParameter(crs_param)        self.addParameter(QgsProcessingParameterFeatureSink(self.OUTPUT,                                                            self.tr('CRS candidates')))    def name(self):        return 'findprojection'    def displayName(self):        return self.tr('Find projection')    def processAlgorithm(self, parameters, context, feedback):        source = self.parameterAsSource(parameters, self.INPUT, context)        if source is None:            raise QgsProcessingException(self.invalidSourceError(parameters, self.INPUT))        extent = self.parameterAsExtent(parameters, self.TARGET_AREA, context)        target_crs = self.parameterAsExtentCrs(parameters, self.TARGET_AREA, context)        if self.TARGET_AREA_CRS in parameters:            c = self.parameterAsCrs(parameters, self.TARGET_AREA_CRS, context)            if c.isValid():                target_crs = c        target_geom = QgsGeometry.fromRect(extent)        fields = QgsFields()        fields.append(QgsField('auth_id', QVariant.String, '', 20))        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,                                               fields, QgsWkbTypes.NoGeometry, QgsCoordinateReferenceSystem())        if sink is None:            raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))        # make intersection tests nice and fast        engine = QgsGeometry.createGeometryEngine(target_geom.constGet())        engine.prepareGeometry()        layer_bounds = QgsGeometry.fromRect(source.sourceExtent())        crses_to_check = QgsCoordinateReferenceSystem.validSrsIds()        total = 100.0 / len(crses_to_check)        found_results = 0        transform_context = QgsCoordinateTransformContext()        for current, srs_id in enumerate(crses_to_check):            if feedback.isCanceled():                break            candidate_crs = QgsCoordinateReferenceSystem.fromSrsId(srs_id)            if not candidate_crs.isValid():                continue            transform_candidate = QgsCoordinateTransform(candidate_crs, target_crs, transform_context)            transform_candidate.setBallparkTransformsAreAppropriate(True)            transform_candidate.disableFallbackOperationHandler(True)            transformed_bounds = QgsGeometry(layer_bounds)            try:                if transformed_bounds.transform(transform_candidate) != 0:                    continue            except:                continue            try:                if engine.intersects(transformed_bounds.constGet()):                    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            except:                continue            feedback.setProgress(int(current * total))        if found_results == 0:            feedback.reportError(self.tr('No matching projections found'))        return {self.OUTPUT: dest_id}
 |