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