aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/proj/datum.hpp2
-rw-r--r--include/proj/io.hpp8
-rw-r--r--scripts/reference_exported_symbols.txt1
-rw-r--r--src/iso19111/datum.cpp3
-rw-r--r--src/iso19111/factory.cpp74
-rw-r--r--test/unit/test_factory.cpp42
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"),