aboutsummaryrefslogtreecommitdiff
path: root/src/iso19111/io.cpp
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-08-09 17:10:20 +0200
committerEven Rouault <even.rouault@spatialys.com>2019-08-09 17:41:23 +0200
commitf0d766e45640800412c08a7cb9ab4f8823d88d05 (patch)
tree1973086c9f52043d61fb1a71cbbc1c3a794c3afc /src/iso19111/io.cpp
parent81bd57dfd8cfae609288643d1b09a4805f1bcded (diff)
downloadPROJ-f0d766e45640800412c08a7cb9ab4f8823d88d05.tar.gz
PROJ-f0d766e45640800412c08a7cb9ab4f8823d88d05.zip
PROJSJON: add import/export of VerticalCRS, CompoundCRS, BoundCRS, Transformation and ConcatenatedOperation
Diffstat (limited to 'src/iso19111/io.cpp')
-rw-r--r--src/iso19111/io.cpp263
1 files changed, 255 insertions, 8 deletions
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index bcd14429..eadc54cc 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -4390,17 +4390,24 @@ class JSONParser {
static Measure getMeasure(const json &j);
ObjectDomainPtr buildObjectDomain(const json &j);
- PropertyMap buildProperties(const json &j);
+ PropertyMap buildProperties(const json &j, bool removeInverseOf = false);
GeographicCRSNNPtr buildGeographicCRS(const json &j);
GeodeticCRSNNPtr buildGeodeticCRS(const json &j);
ProjectedCRSNNPtr buildProjectedCRS(const json &j);
ConversionNNPtr buildConversion(const json &j);
GeodeticReferenceFrameNNPtr buildGeodeticReferenceFrame(const json &j);
+ VerticalReferenceFrameNNPtr buildVerticalReferenceFrame(const json &j);
EllipsoidNNPtr buildEllipsoid(const json &j);
PrimeMeridianNNPtr buildPrimeMeridian(const json &j);
CoordinateSystemNNPtr buildCS(const json &j);
CoordinateSystemAxisNNPtr buildAxis(const json &j);
+ VerticalCRSNNPtr buildVerticalCRS(const json &j);
+ CRSNNPtr buildCRS(const json &j);
+ CompoundCRSNNPtr buildCompoundCRS(const json &j);
+ BoundCRSNNPtr buildBoundCRS(const json &j);
+ TransformationNNPtr buildTransformation(const json &j);
+ ConcatenatedOperationNNPtr buildConcatenatedOperation(const json &j);
public:
JSONParser() = default;
@@ -4592,14 +4599,23 @@ ObjectDomainPtr JSONParser::buildObjectDomain(const json &j) {
// ---------------------------------------------------------------------------
-PropertyMap JSONParser::buildProperties(const json &j) {
+PropertyMap JSONParser::buildProperties(const json &j, bool removeInverseOf) {
PropertyMap map;
- map.set(IdentifiedObject::NAME_KEY, getName(j));
+ std::string name(getName(j));
+ if (removeInverseOf && starts_with(name, "Inverse of ")) {
+ name = name.substr(strlen("Inverse of "));
+ }
+ map.set(IdentifiedObject::NAME_KEY, name);
if (j.contains("id")) {
auto id = getObject(j, "id");
- map.set(metadata::Identifier::CODESPACE_KEY,
- getString(id, "authority"));
+ auto codeSpace(getString(id, "authority"));
+ if (removeInverseOf && starts_with(codeSpace, "INVERSE(") &&
+ codeSpace.back() == ')') {
+ codeSpace = codeSpace.substr(strlen("INVERSE("));
+ codeSpace.resize(codeSpace.size() - 1);
+ }
+ map.set(metadata::Identifier::CODESPACE_KEY, codeSpace);
if (!id.contains("code")) {
throw ParsingException("Missing \"code\" key");
}
@@ -4652,7 +4668,7 @@ PropertyMap JSONParser::buildProperties(const json &j) {
BaseObjectNNPtr JSONParser::create(const json &j)
{
- if (j.type() != json::value_t::object) {
+ if (!j.is_object()) {
throw ParsingException("JSON object expected");
}
auto type = getString(j, "type");
@@ -4665,9 +4681,21 @@ BaseObjectNNPtr JSONParser::create(const json &j)
if (type == "ProjectedCRS") {
return buildProjectedCRS(j);
}
+ if (type == "VerticalCRS") {
+ return buildVerticalCRS(j);
+ }
+ if (type == "CompoundCRS") {
+ return buildCompoundCRS(j);
+ }
+ if (type == "BoundCRS") {
+ return buildBoundCRS(j);
+ }
if (type == "GeodeticReferenceFrame") {
return buildGeodeticReferenceFrame(j);
}
+ if (type == "VerticalReferenceFrame") {
+ return buildVerticalReferenceFrame(j);
+ }
if (type == "Ellipsoid") {
return buildEllipsoid(j);
}
@@ -4677,6 +4705,15 @@ BaseObjectNNPtr JSONParser::create(const json &j)
if (type == "CoordinateSystem") {
return buildCS(j);
}
+ if (type == "Conversion") {
+ return buildConversion(j);
+ }
+ if (type == "Transformation") {
+ return buildTransformation(j);
+ }
+ if (type == "ConcatenatedOperation") {
+ return buildConcatenatedOperation(j);
+ }
throw ParsingException("Unsupported value of \"type\"");
}
@@ -4755,6 +4792,48 @@ ProjectedCRSNNPtr JSONParser::buildProjectedCRS(const json &j) {
// ---------------------------------------------------------------------------
+VerticalCRSNNPtr JSONParser::buildVerticalCRS(const json &j) {
+ auto datumJ = getObject(j, "datum");
+ if (getType(datumJ) != "VerticalReferenceFrame") {
+ throw ParsingException("Unsupported type for datum.");
+ }
+ auto datum = buildVerticalReferenceFrame(datumJ);
+ auto csJ = getObject(j, "coordinate_system");
+ auto verticalCS = util::nn_dynamic_pointer_cast<VerticalCS>(buildCS(csJ));
+ if (!verticalCS) {
+ throw ParsingException("expected a vertical CS");
+ }
+ return VerticalCRS::create(buildProperties(j), datum,
+ NN_NO_CHECK(verticalCS));
+}
+
+// ---------------------------------------------------------------------------
+
+CRSNNPtr JSONParser::buildCRS(const json &j) {
+ auto crs = util::nn_dynamic_pointer_cast<CRS>(create(j));
+ if (crs) {
+ return NN_NO_CHECK(crs);
+ }
+ throw ParsingException("Object is not a CRS");
+}
+
+// ---------------------------------------------------------------------------
+
+CompoundCRSNNPtr JSONParser::buildCompoundCRS(const json &j) {
+ auto componentsJ = getArray(j, "components");
+ std::vector<CRSNNPtr> components;
+ for (const auto &componentJ : componentsJ) {
+ if (!componentJ.is_object()) {
+ throw ParsingException(
+ "Unexpected type for a \"components\" child");
+ }
+ components.push_back(buildCRS(componentJ));
+ }
+ return CompoundCRS::create(buildProperties(j), components);
+}
+
+// ---------------------------------------------------------------------------
+
ConversionNNPtr JSONParser::buildConversion(const json &j) {
auto methodJ = getObject(j, "method");
auto convProps = buildProperties(j);
@@ -4775,11 +4854,152 @@ ConversionNNPtr JSONParser::buildConversion(const json &j) {
OperationParameter::create(buildProperties(param)));
values.emplace_back(ParameterValue::create(getMeasure(param)));
}
+
+ 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(j, true);
+ auto invMethodProps = buildProperties(methodJ, 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);
}
// ---------------------------------------------------------------------------
+BoundCRSNNPtr JSONParser::buildBoundCRS(const json &j) {
+
+ auto sourceCRS = buildCRS(getObject(j, "source_crs"));
+ auto targetCRS = buildCRS(getObject(j, "target_crs"));
+ auto transformationJ = getObject(j, "transformation");
+ auto methodJ = getObject(transformationJ, "method");
+ auto parametersJ = getArray(transformationJ, "parameters");
+ std::vector<OperationParameterNNPtr> parameters;
+ std::vector<ParameterValueNNPtr> values;
+ for (const auto &param : parametersJ) {
+ if (!param.is_object()) {
+ throw ParsingException(
+ "Unexpected type for a \"parameters\" child");
+ }
+ parameters.emplace_back(
+ OperationParameter::create(buildProperties(param)));
+ if (param.contains("value")) {
+ auto v = param["value"];
+ if (v.is_string()) {
+ values.emplace_back(
+ ParameterValue::createFilename(v.get<std::string>()));
+ continue;
+ }
+ }
+ values.emplace_back(ParameterValue::create(getMeasure(param)));
+ }
+
+ CRSPtr sourceTransformationCRS;
+ if (dynamic_cast<GeographicCRS *>(targetCRS.get())) {
+ sourceTransformationCRS = sourceCRS->extractGeographicCRS();
+ if (!sourceTransformationCRS) {
+ sourceTransformationCRS =
+ std::dynamic_pointer_cast<VerticalCRS>(sourceCRS.as_nullable());
+ if (!sourceTransformationCRS) {
+ throw ParsingException(
+ "Cannot find GeographicCRS or VerticalCRS in sourceCRS");
+ }
+ }
+ } else {
+ sourceTransformationCRS = sourceCRS;
+ }
+
+ auto transformation = Transformation::create(
+ buildProperties(transformationJ), NN_NO_CHECK(sourceTransformationCRS),
+ targetCRS, nullptr, buildProperties(methodJ), parameters, values,
+ std::vector<PositionalAccuracyNNPtr>());
+
+ return BoundCRS::create(sourceCRS, targetCRS, transformation);
+}
+
+// ---------------------------------------------------------------------------
+
+TransformationNNPtr JSONParser::buildTransformation(const json &j) {
+
+ auto sourceCRS = buildCRS(getObject(j, "source_crs"));
+ auto targetCRS = buildCRS(getObject(j, "target_crs"));
+ auto methodJ = getObject(j, "method");
+ auto parametersJ = getArray(j, "parameters");
+ std::vector<OperationParameterNNPtr> parameters;
+ std::vector<ParameterValueNNPtr> values;
+ for (const auto &param : parametersJ) {
+ if (!param.is_object()) {
+ throw ParsingException(
+ "Unexpected type for a \"parameters\" child");
+ }
+ parameters.emplace_back(
+ OperationParameter::create(buildProperties(param)));
+ if (param.contains("value")) {
+ auto v = param["value"];
+ if (v.is_string()) {
+ values.emplace_back(
+ ParameterValue::createFilename(v.get<std::string>()));
+ continue;
+ }
+ }
+ values.emplace_back(ParameterValue::create(getMeasure(param)));
+ }
+ CRSPtr interpolationCRS;
+ if (j.contains("interpolation_crs")) {
+ interpolationCRS =
+ buildCRS(getObject(j, "interpolation_crs")).as_nullable();
+ }
+ std::vector<PositionalAccuracyNNPtr> accuracies;
+ if (j.contains("accuracy")) {
+ accuracies.push_back(
+ PositionalAccuracy::create(getString(j, "accuracy")));
+ }
+
+ return Transformation::create(buildProperties(j), sourceCRS, targetCRS,
+ interpolationCRS, buildProperties(methodJ),
+ parameters, values, accuracies);
+}
+
+// ---------------------------------------------------------------------------
+
+ConcatenatedOperationNNPtr
+JSONParser::buildConcatenatedOperation(const json &j) {
+
+ auto sourceCRS = buildCRS(getObject(j, "source_crs"));
+ auto targetCRS = buildCRS(getObject(j, "target_crs"));
+ auto stepsJ = getArray(j, "steps");
+ std::vector<CoordinateOperationNNPtr> operations;
+ for (const auto &stepJ : stepsJ) {
+ if (!stepJ.is_object()) {
+ throw ParsingException("Unexpected type for a \"steps\" child");
+ }
+ auto op = nn_dynamic_pointer_cast<CoordinateOperation>(create(stepJ));
+ if (!op) {
+ throw ParsingException("Invalid content in a \"steps\" child");
+ }
+ operations.emplace_back(NN_NO_CHECK(op));
+ }
+
+ ConcatenatedOperation::fixStepsDirection(sourceCRS, targetCRS, operations);
+
+ try {
+ return ConcatenatedOperation::create(
+ buildProperties(j), operations,
+ std::vector<PositionalAccuracyNNPtr>());
+ } catch (const InvalidOperation &e) {
+ throw ParsingException(
+ std::string("Cannot build concatenated operation: ") + e.what());
+ }
+}
+
+// ---------------------------------------------------------------------------
+
CoordinateSystemAxisNNPtr JSONParser::buildAxis(const json &j) {
auto dirString = getString(j, "direction");
auto abbreviation = getString(j, "abbreviation");
@@ -4884,9 +5104,23 @@ JSONParser::buildGeodeticReferenceFrame(const json &j) {
auto pm = j.contains("prime_meridian")
? buildPrimeMeridian(getObject(j, "prime_meridian"))
: PrimeMeridian::GREENWICH;
+ optional<std::string> anchor;
+ if (j.contains("anchor")) {
+ anchor = getString(j, "anchor");
+ }
return GeodeticReferenceFrame::create(
- buildProperties(j), buildEllipsoid(ellipsoidJ),
- optional<std::string>() /* anchor */, pm);
+ buildProperties(j), buildEllipsoid(ellipsoidJ), anchor, pm);
+}
+
+// ---------------------------------------------------------------------------
+
+VerticalReferenceFrameNNPtr
+JSONParser::buildVerticalReferenceFrame(const json &j) {
+ optional<std::string> anchor;
+ if (j.contains("anchor")) {
+ anchor = getString(j, "anchor");
+ }
+ return VerticalReferenceFrame::create(buildProperties(j), anchor);
}
// ---------------------------------------------------------------------------
@@ -8605,6 +8839,7 @@ struct JSONFormatter::Private {
std::vector<bool> outputIdStack_{true};
bool allowIDInImmediateChild_ = false;
bool omitTypeInImmediateChild_ = false;
+ bool abridgedTransformation_ = false;
std::string result_{};
@@ -8717,6 +8952,18 @@ JSONFormatter::ObjectContext::~ObjectContext() {
m_formatter.d->popOutputId();
}
+// ---------------------------------------------------------------------------
+
+void JSONFormatter::setAbridgedTransformation(bool outputIn) {
+ d->abridgedTransformation_ = outputIn;
+}
+
+// ---------------------------------------------------------------------------
+
+bool JSONFormatter::abridgedTransformation() const {
+ return d->abridgedTransformation_;
+}
+
//! @endcond
// ---------------------------------------------------------------------------