From bb770de3b7cb04aad8116ed84a5815b7f6f7a82c Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 3 Apr 2020 19:41:23 +0200 Subject: createFromUserInput(): allow compound CRS with the 2 parts given by names, e.g. 'WGS 84 + EGM96 height' --- src/iso19111/c_api.cpp | 4 +- src/iso19111/io.cpp | 107 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 89 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index 17fbd079..5a3f0374 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -427,7 +427,9 @@ PJ *proj_clone(PJ_CONTEXT *ctx, const PJ *obj) { /** \brief Instantiate an object from a WKT string, PROJ string, object code * (like "EPSG:4326", "urn:ogc:def:crs:EPSG::4326", - * "urn:ogc:def:coordinateOperation:EPSG::1671") or PROJJSON string. + * "urn:ogc:def:coordinateOperation:EPSG::1671"), a PROJJSON string, an object + * name (e.g "WGS 84") of a compound CRS build from object names + * (e.g "WGS 84 + EGM96 height") * * This function calls osgeo::proj::io::createFromUserInput() * diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 8bfb4395..dfc1aa27 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -6025,32 +6025,20 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, if (dbContext) { auto factory = AuthorityFactory::create(NN_NO_CHECK(dbContext), std::string()); - // First pass: exact match on CRS objects - // Second pass: exact match on other objects - // Third pass: approximate match on CRS objects - // Fourth pass: approximate match on other objects - constexpr size_t limitResultCount = 10; - for (int pass = 0; pass <= 3; ++pass) { - const bool approximateMatch = (pass >= 2); + + const auto searchObject = [&factory]( + const std::string &objectName, bool approximateMatch, + const std::vector &objectTypes, + bool &goOn) { + constexpr size_t limitResultCount = 10; auto res = factory->createObjectsFromName( - text, - (pass == 0 || pass == 2) - ? std::vector< - AuthorityFactory::ObjectType>{AuthorityFactory:: - ObjectType::CRS} - : std::vector< - AuthorityFactory:: - ObjectType>{AuthorityFactory::ObjectType:: - ELLIPSOID, - AuthorityFactory::ObjectType::DATUM, - AuthorityFactory::ObjectType:: - COORDINATE_OPERATION}, - approximateMatch, limitResultCount); + objectName, objectTypes, approximateMatch, limitResultCount); if (res.size() == 1) { return res.front(); } if (res.size() > 1) { - if (pass == 0 || pass == 2) { + if (objectTypes.size() == 1 && + objectTypes[0] == AuthorityFactory::ObjectType::CRS) { for (size_t ndim = 2; ndim <= 3; ndim++) { for (const auto &obj : res) { auto crs = @@ -6079,6 +6067,79 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, } throw ParsingException(msg); } + goOn = true; + throw ParsingException("dummy"); + }; + + const auto searchCRS = [&searchObject](const std::string &objectName) { + bool goOn = false; + const auto objectTypes = std::vector{ + AuthorityFactory::ObjectType::CRS}; + try { + constexpr bool approximateMatch = false; + return searchObject(objectName, approximateMatch, objectTypes, + goOn); + } catch (const std::exception &) { + if (!goOn) + throw; + } + constexpr bool approximateMatch = true; + return searchObject(objectName, approximateMatch, objectTypes, + goOn); + }; + + // strings like "WGS 84 + EGM96 height" + CompoundCRSPtr compoundCRS; + try { + const auto tokensCompound = split(text, " + "); + if (tokensCompound.size() == 2) { + auto obj1 = searchCRS(tokensCompound[0]); + auto obj2 = searchCRS(tokensCompound[1]); + auto crs1 = util::nn_dynamic_pointer_cast(obj1); + auto crs2 = util::nn_dynamic_pointer_cast(obj2); + if (crs1 && crs2) { + compoundCRS = + CompoundCRS::create( + util::PropertyMap().set(IdentifiedObject::NAME_KEY, + crs1->nameStr() + " + " + + crs2->nameStr()), + {NN_NO_CHECK(crs1), NN_NO_CHECK(crs2)}) + .as_nullable(); + } + } + } catch (const std::exception &) { + } + + // First pass: exact match on CRS objects + // Second pass: exact match on other objects + // Third pass: approximate match on CRS objects + // Fourth pass: approximate match on other objects + for (int pass = 0; pass <= 3; ++pass) { + const bool approximateMatch = (pass >= 2); + bool goOn = false; + try { + return searchObject( + text, approximateMatch, + (pass == 0 || pass == 2) + ? std::vector< + AuthorityFactory::ObjectType>{AuthorityFactory:: + ObjectType::CRS} + : std::vector< + AuthorityFactory:: + ObjectType>{AuthorityFactory::ObjectType:: + ELLIPSOID, + AuthorityFactory::ObjectType:: + DATUM, + AuthorityFactory::ObjectType:: + COORDINATE_OPERATION}, + goOn); + } catch (const std::exception &) { + if (!goOn) + throw; + } + if (compoundCRS) { + return NN_NO_CHECK(compoundCRS); + } } } @@ -6114,6 +6175,8 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, *
  • an Object name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as * uniqueness is not guaranteed, the function may apply heuristics to * determine the appropriate best match.
  • + *
  • a compound CRS made from two object names separated with " + ". + * e.g. "WGS 84 + EGM96 height"
  • *
  • PROJJSON string
  • * * @@ -6163,6 +6226,8 @@ BaseObjectNNPtr createFromUserInput(const std::string &text, *
  • an Object name. e.g "WGS 84", "WGS 84 / UTM zone 31N". In that case as * uniqueness is not guaranteed, the function may apply heuristics to * determine the appropriate best match.
  • + *
  • a compound CRS made from two object names separated with " + ". + * e.g. "WGS 84 + EGM96 height"
  • *
  • PROJJSON string
  • * * -- cgit v1.2.3