From c5cddfe2cfd868c9bb4fa4429e7611f1ca0e7add Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Fri, 9 Aug 2019 17:10:20 +0200 Subject: [PATCH] PROJSJON: add import/export of VerticalCRS, CompoundCRS, BoundCRS, Transformation and ConcatenatedOperation --- data/crsjson.schema.json | 292 ++++++- include/proj/coordinateoperation.hpp | 12 +- include/proj/crs.hpp | 105 ++- include/proj/datum.hpp | 21 +- .../internal/coordinateoperation_internal.hpp | 11 + include/proj/io.hpp | 3 + src/iso19111/coordinateoperation.cpp | 174 +++- src/iso19111/crs.cpp | 268 ++++-- src/iso19111/datum.cpp | 88 ++ src/iso19111/io.cpp | 263 +++++- test/unit/test_io.cpp | 790 ++++++++++++++++++ travis/install.sh | 19 + 12 files changed, 1934 insertions(+), 112 deletions(-) diff --git a/data/crsjson.schema.json b/data/crsjson.schema.json index 86f1e13ef0..5e2d41d06e 100644 --- a/data/crsjson.schema.json +++ b/data/crsjson.schema.json @@ -8,11 +8,28 @@ { "$ref": "#/definitions/datum" }, { "$ref": "#/definitions/ellipsoid" }, { "$ref": "#/definitions/prime_meridian" }, - { "$ref": "#/definitions/conversion" } + { "$ref": "#/definitions/single_operation" }, + { "$ref": "#/definitions/concatenated_operation" } ], "definitions": { + "abridged_transformation": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["AbridgedTransformation"] }, + "name": { "type": "string" }, + "method": { "$ref": "#/definitions/method" }, + "parameters": { + "type": "array", + "items": { "$ref": "#/definitions/parameter_value" } + }, + "id": { "$ref": "#/definitions/id" } + }, + "required" : [ "name", "method", "parameters" ], + "additionalProperties": false + }, + "axis": { "type": "object", "properties": { @@ -40,6 +57,62 @@ "additionalProperties": false }, + "bound_crs": { + "type": "object", + "properties": { + "type": { "type": "string", "enum": ["BoundCRS"] }, + "source_crs": { "$ref": "#/definitions/crs" }, + "target_crs": { "$ref": "#/definitions/crs" }, + "transformation": { "$ref": "#/definitions/abridged_transformation" } + }, + "required" : [ "source_crs", "target_crs", "transformation" ], + "additionalProperties": false + }, + + "compound_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["CompoundCRS"] }, + "name": { "type": "string" }, + "components": { + "type": "array", + "items": { "$ref": "#/definitions/crs" } + }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "components" ], + "additionalProperties": false + }, + + "concatenated_operation": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["ConcatenatedOperation"] }, + "name": { "type": "string" }, + "source_crs": { "$ref": "#/definitions/crs" }, + "target_crs": { "$ref": "#/definitions/crs" }, + "steps": { + "type": "array", + "items": { "$ref": "#/definitions/single_operation" } + }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "source_crs", "target_crs", "steps" ], + "additionalProperties": false + }, + "conversion": { "type": "object", "properties": { @@ -52,7 +125,7 @@ }, "id": { "$ref": "#/definitions/id" } }, - "required" : [ "name", "method", "parameters" ], + "required" : [ "name", "method" ], "additionalProperties": false }, @@ -75,12 +148,24 @@ "crs": { "oneOf": [ { "$ref": "#/definitions/geodetic_crs" }, - { "$ref": "#/definitions/derived_crs" } + { "$ref": "#/definitions/derived_crs" }, + { "$ref": "#/definitions/vertical_crs" }, + { "$ref": "#/definitions/compound_crs" }, + { "$ref": "#/definitions/bound_crs" }, + { "$ref": "#/definitions/engineering_crs" }, + { "$ref": "#/definitions/parametric_crs" }, + { "$ref": "#/definitions/temporal_crs" } ] }, "datum": { - "oneOf": [ { "$ref": "#/definitions/geodetic_reference_frame" } ] + "oneOf": [ + { "$ref": "#/definitions/geodetic_reference_frame" }, + { "$ref": "#/definitions/vertical_reference_frame" }, + { "$ref": "#/definitions/temporal_datum" }, + { "$ref": "#/definitions/parametric_datum" }, + { "$ref": "#/definitions/engineering_datum" } + ] }, "derived_crs": { @@ -88,12 +173,19 @@ "allOf": [{ "$ref": "#/definitions/object_usage" }], "properties": { "type": { "type": "string", - "enum": ["ProjectedCRS", "DerivedGeodeticCRS", - "DerivedGeographicCRS"] }, + "enum": ["ProjectedCRS", + "DerivedGeodeticCRS", + "DerivedGeographicCRS", + "DerivedProjectedCRS", + "DerivedVerticalCRS", + "DerivedTemporalCRS", + "DerivedParametricCRS", + "DerivedEngineeringCRS"] }, "name": { "type": "string" }, "base_crs": { "$ref": "#/definitions/crs" }, "conversion": { "$ref": "#/definitions/conversion" }, "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "scope": {}, "area": {}, "bbox": {}, "usages": {}, @@ -142,14 +234,52 @@ ] }, + "engineering_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["EngineeringCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/engineering_datum" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "engineering_datum": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["EngineeringDatum"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name" ], + "additionalProperties": false + }, + "geodetic_crs": { "type": "object", "allOf": [{ "$ref": "#/definitions/object_usage" }], "properties": { "type": { "type": "string", "enum": ["GeodeticCRS", "GeographicCRS"] }, "name": { "type": "string" }, - "datum": { "$ref": "#/definitions/datum" }, + "datum": { "$ref": "#/definitions/geodetic_reference_frame" }, "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "scope": {}, "area": {}, "bbox": {}, "usages": {}, @@ -169,6 +299,7 @@ "anchor": { "type": "string" }, "ellipsoid": { "$ref": "#/definitions/ellipsoid" }, "prime_meridian": { "$ref": "#/definitions/prime_meridian" }, + "scope": {}, "area": {}, "bbox": {}, "usages": {}, @@ -207,6 +338,7 @@ { "type": "object", "properties": { + "scope": { "type": "string" }, "area": { "type": "string" }, "bbox": { "$ref": "#/definitions/bbox" }, "remarks": { "type": "string" }, @@ -242,6 +374,43 @@ "additionalProperties": false }, + "parametric_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["ParametricCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/parametric_datum" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "parametric_datum": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["ParametricDatum"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name" ], + "additionalProperties": false + }, + "prime_meridian": { "type": "object", "properties": { @@ -254,6 +423,77 @@ "additionalProperties": false }, + "single_operation": { + "oneOf": [ + { "$ref": "#/definitions/conversion" }, + { "$ref": "#/definitions/transformation" } + ] + }, + + "temporal_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["TemporalCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/temporal_datum" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "temporal_datum": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["TemporalDatum"] }, + "name": { "type": "string" }, + "calendar": { "type": "string" }, + "time_origin": { "type": "string" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "calendar" ], + "additionalProperties": false + }, + + "transformation": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["Transformation"] }, + "name": { "type": "string" }, + "source_crs": { "$ref": "#/definitions/crs" }, + "target_crs": { "$ref": "#/definitions/crs" }, + "interpolation_crs": { "$ref": "#/definitions/crs" }, + "method": { "$ref": "#/definitions/method" }, + "parameters": { + "type": "array", + "items": { "$ref": "#/definitions/parameter_value" } + }, + "accuracy": { "type": "string" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "source_crs", "target_crs", "method", "parameters" ], + "additionalProperties": false + }, + "unit": { "oneOf": [ { @@ -281,6 +521,7 @@ "items": { "type": "object", "properties": { + "scope": { "type": "string" }, "area": { "type": "string" }, "bbox": { "$ref": "#/definitions/bbox" } }, @@ -303,6 +544,43 @@ { "type": "number" }, { "$ref": "#/definitions/value_and_unit" } ] + }, + + "vertical_crs": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["VerticalCRS"] }, + "name": { "type": "string" }, + "datum": { "$ref": "#/definitions/vertical_reference_frame" }, + "coordinate_system": { "$ref": "#/definitions/coordinate_system" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name", "datum" ], + "additionalProperties": false + }, + + "vertical_reference_frame": { + "type": "object", + "allOf": [{ "$ref": "#/definitions/object_usage" }], + "properties": { + "type": { "type": "string", "enum": ["VerticalReferenceFrame"] }, + "name": { "type": "string" }, + "anchor": { "type": "string" }, + "scope": {}, + "area": {}, + "bbox": {}, + "usages": {}, + "remarks": {}, + "id": {} + }, + "required" : [ "name" ], + "additionalProperties": false } } diff --git a/include/proj/coordinateoperation.hpp b/include/proj/coordinateoperation.hpp index 9b2dfe6430..2f6095f7f1 100644 --- a/include/proj/coordinateoperation.hpp +++ b/include/proj/coordinateoperation.hpp @@ -116,7 +116,8 @@ using CoordinateOperationNNPtr = util::nn; * \remark Implements CoordinateOperation from \ref ISO_19111_2019 */ class PROJ_GCC_DLL CoordinateOperation : public common::ObjectUsage, - public io::IPROJStringExportable { + public io::IPROJStringExportable, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~CoordinateOperation() override; @@ -849,8 +850,7 @@ EPSG:8833 */ -class PROJ_GCC_DLL Conversion : public SingleOperation, - public io::IJSONExportable { +class PROJ_GCC_DLL Conversion : public SingleOperation { public: //! @cond Doxygen_Suppress PROJ_DLL ~Conversion() override; @@ -1550,6 +1550,9 @@ class PROJ_GCC_DLL Transformation : public SingleOperation { PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL TransformationNNPtr shallowClone() const; //! @endcond @@ -1655,6 +1658,9 @@ class PROJ_GCC_DLL ConcatenatedOperation final : public CoordinateOperation { util::IComparable::Criterion criterion = util::IComparable::Criterion::STRICT) const override; + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL static void fixStepsDirection(const crs::CRSNNPtr &concatOpSourceCRS, const crs::CRSNNPtr &concatOpTargetCRS, diff --git a/include/proj/crs.hpp b/include/proj/crs.hpp index 702b2d3632..d271046997 100644 --- a/include/proj/crs.hpp +++ b/include/proj/crs.hpp @@ -81,7 +81,8 @@ using CRSNNPtr = util::nn; * * \remark Implements CRS from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL CRS : public common::ObjectUsage { +class PROJ_GCC_DLL CRS : public common::ObjectUsage, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~CRS() override; @@ -211,8 +212,7 @@ using GeodeticCRSNNPtr = util::nn; * \remark Implements GeodeticCRS from \ref ISO_19111_2019 */ class PROJ_GCC_DLL GeodeticCRS : virtual public SingleCRS, - public io::IPROJStringExportable, - public io::IJSONExportable { + public io::IPROJStringExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~GeodeticCRS() override; @@ -447,6 +447,12 @@ class PROJ_GCC_DLL VerticalCRS : virtual public SingleCRS, PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) + const override; // throw(FormattingException) + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -460,9 +466,6 @@ class PROJ_GCC_DLL VerticalCRS : virtual public SingleCRS, const cs::VerticalCSNNPtr &csIn); PROJ_INTERNAL VerticalCRS(const VerticalCRS &other); - PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) - const override; // throw(FormattingException) - PROJ_INTERNAL std::list> _identify(const io::AuthorityFactoryPtr &authorityFactory) const override; @@ -502,6 +505,10 @@ class PROJ_GCC_DLL DerivedCRS : virtual public SingleCRS { //! @cond Doxygen_Suppress PROJ_INTERNAL const operation::ConversionNNPtr & derivingConversionRef() PROJ_PURE_DECL; + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + //! @endcond protected: @@ -522,6 +529,8 @@ class PROJ_GCC_DLL DerivedCRS : virtual public SingleCRS { util::IComparable::Criterion criterion = util::IComparable::Criterion::STRICT) const override; + PROJ_INTERNAL virtual const char *className() const = 0; + private: PROJ_OPAQUE_PRIVATE_DATA DerivedCRS &operator=(const DerivedCRS &other) = delete; @@ -553,8 +562,7 @@ using ProjectedCRSNNPtr = util::nn; * \remark Implements ProjectedCRS from \ref ISO_19111_2019 */ class PROJ_GCC_DLL ProjectedCRS final : public DerivedCRS, - public io::IPROJStringExportable, - public io::IJSONExportable { + public io::IPROJStringExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~ProjectedCRS() override; @@ -607,6 +615,10 @@ class PROJ_GCC_DLL ProjectedCRS final : public DerivedCRS, PROJ_INTERNAL std::list> _identify(const io::AuthorityFactoryPtr &authorityFactory) const override; + PROJ_INTERNAL const char *className() const override { + return "ProjectedCRS"; + } + INLINED_MAKE_SHARED PROJ_INTERNAL CRSNNPtr _shallowClone() const override; @@ -647,7 +659,11 @@ class PROJ_GCC_DLL TemporalCRS : virtual public SingleCRS { //! @cond Doxygen_Suppress PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - //! @endcond + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + + //! @endcond protected: PROJ_INTERNAL TemporalCRS(const datum::TemporalDatumNNPtr &datumIn, @@ -704,7 +720,11 @@ class PROJ_GCC_DLL EngineeringCRS : virtual public SingleCRS { //! @cond Doxygen_Suppress PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - //! @endcond + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + + //! @endcond protected: PROJ_INTERNAL EngineeringCRS(const datum::EngineeringDatumNNPtr &datumIn, @@ -760,7 +780,11 @@ class PROJ_GCC_DLL ParametricCRS : virtual public SingleCRS { //! @cond Doxygen_Suppress PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - //! @endcond + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + + //! @endcond protected: PROJ_INTERNAL ParametricCRS(const datum::ParametricDatumNNPtr &datumIn, @@ -832,6 +856,9 @@ class PROJ_GCC_DLL CompoundCRS final : public CRS, PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL CRSNNPtr _shallowClone() const override; PROJ_INTERNAL bool @@ -917,6 +944,9 @@ class PROJ_GCC_DLL BoundCRS final : public CRS, PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -977,9 +1007,12 @@ class PROJ_GCC_DLL DerivedGeodeticCRS final : public GeodeticCRS, void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) - const override; // throw(FormattingException) - //! @endcond + PROJ_INTERNAL void + _exportToJSON(io::JSONFormatter *formatter) const override { + return DerivedCRS::_exportToJSON(formatter); + } + + //! @endcond protected: PROJ_INTERNAL @@ -1006,6 +1039,10 @@ class PROJ_GCC_DLL DerivedGeodeticCRS final : public GeodeticCRS, PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) + PROJ_INTERNAL const char *className() const override { + return "DerivedGeodeticCRS"; + } + INLINED_MAKE_SHARED private: @@ -1049,9 +1086,12 @@ class PROJ_GCC_DLL DerivedGeographicCRS final : public GeographicCRS, PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) - const override; // throw(FormattingException) - //! @endcond + PROJ_INTERNAL void + _exportToJSON(io::JSONFormatter *formatter) const override { + return DerivedCRS::_exportToJSON(formatter); + } + + //! @endcond protected: PROJ_INTERNAL @@ -1070,6 +1110,10 @@ class PROJ_GCC_DLL DerivedGeographicCRS final : public GeographicCRS, PROJ_INTERNAL std::list> _identify(const io::AuthorityFactoryPtr &authorityFactory) const override; + PROJ_INTERNAL const char *className() const override { + return "DerivedGeographicCRS"; + } + // cppcheck-suppress functionStatic PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) @@ -1131,6 +1175,10 @@ class PROJ_GCC_DLL DerivedProjectedCRS final : public DerivedCRS { util::IComparable::Criterion criterion = util::IComparable::Criterion::STRICT) const override; + PROJ_INTERNAL const char *className() const override { + return "DerivedProjectedCRS"; + } + INLINED_MAKE_SHARED private: @@ -1170,7 +1218,13 @@ class PROJ_GCC_DLL DerivedVerticalCRS final : public VerticalCRS, //! @cond Doxygen_Suppress PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - //! @endcond + + PROJ_INTERNAL void + _exportToJSON(io::JSONFormatter *formatter) const override { + return DerivedCRS::_exportToJSON(formatter); + } + + //! @endcond protected: PROJ_INTERNAL @@ -1189,6 +1243,10 @@ class PROJ_GCC_DLL DerivedVerticalCRS final : public VerticalCRS, PROJ_INTERNAL std::list> _identify(const io::AuthorityFactoryPtr &authorityFactory) const override; + PROJ_INTERNAL const char *className() const override { + return "DerivedVerticalCRS"; + } + // cppcheck-suppress functionStatic PROJ_INTERNAL void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) @@ -1251,7 +1309,12 @@ class PROJ_GCC_DLL DerivedCRSTemplate final : public DerivedCRSTraits::BaseType, //! @cond Doxygen_Suppress PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - //! @endcond + + PROJ_INTERNAL void + _exportToJSON(io::JSONFormatter *formatter) const override { + return DerivedCRS::_exportToJSON(formatter); + } + //! @endcond protected: PROJ_INTERNAL @@ -1267,6 +1330,10 @@ class PROJ_GCC_DLL DerivedCRSTemplate final : public DerivedCRSTraits::BaseType, util::IComparable::Criterion criterion = util::IComparable::Criterion::STRICT) const override; + PROJ_INTERNAL const char *className() const override { + return DerivedCRSTraits::CRSName().c_str(); + } + INLINED_MAKE_SHARED private: diff --git a/include/proj/datum.hpp b/include/proj/datum.hpp index 00e56a1cdc..3724bfb144 100644 --- a/include/proj/datum.hpp +++ b/include/proj/datum.hpp @@ -61,7 +61,8 @@ namespace datum { * * \remark Implements Datum from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL Datum : public common::ObjectUsage { +class PROJ_GCC_DLL Datum : public common::ObjectUsage, + public io::IJSONExportable { public: //! @cond Doxygen_Suppress PROJ_DLL ~Datum() override; @@ -379,8 +380,7 @@ using GeodeticReferenceFrameNNPtr = util::nn; * * \remark Implements GeodeticReferenceFrame from \ref ISO_19111_2019 */ -class PROJ_GCC_DLL GeodeticReferenceFrame : public Datum, - public io::IJSONExportable { +class PROJ_GCC_DLL GeodeticReferenceFrame : public Datum { public: //! @cond Doxygen_Suppress PROJ_DLL ~GeodeticReferenceFrame() override; @@ -566,7 +566,11 @@ class PROJ_GCC_DLL VerticalReferenceFrame : public Datum { PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) - //! @endcond + + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + + //! @endcond protected: #ifdef DOXYGEN_ENABLED @@ -680,6 +684,9 @@ class PROJ_GCC_DLL TemporalDatum final : public Datum { PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -728,6 +735,9 @@ class PROJ_GCC_DLL EngineeringDatum final : public Datum { PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -772,6 +782,9 @@ class PROJ_GCC_DLL ParametricDatum final : public Datum { PROJ_INTERNAL void _exportToWKT(io::WKTFormatter *formatter) const override; // throw(io::FormattingException) + PROJ_INTERNAL void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + PROJ_INTERNAL bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = diff --git a/include/proj/internal/coordinateoperation_internal.hpp b/include/proj/internal/coordinateoperation_internal.hpp index 207c20b407..7ae2cd7836 100644 --- a/include/proj/internal/coordinateoperation_internal.hpp +++ b/include/proj/internal/coordinateoperation_internal.hpp @@ -149,6 +149,10 @@ class InverseConversion : public Conversion, public InverseCoordinateOperation { Conversion::_exportToWKT(formatter); } + void _exportToJSON(io::JSONFormatter *formatter) const override { + Conversion::_exportToJSON(formatter); + } + void _exportToPROJString(io::PROJStringFormatter *formatter) const override { InverseCoordinateOperation::_exportToPROJString(formatter); @@ -200,6 +204,10 @@ class InverseTransformation : public Transformation, return InverseCoordinateOperation::_exportToPROJString(formatter); } + void _exportToJSON(io::JSONFormatter *formatter) const override { + Transformation::_exportToJSON(formatter); + } + bool _isEquivalentTo(const util::IComparable *other, util::IComparable::Criterion criterion = @@ -270,6 +278,9 @@ class PROJBasedOperation : public SingleOperation { void _exportToPROJString(io::PROJStringFormatter *formatter) const override; // throw(FormattingException) + void _exportToJSON(io::JSONFormatter *formatter) + const override; // throw(FormattingException) + CoordinateOperationNNPtr _shallowClone() const override; INLINED_MAKE_SHARED diff --git a/include/proj/io.hpp b/include/proj/io.hpp index 043b4c4be6..66c1a4cd34 100644 --- a/include/proj/io.hpp +++ b/include/proj/io.hpp @@ -505,6 +505,9 @@ class PROJ_GCC_DLL JSONFormatter { PROJ_INTERNAL void setOmitTypeInImmediateChild(); + PROJ_INTERNAL void setAbridgedTransformation(bool abriged); + PROJ_INTERNAL bool abridgedTransformation() const; + // cppcheck-suppress functionStatic PROJ_INTERNAL bool outputId() const; diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index f4e90fe806..27a22b5152 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -5484,13 +5484,16 @@ void Conversion::_exportToJSON( formatter->setAllowIDInImmediateChild(); method()->_exportToJSON(formatter); - writer.AddObjKey("parameters"); - { - auto parametersContext(writer.MakeArrayContext(false)); - for (const auto &genOpParamvalue : parameterValues()) { - formatter->setAllowIDInImmediateChild(); - formatter->setOmitTypeInImmediateChild(); - genOpParamvalue->_exportToJSON(formatter); + const auto &l_parameterValues = parameterValues(); + if (!l_parameterValues.empty()) { + writer.AddObjKey("parameters"); + { + auto parametersContext(writer.MakeArrayContext(false)); + for (const auto &genOpParamvalue : l_parameterValues) { + formatter->setAllowIDInImmediateChild(); + formatter->setOmitTypeInImmediateChild(); + genOpParamvalue->_exportToJSON(formatter); + } } } @@ -7862,6 +7865,76 @@ void Transformation::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void Transformation::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext( + formatter->abridgedTransformation() ? "AbridgedTransformation" + : "Transformation", + !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + if (!formatter->abridgedTransformation()) { + writer.AddObjKey("source_crs"); + formatter->setAllowIDInImmediateChild(); + sourceCRS()->_exportToJSON(formatter); + + writer.AddObjKey("target_crs"); + formatter->setAllowIDInImmediateChild(); + targetCRS()->_exportToJSON(formatter); + + const auto &l_interpolationCRS = interpolationCRS(); + if (l_interpolationCRS) { + writer.AddObjKey("interpolation_crs"); + formatter->setAllowIDInImmediateChild(); + l_interpolationCRS->_exportToJSON(formatter); + } + } + + writer.AddObjKey("method"); + formatter->setOmitTypeInImmediateChild(); + formatter->setAllowIDInImmediateChild(); + method()->_exportToJSON(formatter); + + writer.AddObjKey("parameters"); + { + auto parametersContext(writer.MakeArrayContext(false)); + for (const auto &genOpParamvalue : parameterValues()) { + formatter->setAllowIDInImmediateChild(); + formatter->setOmitTypeInImmediateChild(); + genOpParamvalue->_exportToJSON(formatter); + } + } + + if (!formatter->abridgedTransformation()) { + if (!coordinateOperationAccuracies().empty()) { + writer.AddObjKey("accuracy"); + writer.Add(coordinateOperationAccuracies()[0]->value()); + } + } + + if (formatter->abridgedTransformation()) { + if (formatter->outputId()) { + formatID(formatter); + } + } else { + ObjectUsage::baseExportToJSON(formatter); + } +} + +//! @endcond + +// --------------------------------------------------------------------------- + static void exportSourceCRSAndTargetCRSToWKT(const CoordinateOperation *co, io::WKTFormatter *formatter) { auto l_sourceCRS = co->sourceCRS(); @@ -9677,6 +9750,46 @@ void ConcatenatedOperation::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void ConcatenatedOperation::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext("ConcatenatedOperation", + !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("source_crs"); + formatter->setAllowIDInImmediateChild(); + sourceCRS()->_exportToJSON(formatter); + + writer.AddObjKey("target_crs"); + formatter->setAllowIDInImmediateChild(); + targetCRS()->_exportToJSON(formatter); + + writer.AddObjKey("steps"); + { + auto parametersContext(writer.MakeArrayContext(false)); + for (const auto &operation : operations()) { + formatter->setAllowIDInImmediateChild(); + operation->_exportToJSON(formatter); + } + } + + ObjectUsage::baseExportToJSON(formatter); +} + +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress CoordinateOperationNNPtr ConcatenatedOperation::_shallowClone() const { auto op = @@ -13148,6 +13261,53 @@ void PROJBasedOperation::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +void PROJBasedOperation::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext(formatter->MakeObjectContext( + (sourceCRS() && targetCRS()) ? "Transformation" : "Conversion", + !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + if (sourceCRS() && targetCRS()) { + writer.AddObjKey("source_crs"); + formatter->setAllowIDInImmediateChild(); + sourceCRS()->_exportToJSON(formatter); + + writer.AddObjKey("target_crs"); + formatter->setAllowIDInImmediateChild(); + targetCRS()->_exportToJSON(formatter); + } + + writer.AddObjKey("method"); + formatter->setOmitTypeInImmediateChild(); + formatter->setAllowIDInImmediateChild(); + method()->_exportToJSON(formatter); + + const auto &l_parameterValues = parameterValues(); + if (!l_parameterValues.empty()) { + writer.AddObjKey("parameters"); + { + auto parametersContext(writer.MakeArrayContext(false)); + for (const auto &genOpParamvalue : l_parameterValues) { + formatter->setAllowIDInImmediateChild(); + formatter->setOmitTypeInImmediateChild(); + genOpParamvalue->_exportToJSON(formatter); + } + } + } +} + +// --------------------------------------------------------------------------- + void PROJBasedOperation::_exportToPROJString( io::PROJStringFormatter *formatter) const { if (projStringExportable_) { diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 670d0c1a77..28f8fabbb1 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -2265,6 +2265,7 @@ void VerticalCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress void VerticalCRS::_exportToPROJString( io::PROJStringFormatter *formatter) const // throw(io::FormattingException) { @@ -2284,6 +2285,36 @@ void VerticalCRS::_exportToPROJString( } } } +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +void VerticalCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("VerticalCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("datum"); + datum()->_exportToJSON(formatter); + + writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond // --------------------------------------------------------------------------- @@ -2649,6 +2680,38 @@ void DerivedCRS::baseExportToWKT(io::WKTFormatter *formatter, // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void DerivedCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext(className(), !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"); + formatter->setOmitTypeInImmediateChild(); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress struct ProjectedCRS::Private { GeodeticCRSNNPtr baseCRS_; @@ -3514,6 +3577,36 @@ void CompoundCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void CompoundCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("CompoundCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("components"); + { + auto componentsContext(writer.MakeArrayContext(false)); + for (const auto &crs : componentReferenceSystems()) { + crs->_exportToJSON(formatter); + } + } + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + void CompoundCRS::_exportToPROJString( io::PROJStringFormatter *formatter) const // throw(io::FormattingException) { @@ -4004,6 +4097,30 @@ void BoundCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void BoundCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("BoundCRS", !identifiers().empty())); + + writer.AddObjKey("source_crs"); + d->baseCRS()->_exportToJSON(formatter); + + writer.AddObjKey("target_crs"); + d->hubCRS()->_exportToJSON(formatter); + + writer.AddObjKey("transformation"); + formatter->setOmitTypeInImmediateChild(); + formatter->setAbridgedTransformation(true); + d->transformation()->_exportToJSON(formatter); + formatter->setAbridgedTransformation(false); +} +//! @endcond + +// --------------------------------------------------------------------------- + void BoundCRS::_exportToPROJString( io::PROJStringFormatter *formatter) const // throw(io::FormattingException) { @@ -4298,38 +4415,6 @@ 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"); - formatter->setOmitTypeInImmediateChild(); - coordinateSystem()->_exportToJSON(formatter); - - ObjectUsage::baseExportToJSON(formatter); -} -//! @endcond - -// --------------------------------------------------------------------------- - void DerivedGeodeticCRS::_exportToPROJString( io::PROJStringFormatter *) const // throw(io::FormattingException) { @@ -4468,38 +4553,6 @@ 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"); - formatter->setOmitTypeInImmediateChild(); - coordinateSystem()->_exportToJSON(formatter); - - ObjectUsage::baseExportToJSON(formatter); -} -//! @endcond - -// --------------------------------------------------------------------------- - void DerivedGeographicCRS::_exportToPROJString( io::PROJStringFormatter *) const // throw(io::FormattingException) { @@ -4756,6 +4809,35 @@ void TemporalCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void TemporalCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("TemporalCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("datum"); + datum()->_exportToJSON(formatter); + + writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + bool TemporalCRS::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion) const { @@ -4864,6 +4946,35 @@ void EngineeringCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void EngineeringCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("EngineeringCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("datum"); + datum()->_exportToJSON(formatter); + + writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + bool EngineeringCRS::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion) const { @@ -4966,6 +5077,35 @@ void ParametricCRS::_exportToWKT(io::WKTFormatter *formatter) const { // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void ParametricCRS::_exportToJSON( + io::JSONFormatter *formatter) const // throw(io::FormattingException) +{ + auto &writer = formatter->writer(); + auto objectContext( + formatter->MakeObjectContext("ParametricCRS", !identifiers().empty())); + + writer.AddObjKey("name"); + auto l_name = nameStr(); + if (l_name.empty()) { + writer.Add("unnamed"); + } else { + writer.Add(l_name); + } + + writer.AddObjKey("datum"); + datum()->_exportToJSON(formatter); + + writer.AddObjKey("coordinate_system"); + formatter->setOmitTypeInImmediateChild(); + coordinateSystem()->_exportToJSON(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + bool ParametricCRS::_isEquivalentTo( const util::IComparable *other, util::IComparable::Criterion criterion) const { diff --git a/src/iso19111/datum.cpp b/src/iso19111/datum.cpp index 2944da1eb6..d6e6bc2132 100644 --- a/src/iso19111/datum.cpp +++ b/src/iso19111/datum.cpp @@ -1725,6 +1725,30 @@ void VerticalReferenceFrame::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void VerticalReferenceFrame::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto objectContext(formatter->MakeObjectContext("VerticalReferenceFrame", + !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); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool VerticalReferenceFrame::_isEquivalentTo( const util::IComparable *other, @@ -1988,6 +2012,32 @@ void TemporalDatum::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void TemporalDatum::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto objectContext( + formatter->MakeObjectContext("TemporalDatum", !identifiers().empty())); + auto &writer = formatter->writer(); + + writer.AddObjKey("name"); + writer.Add(nameStr()); + + writer.AddObjKey("calendar"); + writer.Add(calendar()); + + const auto &timeOriginStr = temporalOrigin().toString(); + if (!timeOriginStr.empty()) { + writer.AddObjKey("time_origin"); + writer.Add(timeOriginStr); + } + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool TemporalDatum::_isEquivalentTo( const util::IComparable *other, @@ -2061,6 +2111,25 @@ void EngineeringDatum::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void EngineeringDatum::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto objectContext(formatter->MakeObjectContext("EngineeringDatum", + !identifiers().empty())); + auto &writer = formatter->writer(); + + writer.AddObjKey("name"); + writer.Add(nameStr()); + + Datum::getPrivate()->exportAnchorDefinition(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool EngineeringDatum::_isEquivalentTo( const util::IComparable *other, @@ -2127,6 +2196,25 @@ void ParametricDatum::_exportToWKT( // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress +void ParametricDatum::_exportToJSON( + io::JSONFormatter *formatter) const // throw(FormattingException) +{ + auto objectContext(formatter->MakeObjectContext("ParametricDatum", + !identifiers().empty())); + auto &writer = formatter->writer(); + + writer.AddObjKey("name"); + writer.Add(nameStr()); + + Datum::getPrivate()->exportAnchorDefinition(formatter); + + ObjectUsage::baseExportToJSON(formatter); +} +//! @endcond + +// --------------------------------------------------------------------------- + //! @cond Doxygen_Suppress bool ParametricDatum::_isEquivalentTo( const util::IComparable *other, diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index bcd1442969..eadc54cc84 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(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(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 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::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 parameters; + std::vector values; + for (const auto ¶m : 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())); + continue; + } + } + values.emplace_back(ParameterValue::create(getMeasure(param))); + } + + CRSPtr sourceTransformationCRS; + if (dynamic_cast(targetCRS.get())) { + sourceTransformationCRS = sourceCRS->extractGeographicCRS(); + if (!sourceTransformationCRS) { + sourceTransformationCRS = + std::dynamic_pointer_cast(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()); + + 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 parameters; + std::vector values; + for (const auto ¶m : 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())); + 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 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 operations; + for (const auto &stepJ : stepsJ) { + if (!stepJ.is_object()) { + throw ParsingException("Unexpected type for a \"steps\" child"); + } + auto op = nn_dynamic_pointer_cast(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()); + } 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 anchor; + if (j.contains("anchor")) { + anchor = getString(j, "anchor"); + } return GeodeticReferenceFrame::create( - buildProperties(j), buildEllipsoid(ellipsoidJ), - optional() /* anchor */, pm); + buildProperties(j), buildEllipsoid(ellipsoidJ), anchor, pm); +} + +// --------------------------------------------------------------------------- + +VerticalReferenceFrameNNPtr +JSONParser::buildVerticalReferenceFrame(const json &j) { + optional anchor; + if (j.contains("anchor")) { + anchor = getString(j, "anchor"); + } + return VerticalReferenceFrame::create(buildProperties(j), anchor); } // --------------------------------------------------------------------------- @@ -8605,6 +8839,7 @@ struct JSONFormatter::Private { std::vector 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 // --------------------------------------------------------------------------- diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index c993c5e445..d3c4c8ec31 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -9612,3 +9612,793 @@ TEST(wkt_export, json_import_projected_crs) { ASSERT_TRUE(pcrs != nullptr); EXPECT_EQ(pcrs->exportToJSON((JSONFormatter::create().get())), json); } + +// --------------------------------------------------------------------------- + +TEST(wkt_export, json_import_compound_crs) { + auto json = "{\n" + " \"type\": \"CompoundCRS\",\n" + " \"name\": \"WGS 84 + EGM2008 height\",\n" + " \"components\": [\n" + " {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"WGS 84\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"World Geodetic System 1984\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"WGS 84\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257223563\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 4326\n" + " }\n" + " },\n" + " {\n" + " \"type\": \"VerticalCRS\",\n" + " \"name\": \"EGM2008 height\",\n" + " \"datum\": {\n" + " \"type\": \"VerticalReferenceFrame\",\n" + " \"name\": \"EGM2008 geoid\"\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"vertical\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Gravity-related height\",\n" + " \"abbreviation\": \"H\",\n" + " \"direction\": \"up\",\n" + " \"unit\": \"metre\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 3855\n" + " }\n" + " }\n" + " ]\n" + "}"; + auto obj = createFromUserInput(json, nullptr); + auto compoundCRS = nn_dynamic_pointer_cast(obj); + ASSERT_TRUE(compoundCRS != nullptr); + EXPECT_EQ(compoundCRS->exportToJSON((JSONFormatter::create().get())), json); +} + +// --------------------------------------------------------------------------- + +TEST(wkt_export, json_import_bound_crs) { + auto json = + "{\n" + " \"type\": \"BoundCRS\",\n" + " \"source_crs\": {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"unknown\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"Unknown based on GRS80 ellipsoid\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"GRS 1980\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257222101,\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 7019\n" + " }\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Longitude\",\n" + " \"abbreviation\": \"lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Latitude\",\n" + " \"abbreviation\": \"lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " \"target_crs\": {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"WGS 84\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"World Geodetic System 1984\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"WGS 84\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257223563\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Latitude\",\n" + " \"abbreviation\": \"lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Longitude\",\n" + " \"abbreviation\": \"lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 4326\n" + " }\n" + " },\n" + " \"transformation\": {\n" + " \"name\": \"unknown to WGS84\",\n" + " \"method\": {\n" + " \"name\": \"NTv2\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 9615\n" + " }\n" + " },\n" + " \"parameters\": [\n" + " {\n" + " \"name\": \"Latitude and longitude difference file\",\n" + " \"value\": \"@foo\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8656\n" + " }\n" + " }\n" + " ]\n" + " }\n" + "}"; + auto obj = createFromUserInput(json, nullptr); + auto boundCRS = nn_dynamic_pointer_cast(obj); + ASSERT_TRUE(boundCRS != nullptr); + EXPECT_EQ(boundCRS->exportToJSON((JSONFormatter::create().get())), json); +} + +// --------------------------------------------------------------------------- + +TEST(wkt_export, json_import_transformation) { + auto json = "{\n" + " \"type\": \"Transformation\",\n" + " \"name\": \"GDA94 to GDA2020 (1)\",\n" + " \"source_crs\": {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"GDA94\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"Geocentric Datum of Australia 1994\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"GRS 1980\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257222101\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " \"target_crs\": {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"GDA2020\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"Geocentric Datum of Australia 2020\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"GRS 1980\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257222101\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " }\n" + " },\n" + " \"method\": {\n" + " \"name\": \"Coordinate Frame rotation (geog2D domain)\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 9607\n" + " }\n" + " },\n" + " \"parameters\": [\n" + " {\n" + " \"name\": \"X-axis translation\",\n" + " \"value\": 61.55,\n" + " \"unit\": {\n" + " \"type\": \"LinearUnit\",\n" + " \"name\": \"millimetre\",\n" + " \"conversion_factor\": 0.001\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8605\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Y-axis translation\",\n" + " \"value\": -10.87,\n" + " \"unit\": {\n" + " \"type\": \"LinearUnit\",\n" + " \"name\": \"millimetre\",\n" + " \"conversion_factor\": 0.001\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8606\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Z-axis translation\",\n" + " \"value\": -40.19,\n" + " \"unit\": {\n" + " \"type\": \"LinearUnit\",\n" + " \"name\": \"millimetre\",\n" + " \"conversion_factor\": 0.001\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8607\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"X-axis rotation\",\n" + " \"value\": -39.4924,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"milliarc-second\",\n" + " \"conversion_factor\": 4.84813681109536e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8608\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Y-axis rotation\",\n" + " \"value\": -32.7221,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"milliarc-second\",\n" + " \"conversion_factor\": 4.84813681109536e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8609\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Z-axis rotation\",\n" + " \"value\": -32.8979,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"milliarc-second\",\n" + " \"conversion_factor\": 4.84813681109536e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8610\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Scale difference\",\n" + " \"value\": -9.994,\n" + " \"unit\": {\n" + " \"type\": \"ScaleUnit\",\n" + " \"name\": \"parts per billion\",\n" + " \"conversion_factor\": 1e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8611\n" + " }\n" + " }\n" + " ],\n" + " \"accuracy\": \"0.01\",\n" + " \"scope\": \"scope\",\n" + " \"area\": \"Australia - GDA\",\n" + " \"bbox\": {\n" + " \"south_latitude\": -60.56,\n" + " \"west_longitude\": 93.41,\n" + " \"north_latitude\": -8.47,\n" + " \"east_longitude\": 173.35\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8048\n" + " },\n" + " \"remarks\": \"foo\"\n" + "}"; + auto obj = createFromUserInput(json, nullptr); + auto transf = nn_dynamic_pointer_cast(obj); + ASSERT_TRUE(transf != nullptr); + EXPECT_EQ(transf->exportToJSON((JSONFormatter::create().get())), json); +} + +// --------------------------------------------------------------------------- + +TEST(wkt_export, json_import_concatenated_operation) { + auto json = + "{\n" + " \"type\": \"ConcatenatedOperation\",\n" + " \"name\": \"Inverse of Vicgrid + GDA94 to GDA2020 (1)\",\n" + " \"source_crs\": {\n" + " \"type\": \"ProjectedCRS\",\n" + " \"name\": \"GDA94 / Vicgrid\",\n" + " \"base_crs\": {\n" + " \"name\": \"GDA94\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"Geocentric Datum of Australia 1994\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"GRS 1980\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257222101\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 4283\n" + " }\n" + " },\n" + " \"conversion\": {\n" + " \"name\": \"Vicgrid\",\n" + " \"method\": {\n" + " \"name\": \"Lambert Conic Conformal (2SP)\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 9802\n" + " }\n" + " },\n" + " \"parameters\": [\n" + " {\n" + " \"name\": \"Latitude of false origin\",\n" + " \"value\": -37,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8821\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Longitude of false origin\",\n" + " \"value\": 145,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8822\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Latitude of 1st standard parallel\",\n" + " \"value\": -36,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8823\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Latitude of 2nd standard parallel\",\n" + " \"value\": -38,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8824\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Easting at false origin\",\n" + " \"value\": 2500000,\n" + " \"unit\": \"metre\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8826\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Northing at false origin\",\n" + " \"value\": 2500000,\n" + " \"unit\": \"metre\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8827\n" + " }\n" + " }\n" + " ]\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"Cartesian\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Easting\",\n" + " \"abbreviation\": \"E\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"metre\"\n" + " },\n" + " {\n" + " \"name\": \"Northing\",\n" + " \"abbreviation\": \"N\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"metre\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 3111\n" + " }\n" + " },\n" + " \"target_crs\": {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"GDA2020\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"Geocentric Datum of Australia 2020\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"GRS 1980\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257222101\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 7844\n" + " }\n" + " },\n" + " \"steps\": [\n" + " {\n" + " \"type\": \"Conversion\",\n" + " \"name\": \"Inverse of Vicgrid\",\n" + " \"method\": {\n" + " \"name\": \"Inverse of Lambert Conic Conformal (2SP)\",\n" + " \"id\": {\n" + " \"authority\": \"INVERSE(EPSG)\",\n" + " \"code\": 9802\n" + " }\n" + " },\n" + " \"parameters\": [\n" + " {\n" + " \"name\": \"Latitude of false origin\",\n" + " \"value\": -37,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8821\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Longitude of false origin\",\n" + " \"value\": 145,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8822\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Latitude of 1st standard parallel\",\n" + " \"value\": -36,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8823\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Latitude of 2nd standard parallel\",\n" + " \"value\": -38,\n" + " \"unit\": \"degree\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8824\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Easting at false origin\",\n" + " \"value\": 2500000,\n" + " \"unit\": \"metre\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8826\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Northing at false origin\",\n" + " \"value\": 2500000,\n" + " \"unit\": \"metre\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8827\n" + " }\n" + " }\n" + " ],\n" + " \"id\": {\n" + " \"authority\": \"INVERSE(EPSG)\",\n" + " \"code\": 17361\n" + " }\n" + " },\n" + " {\n" + " \"type\": \"Transformation\",\n" + " \"name\": \"GDA94 to GDA2020 (1)\",\n" + " \"source_crs\": {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"GDA94\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"Geocentric Datum of Australia 1994\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"GRS 1980\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257222101\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 4283\n" + " }\n" + " },\n" + " \"target_crs\": {\n" + " \"type\": \"GeographicCRS\",\n" + " \"name\": \"GDA2020\",\n" + " \"datum\": {\n" + " \"type\": \"GeodeticReferenceFrame\",\n" + " \"name\": \"Geocentric Datum of Australia 2020\",\n" + " \"ellipsoid\": {\n" + " \"name\": \"GRS 1980\",\n" + " \"semi_major_axis\": 6378137,\n" + " \"inverse_flattening\": 298.257222101\n" + " }\n" + " },\n" + " \"coordinate_system\": {\n" + " \"subtype\": \"ellipsoidal\",\n" + " \"axis\": [\n" + " {\n" + " \"name\": \"Geodetic latitude\",\n" + " \"abbreviation\": \"Lat\",\n" + " \"direction\": \"north\",\n" + " \"unit\": \"degree\"\n" + " },\n" + " {\n" + " \"name\": \"Geodetic longitude\",\n" + " \"abbreviation\": \"Lon\",\n" + " \"direction\": \"east\",\n" + " \"unit\": \"degree\"\n" + " }\n" + " ]\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 7844\n" + " }\n" + " },\n" + " \"method\": {\n" + " \"name\": \"Coordinate Frame rotation (geog2D domain)\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 9607\n" + " }\n" + " },\n" + " \"parameters\": [\n" + " {\n" + " \"name\": \"X-axis translation\",\n" + " \"value\": 61.55,\n" + " \"unit\": {\n" + " \"type\": \"LinearUnit\",\n" + " \"name\": \"millimetre\",\n" + " \"conversion_factor\": 0.001\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8605\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Y-axis translation\",\n" + " \"value\": -10.87,\n" + " \"unit\": {\n" + " \"type\": \"LinearUnit\",\n" + " \"name\": \"millimetre\",\n" + " \"conversion_factor\": 0.001\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8606\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Z-axis translation\",\n" + " \"value\": -40.19,\n" + " \"unit\": {\n" + " \"type\": \"LinearUnit\",\n" + " \"name\": \"millimetre\",\n" + " \"conversion_factor\": 0.001\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8607\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"X-axis rotation\",\n" + " \"value\": -39.4924,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"milliarc-second\",\n" + " \"conversion_factor\": 4.84813681109536e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8608\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Y-axis rotation\",\n" + " \"value\": -32.7221,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"milliarc-second\",\n" + " \"conversion_factor\": 4.84813681109536e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8609\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Z-axis rotation\",\n" + " \"value\": -32.8979,\n" + " \"unit\": {\n" + " \"type\": \"AngularUnit\",\n" + " \"name\": \"milliarc-second\",\n" + " \"conversion_factor\": 4.84813681109536e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8610\n" + " }\n" + " },\n" + " {\n" + " \"name\": \"Scale difference\",\n" + " \"value\": -9.994,\n" + " \"unit\": {\n" + " \"type\": \"ScaleUnit\",\n" + " \"name\": \"parts per billion\",\n" + " \"conversion_factor\": 1e-09\n" + " },\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8611\n" + " }\n" + " }\n" + " ],\n" + " \"accuracy\": \"0.01\",\n" + " \"id\": {\n" + " \"authority\": \"EPSG\",\n" + " \"code\": 8048\n" + " },\n" + " \"remarks\": \"remarks\"\n" + " }\n" + " ],\n" + " \"area\": \"Australia - GDA\",\n" + " \"bbox\": {\n" + " \"south_latitude\": -60.56,\n" + " \"west_longitude\": 93.41,\n" + " \"north_latitude\": -8.47,\n" + " \"east_longitude\": 173.35\n" + " }\n" + "}"; + auto obj = createFromUserInput(json, nullptr); + auto concat = nn_dynamic_pointer_cast(obj); + ASSERT_TRUE(concat != nullptr); + EXPECT_EQ(concat->exportToJSON((JSONFormatter::create().get())), json); +} diff --git a/travis/install.sh b/travis/install.sh index 7a31e5c26a..249e0f2c8b 100755 --- a/travis/install.sh +++ b/travis/install.sh @@ -57,6 +57,25 @@ cat out.json echo "Validating JSON" jsonschema -i out.json /tmp/proj_autoconf_install_from_dist_all/share/proj/crsjson.schema.json && echo "Valid !" +/tmp/proj_autoconf_install_from_dist_all/bin/projinfo EPSG:4326+3855 -o PROJJSON -q > out.json +cat out.json +echo "Validating JSON" +jsonschema -i out.json /tmp/proj_autoconf_install_from_dist_all/share/proj/crsjson.schema.json && echo "Valid !" + +/tmp/proj_autoconf_install_from_dist_all/bin/projinfo "+proj=longlat +ellps=GRS80 +nadgrids=@foo +type=crs" -o PROJJSON -q > out.json +cat out.json +echo "Validating JSON" +jsonschema -i out.json /tmp/proj_autoconf_install_from_dist_all/share/proj/crsjson.schema.json && echo "Valid !" +/tmp/proj_autoconf_install_from_dist_all/bin/projinfo @out.json -o PROJJSON -q > out2.json +diff -u out.json out2.json + +/tmp/proj_autoconf_install_from_dist_all/bin/projinfo -s EPSG:3111 -t GDA2020 -o PROJJSON -o PROJJSON -q > out.json +cat out.json +echo "Validating JSON" +jsonschema -i out.json /tmp/proj_autoconf_install_from_dist_all/share/proj/crsjson.schema.json && echo "Valid !" +/tmp/proj_autoconf_install_from_dist_all/bin/projinfo @out.json -o PROJJSON -q > out2.json +diff -u out.json out2.json + cd .. # cmake build from generated tarball