Branch data Line data Source code
1 : : /***************************************************************************
2 : : qgscoordinatereferencesystem.h
3 : :
4 : : -------------------
5 : : begin : 2007
6 : : copyright : (C) 2007 by Gary E. Sherman
7 : : email : sherman@mrcc.com
8 : : ***************************************************************************/
9 : :
10 : : /***************************************************************************
11 : : * *
12 : : * This program is free software; you can redistribute it and/or modify *
13 : : * it under the terms of the GNU General Public License as published by *
14 : : * the Free Software Foundation; either version 2 of the License, or *
15 : : * (at your option) any later version. *
16 : : * *
17 : : ***************************************************************************/
18 : : #ifndef QGSCOORDINATEREFERENCESYSTEM_H
19 : : #define QGSCOORDINATEREFERENCESYSTEM_H
20 : :
21 : : //Standard includes
22 : : #include "qgis_core.h"
23 : : #include <ostream>
24 : :
25 : : //qt includes
26 : : #include <QString>
27 : : #include <QMap>
28 : : #include <QHash>
29 : : #include <QReadWriteLock>
30 : : #include <QExplicitlySharedDataPointer>
31 : : #include <QObject>
32 : :
33 : : //qgis includes
34 : : #include "qgis_sip.h"
35 : : #include "qgsunittypes.h"
36 : : #include "qgsrectangle.h"
37 : : #include "qgssqliteutils.h"
38 : :
39 : : class QDomNode;
40 : : class QDomDocument;
41 : : class QgsCoordinateReferenceSystemPrivate;
42 : :
43 : : #ifndef SIP_RUN
44 : : struct PJconsts;
45 : : typedef struct PJconsts PJ;
46 : :
47 : : #if PROJ_VERSION_MAJOR>=8
48 : : struct pj_ctx;
49 : : typedef struct pj_ctx PJ_CONTEXT;
50 : : #else
51 : : struct projCtx_t;
52 : : typedef struct projCtx_t PJ_CONTEXT;
53 : : #endif
54 : : #endif
55 : :
56 : : // forward declaration for sqlite3
57 : : typedef struct sqlite3 sqlite3 SIP_SKIP;
58 : :
59 : : #ifdef DEBUG
60 : : typedef struct OGRSpatialReferenceHS *OGRSpatialReferenceH SIP_SKIP;
61 : : #else
62 : : typedef void *OGRSpatialReferenceH SIP_SKIP;
63 : : #endif
64 : :
65 : : class QgsCoordinateReferenceSystem;
66 : : typedef void ( *CUSTOM_CRS_VALIDATION )( QgsCoordinateReferenceSystem & ) SIP_SKIP;
67 : :
68 : : /**
69 : : * \ingroup core
70 : : * \brief This class represents a coordinate reference system (CRS).
71 : : *
72 : : * Coordinate reference system object defines a specific map projection, as well as transformations
73 : : * between different coordinate reference systems. There are various ways how a CRS can be defined:
74 : : * using well-known text (WKT), PROJ string or combination of authority and code (e.g. EPSG:4326).
75 : : * QGIS comes with its internal database of coordinate reference systems (stored in SQLite) that
76 : : * allows lookups of CRS and seamless conversions between the various definitions.
77 : : *
78 : : * Most commonly one comes across two types of coordinate systems:
79 : : *
80 : : * - Geographic coordinate systems: based on a geodetic datum, normally with coordinates being
81 : : * latitude/longitude in degrees. The most common one is World Geodetic System 84 (WGS84).
82 : : * - Projected coordinate systems: based on a geodetic datum with coordinates projected to a plane,
83 : : * typically using meters or feet as units. Common projected coordinate systems are Universal
84 : : * Transverse Mercator or Albers Equal Area.
85 : : *
86 : : * Internally QGIS uses proj library for all the math behind coordinate transformations, so in case
87 : : * of any troubles with projections it is best to examine the PROJ representation within the object,
88 : : * as that is the representation that will be ultimately used.
89 : : *
90 : : * Methods that allow inspection of CRS instances include isValid(), authid(), description(),
91 : : * toWkt(), toProj(), mapUnits() and others.
92 : : * Creation of CRS instances is further described in \ref crs_construct_and_copy section below.
93 : : * Transformations between coordinate reference systems are done using QgsCoordinateTransform class.
94 : : *
95 : : * For example, the following code will create and inspect "British national grid" CRS:
96 : : *
97 : : * \code{.py}
98 : : * crs = QgsCoordinateReferenceSystem("EPSG:27700")
99 : : * if crs.isValid():
100 : : * print("CRS Description: {}".format(crs.description()))
101 : : * print("CRS PROJ text: {}".format(crs.toProj()))
102 : : * else:
103 : : * print("Invalid CRS!")
104 : : * \endcode
105 : : *
106 : : * This will produce the following output:
107 : : *
108 : : * \code
109 : : * CRS Description: OSGB 1936 / British National Grid
110 : : * CRS PROJ text: +proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 +x_0=400000 +y_0=-100000 [output trimmed]
111 : : * \endcode
112 : : *
113 : : * \section crs_def_formats CRS Definition Formats
114 : : *
115 : : * This section gives an overview of various supported CRS definition formats:
116 : : *
117 : : * - Authority and Code: Also referred to as OGC WMS format within QGIS as they have been widely
118 : : * used in OGC standards. These are encoded as `<auth>:<code>`, for example `EPSG:4326` refers
119 : : * to WGS84 system. EPSG is the most commonly used authority that covers a wide range
120 : : * of coordinate systems around the world.
121 : : *
122 : : * An extended variant of this format is OGC URN. Syntax of URN for CRS definition is
123 : : * `urn:ogc:def:crs:<auth>:[<version>]:<code>`. This class can also parse URNs (versions
124 : : * are currently ignored). For example, WGS84 may be encoded as `urn:ogc:def:crs:OGC:1.3:CRS84`.
125 : : *
126 : : * QGIS adds support for "USER" authority that refers to IDs used internally in QGIS. This variant
127 : : * is best avoided or used with caution as the IDs are not permanent and they refer to different CRS
128 : : * on different machines or user profiles.
129 : : *
130 : : * \see authid()
131 : : * \see createFromOgcWmsCrs()
132 : : *
133 : : * - PROJ string: This is a string consisting of a series of key/value pairs in the following
134 : : * format: `+param1=value1 +param2=value2 [...]`. This is the format natively used by the
135 : : * underlying proj library. For example, the definition of WGS84 looks like this:
136 : : *
137 : : * \code
138 : : * +proj=longlat +datum=WGS84 +no_defs
139 : : * \endcode
140 : : *
141 : : * \see toProj()
142 : : * \see createFromProj()
143 : : *
144 : : * - Well-known text (WKT): Defined by Open Geospatial Consortium (OGC), this is another common
145 : : * format to define CRS. For WGS84 the OGC WKT definition is the following:
146 : : *
147 : : * \code
148 : : * GEOGCS["WGS 84",
149 : : * DATUM["WGS_1984",
150 : : * SPHEROID["WGS 84",6378137,298.257223563,AUTHORITY["EPSG","7030"]],
151 : : * AUTHORITY["EPSG","6326"]],
152 : : * PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],
153 : : * UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]],
154 : : * AUTHORITY["EPSG","4326"]]
155 : : * \endcode
156 : : *
157 : : * \see toWkt()
158 : : * \see createFromWkt()
159 : : *
160 : : * \section crs_db_and_custom CRS Database and Custom CRS
161 : : *
162 : : * The database of CRS shipped with QGIS is stored in a SQLite database (see QgsApplication::srsDatabaseFilePath())
163 : : * and it is based on the data files maintained by GDAL project (a variety of .csv and .wkt files).
164 : : *
165 : : * Sometimes it happens that users need to use a CRS definition that is not well known
166 : : * or that has been only created with a specific purpose (and thus its definition is not
167 : : * available in our database of CRS). Whenever a new CRS definition is seen, it will
168 : : * be added to the local database (in user's home directory, see QgsApplication::qgisUserDatabaseFilePath()).
169 : : * QGIS also features a GUI for management of local custom CRS definitions.
170 : : *
171 : : * There are therefore two databases: one for shipped CRS definitions and one for custom CRS definitions.
172 : : * Custom CRS have internal IDs (accessible with srsid()) greater or equal to \ref USER_CRS_START_ID.
173 : : * The local CRS databases should never be accessed directly with SQLite functions, instead
174 : : * you should use QgsCoordinateReferenceSystem API for CRS lookups and for managements of custom CRS.
175 : : *
176 : : * \section validation Validation
177 : : *
178 : : * In some cases (most prominently when loading a map layer), QGIS will try to ensure
179 : : * that the given map layer CRS is valid using validate() call. If not, a custom
180 : : * validation function will be called - such function may for example show a GUI
181 : : * for manual CRS selection. The validation function is configured using setCustomCrsValidation().
182 : : * If validation fails or no validation function is set, the default CRS is assigned
183 : : * (WGS84). QGIS application registers its validation function that will act according
184 : : * to user's settings (either show CRS selector dialog or use project/custom CRS).
185 : : *
186 : : * \section crs_construct_and_copy Object Construction and Copying
187 : : *
188 : : * The easiest way of creating CRS instances is to use QgsCoordinateReferenceSystem(const QString&)
189 : : * constructor that automatically recognizes definition format from the given string.
190 : : *
191 : : * Creation of CRS object involves some queries in a local SQLite database, which may
192 : : * be potentially expensive. Consequently, CRS creation methods use an internal cache to avoid
193 : : * unnecessary database lookups. If the CRS database is modified, then it is necessary to call
194 : : * invalidateCache() to ensure that outdated records are not being returned from the cache.
195 : : *
196 : : * Since QGIS 2.16 QgsCoordinateReferenceSystem objects are implicitly shared.
197 : : *
198 : : * \section caveats Caveats
199 : : *
200 : : * There are two different flavors of WKT: one is defined by OGC, the other is the standard
201 : : * used by ESRI. They look very similar, but they are not the same. QGIS is able to consume
202 : : * both flavors.
203 : : *
204 : : * \see QgsCoordinateTransform
205 : : */
206 : :
207 : : class CORE_EXPORT QgsCoordinateReferenceSystem
208 : : {
209 : : Q_GADGET
210 : :
211 : : Q_PROPERTY( QgsUnitTypes::DistanceUnit mapUnits READ mapUnits )
212 : : Q_PROPERTY( bool isGeographic READ isGeographic )
213 : :
214 : : public:
215 : :
216 : : //! Enumeration of types of IDs accepted in createFromId() method
217 : : enum CrsType
218 : : {
219 : : InternalCrsId, //!< Internal ID used by QGIS in the local SQLite database
220 : : PostgisCrsId, //!< SRID used in PostGIS. DEPRECATED -- DO NOT USE
221 : : EpsgCrsId //!< EPSG code
222 : : };
223 : :
224 : : //! Projection definition formats
225 : : enum Format
226 : : {
227 : : FormatWkt = 0, //!< WKT format (always recommended over proj string format)
228 : : FormatProj, //!< Proj string format
229 : : };
230 : :
231 : : //! Constructs an invalid CRS object
232 : : QgsCoordinateReferenceSystem();
233 : :
234 : : ~QgsCoordinateReferenceSystem();
235 : :
236 : : // TODO QGIS 4: remove "POSTGIS" and "INTERNAL"
237 : :
238 : : /**
239 : : * Constructs a CRS object from a string definition using createFromString()
240 : : *
241 : : * It supports the following formats:
242 : : *
243 : : * - "EPSG:<code>" - handled with createFromOgcWms()
244 : : * - "POSTGIS:<srid>" - handled with createFromSrid()
245 : : * - "INTERNAL:<srsid>" - handled with createFromSrsId()
246 : : * - "PROJ:<proj>" - handled with createFromProj()
247 : : * - "WKT:<wkt>" - handled with createFromWkt()
248 : : *
249 : : * If no prefix is specified, WKT definition is assumed.
250 : : * \param definition A String containing a coordinate reference system definition.
251 : : * \see createFromString()
252 : : */
253 : : explicit QgsCoordinateReferenceSystem( const QString &definition );
254 : :
255 : : // TODO QGIS 4: remove type and always use EPSG code
256 : :
257 : : /**
258 : : * Constructor
259 : : *
260 : : * A CRS object using a PostGIS SRID, an EPSG code or an internal QGIS CRS ID.
261 : : * \note We encourage you to use EPSG code or WKT to describe CRSes in your code
262 : : * wherever possible. Internal QGIS CRS IDs are not guaranteed to be permanent / involatile,
263 : : * and proj strings are a lossy format.
264 : : * \param id The ID valid for the chosen CRS ID type
265 : : * \param type One of the types described in CrsType
266 : : * \deprecated QGIS 3.10 We encourage you to use EPSG codes or WKT to describe CRSes in your code wherever possible. Internal QGIS CRS IDs are not guaranteed to be permanent / involatile, and Proj strings are a lossy format.
267 : : */
268 : : Q_DECL_DEPRECATED explicit QgsCoordinateReferenceSystem( long id, CrsType type = PostgisCrsId ) SIP_DEPRECATED;
269 : :
270 : : //! Copy constructor
271 : : QgsCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &srs );
272 : :
273 : : //! Assignment operator
274 : : QgsCoordinateReferenceSystem &operator=( const QgsCoordinateReferenceSystem &srs );
275 : :
276 : : //! Allows direct construction of QVariants from QgsCoordinateReferenceSystem.
277 : 0 : operator QVariant() const
278 : : {
279 : 0 : return QVariant::fromValue( *this );
280 : : }
281 : :
282 : : /**
283 : : * Returns a list of all valid SRS IDs present in the CRS database. Any of the
284 : : * returned values can be safely passed to fromSrsId() to create a new, valid
285 : : * QgsCoordinateReferenceSystem object.
286 : : * \see fromSrsId()
287 : : * \since QGIS 3.0
288 : : */
289 : : static QList< long > validSrsIds();
290 : :
291 : : // static creators
292 : :
293 : : /**
294 : : * Creates a CRS from a given OGC WMS-format Coordinate Reference System string.
295 : : * \param ogcCrs OGR compliant CRS definition, e.g., "EPSG:4326"
296 : : * \returns matching CRS, or an invalid CRS if string could not be matched
297 : : * \see createFromOgcWmsCrs()
298 : : * \since QGIS 3.0
299 : : */
300 : : static QgsCoordinateReferenceSystem fromOgcWmsCrs( const QString &ogcCrs );
301 : :
302 : : /**
303 : : * Creates a CRS from a given EPSG ID.
304 : : * \param epsg epsg CRS ID
305 : : * \returns matching CRS, or an invalid CRS if string could not be matched
306 : : * \since QGIS 3.0
307 : : */
308 : : Q_INVOKABLE static QgsCoordinateReferenceSystem fromEpsgId( long epsg );
309 : :
310 : : /**
311 : : * Creates a CRS from a proj style formatted string.
312 : : * \returns matching CRS, or an invalid CRS if string could not be matched
313 : : * \see createFromProj()
314 : : * \deprecated QGIS 3.10 Use fromProj() instead.
315 : : */
316 : : Q_DECL_DEPRECATED static QgsCoordinateReferenceSystem fromProj4( const QString &proj4 ) SIP_DEPRECATED;
317 : :
318 : : /**
319 : : * Creates a CRS from a proj style formatted string.
320 : : * \param proj proj format string
321 : : * \returns matching CRS, or an invalid CRS if string could not be matched
322 : : * \see createFromProj()
323 : : * \since QGIS 3.10.3
324 : : */
325 : : static QgsCoordinateReferenceSystem fromProj( const QString &proj );
326 : :
327 : : /**
328 : : * Creates a CRS from a WKT spatial ref sys definition string.
329 : : * \param wkt WKT for the desired spatial reference system.
330 : : * \returns matching CRS, or an invalid CRS if string could not be matched
331 : : * \see createFromWkt()
332 : : * \since QGIS 3.0
333 : : */
334 : : static QgsCoordinateReferenceSystem fromWkt( const QString &wkt );
335 : :
336 : : /**
337 : : * Creates a CRS from a specified QGIS SRS ID.
338 : : * \param srsId internal QGIS SRS ID
339 : : * \returns matching CRS, or an invalid CRS if ID could not be found
340 : : * \see createFromSrsId()
341 : : * \see validSrsIds()
342 : : * \since QGIS 3.0
343 : : */
344 : : static QgsCoordinateReferenceSystem fromSrsId( long srsId );
345 : :
346 : : // Misc helper functions -----------------------
347 : :
348 : : // TODO QGIS 4: remove type and always use EPSG code, rename to createFromEpsg
349 : :
350 : : /**
351 : : * Sets this CRS by lookup of the given ID in the CRS database.
352 : : * \returns TRUE on success else FALSE
353 : : * \deprecated QGIS 3.10 We encourage you to use EPSG code or WKT to describe CRSes in your code wherever possible. Internal QGIS CRS IDs are not guaranteed to be permanent / involatile, and Proj strings are a lossy format.
354 : : */
355 : : Q_DECL_DEPRECATED bool createFromId( long id, CrsType type = PostgisCrsId ) SIP_DEPRECATED;
356 : :
357 : : // TODO QGIS 4: remove "QGIS" and "CUSTOM", only support "USER" (also returned by authid())
358 : :
359 : : /**
360 : : * Sets this CRS to the given OGC WMS-format Coordinate Reference Systems.
361 : : *
362 : : * Accepts both "<auth>:<code>" format and OGC URN "urn:ogc:def:crs:<auth>:[<version>]:<code>".
363 : : * It also recognizes "QGIS", "USER", "CUSTOM" authorities, which all have the same meaning
364 : : * and refer to QGIS internal CRS IDs.
365 : : * \returns TRUE on success else FALSE
366 : : * \note this method uses an internal cache. Call invalidateCache() to clear the cache.
367 : : * \see fromOgcWmsCrs()
368 : : */
369 : : bool createFromOgcWmsCrs( const QString &crs );
370 : :
371 : : // TODO QGIS 4: remove unless really necessary - let's use EPSG codes instead
372 : :
373 : : /**
374 : : * Sets this CRS by lookup of the given PostGIS SRID in the CRS database.
375 : : * \param srid The PostGIS SRID for the desired spatial reference system.
376 : : * \returns TRUE on success else FALSE
377 : : *
378 : : * \deprecated QGIS 3.10 Use alternative methods for SRS construction instead -- this method was specifically created for use by the postgres provider alone, and using it elsewhere will lead to subtle bugs.
379 : : */
380 : : Q_DECL_DEPRECATED bool createFromSrid( long srid ) SIP_DEPRECATED;
381 : :
382 : : /**
383 : : * Sets this CRS using a WKT definition.
384 : : *
385 : : * If EPSG code of the WKT definition can be determined, it is extracted
386 : : * and createFromOgcWmsCrs() is used to initialize the object.
387 : : *
388 : : * \param wkt The WKT for the desired spatial reference system.
389 : : * \returns TRUE on success else FALSE
390 : : * \note Some members may be left blank if no match can be found in CRS database.
391 : : * \note this method uses an internal cache. Call invalidateCache() to clear the cache.
392 : : * \see fromWkt()
393 : : */
394 : : bool createFromWkt( const QString &wkt );
395 : :
396 : : /**
397 : : * Sets this CRS by lookup of internal QGIS CRS ID in the CRS database.
398 : : *
399 : : * If the srsid is < USER_CRS_START_ID, system CRS database is used, otherwise
400 : : * user's local CRS database from home directory is used.
401 : : * \param srsId The internal QGIS CRS ID for the desired spatial reference system.
402 : : * \returns TRUE on success else FALSE
403 : : * \note this method uses an internal cache. Call invalidateCache() to clear the cache.
404 : : * \see fromSrsId()
405 : : * \warning This method is highly discouraged, and CRS objects should instead be constructed
406 : : * using auth:id codes or WKT strings
407 : : */
408 : : bool createFromSrsId( long srsId );
409 : :
410 : : /**
411 : : * Sets this CRS by passing it a PROJ style formatted string.
412 : : *
413 : : * The string will be parsed and the projection and ellipsoid
414 : : * members set and the remainder of the Proj string will be stored
415 : : * in the parameters member. The reason for this is so that we
416 : : * can easily present the user with 'natural language' representation
417 : : * of the projection and ellipsoid by looking them up in the srs.db sqlite
418 : : * database.
419 : : *
420 : : * We try to match the Proj string to internal QGIS CRS ID using the following logic:
421 : : *
422 : : * - ask the Proj library to identify the CRS to a standard registered CRS (e.g. EPSG codes)
423 : : * - if no match is found, compare the CRS to all user CRSes, using the Proj library to determine CRS equivalence (hence making the match parameter order insensitive)
424 : : * - if none of the above match, use the Proj string to create the CRS and do not associated an internal CRS ID to it.
425 : : *
426 : : * \param projString A Proj format string
427 : : * \returns TRUE on success else FALSE
428 : : * \note Some members may be left blank if no match can be found in CRS database.
429 : : * \note This method uses an internal cache. Call invalidateCache() to clear the cache.
430 : : * \see fromProj()
431 : : * \deprecated QGIS 3.10 Use createFromProj() instead
432 : : */
433 : : Q_DECL_DEPRECATED bool createFromProj4( const QString &projString ) SIP_DEPRECATED;
434 : :
435 : : /**
436 : : * Sets this CRS by passing it a PROJ style formatted string.
437 : : *
438 : : * The string will be parsed and the projection and ellipsoid
439 : : * members set and the remainder of the Proj string will be stored
440 : : * in the parameters member. The reason for this is so that we
441 : : * can easily present the user with 'natural language' representation
442 : : * of the projection and ellipsoid by looking them up in the srs.db sqlite
443 : : * database.
444 : : *
445 : : * We try to match the Proj string to internal QGIS CRS ID using the following logic:
446 : : *
447 : : * - ask the Proj library to identify the CRS to a standard registered CRS (e.g. EPSG codes)
448 : : * - if no match is found, compare the CRS to all user CRSes, using the Proj library to determine CRS equivalence (hence making the match parameter order insensitive)
449 : : * - if none of the above match, use the Proj string to create the CRS and do not associated an internal CRS ID to it.
450 : : *
451 : : * \param projString A Proj format string
452 : : * \param identify if FALSE, no attempts will be made to match the proj string against known CRS authorities. This is much
453 : : * faster, but should only ever be used when it is known in advance that the definition does not correspond to a known or user CRS. This
454 : : * argument is not available in Python.
455 : : *
456 : : * \returns TRUE on success else FALSE
457 : : * \note Some members may be left blank if no match can be found in CRS database.
458 : : * \note This method uses an internal cache. Call invalidateCache() to clear the cache.
459 : : * \see fromProj()
460 : : * \since QGIS 3.10.3
461 : : */
462 : : #ifndef SIP_RUN
463 : : bool createFromProj( const QString &projString, bool identify = true );
464 : : #else
465 : : bool createFromProj( const QString &projString );
466 : : #endif
467 : :
468 : : /**
469 : : * Set up this CRS from a string definition.
470 : : *
471 : : * It supports the following formats:
472 : : *
473 : : * - "EPSG:<code>" - handled with createFromOgcWms()
474 : : * - "POSTGIS:<srid>" - handled with createFromSrid()
475 : : * - "INTERNAL:<srsid>" - handled with createFromSrsId()
476 : : * - "PROJ:<proj>" - handled with createFromProj()
477 : : * - "WKT:<wkt>" - handled with createFromWkt()
478 : : *
479 : : * If no prefix is specified, WKT definition is assumed.
480 : : * \param definition A String containing a coordinate reference system definition.
481 : : * \returns TRUE on success else FALSE
482 : : */
483 : : bool createFromString( const QString &definition );
484 : :
485 : : // TODO QGIS 4: rename to createFromStringOGR so it is clear it's similar to createFromString, just different backend
486 : :
487 : : /**
488 : : * Set up this CRS from various text formats.
489 : : *
490 : : * Valid formats: WKT string, "EPSG:n", "EPSGA:n", "AUTO:proj_id,unit_id,lon0,lat0",
491 : : * "urn:ogc:def:crs:EPSG::n", PROJ string, filename (with WKT, XML or PROJ string),
492 : : * well known name (such as NAD27, NAD83, WGS84 or WGS72),
493 : : * ESRI::[WKT string] (directly or in a file), "IGNF:xxx"
494 : : *
495 : : * For more details on supported formats see OGRSpatialReference::SetFromUserInput()
496 : : * ( https://gdal.org/doxygen/classOGRSpatialReference.html#aec3c6a49533fe457ddc763d699ff8796 )
497 : : * \param definition A String containing a coordinate reference system definition.
498 : : * \returns TRUE on success else FALSE
499 : : * \note this function generates a WKT string using OSRSetFromUserInput() and
500 : : * passes it to createFromWkt() function.
501 : : */
502 : : bool createFromUserInput( const QString &definition );
503 : :
504 : : /**
505 : : * Make sure that ESRI WKT import is done properly.
506 : : * This is required for proper shapefile CRS import when using gdal>= 1.9.
507 : : * \note This function is called by createFromUserInput() and QgsOgrProvider::crs(), there is usually
508 : : * no need to call it from elsewhere.
509 : : * \note This function sets CPL config option GDAL_FIX_ESRI_WKT to a proper value,
510 : : * unless it has been set by the user through the commandline or an environment variable.
511 : : * For more details refer to OGRSpatialReference::morphFromESRI() .
512 : : * \deprecated QGIS 3.10 Not used on builds based on Proj version 6 or later
513 : : */
514 : : Q_DECL_DEPRECATED static void setupESRIWktFix() SIP_DEPRECATED;
515 : :
516 : : //! Returns whether this CRS is correctly initialized and usable
517 : : bool isValid() const;
518 : :
519 : : /**
520 : : * Perform some validation on this CRS. If the CRS doesn't validate the
521 : : * default behavior settings for layers with unknown CRS will be
522 : : * consulted and acted on accordingly. By hell or high water this
523 : : * method will do its best to make sure that this CRS is valid - even
524 : : * if that involves resorting to a hard coded default of geocs:wgs84.
525 : : *
526 : : * \note It is not usually necessary to use this function, unless you
527 : : * are trying to force this CRS to be valid.
528 : : * \see setCustomCrsValidation(), customCrsValidation()
529 : : */
530 : : void validate();
531 : :
532 : : // TODO QGIS 4: seems completely obsolete now (only compares proj4 - already done in createFromProj4)
533 : :
534 : : /**
535 : : * Walks the CRS databases (both system and user database) trying to match
536 : : * stored PROJ string to a database entry in order to fill in further
537 : : * pieces of information about CRS.
538 : : * \note The ellipsoid and projection acronyms must be set as well as the proj string!
539 : : * \returns long the SrsId of the matched CRS, zero if no match was found
540 : : * \deprecated QGIS 3.10 Not used in Proj >= 6 based builds
541 : : */
542 : : Q_DECL_DEPRECATED long findMatchingProj() SIP_DEPRECATED;
543 : :
544 : : /**
545 : : * Overloaded == operator used to compare to CRS's.
546 : : *
547 : : * Internally it will use authid() for comparison.
548 : : */
549 : : bool operator==( const QgsCoordinateReferenceSystem &srs ) const;
550 : :
551 : : /**
552 : : * Overloaded != operator used to compare to CRS's.
553 : : *
554 : : * Returns opposite bool value to operator ==
555 : : */
556 : : bool operator!=( const QgsCoordinateReferenceSystem &srs ) const;
557 : :
558 : : /**
559 : : * Restores state from the given DOM node.
560 : : * If it fails or if the node is empty, a default empty CRS will be returned.
561 : : * \param node The node from which state will be restored
562 : : * \returns bool TRUE on success, FALSE on failure
563 : : */
564 : : bool readXml( const QDomNode &node );
565 : :
566 : : /**
567 : : * Stores state to the given Dom node in the given document.
568 : : * \param node The node in which state will be restored
569 : : * \param doc The document in which state will be stored
570 : : * \returns bool TRUE on success, FALSE on failure
571 : : */
572 : : bool writeXml( QDomNode &node, QDomDocument &doc ) const;
573 : :
574 : :
575 : : /**
576 : : * Sets custom function to force valid CRS
577 : : * \note not available in Python bindings
578 : : */
579 : : static void setCustomCrsValidation( CUSTOM_CRS_VALIDATION f ) SIP_SKIP;
580 : :
581 : : /**
582 : : * Gets custom function
583 : : * \note not available in Python bindings
584 : : */
585 : : static CUSTOM_CRS_VALIDATION customCrsValidation() SIP_SKIP;
586 : :
587 : : // Accessors -----------------------------------
588 : :
589 : : /**
590 : : * Returns the internal CRS ID, if available.
591 : : * \returns the internal sqlite3 srs.db primary key for this CRS
592 : : */
593 : : long srsid() const;
594 : :
595 : : // TODO QGIS 4: remove unless really necessary - let's use EPSG codes instead
596 : :
597 : : /**
598 : : * Returns PostGIS SRID for the CRS.
599 : : * \returns the PostGIS spatial_ref_sys identifier for this CRS (defaults to 0)
600 : : */
601 : : long postgisSrid() const;
602 : :
603 : : /**
604 : : * Returns the authority identifier for the CRS.
605 : : *
606 : : * The identifier includes both the authority (e.g., EPSG) and the CRS number (e.g., 4326).
607 : : * This is the best method to use when showing a very short CRS identifier to a user,
608 : : * e.g., "EPSG:4326".
609 : : *
610 : : * If CRS object is a custom CRS (not found in database), the method will return
611 : : * internal QGIS CRS ID with "QGIS" authority, for example "QGIS:100005"
612 : : * \returns the authority identifier for this CRS
613 : : * \see description()
614 : : */
615 : : QString authid() const;
616 : :
617 : : /**
618 : : * Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
619 : :
620 : : * \note an empty string will be returned if the description is not available for the CRS
621 : : * \see authid()
622 : : * \see userFriendlyIdentifier()
623 : : */
624 : : QString description() const;
625 : :
626 : : /**
627 : : * Type of identifier string to create.
628 : : *
629 : : * \since QGIS 3.10.3
630 : : */
631 : : enum IdentifierType
632 : : {
633 : : ShortString, //!< A heavily abbreviated string, for use when a compact representation is required
634 : : MediumString, //!< A medium-length string, recommended for general purpose use
635 : : FullString, //!< Full definition -- possibly a very lengthy string, e.g. with no truncation of custom WKT definitions
636 : : };
637 : :
638 : : /**
639 : : * Returns a user friendly identifier for the CRS.
640 : : *
641 : : * Depending on the format of the CRS, this may reflect the CRSes registered name, or for
642 : : * CRSes not saved in the database it may reflect the underlying WKT or Proj string definition
643 : : * of the CRS.
644 : : *
645 : : * In most cases this is the best method to use when showing a friendly identifier for the CRS to a
646 : : * user.
647 : : *
648 : : * \see description()
649 : : * \since QGIS 3.10.3
650 : : */
651 : : QString userFriendlyIdentifier( IdentifierType type = MediumString ) const;
652 : :
653 : : /**
654 : : * Returns the projection acronym for the projection used by the CRS.
655 : : * \returns the official Proj acronym for the projection family
656 : : * \note an empty string will be returned if the projectionAcronym is not available for the CRS
657 : : * \see ellipsoidAcronym()
658 : : */
659 : : QString projectionAcronym() const;
660 : :
661 : : /**
662 : : * Returns the ellipsoid acronym for the ellipsoid used by the CRS.
663 : : * \returns the official authority:code identifier for the ellipsoid, or PARAMETER:MAJOR:MINOR for custom ellipsoids
664 : : * \note an empty string will be returned if the ellipsoidAcronym is not available for the CRS
665 : : * \see projectionAcronym()
666 : : */
667 : : QString ellipsoidAcronym() const;
668 : :
669 : : //! WKT formatting variants, only used for builds based on Proj >= 6
670 : : enum WktVariant
671 : : {
672 : : WKT1_GDAL, //!< WKT1 as traditionally output by GDAL, deriving from OGC 01-009. A notable departure from WKT1_GDAL with respect to OGC 01-009 is that in WKT1_GDAL, the unit of the PRIMEM value is always degrees.
673 : : WKT1_ESRI, //!< WKT1 as traditionally output by ESRI software, deriving from OGC 99-049.
674 : : WKT2_2015, //!< Full WKT2 string, conforming to ISO 19162:2015(E) / OGC 12-063r5 with all possible nodes and new keyword names.
675 : : WKT2_2015_SIMPLIFIED, //!< Same as WKT2_2015 with the following exceptions: UNIT keyword used. ID node only on top element. No ORDER element in AXIS element. PRIMEM node omitted if it is Greenwich. ELLIPSOID.UNIT node omitted if it is UnitOfMeasure::METRE. PARAMETER.UNIT / PRIMEM.UNIT omitted if same as AXIS. AXIS.UNIT omitted and replaced by a common GEODCRS.UNIT if they are all the same on all axis.
676 : : WKT2_2018, //!< Alias for WKT2_2019
677 : : WKT2_2018_SIMPLIFIED, //!< Alias for WKT2_2019_SIMPLIFIED
678 : : WKT2_2019 = WKT2_2018, //!< Full WKT2 string, conforming to ISO 19162:2019 / OGC 18-010, with all possible nodes and new keyword names. Non-normative list of differences: WKT2_2019 uses GEOGCRS / BASEGEOGCRS keywords for GeographicCRS.
679 : : WKT2_2019_SIMPLIFIED = WKT2_2018_SIMPLIFIED, //!< WKT2_2019 with the simplification rule of WKT2_SIMPLIFIED
680 : :
681 : : WKT_PREFERRED = WKT2_2019, //!< Preferred format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019, but may change in future versions.
682 : : WKT_PREFERRED_SIMPLIFIED = WKT2_2019_SIMPLIFIED, //!< Preferred simplified format, matching the most recent WKT ISO standard. Currently an alias to WKT2_2019_SIMPLIFIED, but may change in future versions.
683 : : WKT_PREFERRED_GDAL = WKT2_2019, //!< Preferred format for conversion of CRS to WKT for use with the GDAL library.
684 : : };
685 : :
686 : : /**
687 : : * Returns a WKT representation of this CRS.
688 : : *
689 : : * The \a variant argument specifies the formatting variant to use when creating the WKT string. This is
690 : : * only used on builds based on Proj >= 6, with earlier versions always using WKT1_GDAL.
691 : : *
692 : : * If \a multiline is TRUE then a formatted multiline string will be returned, using the specified \a indentationWidth.
693 : : * This is only used on builds based on Proj >= 6.
694 : : *
695 : : * \see toProj()
696 : : */
697 : : QString toWkt( WktVariant variant = WKT1_GDAL, bool multiline = false, int indentationWidth = 4 ) const;
698 : :
699 : : /**
700 : : * Returns a Proj string representation of this CRS.
701 : : *
702 : : * If proj and ellps keys are found in the parameters,
703 : : * they will be stripped out and the projection and ellipsoid acronyms will be
704 : : * overridden with these.
705 : : * \returns Proj format string that defines this CRS.
706 : : * \warning Not all CRS definitions can be represented by Proj strings. An empty
707 : : * string will be returned if the CRS could not be represented by a Proj string.
708 : : * \see toWkt()
709 : : * \deprecated QGIS 3.10 Use toProj() instead.
710 : : */
711 : : Q_DECL_DEPRECATED QString toProj4() const SIP_DEPRECATED;
712 : :
713 : : /**
714 : : * Returns a Proj string representation of this CRS.
715 : : *
716 : : * If proj and ellps keys are found in the parameters,
717 : : * they will be stripped out and the projection and ellipsoid acronyms will be
718 : : * overridden with these.
719 : : * \returns Proj format string that defines this CRS.
720 : : * \warning Not all CRS definitions can be represented by Proj strings. An empty
721 : : * string will be returned if the CRS could not be represented by a Proj string.
722 : : * \see toWkt()
723 : : * \since QGIS 3.10.3
724 : : */
725 : : QString toProj() const;
726 : :
727 : : /**
728 : : * Returns whether the CRS is a geographic CRS (using lat/lon coordinates)
729 : : * \returns TRUE if CRS is geographic, or FALSE if it is a projected CRS
730 : : */
731 : : bool isGeographic() const;
732 : :
733 : : /**
734 : : * Returns whether axis is inverted (e.g., for WMS 1.3) for the CRS.
735 : : * \returns TRUE if CRS axis is inverted
736 : : */
737 : : bool hasAxisInverted() const;
738 : :
739 : : /**
740 : : * Returns the units for the projection used by the CRS.
741 : : */
742 : : QgsUnitTypes::DistanceUnit mapUnits() const;
743 : :
744 : : /**
745 : : * Returns the approximate bounds for the region the CRS is usable within.
746 : : *
747 : : * The returned bounds represent the latitude and longitude extent for the
748 : : * projection in the WGS 84 CRS.
749 : : *
750 : : * \since QGIS 3.0
751 : : */
752 : : QgsRectangle bounds() const;
753 : :
754 : : // Mutators -----------------------------------
755 : :
756 : : /**
757 : : * Updates the definition and parameters of the coordinate reference system to their
758 : : * latest values.
759 : : *
760 : : * This only has an effect if the CRS is a user defined custom CRS, and the definition
761 : : * of that custom CRS has changed. In this case the parameters of the object (such as the
762 : : * proj and WKT string definitions, and other related properties) will be updated to
763 : : * reflect the current definition of the custom CRS.
764 : : *
765 : : * Any objects which store CRS objects should connect to the QgsApplication::coordinateReferenceSystemRegistry()'s
766 : : * QgsCoordinateReferenceSystemRegistry::userCrsChanged() signal and call this method
767 : : * on their stored CRS objects whenever the signal is emitted in order to update these
768 : : * CRSes to their new definitions.
769 : : *
770 : : * \since QGIS 3.18
771 : : */
772 : : void updateDefinition();
773 : :
774 : : /**
775 : : * Set user hint for validation
776 : : */
777 : : void setValidationHint( const QString &html );
778 : :
779 : : /**
780 : : * Gets user hint for validation
781 : : */
782 : : QString validationHint();
783 : :
784 : : /**
785 : : * Update proj.4 parameters in our database from proj.4
786 : : * \returns number of updated CRS on success and
787 : : * negative number of failed updates in case of errors.
788 : : * \note This is used internally and should not be necessary to call in client code
789 : : */
790 : : static int syncDatabase();
791 : :
792 : : /**
793 : : * Saves the CRS as a new custom ("USER") CRS.
794 : : *
795 : : * Returns the new CRS srsid(), or -1 if the CRS could not be saved.
796 : : *
797 : : * The \a nativeFormat argument specifies the format to use when saving the CRS
798 : : * definition. FormatWkt is recommended as it is a lossless format.
799 : : *
800 : : * \warning Not all CRS definitions can be represented as a Proj string, so
801 : : * take care when using the FormatProj option.
802 : : *
803 : : * \note Since QGIS 3.18, internally this calls QgsCoordinateReferenceSystemRegistry::addUserCrs().
804 : : */
805 : : long saveAsUserCrs( const QString &name, Format nativeFormat = FormatWkt );
806 : :
807 : : //! Returns auth id of related geographic CRS
808 : : QString geographicCrsAuthId() const;
809 : :
810 : : #ifdef SIP_RUN
811 : : SIP_PYOBJECT __repr__();
812 : : % MethodCode
813 : : const QString str = sipCpp->isValid() ? QStringLiteral( "<QgsCoordinateReferenceSystem: %1>" ).arg( !sipCpp->authid().isEmpty() ? sipCpp->authid() : sipCpp->toWkt( QgsCoordinateReferenceSystem::WKT_PREFERRED ) )
814 : : : QStringLiteral( "<QgsCoordinateReferenceSystem: invalid>" );
815 : : sipRes = PyUnicode_FromString( str.toUtf8().constData() );
816 : : % End
817 : : #endif
818 : :
819 : : #ifndef SIP_RUN
820 : :
821 : : /**
822 : : * Returns the underlying PROJ PJ object corresponding to the CRS, or NULLPTR
823 : : * if the CRS is invalid.
824 : : *
825 : : * This object is only valid for the lifetime of the QgsCoordinateReferenceSystem.
826 : : *
827 : : * \note Not available in Python bindings.
828 : : * \since QGIS 3.8
829 : : */
830 : : PJ *projObject() const;
831 : : #endif
832 : :
833 : : /**
834 : : * Returns a list of recently used projections
835 : : * \returns list of srsid for recently used projections
836 : : * \deprecated QGIS 3.10 Use recentCoordinateReferenceSystems() instead.
837 : : */
838 : : Q_DECL_DEPRECATED static QStringList recentProjections() SIP_DEPRECATED;
839 : :
840 : : /**
841 : : * Returns a list of recently used CRS.
842 : : * \since QGIS 3.10.3
843 : : */
844 : : static QList< QgsCoordinateReferenceSystem > recentCoordinateReferenceSystems();
845 : :
846 : : /**
847 : : * Pushes a recently used CRS to the top of the recent CRS list.
848 : : * \since QGIS 3.10.3
849 : : */
850 : : static void pushRecentCoordinateReferenceSystem( const QgsCoordinateReferenceSystem &crs );
851 : :
852 : : #ifndef SIP_RUN
853 : :
854 : : /**
855 : : * Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
856 : : * This should be called whenever the srs database has been modified in order to ensure
857 : : * that outdated CRS objects are not created.
858 : : *
859 : : * If \a disableCache is TRUE then the inbuilt cache will be completely disabled. This
860 : : * argument is for internal use only.
861 : : *
862 : : * \since QGIS 3.0
863 : : */
864 : : static void invalidateCache( bool disableCache = false );
865 : : #else
866 : :
867 : : /**
868 : : * Clears the internal cache used to initialize QgsCoordinateReferenceSystem objects.
869 : : * This should be called whenever the srs database has been modified in order to ensure
870 : : * that outdated CRS objects are not created.
871 : : *
872 : : * \since QGIS 3.0
873 : : */
874 : : static void invalidateCache( bool disableCache SIP_PYARGREMOVE = false );
875 : : #endif
876 : :
877 : : // Mutators -----------------------------------
878 : : // We don't want to expose these to the public api since they won't create
879 : : // a fully valid crs. Programmers should use the createFrom* methods rather
880 : : private:
881 : :
882 : : /**
883 : : * A static helper function to find out the proj string for a srsid
884 : : * \param srsId The srsid used for the lookup
885 : : * \returns QString The proj string
886 : : */
887 : : static QString projFromSrsId( int srsId );
888 : :
889 : : /**
890 : : * Set the Proj string.
891 : : * \param projString Proj format specifies
892 : : * (excluding proj and ellips) that define this CRS.
893 : : */
894 : : void setProjString( const QString &projString );
895 : :
896 : : /**
897 : : * Set the WKT string
898 : : */
899 : : bool setWktString( const QString &wkt );
900 : :
901 : : /**
902 : : * Print the description if debugging
903 : : */
904 : : void debugPrint();
905 : :
906 : : //! A string based associative array used for passing records around
907 : : typedef QMap<QString, QString> RecordMap;
908 : :
909 : : /**
910 : : * Gets a record from the srs.db or qgis.db backends, given an sql statement.
911 : : * \param sql The sql query to execute
912 : : * \returns An associative array of field name <-> value pairs
913 : : * \note only handles queries that return a single record.
914 : : * \note it will first try the system srs.db then the users qgis.db!
915 : : */
916 : : RecordMap getRecord( const QString &sql );
917 : :
918 : : /**
919 : : * Open SQLite db and show message if cannot be opened
920 : : * \returns the same code as sqlite3_open
921 : : */
922 : : static int openDatabase( const QString &path, sqlite3_database_unique_ptr &database, bool readonly = true );
923 : :
924 : : //! Work out the projection units and set the appropriate local variable
925 : : void setMapUnits();
926 : :
927 : : //! Helper for getting number of user CRS already in db
928 : : static long getRecordCount();
929 : :
930 : : bool loadFromAuthCode( const QString &auth, const QString &code );
931 : :
932 : : /**
933 : : * Returns a list of all users SRS IDs present in the CRS database.
934 : : */
935 : : static QList< long > userSrsIds();
936 : :
937 : : /**
938 : : * Tries to match the current definition of the CRS to user CRSes.
939 : : *
940 : : * Uses proj's equivalent testing API so that matches are tolerant to differences in
941 : : * parameter order and naming for proj or WKT strings (internally, uses the PJ_COMP_EQUIVALENT
942 : : * criteria).
943 : : */
944 : : long matchToUserCrs() const;
945 : :
946 : : /**
947 : : * Initialize the CRS object by looking up CRS database in path given in db argument,
948 : : * using first CRS entry where expression = 'value'
949 : : */
950 : : bool loadFromDatabase( const QString &db, const QString &expression, const QString &value );
951 : :
952 : : bool createFromWktInternal( const QString &wkt, const QString &description );
953 : :
954 : : QExplicitlySharedDataPointer<QgsCoordinateReferenceSystemPrivate> d;
955 : :
956 : : QString mValidationHint;
957 : :
958 : : friend class QgsProjContext;
959 : :
960 : : // Only meant to be called by QgsProjContext::~QgsProjContext()
961 : : static void removeFromCacheObjectsBelongingToCurrentThread( PJ_CONTEXT *pj_context );
962 : :
963 : : //! Function for CRS validation. May be NULLPTR.
964 : : static CUSTOM_CRS_VALIDATION sCustomSrsValidation;
965 : :
966 : : // cache
967 : :
968 : : static bool sDisableSrIdCache;
969 : : static bool sDisableOgcCache;
970 : : static bool sDisableProjCache;
971 : : static bool sDisableWktCache;
972 : : static bool sDisableSrsIdCache;
973 : : static bool sDisableStringCache;
974 : :
975 : : // for tests
976 : : static const QHash< QString, QgsCoordinateReferenceSystem > &stringCache();
977 : : static const QHash< QString, QgsCoordinateReferenceSystem > &projCache();
978 : : static const QHash< QString, QgsCoordinateReferenceSystem > &ogcCache();
979 : : static const QHash< QString, QgsCoordinateReferenceSystem > &wktCache();
980 : : static const QHash< long, QgsCoordinateReferenceSystem > &srsIdCache();
981 : : static const QHash< long, QgsCoordinateReferenceSystem > &srIdCache();
982 : :
983 : : friend class TestQgsCoordinateReferenceSystem;
984 : : friend class QgsPostgresProvider;
985 : : friend class QgsCoordinateReferenceSystemRegistry;
986 : : friend bool CORE_EXPORT operator> ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
987 : : friend bool CORE_EXPORT operator< ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
988 : : friend bool CORE_EXPORT operator>= ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
989 : : friend bool CORE_EXPORT operator<= ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
990 : :
991 : : bool createFromPostgisSrid( const long id );
992 : : };
993 : :
994 : 200 : Q_DECLARE_METATYPE( QgsCoordinateReferenceSystem )
995 : :
996 : : //! Output stream operator
997 : : #ifndef SIP_RUN
998 : : inline std::ostream &operator << ( std::ostream &os, const QgsCoordinateReferenceSystem &r )
999 : : {
1000 : : QString mySummary( QStringLiteral( "\n\tSpatial Reference System:" ) );
1001 : : mySummary += QLatin1String( "\n\t\tDescription : " );
1002 : : if ( !r.description().isNull() )
1003 : : {
1004 : : mySummary += r.description();
1005 : : }
1006 : : else
1007 : : {
1008 : : mySummary += QLatin1String( "Undefined" );
1009 : : }
1010 : : mySummary += QLatin1String( "\n\t\tProjection : " );
1011 : : if ( !r.projectionAcronym().isNull() )
1012 : : {
1013 : : mySummary += r.projectionAcronym();
1014 : : }
1015 : : else
1016 : : {
1017 : : mySummary += QLatin1String( "Undefined" );
1018 : : }
1019 : :
1020 : : mySummary += QLatin1String( "\n\t\tEllipsoid : " );
1021 : : if ( !r.ellipsoidAcronym().isNull() )
1022 : : {
1023 : : mySummary += r.ellipsoidAcronym();
1024 : : }
1025 : : else
1026 : : {
1027 : : mySummary += QLatin1String( "Undefined" );
1028 : : }
1029 : :
1030 : : mySummary += QLatin1String( "\n\t\tProjString : " );
1031 : : if ( !r.toProj().isNull() )
1032 : : {
1033 : : mySummary += r.toProj();
1034 : : }
1035 : : else
1036 : : {
1037 : : mySummary += QLatin1String( "Undefined" );
1038 : : }
1039 : : // Using streams we need to use local 8 Bit
1040 : : return os << mySummary.toLocal8Bit().data() << std::endl;
1041 : : }
1042 : :
1043 : : bool CORE_EXPORT operator> ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
1044 : : bool CORE_EXPORT operator< ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
1045 : : bool CORE_EXPORT operator>= ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
1046 : : bool CORE_EXPORT operator<= ( const QgsCoordinateReferenceSystem &c1, const QgsCoordinateReferenceSystem &c2 );
1047 : : #endif
1048 : :
1049 : : #endif // QGSCOORDINATEREFERENCESYSTEM_H
|