QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgscoordinatereferencesystemregistry.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgscoordinatereferencesystemregistry.cpp
3 -------------------
4 begin : January 2021
5 copyright : (C) 2021 by Nyall Dawson
6 email : nyall dot dawson 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
21#include "qgsapplication.h"
22#include "qgslogger.h"
23#include "qgsmessagelog.h"
24#include "qgssqliteutils.h"
25#include "qgscelestialbody.h"
26#include "qgsprojutils.h"
27#include "qgsruntimeprofiler.h"
28#include "qgsexception.h"
29#include "qgsprojoperation.h"
30#include "qgssettings.h"
31
32#include <QFileInfo>
33#include <sqlite3.h>
34#include <mutex>
35#include <proj.h>
36
38 : QObject( parent )
39{
40
41}
42
44
45QList<QgsCoordinateReferenceSystemRegistry::UserCrsDetails> QgsCoordinateReferenceSystemRegistry::userCrsList() const
46{
47 QList<QgsCoordinateReferenceSystemRegistry::UserCrsDetails> res;
48
49 //Setup connection to the existing custom CRS database:
51 //check the db is available
52 int result = database.open_v2( QgsApplication::qgisUserDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
53 if ( result != SQLITE_OK )
54 {
55 QgsDebugError( QStringLiteral( "Can't open database: %1" ).arg( database.errorMessage() ) );
56 return res;
57 }
58
59 const QString sql = QStringLiteral( "select srs_id,description,parameters, wkt from tbl_srs" );
60 QgsDebugMsgLevel( QStringLiteral( "Query to populate existing list:%1" ).arg( sql ), 4 );
61 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
62 if ( result == SQLITE_OK )
63 {
65 while ( preparedStatement.step() == SQLITE_ROW )
66 {
67 UserCrsDetails details;
68 details.id = preparedStatement.columnAsText( 0 ).toLong();
69 details.name = preparedStatement.columnAsText( 1 );
70 details.proj = preparedStatement.columnAsText( 2 );
71 details.wkt = preparedStatement.columnAsText( 3 );
72
73 if ( !details.wkt.isEmpty() )
74 details.crs.createFromWkt( details.wkt );
75 else
76 details.crs.createFromProj( details.proj );
77
78 res << details;
79 }
80 }
81 return res;
82}
83
85{
86 if ( !crs.isValid() )
87 {
88 QgsDebugMsgLevel( QStringLiteral( "Can't save an invalid CRS!" ), 4 );
89 return -1;
90 }
91
92 QString mySql;
93
94 QString proj4String = crs.d->mProj4;
95 if ( proj4String.isEmpty() )
96 {
97 proj4String = crs.toProj();
98 }
99 const QString wktString = crs.toWkt( Qgis::CrsWktVariant::Preferred );
100
101 // ellipsoid acroynym column is incorrectly marked as not null in many crs database instances,
102 // hack around this by using an empty string instead
103 const QString quotedEllipsoidString = crs.ellipsoidAcronym().isNull() ? QStringLiteral( "''" ) : QgsSqliteUtils::quotedString( crs.ellipsoidAcronym() );
104
105 //if this is the first record we need to ensure that its srs_id is 10000. For
106 //any rec after that sqlite3 will take care of the autonumbering
107 //this was done to support sqlite 3.0 as it does not yet support
108 //the autoinc related system tables.
109 if ( QgsCoordinateReferenceSystem::getRecordCount() == 0 )
110 {
111 mySql = "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
112 + QString::number( USER_CRS_START_ID )
113 + ',' + QgsSqliteUtils::quotedString( name )
114 + ',' + ( !crs.d->mProjectionAcronym.isEmpty() ? QgsSqliteUtils::quotedString( crs.d->mProjectionAcronym ) : QStringLiteral( "''" ) )
115 + ',' + quotedEllipsoidString
116 + ',' + ( !proj4String.isEmpty() ? QgsSqliteUtils::quotedString( proj4String ) : QStringLiteral( "''" ) )
117 + ",0," // <-- is_geo shamelessly hard coded for now
118 + ( nativeFormat == Qgis::CrsDefinitionFormat::Wkt ? QgsSqliteUtils::quotedString( wktString ) : QStringLiteral( "''" ) )
119 + ')';
120 }
121 else
122 {
123 mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
125 + ',' + ( !crs.d->mProjectionAcronym.isEmpty() ? QgsSqliteUtils::quotedString( crs.d->mProjectionAcronym ) : QStringLiteral( "''" ) )
126 + ',' + quotedEllipsoidString
127 + ',' + ( !proj4String.isEmpty() ? QgsSqliteUtils::quotedString( proj4String ) : QStringLiteral( "''" ) )
128 + ",0," // <-- is_geo shamelessly hard coded for now
129 + ( nativeFormat == Qgis::CrsDefinitionFormat::Wkt ? QgsSqliteUtils::quotedString( wktString ) : QStringLiteral( "''" ) )
130 + ')';
131 }
134 //check the db is available
135 int myResult = database.open( QgsApplication::qgisUserDatabaseFilePath() );
136 if ( myResult != SQLITE_OK )
137 {
138 QgsDebugError( QStringLiteral( "Can't open or create database %1: %2" )
140 database.errorMessage() ) );
141 return false;
142 }
143 statement = database.prepare( mySql, myResult );
144
145 qint64 returnId = -1;
146 if ( myResult == SQLITE_OK && statement.step() == SQLITE_DONE )
147 {
148 QgsMessageLog::logMessage( QObject::tr( "Saved user CRS [%1]" ).arg( crs.toProj() ), QObject::tr( "CRS" ) );
149
150 returnId = sqlite3_last_insert_rowid( database.get() );
151 crs.d->mSrsId = returnId;
152 crs.d->mAuthId = QStringLiteral( "USER:%1" ).arg( returnId );
153 crs.d->mDescription = name;
154 }
155
156 if ( returnId != -1 )
157 {
158 // If we have a projection acronym not in the user db previously, add it.
159 // This is a must, or else we can't select it from the vw_srs table.
160 // Actually, add it always and let the SQL PRIMARY KEY remove duplicates.
161 insertProjection( crs.projectionAcronym() );
162 }
163
166
167 if ( returnId != -1 )
168 {
169 emit userCrsAdded( crs.d->mAuthId );
171 }
172
173 return returnId;
174}
175
177{
178 if ( !crs.isValid() )
179 {
180 QgsDebugMsgLevel( QStringLiteral( "Can't save an invalid CRS!" ), 4 );
181 return false;
182 }
183
184 const QString sql = "update tbl_srs set description="
186 + ",projection_acronym=" + ( !crs.projectionAcronym().isEmpty() ? QgsSqliteUtils::quotedString( crs.projectionAcronym() ) : QStringLiteral( "''" ) )
187 + ",ellipsoid_acronym=" + ( !crs.ellipsoidAcronym().isEmpty() ? QgsSqliteUtils::quotedString( crs.ellipsoidAcronym() ) : QStringLiteral( "''" ) )
188 + ",parameters=" + ( !crs.toProj().isEmpty() ? QgsSqliteUtils::quotedString( crs.toProj() ) : QStringLiteral( "''" ) )
189 + ",is_geo=0" // <--shamelessly hard coded for now
190 + ",wkt=" + ( nativeFormat == Qgis::CrsDefinitionFormat::Wkt ? QgsSqliteUtils::quotedString( crs.toWkt( Qgis::CrsWktVariant::Preferred, false ) ) : QStringLiteral( "''" ) )
191 + " where srs_id=" + QgsSqliteUtils::quotedString( QString::number( id ) )
192 ;
193
195 //check the db is available
196 const int myResult = database.open( QgsApplication::qgisUserDatabaseFilePath() );
197 if ( myResult != SQLITE_OK )
198 {
199 QgsDebugError( QStringLiteral( "Can't open or create database %1: %2" )
201 database.errorMessage() ) );
202 return false;
203 }
204
205 bool res = true;
206 QString errorMessage;
207 if ( database.exec( sql, errorMessage ) != SQLITE_OK )
208 {
209 QgsMessageLog::logMessage( QObject::tr( "Error saving user CRS [%1]: %2" ).arg( crs.toProj(), errorMessage ), QObject::tr( "CRS" ) );
210 res = false;
211 }
212 else
213 {
214 const int changed = sqlite3_changes( database.get() );
215 if ( changed )
216 {
217 QgsMessageLog::logMessage( QObject::tr( "Saved user CRS [%1]" ).arg( crs.toProj() ), QObject::tr( "CRS" ) );
218 }
219 else
220 {
221 QgsMessageLog::logMessage( QObject::tr( "Error saving user CRS [%1]: No matching ID found in database" ).arg( crs.toProj() ), QObject::tr( "CRS" ) );
222 res = false;
223 }
224 }
225
226 if ( res )
227 {
228 // If we have a projection acronym not in the user db previously, add it.
229 // This is a must, or else we can't select it from the vw_srs table.
230 // Actually, add it always and let the SQL PRIMARY KEY remove duplicates.
231 insertProjection( crs.projectionAcronym() );
232 }
233
236
237 if ( res )
238 {
239 emit userCrsChanged( QStringLiteral( "USER:%1" ).arg( id ) );
241 }
242
243 return res;
244}
245
247{
249
250 const QString sql = "delete from tbl_srs where srs_id=" + QgsSqliteUtils::quotedString( QString::number( id ) );
251 QgsDebugMsgLevel( sql, 4 );
252 //check the db is available
253 int result = database.open( QgsApplication::qgisUserDatabaseFilePath() );
254 if ( result != SQLITE_OK )
255 {
256 QgsDebugError( QStringLiteral( "Can't open database: %1 \n please notify QGIS developers of this error \n %2 (file name) " ).arg( database.errorMessage(),
258 return false;
259 }
260
261 bool res = true;
262 {
263 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
264 if ( result != SQLITE_OK || preparedStatement.step() != SQLITE_DONE )
265 {
266 QgsDebugError( QStringLiteral( "failed to remove custom CRS from database: %1 [%2]" ).arg( sql, database.errorMessage() ) );
267 res = false;
268 }
269 else
270 {
271 const int changed = sqlite3_changes( database.get() );
272 if ( changed )
273 {
274 QgsMessageLog::logMessage( QObject::tr( "Removed user CRS [%1]" ).arg( id ), QObject::tr( "CRS" ) );
275 }
276 else
277 {
278 QgsMessageLog::logMessage( QObject::tr( "Error removing user CRS [%1]: No matching ID found in database" ).arg( id ), QObject::tr( "CRS" ) );
279 res = false;
280 }
281 }
282 }
283
286
287 if ( res )
288 {
289 emit userCrsRemoved( id );
291 }
292
293 return res;
294}
295
296
297bool QgsCoordinateReferenceSystemRegistry::insertProjection( const QString &projectionAcronym )
298{
300 sqlite3_database_unique_ptr srsDatabase;
301 QString sql;
302 //check the db is available
303 int result = database.open( QgsApplication::qgisUserDatabaseFilePath() );
304 if ( result != SQLITE_OK )
305 {
306 QgsDebugError( QStringLiteral( "Can't open database: %1 \n please notify QGIS developers of this error \n %2 (file name) " ).arg( database.errorMessage(),
308 return false;
309 }
310 int srsResult = srsDatabase.open( QgsApplication::srsDatabaseFilePath() );
311 if ( result != SQLITE_OK )
312 {
313 QgsDebugError( QStringLiteral( "Can't open database %1 [%2]" ).arg( QgsApplication::srsDatabaseFilePath(),
314 srsDatabase.errorMessage() ) );
315 return false;
316 }
317
318 // Set up the query to retrieve the projection information needed to populate the PROJECTION list
319 const QString srsSql = "select acronym,name,notes,parameters from tbl_projection where acronym=" + QgsSqliteUtils::quotedString( projectionAcronym );
320
321 sqlite3_statement_unique_ptr srsPreparedStatement = srsDatabase.prepare( srsSql, srsResult );
322 if ( srsResult == SQLITE_OK )
323 {
324 if ( srsPreparedStatement.step() == SQLITE_ROW )
325 {
326 QgsDebugMsgLevel( QStringLiteral( "Trying to insert projection" ), 4 );
327 // We have the result from system srs.db. Now insert into user db.
328 sql = "insert into tbl_projection(acronym,name,notes,parameters) values ("
329 + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 0 ) )
330 + ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 1 ) )
331 + ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 2 ) )
332 + ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 3 ) )
333 + ')';
334 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
335 if ( result != SQLITE_OK || preparedStatement.step() != SQLITE_DONE )
336 {
337 QgsDebugError( QStringLiteral( "Could not insert projection into database: %1 [%2]" ).arg( sql, database.errorMessage() ) );
338 return false;
339 }
340 }
341 }
342 else
343 {
344 QgsDebugError( QStringLiteral( "prepare failed: %1 [%2]" ).arg( srsSql, srsDatabase.errorMessage() ) );
345 return false;
346 }
347
348 return true;
349}
350
351QMap<QString, QgsProjOperation> QgsCoordinateReferenceSystemRegistry::projOperations() const
352{
353 static std::once_flag initialized;
354 std::call_once( initialized, [this]
355 {
356 const QgsScopedRuntimeProfile profile( QObject::tr( "Initialize PROJ operations" ) );
357
358 const PJ_OPERATIONS *operation = proj_list_operations();
359 while ( operation && operation->id )
360 {
361 QgsProjOperation value;
362 value.mValid = true;
363 value.mId = QString( operation->id );
364
365 const QString description( *operation->descr );
366 const QStringList descriptionParts = description.split( QStringLiteral( "\n\t" ) );
367 value.mDescription = descriptionParts.value( 0 );
368 value.mDetails = descriptionParts.mid( 1 ).join( '\n' );
369
370 mProjOperations.insert( value.id(), value );
371
372 operation++;
373 }
374 } );
375
376 return mProjOperations;
377}
378
380{
381#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1)
382
383 static std::once_flag initialized;
384 std::call_once( initialized, [this]
385 {
386 QgsScopedRuntimeProfile profile( QObject::tr( "Initialize celestial bodies" ) );
387
388 PJ_CONTEXT *context = QgsProjContext::get();
389
390 int resultCount = 0;
391 PROJ_CELESTIAL_BODY_INFO **list = proj_get_celestial_body_list_from_database( context, nullptr, &resultCount );
392 mCelestialBodies.reserve( resultCount );
393 for ( int i = 0; i < resultCount; i++ )
394 {
395 const PROJ_CELESTIAL_BODY_INFO *info = list[ i ];
396 if ( !info )
397 break;
398
399 QgsCelestialBody body;
400 body.mValid = true;
401 body.mAuthority = QString( info->auth_name );
402 body.mName = QString( info->name );
403
404 mCelestialBodies << body;
405 }
406 proj_celestial_body_list_destroy( list );
407 } );
408
409 return mCelestialBodies;
410#else
411 throw QgsNotSupportedException( QObject::tr( "Retrieving celestial bodies requires a QGIS build based on PROJ 8.1 or later" ) );
412#endif
413}
414
416{
417 static std::once_flag initialized;
418 std::call_once( initialized, [this]
419 {
420 QgsScopedRuntimeProfile profile( QObject::tr( "Initialize authorities" ) );
421
422 PJ_CONTEXT *pjContext = QgsProjContext::get();
423 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
424
425 for ( auto authIter = authorities; authIter && *authIter; ++authIter )
426 {
427 const QString authority( *authIter );
428 mKnownAuthorities.insert( authority.toLower() );
429 }
430
431 proj_string_list_destroy( authorities );
432 } );
433
434 return mKnownAuthorities;
435}
436
438{
439 static std::once_flag initialized;
440 std::call_once( initialized, [this]
441 {
442 const QString srsDatabaseFileName = QgsApplication::srsDatabaseFilePath();
443 if ( QFileInfo::exists( srsDatabaseFileName ) )
444 {
445 // open the database containing the spatial reference data, and do a one-time read
447 int result = database.open_v2( srsDatabaseFileName, SQLITE_OPEN_READONLY, nullptr );
448 if ( result == SQLITE_OK )
449 {
450 const QString sql = QStringLiteral( "SELECT description, srs_id, auth_name, auth_id, projection_acronym, deprecated, srs_type FROM tbl_srs" );
451 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
452 if ( result == SQLITE_OK )
453 {
454 while ( preparedStatement.step() == SQLITE_ROW )
455 {
456 QgsCrsDbRecord record;
457 record.description = preparedStatement.columnAsText( 0 );
458 record.srsId = preparedStatement.columnAsText( 1 );
459 record.authName = preparedStatement.columnAsText( 2 );
460 record.authId = preparedStatement.columnAsText( 3 );
461 record.projectionAcronym = preparedStatement.columnAsText( 4 );
462 record.deprecated = preparedStatement.columnAsText( 5 ).toInt();
463 record.type = qgsEnumKeyToValue( preparedStatement.columnAsText( 6 ), Qgis::CrsType::Unknown );
464 mCrsDbRecords.append( record );
465 }
466 }
467 }
468 }
469 } );
470
471 return mCrsDbRecords;
472}
473
474QList<QgsCoordinateReferenceSystem> QgsCoordinateReferenceSystemRegistry::recentCrs()
475{
476 QList<QgsCoordinateReferenceSystem> res;
477
478 // Read settings from persistent storage
479 QgsSettings settings;
480 QStringList projectionsProj4 = settings.value( QStringLiteral( "UI/recentProjectionsProj4" ) ).toStringList();
481 QStringList projectionsWkt = settings.value( QStringLiteral( "UI/recentProjectionsWkt" ) ).toStringList();
482 QStringList projectionsAuthId = settings.value( QStringLiteral( "UI/recentProjectionsAuthId" ) ).toStringList();
483 int max = std::max( projectionsAuthId.size(), std::max( projectionsProj4.size(), projectionsWkt.size() ) );
484 res.reserve( max );
485 for ( int i = 0; i < max; ++i )
486 {
487 const QString proj = projectionsProj4.value( i );
488 const QString wkt = projectionsWkt.value( i );
489 const QString authid = projectionsAuthId.value( i );
490
492 if ( !authid.isEmpty() )
494 if ( !crs.isValid() && !wkt.isEmpty() )
495 crs.createFromWkt( wkt );
496 if ( !crs.isValid() && !proj.isEmpty() )
497 crs.createFromProj( wkt );
498
499 if ( crs.isValid() )
500 res << crs;
501 }
502 return res;
503}
504
506{
507 QgsSettings settings;
508 settings.remove( QStringLiteral( "UI/recentProjectionsAuthId" ) );
509 settings.remove( QStringLiteral( "UI/recentProjectionsWkt" ) );
510 settings.remove( QStringLiteral( "UI/recentProjectionsProj4" ) );
511
512 emit recentCrsCleared();
513}
514
516{
517 // we only want saved and standard CRSes in the recent list
518 if ( crs.srsid() == 0 || !crs.isValid() )
519 return;
520
521 QList<QgsCoordinateReferenceSystem> recent = recentCrs();
522 recent.removeAll( crs );
523 recent.insert( 0, crs );
524
525 auto hasVertical = []( const QgsCoordinateReferenceSystem & crs )
526 {
527 switch ( crs.type() )
528 {
539 return false;
540
544 return true;
545 }
547 };
548 QList<QgsCoordinateReferenceSystem> recentSameType;
549 std::copy_if( recent.begin(), recent.end(), std::back_inserter( recentSameType ), [crs, &hasVertical]( const QgsCoordinateReferenceSystem & it )
550 {
551 return hasVertical( it ) == hasVertical( crs );
552 } );
553
554 // trim to max 30 items of the same type
555 const QList<QgsCoordinateReferenceSystem> toTrim = recentSameType.mid( 30 );
556 for ( const QgsCoordinateReferenceSystem &crsTrimmed : toTrim )
557 {
558 recent.removeOne( crsTrimmed );
559 emit recentCrsRemoved( crsTrimmed );
560 }
561
562 QStringList authids;
563 authids.reserve( recent.size() );
564 QStringList proj;
565 proj.reserve( recent.size() );
566 QStringList wkt;
567 wkt.reserve( recent.size() );
568 for ( const QgsCoordinateReferenceSystem &c : std::as_const( recent ) )
569 {
570 authids << c.authid();
571 proj << c.toProj();
572 wkt << c.toWkt( Qgis::CrsWktVariant::Preferred );
573 }
574
575 QgsSettings settings;
576 settings.setValue( QStringLiteral( "UI/recentProjectionsAuthId" ), authids );
577 settings.setValue( QStringLiteral( "UI/recentProjectionsWkt" ), wkt );
578 settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
579
580 emit recentCrsPushed( crs );
581}
582
584{
585 if ( crs.srsid() == 0 || !crs.isValid() )
586 return;
587
588 QList<QgsCoordinateReferenceSystem> recent = recentCrs();
589 recent.removeAll( crs );
590 QStringList authids;
591 authids.reserve( recent.size() );
592 QStringList proj;
593 proj.reserve( recent.size() );
594 QStringList wkt;
595 wkt.reserve( recent.size() );
596 for ( const QgsCoordinateReferenceSystem &c : std::as_const( recent ) )
597 {
598 authids << c.authid();
599 proj << c.toProj();
600 wkt << c.toWkt( Qgis::CrsWktVariant::Preferred );
601 }
602 QgsSettings settings;
603 settings.setValue( QStringLiteral( "UI/recentProjectionsAuthId" ), authids );
604 settings.setValue( QStringLiteral( "UI/recentProjectionsWkt" ), wkt );
605 settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
606
607 emit recentCrsRemoved( crs );
608}
@ Vertical
Vertical CRS.
@ Temporal
Temporal CRS.
@ Compound
Compound (horizontal + vertical) CRS.
@ Projected
Projected CRS.
@ Other
Other type.
@ Bound
Bound CRS.
@ DerivedProjected
Derived projected CRS.
@ Unknown
Unknown type.
@ Engineering
Engineering CRS.
@ Geographic3d
3D geopraphic CRS
@ Geodetic
Geodetic CRS.
@ Geographic2d
2D geographic CRS
@ Geocentric
Geocentric CRS.
CrsDefinitionFormat
CRS definition formats.
Definition: qgis.h:3167
@ Wkt
WKT format (always recommended over proj string format)
@ Preferred
Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019,...
static QString qgisUserDatabaseFilePath()
Returns the path to the user qgis.db file.
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
Contains information about a celestial body.
QgsCoordinateReferenceSystem crs
QgsCoordinateReferenceSystem object representing the user-defined CRS.
QList< QgsCrsDbRecord > crsDbRecords() const
Returns the list of records from the QGIS srs db.
void userCrsAdded(const QString &id)
Emitted whenever a new user CRS definition is added.
void recentCrsRemoved(const QgsCoordinateReferenceSystem &crs)
Emitted when a recently used CRS has been removed from the recent CRS list.
void userCrsChanged(const QString &id)
Emitted whenever an existing user CRS definition is changed.
void recentCrsCleared()
Emitted when the list of recently used CRS has been cleared.
void recentCrsPushed(const QgsCoordinateReferenceSystem &crs)
Emitted when a recently used CRS has been pushed to the top of the recent CRS list.
QList< QgsCelestialBody > celestialBodies() const
Returns a list of all known celestial bodies.
void userCrsRemoved(long id)
Emitted when the user CRS with matching id is removed from the database.
void crsDefinitionsChanged()
Emitted whenever an operation has caused any of the known CRS definitions (including user-defined CRS...
bool updateUserCrs(long id, const QgsCoordinateReferenceSystem &crs, const QString &name, Qgis::CrsDefinitionFormat nativeFormat=Qgis::CrsDefinitionFormat::Wkt)
Updates the definition of the existing user CRS with matching id.
QgsCoordinateReferenceSystemRegistry(QObject *parent=nullptr)
Constructor for QgsCoordinateReferenceSystemRegistry, with the specified parent object.
void removeRecent(const QgsCoordinateReferenceSystem &crs)
Removes a CRS from the list of recently used CRS.
long addUserCrs(const QgsCoordinateReferenceSystem &crs, const QString &name, Qgis::CrsDefinitionFormat nativeFormat=Qgis::CrsDefinitionFormat::Wkt)
Adds a new crs definition as a custom ("USER") CRS.
QSet< QString > authorities() const
Returns a list of all known authorities.
bool removeUserCrs(long id)
Removes the existing user CRS with matching id.
void clearRecent()
Cleans the list of recently used CRS.
QList< QgsCoordinateReferenceSystemRegistry::UserCrsDetails > userCrsList() const
Returns a list containing the details of all registered custom (user-defined) CRSes.
QList< QgsCoordinateReferenceSystem > recentCrs()
Returns a list of recently used CRS.
void pushRecent(const QgsCoordinateReferenceSystem &crs)
Pushes a recently used CRS to the top of the recent CRS list.
QMap< QString, QgsProjOperation > projOperations() const
Returns a map of all valid PROJ operations.
This class represents a coordinate reference system (CRS).
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
bool createFromWkt(const QString &wkt)
Sets this CRS using a WKT definition.
QString toProj() const
Returns a Proj string representation of this CRS.
QString ellipsoidAcronym() const
Returns the ellipsoid acronym for the ellipsoid used by the CRS.
QString projectionAcronym() const
Returns the projection acronym for the projection used by the CRS.
bool createFromProj(const QString &projString, bool identify=true)
Sets this CRS by passing it a PROJ style formatted string.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
QString toWkt(Qgis::CrsWktVariant variant=Qgis::CrsWktVariant::Wkt1Gdal, bool multiline=false, int indentationWidth=4) const
Returns a WKT representation of this CRS.
long srsid() const
Returns the internal CRS ID, if available.
Qgis::CrsType type() const
Returns the type of the CRS.
static void invalidateCache(bool disableCache=false)
Clears the internal cache used to initialize QgsCoordinateTransform objects.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::MessageLevel::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
Custom exception class which is raised when an operation is not supported.
Definition: qgsexception.h:118
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
Contains information about a PROJ operation.
QString id() const
ID of operation.
Scoped object for logging of the runtime for a single operation or group of operations.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:64
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void remove(const QString &key, QgsSettings::Section section=QgsSettings::NoSection)
Removes the setting key and any sub-settings of key in a section.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QString quotedString(const QString &value)
Returns a quoted string value, surround by ' characters and with special characters correctly escaped...
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
int open(const QString &path)
Opens the database at the specified file path.
QString errorMessage() const
Returns the most recent error message encountered by the database.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
int exec(const QString &sql, QString &errorMessage) const
Executes the sql command in the database.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
T qgsEnumKeyToValue(const QString &key, const T &defaultValue, bool tryValueAsKey=true, bool *returnOk=nullptr)
Returns the value corresponding to the given key of an enum.
Definition: qgis.h:5417
#define BUILTIN_UNREACHABLE
Definition: qgis.h:5853
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/....
Definition: qgis.h:5724
struct projCtx_t PJ_CONTEXT
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define QgsDebugError(str)
Definition: qgslogger.h:38
const QgsCoordinateReferenceSystem & crs