From 5163741254088b7f3fbb651349463cd2942df4f6 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Sat, 10 Oct 2020 14:23:42 +0200 Subject: WKT2:2019 import/export: handle DATUM (at top level object) with PRIMEM This is a peculiarity of the WKT grammar. Despite ISO 19111 saying that the prime meridian is a component of the datum, in WKT, they are placed at the same level, for backward compatibility with earlier WKT versions. So handle exporting and importing that. The fix is only for situation where DATUM is the top level object (was working fine otherwise), which is a uncommon use case. And to limit the amount of issue, on export emit the prime meridian only if it is not Greenwich. --- src/iso19111/datum.cpp | 7 +++++++ src/iso19111/io.cpp | 46 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 44 insertions(+), 9 deletions(-) (limited to 'src/iso19111') diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 83f615e9..fbd4fd2d 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -1300,6 +1300,13 @@ void GeodeticReferenceFrame::_exportToWKT( } // the PRIMEM is exported as a child of the CRS formatter->endNode(); + + if (formatter->isAtTopLevel()) { + const auto &l_primeMeridian(primeMeridian()); + if (l_primeMeridian->nameStr() != "Greenwich") { + l_primeMeridian->_exportToWKT(formatter); + } + } } //! @endcond diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 16ab22f7..c464b724 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -388,6 +388,12 @@ void WKTFormatter::leave() { // --------------------------------------------------------------------------- +bool WKTFormatter::isAtTopLevel() const { + return d->level_ == 0 && d->indentLevel_ == 0; +} + +// --------------------------------------------------------------------------- + void WKTFormatter::startNode(const std::string &keyword, bool hasId) { if (!d->stackHasChild_.empty()) { d->startNewChild(); @@ -4733,13 +4739,7 @@ BaseObjectNNPtr WKTParser::Private::build(const WKTNodeNNPtr &node) { return util::nn_static_pointer_cast(NN_NO_CHECK(crs)); } - if (ci_equal(name, WKTConstants::DATUM) || - ci_equal(name, WKTConstants::GEODETICDATUM) || - ci_equal(name, WKTConstants::TRF)) { - return util::nn_static_pointer_cast( - buildGeodeticReferenceFrame(node, PrimeMeridian::GREENWICH, - null_node)); - } + // Datum handled by caller code WKTParser::createFromWKT() if (ci_equal(name, WKTConstants::ENSEMBLE)) { return util::nn_static_pointer_cast(buildDatumEnsemble( @@ -6441,8 +6441,36 @@ BaseObjectNNPtr createFromUserInput(const std::string &text, PJ_CONTEXT *ctx) { * @throw ParsingException */ BaseObjectNNPtr WKTParser::createFromWKT(const std::string &wkt) { - WKTNodeNNPtr root = WKTNode::createFrom(wkt); - auto obj = d->build(root); + const auto build = [this, &wkt]() -> BaseObjectNNPtr { + size_t indexEnd; + WKTNodeNNPtr root = WKTNode::createFrom(wkt, 0, 0, indexEnd); + const std::string &name(root->GP()->value()); + if (ci_equal(name, WKTConstants::DATUM) || + ci_equal(name, WKTConstants::GEODETICDATUM) || + ci_equal(name, WKTConstants::TRF)) { + + auto primeMeridian = PrimeMeridian::GREENWICH; + if (indexEnd < wkt.size()) { + indexEnd = skipSpace(wkt, indexEnd); + if (indexEnd < wkt.size() && wkt[indexEnd] == ',') { + ++indexEnd; + indexEnd = skipSpace(wkt, indexEnd); + if (indexEnd < wkt.size() && + ci_starts_with(wkt.c_str() + indexEnd, + WKTConstants::PRIMEM.c_str())) { + primeMeridian = d->buildPrimeMeridian( + WKTNode::createFrom(wkt, indexEnd + 1, 0, indexEnd), + UnitOfMeasure::DEGREE); + } + } + } + return d->buildGeodeticReferenceFrame(root, primeMeridian, + null_node); + } + return d->build(root); + }; + + auto obj = build(); const auto dialect = guessDialect(wkt); if (dialect == WKTGuessedDialect::WKT1_GDAL || -- cgit v1.2.3