diff options
| author | Even Rouault <even.rouault@spatialys.com> | 2020-05-14 15:11:02 +0200 |
|---|---|---|
| committer | Even Rouault <even.rouault@spatialys.com> | 2020-05-14 18:51:40 +0200 |
| commit | 11012ebcc910c4d95d5acbff43f444715ae1ad32 (patch) | |
| tree | 777757d7c6daf0e29900d4a49328a6cc78a7afbd | |
| parent | 0c9cf39297a24d5e56aa488820a5ba3edaace90e (diff) | |
| download | PROJ-11012ebcc910c4d95d5acbff43f444715ae1ad32.tar.gz PROJ-11012ebcc910c4d95d5acbff43f444715ae1ad32.zip | |
WKT/PROJJSON parsing: fix BoundCRS/PROJ4_GRIDS handling for vertical component when vertical CRS has non metre unit (fixes #2217)
| -rw-r--r-- | src/iso19111/io.cpp | 137 | ||||
| -rw-r--r-- | test/unit/test_io.cpp | 26 | ||||
| -rw-r--r-- | test/unit/test_operation.cpp | 55 |
3 files changed, 164 insertions, 54 deletions
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp index 97f741be..7fddd324 100644 --- a/src/iso19111/io.cpp +++ b/src/iso19111/io.cpp @@ -3987,6 +3987,79 @@ WKTParser::Private::buildParametricDatum(const WKTNodeNNPtr &node) { // --------------------------------------------------------------------------- +static CRSNNPtr +createBoundCRSSourceTransformationCRS(const crs::CRSPtr &sourceCRS, + const crs::CRSPtr &targetCRS) { + CRSPtr sourceTransformationCRS; + if (dynamic_cast<GeographicCRS *>(targetCRS.get())) { + GeographicCRSPtr sourceGeographicCRS = + sourceCRS->extractGeographicCRS(); + sourceTransformationCRS = sourceGeographicCRS; + if (sourceGeographicCRS) { + if (sourceGeographicCRS->datum() != nullptr && + sourceGeographicCRS->primeMeridian() + ->longitude() + .getSIValue() != 0.0) { + sourceTransformationCRS = + GeographicCRS::create( + util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + sourceGeographicCRS->nameStr() + + " (with Greenwich prime meridian)"), + datum::GeodeticReferenceFrame::create( + util::PropertyMap().set( + common::IdentifiedObject::NAME_KEY, + sourceGeographicCRS->datum()->nameStr() + + " (with Greenwich prime meridian)"), + sourceGeographicCRS->datum()->ellipsoid(), + util::optional<std::string>(), + datum::PrimeMeridian::GREENWICH), + sourceGeographicCRS->coordinateSystem()) + .as_nullable(); + } + } else { + auto vertSourceCRS = + std::dynamic_pointer_cast<VerticalCRS>(sourceCRS); + if (!vertSourceCRS) { + throw ParsingException( + "Cannot find GeographicCRS or VerticalCRS in sourceCRS"); + } + const auto &axis = vertSourceCRS->coordinateSystem()->axisList()[0]; + if (axis->unit() == common::UnitOfMeasure::METRE && + &(axis->direction()) == &AxisDirection::UP) { + sourceTransformationCRS = sourceCRS; + } else { + std::string sourceTransformationCRSName( + vertSourceCRS->nameStr()); + if (ends_with(sourceTransformationCRSName, " (ftUS)")) { + sourceTransformationCRSName.resize( + sourceTransformationCRSName.size() - strlen(" (ftUS)")); + } + if (ends_with(sourceTransformationCRSName, " depth")) { + sourceTransformationCRSName.resize( + sourceTransformationCRSName.size() - strlen(" depth")); + } + if (!ends_with(sourceTransformationCRSName, " height")) { + sourceTransformationCRSName += " height"; + } + sourceTransformationCRS = + VerticalCRS::create( + PropertyMap().set(IdentifiedObject::NAME_KEY, + sourceTransformationCRSName), + vertSourceCRS->datum(), vertSourceCRS->datumEnsemble(), + VerticalCS::createGravityRelatedHeight( + common::UnitOfMeasure::METRE)) + .as_nullable(); + } + } + } else { + sourceTransformationCRS = sourceCRS; + } + return NN_NO_CHECK(sourceTransformationCRS); +} + +// --------------------------------------------------------------------------- + CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { const auto *nodeP = node->GP(); auto &datumNode = @@ -4111,16 +4184,18 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) { gridName != "g2012a_conus.gtx,g2012a_alaska.gtx," "g2012a_guam.gtx,g2012a_hawaii.gtx," "g2012a_puertorico.gtx,g2012a_samoa.gtx") { - std::string transformationName(crs->nameStr()); - if (!ends_with(transformationName, " height")) { - transformationName += " height"; - } - transformationName += " to WGS84 ellipsoidal height"; + auto sourceTransformationCRS = + createBoundCRSSourceTransformationCRS( + crs.as_nullable(), + GeographicCRS::EPSG_4979.as_nullable()); auto transformation = Transformation:: createGravityRelatedHeightToGeographic3D( - PropertyMap().set(IdentifiedObject::NAME_KEY, - transformationName), - crs, GeographicCRS::EPSG_4979, nullptr, gridName, + PropertyMap().set( + IdentifiedObject::NAME_KEY, + sourceTransformationCRS->nameStr() + + " to WGS84 ellipsoidal height"), + sourceTransformationCRS, GeographicCRS::EPSG_4979, + nullptr, gridName, std::vector<PositionalAccuracyNNPtr>()); return nn_static_pointer_cast<CRS>(BoundCRS::create( crs, GeographicCRS::EPSG_4979, transformation)); @@ -4190,52 +4265,6 @@ CRSNNPtr WKTParser::Private::buildCompoundCRS(const WKTNodeNNPtr &node) { // --------------------------------------------------------------------------- -static CRSNNPtr -createBoundCRSSourceTransformationCRS(const crs::CRSPtr &sourceCRS, - const crs::CRSPtr &targetCRS) { - CRSPtr sourceTransformationCRS; - if (dynamic_cast<GeographicCRS *>(targetCRS.get())) { - GeographicCRSPtr sourceGeographicCRS = - sourceCRS->extractGeographicCRS(); - sourceTransformationCRS = sourceGeographicCRS; - if (sourceGeographicCRS) { - if (sourceGeographicCRS->datum() != nullptr && - sourceGeographicCRS->primeMeridian() - ->longitude() - .getSIValue() != 0.0) { - sourceTransformationCRS = - GeographicCRS::create( - util::PropertyMap().set( - common::IdentifiedObject::NAME_KEY, - sourceGeographicCRS->nameStr() + - " (with Greenwich prime meridian)"), - datum::GeodeticReferenceFrame::create( - util::PropertyMap().set( - common::IdentifiedObject::NAME_KEY, - sourceGeographicCRS->datum()->nameStr() + - " (with Greenwich prime meridian)"), - sourceGeographicCRS->datum()->ellipsoid(), - util::optional<std::string>(), - datum::PrimeMeridian::GREENWICH), - sourceGeographicCRS->coordinateSystem()) - .as_nullable(); - } - } else { - sourceTransformationCRS = - std::dynamic_pointer_cast<VerticalCRS>(sourceCRS); - if (!sourceTransformationCRS) { - throw ParsingException( - "Cannot find GeographicCRS or VerticalCRS in sourceCRS"); - } - } - } else { - sourceTransformationCRS = sourceCRS; - } - return NN_NO_CHECK(sourceTransformationCRS); -} - -// --------------------------------------------------------------------------- - BoundCRSNNPtr WKTParser::Private::buildBoundCRS(const WKTNodeNNPtr &node) { const auto *nodeP = node->GP(); auto &abridgedNode = diff --git a/test/unit/test_io.cpp b/test/unit/test_io.cpp index 0570bb7e..e57cb003 100644 --- a/test/unit/test_io.cpp +++ b/test/unit/test_io.cpp @@ -3442,6 +3442,32 @@ TEST(wkt_parse, WKT1_VERT_DATUM_EXTENSION) { // --------------------------------------------------------------------------- +TEST(wkt_parse, WKT1_VERT_DATUM_EXTENSION_units_ftUS) { + auto wkt = "VERT_CS[\"NAVD88 height (ftUS)\"," + " VERT_DATUM[\"North American Vertical Datum 1988\",2005," + " EXTENSION[\"PROJ4_GRIDS\",\"foo.gtx\"]," + " AUTHORITY[\"EPSG\",\"5103\"]]," + " UNIT[\"US survey foot\",0.304800609601219," + " AUTHORITY[\"EPSG\",\"9003\"]]," + " AXIS[\"Gravity-related height\",UP]," + " AUTHORITY[\"EPSG\",\"6360\"]]"; + + auto obj = WKTParser().createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<BoundCRS>(obj); + ASSERT_TRUE(crs != nullptr); + + EXPECT_EQ(crs->transformation()->nameStr(), + "NAVD88 height to WGS84 ellipsoidal height"); // no (ftUS) + auto sourceTransformationCRS = crs->transformation()->sourceCRS(); + auto sourceTransformationVertCRS = + nn_dynamic_pointer_cast<VerticalCRS>(sourceTransformationCRS); + EXPECT_EQ( + sourceTransformationVertCRS->coordinateSystem()->axisList()[0]->unit(), + UnitOfMeasure::METRE); +} + +// --------------------------------------------------------------------------- + TEST(wkt_parse, WKT1_DATUM_EXTENSION) { auto wkt = "PROJCS[\"unnamed\",\n" diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp index 9b339525..d8944aa8 100644 --- a/test/unit/test_operation.cpp +++ b/test/unit/test_operation.cpp @@ -7136,6 +7136,61 @@ TEST(operation, // --------------------------------------------------------------------------- +TEST(operation, + compoundCRS_with_boundProjCRS_with_ftus_and_boundVerticalCRS_to_geogCRS) { + + auto wkt = + "COMPD_CS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet + " + "NAVD88 height - Geoid12B (US Feet)\",\n" + " PROJCS[\"NAD_1983_StatePlane_Alabama_West_FIPS_0102_Feet\",\n" + " GEOGCS[\"NAD83\",\n" + " DATUM[\"North_American_Datum_1983\",\n" + " SPHEROID[\"GRS 1980\",6378137,298.257222101,\n" + " AUTHORITY[\"EPSG\",\"7019\"]],\n" + " TOWGS84[0,0,0,0,0,0,0],\n" + " AUTHORITY[\"EPSG\",\"6269\"]],\n" + " PRIMEM[\"Greenwich\",0],\n" + " UNIT[\"Degree\",0.0174532925199433]],\n" + " PROJECTION[\"Transverse_Mercator\"],\n" + " PARAMETER[\"latitude_of_origin\",30],\n" + " PARAMETER[\"central_meridian\",-87.5],\n" + " PARAMETER[\"scale_factor\",0.999933333333333],\n" + " PARAMETER[\"false_easting\",1968500],\n" + " PARAMETER[\"false_northing\",0],\n" + " UNIT[\"US survey foot\",0.304800609601219,\n" + " AUTHORITY[\"EPSG\",\"9003\"]],\n" + " AXIS[\"Easting\",EAST],\n" + " AXIS[\"Northing\",NORTH],\n" + " AUTHORITY[\"ESRI\",\"102630\"]],\n" + " VERT_CS[\"NAVD88 height (ftUS)\",\n" + " VERT_DATUM[\"North American Vertical Datum 1988\",2005,\n" + " EXTENSION[\"PROJ4_GRIDS\",\"foo.gtx\"],\n" + " AUTHORITY[\"EPSG\",\"5103\"]],\n" + " UNIT[\"US survey foot\",0.304800609601219,\n" + " AUTHORITY[\"EPSG\",\"9003\"]],\n" + " AXIS[\"Gravity-related height\",UP],\n" + " AUTHORITY[\"EPSG\",\"6360\"]]]"; + + auto obj = WKTParser().createFromWKT(wkt); + auto crs = nn_dynamic_pointer_cast<BoundCRS>(obj); + ASSERT_TRUE(crs != nullptr); + auto op = CoordinateOperationFactory::create()->createOperation( + NN_NO_CHECK(crs), GeographicCRS::EPSG_4979); + ASSERT_TRUE(op != nullptr); + + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=unitconvert +xy_in=us-ft +xy_out=m " + "+step +inv +proj=tmerc +lat_0=30 +lon_0=-87.5 " + "+k=0.999933333333333 +x_0=600000 +y_0=0 +ellps=GRS80 " + "+step +proj=unitconvert +z_in=us-ft +z_out=m " + "+step +proj=vgridshift +grids=foo.gtx +multiplier=1 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg " + "+step +proj=axisswap +order=2,1"); +} + +// --------------------------------------------------------------------------- + TEST(operation, geocent_to_compoundCRS) { auto objSrc = PROJStringParser().createFromPROJString( "+proj=geocent +datum=WGS84 +units=m +type=crs"); |
