aboutsummaryrefslogtreecommitdiff
path: root/src/iso19111
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-07-06 17:06:23 +0200
committerEven Rouault <even.rouault@spatialys.com>2019-07-08 00:05:00 +0200
commitece151aed1b4bf2634de5759f37fd7bc005e8313 (patch)
tree8e2e38daaffc878cc3ba673857e66274555e3dcc /src/iso19111
parent17f0b0b3bc65ffba39bf6f22a12b2cc7fcb9bafd (diff)
downloadPROJ-ece151aed1b4bf2634de5759f37fd7bc005e8313.tar.gz
PROJ-ece151aed1b4bf2634de5759f37fd7bc005e8313.zip
CRS JSON: export GeographicCRS and Projected CRS
Diffstat (limited to 'src/iso19111')
-rw-r--r--src/iso19111/common.cpp84
-rw-r--r--src/iso19111/coordinateoperation.cpp85
-rw-r--r--src/iso19111/coordinatesystem.cpp59
-rw-r--r--src/iso19111/crs.cpp160
-rw-r--r--src/iso19111/datum.cpp106
-rw-r--r--src/iso19111/io.cpp61
-rw-r--r--src/iso19111/metadata.cpp2
7 files changed, 541 insertions, 16 deletions
diff --git a/src/iso19111/common.cpp b/src/iso19111/common.cpp
index f2a51032..fb7a63c0 100644
--- a/src/iso19111/common.cpp
+++ b/src/iso19111/common.cpp
@@ -243,7 +243,9 @@ void UnitOfMeasure::_exportToJSON(
JSONFormatter *formatter) const // throw(FormattingException)
{
auto &writer = formatter->writer();
- PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer);
+ const auto &l_codeSpace = codeSpace();
+ auto objContext(
+ formatter->MakeObjectContext(nullptr, !l_codeSpace.empty()));
writer.AddObjKey("type");
const auto l_type = type();
if (l_type == Type::LINEAR) {
@@ -268,10 +270,9 @@ void UnitOfMeasure::_exportToJSON(
writer.AddObjKey("conversion_factor");
writer.Add(factor, 15);
- const auto &l_codeSpace = codeSpace();
if (!l_codeSpace.empty() && formatter->outputId()) {
writer.AddObjKey("id");
- PROJ::CPLJSonStreamingWriter::ObjectContext idContext(writer);
+ auto idContext(formatter->MakeObjectContext(nullptr, false));
writer.AddObjKey("authority");
writer.Add(l_codeSpace);
writer.AddObjKey("code");
@@ -871,7 +872,7 @@ void IdentifiedObject::formatID(JSONFormatter *formatter) const {
ids.front()->_exportToJSON(formatter);
} else if (!ids.empty()) {
writer.AddObjKey("ids");
- PROJ::CPLJSonStreamingWriter::ArrayContext arrayContext(writer);
+ auto arrayContext(writer.MakeArrayContext());
for (const auto &id : ids) {
id->_exportToJSON(formatter);
}
@@ -880,6 +881,16 @@ void IdentifiedObject::formatID(JSONFormatter *formatter) const {
// ---------------------------------------------------------------------------
+void IdentifiedObject::formatRemarks(JSONFormatter *formatter) const {
+ if (!remarks().empty()) {
+ auto &writer = formatter->writer();
+ writer.AddObjKey("remarks");
+ writer.Add(remarks());
+ }
+}
+
+// ---------------------------------------------------------------------------
+
bool IdentifiedObject::_isEquivalentTo(
const util::IComparable *other,
util::IComparable::Criterion criterion) const {
@@ -1031,6 +1042,46 @@ void ObjectDomain::_exportToWKT(WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void ObjectDomain::_exportToJSON(JSONFormatter *formatter) const {
+ auto &writer = formatter->writer();
+ if (d->scope_.has_value()) {
+ writer.AddObjKey("scope");
+ writer.Add(*(d->scope_));
+ }
+ if (d->domainOfValidity_) {
+ if (d->domainOfValidity_->description().has_value()) {
+ writer.AddObjKey("area");
+ writer.Add(*(d->domainOfValidity_->description()));
+ }
+ if (d->domainOfValidity_->geographicElements().size() == 1) {
+ const auto bbox = dynamic_cast<const GeographicBoundingBox *>(
+ d->domainOfValidity_->geographicElements()[0].get());
+ if (bbox) {
+ writer.AddObjKey("bbox");
+ auto bboxContext(writer.MakeObjectContext());
+ writer.AddObjKey("south_latitude");
+ writer.Add(bbox->southBoundLatitude(), 15);
+ writer.AddObjKey("west_longitude");
+ writer.Add(bbox->westBoundLongitude(), 15);
+ writer.AddObjKey("north_latitude");
+ writer.Add(bbox->northBoundLatitude(), 15);
+ writer.AddObjKey("east_longitude");
+ writer.Add(bbox->eastBoundLongitude(), 15);
+ }
+ }
+ if (d->domainOfValidity_->verticalElements().size() == 1) {
+ // TODO
+ }
+ if (d->domainOfValidity_->temporalElements().size() == 1) {
+ // TODO
+ }
+ }
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
bool ObjectDomain::_isEquivalentTo(
const util::IComparable *other,
util::IComparable::Criterion criterion) const {
@@ -1162,6 +1213,31 @@ void ObjectUsage::baseExportToWKT(WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
+void ObjectUsage::baseExportToJSON(JSONFormatter *formatter) const {
+
+ auto &writer = formatter->writer();
+ if (formatter->outputUsage()) {
+ const auto &l_domains = domains();
+ if (l_domains.size() == 1) {
+ l_domains[0]->_exportToJSON(formatter);
+ } else if (!l_domains.empty()) {
+ writer.AddObjKey("usages");
+ auto arrayContext(writer.MakeArrayContext(false));
+ for (const auto &domain : l_domains) {
+ auto objContext(writer.MakeObjectContext());
+ domain->_exportToJSON(formatter);
+ }
+ }
+ }
+
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+ formatRemarks(formatter);
+}
+
+// ---------------------------------------------------------------------------
+
//! @cond Doxygen_Suppress
bool ObjectUsage::_isEquivalentTo(
const util::IComparable *other,
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index 7f3a2137..a2a31edd 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -991,6 +991,24 @@ void OperationMethod::_exportToWKT(io::WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void OperationMethod::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(formatter->MakeObjectContext("OperationMethod",
+ !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ writer.Add(nameStr());
+
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
bool OperationMethod::_isEquivalentTo(
const util::IComparable *other,
util::IComparable::Criterion criterion) const {
@@ -1168,6 +1186,35 @@ void OperationParameterValue::_exportToWKT(io::WKTFormatter *formatter,
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void OperationParameterValue::_exportToJSON(
+ io::JSONFormatter *formatter) const {
+ auto &writer = formatter->writer();
+ auto objectContext(formatter->MakeObjectContext(
+ "ParameterValue", !parameter()->identifiers().empty()));
+
+ writer.AddObjKey("name");
+ writer.Add(parameter()->nameStr());
+
+ const auto &l_value(parameterValue());
+ if (l_value->type() == ParameterValue::Type::MEASURE) {
+ writer.AddObjKey("value");
+ writer.Add(l_value->value().value(), 15);
+ writer.AddObjKey("unit");
+ l_value->value().unit()._exportToJSON(formatter);
+ } else if (l_value->type() == ParameterValue::Type::FILENAME) {
+ writer.AddObjKey("value");
+ writer.Add(l_value->valueFile());
+ }
+
+ if (formatter->outputId()) {
+ parameter()->formatID(formatter);
+ }
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
/** Utility method used on WKT2 import to convert from abridged transformation
* to "normal" transformation parameters.
@@ -5410,6 +5457,44 @@ void Conversion::_exportToWKT(io::WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void Conversion::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(
+ formatter->MakeObjectContext("Conversion", !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ writer.AddObjKey("method");
+ formatter->setAllowIDInImmediateChild();
+ method()->_exportToJSON(formatter);
+
+ writer.AddObjKey("parameters");
+ {
+ auto parametersContext(writer.MakeArrayContext(false));
+ for (const auto &genOpParamvalue : parameterValues()) {
+ formatter->setAllowIDInImmediateChild();
+ genOpParamvalue->_exportToJSON(formatter);
+ }
+ }
+
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+}
+
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
static bool createPROJ4WebMercator(const Conversion *conv,
io::PROJStringFormatter *formatter) {
const double centralMeridian = conv->parameterValueNumeric(
diff --git a/src/iso19111/coordinatesystem.cpp b/src/iso19111/coordinatesystem.cpp
index ef9cac93..f96a962f 100644
--- a/src/iso19111/coordinatesystem.cpp
+++ b/src/iso19111/coordinatesystem.cpp
@@ -311,8 +311,8 @@ void CoordinateSystemAxis::_exportToWKT(io::WKTFormatter *formatter, int order,
bool disableAbbrev) const {
const bool isWKT2 = formatter->version() == io::WKTFormatter::Version::WKT2;
formatter->startNode(io::WKTConstants::AXIS, !identifiers().empty());
- std::string axisName = *(name()->description());
- std::string abbrev = abbreviation();
+ const std::string &axisName = nameStr();
+ const std::string &abbrev = abbreviation();
std::string parenthesizedAbbrev = "(" + abbrev + ")";
std::string dir = direction().toString();
std::string axisDesignation;
@@ -393,6 +393,34 @@ void CoordinateSystemAxis::_exportToWKT(io::WKTFormatter *formatter, int order,
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void CoordinateSystemAxis::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(
+ formatter->MakeObjectContext("Axis", !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ writer.Add(nameStr());
+
+ writer.AddObjKey("abbreviation");
+ writer.Add(abbreviation());
+
+ writer.AddObjKey("direction");
+ writer.Add(direction().toString());
+
+ writer.AddObjKey("unit");
+ unit()._exportToJSON(formatter);
+
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
bool CoordinateSystemAxis::_isEquivalentTo(
const util::IComparable *other,
util::IComparable::Criterion criterion) const {
@@ -535,6 +563,33 @@ void CoordinateSystem::_exportToWKT(
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void CoordinateSystem::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(formatter->MakeObjectContext("CoordinateSystem",
+ !identifiers().empty()));
+
+ writer.AddObjKey("subtype");
+ writer.Add(getWKT2Type(true));
+
+ writer.AddObjKey("axis");
+ auto axisContext(writer.MakeArrayContext(false));
+ const auto &l_axisList = axisList();
+ for (auto &axis : l_axisList) {
+ axis->_exportToJSON(formatter);
+ }
+
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+}
+
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
bool CoordinateSystem::_isEquivalentTo(
const util::IComparable *other,
util::IComparable::Criterion criterion) const {
diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp
index 476bc72b..2ca2786d 100644
--- a/src/iso19111/crs.cpp
+++ b/src/iso19111/crs.cpp
@@ -1342,6 +1342,39 @@ void GeodeticCRS::addDatumInfoToPROJString(
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void GeodeticCRS::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(io::FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(
+ formatter->MakeObjectContext("GeodeticCRS", !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ const auto &l_datum(datum());
+ if (l_datum) {
+ writer.AddObjKey("datum");
+ l_datum->_exportToJSON(formatter);
+ } else {
+ // TODO DatumEnsemble
+ }
+
+ writer.AddObjKey("coordinate_system");
+ coordinateSystem()->_exportToJSON(formatter);
+
+ ObjectUsage::baseExportToJSON(formatter);
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
static util::IComparable::Criterion
getStandardCriterion(util::IComparable::Criterion criterion) {
return criterion == util::IComparable::Criterion::
@@ -2059,6 +2092,39 @@ void GeographicCRS::_exportToPROJString(
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void GeographicCRS::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(io::FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(
+ formatter->MakeObjectContext("GeographicCRS", !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ const auto &l_datum(datum());
+ if (l_datum) {
+ writer.AddObjKey("datum");
+ l_datum->_exportToJSON(formatter);
+ } else {
+ // TODO DatumEnsemble
+ }
+
+ writer.AddObjKey("coordinate_system");
+ coordinateSystem()->_exportToJSON(formatter);
+
+ ObjectUsage::baseExportToJSON(formatter);
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
struct VerticalCRS::Private {
std::vector<operation::TransformationNNPtr> geoidModel{};
std::vector<operation::PointMotionOperationNNPtr> velocityModel{};
@@ -2856,6 +2922,38 @@ void ProjectedCRS::_exportToWKT(io::WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
+//! @cond Doxygen_Suppress
+void ProjectedCRS::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(io::FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(
+ formatter->MakeObjectContext("ProjectedCRS", !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ writer.AddObjKey("base_crs");
+ formatter->setAllowIDInImmediateChild();
+ baseCRS()->_exportToJSON(formatter);
+
+ writer.AddObjKey("conversion");
+ derivingConversionRef()->_exportToJSON(formatter);
+
+ writer.AddObjKey("coordinate_system");
+ coordinateSystem()->_exportToJSON(formatter);
+
+ ObjectUsage::baseExportToJSON(formatter);
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
void ProjectedCRS::_exportToPROJString(
io::PROJStringFormatter *formatter) const // throw(io::FormattingException)
{
@@ -4195,6 +4293,37 @@ void DerivedGeodeticCRS::_exportToWKT(io::WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
+//! @cond Doxygen_Suppress
+void DerivedGeodeticCRS::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(io::FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(formatter->MakeObjectContext("DerivedGeodeticCRS",
+ !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ writer.AddObjKey("base_crs");
+ baseCRS()->_exportToJSON(formatter);
+
+ writer.AddObjKey("conversion");
+ derivingConversionRef()->_exportToJSON(formatter);
+
+ writer.AddObjKey("coordinate_system");
+ coordinateSystem()->_exportToJSON(formatter);
+
+ ObjectUsage::baseExportToJSON(formatter);
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
void DerivedGeodeticCRS::_exportToPROJString(
io::PROJStringFormatter *) const // throw(io::FormattingException)
{
@@ -4333,6 +4462,37 @@ void DerivedGeographicCRS::_exportToWKT(io::WKTFormatter *formatter) const {
// ---------------------------------------------------------------------------
+//! @cond Doxygen_Suppress
+void DerivedGeographicCRS::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(io::FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(formatter->MakeObjectContext("DerivedGeographicCRS",
+ !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ writer.AddObjKey("base_crs");
+ baseCRS()->_exportToJSON(formatter);
+
+ writer.AddObjKey("conversion");
+ derivingConversionRef()->_exportToJSON(formatter);
+
+ writer.AddObjKey("coordinate_system");
+ coordinateSystem()->_exportToJSON(formatter);
+
+ ObjectUsage::baseExportToJSON(formatter);
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
void DerivedGeographicCRS::_exportToPROJString(
io::PROJStringFormatter *) const // throw(io::FormattingException)
{
diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp
index 6ba219d4..89ecc755 100644
--- a/src/iso19111/datum.cpp
+++ b/src/iso19111/datum.cpp
@@ -93,6 +93,9 @@ struct Datum::Private {
// cppcheck-suppress functionStatic
void exportAnchorDefinition(io::WKTFormatter *formatter) const;
+
+ // cppcheck-suppress functionStatic
+ void exportAnchorDefinition(io::JSONFormatter *formatter) const;
};
// ---------------------------------------------------------------------------
@@ -105,6 +108,17 @@ void Datum::Private::exportAnchorDefinition(io::WKTFormatter *formatter) const {
}
}
+// ---------------------------------------------------------------------------
+
+void Datum::Private::exportAnchorDefinition(
+ io::JSONFormatter *formatter) const {
+ if (anchorDefinition) {
+ auto &writer = formatter->writer();
+ writer.AddObjKey("anchor");
+ writer.Add(*anchorDefinition);
+ }
+}
+
//! @endcond
// ---------------------------------------------------------------------------
@@ -352,10 +366,8 @@ void PrimeMeridian::_exportToJSON(
io::JSONFormatter *formatter) const // throw(FormattingException)
{
auto &writer = formatter->writer();
- PROJ::CPLJSonStreamingWriter::ObjectContext objectContext(writer);
-
- writer.AddObjKey("type");
- writer.Add("PrimeMeridian");
+ auto objectContext(
+ formatter->MakeObjectContext("PrimeMeridian", !identifiers().empty()));
writer.AddObjKey("name");
std::string l_name =
@@ -365,7 +377,7 @@ void PrimeMeridian::_exportToJSON(
const auto &l_long = longitude();
writer.AddObjKey("longitude");
{
- PROJ::CPLJSonStreamingWriter::ObjectContext longitudeContext(writer);
+ auto longitudeContext(formatter->MakeObjectContext(nullptr, false));
writer.AddObjKey("value");
writer.Add(l_long.value(), 15);
@@ -803,6 +815,60 @@ void Ellipsoid::_exportToWKT(
// ---------------------------------------------------------------------------
+//! @cond Doxygen_Suppress
+void Ellipsoid::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto &writer = formatter->writer();
+ auto objectContext(
+ formatter->MakeObjectContext("Ellipsoid", !identifiers().empty()));
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ const auto &semiMajor = semiMajorAxis();
+ const auto &semiMajorUnit = semiMajor.unit();
+ writer.AddObjKey(isSphere() ? "radius" : "semi_major_axis");
+ {
+ auto objContext(formatter->MakeObjectContext(nullptr, false));
+ writer.AddObjKey("value");
+ writer.Add(semiMajor.value(), 15);
+
+ writer.AddObjKey("unit");
+ semiMajorUnit._exportToJSON(formatter);
+ }
+
+ if (!isSphere()) {
+ const auto &l_inverseFlattening = inverseFlattening();
+ if (l_inverseFlattening.has_value()) {
+ writer.AddObjKey("inverse_flattening");
+ writer.Add(l_inverseFlattening->getSIValue(), 15);
+ } else {
+ writer.AddObjKey("semi_minor_axis");
+ {
+ auto objContext(formatter->MakeObjectContext(nullptr, false));
+ writer.AddObjKey("value");
+ writer.Add(semiMinorAxis()->value(), 15);
+
+ writer.AddObjKey("unit");
+ semiMinorAxis()->unit()._exportToJSON(formatter);
+ }
+ }
+ }
+
+ if (formatter->outputId()) {
+ formatID(formatter);
+ }
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
bool Ellipsoid::lookForProjWellKnownEllps(std::string &projEllpsName,
std::string &ellpsName) const {
const double a = semiMajorAxis().getSIValue();
@@ -1188,6 +1254,36 @@ void GeodeticReferenceFrame::_exportToWKT(
// ---------------------------------------------------------------------------
//! @cond Doxygen_Suppress
+void GeodeticReferenceFrame::_exportToJSON(
+ io::JSONFormatter *formatter) const // throw(FormattingException)
+{
+ auto objectContext(formatter->MakeObjectContext("GeodeticReferenceFrame",
+ !identifiers().empty()));
+ auto &writer = formatter->writer();
+
+ writer.AddObjKey("name");
+ auto l_name = nameStr();
+ if (l_name.empty()) {
+ writer.Add("unnamed");
+ } else {
+ writer.Add(l_name);
+ }
+
+ Datum::getPrivate()->exportAnchorDefinition(formatter);
+
+ writer.AddObjKey("ellipsoid");
+ ellipsoid()->_exportToJSON(formatter);
+
+ writer.AddObjKey("prime_meridian");
+ primeMeridian()->_exportToJSON(formatter);
+
+ ObjectUsage::baseExportToJSON(formatter);
+}
+//! @endcond
+
+// ---------------------------------------------------------------------------
+
+//! @cond Doxygen_Suppress
bool GeodeticReferenceFrame::_isEquivalentTo(
const util::IComparable *other,
util::IComparable::Criterion criterion) const {
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index 0c9f8a0c..35798d9d 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -8021,9 +8021,20 @@ PROJStringParser::createFromPROJString(const std::string &projString) {
//! @cond Doxygen_Suppress
struct JSONFormatter::Private {
- PROJ::CPLJSonStreamingWriter writer_{nullptr, nullptr};
+ CPLJSonStreamingWriter writer_{nullptr, nullptr};
DatabaseContextPtr dbContext_{};
+
+ std::vector<bool> stackHasId_{false};
+ std::vector<bool> outputIdStack_{true};
+ bool allowIDInImmediateChild_ = false;
+
std::string result_{};
+
+ // cppcheck-suppress functionStatic
+ void pushOutputId(bool outputIdIn) { outputIdStack_.push_back(outputIdIn); }
+
+ // cppcheck-suppress functionStatic
+ void popOutputId() { outputIdStack_.pop_back(); }
};
//! @endcond
@@ -8071,13 +8082,55 @@ JSONFormatter::~JSONFormatter() = default;
// ---------------------------------------------------------------------------
-PROJ::CPLJSonStreamingWriter &JSONFormatter::writer() const {
- return d->writer_;
+CPLJSonStreamingWriter &JSONFormatter::writer() const { return d->writer_; }
+
+// ---------------------------------------------------------------------------
+
+bool JSONFormatter::outputId() const { return d->outputIdStack_.back(); }
+
+// ---------------------------------------------------------------------------
+
+bool JSONFormatter::outputUsage() const {
+ return outputId() && d->outputIdStack_.size() == 2;
}
// ---------------------------------------------------------------------------
-bool JSONFormatter::outputId() const { return true; }
+void JSONFormatter::setAllowIDInImmediateChild() {
+ d->allowIDInImmediateChild_ = true;
+}
+
+// ---------------------------------------------------------------------------
+
+JSONFormatter::ObjectContext::ObjectContext(JSONFormatter &formatter,
+ const char *objectType, bool hasId)
+ : m_formatter(formatter) {
+ m_formatter.d->writer_.StartObj();
+ if (objectType) {
+ m_formatter.d->writer_.AddObjKey("type");
+ m_formatter.d->writer_.Add(objectType);
+ }
+ // All intermediate nodes shouldn't have ID if a parent has an ID
+ // unless explicitly enabled.
+ if (m_formatter.d->allowIDInImmediateChild_) {
+ m_formatter.d->pushOutputId(m_formatter.d->outputIdStack_[0]);
+ m_formatter.d->allowIDInImmediateChild_ = false;
+ } else {
+ m_formatter.d->pushOutputId(m_formatter.d->outputIdStack_[0] &&
+ !m_formatter.d->stackHasId_.back());
+ }
+
+ m_formatter.d->stackHasId_.push_back(hasId ||
+ m_formatter.d->stackHasId_.back());
+}
+
+// ---------------------------------------------------------------------------
+
+JSONFormatter::ObjectContext::~ObjectContext() {
+ m_formatter.d->writer_.EndObj();
+ m_formatter.d->stackHasId_.pop_back();
+ m_formatter.d->popOutputId();
+}
//! @endcond
diff --git a/src/iso19111/metadata.cpp b/src/iso19111/metadata.cpp
index 761b909b..41653b32 100644
--- a/src/iso19111/metadata.cpp
+++ b/src/iso19111/metadata.cpp
@@ -1096,7 +1096,7 @@ void Identifier::_exportToJSON(JSONFormatter *formatter) const {
const std::string &l_codeSpace = *codeSpace();
if (!l_codeSpace.empty() && !l_code.empty()) {
auto &writer = formatter->writer();
- PROJ::CPLJSonStreamingWriter::ObjectContext objContext(writer);
+ auto objContext(formatter->MakeObjectContext(nullptr, false));
writer.AddObjKey("authority");
writer.Add(l_codeSpace);
writer.AddObjKey("code");