diff options
| -rw-r--r-- | include/proj/datum.hpp | 2 | ||||
| -rw-r--r-- | include/proj/io.hpp | 8 | ||||
| -rw-r--r-- | scripts/reference_exported_symbols.txt | 1 | ||||
| -rw-r--r-- | src/iso19111/datum.cpp | 3 | ||||
| -rw-r--r-- | src/iso19111/factory.cpp | 74 | ||||
| -rw-r--r-- | test/unit/test_factory.cpp | 42 |
6 files changed, 123 insertions, 7 deletions
diff --git a/include/proj/datum.hpp b/include/proj/datum.hpp index f1d45c6b..35b8576e 100644 --- a/include/proj/datum.hpp +++ b/include/proj/datum.hpp @@ -125,7 +125,7 @@ using DatumEnsembleNNPtr = util::nn<DatumEnsemblePtr>; * * \remark Implements DatumEnsemble from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL DatumEnsemble final : public common::IdentifiedObject, +class PROJ_GCC_DLL DatumEnsemble final : public common::ObjectUsage, public io::IJSONExportable { public: //! @cond Doxygen_Suppress diff --git a/include/proj/io.hpp b/include/proj/io.hpp index 19ed292d..b4db0ef7 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -71,6 +71,10 @@ class Datum; using DatumPtr = std::shared_ptr<Datum>; using DatumNNPtr = util::nn<DatumPtr>; +class DatumEnsemble; +using DatumEnsemblePtr = std::shared_ptr<DatumEnsemble>; +using DatumEnsembleNNPtr = util::nn<DatumEnsemblePtr>; + class Ellipsoid; using EllipsoidPtr = std::shared_ptr<Ellipsoid>; using EllipsoidNNPtr = util::nn<EllipsoidPtr>; @@ -930,6 +934,10 @@ class PROJ_GCC_DLL AuthorityFactory { PROJ_DLL datum::DatumNNPtr createDatum(const std::string &code) const; + PROJ_DLL datum::DatumEnsembleNNPtr + createDatumEnsemble(const std::string &code, + const std::string &type = std::string()) const; + PROJ_DLL datum::GeodeticReferenceFrameNNPtr createGeodeticDatum(const std::string &code) const; diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index fd44436d..d864030a 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -321,6 +321,7 @@ osgeo::proj::io::AuthorityFactory::createConversion(std::string const&) const osgeo::proj::io::AuthorityFactory::createCoordinateOperation(std::string const&, bool) const osgeo::proj::io::AuthorityFactory::createCoordinateReferenceSystem(std::string const&) const osgeo::proj::io::AuthorityFactory::createCoordinateSystem(std::string const&) const +osgeo::proj::io::AuthorityFactory::createDatumEnsemble(std::string const&, std::string const&) const osgeo::proj::io::AuthorityFactory::createDatum(std::string const&) const osgeo::proj::io::AuthorityFactory::create(dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::io::DatabaseContext> > const&, std::string const&) osgeo::proj::io::AuthorityFactory::createEllipsoid(std::string const&) const diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 83f615e9..d94d729c 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -1574,8 +1574,7 @@ DatumEnsemble::DatumEnsemble(const std::vector<DatumNNPtr> &datumsIn, #ifdef notdef DatumEnsemble::DatumEnsemble(const DatumEnsemble &other) - : common::IdentifiedObject(other), - d(internal::make_unique<Private>(*other.d)) {} + : common::ObjectUsage(other), d(internal::make_unique<Private>(*other.d)) {} #endif // --------------------------------------------------------------------------- diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp index 46657431..3895edb2 100644 --- a/src/iso19111/factory.cpp +++ b/src/iso19111/factory.cpp @@ -1604,9 +1604,9 @@ AuthorityFactory::CRSInfo::CRSInfo() util::BaseObjectNNPtr AuthorityFactory::createObject(const std::string &code) const { - auto res = d->runWithCodeParam( - "SELECT table_name FROM object_view WHERE auth_name = ? AND code = ?", - code); + auto res = d->runWithCodeParam("SELECT table_name, type FROM object_view " + "WHERE auth_name = ? AND code = ?", + code); if (res.empty()) { throw NoSuchAuthorityCodeException("not found", d->authority(), code); } @@ -1622,7 +1622,9 @@ AuthorityFactory::createObject(const std::string &code) const { } throw FactoryException(msg); } - const auto &table_name = res.front()[0]; + const auto &first_row = res.front(); + const auto &table_name = first_row[0]; + const auto &type = first_row[1]; if (table_name == "extent") { return util::nn_static_pointer_cast<util::BaseObject>( createExtent(code)); @@ -1640,10 +1642,18 @@ AuthorityFactory::createObject(const std::string &code) const { createEllipsoid(code)); } if (table_name == "geodetic_datum") { + if (type == "ensemble") { + return util::nn_static_pointer_cast<util::BaseObject>( + createDatumEnsemble(code, table_name)); + } return util::nn_static_pointer_cast<util::BaseObject>( createGeodeticDatum(code)); } if (table_name == "vertical_datum") { + if (type == "ensemble") { + return util::nn_static_pointer_cast<util::BaseObject>( + createDatumEnsemble(code, table_name)); + } return util::nn_static_pointer_cast<util::BaseObject>( createVerticalDatum(code)); } @@ -2093,6 +2103,62 @@ AuthorityFactory::createVerticalDatum(const std::string &code) const { // --------------------------------------------------------------------------- +/** \brief Returns a datum::DatumEnsemble from the specified code. + * + * @param code Object code allocated by authority. + * @param type "geodetic_datum", "vertical_datum" or empty string if unknown + * @return object. + * @throw NoSuchAuthorityCodeException + * @throw FactoryException + */ + +datum::DatumEnsembleNNPtr +AuthorityFactory::createDatumEnsemble(const std::string &code, + const std::string &type) const { + auto res = d->run( + "SELECT 'geodetic_datum', name, ensemble_accuracy, deprecated FROM " + "geodetic_datum WHERE " + "auth_name = ? AND code = ? AND ensemble_accuracy IS NOT NULL " + "UNION ALL " + "SELECT 'vertical_datum', name, ensemble_accuracy, deprecated FROM " + "vertical_datum WHERE " + "auth_name = ? AND code = ? AND ensemble_accuracy IS NOT NULL", + {d->authority(), code, d->authority(), code}); + if (res.empty()) { + throw NoSuchAuthorityCodeException("datum ensemble not found", + d->authority(), code); + } + for (const auto &row : res) { + const std::string &gotType = row[0]; + const std::string &name = row[1]; + const std::string &ensembleAccuracy = row[2]; + const bool deprecated = row[3] == "1"; + if (type.empty() || type == gotType) { + auto resMembers = + d->run("SELECT member_auth_name, member_code FROM " + gotType + + "_ensemble_member WHERE " + "ensemble_auth_name = ? AND ensemble_code = ? " + "ORDER BY sequence", + {d->authority(), code}); + + std::vector<datum::DatumNNPtr> members; + for (const auto &memberRow : resMembers) { + members.push_back( + d->createFactory(memberRow[0])->createDatum(memberRow[1])); + } + auto props = d->createPropertiesSearchUsages(gotType, code, name, + deprecated); + return datum::DatumEnsemble::create( + props, std::move(members), + metadata::PositionalAccuracy::create(ensembleAccuracy)); + } + } + throw NoSuchAuthorityCodeException("datum ensemble not found", + d->authority(), code); +} + +// --------------------------------------------------------------------------- + /** \brief Returns a datum::Datum from the specified code. * * @param code Object code allocated by authority. diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp index 1d070a43..6b87fba6 100644 --- a/test/unit/test_factory.cpp +++ b/test/unit/test_factory.cpp @@ -316,6 +316,48 @@ TEST(factory, AuthorityFactory_createDatum) { // --------------------------------------------------------------------------- +TEST(factory, AuthorityFactory_createDatumEnsembleGeodetic) { + auto factory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + EXPECT_THROW(factory->createDatumEnsemble("-1"), + NoSuchAuthorityCodeException); + EXPECT_THROW(factory->createDatumEnsemble("6326", "vertical_datum"), + NoSuchAuthorityCodeException); + auto ensemble = factory->createDatumEnsemble("6326"); + EXPECT_EQ(ensemble->nameStr(), "World Geodetic System 1984 ensemble"); + ASSERT_EQ(ensemble->identifiers().size(), 1U); + EXPECT_EQ(ensemble->identifiers()[0]->code(), "6326"); + EXPECT_EQ(*(ensemble->identifiers()[0]->codeSpace()), "EPSG"); + EXPECT_EQ(ensemble->datums().size(), 6U); + EXPECT_EQ(ensemble->positionalAccuracy()->value(), "2.0"); + ASSERT_TRUE(!ensemble->domains().empty()); + auto domain = ensemble->domains()[0]; + auto extent = domain->domainOfValidity(); + ASSERT_TRUE(extent != nullptr); + EXPECT_TRUE(extent->isEquivalentTo(factory->createExtent("1262").get())); +} + +// --------------------------------------------------------------------------- + +TEST(factory, AuthorityFactory_createDatumEnsembleVertical) { + auto factory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); + EXPECT_THROW(factory->createDatumEnsemble("1288", "geodetic_datum"), + NoSuchAuthorityCodeException); + auto ensemble = factory->createDatumEnsemble("1288"); + EXPECT_EQ(ensemble->nameStr(), "British Isles height ensemble"); + ASSERT_EQ(ensemble->identifiers().size(), 1U); + EXPECT_EQ(ensemble->identifiers()[0]->code(), "1288"); + EXPECT_EQ(*(ensemble->identifiers()[0]->codeSpace()), "EPSG"); + EXPECT_EQ(ensemble->datums().size(), 9U); + EXPECT_EQ(ensemble->positionalAccuracy()->value(), "0.4"); + ASSERT_TRUE(!ensemble->domains().empty()); + auto domain = ensemble->domains()[0]; + auto extent = domain->domainOfValidity(); + ASSERT_TRUE(extent != nullptr); + EXPECT_TRUE(extent->isEquivalentTo(factory->createExtent("4606").get())); +} + +// --------------------------------------------------------------------------- + TEST(factory, AuthorityFactory_createCoordinateSystem_ellipsoidal_2_axis) { auto factory = AuthorityFactory::create(DatabaseContext::create(), "EPSG"); EXPECT_THROW(factory->createCoordinateSystem("-1"), |
