25 #if PROJ_VERSION_MAJOR>=6 30 QReadWriteLock QgsEllipsoidUtils::sEllipsoidCacheLock;
31 QHash< QString, QgsEllipsoidUtils::EllipsoidParameters > QgsEllipsoidUtils::sEllipsoidCache;
32 QReadWriteLock QgsEllipsoidUtils::sDefinitionCacheLock;
33 QList< QgsEllipsoidUtils::EllipsoidDefinition > QgsEllipsoidUtils::sDefinitionCache;
38 {
"clrk80",
"clrk80ign" },
39 {
"Adrastea2000",
"ESRI:107909"},
40 {
"Amalthea2000",
"ESRI:107910"},
41 {
"Ananke2000",
"ESRI:107911"},
42 {
"Ariel2000",
"ESRI:107945"},
43 {
"Atlas2000",
"ESRI:107926"},
44 {
"Belinda2000",
"ESRI:107946"},
45 {
"Bianca2000",
"ESRI:107947"},
46 {
"Callisto2000",
"ESRI:107912"},
47 {
"Calypso2000",
"ESRI:107927"},
48 {
"Carme2000",
"ESRI:107913"},
49 {
"Charon2000",
"ESRI:107970"},
50 {
"Cordelia2000",
"ESRI:107948"},
51 {
"Cressida2000",
"ESRI:107949"},
52 {
"Deimos2000",
"ESRI:107906"},
53 {
"Desdemona2000",
"ESRI:107950"},
54 {
"Despina2000",
"ESRI:107961"},
55 {
"Dione2000",
"ESRI:107928"},
56 {
"Elara2000",
"ESRI:107914"},
57 {
"Enceladus2000",
"ESRI:107929"},
58 {
"Epimetheus2000",
"ESRI:107930"},
59 {
"Europa2000",
"ESRI:107915"},
60 {
"Galatea2000",
"ESRI:107962"},
61 {
"Ganymede2000",
"ESRI:107916"},
62 {
"Helene2000",
"ESRI:107931"},
63 {
"Himalia2000",
"ESRI:107917"},
64 {
"Hyperion2000",
"ESRI:107932"},
65 {
"Iapetus2000",
"ESRI:107933"},
66 {
"Io2000",
"ESRI:107918"},
67 {
"Janus2000",
"ESRI:107934"},
68 {
"Juliet2000",
"ESRI:107951"},
69 {
"Jupiter2000",
"ESRI:107908"},
70 {
"Larissa2000",
"ESRI:107963"},
71 {
"Leda2000",
"ESRI:107919"},
72 {
"Lysithea2000",
"ESRI:107920"},
73 {
"Mars2000",
"ESRI:107905"},
74 {
"Mercury2000",
"ESRI:107900"},
75 {
"Metis2000",
"ESRI:107921"},
76 {
"Mimas2000",
"ESRI:107935"},
77 {
"Miranda2000",
"ESRI:107952"},
78 {
"Moon2000",
"ESRI:107903"},
79 {
"Naiad2000",
"ESRI:107964"},
80 {
"Neptune2000",
"ESRI:107960"},
81 {
"Nereid2000",
"ESRI:107965"},
82 {
"Oberon2000",
"ESRI:107953"},
83 {
"Ophelia2000",
"ESRI:107954"},
84 {
"Pan2000",
"ESRI:107936"},
85 {
"Pandora2000",
"ESRI:107937"},
86 {
"Pasiphae2000",
"ESRI:107922"},
87 {
"Phobos2000",
"ESRI:107907"},
88 {
"Phoebe2000",
"ESRI:107938"},
89 {
"Pluto2000",
"ESRI:107969"},
90 {
"Portia2000",
"ESRI:107955"},
91 {
"Prometheus2000",
"ESRI:107939"},
92 {
"Proteus2000",
"ESRI:107966"},
93 {
"Puck2000",
"ESRI:107956"},
94 {
"Rhea2000",
"ESRI:107940"},
95 {
"Rosalind2000",
"ESRI:107957"},
96 {
"Saturn2000",
"ESRI:107925"},
97 {
"Sinope2000",
"ESRI:107923"},
98 {
"Telesto2000",
"ESRI:107941"},
99 {
"Tethys2000",
"ESRI:107942"},
100 {
"Thalassa2000",
"ESRI:107967"},
101 {
"Thebe2000",
"ESRI:107924"},
102 {
"Titan2000",
"ESRI:107943"},
103 {
"Titania2000",
"ESRI:107958"},
104 {
"Triton2000",
"ESRI:107968"},
105 {
"Umbriel2000",
"ESRI:107959"},
106 {
"Uranus2000",
"ESRI:107944"},
107 {
"Venus2000",
"ESRI:107902"},
108 {
"IGNF:ELG053",
"EPSG:7030"},
109 {
"IGNF:ELG052",
"EPSG:7043"},
110 {
"IGNF:ELG102",
"EPSG:7043"},
111 {
"WGS66",
"ESRI:107001"},
112 {
"plessis",
"EPSG:7027"},
113 {
"IGNF:ELG017",
"EPSG:7027"},
114 {
"mod_airy",
"EPSG:7002"},
115 {
"IGNF:ELG037",
"EPSG:7019"},
116 {
"IGNF:ELG108",
"EPSG:7036"},
117 {
"cape",
"EPSG:7034"},
118 {
"IGNF:ELG010",
"EPSG:7011"},
119 {
"IGNF:ELG003",
"EPSG:7012"},
120 {
"IGNF:ELG004",
"EPSG:7008"},
121 {
"GSK2011",
"EPSG:1025"},
122 {
"airy",
"EPSG:7001"},
123 {
"aust_SA",
"EPSG:7003"},
124 {
"bessel",
"EPSG:7004"},
125 {
"clrk66",
"EPSG:7008"},
126 {
"clrk80ign",
"EPSG:7011"},
127 {
"evrst30",
"EPSG:7015"},
128 {
"evrstSS",
"EPSG:7016"},
129 {
"evrst48",
"EPSG:7018"},
130 {
"GRS80",
"EPSG:7019"},
131 {
"helmert",
"EPSG:7020"},
132 {
"intl",
"EPSG:7022"},
133 {
"krass",
"EPSG:7024"},
134 {
"NWL9D",
"EPSG:7025"},
135 {
"WGS84",
"EPSG:7030"},
136 {
"GRS67",
"EPSG:7036"},
137 {
"WGS72",
"EPSG:7043"},
138 {
"bess_nam",
"EPSG:7046"},
139 {
"IAU76",
"EPSG:7049"},
140 {
"sphere",
"EPSG:7052"},
141 {
"hough",
"EPSG:7053"},
142 {
"evrst69",
"EPSG:7056"},
143 {
"fschr60",
"ESRI:107002"},
144 {
"fschr68",
"ESRI:107003"},
145 {
"fschr60m",
"ESRI:107004"},
146 {
"walbeck",
"ESRI:107007"},
147 {
"IGNF:ELG001",
"EPSG:7022"},
148 {
"engelis",
"EPSG:7054"},
149 {
"evrst56",
"EPSG:7044"},
150 {
"SEasia",
"ESRI:107004"},
151 {
"SGS85",
"EPSG:7054"},
152 {
"andrae",
"PROJ:ANDRAE"},
153 {
"clrk80",
"EPSG:7034"},
155 {
"delmbr",
"PROJ:DELMBR"},
156 {
"Earth2000",
"PROJ:EARTH2000"},
157 {
"kaula",
"PROJ:KAULA"},
158 {
"lerch",
"PROJ:LERCH"},
159 {
"MERIT",
"PROJ:MERIT"},
160 {
"mprts",
"PROJ:MPRTS"},
161 {
"new_intl",
"PROJ:NEW_INTL"},
162 {
"WGS60",
"PROJ:WGS60"}
167 QString ellipsoid = e;
168 #if PROJ_VERSION_MAJOR >= 6 170 static std::once_flag initialized;
171 std::call_once( initialized, [ = ]
182 QHash< QString, EllipsoidParameters >::const_iterator cacheIt = sEllipsoidCache.constFind( ellipsoid );
183 if ( cacheIt != sEllipsoidCache.constEnd() )
197 if ( ellipsoid.startsWith( QLatin1String(
"PARAMETER" ) ) )
199 QStringList paramList = ellipsoid.split(
':' );
200 bool semiMajorOk, semiMinorOk;
201 double semiMajor = paramList[1].toDouble( & semiMajorOk );
202 double semiMinor = paramList[2].toDouble( & semiMinorOk );
203 if ( semiMajorOk && semiMinorOk )
212 params.
valid =
false;
216 sEllipsoidCache.insert( ellipsoid, params );
220 #if PROJ_VERSION_MAJOR< 6 224 QString radius, parameter2;
242 QString sql =
"select radius, parameter2 from tbl_ellipsoid where acronym='" + ellipsoid +
'\'';
243 statement = database.
prepare( sql, result );
245 if ( result == SQLITE_OK )
247 if ( statement.
step() == SQLITE_ROW )
254 if ( radius.isEmpty() || parameter2.isEmpty() )
256 QgsDebugMsg( QStringLiteral(
"setEllipsoid: no row in tbl_ellipsoid for acronym '%1'" ).arg( ellipsoid ) );
257 params.
valid =
false;
258 sEllipsoidCacheLock.lockForWrite();
259 sEllipsoidCache.insert( ellipsoid, params );
260 sEllipsoidCacheLock.unlock();
265 if ( radius.left( 2 ) == QLatin1String(
"a=" ) )
266 params.
semiMajor = radius.midRef( 2 ).toDouble();
269 QgsDebugMsg( QStringLiteral(
"setEllipsoid: wrong format of radius field: '%1'" ).arg( radius ) );
270 params.
valid =
false;
271 sEllipsoidCacheLock.lockForWrite();
272 sEllipsoidCache.insert( ellipsoid, params );
273 sEllipsoidCacheLock.unlock();
280 if ( parameter2.left( 2 ) == QLatin1String(
"b=" ) )
282 params.
semiMinor = parameter2.midRef( 2 ).toDouble();
285 else if ( parameter2.left( 3 ) == QLatin1String(
"rf=" ) )
292 QgsDebugMsg( QStringLiteral(
"setEllipsoid: wrong format of parameter2 field: '%1'" ).arg( parameter2 ) );
293 params.
valid =
false;
294 sEllipsoidCacheLock.lockForWrite();
295 sEllipsoidCache.insert( ellipsoid, params );
296 sEllipsoidCacheLock.unlock();
304 QString proj4 =
"+proj=longlat +ellps=" + ellipsoid +
" +no_defs";
310 if ( destCRS.
srsid() == 0 )
312 QString name = QStringLiteral(
" * %1 (%2)" )
313 .arg( QObject::tr(
"Generated CRS",
"A CRS automatically generated from layer info get this prefix for description" ),
320 params.
crs = destCRS;
322 sEllipsoidCacheLock.lockForWrite();
323 sEllipsoidCache.insert( ellipsoid, params );
324 sEllipsoidCacheLock.unlock();
327 params.
valid =
false;
330 sEllipsoidCache.insert( ellipsoid, params );
339 if ( !sDefinitionCache.isEmpty() )
341 QList<QgsEllipsoidUtils::EllipsoidDefinition> defs = sDefinitionCache;
346 QList<QgsEllipsoidUtils::EllipsoidDefinition> defs;
348 #if PROJ_VERSION_MAJOR>=6 352 if ( PROJ_STRING_LIST authorities = proj_get_authorities_from_database( context ) )
354 PROJ_STRING_LIST authoritiesIt = authorities;
355 while (
char *authority = *authoritiesIt )
357 if ( PROJ_STRING_LIST codes = proj_get_codes_from_database( context, authority, PJ_TYPE_ELLIPSOID, 0 ) )
359 PROJ_STRING_LIST codesIt = codes;
360 while (
char *code = *codesIt )
362 QgsProjUtils::proj_pj_unique_ptr ellipsoid( proj_create_from_database( context, authority, code, PJ_CATEGORY_ELLIPSOID, 0,
nullptr ) );
363 if ( ellipsoid.get() )
366 QString name = QString( proj_get_name( ellipsoid.get() ) );
367 def.
acronym = QStringLiteral(
"%1:%2" ).arg( authority, code );
368 name.replace(
'_',
' ' );
369 def.
description = QStringLiteral(
"%1 (%2:%3)" ).arg( name, authority, code );
371 double semiMajor, semiMinor, invFlattening;
372 int semiMinorComputed = 0;
373 if ( proj_ellipsoid_get_parameters( context, ellipsoid.get(), &semiMajor, &semiMinor, &semiMinorComputed, &invFlattening ) )
378 if ( !semiMinorComputed )
391 sEllipsoidCache.insert( def.acronym, def.parameters );
396 proj_string_list_destroy( codes );
401 proj_string_list_destroy( authorities );
417 Q_ASSERT( result == 0 );
421 QString sql = QStringLiteral(
"select acronym, name from tbl_ellipsoid order by name" );
422 statement = database.
prepare( sql, result );
424 if ( result == SQLITE_OK )
426 while ( statement.
step() == SQLITE_ROW )
442 collator.setCaseSensitivity( Qt::CaseInsensitive );
445 return collator.compare( a.
description, b.description ) < 0;
447 sDefinitionCache = defs;
458 result << def.acronym;
static QgsCoordinateReferenceSystem fromProj4(const QString &proj4)
Creates a CRS from a proj4 style formatted string.
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 ...
bool qgsDoubleNear(double a, double b, double epsilon=4 *std::numeric_limits< double >::epsilon())
Compare two doubles (but allow some difference)
QString toProj4() const
Returns a Proj4 string representation of this CRS.
Contains parameters for an ellipsoid.
static EllipsoidParameters ellipsoidParameters(const QString &ellipsoid)
Returns the parameters for the specified ellipsoid.
long saveAsUserCrs(const QString &name)
Save the proj4-string as a custom CRS.
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.
#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.
const QMap< QString, QString > sProj6EllipsoidAcronymMap
QString acronym
authority:code for QGIS builds with proj version 6 or greater, or custom acronym for ellipsoid for ea...
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.
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.