diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2022-02-14 20:00:25 +0100 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2022-02-14 20:00:25 +0100 |
| commit | df9e2fe519d97139a8264057d96b034788e8e8e7 (patch) | |
| tree | 0ac30dd48e217392fcf1b3937e025adaa81b9730 | |
| parent | f67c82912fde55a58d565697263306c840b3efd4 (diff) | |
| download | PROJ-df9e2fe519d97139a8264057d96b034788e8e8e7.tar.gz PROJ-df9e2fe519d97139a8264057d96b034788e8e8e7.zip | |
Better deal with importing strings like '+init=epsg:XXXX +over' (refs MapServer/MapServer#6478)
| -rw-r--r-- | include/proj/crs.hpp | 2 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 42 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 10 | ||||
| -rw-r--r-- | src/iso19111/operation/conversion.cpp | 6 | ||||
| -rw-r--r-- | src/iso19111/operation/coordinateoperationfactory.cpp | 3 | ||||
| -rw-r--r-- | test/unit/test_c_api.cpp | 38 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 4 |
7 files changed, 91 insertions, 14 deletions
diff --git a/include/proj/crs.hpp b/include/proj/crs.hpp index ce950c47..593bfc4b 100644 --- a/include/proj/crs.hpp +++ b/include/proj/crs.hpp @@ -158,6 +158,8 @@ class PROJ_GCC_DLL CRS : public common::ObjectUsage, PROJ_INTERNAL bool hasImplicitCS() const; + PROJ_INTERNAL bool hasOver() const; + PROJ_INTERNAL static CRSNNPtr getResolvedCRS(const CRSNNPtr &crs, const io::AuthorityFactoryPtr &authFactory, diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 2ea8393c..4750896a 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -98,20 +98,36 @@ struct CRS::Private { BoundCRSPtr canonicalBoundCRS_{}; std::string extensionProj4_{}; bool implicitCS_ = false; + bool over_ = false; bool allowNonConformantWKT1Export_ = false; // for what was initially a COMPD_CS with a VERT_CS with a datum type == // ellipsoidal height / 2002 CompoundCRSPtr originalCompoundCRS_{}; - void setImplicitCS(const util::PropertyMap &properties) { - const auto pVal = properties.get("IMPLICIT_CS"); - if (pVal) { - if (const auto genVal = - dynamic_cast<const util::BoxedValue *>(pVal->get())) { - if (genVal->type() == util::BoxedValue::Type::BOOLEAN && - genVal->booleanValue()) { - implicitCS_ = true; + void setNonStandardProperties(const util::PropertyMap &properties) { + { + const auto pVal = properties.get("IMPLICIT_CS"); + if (pVal) { + if (const auto genVal = + dynamic_cast<const util::BoxedValue *>(pVal->get())) { + if (genVal->type() == util::BoxedValue::Type::BOOLEAN && + genVal->booleanValue()) { + implicitCS_ = true; + } + } + } + } + + { + const auto pVal = properties.get("OVER"); + if (pVal) { + if (const auto genVal = + dynamic_cast<const util::BoxedValue *>(pVal->get())) { + if (genVal->type() == util::BoxedValue::Type::BOOLEAN && + genVal->booleanValue()) { + over_ = true; + } } } } @@ -142,6 +158,9 @@ CRS::~CRS() = default; * (e.g from ESRI WKT) */ bool CRS::hasImplicitCS() const { return d->implicitCS_; } +/** \brief Return whether the CRS has a +over flag */ +bool CRS::hasOver() const { return d->over_; } + //! @endcond // --------------------------------------------------------------------------- @@ -2854,7 +2873,7 @@ GeographicCRS::create(const util::PropertyMap &properties, GeographicCRS::nn_make_shared<GeographicCRS>(datum, datumEnsemble, cs)); crs->assignSelf(crs); crs->setProperties(properties); - crs->CRS::getPrivate()->setImplicitCS(properties); + crs->CRS::getPrivate()->setNonStandardProperties(properties); return crs; } @@ -3122,6 +3141,9 @@ void GeographicCRS::_exportToPROJString( if (!formatter->getCRSExport()) { addAngularUnitConvertAndAxisSwap(formatter); } + if (hasOver()) { + formatter->addParam("over"); + } } //! @endcond @@ -4298,7 +4320,7 @@ ProjectedCRS::create(const util::PropertyMap &properties, crs->assignSelf(crs); crs->setProperties(properties); crs->setDerivingConversionCRS(); - crs->CRS::getPrivate()->setImplicitCS(properties); + crs->CRS::getPrivate()->setNonStandardProperties(properties); return crs; } diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index a7fedb91..f047ef3e 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -10489,9 +10489,12 @@ PROJStringParser::createFromPROJString(const std::string &projString) { auto crs = dynamic_cast<CRS *>(obj.get()); bool hasSignificantParamValues = false; + bool hasOver = false; for (const auto &kv : d->steps_[0].paramValues) { - if (!((kv.key == "type" && kv.value == "crs") || - kv.key == "wktext" || kv.key == "no_defs")) { + if (kv.key == "over") { + hasOver = true; + } else if (!((kv.key == "type" && kv.value == "crs") || + kv.key == "wktext" || kv.key == "no_defs")) { hasSignificantParamValues = true; break; } @@ -10502,6 +10505,9 @@ PROJStringParser::createFromPROJString(const std::string &projString) { properties.set(IdentifiedObject::NAME_KEY, d->title_.empty() ? crs->nameStr() : d->title_); + if (hasOver) { + properties.set("OVER", true); + } const auto &extent = getExtent(crs); if (extent) { properties.set( diff --git a/src/iso19111/operation/conversion.cpp b/src/iso19111/operation/conversion.cpp index 21052a07..39c21439 100644 --- a/src/iso19111/operation/conversion.cpp +++ b/src/iso19111/operation/conversion.cpp @@ -3320,6 +3320,9 @@ static bool createPROJ4WebMercator(const Conversion *conv, formatter->addParam("k", 1.0); formatter->addParam("units", units); formatter->addParam("nadgrids", "@null"); + if (targetProjCRS && targetProjCRS->hasOver()) { + formatter->addParam("over"); + } formatter->addParam("wktext"); formatter->addParam("no_defs"); return true; @@ -4095,6 +4098,9 @@ void Conversion::_exportToPROJString( formatter->pushOmitZUnitConversion(); projCRS->addUnitConvertAndAxisSwap(formatter, bAxisSpecFound); formatter->popOmitZUnitConversion(); + if (projCRS->hasOver()) { + formatter->addParam("over"); + } } auto derivedGeographicCRS = diff --git a/src/iso19111/operation/coordinateoperationfactory.cpp b/src/iso19111/operation/coordinateoperationfactory.cpp index e13d4071..6b7d4d20 100644 --- a/src/iso19111/operation/coordinateoperationfactory.cpp +++ b/src/iso19111/operation/coordinateoperationfactory.cpp @@ -5645,6 +5645,9 @@ namespace crs { crs::CRSNNPtr CRS::getResolvedCRS(const crs::CRSNNPtr &crs, const io::AuthorityFactoryPtr &authFactory, metadata::ExtentPtr &extentOut) { + if (crs->hasOver()) { + return crs; + } const auto &ids = crs->identifiers(); const auto &name = crs->nameStr(); diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 3e6ef1ab..ecbb2999 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -5392,6 +5392,44 @@ TEST_F(CApi, use_proj4_init_rules) { PJ_CONTEXT *ctx = proj_context_create(); proj_context_use_proj4_init_rules(ctx, true); ASSERT_TRUE(proj_context_get_use_proj4_init_rules(ctx, true)); + + { + // Test +over + auto crs = proj_create(ctx, "+init=epsg:28992 +over"); + ObjectKeeper keeper_crs(crs); + ASSERT_NE(crs, nullptr); + + auto datum = proj_crs_get_datum(ctx, crs); + ASSERT_NE(datum, nullptr); + ObjectKeeper keeper_datum(datum); + + auto datum_name = proj_get_name(datum); + ASSERT_TRUE(datum_name != nullptr); + EXPECT_EQ(datum_name, std::string("Amersfoort")); + + auto proj_5 = proj_as_proj_string(ctx, crs, PJ_PROJ_5, nullptr); + ASSERT_NE(proj_5, nullptr); + EXPECT_EQ(std::string(proj_5), + "+proj=sterea +lat_0=52.1561605555556 " + "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 " + "+y_0=463000 +ellps=bessel +units=m +over " + "+no_defs +type=crs"); + } + + { + // Test +over on epsg:3857 + auto crs = proj_create(ctx, "+init=epsg:3857 +over"); + ObjectKeeper keeper_crs(crs); + ASSERT_NE(crs, nullptr); + + auto proj_5 = proj_as_proj_string(ctx, crs, PJ_PROJ_5, nullptr); + ASSERT_NE(proj_5, nullptr); + EXPECT_EQ(std::string(proj_5), + "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 " + "+y_0=0 +k=1 +units=m +nadgrids=@null +over +wktext " + "+no_defs +type=crs"); + } + proj_context_use_proj4_init_rules(ctx, false); ASSERT_TRUE(!proj_context_get_use_proj4_init_rules(ctx, true)); proj_context_destroy(ctx); diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 1c7fc812..33f4c731 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -10531,13 +10531,13 @@ TEST(io, projparse_init) { } { - auto obj = createFromUserInput("+title=mytitle +over +init=epsg:4326", + auto obj = createFromUserInput("+title=mytitle +init=epsg:4326 +over", dbContext, true); auto crs = nn_dynamic_pointer_cast<GeographicCRS>(obj); ASSERT_TRUE(crs != nullptr); EXPECT_EQ(crs->nameStr(), "mytitle"); EXPECT_EQ(crs->exportToPROJString(PROJStringFormatter::create().get()), - "+proj=longlat +over +datum=WGS84 +no_defs +type=crs"); + "+proj=longlat +datum=WGS84 +over +no_defs +type=crs"); } { |
