diff options
| -rw-r--r-- | data/sql/customizations_early.sql | 2 | ||||
| -rw-r--r-- | data/sql/proj_db_table_defs.sql | 11 | ||||
| -rw-r--r-- | include/proj/io.hpp | 13 | ||||
| -rw-r--r-- | src/apps/projinfo.cpp | 12 | ||||
| -rw-r--r-- | src/iso19111/factory.cpp | 91 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 179 | ||||
| -rw-r--r-- | src/iso19111/metadata.cpp | 25 | ||||
| -rw-r--r-- | test/unit/test_crs.cpp | 47 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 16 |
9 files changed, 329 insertions, 67 deletions
diff --git a/data/sql/customizations_early.sql b/data/sql/customizations_early.sql index fceef235..08c44b37 100644 --- a/data/sql/customizations_early.sql +++ b/data/sql/customizations_early.sql @@ -5,7 +5,7 @@ INSERT INTO "scope" VALUES('PROJ','SCOPE_UNKNOWN','Not known.',0); INSERT INTO celestial_body VALUES('PROJ', 'EARTH', 'Earth', 6378137.0); - +INSERT INTO versioned_auth_name_mapping VALUES ('IAU_2015', 'IAU', '2015', 1); CREATE TRIGGER conversion_method_check_insert_trigger_orthographic INSTEAD OF INSERT ON conversion diff --git a/data/sql/proj_db_table_defs.sql b/data/sql/proj_db_table_defs.sql index bf7afca0..20ce940e 100644 --- a/data/sql/proj_db_table_defs.sql +++ b/data/sql/proj_db_table_defs.sql @@ -1515,3 +1515,14 @@ CREATE TABLE authority_to_authority_preference( allowed_authorities TEXT NOT NULL, -- for example 'PROJ,EPSG,any' CONSTRAINT unique_authority_to_authority_preference UNIQUE (source_auth_name, target_auth_name) ); + +-- Map 'IAU_2015' to auth_name=IAU and version=2015 +CREATE TABLE versioned_auth_name_mapping( + versioned_auth_name TEXT NOT NULL PRIMARY KEY, + auth_name TEXT NOT NULL, + version TEXT NOT NULL, + priority INTEGER NOT NULL, + CONSTRAINT unique_auth_name_version UNIQUE (auth_name, version), + CONSTRAINT unique_auth_name_priority UNIQUE (auth_name, priority) +); + diff --git a/include/proj/io.hpp b/include/proj/io.hpp index 6b811b2d..eefec11e 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -512,6 +512,8 @@ class PROJ_GCC_DLL JSONFormatter { PROJ_INTERNAL CPLJSonStreamingWriter * writer() const; + PROJ_INTERNAL const DatabaseContextPtr &databaseContext() const; + struct ObjectContext { JSONFormatter &m_formatter; @@ -912,6 +914,17 @@ class PROJ_GCC_DLL DatabaseContext { getTransformationsForGridName(const DatabaseContextNNPtr &databaseContext, const std::string &gridName); + PROJ_INTERNAL bool + getAuthorityAndVersion(const std::string &versionedAuthName, + std::string &authNameOut, std::string &versionOut); + + PROJ_INTERNAL bool getVersionedAuthority(const std::string &authName, + const std::string &version, + std::string &versionedAuthNameOut); + + PROJ_INTERNAL std::vector<std::string> + getVersionedAuthoritiesFromName(const std::string &authName); + //! @endcond protected: diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp index 10944984..5dfc4f72 100644 --- a/src/apps/projinfo.cpp +++ b/src/apps/projinfo.cpp @@ -495,8 +495,8 @@ static void outputObject( if (!outputOpt.quiet) { std::cout << "WKT2:2015 string:" << std::endl; } - auto formatter = - WKTFormatter::create(WKTFormatter::Convention::WKT2_2015); + auto formatter = WKTFormatter::create( + WKTFormatter::Convention::WKT2_2015, dbContext); formatter->setMultiLine(!outputOpt.singleLine); formatter->setStrict(outputOpt.strict); auto wkt = wktExportable->exportToWKT(formatter.get()); @@ -520,7 +520,7 @@ static void outputObject( std::cout << "WKT2:2015_SIMPLIFIED string:" << std::endl; } auto formatter = WKTFormatter::create( - WKTFormatter::Convention::WKT2_2015_SIMPLIFIED); + WKTFormatter::Convention::WKT2_2015_SIMPLIFIED, dbContext); if (outputOpt.singleLine) { formatter->setMultiLine(false); } @@ -545,8 +545,8 @@ static void outputObject( if (!outputOpt.quiet) { std::cout << "WKT2:2019 string:" << std::endl; } - auto formatter = - WKTFormatter::create(WKTFormatter::Convention::WKT2_2019); + auto formatter = WKTFormatter::create( + WKTFormatter::Convention::WKT2_2019, dbContext); if (outputOpt.singleLine) { formatter->setMultiLine(false); } @@ -572,7 +572,7 @@ static void outputObject( std::cout << "WKT2:2019_SIMPLIFIED string:" << std::endl; } auto formatter = WKTFormatter::create( - WKTFormatter::Convention::WKT2_2019_SIMPLIFIED); + WKTFormatter::Convention::WKT2_2019_SIMPLIFIED, dbContext); if (outputOpt.singleLine) { formatter->setMultiLine(false); } 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())); } diff --git a/test/unit/test_crs.cpp b/test/unit/test_crs.cpp index 42e6018b..449da2bf 100644 --- a/test/unit/test_crs.cpp +++ b/test/unit/test_crs.cpp @@ -747,6 +747,53 @@ TEST(crs, EPSG_4268_geogcrs_deprecated_as_WKT1_GDAL) { // --------------------------------------------------------------------------- +TEST(crs, IAU_1000_as_WKT2) { + auto dbContext = DatabaseContext::create(); + auto factory = AuthorityFactory::create(dbContext, "IAU_2015"); + auto crs = factory->createCoordinateReferenceSystem("1000"); + WKTFormatterNNPtr f( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2019, dbContext)); + auto wkt = crs->exportToWKT(f.get()); + // Check that IAU_2015 is split into a authority name and version + EXPECT_TRUE(wkt.find("ID[\"IAU\",1000,2015]") != std::string::npos) << wkt; + + auto obj = createFromUserInput(wkt, dbContext); + auto crs2 = nn_dynamic_pointer_cast<CRS>(obj); + ASSERT_TRUE(crs2 != nullptr); + auto wkt2 = crs2->exportToWKT(f.get()); + // Check that IAU_2015 is split into a authority name and version + EXPECT_TRUE(wkt2.find("ID[\"IAU\",1000,2015]") != std::string::npos) + << wkt2; +} + +// --------------------------------------------------------------------------- + +TEST(crs, IAU_1000_as_PROJJSON) { + auto dbContext = DatabaseContext::create(); + auto factory = AuthorityFactory::create(dbContext, "IAU_2015"); + auto crs = factory->createCoordinateReferenceSystem("1000"); + auto projjson = crs->exportToJSON(JSONFormatter::create(dbContext).get()); + // Check that IAU_2015 is split into a authority name and version + EXPECT_TRUE(projjson.find("\"authority\": \"IAU\",") != std::string::npos) + << projjson; + EXPECT_TRUE(projjson.find("\"code\": 1000,") != std::string::npos) + << projjson; + EXPECT_TRUE(projjson.find("\"version\": 2015") != std::string::npos) + << projjson; + + auto obj = createFromUserInput(projjson, dbContext); + auto crs2 = nn_dynamic_pointer_cast<CRS>(obj); + ASSERT_TRUE(crs2 != nullptr); + WKTFormatterNNPtr f( + WKTFormatter::create(WKTFormatter::Convention::WKT2_2019, dbContext)); + auto wkt2 = crs2->exportToWKT(f.get()); + // Check that IAU_2015 is split into a authority name and version + EXPECT_TRUE(wkt2.find("ID[\"IAU\",1000,2015]") != std::string::npos) + << wkt2; +} + +// --------------------------------------------------------------------------- + TEST(crs, EPSG_2008_projcrs_deprecated_as_WKT1_GDAL) { auto dbContext = DatabaseContext::create(); auto factory = AuthorityFactory::create(dbContext, "EPSG"); diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index f9a54f3c..646a990a 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -10495,6 +10495,8 @@ TEST(io, createFromUserInput) { EXPECT_NO_THROW(createFromUserInput("epsg:4326", dbContext)); EXPECT_NO_THROW( createFromUserInput("urn:ogc:def:crs:EPSG::4326", dbContext)); + EXPECT_NO_THROW( + createFromUserInput("urn:ogc:def:crs:EPSG:10:4326", dbContext)); EXPECT_THROW(createFromUserInput("urn:ogc:def:crs:EPSG::4326", nullptr), ParsingException); EXPECT_NO_THROW(createFromUserInput( @@ -10508,6 +10510,20 @@ TEST(io, createFromUserInput) { EXPECT_NO_THROW( createFromUserInput("urn:ogc:def:ellipsoid:EPSG::7030", dbContext)); + EXPECT_NO_THROW(createFromUserInput("IAU:1000", dbContext)); + EXPECT_NO_THROW(createFromUserInput("IAU_2015:1000", dbContext)); + EXPECT_NO_THROW( + createFromUserInput("urn:ogc:def:crs:IAU::1000", dbContext)); + EXPECT_NO_THROW( + createFromUserInput("urn:ogc:def:crs:IAU_2015::1000", dbContext)); + EXPECT_NO_THROW( + createFromUserInput("urn:ogc:def:crs:IAU:2015:1000", dbContext)); + + EXPECT_THROW(createFromUserInput("urn:ogc:def:crs:IAU_2015::xxxx", nullptr), + ParsingException); + EXPECT_THROW(createFromUserInput("urn:ogc:def:crs:IAU:xxxx:1000", nullptr), + ParsingException); + // Found as srsName in some GMLs... EXPECT_NO_THROW( createFromUserInput("URN:OGC:DEF:CRS:OGC:1.3:CRS84", dbContext)); |
