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