aboutsummaryrefslogtreecommitdiff
path: root/src/iso19111/io.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/iso19111/io.cpp')
-rw-r--r--src/iso19111/io.cpp73
1 files changed, 62 insertions, 11 deletions
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 4ca5a7f0..6a2c3e1a 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -1153,9 +1153,11 @@ struct WKTParser::Private {
BaseObjectNNPtr build(const WKTNodeNNPtr &node);
- IdentifierPtr buildId(const WKTNodeNNPtr &node, bool tolerant = true);
+ IdentifierPtr buildId(const WKTNodeNNPtr &node, bool tolerant,
+ bool removeInverseOf);
- PropertyMap &buildProperties(const WKTNodeNNPtr &node);
+ PropertyMap &buildProperties(const WKTNodeNNPtr &node,
+ bool removeInverseOf = false);
ObjectDomainPtr buildObjectDomain(const WKTNodeNNPtr &node);
@@ -1396,11 +1398,16 @@ double WKTParser::Private::asDouble(const WKTNodeNNPtr &node) {
// ---------------------------------------------------------------------------
IdentifierPtr WKTParser::Private::buildId(const WKTNodeNNPtr &node,
- bool tolerant) {
+ bool tolerant, bool removeInverseOf) {
const auto *nodeP = node->GP();
const auto &nodeChidren = nodeP->children();
if (nodeChidren.size() >= 2) {
auto codeSpace = stripQuotes(nodeChidren[0]);
+ if (removeInverseOf && starts_with(codeSpace, "INVERSE(") &&
+ codeSpace.back() == ')') {
+ codeSpace = codeSpace.substr(strlen("INVERSE("));
+ codeSpace.resize(codeSpace.size() - 1);
+ }
auto code = stripQuotes(nodeChidren[1]);
auto &citationNode = nodeP->lookForChild(WKTConstants::CITATION);
auto &uriNode = nodeP->lookForChild(WKTConstants::URI);
@@ -1444,7 +1451,8 @@ IdentifierPtr WKTParser::Private::buildId(const WKTNodeNNPtr &node,
// ---------------------------------------------------------------------------
-PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node) {
+PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node,
+ bool removeInverseOf) {
if (propertyCount_ == MAX_PROPERTY_SIZE) {
throw ParsingException("MAX_PROPERTY_SIZE reached");
@@ -1460,6 +1468,10 @@ PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node) {
if (!nodeChildren.empty()) {
const auto &nodeName(nodeP->value());
auto name(stripQuotes(nodeChildren[0]));
+ if (removeInverseOf && starts_with(name, "Inverse of ")) {
+ name = name.substr(strlen("Inverse of "));
+ }
+
if (ends_with(name, " (deprecated)")) {
name.resize(name.size() - strlen(" (deprecated)"));
properties->set(common::IdentifiedObject::DEPRECATED_KEY, true);
@@ -1512,7 +1524,7 @@ PropertyMap &WKTParser::Private::buildProperties(const WKTNodeNNPtr &node) {
const auto &subNodeName(subNode->GP()->value());
if (ci_equal(subNodeName, WKTConstants::ID) ||
ci_equal(subNodeName, WKTConstants::AUTHORITY)) {
- auto id = buildId(subNode);
+ auto id = buildId(subNode, true, removeInverseOf);
if (id) {
identifiers->add(NN_NO_CHECK(id));
}
@@ -1990,7 +2002,7 @@ GeodeticReferenceFrameNNPtr WKTParser::Private::buildGeodeticReferenceFrame(
auto &idNode = nodeP->lookForChild(WKTConstants::AUTHORITY);
if (!isNull(idNode)) {
try {
- auto id = buildId(idNode);
+ auto id = buildId(idNode, true, false);
auto authFactory2 = AuthorityFactory::create(
NN_NO_CHECK(dbContext_), *id->codeSpace());
auto dbDatum =
@@ -2850,8 +2862,22 @@ WKTParser::Private::buildConversion(const WKTNodeNNPtr &node,
consumeParameters(node, false, parameters, values, defaultLinearUnit,
defaultAngularUnit);
- return Conversion::create(buildProperties(node),
- buildProperties(methodNode), parameters, values);
+ auto &convProps = buildProperties(node);
+ auto &methodProps = buildProperties(methodNode);
+ std::string convName;
+ std::string methodName;
+ if (convProps.getStringValue(IdentifiedObject::NAME_KEY, convName) &&
+ methodProps.getStringValue(IdentifiedObject::NAME_KEY, methodName) &&
+ starts_with(convName, "Inverse of ") &&
+ starts_with(methodName, "Inverse of ")) {
+
+ auto &invConvProps = buildProperties(node, true);
+ auto &invMethodProps = buildProperties(methodNode, true);
+ return NN_NO_CHECK(util::nn_dynamic_pointer_cast<Conversion>(
+ Conversion::create(invConvProps, invMethodProps, parameters, values)
+ ->inverse()));
+ }
+ return Conversion::create(convProps, methodProps, parameters, values);
}
// ---------------------------------------------------------------------------
@@ -2918,8 +2944,28 @@ WKTParser::Private::buildCoordinateOperation(const WKTNodeNNPtr &node) {
ConcatenatedOperationNNPtr
WKTParser::Private::buildConcatenatedOperation(const WKTNodeNNPtr &node) {
+
+ const auto *nodeP = node->GP();
+ auto &sourceCRSNode = nodeP->lookForChild(WKTConstants::SOURCECRS);
+ if (/*isNull(sourceCRSNode) ||*/ sourceCRSNode->GP()->childrenSize() != 1) {
+ ThrowMissing(WKTConstants::SOURCECRS);
+ }
+ auto sourceCRS = buildCRS(sourceCRSNode->GP()->children()[0]);
+ if (!sourceCRS) {
+ throw ParsingException("Invalid content in SOURCECRS node");
+ }
+
+ auto &targetCRSNode = nodeP->lookForChild(WKTConstants::TARGETCRS);
+ if (/*isNull(targetCRSNode) ||*/ targetCRSNode->GP()->childrenSize() != 1) {
+ ThrowMissing(WKTConstants::TARGETCRS);
+ }
+ auto targetCRS = buildCRS(targetCRSNode->GP()->children()[0]);
+ if (!targetCRS) {
+ throw ParsingException("Invalid content in TARGETCRS node");
+ }
+
std::vector<CoordinateOperationNNPtr> operations;
- for (const auto &childNode : node->GP()->children()) {
+ for (const auto &childNode : nodeP->children()) {
if (ci_equal(childNode->GP()->value(), WKTConstants::STEP)) {
if (childNode->GP()->childrenSize() != 1) {
throw ParsingException("Invalid content in STEP node");
@@ -2932,6 +2978,10 @@ WKTParser::Private::buildConcatenatedOperation(const WKTNodeNNPtr &node) {
operations.emplace_back(NN_NO_CHECK(op));
}
}
+
+ ConcatenatedOperation::fixStepsDirection(
+ NN_NO_CHECK(sourceCRS), NN_NO_CHECK(targetCRS), operations);
+
try {
return ConcatenatedOperation::create(
buildProperties(node), operations,
@@ -4213,7 +4263,7 @@ BaseObjectNNPtr WKTParser::Private::build(const WKTNodeNNPtr &node) {
if (ci_equal(name, WKTConstants::ID) ||
ci_equal(name, WKTConstants::AUTHORITY)) {
return util::nn_static_pointer_cast<BaseObject>(
- NN_NO_CHECK(buildId(node, false)));
+ NN_NO_CHECK(buildId(node, false, false)));
}
throw ParsingException(concat("unhandled keyword: ", name));
@@ -5914,7 +5964,8 @@ PROJStringParser::Private::buildDatum(const Step &step,
PropertyMap grfMap;
// It is arguable that we allow the prime meridian of a datum defined by
- // its name to be overridden, but this is found at least in a regression test
+ // its name to be overridden, but this is found at least in a regression
+ // test
// of GDAL. So let's keep the ellipsoid part of the datum in that case and
// use the specified prime meridian.
const auto overridePmIfNeeded =