aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2019-05-06 19:45:27 +0200
committerEven Rouault <even.rouault@spatialys.com>2019-05-06 20:21:27 +0200
commit61cf8c5b29c82ab7e46b207bd125eaad49c03021 (patch)
tree0d02cecceb233a94fa931caa47aed2c33543c53b
parent5e98fed78205605ccb01ab4310d3cba292de73b4 (diff)
downloadPROJ-61cf8c5b29c82ab7e46b207bd125eaad49c03021.tar.gz
PROJ-61cf8c5b29c82ab7e46b207bd125eaad49c03021.zip
createOperations(): for 'Amersfoort / RD New + NAP height' (EPSG:7415) to ETRS89 (EPSG:4937), make sure that the vgridshift is applied first (ie on Amersfoort datum) before the hgridshift
-rw-r--r--data/sql/customizations.sql19
-rw-r--r--include/proj/coordinateoperation.hpp3
-rw-r--r--include/proj/internal/internal.hpp3
-rw-r--r--include/proj/io.hpp3
-rw-r--r--scripts/reference_exported_symbols.txt3
-rw-r--r--src/iso19111/coordinateoperation.cpp111
-rw-r--r--src/iso19111/internal.cpp15
-rw-r--r--src/iso19111/io.cpp20
-rw-r--r--test/unit/test_operation.cpp28
9 files changed, 169 insertions, 36 deletions
diff --git a/data/sql/customizations.sql b/data/sql/customizations.sql
index ee023700..0ce4a692 100644
--- a/data/sql/customizations.sql
+++ b/data/sql/customizations.sql
@@ -19,6 +19,25 @@ DELETE FROM "supersession" WHERE superseded_table_name = 'grid_transformation' A
replacement_code = '8885' AND
source = 'EPSG';
+-- ('EPSG','7001','ETRS89 to NAP height (1)') lacks an interpolationCRS with Amersfoort / EPSG:4289
+-- See https://salsa.debian.org/debian-gis-team/proj-rdnap/blob/debian/2008-8/Use%20of%20RDTRANS2008%20and%20NAPTRANS2008.pdf
+-- "The naptrans2008 VDatum-grid is referenced to the Bessel-1841 ellipsoid"
+CREATE TABLE dummy(foo);
+CREATE TRIGGER check_grid_transformation_epsg_7001
+BEFORE INSERT ON dummy
+FOR EACH ROW BEGIN
+ SELECT RAISE(ABORT, 'grid_transformation EPSG:7001 entry is not ETRS89 to NAP height (1)')
+ WHERE NOT EXISTS(SELECT 1 FROM grid_transformation WHERE auth_name = 'EPSG' AND code = '7001' AND name = 'ETRS89 to NAP height (1)');
+ SELECT RAISE(ABORT, 'grid_transformation EPSG:7001 entry has already an interpolationCRS')
+ WHERE EXISTS(SELECT 1 FROM grid_transformation WHERE auth_name = 'EPSG' AND code = '7001' AND interpolation_crs_auth_name IS NOT NULL);
+END;
+INSERT INTO dummy DEFAULT VALUES;
+DROP TRIGGER check_grid_transformation_epsg_7001;
+DROP TABLE dummy;
+UPDATE grid_transformation SET interpolation_crs_auth_name = 'EPSG',
+ interpolation_crs_code = '4289'
+ WHERE auth_name = 'EPSG' AND code = '7001';
+
-- Define the allowed authorities, and their precedence, when researching a
-- coordinate operation
diff --git a/include/proj/coordinateoperation.hpp b/include/proj/coordinateoperation.hpp
index 994cbab2..7ade26f2 100644
--- a/include/proj/coordinateoperation.hpp
+++ b/include/proj/coordinateoperation.hpp
@@ -1476,7 +1476,8 @@ class PROJ_GCC_DLL Transformation : public SingleOperation {
PROJ_DLL static TransformationNNPtr
createGravityRelatedHeightToGeographic3D(
const util::PropertyMap &properties, const crs::CRSNNPtr &sourceCRSIn,
- const crs::CRSNNPtr &targetCRSIn, const std::string &filename,
+ const crs::CRSNNPtr &targetCRSIn, const crs::CRSPtr &interpolationCRSIn,
+ const std::string &filename,
const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies);
PROJ_DLL static TransformationNNPtr createVERTCON(
diff --git a/include/proj/internal/internal.hpp b/include/proj/internal/internal.hpp
index 220c137b..2222a264 100644
--- a/include/proj/internal/internal.hpp
+++ b/include/proj/internal/internal.hpp
@@ -140,6 +140,9 @@ std::string toupper(const std::string &osStr);
PROJ_FOR_TEST std::vector<std::string> split(const std::string &osStr,
char separator);
+PROJ_FOR_TEST std::vector<std::string> split(const std::string &osStr,
+ const std::string &separator);
+
bool ci_equal(const char *a, const char *b) noexcept;
#ifdef SUPPORT_DELETED_FUNCTION
diff --git a/include/proj/io.hpp b/include/proj/io.hpp
index a603533e..c553598d 100644
--- a/include/proj/io.hpp
+++ b/include/proj/io.hpp
@@ -427,7 +427,8 @@ class PROJ_GCC_DLL PROJStringFormatter {
PROJ_INTERNAL void setOmitProjLongLatIfPossible(bool omit);
PROJ_INTERNAL bool omitProjLongLatIfPossible() const;
- PROJ_INTERNAL void setOmitZUnitConversion(bool omit);
+ PROJ_INTERNAL void pushOmitZUnitConversion();
+ PROJ_INTERNAL void popOmitZUnitConversion();
PROJ_INTERNAL bool omitZUnitConversion() const;
PROJ_INTERNAL void setDropEarlyBindingsTerms(bool drop);
diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt
index 5d774eef..fe217812 100644
--- a/scripts/reference_exported_symbols.txt
+++ b/scripts/reference_exported_symbols.txt
@@ -279,6 +279,7 @@ osgeo::proj::internal::ci_find(std::string const&, char const*)
osgeo::proj::internal::c_locale_stod(std::string const&)
osgeo::proj::internal::replaceAll(std::string const&, std::string const&, std::string const&)
osgeo::proj::internal::split(std::string const&, char)
+osgeo::proj::internal::split(std::string const&, std::string const&)
osgeo::proj::internal::tolower(std::string const&)
osgeo::proj::internal::toString(double, int)
osgeo::proj::io::AuthorityFactory::~AuthorityFactory()
@@ -618,7 +619,7 @@ osgeo::proj::operation::Transformation::createGeocentricTranslations(osgeo::proj
osgeo::proj::operation::Transformation::createGeographic2DOffsets(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
osgeo::proj::operation::Transformation::createGeographic2DWithHeightOffsets(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
osgeo::proj::operation::Transformation::createGeographic3DOffsets(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Angle const&, osgeo::proj::common::Length const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
-osgeo::proj::operation::Transformation::createGravityRelatedHeightToGeographic3D(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, std::string const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
+osgeo::proj::operation::Transformation::createGravityRelatedHeightToGeographic3D(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, std::shared_ptr<osgeo::proj::crs::CRS> const&, std::string const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
osgeo::proj::operation::Transformation::createLongitudeRotation(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, osgeo::proj::common::Angle const&)
osgeo::proj::operation::Transformation::createMolodensky(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, double, double, double, double, double, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
osgeo::proj::operation::Transformation::createNTv2(osgeo::proj::util::PropertyMap const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::crs::CRS> > const&, std::string const&, std::vector<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> >, std::allocator<dropbox::oxygen::nn<std::shared_ptr<osgeo::proj::metadata::PositionalAccuracy> > > > const&)
diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp
index f75f7588..348a776a 100644
--- a/src/iso19111/coordinateoperation.cpp
+++ b/src/iso19111/coordinateoperation.cpp
@@ -6958,11 +6958,11 @@ TransformationNNPtr Transformation::createNTv2(
static TransformationNNPtr _createGravityRelatedHeightToGeographic3D(
const util::PropertyMap &properties, bool inverse,
const crs::CRSNNPtr &sourceCRSIn, const crs::CRSNNPtr &targetCRSIn,
- const std::string &filename,
+ const crs::CRSPtr &interpolationCRSIn, const std::string &filename,
const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) {
return Transformation::create(
- properties, sourceCRSIn, targetCRSIn, nullptr,
+ properties, sourceCRSIn, targetCRSIn, interpolationCRSIn,
util::PropertyMap().set(
common::IdentifiedObject::NAME_KEY,
inverse ? INVERSE_OF + PROJ_WKT2_NAME_METHOD_HEIGHT_TO_GEOG3D
@@ -6981,17 +6981,20 @@ static TransformationNNPtr _createGravityRelatedHeightToGeographic3D(
* At minimum the name should be defined.
* @param sourceCRSIn Source CRS.
* @param targetCRSIn Target CRS.
+ * @param interpolationCRSIn Interpolation CRS. (might be null)
* @param filename GRID filename.
* @param accuracies Vector of positional accuracy (might be empty).
* @return new Transformation.
*/
TransformationNNPtr Transformation::createGravityRelatedHeightToGeographic3D(
const util::PropertyMap &properties, const crs::CRSNNPtr &sourceCRSIn,
- const crs::CRSNNPtr &targetCRSIn, const std::string &filename,
+ const crs::CRSNNPtr &targetCRSIn, const crs::CRSPtr &interpolationCRSIn,
+ const std::string &filename,
const std::vector<metadata::PositionalAccuracyNNPtr> &accuracies) {
return _createGravityRelatedHeightToGeographic3D(
- properties, false, sourceCRSIn, targetCRSIn, filename, accuracies);
+ properties, false, sourceCRSIn, targetCRSIn, interpolationCRSIn,
+ filename, accuracies);
}
// ---------------------------------------------------------------------------
@@ -7302,8 +7305,20 @@ createPropertiesForInverse(const CoordinateOperation *op, bool derivedFrom,
auto targetCRS = op->targetCRS();
std::string name;
if (!forwardName.empty()) {
- if (starts_with(forwardName, INVERSE_OF)) {
- name = forwardName.substr(INVERSE_OF.size());
+ if (starts_with(forwardName, INVERSE_OF) ||
+ forwardName.find(" + ") != std::string::npos) {
+ auto tokens = split(forwardName, " + ");
+ for (size_t i = tokens.size(); i > 0;) {
+ i--;
+ if (!name.empty()) {
+ name += " + ";
+ }
+ if (starts_with(tokens[i], INVERSE_OF)) {
+ name += tokens[i].substr(INVERSE_OF.size());
+ } else {
+ name += INVERSE_OF + tokens[i];
+ }
+ }
} else if (!sourceCRS || !targetCRS ||
forwardName != buildOpName(opType, sourceCRS, targetCRS)) {
name = INVERSE_OF + forwardName;
@@ -8195,13 +8210,14 @@ TransformationNNPtr Transformation::substitutePROJAlternativeGridNames(
return createGravityRelatedHeightToGeographic3D(
createPropertiesForInverse(self.as_nullable().get(),
true, false),
- targetCRS(), sourceCRS(), projFilename,
- coordinateOperationAccuracies())
+ targetCRS(), sourceCRS(), interpolationCRS(),
+ projFilename, coordinateOperationAccuracies())
->inverseAsTransformation();
} else {
return createGravityRelatedHeightToGeographic3D(
createSimilarPropertiesTransformation(self), sourceCRS(),
- targetCRS(), projFilename, coordinateOperationAccuracies());
+ targetCRS(), interpolationCRS(), projFilename,
+ coordinateOperationAccuracies());
}
}
}
@@ -10972,19 +10988,19 @@ struct MyPROJStringExportableHorizVertical final
// cppcheck-suppress functionStatic
_exportToPROJString(io::PROJStringFormatter *formatter) const override {
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
horizTransform->_exportToPROJString(formatter);
formatter->startInversion();
geogDst->addAngularUnitConvertAndAxisSwap(formatter);
formatter->stopInversion();
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
verticalTransform->_exportToPROJString(formatter);
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
geogDst->addAngularUnitConvertAndAxisSwap(formatter);
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
}
};
@@ -11016,7 +11032,7 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final
// cppcheck-suppress functionStatic
_exportToPROJString(io::PROJStringFormatter *formatter) const override {
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
opSrcCRSToGeogCRS->_exportToPROJString(formatter);
@@ -11024,17 +11040,17 @@ struct MyPROJStringExportableHorizVerticalHorizPROJBased final
interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter);
formatter->stopInversion();
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
verticalTransform->_exportToPROJString(formatter);
- formatter->setOmitZUnitConversion(true);
+ formatter->pushOmitZUnitConversion();
interpolationGeogCRS->addAngularUnitConvertAndAxisSwap(formatter);
opGeogCRStoDstCRS->_exportToPROJString(formatter);
- formatter->setOmitZUnitConversion(false);
+ formatter->popOmitZUnitConversion();
}
};
@@ -12380,7 +12396,8 @@ CoordinateOperationFactory::Private::createOperations(
const auto &componentsSrc = compoundSrc->componentReferenceSystems();
if (!componentsSrc.empty()) {
std::vector<CoordinateOperationNNPtr> horizTransforms;
- if (componentsSrc[0]->extractGeographicCRS()) {
+ auto srcGeogCRS = componentsSrc[0]->extractGeographicCRS();
+ if (srcGeogCRS) {
horizTransforms =
createOperations(componentsSrc[0], targetCRS, context);
}
@@ -12394,11 +12411,61 @@ CoordinateOperationFactory::Private::createOperations(
for (const auto &horizTransform : horizTransforms) {
for (const auto &verticalTransform : verticalTransforms) {
- auto op = createHorizVerticalPROJBased(
- sourceCRS, targetCRS, horizTransform,
- verticalTransform);
+ crs::GeographicCRSPtr interpolationGeogCRS;
+ auto transformationVerticalTransform =
+ dynamic_cast<const Transformation *>(
+ verticalTransform.get());
+ if (transformationVerticalTransform) {
+ auto interpTransformCRS =
+ transformationVerticalTransform
+ ->interpolationCRS();
+ if (interpTransformCRS) {
+ auto nn_interpTransformCRS =
+ NN_NO_CHECK(interpTransformCRS);
+ if (dynamic_cast<const crs::GeographicCRS *>(
+ nn_interpTransformCRS.get())) {
+ interpolationGeogCRS =
+ util::nn_dynamic_pointer_cast<
+ crs::GeographicCRS>(
+ nn_interpTransformCRS);
+ }
+ }
+ }
+ bool done = false;
+ if (interpolationGeogCRS &&
+ (interpolationGeogCRS->_isEquivalentTo(
+ srcGeogCRS.get(),
+ util::IComparable::Criterion::EQUIVALENT) ||
+ interpolationGeogCRS->is2DPartOf3D(
+ NN_NO_CHECK(srcGeogCRS.get())))) {
+ auto srcToInterp = createOperations(
+ componentsSrc[0],
+ NN_NO_CHECK(interpolationGeogCRS), context);
+ auto interpToCompoundHoriz = createOperations(
+ NN_NO_CHECK(interpolationGeogCRS),
+ componentsSrc[0], context);
+ if (!srcToInterp.empty() &&
+ !interpToCompoundHoriz.empty()) {
+ auto op = createHorizVerticalHorizPROJBased(
+ sourceCRS, componentsSrc[0],
+ srcToInterp.front(), verticalTransform,
+ interpToCompoundHoriz.front(),
+ interpolationGeogCRS);
+ done = true;
+ res.emplace_back(
+ ConcatenatedOperation::
+ createComputeMetadata(
+ {op, horizTransform},
+ !allowEmptyIntersection));
+ }
+ }
+ if (!done) {
+ auto op = createHorizVerticalPROJBased(
+ sourceCRS, targetCRS, horizTransform,
+ verticalTransform);
- res.emplace_back(op);
+ res.emplace_back(op);
+ }
}
}
return res;
diff --git a/src/iso19111/internal.cpp b/src/iso19111/internal.cpp
index 240c98f4..4810202d 100644
--- a/src/iso19111/internal.cpp
+++ b/src/iso19111/internal.cpp
@@ -298,6 +298,21 @@ std::vector<std::string> split(const std::string &str, char separator) {
// ---------------------------------------------------------------------------
+std::vector<std::string> split(const std::string &str,
+ const std::string &separator) {
+ std::vector<std::string> res;
+ size_t lastPos = 0;
+ size_t newPos = 0;
+ while ((newPos = str.find(separator, lastPos)) != std::string::npos) {
+ res.push_back(str.substr(lastPos, newPos - lastPos));
+ lastPos = newPos + separator.size();
+ }
+ res.push_back(str.substr(lastPos));
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+
#ifdef _WIN32
// For some reason, sqlite3_snprintf() in the sqlite3 builds used on AppVeyor
diff --git a/src/iso19111/io.cpp b/src/iso19111/io.cpp
index e072a66f..c84ea2f3 100644
--- a/src/iso19111/io.cpp
+++ b/src/iso19111/io.cpp
@@ -3818,7 +3818,7 @@ CRSNNPtr WKTParser::Private::buildVerticalCRS(const WKTNodeNNPtr &node) {
Transformation::createGravityRelatedHeightToGeographic3D(
PropertyMap().set(IdentifiedObject::NAME_KEY,
transformationName),
- crs, GeographicCRS::EPSG_4979,
+ crs, GeographicCRS::EPSG_4979, nullptr,
stripQuotes(extensionChildren[1]),
std::vector<PositionalAccuracyNNPtr>());
return nn_static_pointer_cast<CRS>(BoundCRS::create(
@@ -4922,7 +4922,7 @@ struct PROJStringFormatter::Private {
};
std::vector<InversionStackElt> inversionStack_{InversionStackElt()};
bool omitProjLongLatIfPossible_ = false;
- bool omitZUnitConversion_ = false;
+ std::vector<bool> omitZUnitConversion_{false};
DatabaseContextPtr dbContext_{};
bool useApproxTMerc_ = false;
bool addNoDefs_ = true;
@@ -5939,15 +5939,21 @@ bool PROJStringFormatter::omitProjLongLatIfPossible() const {
// ---------------------------------------------------------------------------
-void PROJStringFormatter::setOmitZUnitConversion(bool omit) {
- assert(d->omitZUnitConversion_ ^ omit);
- d->omitZUnitConversion_ = omit;
+void PROJStringFormatter::pushOmitZUnitConversion() {
+ d->omitZUnitConversion_.push_back(true);
+}
+
+// ---------------------------------------------------------------------------
+
+void PROJStringFormatter::popOmitZUnitConversion() {
+ assert(d->omitZUnitConversion_.size() > 1);
+ d->omitZUnitConversion_.pop_back();
}
// ---------------------------------------------------------------------------
bool PROJStringFormatter::omitZUnitConversion() const {
- return d->omitZUnitConversion_;
+ return d->omitZUnitConversion_.back();
}
// ---------------------------------------------------------------------------
@@ -6995,7 +7001,7 @@ PROJStringParser::Private::buildBoundOrCompoundCRSIfNeeded(int iStep,
Transformation::createGravityRelatedHeightToGeographic3D(
PropertyMap().set(IdentifiedObject::NAME_KEY,
"unknown to WGS84 ellipsoidal height"),
- crs, GeographicCRS::EPSG_4979, geoidgrids,
+ crs, GeographicCRS::EPSG_4979, nullptr, geoidgrids,
std::vector<PositionalAccuracyNNPtr>());
auto boundvcrs =
BoundCRS::create(vcrs, GeographicCRS::EPSG_4979, transformation);
diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp
index f3d9eefe..5ac1609d 100644
--- a/test/unit/test_operation.cpp
+++ b/test/unit/test_operation.cpp
@@ -5970,8 +5970,8 @@ static BoundCRSNNPtr createBoundVerticalCRS() {
auto vertCRS = createVerticalCRS();
auto transformation =
Transformation::createGravityRelatedHeightToGeographic3D(
- PropertyMap(), vertCRS, GeographicCRS::EPSG_4979, "egm08_25.gtx",
- std::vector<PositionalAccuracyNNPtr>());
+ PropertyMap(), vertCRS, GeographicCRS::EPSG_4979, nullptr,
+ "egm08_25.gtx", std::vector<PositionalAccuracyNNPtr>());
return BoundCRS::create(vertCRS, GeographicCRS::EPSG_4979, transformation);
}
@@ -6756,6 +6756,22 @@ TEST(operation, compoundCRS_from_WKT2_no_id_to_geogCRS_3D_context) {
auto list =
CoordinateOperationFactory::create()->createOperations(src, dst, ctxt);
ASSERT_GE(list.size(), 1U);
+
+ {
+ // Important here is vgridshift before hgridshift
+ auto op_proj =
+ list[0]->exportToPROJString(PROJStringFormatter::create().get());
+ EXPECT_EQ(
+ op_proj,
+ "+proj=pipeline +step +inv +proj=sterea +lat_0=52.1561605555556 "
+ "+lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 "
+ "+ellps=bessel "
+ "+step +proj=vgridshift +grids=naptrans2008.gtx +multiplier=1 "
+ "+step +proj=hgridshift +grids=rdtrans2008.gsb "
+ "+step +proj=unitconvert +xy_in=rad +z_in=m +xy_out=deg +z_out=m "
+ "+step +proj=axisswap +order=2,1");
+ }
+
auto wkt2 =
"COMPOUNDCRS[\"unknown\",\n"
" PROJCRS[\"unknown\",\n"
@@ -6788,8 +6804,12 @@ TEST(operation, compoundCRS_from_WKT2_no_id_to_geogCRS_3D_context) {
for (size_t i = 0; i < list.size(); i++) {
const auto &op = list[i];
const auto &op2 = list2[i];
- EXPECT_TRUE(
- op->isEquivalentTo(op2.get(), IComparable::Criterion::EQUIVALENT));
+ auto op_proj =
+ op->exportToPROJString(PROJStringFormatter::create().get());
+ auto op2_proj =
+ op2->exportToPROJString(PROJStringFormatter::create().get());
+ EXPECT_EQ(op_proj, op2_proj) << "op=" << op->nameStr()
+ << " op2=" << op2->nameStr();
}
}