aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2020-10-08 20:59:19 +0200
committerEven Rouault <even.rouault@spatialys.com>2020-11-01 12:57:34 +0100
commit1e5acb00a0c0fc2533b9bce2e5803da10ed1d8d6 (patch)
treedf572ae12dfec9333a8931886dd3ce221a65edf8
parentc2b0dcc468b4e722e46fe10fca93fe70a95fcb8e (diff)
downloadPROJ-1e5acb00a0c0fc2533b9bce2e5803da10ed1d8d6.tar.gz
PROJ-1e5acb00a0c0fc2533b9bce2e5803da10ed1d8d6.zip
projinfo / createObjectsFromName(): support returning a datum ensemble
-rw-r--r--docs/source/apps/projinfo.rst4
-rw-r--r--include/proj/io.hpp2
-rw-r--r--src/apps/projinfo.cpp18
-rw-r--r--src/iso19111/c_api.cpp2
-rw-r--r--src/iso19111/datum.cpp8
-rw-r--r--src/iso19111/factory.cpp51
-rw-r--r--src/iso19111/io.cpp5
-rwxr-xr-xtest/cli/testprojinfo4
-rw-r--r--test/cli/testprojinfo_out.dist21
-rw-r--r--test/unit/test_factory.cpp24
-rw-r--r--test/unit/test_io.cpp8
11 files changed, 137 insertions, 10 deletions
diff --git a/docs/source/apps/projinfo.rst b/docs/source/apps/projinfo.rst
index 05184ef9..a07cf709 100644
--- a/docs/source/apps/projinfo.rst
+++ b/docs/source/apps/projinfo.rst
@@ -16,7 +16,7 @@ Synopsis
********
| **projinfo**
- | [-o formats] [-k crs|operation|datum|ellipsoid] [--summary] [-q]
+ | [-o formats] [-k crs|operation|datum|ensemble|ellipsoid] [--summary] [-q]
| [[--area name_or_code] | [--bbox west_long,south_lat,east_long,north_lat]]
| [--spatial-test contains|intersects]
| [--crs-extent-use none|both|intersection|smallest]
@@ -86,7 +86,7 @@ The following control parameters can appear in any order:
.. note:: Before PROJ 6.3.0, WKT1:GDAL was implicitly calling --boundcrs-to-wgs84.
This is no longer the case.
-.. option:: -k crs|operation|datum|ellipsoid
+.. option:: -k crs|operation|datum|ensemble|ellipsoid
When used to query a single object with a AUTHORITY:CODE, determines the (k)ind of the object
in case there are CRS, coordinate operations or ellipsoids with the same CODE.
diff --git a/include/proj/io.hpp b/include/proj/io.hpp
index a30b04dc..de8a90fc 100644
--- a/include/proj/io.hpp
+++ b/include/proj/io.hpp
@@ -1032,6 +1032,8 @@ class PROJ_GCC_DLL AuthorityFactory {
DYNAMIC_GEODETIC_REFERENCE_FRAME,
/** Object of type datum::DynamicVerticalReferenceFrame */
DYNAMIC_VERTICAL_REFERENCE_FRAME,
+ /** Object of type datum::DatumEnsemble */
+ DATUM_ENSEMBLE,
};
PROJ_DLL std::set<std::string>
diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp
index 37b76346..6ee5925a 100644
--- a/src/apps/projinfo.cpp
+++ b/src/apps/projinfo.cpp
@@ -79,7 +79,8 @@ struct OutputOptions {
static void usage() {
std::cerr
- << "usage: projinfo [-o formats] [-k crs|operation|datum|ellipsoid] "
+ << "usage: projinfo [-o formats] "
+ "[-k crs|operation|datum|ensemble|ellipsoid] "
"[--summary] [-q]"
<< std::endl
<< " ([--area name_or_code] | "
@@ -184,11 +185,11 @@ static BaseObjectNNPtr buildObject(
auto urn = "urn:ogc:def:coordinateOperation:" + tokens[0] + "::" +
tokens[1];
obj = createFromUserInput(urn, dbContext).as_nullable();
- } else if (kind == "ellipsoid" && tokens.size() == 2) {
- auto urn = "urn:ogc:def:ellipsoid:" + tokens[0] + "::" + tokens[1];
- obj = createFromUserInput(urn, dbContext).as_nullable();
- } else if (kind == "datum" && tokens.size() == 2) {
- auto urn = "urn:ogc:def:datum:" + tokens[0] + "::" + tokens[1];
+ } else if ((kind == "ellipsoid" || kind == "datum" ||
+ kind == "ensemble") &&
+ tokens.size() == 2) {
+ auto urn =
+ "urn:ogc:def:" + kind + ":" + tokens[0] + "::" + tokens[1];
obj = createFromUserInput(urn, dbContext).as_nullable();
} else {
// Convenience to be able to use C escaped strings...
@@ -222,6 +223,9 @@ static BaseObjectNNPtr buildObject(
AuthorityFactory::ObjectType::ELLIPSOID);
else if (kind == "datum")
allowedTypes.push_back(AuthorityFactory::ObjectType::DATUM);
+ else if (kind == "ensemble")
+ allowedTypes.push_back(
+ AuthorityFactory::ObjectType::DATUM_ENSEMBLE);
constexpr size_t limitResultCount = 10;
auto factory = AuthorityFactory::create(NN_NO_CHECK(dbContext),
std::string());
@@ -929,6 +933,8 @@ int main(int argc, char **argv) {
objectKind = "ellipsoid";
} else if (ci_equal(kind, "datum")) {
objectKind = "datum";
+ } else if (ci_equal(kind, "ensemble")) {
+ objectKind = "ensemble";
} else {
std::cerr << "Unrecognized value for option -k: " << kind
<< std::endl;
diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp
index 90a414c6..4fb73d31 100644
--- a/src/iso19111/c_api.cpp
+++ b/src/iso19111/c_api.cpp
@@ -916,7 +916,7 @@ convertPJObjectTypeToObjectType(PJ_TYPE type, bool &valid) {
break;
case PJ_TYPE_DATUM_ENSEMBLE:
- cppType = AuthorityFactory::ObjectType::DATUM;
+ cppType = AuthorityFactory::ObjectType::DATUM_ENSEMBLE;
break;
case PJ_TYPE_TEMPORAL_DATUM:
diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp
index 5bc8074c..e29f6319 100644
--- a/src/iso19111/datum.cpp
+++ b/src/iso19111/datum.cpp
@@ -1731,6 +1731,14 @@ void DatumEnsemble::_exportToWKT(
formatter->startNode(io::WKTConstants::ENSEMBLEACCURACY, false);
formatter->add(positionalAccuracy()->value());
formatter->endNode();
+
+ // In theory, we should do the following, but currently the WKT grammar
+ // doesn't allow this
+ // ObjectUsage::baseExportToWKT(formatter);
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+
formatter->endNode();
}
//! @endcond
diff --git a/src/iso19111/factory.cpp b/src/iso19111/factory.cpp
index 301b88be..0ccfefc1 100644
--- a/src/iso19111/factory.cpp
+++ b/src/iso19111/factory.cpp
@@ -5452,6 +5452,11 @@ AuthorityFactory::getAuthorityCodes(const ObjectType &type,
case ObjectType::CONCATENATED_OPERATION:
sql = "SELECT code FROM concatenated_operation WHERE ";
break;
+ case ObjectType::DATUM_ENSEMBLE:
+ sql = "SELECT code FROM object_view WHERE table_name IN "
+ "('geodetic_datum', 'vertical_datum') AND "
+ "type = 'ensemble' AND ";
+ break;
}
sql += "auth_name = ?";
@@ -5961,12 +5966,28 @@ AuthorityFactory::createObjectsFromNameEx(
res.emplace_back(
TableType("concatenated_operation", std::string()));
break;
+ case ObjectType::DATUM_ENSEMBLE:
+ res.emplace_back(TableType("geodetic_datum", "ensemble"));
+ res.emplace_back(TableType("vertical_datum", "ensemble"));
+ break;
}
}
}
return res;
};
+ bool datumEnsembleAllowed = false;
+ if (allowedObjectTypes.empty()) {
+ datumEnsembleAllowed = true;
+ } else {
+ for (const auto type : allowedObjectTypes) {
+ if (type == ObjectType::DATUM_ENSEMBLE) {
+ datumEnsembleAllowed = true;
+ break;
+ }
+ }
+ }
+
const auto listTableNameType = getTableAndTypeConstraints();
bool first = true;
ListOfParams params;
@@ -5984,6 +6005,8 @@ AuthorityFactory::createObjectsFromNameEx(
if (!tableNameTypePair.second.empty()) {
if (tableNameTypePair.second == "frame_reference_epoch") {
sql += "AND frame_reference_epoch IS NOT NULL ";
+ } else if (tableNameTypePair.second == "ensemble") {
+ sql += "AND ensemble_accuracy IS NOT NULL ";
} else {
sql += "AND type = '";
sql += tableNameTypePair.second;
@@ -6018,6 +6041,8 @@ AuthorityFactory::createObjectsFromNameEx(
if (!tableNameTypePair.second.empty()) {
if (tableNameTypePair.second == "frame_reference_epoch") {
sql += "AND ov.frame_reference_epoch IS NOT NULL ";
+ } else if (tableNameTypePair.second == "ensemble") {
+ sql += "AND ov.ensemble_accuracy IS NOT NULL ";
} else {
sql += "AND ov.type = '";
sql += tableNameTypePair.second;
@@ -6165,7 +6190,7 @@ AuthorityFactory::createObjectsFromNameEx(
break;
}
auto factory = d->createFactory(auth_name);
- auto getObject = [&factory](
+ auto getObject = [&factory, datumEnsembleAllowed](
const std::string &l_table_name,
const std::string &l_code) -> common::IdentifiedObjectNNPtr {
if (l_table_name == "prime_meridian") {
@@ -6173,8 +6198,32 @@ AuthorityFactory::createObjectsFromNameEx(
} else if (l_table_name == "ellipsoid") {
return factory->createEllipsoid(l_code);
} else if (l_table_name == "geodetic_datum") {
+ if (datumEnsembleAllowed) {
+ datum::GeodeticReferenceFramePtr datum;
+ datum::DatumEnsemblePtr datumEnsemble;
+ constexpr bool turnEnsembleAsDatum = false;
+ factory->createGeodeticDatumOrEnsemble(
+ l_code, datum, datumEnsemble, turnEnsembleAsDatum);
+ if (datum) {
+ return NN_NO_CHECK(datum);
+ }
+ assert(datumEnsemble);
+ return NN_NO_CHECK(datumEnsemble);
+ }
return factory->createGeodeticDatum(l_code);
} else if (l_table_name == "vertical_datum") {
+ if (datumEnsembleAllowed) {
+ datum::VerticalReferenceFramePtr datum;
+ datum::DatumEnsemblePtr datumEnsemble;
+ constexpr bool turnEnsembleAsDatum = false;
+ factory->createVerticalDatumOrEnsemble(
+ l_code, datum, datumEnsemble, turnEnsembleAsDatum);
+ if (datum) {
+ return NN_NO_CHECK(datum);
+ }
+ assert(datumEnsemble);
+ return NN_NO_CHECK(datumEnsemble);
+ }
return factory->createVerticalDatum(l_code);
} else if (l_table_name == "geodetic_crs") {
return factory->createGeodeticCRS(l_code);
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index fde697ad..b2e5822b 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -6267,6 +6267,9 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
if (type == "datum") {
return factory->createDatum(code);
}
+ if (type == "ensemble") {
+ return factory->createDatumEnsemble(code);
+ }
if (type == "ellipsoid") {
return factory->createEllipsoid(code);
}
@@ -6385,6 +6388,8 @@ static BaseObjectNNPtr createFromUserInput(const std::string &text,
AuthorityFactory::ObjectType::
DATUM,
AuthorityFactory::ObjectType::
+ DATUM_ENSEMBLE,
+ AuthorityFactory::ObjectType::
COORDINATE_OPERATION},
goOn);
} catch (const std::exception &) {
diff --git a/test/cli/testprojinfo b/test/cli/testprojinfo
index 62713af5..c31cfef0 100755
--- a/test/cli/testprojinfo
+++ b/test/cli/testprojinfo
@@ -171,6 +171,10 @@ echo 'Testing -k datum EPSG:6326' >> ${OUT}
$EXE -k datum EPSG:6326 >>${OUT} 2>&1
echo "" >>${OUT}
+echo 'Testing -k ensemble WGS84' >> ${OUT}
+$EXE -k ensemble WGS84 >>${OUT} 2>&1
+echo "" >>${OUT}
+
echo 'Testing -k operation EPSG:8457 -o PROJ -q' >> ${OUT}
$EXE -k operation EPSG:8457 -o PROJ -q >>${OUT} 2>&1
echo "" >>${OUT}
diff --git a/test/cli/testprojinfo_out.dist b/test/cli/testprojinfo_out.dist
index 2d4990ee..174f11d3 100644
--- a/test/cli/testprojinfo_out.dist
+++ b/test/cli/testprojinfo_out.dist
@@ -1260,6 +1260,27 @@ DATUM["World Geodetic System 1984",
LENGTHUNIT["metre",1]],
ID["EPSG",6326]]
+Testing -k ensemble WGS84
+WKT2:2019 string:
+ENSEMBLE["World Geodetic System 1984 ensemble",
+ MEMBER["World Geodetic System 1984 (Transit)",
+ ID["EPSG",1166]],
+ MEMBER["World Geodetic System 1984 (G730)",
+ ID["EPSG",1152]],
+ MEMBER["World Geodetic System 1984 (G873)",
+ ID["EPSG",1153]],
+ MEMBER["World Geodetic System 1984 (G1150)",
+ ID["EPSG",1154]],
+ MEMBER["World Geodetic System 1984 (G1674)",
+ ID["EPSG",1155]],
+ MEMBER["World Geodetic System 1984 (G1762)",
+ ID["EPSG",1156]],
+ ELLIPSOID["WGS 84",6378137,298.257223563,
+ LENGTHUNIT["metre",1],
+ ID["EPSG",7030]],
+ ENSEMBLEACCURACY[2.0],
+ ID["EPSG",6326]]
+
Testing -k operation EPSG:8457 -o PROJ -q
+proj=pipeline
+step +proj=axisswap +order=2,1
diff --git a/test/unit/test_factory.cpp b/test/unit/test_factory.cpp
index 681ac810..8e9b7ab6 100644
--- a/test/unit/test_factory.cpp
+++ b/test/unit/test_factory.cpp
@@ -3186,6 +3186,29 @@ TEST(factory, createObjectsFromName) {
.size(),
1U);
+ {
+ auto res = factory->createObjectsFromName(
+ "World Geodetic System 1984 ensemble",
+ {AuthorityFactory::ObjectType::DATUM_ENSEMBLE}, false);
+ EXPECT_EQ(res.size(), 1U);
+ if (!res.empty()) {
+ EXPECT_EQ(res.front()->getEPSGCode(), 6326);
+ EXPECT_TRUE(dynamic_cast<DatumEnsemble *>(res.front().get()) !=
+ nullptr);
+ }
+ }
+
+ {
+ auto res = factory->createObjectsFromName(
+ "World Geodetic System 1984 ensemble", {}, false);
+ EXPECT_EQ(res.size(), 1U);
+ if (!res.empty()) {
+ EXPECT_EQ(res.front()->getEPSGCode(), 6326);
+ EXPECT_TRUE(dynamic_cast<DatumEnsemble *>(res.front().get()) !=
+ nullptr);
+ }
+ }
+
const auto types = std::vector<AuthorityFactory::ObjectType>{
AuthorityFactory::ObjectType::PRIME_MERIDIAN,
AuthorityFactory::ObjectType::ELLIPSOID,
@@ -3207,6 +3230,7 @@ TEST(factory, createObjectsFromName) {
AuthorityFactory::ObjectType::CONVERSION,
AuthorityFactory::ObjectType::TRANSFORMATION,
AuthorityFactory::ObjectType::CONCATENATED_OPERATION,
+ AuthorityFactory::ObjectType::DATUM_ENSEMBLE,
};
for (const auto type : types) {
factory->createObjectsFromName("i_dont_exist", {type}, false, 1);
diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp
index 555d1159..3d8df998 100644
--- a/test/unit/test_io.cpp
+++ b/test/unit/test_io.cpp
@@ -10444,6 +10444,14 @@ TEST(io, createFromUserInput) {
ParsingException);
EXPECT_THROW(createFromUserInput("foobar + EGM96 height", dbContext),
ParsingException);
+
+ {
+ auto obj = createFromUserInput("World Geodetic System 1984 ensemble",
+ dbContext);
+ auto ensemble = nn_dynamic_pointer_cast<DatumEnsemble>(obj);
+ ASSERT_TRUE(ensemble != nullptr);
+ EXPECT_EQ(ensemble->identifiers().size(), 1U);
+ }
}
// ---------------------------------------------------------------------------