QGIS API Documentation 3.43.0-Master (261ee7da134)
qgsalgorithmfindprojection.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsalgorithmfindprojection.cpp
3 ---------------------
4 begin : March 2025
5 copyright : (C) 2025 by Alexander Bruy
6 email : alexander dot bruy 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
19#include "qgsgeometryengine.h"
20
22
23QString QgsFindProjectionAlgorithm::name() const
24{
25 return QStringLiteral( "findprojection" );
26}
27
28QString QgsFindProjectionAlgorithm::displayName() const
29{
30 return QObject::tr( "Find projection" );
31}
32
33QStringList QgsFindProjectionAlgorithm::tags() const
34{
35 return QObject::tr( "crs,srs,coordinate,reference,system,guess,estimate,finder,determine" ).split( ',' );
36}
37
38QString QgsFindProjectionAlgorithm::group() const
39{
40 return QObject::tr( "Vector general" );
41}
42
43QString QgsFindProjectionAlgorithm::groupId() const
44{
45 return QStringLiteral( "vectorgeneral" );
46}
47
48QString QgsFindProjectionAlgorithm::shortHelpString() const
49{
50 return QObject::tr( "Creates a list of possible candidate coordinate reference systems for a layer "
51 "with an unknown projection.\n\n"
52 "The expected area which the layer should reside in must be specified via the "
53 "target area parameter.\n\n"
54 "The algorithm operates by testing the layer's extent in every known reference "
55 "system and listing any in which the bounds would fall within the target area if "
56 "the layer was in this projection." );
57}
58
59QString QgsFindProjectionAlgorithm::shortDescription() const
60{
61 return QObject::tr( "Creates a list of possible candidate coordinate reference systems for a layer with an unknown projection." );
62}
63
64QgsFindProjectionAlgorithm *QgsFindProjectionAlgorithm::createInstance() const
65{
66 return new QgsFindProjectionAlgorithm();
67}
68
69void QgsFindProjectionAlgorithm::initAlgorithm( const QVariantMap & )
70{
71 addParameter( new QgsProcessingParameterFeatureSource( QStringLiteral( "INPUT" ), QObject::tr( "Input layer" ) ) );
72 addParameter( new QgsProcessingParameterExtent( QStringLiteral( "TARGET_AREA" ), QObject::tr( "Target area for layer" ) ) );
73
74 // deprecated
75 auto crsParam = std::make_unique<QgsProcessingParameterCrs>( QStringLiteral( "TARGET_AREA_CRS" ), QObject::tr( "Target area CRS" ), QVariant(), true );
76 crsParam->setFlags( crsParam->flags() | Qgis::ProcessingParameterFlag::Hidden );
77 addParameter( crsParam.release() );
78
79 addParameter( new QgsProcessingParameterFeatureSink( QStringLiteral( "OUTPUT" ), QObject::tr( "CRS candidates" ), Qgis::ProcessingSourceType::Vector ) );
80}
81
82QVariantMap QgsFindProjectionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
83{
84 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, QStringLiteral( "INPUT" ), context ) );
85 if ( !source )
86 throw QgsProcessingException( invalidSourceError( parameters, QStringLiteral( "INPUT" ) ) );
87
88 const QgsRectangle extent = parameterAsExtent( parameters, QStringLiteral( "TARGET_AREA" ), context );
89 QgsCoordinateReferenceSystem targetCrs = parameterAsExtentCrs( parameters, QStringLiteral( "TARGET_AREA" ), context );
90 if ( parameters.contains( QStringLiteral( "TARGET_AREA_CRS" ) ) )
91 {
92 QgsCoordinateReferenceSystem crs = parameterAsCrs( parameters, QStringLiteral( "TARGET_AREA_CRS" ), context );
93 if ( crs.isValid() )
94 {
95 targetCrs = crs;
96 }
97 }
98
99 QgsGeometry targetGeometry = QgsGeometry::fromRect( extent );
100
101 QgsFields fields;
102 fields.append( QgsField( "auth_id", QMetaType::Type::QString ) );
103
104 QString dest;
105 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, QStringLiteral( "OUTPUT" ), context, dest, fields, Qgis::WkbType::NoGeometry, QgsCoordinateReferenceSystem() ) );
106 if ( !sink )
107 {
108 throw QgsProcessingException( invalidSinkError( parameters, QStringLiteral( "OUTPUT" ) ) );
109 }
110
111 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( targetGeometry.constGet() ) );
112 engine->prepareGeometry();
113
114 QgsGeometry layerBounds = QgsGeometry::fromRect( source->sourceExtent() );
115
116 const QList< long > crsesToCheck = QgsCoordinateReferenceSystem::validSrsIds();
117 double step = crsesToCheck.count() > 0 ? 100.0 / crsesToCheck.count() : 0;
118 long foundResults = 0;
119 long i = 0;
120
121 QgsCoordinateTransformContext transformContext;
122
123 for ( long srsId : crsesToCheck )
124 {
125 if ( feedback->isCanceled() )
126 {
127 break;
128 }
129
131 if ( !candidateCrs.isValid() )
132 {
133 continue;
134 }
135
136 QgsCoordinateTransform transformCandidate = QgsCoordinateTransform( candidateCrs, targetCrs, transformContext );
137 transformCandidate.setBallparkTransformsAreAppropriate( true );
138 transformCandidate.disableFallbackOperationHandler( true );
139 QgsGeometry transformedBounds = QgsGeometry( layerBounds );
140
141 try
142 {
143 if ( transformedBounds.transform( transformCandidate ) != Qgis::GeometryOperationResult::Success )
144 {
145 continue;
146 }
147 }
148 catch ( QgsCsException & )
149 {
150 continue;
151 }
152
153 try
154 {
155 if ( engine->intersects( transformedBounds.constGet() ) )
156 {
157 feedback->pushInfo( QObject::tr( "Found candidate CRS: %1." ).arg( candidateCrs.authid() ) );
158 QgsFeature f = QgsFeature( fields );
159 f.setAttributes( QgsAttributes() << candidateCrs.authid() );
160 sink->addFeature( f, QgsFeatureSink::Flag::FastInsert );
161 foundResults++;
162 }
163 }
164 catch ( QgsCsException & )
165 {
166 continue;
167 }
168
169 feedback->setProgress( i * step );
170 i++;
171 }
172
173 if ( foundResults == 0 )
174 {
175 feedback->reportError( QObject::tr( "No matching projections found." ) );
176 }
177
178 sink->finalize();
179
180 QVariantMap outputs;
181 outputs.insert( QStringLiteral( "OUTPUT" ), dest );
182 return outputs;
183}
184
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
@ Success
Operation succeeded.
@ NoGeometry
No geometry.
@ Hidden
Parameter is hidden and should not be shown to users.
A vector of attributes.
Represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
static QList< long > validSrsIds()
Returns a list of all valid SRS IDs present in the CRS database.
static QgsCoordinateReferenceSystem fromSrsId(long srsId)
Creates a CRS from a specified QGIS SRS ID.
Contains information about the context in which a coordinate transform is executed.
Handles coordinate transforms between two coordinate systems.
void setBallparkTransformsAreAppropriate(bool appropriate)
Sets whether approximate "ballpark" results are appropriate for this coordinate transform.
void disableFallbackOperationHandler(bool disabled)
Sets whether the default fallback operation handler is disabled for this transform instance.
Custom exception class for Coordinate Reference System related exceptions.
@ FastInsert
Use faster inserts, at the cost of updating the passed features to reflect changes made at the provid...
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:53
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:61
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:53
Container of fields for a vector layer.
Definition qgsfields.h:46
bool append(const QgsField &field, Qgis::FieldOrigin origin=Qgis::FieldOrigin::Provider, int originIndex=-1)
Appends a field.
Definition qgsfields.cpp:70
A geometry is the spatial representation of a feature.
static QgsGeometry fromRect(const QgsRectangle &rect)
Creates a new geometry from a QgsRectangle.
Qgis::GeometryOperationResult transform(const QgsCoordinateTransform &ct, Qgis::TransformDirection direction=Qgis::TransformDirection::Forward, bool transformZ=false)
Transforms this geometry as described by the coordinate transform ct.
const QgsAbstractGeometry * constGet() const
Returns a non-modifiable (const) reference to the underlying abstract geometry primitive.
static QgsGeometryEngine * createGeometryEngine(const QgsAbstractGeometry *geometry, double precision=0.0, Qgis::GeosCreationFlags flags=Qgis::GeosCreationFlag::SkipEmptyInteriorRings)
Creates and returns a new geometry engine representing the specified geometry using precision on a gr...
Contains information about the context in which a processing algorithm is executed.
Custom exception class for processing related exceptions.
Base class for providing feedback from a processing algorithm.
virtual void pushInfo(const QString &info)
Pushes a general informational message from the algorithm.
virtual void reportError(const QString &error, bool fatalError=false)
Reports that the algorithm encountered an error while executing.
A rectangular map extent parameter for processing algorithms.
A feature sink output for processing algorithms.
An input feature source (such as vector layers) parameter for processing algorithms.
A rectangle specified with double values.
const QgsCoordinateReferenceSystem & crs