diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2021-09-28 14:47:09 +0200 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2021-09-28 14:47:09 +0200 |
| commit | e6e6e4ca345e774910afa5bbe485c3d9f7851cd4 (patch) | |
| tree | dd1cd3df30565228b932bbfc1d8d97e142111344 /src/iso19111 | |
| parent | f982d9d3104731727c445930bf14008d1c572d0a (diff) | |
| download | PROJ-e6e6e4ca345e774910afa5bbe485c3d9f7851cd4.tar.gz PROJ-e6e6e4ca345e774910afa5bbe485c3d9f7851cd4.zip | |
Add a mapping for versioned authorities, so that one can use IAU:xxxx or IAU_2015:xxxx transparently
Diffstat (limited to 'src/iso19111')
| -rw-r--r-- | src/iso19111/factory.cpp | 91 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 179 | ||||
| -rw-r--r-- | src/iso19111/metadata.cpp | 25 |
3 files changed, 235 insertions, 60 deletions
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 94c2de2c..f08e32b9 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -754,6 +754,14 @@ struct DatabaseContext::Private { // cppcheck-suppress functionStatic void cache(const std::string &code, const GridInfoCache &info); + struct VersionedAuthName { + std::string versionedAuthName{}; + std::string authName{}; + std::string version{}; + int priority = 0; + }; + const std::vector<VersionedAuthName> &getCacheAuthNameWithVersion(); + private: friend class DatabaseContext; @@ -795,6 +803,8 @@ struct DatabaseContext::Private { lru11::Cache<std::string, std::list<std::string>> cacheAliasNames_{ CACHE_SIZE}; + std::vector<VersionedAuthName> cacheAuthNameWithVersion_{}; + static void insertIntoCache(LRUCacheOfObjects &cache, const std::string &code, const util::BaseObjectPtr &obj); @@ -3558,6 +3568,87 @@ DatabaseContext::getNonDeprecated(const std::string &tableName, // --------------------------------------------------------------------------- +const std::vector<DatabaseContext::Private::VersionedAuthName> & +DatabaseContext::Private::getCacheAuthNameWithVersion() { + if (cacheAuthNameWithVersion_.empty()) { + const auto sqlRes = + run("SELECT versioned_auth_name, auth_name, version, priority " + "FROM versioned_auth_name_mapping"); + for (const auto &row : sqlRes) { + VersionedAuthName van; + van.versionedAuthName = row[0]; + van.authName = row[1]; + van.version = row[2]; + van.priority = atoi(row[3].c_str()); + cacheAuthNameWithVersion_.emplace_back(std::move(van)); + } + } + return cacheAuthNameWithVersion_; +} + +// --------------------------------------------------------------------------- + +// From IAU_2015 returns (IAU,2015) +bool DatabaseContext::getAuthorityAndVersion( + const std::string &versionedAuthName, std::string &authNameOut, + std::string &versionOut) { + + for (const auto &van : d->getCacheAuthNameWithVersion()) { + if (van.versionedAuthName == versionedAuthName) { + authNameOut = van.authName; + versionOut = van.version; + return true; + } + } + return false; +} + +// --------------------------------------------------------------------------- + +// From IAU and 2015, returns IAU_2015 +bool DatabaseContext::getVersionedAuthority(const std::string &authName, + const std::string &version, + std::string &versionedAuthNameOut) { + + for (const auto &van : d->getCacheAuthNameWithVersion()) { + if (van.authName == authName && van.version == version) { + versionedAuthNameOut = van.versionedAuthName; + return true; + } + } + return false; +} + +// --------------------------------------------------------------------------- + +// From IAU returns IAU_latest, ... IAU_2015 +std::vector<std::string> +DatabaseContext::getVersionedAuthoritiesFromName(const std::string &authName) { + + typedef std::pair<std::string, int> VersionedAuthNamePriority; + std::vector<VersionedAuthNamePriority> tmp; + for (const auto &van : d->getCacheAuthNameWithVersion()) { + if (van.authName == authName) { + tmp.emplace_back( + VersionedAuthNamePriority(van.versionedAuthName, van.priority)); + } + } + std::vector<std::string> res; + if (!tmp.empty()) { + // Sort by decreasing priority + std::sort(tmp.begin(), tmp.end(), + [](const VersionedAuthNamePriority &a, + const VersionedAuthNamePriority &b) { + return b.second > a.second; + }); + for (const auto &pair : tmp) + res.emplace_back(pair.first); + } + return res; +} + +// --------------------------------------------------------------------------- + std::vector<operation::CoordinateOperationNNPtr> DatabaseContext::getTransformationsForGridName( const DatabaseContextNNPtr &databaseContext, const std::string &gridName) { diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index b317213a..9e7f0580 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -1518,6 +1518,23 @@ IdentifierPtr WKTParser::Private::buildId(const WKTNodeNNPtr &node, codeSpace = codeSpace.substr(strlen("INVERSE(")); codeSpace.resize(codeSpace.size() - 1); } + + std::string version; + if (nodeChildren.size() >= 3 && + nodeChildren[2]->GP()->childrenSize() == 0) { + version = stripQuotes(nodeChildren[2]); + } + + // IAU + 2015 -> IAU_2015 + if (dbContext_ && !version.empty()) { + std::string codeSpaceOut; + if (dbContext_->getVersionedAuthority(codeSpace, version, + codeSpaceOut)) { + codeSpace = codeSpaceOut; + version.clear(); + } + } + auto code = stripQuotes(nodeChildren[1]); auto &citationNode = nodeP->lookForChild(WKTConstants::CITATION); auto &uriNode = nodeP->lookForChild(WKTConstants::URI); @@ -1542,9 +1559,7 @@ IdentifierPtr WKTParser::Private::buildId(const WKTNodeNNPtr &node, stripQuotes(uriNodeP->children()[0])); } } - if (nodeChildren.size() >= 3 && - nodeChildren[2]->GP()->childrenSize() == 0) { - auto version = stripQuotes(nodeChildren[2]); + if (!version.empty()) { propertiesId.set(Identifier::VERSION_KEY, version); } return Identifier::create(code, propertiesId); @@ -5381,24 +5396,10 @@ IdentifierNNPtr JSONParser::buildId(const json &j, bool removeInverseOf) { codeSpace = codeSpace.substr(strlen("INVERSE(")); codeSpace.resize(codeSpace.size() - 1); } - propertiesId.set(metadata::Identifier::CODESPACE_KEY, codeSpace); - propertiesId.set(metadata::Identifier::AUTHORITY_KEY, codeSpace); - if (!j.contains("code")) { - throw ParsingException("Missing \"code\" key"); - } - std::string code; - auto codeJ = j["code"]; - if (codeJ.is_string()) { - code = codeJ.get<std::string>(); - } else if (codeJ.is_number_integer()) { - code = internal::toString(codeJ.get<int>()); - } else { - throw ParsingException("Unexpected type for value of \"code\""); - } + std::string version; if (j.contains("version")) { auto versionJ = j["version"]; - std::string version; if (versionJ.is_string()) { version = versionJ.get<std::string>(); } else if (versionJ.is_number()) { @@ -5413,6 +5414,34 @@ IdentifierNNPtr JSONParser::buildId(const json &j, bool removeInverseOf) { } else { throw ParsingException("Unexpected type for value of \"version\""); } + } + + // IAU + 2015 -> IAU_2015 + if (dbContext_ && !version.empty()) { + std::string codeSpaceOut; + if (dbContext_->getVersionedAuthority(codeSpace, version, + codeSpaceOut)) { + codeSpace = codeSpaceOut; + version.clear(); + } + } + + propertiesId.set(metadata::Identifier::CODESPACE_KEY, codeSpace); + propertiesId.set(metadata::Identifier::AUTHORITY_KEY, codeSpace); + if (!j.contains("code")) { + throw ParsingException("Missing \"code\" key"); + } + std::string code; + auto codeJ = j["code"]; + if (codeJ.is_string()) { + code = codeJ.get<std::string>(); + } else if (codeJ.is_number_integer()) { + code = internal::toString(codeJ.get<int>()); + } else { + throw ParsingException("Unexpected type for value of \"code\""); + } + + if (!version.empty()) { propertiesId.set(Identifier::VERSION_KEY, version); } @@ -6392,6 +6421,61 @@ static CRSNNPtr importFromWMSAUTO(const std::string &text) { // --------------------------------------------------------------------------- +static BaseObjectNNPtr createFromURNPart(const DatabaseContextPtr &dbContext, + const std::string &type, + const std::string &authName, + const std::string &version, + const std::string &code) { + if (!dbContext) { + throw ParsingException("no database context specified"); + } + try { + auto factory = + AuthorityFactory::create(NN_NO_CHECK(dbContext), authName); + if (type == "crs") { + return factory->createCoordinateReferenceSystem(code); + } + if (type == "coordinateOperation") { + return factory->createCoordinateOperation(code, true); + } + if (type == "datum") { + return factory->createDatum(code); + } + if (type == "ensemble") { + return factory->createDatumEnsemble(code); + } + if (type == "ellipsoid") { + return factory->createEllipsoid(code); + } + if (type == "meridian") { + return factory->createPrimeMeridian(code); + } + throw ParsingException(concat("unhandled object type: ", type)); + } catch (...) { + if (version.empty()) { + const auto authoritiesFromAuthName = + dbContext->getVersionedAuthoritiesFromName(authName); + for (const auto &authNameVersioned : authoritiesFromAuthName) { + try { + return createFromURNPart(dbContext, type, authNameVersioned, + std::string(), code); + } catch (...) { + } + } + throw; + } + std::string authNameWithVersion; + if (!dbContext->getVersionedAuthority(authName, version, + authNameWithVersion)) { + throw; + } + return createFromURNPart(dbContext, type, authNameWithVersion, + std::string(), code); + } +} + +// --------------------------------------------------------------------------- + static BaseObjectNNPtr createFromUserInput(const std::string &text, const DatabaseContextPtr &dbContext, bool usePROJ4InitRules, @@ -6481,8 +6565,19 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, return factory->createCoordinateReferenceSystem(code); } - const auto authorities = dbContextNNPtr->getAuthorities(); - for (const auto &authCandidate : authorities) { + const auto authoritiesFromAuthName = + dbContextNNPtr->getVersionedAuthoritiesFromName(authName); + for (const auto &authNameVersioned : authoritiesFromAuthName) { + factory = + AuthorityFactory::create(dbContextNNPtr, authNameVersioned); + try { + return factory->createCoordinateReferenceSystem(code); + } catch (...) { + } + } + + const auto allAuthorities = dbContextNNPtr->getAuthorities(); + for (const auto &authCandidate : allAuthorities) { if (ci_equal(authCandidate, authName)) { factory = AuthorityFactory::create(dbContextNNPtr, authCandidate); @@ -6740,42 +6835,14 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, return ConcatenatedOperation::createComputeMetadata(components, true); } - const auto createFromURNPart = - [&dbContext](const std::string &type, const std::string &authName, - const std::string &code) -> BaseObjectNNPtr { - if (!dbContext) { - throw ParsingException("no database context specified"); - } - auto factory = - AuthorityFactory::create(NN_NO_CHECK(dbContext), authName); - if (type == "crs") { - return factory->createCoordinateReferenceSystem(code); - } - if (type == "coordinateOperation") { - return factory->createCoordinateOperation(code, true); - } - if (type == "datum") { - return factory->createDatum(code); - } - if (type == "ensemble") { - return factory->createDatumEnsemble(code); - } - if (type == "ellipsoid") { - return factory->createEllipsoid(code); - } - if (type == "meridian") { - return factory->createPrimeMeridian(code); - } - throw ParsingException(concat("unhandled object type: ", type)); - }; - // urn:ogc:def:crs:EPSG::4326 if (tokens.size() == 7 && tolower(tokens[0]) == "urn") { const auto type = tokens[3] == "CRS" ? "crs" : tokens[3]; const auto &authName = tokens[4]; + const auto &version = tokens[5]; const auto &code = tokens[6]; - return createFromURNPart(type, authName, code); + return createFromURNPart(dbContext, type, authName, version, code); } // urn:ogc:def:crs:OGC::AUTO42001:-117:33 @@ -6790,8 +6857,9 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, if (tokens.size() == 6 && tokens[0] == "urn" && tokens[2] != "def") { const auto &type = tokens[2]; const auto &authName = tokens[3]; + const auto &version = tokens[4]; const auto &code = tokens[5]; - return createFromURNPart(type, authName, code); + return createFromURNPart(dbContext, type, authName, version, code); } // Legacy urn:x-ogc:def:crs:EPSG:4326 (note the missing version) @@ -6799,7 +6867,8 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text, const auto &type = tokens[3]; const auto &authName = tokens[4]; const auto &code = tokens[5]; - return createFromURNPart(type, authName, code); + return createFromURNPart(dbContext, type, authName, std::string(), + code); } if (dbContext) { @@ -10784,6 +10853,12 @@ CPLJSonStreamingWriter *JSONFormatter::writer() const { return &(d->writer_); } // --------------------------------------------------------------------------- +const DatabaseContextPtr &JSONFormatter::databaseContext() const { + return d->dbContext_; +} + +// --------------------------------------------------------------------------- + bool JSONFormatter::outputId() const { return d->outputIdStack_.back(); } // --------------------------------------------------------------------------- diff --git a/src/iso19111/metadata.cpp b/src/iso19111/metadata.cpp index fc1b103f..6c168152 100644 --- a/src/iso19111/metadata.cpp +++ b/src/iso19111/metadata.cpp @@ -1058,7 +1058,12 @@ const optional<std::string> &Identifier::uri() PROJ_PURE_DEFN { void Identifier::_exportToWKT(WKTFormatter *formatter) const { const bool isWKT2 = formatter->version() == WKTFormatter::Version::WKT2; const std::string &l_code = code(); - const std::string &l_codeSpace = *codeSpace(); + std::string l_codeSpace = *codeSpace(); + std::string l_version = *version(); + const auto &dbContext = formatter->databaseContext(); + if (dbContext) { + dbContext->getAuthorityAndVersion(*codeSpace(), l_codeSpace, l_version); + } if (!l_codeSpace.empty() && !l_code.empty()) { if (isWKT2) { formatter->startNode(WKTConstants::ID, false); @@ -1069,8 +1074,7 @@ void Identifier::_exportToWKT(WKTFormatter *formatter) const { } catch (const std::exception &) { formatter->addQuotedString(l_code); } - if (version().has_value()) { - auto l_version = *(version()); + if (!l_version.empty()) { try { (void)c_locale_stod(l_version); formatter->add(l_version); @@ -1079,7 +1083,7 @@ void Identifier::_exportToWKT(WKTFormatter *formatter) const { } } if (authority().has_value() && - *(authority()->title()) != l_codeSpace) { + *(authority()->title()) != *codeSpace()) { formatter->startNode(WKTConstants::CITATION, false); formatter->addQuotedString(*(authority()->title())); formatter->endNode(); @@ -1103,7 +1107,12 @@ void Identifier::_exportToWKT(WKTFormatter *formatter) const { void Identifier::_exportToJSON(JSONFormatter *formatter) const { const std::string &l_code = code(); - const std::string &l_codeSpace = *codeSpace(); + std::string l_codeSpace = *codeSpace(); + std::string l_version = *version(); + const auto &dbContext = formatter->databaseContext(); + if (dbContext) { + dbContext->getAuthorityAndVersion(*codeSpace(), l_codeSpace, l_version); + } if (!l_codeSpace.empty() && !l_code.empty()) { auto writer = formatter->writer(); auto objContext(formatter->MakeObjectContext(nullptr, false)); @@ -1116,8 +1125,7 @@ void Identifier::_exportToJSON(JSONFormatter *formatter) const { writer->Add(l_code); } - if (version().has_value()) { - const auto l_version = *(version()); + if (!l_version.empty()) { writer->AddObjKey("version"); try { const double dblVersion = c_locale_stod(l_version); @@ -1132,7 +1140,8 @@ void Identifier::_exportToJSON(JSONFormatter *formatter) const { writer->Add(l_version); } } - if (authority().has_value() && *(authority()->title()) != l_codeSpace) { + if (authority().has_value() && + *(authority()->title()) != *codeSpace()) { writer->AddObjKey("authority_citation"); writer->Add(*(authority()->title())); } |
