25 #if PROJ_VERSION_MAJOR>=6 38 static
bool sDisableCache = false;
43 static const QMap< QString, QString > sProj6EllipsoidAcronymMap
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"},
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"}
172 QString ellipsoid = e;
173 #if PROJ_VERSION_MAJOR >= 6 175 static std::once_flag initialized;
176 std::call_once( initialized, [ = ]
178 ( void )definitions();
181 ellipsoid = sProj6EllipsoidAcronymMap.value( ellipsoid, ellipsoid );
183 ( void )sProj6EllipsoidAcronymMap;
189 if ( !sDisableCache )
191 QHash< QString, EllipsoidParameters >::const_iterator cacheIt = sEllipsoidCache()->constFind( ellipsoid );
192 if ( cacheIt != sEllipsoidCache()->constEnd() )
207 if ( ellipsoid.startsWith( QLatin1String(
"PARAMETER" ) ) )
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 )
222 params.
valid =
false;
226 if ( !sDisableCache )
228 sEllipsoidCache()->insert( ellipsoid, params );
233 #if PROJ_VERSION_MAJOR< 6 237 QString radius, parameter2;
255 QString sql =
"select radius, parameter2 from tbl_ellipsoid where acronym='" + ellipsoid +
'\'';
256 statement = database.
prepare( sql, result );
258 if ( result == SQLITE_OK )
260 if ( statement.
step() == SQLITE_ROW )
267 if ( radius.isEmpty() || parameter2.isEmpty() )
269 QgsDebugMsg( QStringLiteral(
"setEllipsoid: no row in tbl_ellipsoid for acronym '%1'" ).arg( ellipsoid ) );
270 params.
valid =
false;
271 sEllipsoidCacheLock()->lockForWrite();
272 if ( !sDisableCache )
274 sEllipsoidCache()->insert( ellipsoid, params );
276 sEllipsoidCacheLock()->unlock();
281 if ( radius.left( 2 ) == QLatin1String(
"a=" ) )
282 params.
semiMajor = radius.midRef( 2 ).toDouble();
285 QgsDebugMsg( QStringLiteral(
"setEllipsoid: wrong format of radius field: '%1'" ).arg( radius ) );
286 params.
valid =
false;
287 sEllipsoidCacheLock()->lockForWrite();
288 if ( !sDisableCache )
290 sEllipsoidCache()->insert( ellipsoid, params );
292 sEllipsoidCacheLock()->unlock();
299 if ( parameter2.left( 2 ) == QLatin1String(
"b=" ) )
301 params.
semiMinor = parameter2.midRef( 2 ).toDouble();
304 else if ( parameter2.left( 3 ) == QLatin1String(
"rf=" ) )
311 QgsDebugMsg( QStringLiteral(
"setEllipsoid: wrong format of parameter2 field: '%1'" ).arg( parameter2 ) );
312 params.
valid =
false;
313 sEllipsoidCacheLock()->lockForWrite();
314 if ( !sDisableCache )
316 sEllipsoidCache()->insert( ellipsoid, params );
318 sEllipsoidCacheLock()->unlock();
326 QString proj4 =
"+proj=longlat +ellps=" + ellipsoid +
" +no_defs";
332 if ( destCRS.
srsid() == 0 )
334 QString name = QStringLiteral(
" * %1 (%2)" )
335 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
342 params.
crs = destCRS;
344 sEllipsoidCacheLock()->lockForWrite();
345 if ( !sDisableCache )
347 sEllipsoidCache()->insert( ellipsoid, params );
349 sEllipsoidCacheLock()->unlock();
352 params.
valid =
false;
355 if ( !sDisableCache )
357 sEllipsoidCache()->insert( ellipsoid, params );
367 if ( !sDefinitionCache()->isEmpty() )
369 return *sDefinitionCache();
373 QList<QgsEllipsoidUtils::EllipsoidDefinition> defs;
375 #if PROJ_VERSION_MAJOR>=6 379 if ( PROJ_STRING_LIST authorities = proj_get_authorities_from_database( context ) )
381 PROJ_STRING_LIST authoritiesIt = authorities;
382 while (
char *authority = *authoritiesIt )
384 if ( PROJ_STRING_LIST codes = proj_get_codes_from_database( context, authority, PJ_TYPE_ELLIPSOID, 0 ) )
386 PROJ_STRING_LIST codesIt = codes;
387 while (
char *code = *codesIt )
389 QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_create_from_database( context, authority, code, PJ_CATEGORY_ELLIPSOID, 0,
nullptr ) );
390 if ( ellipsoid.get() )
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 );
398 double semiMajor, semiMinor, invFlattening;
399 int semiMinorComputed = 0;
400 if ( proj_ellipsoid_get_parameters( context, ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
405 if ( !semiMinorComputed )
418 if ( !sDisableCache )
420 sEllipsoidCache()->insert( def.acronym, def.parameters );
426 proj_string_list_destroy( codes );
431 proj_string_list_destroy( authorities );
447 Q_ASSERT( result == 0 );
451 QString sql = QStringLiteral(
"select acronym, name from tbl_ellipsoid order by name" );
452 statement = database.
prepare( sql, result );
454 if ( result == SQLITE_OK )
456 while ( statement.
step() == SQLITE_ROW )
472 collator.setCaseSensitivity( Qt::CaseInsensitive );
475 return collator.compare( a.
description, b.description ) < 0;
477 if ( !sDisableCache )
479 *sDefinitionCache() = defs;
488 const QList<QgsEllipsoidUtils::EllipsoidDefinition> defs =
definitions();
489 result.reserve( defs.size() );
492 result << def.acronym;
502 if ( !sDisableCache )
505 sDisableCache =
true;
506 sEllipsoidCache()->clear();
507 sDefinitionCache()->clear();
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.
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)
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)
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...
double semiMinor
Semi-minor axis.
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.
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.
double semiMajor
Semi-major axis.