diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/apps/projinfo.cpp | 33 | ||||
| -rw-r--r-- | src/iso19111/common.cpp | 84 | ||||
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 85 | ||||
| -rw-r--r-- | src/iso19111/coordinatesystem.cpp | 59 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 160 | ||||
| -rw-r--r-- | src/iso19111/datum.cpp | 106 | ||||
| -rw-r--r-- | src/iso19111/io.cpp | 61 | ||||
| -rw-r--r-- | src/iso19111/metadata.cpp | 2 | ||||
| -rw-r--r-- | src/proj_json_streaming_writer.cpp | 5 | ||||
| -rw-r--r-- | src/proj_json_streaming_writer.hpp | 20 |
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 */ |
