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