QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
Loading...
Searching...
No Matches
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
20#include "qgsgeometryengine.h"
21
22#include <QString>
23
24using namespace Qt::StringLiterals;
25
27
28QString QgsFindProjectionAlgorithm::name() const
29{
30 return u"findprojection"_s;
31}
32
33QString QgsFindProjectionAlgorithm::displayName() const
34{
35 return QObject::tr( "Find projection" );
36}
37
38QStringList QgsFindProjectionAlgorithm::tags() const
39{
40 return QObject::tr( "crs,srs,coordinate,reference,system,guess,estimate,finder,determine" ).split( ',' );
41}
42
43QString QgsFindProjectionAlgorithm::group() const
44{
45 return QObject::tr( "Vector general" );
46}
47
48QString QgsFindProjectionAlgorithm::groupId() const
49{
50 return u"vectorgeneral"_s;
51}
52
53QString QgsFindProjectionAlgorithm::shortHelpString() const
54{
55 return QObject::tr(
56 "Creates a list of possible candidate coordinate reference systems for a layer "
57 "with an unknown projection.\n\n"
58 "The expected area which the layer should reside in must be specified via the "
59 "target area parameter.\n\n"
60 "The algorithm operates by testing the layer's extent in every known reference "
61 "system and listing any in which the bounds would fall within the target area if "
62 "the layer was in this projection."
63 );
64}
65
66QString QgsFindProjectionAlgorithm::shortDescription() const
67{
68 return QObject::tr( "Creates a list of possible candidate coordinate reference systems for a layer with an unknown projection." );
69}
70
71QgsFindProjectionAlgorithm *QgsFindProjectionAlgorithm::createInstance() const
72{
73 return new QgsFindProjectionAlgorithm();
74}
75
76void QgsFindProjectionAlgorithm::initAlgorithm( const QVariantMap & )
77{
78 addParameter( new QgsProcessingParameterFeatureSource( u"INPUT"_s, QObject::tr( "Input layer" ) ) );
79 addParameter( new QgsProcessingParameterExtent( u"TARGET_AREA"_s, QObject::tr( "Target area for layer" ) ) );
80
81 // deprecated
82 auto crsParam = std::make_unique<QgsProcessingParameterCrs>( u"TARGET_AREA_CRS"_s, QObject::tr( "Target area CRS" ), QVariant(), true );
83 crsParam->setFlags( crsParam->flags() | Qgis::ProcessingParameterFlag::Hidden );
84 addParameter( crsParam.release() );
85
86 addParameter( new QgsProcessingParameterFeatureSink( u"OUTPUT"_s, QObject::tr( "CRS candidates" ), Qgis::ProcessingSourceType::Vector ) );
87}
88
89QVariantMap QgsFindProjectionAlgorithm::processAlgorithm( const QVariantMap &parameters, QgsProcessingContext &context, QgsProcessingFeedback *feedback )
90{
91 std::unique_ptr<QgsProcessingFeatureSource> source( parameterAsSource( parameters, u"INPUT"_s, context ) );
92 if ( !source )
93 throw QgsProcessingException( invalidSourceError( parameters, u"INPUT"_s ) );
94
95 const QgsRectangle extent = parameterAsExtent( parameters, u"TARGET_AREA"_s, context );
96 QgsCoordinateReferenceSystem targetCrs = parameterAsExtentCrs( parameters, u"TARGET_AREA"_s, context );
97 if ( parameters.contains( u"TARGET_AREA_CRS"_s ) )
98 {
99 QgsCoordinateReferenceSystem crs = parameterAsCrs( parameters, u"TARGET_AREA_CRS"_s, context );
100 if ( crs.isValid() )
101 {
102 targetCrs = crs;
103 }
104 }
105
106 QgsGeometry targetGeometry = QgsGeometry::fromRect( extent );
107
108 QgsFields fields;
109 fields.append( QgsField( "auth_id", QMetaType::Type::QString ) );
110
111 QString dest;
112 std::unique_ptr<QgsFeatureSink> sink( parameterAsSink( parameters, u"OUTPUT"_s, context, dest, fields, Qgis::WkbType::NoGeometry, QgsCoordinateReferenceSystem() ) );
113 if ( !sink )
114 {
115 throw QgsProcessingException( invalidSinkError( parameters, u"OUTPUT"_s ) );
116 }
117
118 std::unique_ptr<QgsGeometryEngine> engine( QgsGeometry::createGeometryEngine( targetGeometry.constGet() ) );
119 engine->prepareGeometry();
120
121 QgsGeometry layerBounds = QgsGeometry::fromRect( source->sourceExtent() );
122
123 const QList< long > crsesToCheck = QgsCoordinateReferenceSystem::validSrsIds();
124 double step = crsesToCheck.count() > 0 ? 100.0 / crsesToCheck.count() : 0;
125 long foundResults = 0;
126 long i = 0;
127
128 QgsCoordinateTransformContext transformContext;
129
130 for ( long srsId : crsesToCheck )
131 {
132 if ( feedback->isCanceled() )
133 {
134 break;
135 }
136
138 if ( !candidateCrs.isValid() )
139 {
140 continue;
141 }
142
143 QgsCoordinateTransform transformCandidate = QgsCoordinateTransform( candidateCrs, targetCrs, transformContext );
144 transformCandidate.setBallparkTransformsAreAppropriate( true );
145 transformCandidate.disableFallbackOperationHandler( true );
146 QgsGeometry transformedBounds = QgsGeometry( layerBounds );
147
148 try
149 {
150 if ( transformedBounds.transform( transformCandidate ) != Qgis::GeometryOperationResult::Success )
151 {
152 continue;
153 }
154 }
155 catch ( QgsCsException & )
156 {
157 continue;
158 }
159
160 try
161 {
162 if ( engine->intersects( transformedBounds.constGet() ) )
163 {
164 feedback->pushInfo( QObject::tr( "Found candidate CRS: %1." ).arg( candidateCrs.authid() ) );
165 QgsFeature f = QgsFeature( fields );
166 f.setAttributes( QgsAttributes() << candidateCrs.authid() );
167 if ( !sink->addFeature( f, QgsFeatureSink::FastInsert ) )
168 throw QgsProcessingException( writeFeatureError( sink.get(), parameters, u"OUTPUT"_s ) );
169
170 foundResults++;
171 }
172 }
173 catch ( QgsCsException & )
174 {
175 continue;
176 }
177
178 feedback->setProgress( i * step );
179 i++;
180 }
181
182 if ( foundResults == 0 )
183 {
184 feedback->reportError( QObject::tr( "No matching projections found." ) );
185 }
186
187 sink->finalize();
188
189 QVariantMap outputs;
190 outputs.insert( u"OUTPUT"_s, dest );
191 return outputs;
192}
193
@ Vector
Tables (i.e. vector layers with or without geometry). When used for a sink this indicates the sink ha...
Definition qgis.h:3653
@ Success
Operation succeeded.
Definition qgis.h:2122
@ NoGeometry
No geometry.
Definition qgis.h:312
@ Hidden
Parameter is hidden and should not be shown to users.
Definition qgis.h:3881
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:60
void setAttributes(const QgsAttributes &attrs)
Sets the feature's attributes.
bool isCanceled() const
Tells whether the operation has been canceled already.
Definition qgsfeedback.h:56
void setProgress(double progress)
Sets the current progress for the feedback object.
Definition qgsfeedback.h:65
Encapsulate a field in an attribute table or data source.
Definition qgsfield.h:56
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:75
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.