QGIS API Documentation  3.12.1-BucureČ™ti (121cc00ff0)
qgsellipsoidutils.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsellipsoidutils.cpp
3  ----------------------
4  Date : April 2017
5  Copyright : (C) 2017 by Nyall Dawson
6  email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsellipsoidutils.h"
17 #include "qgsapplication.h"
18 #include "qgslogger.h"
19 #include "qgsmessagelog.h"
20 #include <sqlite3.h>
21 #include <QCollator>
22 #include "qgsprojutils.h"
23 #include "qgsreadwritelocker.h"
24 
25 #if PROJ_VERSION_MAJOR>=6
26 #include <proj.h>
27 #include <mutex>
28 #endif
29 
30 Q_GLOBAL_STATIC( QReadWriteLock, sEllipsoidCacheLock )
31 typedef QHash< QString, QgsEllipsoidUtils::EllipsoidParameters > EllipsoidParamCache;
32 Q_GLOBAL_STATIC( EllipsoidParamCache, sEllipsoidCache )
33 
34 Q_GLOBAL_STATIC( QReadWriteLock, sDefinitionCacheLock );
35 typedef QList< QgsEllipsoidUtils::EllipsoidDefinition > EllipsoidDefinitionCache;
36 Q_GLOBAL_STATIC( EllipsoidDefinitionCache, sDefinitionCache )
37 
38 static bool sDisableCache = false;
39 
40 QgsEllipsoidUtils::EllipsoidParameters QgsEllipsoidUtils::ellipsoidParameters( const QString &e )
41 {
42 // maps older QGIS ellipsoid acronyms to proj acronyms/names
43  static const QMap< QString, QString > sProj6EllipsoidAcronymMap
44  {
45  { "clrk80", "clrk80ign" },
46  {"Adrastea2000", "ESRI:107909"},
47  {"Amalthea2000", "ESRI:107910"},
48  {"Ananke2000", "ESRI:107911"},
49  {"Ariel2000", "ESRI:107945"},
50  {"Atlas2000", "ESRI:107926"},
51  {"Belinda2000", "ESRI:107946"},
52  {"Bianca2000", "ESRI:107947"},
53  {"Callisto2000", "ESRI:107912"},
54  {"Calypso2000", "ESRI:107927"},
55  {"Carme2000", "ESRI:107913"},
56  {"Charon2000", "ESRI:107970"},
57  {"Cordelia2000", "ESRI:107948"},
58  {"Cressida2000", "ESRI:107949"},
59  {"Deimos2000", "ESRI:107906"},
60  {"Desdemona2000", "ESRI:107950"},
61  {"Despina2000", "ESRI:107961"},
62  {"Dione2000", "ESRI:107928"},
63  {"Elara2000", "ESRI:107914"},
64  {"Enceladus2000", "ESRI:107929"},
65  {"Epimetheus2000", "ESRI:107930"},
66  {"Europa2000", "ESRI:107915"},
67  {"Galatea2000", "ESRI:107962"},
68  {"Ganymede2000", "ESRI:107916"},
69  {"Helene2000", "ESRI:107931"},
70  {"Himalia2000", "ESRI:107917"},
71  {"Hyperion2000", "ESRI:107932"},
72  {"Iapetus2000", "ESRI:107933"},
73  {"Io2000", "ESRI:107918"},
74  {"Janus2000", "ESRI:107934"},
75  {"Juliet2000", "ESRI:107951"},
76  {"Jupiter2000", "ESRI:107908"},
77  {"Larissa2000", "ESRI:107963"},
78  {"Leda2000", "ESRI:107919"},
79  {"Lysithea2000", "ESRI:107920"},
80  {"Mars2000", "ESRI:107905"},
81  {"Mercury2000", "ESRI:107900"},
82  {"Metis2000", "ESRI:107921"},
83  {"Mimas2000", "ESRI:107935"},
84  {"Miranda2000", "ESRI:107952"},
85  {"Moon2000", "ESRI:107903"},
86  {"Naiad2000", "ESRI:107964"},
87  {"Neptune2000", "ESRI:107960"},
88  {"Nereid2000", "ESRI:107965"},
89  {"Oberon2000", "ESRI:107953"},
90  {"Ophelia2000", "ESRI:107954"},
91  {"Pan2000", "ESRI:107936"},
92  {"Pandora2000", "ESRI:107937"},
93  {"Pasiphae2000", "ESRI:107922"},
94  {"Phobos2000", "ESRI:107907"},
95  {"Phoebe2000", "ESRI:107938"},
96  {"Pluto2000", "ESRI:107969"},
97  {"Portia2000", "ESRI:107955"},
98  {"Prometheus2000", "ESRI:107939"},
99  {"Proteus2000", "ESRI:107966"},
100  {"Puck2000", "ESRI:107956"},
101  {"Rhea2000", "ESRI:107940"},
102  {"Rosalind2000", "ESRI:107957"},
103  {"Saturn2000", "ESRI:107925"},
104  {"Sinope2000", "ESRI:107923"},
105  {"Telesto2000", "ESRI:107941"},
106  {"Tethys2000", "ESRI:107942"},
107  {"Thalassa2000", "ESRI:107967"},
108  {"Thebe2000", "ESRI:107924"},
109  {"Titan2000", "ESRI:107943"},
110  {"Titania2000", "ESRI:107958"},
111  {"Triton2000", "ESRI:107968"},
112  {"Umbriel2000", "ESRI:107959"},
113  {"Uranus2000", "ESRI:107944"},
114  {"Venus2000", "ESRI:107902"},
115  {"IGNF:ELG053", "EPSG:7030"},
116  {"IGNF:ELG052", "EPSG:7043"},
117  {"IGNF:ELG102", "EPSG:7043"},
118  {"WGS66", "ESRI:107001"},
119  {"plessis", "EPSG:7027"},
120  {"IGNF:ELG017", "EPSG:7027"},
121  {"mod_airy", "EPSG:7002"},
122  {"IGNF:ELG037", "EPSG:7019"},
123  {"IGNF:ELG108", "EPSG:7036"},
124  {"cape", "EPSG:7034"},
125  {"IGNF:ELG010", "EPSG:7011"},
126  {"IGNF:ELG003", "EPSG:7012"},
127  {"IGNF:ELG004", "EPSG:7008"},
128  {"GSK2011", "EPSG:1025"},
129  {"airy", "EPSG:7001"},
130  {"aust_SA", "EPSG:7003"},
131  {"bessel", "EPSG:7004"},
132  {"clrk66", "EPSG:7008"},
133  {"clrk80ign", "EPSG:7011"},
134  {"evrst30", "EPSG:7015"},
135  {"evrstSS", "EPSG:7016"},
136  {"evrst48", "EPSG:7018"},
137  {"GRS80", "EPSG:7019"},
138  {"helmert", "EPSG:7020"},
139  {"intl", "EPSG:7022"},
140  {"krass", "EPSG:7024"},
141  {"NWL9D", "EPSG:7025"},
142  {"WGS84", "EPSG:7030"},
143  {"GRS67", "EPSG:7036"},
144  {"WGS72", "EPSG:7043"},
145  {"bess_nam", "EPSG:7046"},
146  {"IAU76", "EPSG:7049"},
147  {"sphere", "EPSG:7052"},
148  {"hough", "EPSG:7053"},
149  {"evrst69", "EPSG:7056"},
150  {"fschr60", "ESRI:107002"},
151  {"fschr68", "ESRI:107003"},
152  {"fschr60m", "ESRI:107004"},
153  {"walbeck", "ESRI:107007"},
154  {"IGNF:ELG001", "EPSG:7022"},
155  {"engelis", "EPSG:7054"},
156  {"evrst56", "EPSG:7044"},
157  {"SEasia", "ESRI:107004"},
158  {"SGS85", "EPSG:7054"},
159  {"andrae", "PROJ:ANDRAE"},
160  {"clrk80", "EPSG:7034"},
161  {"CPM", "PROJ:CPM"},
162  {"delmbr", "PROJ:DELMBR"},
163  {"Earth2000", "PROJ:EARTH2000"},
164  {"kaula", "PROJ:KAULA"},
165  {"lerch", "PROJ:LERCH"},
166  {"MERIT", "PROJ:MERIT"},
167  {"mprts", "PROJ:MPRTS"},
168  {"new_intl", "PROJ:NEW_INTL"},
169  {"WGS60", "PROJ:WGS60"}
170  };
171 
172  QString ellipsoid = e;
173 #if PROJ_VERSION_MAJOR >= 6
174  // ensure ellipsoid database is populated when first called
175  static std::once_flag initialized;
176  std::call_once( initialized, [ = ]
177  {
178  ( void )definitions();
179  } );
180 
181  ellipsoid = sProj6EllipsoidAcronymMap.value( ellipsoid, ellipsoid ); // silently upgrade older QGIS acronyms to proj acronyms
182 #else
183  ( void )sProj6EllipsoidAcronymMap;
184 #endif
185 
186  // check cache
187  {
188  QgsReadWriteLocker locker( *sEllipsoidCacheLock(), QgsReadWriteLocker::Read );
189  if ( !sDisableCache )
190  {
191  QHash< QString, EllipsoidParameters >::const_iterator cacheIt = sEllipsoidCache()->constFind( ellipsoid );
192  if ( cacheIt != sEllipsoidCache()->constEnd() )
193  {
194  // found a match in the cache
195  QgsEllipsoidUtils::EllipsoidParameters params = cacheIt.value();
196  return params;
197  }
198  }
199  }
200 
201  EllipsoidParameters params;
202 
203  // Check if we have a custom projection, and set from text string.
204  // Format is "PARAMETER:<semi-major axis>:<semi minor axis>
205  // Numbers must be with (optional) decimal point and no other separators (C locale)
206  // Distances in meters. Flattening is calculated.
207  if ( ellipsoid.startsWith( QLatin1String( "PARAMETER" ) ) )
208  {
209  QStringList paramList = ellipsoid.split( ':' );
210  bool semiMajorOk, semiMinorOk;
211  double semiMajor = paramList[1].toDouble( & semiMajorOk );
212  double semiMinor = paramList[2].toDouble( & semiMinorOk );
213  if ( semiMajorOk && semiMinorOk )
214  {
215  params.semiMajor = semiMajor;
216  params.semiMinor = semiMinor;
217  params.inverseFlattening = semiMajor / ( semiMajor - semiMinor );
218  params.useCustomParameters = true;
219  }
220  else
221  {
222  params.valid = false;
223  }
224 
225  QgsReadWriteLocker locker( *sEllipsoidCacheLock(), QgsReadWriteLocker::Write );
226  if ( !sDisableCache )
227  {
228  sEllipsoidCache()->insert( ellipsoid, params );
229  }
230  return params;
231  }
232 
233 #if PROJ_VERSION_MAJOR< 6
234  // cache miss - get from database
235  // NOT REQUIRED FOR PROJ >= 6 -- we populate known types once by calling definitions() above
236 
237  QString radius, parameter2;
238  //
239  // SQLITE3 stuff - get parameters for selected ellipsoid
240  //
243  // Continue with PROJ list of ellipsoids.
244 
245  //check the db is available
246  int result = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
247  if ( result )
248  {
249  QgsMessageLog::logMessage( QObject::tr( "Can not open srs database (%1): %2" ).arg( QgsApplication::srsDatabaseFilePath(), database.errorMessage() ) );
250  // XXX This will likely never happen since on open, sqlite creates the
251  // database if it does not exist.
252  return params;
253  }
254  // Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
255  QString sql = "select radius, parameter2 from tbl_ellipsoid where acronym='" + ellipsoid + '\'';
256  statement = database.prepare( sql, result );
257  // XXX Need to free memory from the error msg if one is set
258  if ( result == SQLITE_OK )
259  {
260  if ( statement.step() == SQLITE_ROW )
261  {
262  radius = statement.columnAsText( 0 );
263  parameter2 = statement.columnAsText( 1 );
264  }
265  }
266  // row for this ellipsoid wasn't found?
267  if ( radius.isEmpty() || parameter2.isEmpty() )
268  {
269  QgsDebugMsg( QStringLiteral( "setEllipsoid: no row in tbl_ellipsoid for acronym '%1'" ).arg( ellipsoid ) );
270  params.valid = false;
271  sEllipsoidCacheLock()->lockForWrite();
272  if ( !sDisableCache )
273  {
274  sEllipsoidCache()->insert( ellipsoid, params );
275  }
276  sEllipsoidCacheLock()->unlock();
277  return params;
278  }
279 
280  // get major semiaxis
281  if ( radius.left( 2 ) == QLatin1String( "a=" ) )
282  params.semiMajor = radius.midRef( 2 ).toDouble();
283  else
284  {
285  QgsDebugMsg( QStringLiteral( "setEllipsoid: wrong format of radius field: '%1'" ).arg( radius ) );
286  params.valid = false;
287  sEllipsoidCacheLock()->lockForWrite();
288  if ( !sDisableCache )
289  {
290  sEllipsoidCache()->insert( ellipsoid, params );
291  }
292  sEllipsoidCacheLock()->unlock();
293  return params;
294  }
295 
296  // get second parameter
297  // one of values 'b' or 'f' is in field parameter2
298  // second one must be computed using formula: invf = a/(a-b)
299  if ( parameter2.left( 2 ) == QLatin1String( "b=" ) )
300  {
301  params.semiMinor = parameter2.midRef( 2 ).toDouble();
302  params.inverseFlattening = params.semiMajor / ( params.semiMajor - params.semiMinor );
303  }
304  else if ( parameter2.left( 3 ) == QLatin1String( "rf=" ) )
305  {
306  params.inverseFlattening = parameter2.midRef( 3 ).toDouble();
307  params.semiMinor = params.semiMajor - ( params.semiMajor / params.inverseFlattening );
308  }
309  else
310  {
311  QgsDebugMsg( QStringLiteral( "setEllipsoid: wrong format of parameter2 field: '%1'" ).arg( parameter2 ) );
312  params.valid = false;
313  sEllipsoidCacheLock()->lockForWrite();
314  if ( !sDisableCache )
315  {
316  sEllipsoidCache()->insert( ellipsoid, params );
317  }
318  sEllipsoidCacheLock()->unlock();
319  return params;
320  }
321 
322  QgsDebugMsgLevel( QStringLiteral( "setEllipsoid: a=%1, b=%2, 1/f=%3" ).arg( params.semiMajor ).arg( params.semiMinor ).arg( params.inverseFlattening ), 4 );
323 
324 
325  // get spatial ref system for ellipsoid
326  QString proj4 = "+proj=longlat +ellps=" + ellipsoid + " +no_defs";
328  //TODO: createFromProj used to save to the user database any new CRS
329  // this behavior was changed in order to separate creation and saving.
330  // Not sure if it necessary to save it here, should be checked by someone
331  // familiar with the code (should also give a more descriptive name to the generated CRS)
332  if ( destCRS.srsid() == 0 )
333  {
334  QString name = QStringLiteral( " * %1 (%2)" )
335  .arg( QObject::tr( "Generated CRS", "A CRS automatically generated from layer info get this prefix for description" ),
336  destCRS.toProj() );
337  destCRS.saveAsUserCrs( name );
338  }
339  //
340 
341  // set transformation from project CRS to ellipsoid coordinates
342  params.crs = destCRS;
343 
344  sEllipsoidCacheLock()->lockForWrite();
345  if ( !sDisableCache )
346  {
347  sEllipsoidCache()->insert( ellipsoid, params );
348  }
349  sEllipsoidCacheLock()->unlock();
350  return params;
351 #else
352  params.valid = false;
353 
354  QgsReadWriteLocker l( *sEllipsoidCacheLock(), QgsReadWriteLocker::Write );
355  if ( !sDisableCache )
356  {
357  sEllipsoidCache()->insert( ellipsoid, params );
358  }
359 
360  return params;
361 #endif
362 }
363 
364 QList<QgsEllipsoidUtils::EllipsoidDefinition> QgsEllipsoidUtils::definitions()
365 {
366  QgsReadWriteLocker defLocker( *sDefinitionCacheLock(), QgsReadWriteLocker::Read );
367  if ( !sDefinitionCache()->isEmpty() )
368  {
369  return *sDefinitionCache();
370  }
372 
373  QList<QgsEllipsoidUtils::EllipsoidDefinition> defs;
374 
375 #if PROJ_VERSION_MAJOR>=6
376  QgsReadWriteLocker locker( *sEllipsoidCacheLock(), QgsReadWriteLocker::Write );
377 
378  PJ_CONTEXT *context = QgsProjContext::get();
379  if ( PROJ_STRING_LIST authorities = proj_get_authorities_from_database( context ) )
380  {
381  PROJ_STRING_LIST authoritiesIt = authorities;
382  while ( char *authority = *authoritiesIt )
383  {
384  if ( PROJ_STRING_LIST codes = proj_get_codes_from_database( context, authority, PJ_TYPE_ELLIPSOID, 0 ) )
385  {
386  PROJ_STRING_LIST codesIt = codes;
387  while ( char *code = *codesIt )
388  {
389  QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_create_from_database( context, authority, code, PJ_CATEGORY_ELLIPSOID, 0, nullptr ) );
390  if ( ellipsoid.get() )
391  {
393  QString name = QString( proj_get_name( ellipsoid.get() ) );
394  def.acronym = QStringLiteral( "%1:%2" ).arg( authority, code );
395  name.replace( '_', ' ' );
396  def.description = QStringLiteral( "%1 (%2:%3)" ).arg( name, authority, code );
397 
398  double semiMajor, semiMinor, invFlattening;
399  int semiMinorComputed = 0;
400  if ( proj_ellipsoid_get_parameters( context, ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
401  {
402  def.parameters.semiMajor = semiMajor;
403  def.parameters.semiMinor = semiMinor;
404  def.parameters.inverseFlattening = invFlattening;
405  if ( !semiMinorComputed )
406  def.parameters.crs = QgsCoordinateReferenceSystem::fromProj( QStringLiteral( "+proj=longlat +a=%1 +b=%2 +no_defs +type=crs" ).arg( def.parameters.semiMajor, 0, 'g', 17 ).arg( def.parameters.semiMinor, 0, 'g', 17 ) );
407  else if ( !qgsDoubleNear( def.parameters.inverseFlattening, 0.0 ) )
408  def.parameters.crs = QgsCoordinateReferenceSystem::fromProj( QStringLiteral( "+proj=longlat +a=%1 +rf=%2 +no_defs +type=crs" ).arg( def.parameters.semiMajor, 0, 'g', 17 ).arg( def.parameters.inverseFlattening, 0, 'g', 17 ) );
409  else
410  def.parameters.crs = QgsCoordinateReferenceSystem::fromProj( QStringLiteral( "+proj=longlat +a=%1 +no_defs +type=crs" ).arg( def.parameters.semiMajor, 0, 'g', 17 ) );
411  }
412  else
413  {
414  def.parameters.valid = false;
415  }
416 
417  defs << def;
418  if ( !sDisableCache )
419  {
420  sEllipsoidCache()->insert( def.acronym, def.parameters );
421  }
422  }
423 
424  codesIt++;
425  }
426  proj_string_list_destroy( codes );
427  }
428 
429  authoritiesIt++;
430  }
431  proj_string_list_destroy( authorities );
432  }
433  locker.unlock();
434 
435 #else
438  int result;
439 
440  //check the db is available
441  result = database.open_v2( QgsApplication::srsDatabaseFilePath(), SQLITE_OPEN_READONLY, nullptr );
442  if ( result )
443  {
444  QgsDebugMsg( QStringLiteral( "Can't open database: %1" ).arg( database.errorMessage() ) );
445  // XXX This will likely never happen since on open, sqlite creates the
446  // database if it does not exist.
447  Q_ASSERT( result == 0 );
448  }
449 
450  // Set up the query to retrieve the projection information needed to populate the ELLIPSOID list
451  QString sql = QStringLiteral( "select acronym, name from tbl_ellipsoid order by name" );
452  statement = database.prepare( sql, result );
453 
454  if ( result == SQLITE_OK )
455  {
456  while ( statement.step() == SQLITE_ROW )
457  {
459  def.acronym = statement.columnAsText( 0 );
460  def.description = statement.columnAsText( 1 );
461 
462  // use ellipsoidParameters so that result is cached
464 
465  defs << def;
466  }
467  }
468 
469 #endif
470 
471  QCollator collator;
472  collator.setCaseSensitivity( Qt::CaseInsensitive );
473  std::sort( defs.begin(), defs.end(), [&collator]( const EllipsoidDefinition & a, const EllipsoidDefinition & b )
474  {
475  return collator.compare( a.description, b.description ) < 0;
476  } );
477  if ( !sDisableCache )
478  {
479  *sDefinitionCache() = defs;
480  }
481 
482  return defs;
483 }
484 
486 {
487  QStringList result;
488  const QList<QgsEllipsoidUtils::EllipsoidDefinition> defs = definitions();
489  result.reserve( defs.size() );
490  for ( const QgsEllipsoidUtils::EllipsoidDefinition &def : defs )
491  {
492  result << def.acronym;
493  }
494  return result;
495 }
496 
497 void QgsEllipsoidUtils::invalidateCache( bool disableCache )
498 {
499  QgsReadWriteLocker locker1( *sEllipsoidCacheLock(), QgsReadWriteLocker::Write );
500  QgsReadWriteLocker locker2( *sDefinitionCacheLock(), QgsReadWriteLocker::Write );
501 
502  if ( !sDisableCache )
503  {
504  if ( disableCache )
505  sDisableCache = true;
506  sEllipsoidCache()->clear();
507  sDefinitionCache()->clear();
508  }
509 }
static void invalidateCache(bool disableCache=false)
Clears the internal cache used.
bool useCustomParameters
Whether custom parameters alone should be used (semiMajor/semiMinor only)
Contains definition of an ellipsoid.
Unique pointer for sqlite3 prepared statements, which automatically finalizes the statement when the ...
QString toProj() const
Returns a Proj string representation of this CRS.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
long saveAsUserCrs(const QString &name, Format nativeFormat=FormatWkt)
Saves the CRS as a custom ("USER") CRS.
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
Definition: qgis.h:315
Contains parameters for an ellipsoid.
QList< QgsEllipsoidUtils::EllipsoidDefinition > EllipsoidDefinitionCache
static EllipsoidParameters ellipsoidParameters(const QString &ellipsoid)
Returns the parameters for the specified ellipsoid.
QgsCoordinateReferenceSystem crs
Associated coordinate reference system.
QString errorMessage() const
Returns the most recent error message encountered by the database.
The QgsReadWriteLocker class is a convenience class that simplifies locking and unlocking QReadWriteL...
bool valid
Whether ellipsoid parameters are valid.
Q_GLOBAL_STATIC(QReadWriteLock, sDefinitionCacheLock)
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
int step()
Steps to the next record in the statement, returning the sqlite3 result code.
static void logMessage(const QString &message, const QString &tag=QString(), Qgis::MessageLevel level=Qgis::Warning, bool notifyUser=true)
Adds a message to the log instance (and creates it if necessary).
QString columnAsText(int column) const
Returns the column value from the current statement row as a string.
sqlite3_statement_unique_ptr prepare(const QString &sql, int &resultCode) const
Prepares a sql statement, returning the result.
QString acronym
authority:code for QGIS builds with proj version 6 or greater, or custom acronym for ellipsoid for ea...
Contains utility functions for working with ellipsoids and querying the ellipsoid database...
Unique pointer for sqlite3 databases, which automatically closes the database when the pointer goes o...
void unlock()
Unlocks the lock.
int open_v2(const QString &path, int flags, const char *zVfs)
Opens the database at the specified file path.
static QgsCoordinateReferenceSystem fromProj(const QString &proj)
Creates a CRS from a proj style formatted string.
void PJ_CONTEXT
Definition: qgsprojutils.h:151
QHash< QString, QgsEllipsoidUtils::EllipsoidParameters > EllipsoidParamCache
This class represents a coordinate reference system (CRS).
double inverseFlattening
Inverse flattening.
void changeMode(Mode mode)
Change the mode of the lock to mode.
static QString srsDatabaseFilePath()
Returns the path to the srs.db file.
QgsEllipsoidUtils::EllipsoidParameters parameters
Ellipsoid parameters.
static QList< QgsEllipsoidUtils::EllipsoidDefinition > definitions()
Returns a list of the definitions for all known ellipsoids from the internal ellipsoid database...
static PJ_CONTEXT * get()
Returns a thread local instance of a proj context, safe for use in the current thread.
static QStringList acronyms()
Returns a list of all known ellipsoid acronyms from the internal ellipsoid database.
long srsid() const
Returns the internal CRS ID, if available.
QString description
Description of ellipsoid.