diff options
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 20 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 33 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 61 |
3 files changed, 100 insertions, 14 deletions
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 4b174636..ab954ee2 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -5825,6 +5825,24 @@ static bool createPROJ4WebMercator(const Conversion *conv, return false; } + std::string units("m"); + auto targetCRS = conv->targetCRS(); + auto targetProjCRS = + dynamic_cast<const crs::ProjectedCRS *>(targetCRS.get()); + if (targetProjCRS) { + const auto &axisList = targetProjCRS->coordinateSystem()->axisList(); + const auto &unit = axisList[0]->unit(); + if (!unit._isEquivalentTo(common::UnitOfMeasure::METRE, + util::IComparable::Criterion::EQUIVALENT)) { + auto projUnit = unit.exportToPROJString(); + if (!projUnit.empty()) { + units = projUnit; + } else { + return false; + } + } + } + formatter->addStep("merc"); const double a = geogCRS->ellipsoid()->semiMajorAxis().getSIValue(); formatter->addParam("a", a); @@ -5834,7 +5852,7 @@ static bool createPROJ4WebMercator(const Conversion *conv, formatter->addParam("x_0", falseEasting); formatter->addParam("y_0", falseNorthing); formatter->addParam("k", 1.0); - formatter->addParam("units", "m"); + formatter->addParam("units", units); formatter->addParam("nadgrids", "@null"); formatter->addParam("wktext"); formatter->addParam("no_defs"); diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 59116ad6..3a7be2b0 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -3696,13 +3696,13 @@ ConversionNNPtr WKTParser::Private::buildProjectionStandard( // --------------------------------------------------------------------------- -static ProjectedCRSNNPtr createPseudoMercator(const PropertyMap &props) { +static ProjectedCRSNNPtr createPseudoMercator(const PropertyMap &props, + const cs::CartesianCSNNPtr &cs) { auto conversion = Conversion::createPopularVisualisationPseudoMercator( PropertyMap().set(IdentifiedObject::NAME_KEY, "unnamed"), Angle(0), Angle(0), Length(0), Length(0)); - return ProjectedCRS::create( - props, GeographicCRS::EPSG_4326, conversion, - CartesianCS::createEastingNorthing(UnitOfMeasure::METRE)); + return ProjectedCRS::create(props, GeographicCRS::EPSG_4326, conversion, + cs); } // --------------------------------------------------------------------------- @@ -3783,21 +3783,22 @@ WKTParser::Private::buildProjectedCRS(const WKTNodeNNPtr &node) { } } - if (isNull(conversionNode) && hasWebMercPROJ4String(node, projectionNode)) { + if (isNull(conversionNode) && hasWebMercPROJ4String(node, projectionNode) && + cartesianCS) { toWGS84Parameters_.clear(); - return createPseudoMercator(props); + return createPseudoMercator(props, NN_NO_CHECK(cartesianCS)); } // WGS_84_Pseudo_Mercator: Particular case for corrupted ESRI WKT generated // by older GDAL versions // https://trac.osgeo.org/gdal/changeset/30732 // WGS_1984_Web_Mercator: deprecated ESRI:102113 - if (metadata::Identifier::isEquivalentName(projCRSName.c_str(), - "WGS_84_Pseudo_Mercator") || - metadata::Identifier::isEquivalentName(projCRSName.c_str(), - "WGS_1984_Web_Mercator")) { + if (cartesianCS && (metadata::Identifier::isEquivalentName( + projCRSName.c_str(), "WGS_84_Pseudo_Mercator") || + metadata::Identifier::isEquivalentName( + projCRSName.c_str(), "WGS_1984_Web_Mercator"))) { toWGS84Parameters_.clear(); - return createPseudoMercator(props); + return createPseudoMercator(props, NN_NO_CHECK(cartesianCS)); } auto linearUnit = buildUnitInSubNode(node, UnitOfMeasure::Type::LINEAR); @@ -8740,6 +8741,7 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( auto axisType = AxisType::REGULAR; bool bWebMercator = false; + std::string webMercatorName("WGS 84 / Pseudo-Mercator"); if (step.name == "tmerc" && ((getParamValue(step, "axis") == "wsu" && iAxisSwap < 0) || @@ -8828,6 +8830,11 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( getAngularValue(getParamValue(step, "x_0")) == 0.0 && getAngularValue(getParamValue(step, "y_0")) == 0.0) { bWebMercator = true; + if (hasParamValue(step, "units") && + getParamValue(step, "units") != "m") { + webMercatorName += + " (unit " + getParamValue(step, "units") + ')'; + } } } else if (hasParamValue(step, "lat_ts")) { mapping = getMapping(EPSG_CODE_METHOD_MERCATOR_VARIANT_B); @@ -9111,8 +9118,8 @@ CRSNNPtr PROJStringParser::Private::buildProjectedCRS( CRSNNPtr crs = bWebMercator - ? createPseudoMercator(props.set(IdentifiedObject::NAME_KEY, - "WGS 84 / Pseudo-Mercator")) + ? createPseudoMercator( + props.set(IdentifiedObject::NAME_KEY, webMercatorName), cs) : ProjectedCRS::create(props, geogCRS, NN_NO_CHECK(conv), cs); if (!hasParamValue(step, "geoidgrids") && diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 54827046..1c69bb05 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -8511,6 +8511,67 @@ TEST(io, projparse_merc_google_mercator) { // --------------------------------------------------------------------------- +TEST(io, projparse_merc_google_mercator_non_metre_unit) { + auto projString = + "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 " + "+k=1 +units=ft +nadgrids=@null +no_defs +type=crs"; + auto obj = PROJStringParser().createFromPROJString(projString); + auto crs = nn_dynamic_pointer_cast<ProjectedCRS>(obj); + ASSERT_TRUE(crs != nullptr); + EXPECT_EQ(crs->nameStr(), "WGS 84 / Pseudo-Mercator (unit ft)"); + EXPECT_EQ(crs->derivingConversion()->method()->nameStr(), + "Popular Visualisation Pseudo Mercator"); + EXPECT_EQ( + replaceAll(crs->exportToPROJString(PROJStringFormatter::create().get()), + " +wktext", ""), + projString); + + auto wkt = crs->exportToWKT( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2019).get()); + auto expected_wkt = + "PROJCRS[\"WGS 84 / Pseudo-Mercator (unit ft)\",\n" + " BASEGEOGCRS[\"WGS 84\",\n" + " DATUM[\"World Geodetic System 1984\",\n" + " ELLIPSOID[\"WGS 84\",6378137,298.257223563,\n" + " LENGTHUNIT[\"metre\",1]]],\n" + " PRIMEM[\"Greenwich\",0,\n" + " ANGLEUNIT[\"degree\",0.0174532925199433]],\n" + " ID[\"EPSG\",4326]],\n" + " CONVERSION[\"unnamed\",\n" + " METHOD[\"Popular Visualisation Pseudo Mercator\",\n" + " ID[\"EPSG\",1024]],\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[\"foot\",0.3048,\n" + " ID[\"EPSG\",9002]]],\n" + " AXIS[\"(N)\",north,\n" + " ORDER[2],\n" + " LENGTHUNIT[\"foot\",0.3048,\n" + " ID[\"EPSG\",9002]]]]"; + EXPECT_EQ(wkt, expected_wkt); + + auto objFromWkt = WKTParser().createFromWKT(wkt); + auto crsFromWkt = nn_dynamic_pointer_cast<ProjectedCRS>(objFromWkt); + ASSERT_TRUE(crsFromWkt != nullptr); + EXPECT_TRUE(crs->isEquivalentTo(crsFromWkt.get(), + IComparable::Criterion::EQUIVALENT)); +} + +// --------------------------------------------------------------------------- + TEST(io, projparse_merc_not_quite_google_mercator) { auto projString = "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=10 +x_0=0 +y_0=0 " |
