aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/iso19111/crs.cpp109
-rw-r--r--src/iso19111/datum.cpp14
-rw-r--r--src/iso19111/io.cpp15
3 files changed, 118 insertions, 20 deletions
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp
index 88db81f9..5fbc4c4b 100644
--- a/src/iso19111/crs.cpp
+++ b/src/iso19111/crs.cpp
@@ -94,7 +94,11 @@ struct CRS::Private {
BoundCRSPtr canonicalBoundCRS_{};
std::string extensionProj4_{};
bool implicitCS_ = false;
+
bool allowNonConformantWKT1Export_ = false;
+ // for what was initially a COMPD_CS with a VERT_CS with a datum type ==
+ // ellipsoidal height / 2002
+ VerticalCRSPtr originalVertCRS_{};
void setImplicitCS(const util::PropertyMap &properties) {
const auto pVal = properties.get("IMPLICIT_CS");
@@ -562,7 +566,7 @@ CRSNNPtr CRS::shallowClone() const { return _shallowClone(); }
//! @cond Doxygen_Suppress
CRSNNPtr CRS::allowNonConformantWKT1Export() const {
- auto crs = shallowClone();
+ auto crs(shallowClone());
crs->d->allowNonConformantWKT1Export_ = true;
return crs;
}
@@ -573,6 +577,26 @@ CRSNNPtr CRS::allowNonConformantWKT1Export() const {
//! @cond Doxygen_Suppress
+CRSNNPtr CRS::attachOriginalVertCRS(const VerticalCRSNNPtr &vertCRS) const {
+
+ const auto boundCRS = dynamic_cast<const BoundCRS *>(this);
+ if (boundCRS) {
+ return BoundCRS::create(
+ boundCRS->baseCRS()->attachOriginalVertCRS(vertCRS),
+ boundCRS->hubCRS(), boundCRS->transformation());
+ }
+
+ auto crs(shallowClone());
+ crs->d->originalVertCRS_ = vertCRS.as_nullable();
+ return crs;
+}
+
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
+
CRSNNPtr CRS::alterName(const std::string &newName) const {
auto crs = shallowClone();
auto newNameMod(newName);
@@ -1381,15 +1405,39 @@ void GeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const {
if (!isWKT2 && formatter->isStrict() && isGeographic &&
axisList.size() != 2 &&
oldAxisOutputRule != io::WKTFormatter::OutputAxisRule::NO) {
+
+ auto geogCRS2D = demoteTo2D(std::string(), dbContext);
+ if (dbContext) {
+ const auto res = geogCRS2D->identify(
+ io::AuthorityFactory::create(NN_NO_CHECK(dbContext), "EPSG"));
+ if (res.size() == 1) {
+ const auto &front = res.front();
+ if (front.second == 100) {
+ geogCRS2D = front.first;
+ }
+ }
+ }
+
if (CRS::getPrivate()->allowNonConformantWKT1Export_) {
formatter->startNode(io::WKTConstants::COMPD_CS, false);
formatter->addQuotedString(l_name + " + " + l_name);
- auto geogCRS = demoteTo2D(std::string(), dbContext);
- geogCRS->_exportToWKT(formatter);
- geogCRS->_exportToWKT(formatter);
+ geogCRS2D->_exportToWKT(formatter);
+ geogCRS2D->_exportToWKT(formatter);
+ formatter->endNode();
+ return;
+ }
+
+ auto &originalVertCRS = CRS::getPrivate()->originalVertCRS_;
+ if (originalVertCRS) {
+ formatter->startNode(io::WKTConstants::COMPD_CS, false);
+ formatter->addQuotedString(l_name + " + " +
+ originalVertCRS->nameStr());
+ geogCRS2D->_exportToWKT(formatter);
+ originalVertCRS->_exportToWKT(formatter);
formatter->endNode();
return;
}
+
io::FormattingException::Throw(
"WKT1 does not support Geographic 3D CRS.");
}
@@ -2047,6 +2095,7 @@ GeodeticCRS::_identify(const io::AuthorityFactoryPtr &authorityFactory) const {
//! @cond Doxygen_Suppress
struct GeographicCRS::Private {
cs::EllipsoidalCSNNPtr coordinateSystem_;
+
explicit Private(const cs::EllipsoidalCSNNPtr &csIn)
: coordinateSystem_(csIn) {}
};
@@ -3210,22 +3259,22 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const {
const auto &l_coordinateSystem = d->coordinateSystem();
const auto &axisList = l_coordinateSystem->axisList();
if (axisList.size() == 3 && !(isWKT2 && formatter->use2019Keywords())) {
+ auto projCRS2D = demoteTo2D(std::string(), dbContext);
+ if (dbContext) {
+ const auto res = projCRS2D->identify(
+ io::AuthorityFactory::create(NN_NO_CHECK(dbContext), "EPSG"));
+ if (res.size() == 1) {
+ const auto &front = res.front();
+ if (front.second == 100) {
+ projCRS2D = front.first;
+ }
+ }
+ }
+
if (!formatter->useESRIDialect() &&
CRS::getPrivate()->allowNonConformantWKT1Export_) {
formatter->startNode(io::WKTConstants::COMPD_CS, false);
formatter->addQuotedString(l_name + " + " + baseCRS()->nameStr());
- auto projCRS2D = demoteTo2D(std::string(), dbContext);
- if (dbContext) {
- const auto res =
- projCRS2D->identify(io::AuthorityFactory::create(
- NN_NO_CHECK(dbContext), "EPSG"));
- if (res.size() == 1) {
- const auto &front = res.front();
- if (front.second == 100) {
- projCRS2D = front.first;
- }
- }
- }
projCRS2D->_exportToWKT(formatter);
baseCRS()
->demoteTo2D(std::string(), dbContext)
@@ -3233,6 +3282,18 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const {
formatter->endNode();
return;
}
+
+ auto &originalVertCRS = CRS::getPrivate()->originalVertCRS_;
+ if (!formatter->useESRIDialect() && originalVertCRS) {
+ formatter->startNode(io::WKTConstants::COMPD_CS, false);
+ formatter->addQuotedString(l_name + " + " +
+ originalVertCRS->nameStr());
+ projCRS2D->_exportToWKT(formatter);
+ originalVertCRS->_exportToWKT(formatter);
+ formatter->endNode();
+ return;
+ }
+
io::FormattingException::Throw(
"Projected 3D CRS can only be exported since WKT2:2019");
}
@@ -4201,6 +4262,22 @@ CRSNNPtr CompoundCRS::createLax(const util::PropertyMap &properties,
"The 'vertical' geographic CRS is not equivalent to the "
"geographic CRS of the horizontal part");
}
+
+ // Detect a COMPD_CS whose VERT_CS is for ellipoidal heights
+ auto comp1Vert =
+ util::nn_dynamic_pointer_cast<VerticalCRS>(components[1]);
+ if (comp1Vert != nullptr && comp1Vert->datum() &&
+ comp1Vert->datum()->getWKT1DatumType() == "2002") {
+ const auto &axis = comp1Vert->coordinateSystem()->axisList()[0];
+ if (axis->unit()._isEquivalentTo(
+ common::UnitOfMeasure::METRE,
+ util::IComparable::Criterion::EQUIVALENT) &&
+ &(axis->direction()) == &(cs::AxisDirection::UP)) {
+ return components[0]
+ ->promoteTo3D(std::string(), dbContext)
+ ->attachOriginalVertCRS(NN_NO_CHECK(comp1Vert));
+ }
+ }
}
return create(properties, components);
diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp
index 03abb0d7..33eb81fa 100644
--- a/src/iso19111/datum.cpp
+++ b/src/iso19111/datum.cpp
@@ -1788,6 +1788,9 @@ operator=(const RealizationMethod &other) {
//! @cond Doxygen_Suppress
struct VerticalReferenceFrame::Private {
util::optional<RealizationMethod> realizationMethod_{};
+
+ // 2005 = CS_VD_GeoidModelDerived from OGC 01-009
+ std::string wkt1DatumType_{"2005"};
};
//! @endcond
@@ -1837,12 +1840,21 @@ VerticalReferenceFrameNNPtr VerticalReferenceFrame::create(
realizationMethodIn));
rf->setAnchor(anchor);
rf->setProperties(properties);
+ properties.getStringValue("VERT_DATUM_TYPE", rf->d->wkt1DatumType_);
return rf;
}
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+const std::string &VerticalReferenceFrame::getWKT1DatumType() const {
+ return d->wkt1DatumType_;
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
void VerticalReferenceFrame::_exportToWKT(
io::WKTFormatter *formatter) const // throw(FormattingException)
{
@@ -1861,7 +1873,7 @@ void VerticalReferenceFrame::_exportToWKT(
if (isWKT2) {
Datum::getPrivate()->exportAnchorDefinition(formatter);
} else if (!formatter->useESRIDialect()) {
- formatter->add(2005); // CS_VD_GeoidModelDerived from OGC 01-009
+ formatter->add(d->wkt1DatumType_);
const auto &extension = formatter->getVDatumExtension();
if (!extension.empty()) {
formatter->startNode(io::WKTConstants::EXTENSION, false);
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 9d9fa4a3..ebec053a 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -3944,9 +3944,18 @@ VerticalReferenceFrameNNPtr WKTParser::Private::buildVerticalReferenceFrame(
modelName);
}
- // WKT1 VERT_DATUM has a datum type after the datum name that we ignore.
- return VerticalReferenceFrame::create(buildProperties(node),
- getAnchor(node));
+ // WKT1 VERT_DATUM has a datum type after the datum name
+ const auto *nodeP = node->GP();
+ const std::string &name(nodeP->value());
+ auto &props = buildProperties(node);
+ if (ci_equal(name, WKTConstants::VERT_DATUM)) {
+ const auto &children = nodeP->children();
+ if (children.size() >= 2) {
+ props.set("VERT_DATUM_TYPE", children[1]->GP()->value());
+ }
+ }
+
+ return VerticalReferenceFrame::create(props, getAnchor(node));
}
// ---------------------------------------------------------------------------