From c8d5c434020e825b9a941167dc98971e4e8d8b2c Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 17 Dec 2019 11:14:56 +1000 Subject: [PATCH] Don't equate a BoundCRS with an identified SourceCRS as the SourceCRS when identifying CRSes May result in some CRSes which were previously identified as known standard CRSes now being shown as User CRSes, but they aren't the same to we can't equate them. If previously identified CRSes are showing as User CRSes now, then we should investigate these upstream in the proj or gdal libraries, and get all fixes in place upstream rather then trying to do this in QGIS code (which is inevitably going to end up with an unmaintainable mess) --- src/core/qgsprojutils.cpp | 15 ++++++++-- .../core/testqgscoordinatereferencesystem.cpp | 30 ++++++++++++++++++- 2 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/core/qgsprojutils.cpp b/src/core/qgsprojutils.cpp index c2ea6d26163..0696b2b191e 100644 --- a/src/core/qgsprojutils.cpp +++ b/src/core/qgsprojutils.cpp @@ -204,11 +204,22 @@ bool QgsProjUtils::identifyCrs( const PJ *crs, QString &authName, QString &authC { if ( confidence[i] >= bestConfidence ) { - // prefer EPSG codes for compatibility with earlier qgis conversions QgsProjUtils::proj_pj_unique_ptr candidateCrs( proj_list_get( QgsProjContext::get(), crsList, i ) ); + switch ( proj_get_type( candidateCrs.get() ) ) + { + case PJ_TYPE_BOUND_CRS: + // proj_identify also matches bound CRSes to the source CRS. But they are not the same as the source CRS, so we don't + // consider them a candidate for a match here + continue; + + default: + break; + } + candidateCrs = QgsProjUtils::crsToSingleCrs( candidateCrs.get() ); const QString authName( proj_get_id_auth_name( candidateCrs.get(), 0 ) ); - if ( confidence[i] > bestConfidence || authName == QLatin1String( "EPSG" ) ) + // if a match is identical confidence, we prefer EPSG codes for compatibility with earlier qgis conversions + if ( confidence[i] > bestConfidence || ( confidence[i] == bestConfidence && authName == QLatin1String( "EPSG" ) ) ) { bestConfidence = confidence[i]; matchedCrs = std::move( candidateCrs ); diff --git a/tests/src/core/testqgscoordinatereferencesystem.cpp b/tests/src/core/testqgscoordinatereferencesystem.cpp index 1f0b9634159..14b7fe017b6 100644 --- a/tests/src/core/testqgscoordinatereferencesystem.cpp +++ b/tests/src/core/testqgscoordinatereferencesystem.cpp @@ -51,7 +51,6 @@ class TestQgsCoordinateReferenceSystem: public QObject void createFromSrid(); void sridCache(); void createFromWkt(); - void createFromWktWithIdentify(); void createFromWktUnknown(); void fromWkt(); void wktCache(); @@ -92,6 +91,8 @@ class TestQgsCoordinateReferenceSystem: public QObject void customProjString(); void recentProjections(); void displayIdentifier(); + void createFromWktWithIdentify(); + void fromProj4EPSG20936(); private: void debugPrint( QgsCoordinateReferenceSystem &crs ); @@ -407,14 +408,41 @@ void TestQgsCoordinateReferenceSystem::createFromWktWithIdentify() #if PROJ_VERSION_MAJOR>=6 QgsCoordinateReferenceSystem crs; // see https://github.com/qgis/QGIS/issues/33007, WKT string from a MapInfo tabfile in GDA2020 projection + + // currently GDAL gives this BoundCRS WKT, but that's an issue in GDAL -- see https://github.com/OSGeo/PROJ/issues/1752 crs.createFromWkt( QStringLiteral( "BOUNDCRS[SOURCECRS[PROJCRS[\"unnamed\",BASEGEOGCRS[\"unnamed\",DATUM[\"Geocentric Datum of Australia 2020\",ELLIPSOID[\"GRS 80\",6378137,298.257222101,LENGTHUNIT[\"metre\",1,ID[\"EPSG\",9001]]]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433,ID[\"EPSG\",9122]]]],CONVERSION[\"UTM zone 55S\",METHOD[\"Transverse Mercator\",ID[\"EPSG\",9807]],PARAMETER[\"Latitude of natural origin\",0,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8801]],PARAMETER[\"Longitude of natural origin\",147,ANGLEUNIT[\"degree\",0.0174532925199433],ID[\"EPSG\",8802]],PARAMETER[\"Scale factor at natural origin\",0.9996,SCALEUNIT[\"unity\",1],ID[\"EPSG\",8805]],PARAMETER[\"False easting\",500000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8806]],PARAMETER[\"False northing\",10000000,LENGTHUNIT[\"metre\",1],ID[\"EPSG\",8807]],ID[\"EPSG\",17055]],CS[Cartesian,2],AXIS[\"easting\",east,ORDER[1],LENGTHUNIT[\"metre\",1,ID[\"EPSG\",9001]]],AXIS[\"northing\",north,ORDER[2],LENGTHUNIT[\"metre\",1,ID[\"EPSG\",9001]]]]],TARGETCRS[GEOGCRS[\"WGS 84\",DATUM[\"World Geodetic System 1984\",ELLIPSOID[\"WGS 84\",6378137,298.257223563,LENGTHUNIT[\"metre\",1]]],PRIMEM[\"Greenwich\",0,ANGLEUNIT[\"degree\",0.0174532925199433]],CS[ellipsoidal,2],AXIS[\"geodetic latitude (Lat)\",north,ORDER[1],ANGLEUNIT[\"degree\",0.0174532925199433]],AXIS[\"geodetic longitude (Lon)\",east,ORDER[2],ANGLEUNIT[\"degree\",0.0174532925199433]],USAGE[SCOPE[\"unknown\"],AREA[\"World\"],BBOX[-90,-180,90,180]],ID[\"EPSG\",4326]]],ABRIDGEDTRANSFORMATION[\"Transformation to WGS84\",METHOD[\"Position Vector transformation (geog2D domain)\",ID[\"EPSG\",9606]],PARAMETER[\"X-axis translation\",-0.06155,ID[\"EPSG\",8605]],PARAMETER[\"Y-axis translation\",0.01087,ID[\"EPSG\",8606]],PARAMETER[\"Z-axis translation\",0.04019,ID[\"EPSG\",8607]],PARAMETER[\"X-axis rotation\",-0.0394924,ID[\"EPSG\",8608]],PARAMETER[\"Y-axis rotation\",-0.0327221,ID[\"EPSG\",8609]],PARAMETER[\"Z-axis rotation\",-0.0328979,ID[\"EPSG\",8610]],PARAMETER[\"Scale difference\",1.000000009994,ID[\"EPSG\",8611]]]]" ) ); QVERIFY( crs.isValid() ); + // this must be a user CRS -- it's a boundcrs of EPSG:7855, not EPSG:7855 itself + QCOMPARE( crs.authid(), QStringLiteral( "USER:100010" ) ); + QCOMPARE( crs.ellipsoidAcronym(), QStringLiteral( "PARAMETER:6378137:6356752.31414035614579916" ) ); + + // here's the correct (desirable) WKT we should get from GDAL + crs.createFromWkt( QStringLiteral( "PROJCS[\"unnamed\",GEOGCS[\"unnamed\",DATUM[\"Geocentric_Datum_of_Australia_2020\",SPHEROID[\"GRS 80\",6378137,298.257222101]],PRIMEM[\"Greenwich\",0],UNIT[\"degree\",0.0174532925199433,AUTHORITY[\"EPSG\",\"9122\"]]],PROJECTION[\"Transverse_Mercator\"],PARAMETER[\"latitude_of_origin\",0],PARAMETER[\"central_meridian\",147],PARAMETER[\"scale_factor\",0.9996],PARAMETER[\"false_easting\",500000],PARAMETER[\"false_northing\",10000000],UNIT[\"metre\",1,AUTHORITY[\"EPSG\",\"9001\"]],AXIS[\"Easting\",EAST],AXIS[\"Northing\",NORTH]]" ) ); + QVERIFY( crs.isValid() ); QCOMPARE( crs.authid(), QStringLiteral( "EPSG:7855" ) ); QCOMPARE( crs.ellipsoidAcronym(), QStringLiteral( "EPSG:7019" ) ); #endif } +void TestQgsCoordinateReferenceSystem::fromProj4EPSG20936() +{ +#if PROJ_VERSION_MAJOR>=6 + QgsCoordinateReferenceSystem crs = QgsCoordinateReferenceSystem::fromProj4( QStringLiteral( "+proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" ) ); + QVERIFY( crs.isValid() ); + QCOMPARE( crs.toWkt(), QStringLiteral( R"""(PROJCS["unknown",GEOGCS["unknown",DATUM["unknown",SPHEROID["unknown",6378249.145,293.466307699995],TOWGS84[-143,-90,-294,0,0,0,0]],PRIMEM["Greenwich",0,AUTHORITY["EPSG","8901"]],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Transverse_Mercator"],PARAMETER["latitude_of_origin",0],PARAMETER["central_meridian",33],PARAMETER["scale_factor",0.9996],PARAMETER["false_easting",500000],PARAMETER["false_northing",10000000],UNIT["metre",1,AUTHORITY["EPSG","9001"]],AXIS["Easting",EAST],AXIS["Northing",NORTH]])""" ) ); + QCOMPARE( crs.toProj4(), QStringLiteral( "+proj=utm +zone=36 +south +a=6378249.145 +b=6356514.966398753 +towgs84=-143,-90,-294,0,0,0,0 +units=m +no_defs" ) ); + + // should ideally be EPSG:20936, but see https://github.com/OSGeo/PROJ/issues/1805 + // so instead we get a BoundCRS of EPSG:20936 created from the proj string, which must be a user CRS (not EPSG:20936 itself!) +#if 0 + QCOMPARE( crs.authid(), QStringLiteral( "EPSG:20936" ) ); +#endif + + QCOMPARE( crs.ellipsoidAcronym(), QStringLiteral( "EPSG:7013" ) ); +#endif +} + void TestQgsCoordinateReferenceSystem::createFromWktUnknown() { QgsCoordinateReferenceSystem crs;