aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/apps/projinfo.cpp33
-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
-rw-r--r--src/proj_json_streaming_writer.cpp5
-rw-r--r--src/proj_json_streaming_writer.hpp20
10 files changed, 589 insertions, 26 deletions
diff --git a/src/apps/projinfo.cpp b/src/apps/projinfo.cpp
index 9d724522..6b1267e0 100644
--- a/src/apps/projinfo.cpp
+++ b/src/apps/projinfo.cpp
@@ -67,6 +67,7 @@ struct OutputOptions {
bool WKT2_2015_SIMPLIFIED = false;
bool WKT1_GDAL = false;
bool WKT1_ESRI = false;
+ bool JSON = false;
bool c_ify = false;
bool singleLine = false;
bool strict = true;
@@ -101,7 +102,7 @@ static void usage() {
std::cerr << std::endl;
std::cerr << "-o: formats is a comma separated combination of: "
"all,default,PROJ,WKT_ALL,WKT2_2015,WKT2_2018,WKT1_GDAL,"
- "WKT1_ESRI"
+ "WKT1_ESRI,JSON"
<< std::endl;
std::cerr << " Except 'all' and 'default', other format can be preceded "
"by '-' to disable them"
@@ -467,6 +468,29 @@ static void outputObject(
std::cerr << "Error when exporting to WKT1_ESRI: " << e.what()
<< std::endl;
}
+ alreadyOutputed = true;
+ }
+ }
+
+ auto JSONExportable = nn_dynamic_pointer_cast<IJSONExportable>(obj);
+ if (JSONExportable) {
+ if (outputOpt.JSON) {
+ try {
+ if (alreadyOutputed) {
+ std::cout << std::endl;
+ }
+ if (!outputOpt.quiet) {
+ std::cout << "JSON:" << std::endl;
+ }
+
+ std::cout << JSONExportable->exportToJSON(
+ JSONFormatter::create(dbContext).get())
+ << std::endl;
+ } catch (const std::exception &e) {
+ std::cerr << "Error when exporting to JSON: " << e.what()
+ << std::endl;
+ }
+ // alreadyOutputed = true;
}
}
@@ -720,6 +744,7 @@ int main(int argc, char **argv) {
outputOpt.WKT2_2015 = true;
outputOpt.WKT1_GDAL = true;
outputOpt.WKT1_ESRI = true;
+ outputOpt.JSON = true;
} else if (ci_equal(format, "default")) {
outputOpt.PROJ5 = true;
outputOpt.WKT2_2018 = true;
@@ -779,6 +804,10 @@ int main(int argc, char **argv) {
ci_equal(format, "-WKT1-ESRI") ||
ci_equal(format, "-WKT1:ESRI")) {
outputOpt.WKT1_ESRI = false;
+ } else if (ci_equal(format, "JSON")) {
+ outputOpt.JSON = true;
+ } else if (ci_equal(format, "-JSON")) {
+ outputOpt.JSON = false;
} else {
std::cerr << "Unrecognized value for option -o: " << format
<< std::endl;
@@ -998,7 +1027,7 @@ int main(int argc, char **argv) {
if (outputOpt.quiet &&
(outputOpt.PROJ5 + outputOpt.WKT2_2018 + outputOpt.WKT2_2015 +
- outputOpt.WKT1_GDAL) != 1) {
+ outputOpt.WKT1_GDAL + outputOpt.JSON) != 1) {
std::cerr << "-q can only be used with a single output format"
<< std::endl;
usage();
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");
diff --git a/src/proj_json_streaming_writer.cpp b/src/proj_json_streaming_writer.cpp
index 3198308b..4a9b9bd2 100644
--- a/src/proj_json_streaming_writer.cpp
+++ b/src/proj_json_streaming_writer.cpp
@@ -56,8 +56,7 @@ static std::string CPLSPrintf(const char* fmt, ...)
return res;
}
-namespace PROJ
-{
+NS_PROJ_START
CPLJSonStreamingWriter::CPLJSonStreamingWriter(
SerializationFuncType pfnSerializationFunc,
@@ -292,6 +291,6 @@ void CPLJSonStreamingWriter::AddNull()
Print("null");
}
-} // namespace PROJ
+NS_PROJ_END
/*! @endcond */
diff --git a/src/proj_json_streaming_writer.hpp b/src/proj_json_streaming_writer.hpp
index d1510449..62676842 100644
--- a/src/proj_json_streaming_writer.hpp
+++ b/src/proj_json_streaming_writer.hpp
@@ -36,8 +36,8 @@
#define CPL_DLL
-namespace PROJ
-{
+#include "proj/util.hpp"
+NS_PROJ_START
typedef std::int64_t GIntBig;
typedef std::uint64_t GUInt64;
@@ -102,10 +102,15 @@ public:
struct CPL_DLL ObjectContext
{
CPLJSonStreamingWriter& m_serializer;
- explicit ObjectContext(CPLJSonStreamingWriter& serializer):
+
+ ObjectContext(const ObjectContext &) = delete;
+ ObjectContext(ObjectContext&&) = default;
+
+ explicit inline ObjectContext(CPLJSonStreamingWriter& serializer):
m_serializer(serializer) { m_serializer.StartObj(); }
~ObjectContext() { m_serializer.EndObj(); }
};
+ inline ObjectContext MakeObjectContext() { return ObjectContext(*this); }
void StartArray();
void EndArray();
@@ -115,7 +120,10 @@ public:
bool m_bForceSingleLine;
bool m_bNewLineEnabledBackup;
- ArrayContext(CPLJSonStreamingWriter& serializer,
+ ArrayContext(const ArrayContext &) = delete;
+ ArrayContext(ArrayContext&&) = default;
+
+ inline explicit ArrayContext(CPLJSonStreamingWriter& serializer,
bool bForceSingleLine = false):
m_serializer(serializer),
m_bForceSingleLine(bForceSingleLine),
@@ -133,12 +141,14 @@ public:
m_serializer.SetNewline(m_bNewLineEnabledBackup);
}
};
+ inline ArrayContext MakeArrayContext(bool bForceSingleLine = false)
+ { return ArrayContext(*this, bForceSingleLine); }
bool GetNewLine() const { return m_bNewLineEnabled; }
void SetNewline(bool bEnabled) { m_bNewLineEnabled = bEnabled; }
};
-} // namespace PROJ
+NS_PROJ_END
/*! @endcond */