Skip to content

Commit

Permalink
Implement AffineCS and handle it in WKT/PROJJSON
Browse files Browse the repository at this point in the history
  • Loading branch information
rouault committed Jan 21, 2023
1 parent 8f9b77d commit 4b50aac
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 1 deletion.
1 change: 1 addition & 0 deletions data/projjson.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@
"vertical",
"ordinal",
"parametric",
"affine",
"TemporalDateTime",
"TemporalCount",
"TemporalMeasure"] },
Expand Down
1 change: 1 addition & 0 deletions docs/source/specifications/projjson.rst
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ History of the schema
- Added CoordinateMetadata
- Added "datum_epoch" property to GeodeticReferenceFrame and VerticalReferenceFrame
- Added "minimum_value", "maximum_value" and "range_meaning" properties to Axis
- Added "affine" in the CoordinateSystem.subtype enumeration.
* v0.5:
- Implemented in PROJ 9.1:
+ add "meridian" member in Axis object type.
Expand Down
50 changes: 50 additions & 0 deletions include/proj/coordinatesystem.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,56 @@ class PROJ_GCC_DLL CartesianCS final : public CoordinateSystem {

// ---------------------------------------------------------------------------

class AffineCS;
/** Shared pointer of AffineCS. */
using AffineCSPtr = std::shared_ptr<AffineCS>;
/** Non-null shared pointer of AffineCS. */
using AffineCSNNPtr = util::nn<AffineCSPtr>;

/** \brief A two- or three-dimensional coordinate system in Euclidean space
* with straight axes that are not necessarily orthogonal.
*
* \remark Implements AffineCS from \ref ISO_19111_2019
* \since 9.2
*/
class PROJ_GCC_DLL AffineCS final : public CoordinateSystem {
public:
//! @cond Doxygen_Suppress
PROJ_DLL ~AffineCS() override;
//! @endcond

PROJ_DLL static AffineCSNNPtr
create(const util::PropertyMap &properties,
const CoordinateSystemAxisNNPtr &axis1,
const CoordinateSystemAxisNNPtr &axis2);
PROJ_DLL static AffineCSNNPtr
create(const util::PropertyMap &properties,
const CoordinateSystemAxisNNPtr &axis1,
const CoordinateSystemAxisNNPtr &axis2,
const CoordinateSystemAxisNNPtr &axis3);

PROJ_PRIVATE :
//! @cond Doxygen_Suppress
PROJ_INTERNAL AffineCSNNPtr
alterUnit(const common::UnitOfMeasure &unit) const;

//! @endcond

protected:
PROJ_INTERNAL explicit AffineCS(
const std::vector<CoordinateSystemAxisNNPtr> &axisIn);
INLINED_MAKE_SHARED

PROJ_INTERNAL std::string getWKT2Type(bool) const override {
return "affine";
}

private:
AffineCS(const AffineCS &other) = delete;
};

// ---------------------------------------------------------------------------

class OrdinalCS;
/** Shared pointer of OrdinalCS. */
using OrdinalCSPtr = std::shared_ptr<OrdinalCS>;
Expand Down
1 change: 1 addition & 0 deletions schemas/v0.6/projjson.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@
"vertical",
"ordinal",
"parametric",
"affine",
"TemporalDateTime",
"TemporalCount",
"TemporalMeasure"] },
Expand Down
3 changes: 3 additions & 0 deletions scripts/reference_exported_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ osgeo::proj::crs::VerticalCRS::geoidModel() const
osgeo::proj::crs::VerticalCRS::identify(std::shared_ptr<osgeo::proj::io::AuthorityFactory> const&) const
osgeo::proj::crs::VerticalCRS::velocityModel() const
osgeo::proj::crs::VerticalCRS::~VerticalCRS()
osgeo::proj::cs::AffineCS::~AffineCS()
osgeo::proj::cs::AffineCS::create(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&)
osgeo::proj::cs::AffineCS::create(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::cs::CoordinateSystemAxis> > const&)
osgeo::proj::cs::AxisDirection::valueOf(std::string const&)
osgeo::proj::cs::CartesianCS::~CartesianCS()
osgeo::proj::cs::CartesianCS::createEastingNorthing(osgeo::proj::common::UnitOfMeasure const&)
Expand Down
67 changes: 67 additions & 0 deletions src/iso19111/coordinatesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,73 @@ CartesianCS::alterUnit(const common::UnitOfMeasure &unit) const {

// ---------------------------------------------------------------------------

//! @cond Doxygen_Suppress
AffineCS::~AffineCS() = default;
//! @endcond

// ---------------------------------------------------------------------------

AffineCS::AffineCS(const std::vector<CoordinateSystemAxisNNPtr> &axisIn)
: CoordinateSystem(axisIn) {}

// ---------------------------------------------------------------------------

/** \brief Instantiate a AffineCS.
*
* @param properties See \ref general_properties.
* @param axis1 The first axis.
* @param axis2 The second axis.
* @return a new AffineCS.
*/
AffineCSNNPtr AffineCS::create(const util::PropertyMap &properties,
const CoordinateSystemAxisNNPtr &axis1,
const CoordinateSystemAxisNNPtr &axis2) {
std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2};
auto cs(AffineCS::nn_make_shared<AffineCS>(axis));
cs->setProperties(properties);
return cs;
}

// ---------------------------------------------------------------------------

/** \brief Instantiate a AffineCS.
*
* @param properties See \ref general_properties.
* @param axis1 The first axis.
* @param axis2 The second axis.
* @param axis3 The third axis.
* @return a new AffineCS.
*/
AffineCSNNPtr AffineCS::create(const util::PropertyMap &properties,
const CoordinateSystemAxisNNPtr &axis1,
const CoordinateSystemAxisNNPtr &axis2,
const CoordinateSystemAxisNNPtr &axis3) {
std::vector<CoordinateSystemAxisNNPtr> axis{axis1, axis2, axis3};
auto cs(AffineCS::nn_make_shared<AffineCS>(axis));
cs->setProperties(properties);
return cs;
}

// ---------------------------------------------------------------------------

//! @cond Doxygen_Suppress
AffineCSNNPtr AffineCS::alterUnit(const common::UnitOfMeasure &unit) const {
const auto &l_axisList = CoordinateSystem::getPrivate()->axisList;
if (l_axisList.size() == 2) {
return AffineCS::create(util::PropertyMap(),
l_axisList[0]->alterUnit(unit),
l_axisList[1]->alterUnit(unit));
} else {
assert(l_axisList.size() == 3);
return AffineCS::create(
util::PropertyMap(), l_axisList[0]->alterUnit(unit),
l_axisList[1]->alterUnit(unit), l_axisList[2]->alterUnit(unit));
}
}
//! @endcond

// ---------------------------------------------------------------------------

//! @cond Doxygen_Suppress
OrdinalCS::~OrdinalCS() = default;
//! @endcond
Expand Down
20 changes: 19 additions & 1 deletion src/iso19111/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2940,7 +2940,8 @@ WKTParser::Private::buildCS(const WKTNodeNNPtr &node, /* maybe null */
: ci_equal(csType, "parametric")
? UnitOfMeasure::Type::PARAMETRIC
: ci_equal(csType, "Cartesian") ||
ci_equal(csType, "vertical")
ci_equal(csType, "vertical") ||
ci_equal(csType, "affine")
? UnitOfMeasure::Type::LINEAR
: (ci_equal(csType, "temporal") ||
ci_equal(csType, "TemporalDateTime") ||
Expand Down Expand Up @@ -2972,6 +2973,13 @@ WKTParser::Private::buildCS(const WKTNodeNNPtr &node, /* maybe null */
return CartesianCS::create(csMap, axisList[0], axisList[1],
axisList[2]);
}
} else if (ci_equal(csType, "affine")) {
if (axisCount == 2) {
return AffineCS::create(csMap, axisList[0], axisList[1]);
} else if (axisCount == 3) {
return AffineCS::create(csMap, axisList[0], axisList[1],
axisList[2]);
}
} else if (ci_equal(csType, "vertical")) {
if (axisCount == 1) {
return VerticalCS::create(csMap, axisList[0]);
Expand Down Expand Up @@ -6635,6 +6643,16 @@ CoordinateSystemNNPtr JSONParser::buildCS(const json &j) {
}
throw ParsingException("Expected 2 or 3 axis");
}
if (subtype == "affine") {
if (axisCount == 2) {
return AffineCS::create(csMap, axisList[0], axisList[1]);
}
if (axisCount == 3) {
return AffineCS::create(csMap, axisList[0], axisList[1],
axisList[2]);
}
throw ParsingException("Expected 2 or 3 axis");
}
if (subtype == "vertical") {
if (axisCount == 1) {
return VerticalCS::create(csMap, axisList[0]);
Expand Down
61 changes: 61 additions & 0 deletions test/unit/test_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2979,6 +2979,30 @@ TEST(wkt_parse, vdatum_with_ANCHOREPOCH) {

// ---------------------------------------------------------------------------

TEST(wkt_parse, engineeringCRS_WKT2_affine_CS) {

auto wkt = "ENGCRS[\"Engineering CRS\",\n"
" EDATUM[\"Engineering datum\"],\n"
" CS[affine,2],\n"
" AXIS[\"(E)\",east,\n"
" ORDER[1],\n"
" LENGTHUNIT[\"metre\",1,\n"
" ID[\"EPSG\",9001]]],\n"
" AXIS[\"(N)\",north,\n"
" ORDER[2],\n"
" LENGTHUNIT[\"metre\",1,\n"
" ID[\"EPSG\",9001]]]]";

auto obj = WKTParser().createFromWKT(wkt);
auto crs = nn_dynamic_pointer_cast<EngineeringCRS>(obj);
ASSERT_TRUE(crs != nullptr);
EXPECT_EQ(crs->exportToWKT(
WKTFormatter::create(WKTFormatter::Convention::WKT2).get()),
wkt);
}

// ---------------------------------------------------------------------------

TEST(wkt_parse, COMPOUNDCRS) {
auto obj = WKTParser().createFromWKT(
"COMPOUNDCRS[\"horizontal + vertical\",\n"
Expand Down Expand Up @@ -15599,6 +15623,43 @@ TEST(json_import, engineering_crs) {

// ---------------------------------------------------------------------------

TEST(json_import, engineering_crs_affine_CS) {

auto json = "{\n"
" \"$schema\": \"foo\",\n"
" \"type\": \"EngineeringCRS\",\n"
" \"name\": \"myEngCRS\",\n"
" \"datum\": {\n"
" \"name\": \"myEngDatum\"\n"
" },\n"
" \"coordinate_system\": {\n"
" \"subtype\": \"affine\",\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"
"}";

auto obj = createFromUserInput(json, nullptr);
auto crs = nn_dynamic_pointer_cast<EngineeringCRS>(obj);
ASSERT_TRUE(crs != nullptr);
EXPECT_EQ(crs->exportToJSON(&(JSONFormatter::create()->setSchema("foo"))),
json);
}

// ---------------------------------------------------------------------------

TEST(json_import, temporal_crs) {
auto json = "{\n"
" \"$schema\": \"foo\",\n"
Expand Down

0 comments on commit 4b50aac

Please sign in to comment.