diff --git a/src/iso19111/operation/conversion.cpp b/src/iso19111/operation/conversion.cpp index b9dc20c404..60a8eaf990 100644 --- a/src/iso19111/operation/conversion.cpp +++ b/src/iso19111/operation/conversion.cpp @@ -3259,8 +3259,8 @@ const char *Conversion::getWKT1GDALMethodName() const { void Conversion::_exportToWKT(io::WKTFormatter *formatter) const { const auto &l_method = method(); - const auto &methodName = l_method->nameStr(); - const auto methodEPSGCode = l_method->getEPSGCode(); + std::string methodName = l_method->nameStr(); + auto methodEPSGCode = l_method->getEPSGCode(); const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2; if (!isWKT2 && formatter->useESRIDialect()) { @@ -3298,6 +3298,29 @@ void Conversion::_exportToWKT(io::WKTFormatter *formatter) const { #endif bool bAlreadyWritten = false; + + bool methodWritten = false; + + const MethodMapping *mapping = !isWKT2 && !formatter->useESRIDialect() + ? getMapping(l_method.get()) + : nullptr; + + if (!isWKT2 && methodEPSGCode == EPSG_CODE_METHOD_MERCATOR_SPHERICAL) { + auto projCRS = + dynamic_cast(targetCRS().get()); + if (projCRS && projCRS->baseCRS()->ellipsoid()->isSphere()) { + methodName = EPSG_NAME_METHOD_MERCATOR_VARIANT_A; + methodEPSGCode = EPSG_CODE_METHOD_MERCATOR_VARIANT_A; + if (!formatter->useESRIDialect()) { + methodWritten = true; + formatter->startNode(io::WKTConstants::PROJECTION, false); + formatter->addQuotedString("Mercator_1SP"); + formatter->endNode(); + mapping = getMapping(methodEPSGCode); + } + } + } + if (!isWKT2 && formatter->useESRIDialect()) { const ESRIParamMapping *esriParams = nullptr; const char *esriMethodName = nullptr; @@ -3404,10 +3427,18 @@ void Conversion::_exportToWKT(io::WKTFormatter *formatter) const { } if (!bAlreadyWritten) { - l_method->_exportToWKT(formatter); + if (!methodWritten) { + l_method->_exportToWKT(formatter); + } + + if (!isWKT2 && methodEPSGCode == EPSG_CODE_METHOD_MERCATOR_VARIANT_A && + parameterValueNumericAsSI( + EPSG_CODE_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN) != 0.0) { + throw io::FormattingException( + std::string("Unsupported value for ") + + EPSG_NAME_PARAMETER_LATITUDE_OF_NATURAL_ORIGIN); + } - const MethodMapping *mapping = - !isWKT2 ? getMapping(l_method.get()) : nullptr; bool hasInterpolationCRSParameter = false; for (const auto &genOpParamvalue : parameterValues()) { const auto opParamvalue = diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 62197ded64..3bf6f5aa07 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -1305,6 +1305,111 @@ TEST(crs, EPSG_5482_projected_south_pole_south_west) { // --------------------------------------------------------------------------- +TEST(crs, spherical_mercator_on_sphere_to_WKT1) { + auto dbContext = DatabaseContext::create(); + auto obj = WKTParser().attachDatabaseContext(dbContext).createFromWKT( + "PROJCRS[\"Moon (2015) - Sphere / Ocentric / Mercator\",\n" + " BASEGEOGCRS[\"Moon (2015) - Sphere / Ocentric\",\n" + " DATUM[\"Moon (2015) - Sphere\",\n" + " ELLIPSOID[\"Moon (2015) - Sphere\",1737400,0,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Reference Meridian\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"IAU\",30100,2015]],\n" + " CONVERSION[\"Mercator\",\n" + " METHOD[\"Mercator (Spherical)\",\n" + " ID[\"EPSG\",1026]],\n" + " PARAMETER[\"Latitude of natural origin\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8801]],\n" + " PARAMETER[\"Longitude of natural origin\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8802]],\n" + " PARAMETER[\"False easting\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8806]],\n" + " PARAMETER[\"False northing\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8807]]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east,\n" + " ORDER[1],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " AXIS[\"(N)\",north,\n" + " ORDER[2],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"IAU\",30190,2015]]"); + auto crs = nn_dynamic_pointer_cast(obj); + ASSERT_TRUE(crs != nullptr); + + auto wkt1 = crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL, dbContext) + .get()); + EXPECT_EQ(wkt1, + "PROJCS[\"Moon (2015) - Sphere / Ocentric / Mercator\",\n" + " GEOGCS[\"Moon (2015) - Sphere / Ocentric\",\n" + " DATUM[\"Moon (2015) - Sphere\",\n" + " SPHEROID[\"Moon (2015) - Sphere\",1737400,0]],\n" + " PRIMEM[\"Reference Meridian\",0],\n" + " UNIT[\"degree\",0.0174532925199433,\n" + " AUTHORITY[\"EPSG\",\"9122\"]],\n" + " AUTHORITY[\"IAU\",\"30100\"]],\n" + " PROJECTION[\"Mercator_1SP\"],\n" + " PARAMETER[\"central_meridian\",0],\n" + " PARAMETER[\"false_easting\",0],\n" + " PARAMETER[\"false_northing\",0],\n" + " UNIT[\"metre\",1],\n" + " AXIS[\"Easting\",EAST],\n" + " AXIS[\"Northing\",NORTH],\n" + " AUTHORITY[\"IAU\",\"30190\"]]"); +} + +// --------------------------------------------------------------------------- + +TEST(crs, mercator_variant_A_lat0_non_zero_to_WKT1) { + auto obj = WKTParser().createFromWKT( + "PROJCRS[\"test\",\n" + " BASEGEOGCRS[\"Moon (2015) - Sphere / Ocentric\",\n" + " DATUM[\"Moon (2015) - Sphere\",\n" + " ELLIPSOID[\"Moon (2015) - Sphere\",1737400,0,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Reference Meridian\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"IAU\",30100,2015]],\n" + " CONVERSION[\"Mercator\",\n" + " METHOD[\"Mercator (Spherical)\",\n" + " ID[\"EPSG\",1026]],\n" + " PARAMETER[\"Latitude of natural origin\",10,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8801]],\n" + " PARAMETER[\"Longitude of natural origin\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433],\n" + " ID[\"EPSG\",8802]],\n" + " PARAMETER[\"False easting\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8806]],\n" + " PARAMETER[\"False northing\",0,\n" + " LENGTHUNIT[\"metre\",1],\n" + " ID[\"EPSG\",8807]]],\n" + " CS[Cartesian,2],\n" + " AXIS[\"(E)\",east,\n" + " ORDER[1],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " AXIS[\"(N)\",north,\n" + " ORDER[2],\n" + " LENGTHUNIT[\"metre\",1]],\n" + " ID[\"IAU\",30190,2015]]"); + auto crs = nn_dynamic_pointer_cast(obj); + ASSERT_TRUE(crs != nullptr); + + EXPECT_THROW(crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT1_GDAL, + DatabaseContext::create()) + .get()), + FormattingException); +} +// --------------------------------------------------------------------------- + TEST(crs, geodetic_crs_both_datum_datum_ensemble_null) { EXPECT_THROW(GeodeticCRS::create( PropertyMap(), nullptr, nullptr,