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