QGIS API Documentation 3.41.0-Master (af5edcb665c)
Loading...
Searching...
No Matches
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
19#include "moc_qgscoordinatereferencesystemregistry.cpp"
22#include "qgsapplication.h"
23#include "qgslogger.h"
24#include "qgsmessagelog.h"
25#include "qgssqliteutils.h"
26#include "qgscelestialbody.h"
27#include "qgsprojutils.h"
28#include "qgsruntimeprofiler.h"
29#include "qgsexception.h"
30#include "qgsprojoperation.h"
31#include "qgssettings.h"
32
33#include <QFileInfo>
34#include <sqlite3.h>
35#include <mutex>
36#include <proj.h>
37
39 : QObject( parent )
40{
41
42}
43
45
46QList<QgsCoordinateReferenceSystemRegistry::UserCrsDetails> QgsCoordinateReferenceSystemRegistry::userCrsList() const
47{
48 QList<QgsCoordinateReferenceSystemRegistry::UserCrsDetails> res;
49
50 //Setup connection to the existing custom CRS database:
52 //check the db is available
53 int result = database.open_v2( QgsApplication::qgisUserDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
54 if ( result != SQLITE_OK )
55 {
56 QgsDebugError( QStringLiteral( "Can't open database: %1" ).arg( database.errorMessage() ) );
57 return res;
58 }
59
60 const QString sql = QStringLiteral( "select srs_id,description,parameters, wkt from tbl_srs" );
61 QgsDebugMsgLevel( QStringLiteral( "Query to populate existing list:%1" ).arg( sql ), 4 );
62 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
63 if ( result == SQLITE_OK )
64 {
66 while ( preparedStatement.step() == SQLITE_ROW )
67 {
68 UserCrsDetails details;
69 details.id = preparedStatement.columnAsText( 0 ).toLong();
70 details.name = preparedStatement.columnAsText( 1 );
71 details.proj = preparedStatement.columnAsText( 2 );
72 details.wkt = preparedStatement.columnAsText( 3 );
73
74 if ( !details.wkt.isEmpty() )
75 details.crs.createFromWkt( details.wkt );
76 else
77 details.crs.createFromProj( details.proj );
78
79 res << details;
80 }
81 }
82 return res;
83}
84
86{
87 if ( !crs.isValid() )
88 {
89 QgsDebugMsgLevel( QStringLiteral( "Can't save an invalid CRS!" ), 4 );
90 return -1;
91 }
92
93 QString mySql;
94
95 QString proj4String = crs.d->mProj4;
96 if ( proj4String.isEmpty() )
97 {
98 proj4String = crs.toProj();
99 }
100 const QString wktString = crs.toWkt( Qgis::CrsWktVariant::Preferred );
101
102 // ellipsoid acroynym column is incorrectly marked as not null in many crs database instances,
103 // hack around this by using an empty string instead
104 const QString quotedEllipsoidString = crs.ellipsoidAcronym().isNull() ? QStringLiteral( "''" ) : QgsSqliteUtils::quotedString( crs.ellipsoidAcronym() );
105
106 //if this is the first record we need to ensure that its srs_id is 10000. For
107 //any rec after that sqlite3 will take care of the autonumbering
108 //this was done to support sqlite 3.0 as it does not yet support
109 //the autoinc related system tables.
110 if ( QgsCoordinateReferenceSystem::getRecordCount() == 0 )
111 {
112 mySql = "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
113 + QString::number( USER_CRS_START_ID )
114 + ',' + QgsSqliteUtils::quotedString( name )
115 + ',' + ( !crs.d->mProjectionAcronym.isEmpty() ? QgsSqliteUtils::quotedString( crs.d->mProjectionAcronym ) : QStringLiteral( "''" ) )
116 + ',' + quotedEllipsoidString
117 + ',' + ( !proj4String.isEmpty() ? QgsSqliteUtils::quotedString( proj4String ) : QStringLiteral( "''" ) )
118 + ",0," // <-- is_geo shamelessly hard coded for now
119 + ( nativeFormat == Qgis::CrsDefinitionFormat::Wkt ? QgsSqliteUtils::quotedString( wktString ) : QStringLiteral( "''" ) )
120 + ')';
121 }
122 else
123 {
124 mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo,wkt) values ("
126 + ',' + ( !crs.d->mProjectionAcronym.isEmpty() ? QgsSqliteUtils::quotedString( crs.d->mProjectionAcronym ) : QStringLiteral( "''" ) )
127 + ',' + quotedEllipsoidString
128 + ',' + ( !proj4String.isEmpty() ? QgsSqliteUtils::quotedString( proj4String ) : QStringLiteral( "''" ) )
129 + ",0," // <-- is_geo shamelessly hard coded for now
130 + ( nativeFormat == Qgis::CrsDefinitionFormat::Wkt ? QgsSqliteUtils::quotedString( wktString ) : QStringLiteral( "''" ) )
131 + ')';
132 }
135 //check the db is available
136 int myResult = database.open( QgsApplication::qgisUserDatabaseFilePath() );
137 if ( myResult != SQLITE_OK )
138 {
139 QgsDebugError( QStringLiteral( "Can't open or create database %1: %2" )
141 database.errorMessage() ) );
142 return false;
143 }
144 statement = database.prepare( mySql, myResult );
145
146 qint64 returnId = -1;
147 if ( myResult == SQLITE_OK && statement.step() == SQLITE_DONE )
148 {
149 QgsMessageLog::logMessage( QObject::tr( "Saved user CRS [%1]" ).arg( crs.toProj() ), QObject::tr( "CRS" ) );
150
151 returnId = sqlite3_last_insert_rowid( database.get() );
152 crs.d->mSrsId = returnId;
153 crs.d->mAuthId = QStringLiteral( "USER:%1" ).arg( returnId );
154 crs.d->mDescription = name;
155 }
156
157 if ( returnId != -1 )
158 {
159 // If we have a projection acronym not in the user db previously, add it.
160 // This is a must, or else we can't select it from the vw_srs table.
161 // Actually, add it always and let the SQL PRIMARY KEY remove duplicates.
162 insertProjection( crs.projectionAcronym() );
163 }
164
167
168 if ( returnId != -1 )
169 {
170 emit userCrsAdded( crs.d->mAuthId );
172 }
173
174 return returnId;
175}
176
178{
179 if ( !crs.isValid() )
180 {
181 QgsDebugMsgLevel( QStringLiteral( "Can't save an invalid CRS!" ), 4 );
182 return false;
183 }
184
185 const QString sql = "update tbl_srs set description="
187 + ",projection_acronym=" + ( !crs.projectionAcronym().isEmpty() ? QgsSqliteUtils::quotedString( crs.projectionAcronym() ) : QStringLiteral( "''" ) )
188 + ",ellipsoid_acronym=" + ( !crs.ellipsoidAcronym().isEmpty() ? QgsSqliteUtils::quotedString( crs.ellipsoidAcronym() ) : QStringLiteral( "''" ) )
189 + ",parameters=" + ( !crs.toProj().isEmpty() ? QgsSqliteUtils::quotedString( crs.toProj() ) : QStringLiteral( "''" ) )
190 + ",is_geo=0" // <--shamelessly hard coded for now
191 + ",wkt=" + ( nativeFormat == Qgis::CrsDefinitionFormat::Wkt ? QgsSqliteUtils::quotedString( crs.toWkt( Qgis::CrsWktVariant::Preferred, false ) ) : QStringLiteral( "''" ) )
192 + " where srs_id=" + QgsSqliteUtils::quotedString( QString::number( id ) )
193 ;
194
196 //check the db is available
197 const int myResult = database.open( QgsApplication::qgisUserDatabaseFilePath() );
198 if ( myResult != SQLITE_OK )
199 {
200 QgsDebugError( QStringLiteral( "Can't open or create database %1: %2" )
202 database.errorMessage() ) );
203 return false;
204 }
205
206 bool res = true;
207 QString errorMessage;
208 if ( database.exec( sql, errorMessage ) != SQLITE_OK )
209 {
210 QgsMessageLog::logMessage( QObject::tr( "Error saving user CRS [%1]: %2" ).arg( crs.toProj(), errorMessage ), QObject::tr( "CRS" ) );
211 res = false;
212 }
213 else
214 {
215 const int changed = sqlite3_changes( database.get() );
216 if ( changed )
217 {
218 QgsMessageLog::logMessage( QObject::tr( "Saved user CRS [%1]" ).arg( crs.toProj() ), QObject::tr( "CRS" ) );
219 }
220 else
221 {
222 QgsMessageLog::logMessage( QObject::tr( "Error saving user CRS [%1]: No matching ID found in database" ).arg( crs.toProj() ), QObject::tr( "CRS" ) );
223 res = false;
224 }
225 }
226
227 if ( res )
228 {
229 // If we have a projection acronym not in the user db previously, add it.
230 // This is a must, or else we can't select it from the vw_srs table.
231 // Actually, add it always and let the SQL PRIMARY KEY remove duplicates.
232 insertProjection( crs.projectionAcronym() );
233 }
234
237
238 if ( res )
239 {
240 emit userCrsChanged( QStringLiteral( "USER:%1" ).arg( id ) );
242 }
243
244 return res;
245}
246
248{
250
251 const QString sql = "delete from tbl_srs where srs_id=" + QgsSqliteUtils::quotedString( QString::number( id ) );
252 QgsDebugMsgLevel( sql, 4 );
253 //check the db is available
254 int result = database.open( QgsApplication::qgisUserDatabaseFilePath() );
255 if ( result != SQLITE_OK )
256 {
257 QgsDebugError( QStringLiteral( "Can't open database: %1 \n please notify QGIS developers of this error \n %2 (file name) " ).arg( database.errorMessage(),
259 return false;
260 }
261
262 bool res = true;
263 {
264 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
265 if ( result != SQLITE_OK || preparedStatement.step() != SQLITE_DONE )
266 {
267 QgsDebugError( QStringLiteral( "failed to remove custom CRS from database: %1 [%2]" ).arg( sql, database.errorMessage() ) );
268 res = false;
269 }
270 else
271 {
272 const int changed = sqlite3_changes( database.get() );
273 if ( changed )
274 {
275 QgsMessageLog::logMessage( QObject::tr( "Removed user CRS [%1]" ).arg( id ), QObject::tr( "CRS" ) );
276 }
277 else
278 {
279 QgsMessageLog::logMessage( QObject::tr( "Error removing user CRS [%1]: No matching ID found in database" ).arg( id ), QObject::tr( "CRS" ) );
280 res = false;
281 }
282 }
283 }
284
287
288 if ( res )
289 {
290 emit userCrsRemoved( id );
292 }
293
294 return res;
295}
296
297
298bool QgsCoordinateReferenceSystemRegistry::insertProjection( const QString &projectionAcronym )
299{
301 sqlite3_database_unique_ptr srsDatabase;
302 QString sql;
303 //check the db is available
304 int result = database.open( QgsApplication::qgisUserDatabaseFilePath() );
305 if ( result != SQLITE_OK )
306 {
307 QgsDebugError( QStringLiteral( "Can't open database: %1 \n please notify QGIS developers of this error \n %2 (file name) " ).arg( database.errorMessage(),
309 return false;
310 }
311 int srsResult = srsDatabase.open( QgsApplication::srsDatabaseFilePath() );
312 if ( result != SQLITE_OK )
313 {
314 QgsDebugError( QStringLiteral( "Can't open database %1 [%2]" ).arg( QgsApplication::srsDatabaseFilePath(),
315 srsDatabase.errorMessage() ) );
316 return false;
317 }
318
319 // Set up the query to retrieve the projection information needed to populate the PROJECTION list
320 const QString srsSql = "select acronym,name,notes,parameters from tbl_projection where acronym=" + QgsSqliteUtils::quotedString( projectionAcronym );
321
322 sqlite3_statement_unique_ptr srsPreparedStatement = srsDatabase.prepare( srsSql, srsResult );
323 if ( srsResult == SQLITE_OK )
324 {
325 if ( srsPreparedStatement.step() == SQLITE_ROW )
326 {
327 QgsDebugMsgLevel( QStringLiteral( "Trying to insert projection" ), 4 );
328 // We have the result from system srs.db. Now insert into user db.
329 sql = "insert into tbl_projection(acronym,name,notes,parameters) values ("
330 + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 0 ) )
331 + ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 1 ) )
332 + ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 2 ) )
333 + ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 3 ) )
334 + ')';
335 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
336 if ( result != SQLITE_OK || preparedStatement.step() != SQLITE_DONE )
337 {
338 QgsDebugError( QStringLiteral( "Could not insert projection into database: %1 [%2]" ).arg( sql, database.errorMessage() ) );
339 return false;
340 }
341 }
342 }
343 else
344 {
345 QgsDebugError( QStringLiteral( "prepare failed: %1 [%2]" ).arg( srsSql, srsDatabase.errorMessage() ) );
346 return false;
347 }
348
349 return true;
350}
351
352QMap<QString, QgsProjOperation> QgsCoordinateReferenceSystemRegistry::projOperations() const
353{
354 static std::once_flag initialized;
355 static QMap< QString, QgsProjOperation > sProjOperations;
356 std::call_once( initialized, []
357 {
358 const QgsScopedRuntimeProfile profile( QObject::tr( "Initialize PROJ operations" ) );
359
360 const PJ_OPERATIONS *operation = proj_list_operations();
361 while ( operation && operation->id )
362 {
363 QgsProjOperation value;
364 value.mValid = true;
365 value.mId = QString( operation->id );
366
367 const QString description( *operation->descr );
368 const QStringList descriptionParts = description.split( QStringLiteral( "\n\t" ) );
369 value.mDescription = descriptionParts.value( 0 );
370 value.mDetails = descriptionParts.mid( 1 ).join( '\n' );
371
372 sProjOperations.insert( value.id(), value );
373
374 operation++;
375 }
376 } );
377
378 return sProjOperations;
379}
380
382{
383#if PROJ_VERSION_MAJOR>8 || (PROJ_VERSION_MAJOR==8 && PROJ_VERSION_MINOR>=1)
384 static QList< QgsCelestialBody > sCelestialBodies;
385 static std::once_flag initialized;
386 std::call_once( initialized, []
387 {
388 QgsScopedRuntimeProfile profile( QObject::tr( "Initialize celestial bodies" ) );
389
390 PJ_CONTEXT *context = QgsProjContext::get();
391
392 int resultCount = 0;
393 PROJ_CELESTIAL_BODY_INFO **list = proj_get_celestial_body_list_from_database( context, nullptr, &resultCount );
394 sCelestialBodies.reserve( resultCount );
395 for ( int i = 0; i < resultCount; i++ )
396 {
397 const PROJ_CELESTIAL_BODY_INFO *info = list[ i ];
398 if ( !info )
399 break;
400
401 QgsCelestialBody body;
402 body.mValid = true;
403 body.mAuthority = QString( info->auth_name );
404 body.mName = QString( info->name );
405
406 sCelestialBodies << body;
407 }
408 proj_celestial_body_list_destroy( list );
409 } );
410
411 return sCelestialBodies;
412#else
413 throw QgsNotSupportedException( QObject::tr( "Retrieving celestial bodies requires a QGIS build based on PROJ 8.1 or later" ) );
414#endif
415}
416
418{
419 static QSet< QString > sKnownAuthorities;
420 static std::once_flag initialized;
421 std::call_once( initialized, []
422 {
423 QgsScopedRuntimeProfile profile( QObject::tr( "Initialize authorities" ) );
424
425 PJ_CONTEXT *pjContext = QgsProjContext::get();
426 PROJ_STRING_LIST authorities = proj_get_authorities_from_database( pjContext );
427
428 for ( auto authIter = authorities; authIter && *authIter; ++authIter )
429 {
430 const QString authority( *authIter );
431 sKnownAuthorities.insert( authority.toLower() );
432 }
433
434 proj_string_list_destroy( authorities );
435 } );
436
437 return sKnownAuthorities;
438}
439
441{
442 QgsReadWriteLocker locker( mCrsDbRecordsLock, QgsReadWriteLocker::Read );
443 if ( mCrsDbRecordsPopulated )
444 return mCrsDbRecords;
445
447
448 const QString srsDatabaseFileName = QgsApplication::srsDatabaseFilePath();
449 if ( QFileInfo::exists( srsDatabaseFileName ) )
450 {
451 // open the database containing the spatial reference data, and do a one-time read
453 int result = database.open_v2( srsDatabaseFileName, SQLITE_OPEN_READONLY, nullptr );
454 if ( result == SQLITE_OK )
455 {
456 const QString sql = QStringLiteral( "SELECT description, srs_id, auth_name, auth_id, projection_acronym, deprecated, srs_type FROM tbl_srs" );
457 sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
458 if ( result == SQLITE_OK )
459 {
460 while ( preparedStatement.step() == SQLITE_ROW )
461 {
462 QgsCrsDbRecord record;
463 record.description = preparedStatement.columnAsText( 0 );
464 record.srsId = preparedStatement.columnAsText( 1 );
465 record.authName = preparedStatement.columnAsText( 2 );
466 record.authId = preparedStatement.columnAsText( 3 );
467 record.projectionAcronym = preparedStatement.columnAsText( 4 );
468 record.deprecated = preparedStatement.columnAsText( 5 ).toInt();
469 record.type = qgsEnumKeyToValue( preparedStatement.columnAsText( 6 ), Qgis::CrsType::Unknown );
470 mCrsDbRecords.append( record );
471 }
472 }
473 }
474 }
475
476 mCrsDbRecordsPopulated = true;
477 return mCrsDbRecords;
478}
479
480QList<QgsCoordinateReferenceSystem> QgsCoordinateReferenceSystemRegistry::recentCrs()
481{
482 QList<QgsCoordinateReferenceSystem> res;
483
484 // Read settings from persistent storage
485 QgsSettings settings;
486 QStringList projectionsProj4 = settings.value( QStringLiteral( "UI/recentProjectionsProj4" ) ).toStringList();
487 QStringList projectionsWkt = settings.value( QStringLiteral( "UI/recentProjectionsWkt" ) ).toStringList();
488 QStringList projectionsAuthId = settings.value( QStringLiteral( "UI/recentProjectionsAuthId" ) ).toStringList();
489 int max = std::max( projectionsAuthId.size(), std::max( projectionsProj4.size(), projectionsWkt.size() ) );
490 res.reserve( max );
491 for ( int i = 0; i < max; ++i )
492 {
493 const QString proj = projectionsProj4.value( i );
494 const QString wkt = projectionsWkt.value( i );
495 const QString authid = projectionsAuthId.value( i );
496
498 if ( !authid.isEmpty() )
500 if ( !crs.isValid() && !wkt.isEmpty() )
501 crs.createFromWkt( wkt );
502 if ( !crs.isValid() && !proj.isEmpty() )
503 crs.createFromProj( wkt );
504
505 if ( crs.isValid() )
506 res << crs;
507 }
508 return res;
509}
510
512{
513 QgsSettings settings;
514 settings.remove( QStringLiteral( "UI/recentProjectionsAuthId" ) );
515 settings.remove( QStringLiteral( "UI/recentProjectionsWkt" ) );
516 settings.remove( QStringLiteral( "UI/recentProjectionsProj4" ) );
517
518 emit recentCrsCleared();
519}
520
522{
523 // we only want saved and standard CRSes in the recent list
524 if ( crs.srsid() == 0 || !crs.isValid() )
525 return;
526
527 QList<QgsCoordinateReferenceSystem> recent = recentCrs();
528 recent.removeAll( crs );
529 recent.insert( 0, crs );
530
531 auto hasVertical = []( const QgsCoordinateReferenceSystem & crs )
532 {
533 switch ( crs.type() )
534 {
545 return false;
546
550 return true;
551 }
553 };
554 QList<QgsCoordinateReferenceSystem> recentSameType;
555 std::copy_if( recent.begin(), recent.end(), std::back_inserter( recentSameType ), [crs, &hasVertical]( const QgsCoordinateReferenceSystem & it )
556 {
557 return hasVertical( it ) == hasVertical( crs );
558 } );
559
560 // trim to max 30 items of the same type
561 const QList<QgsCoordinateReferenceSystem> toTrim = recentSameType.mid( 30 );
562 for ( const QgsCoordinateReferenceSystem &crsTrimmed : toTrim )
563 {
564 recent.removeOne( crsTrimmed );
565 emit recentCrsRemoved( crsTrimmed );
566 }
567
568 QStringList authids;
569 authids.reserve( recent.size() );
570 QStringList proj;
571 proj.reserve( recent.size() );
572 QStringList wkt;
573 wkt.reserve( recent.size() );
574 for ( const QgsCoordinateReferenceSystem &c : std::as_const( recent ) )
575 {
576 authids << c.authid();
577 proj << c.toProj();
578 wkt << c.toWkt( Qgis::CrsWktVariant::Preferred );
579 }
580
581 QgsSettings settings;
582 settings.setValue( QStringLiteral( "UI/recentProjectionsAuthId" ), authids );
583 settings.setValue( QStringLiteral( "UI/recentProjectionsWkt" ), wkt );
584 settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
585
586 emit recentCrsPushed( crs );
587}
588
590{
591 if ( crs.srsid() == 0 || !crs.isValid() )
592 return;
593
594 QList<QgsCoordinateReferenceSystem> recent = recentCrs();
595 recent.removeAll( crs );
596 QStringList authids;
597 authids.reserve( recent.size() );
598 QStringList proj;
599 proj.reserve( recent.size() );
600 QStringList wkt;
601 wkt.reserve( recent.size() );
602 for ( const QgsCoordinateReferenceSystem &c : std::as_const( recent ) )
603 {
604 authids << c.authid();
605 proj << c.toProj();
606 wkt << c.toWkt( Qgis::CrsWktVariant::Preferred );
607 }
608 QgsSettings settings;
609 settings.setValue( QStringLiteral( "UI/recentProjectionsAuthId" ), authids );
610 settings.setValue( QStringLiteral( "UI/recentProjectionsWkt" ), wkt );
611 settings.setValue( QStringLiteral( "UI/recentProjectionsProj4" ), proj );
612
613 emit recentCrsRemoved( crs );
614}
@ 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:3676
@ 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.
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.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
@ Write
Lock for write.
void changeMode(Mode mode)
Change the mode of the lock to mode.
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:6276
#define BUILTIN_UNREACHABLE
Definition qgis.h:6720
const int USER_CRS_START_ID
Magick number that determines whether a projection crsid is a system (srs.db) or user (~/....
Definition qgis.h:6591
struct projCtx_t PJ_CONTEXT
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39
#define QgsDebugError(str)
Definition qgslogger.h:38
const QgsCoordinateReferenceSystem & crs