diff options
| -rw-r--r-- | data/sql/grid_alternatives.sql | 1 | ||||
| -rw-r--r-- | data/sql/grid_transformation.sql | 4 | ||||
| -rw-r--r-- | data/sql/proj_db_table_defs.sql | 2 | ||||
| -rw-r--r-- | include/proj/internal/coordinateoperation_constants.hpp | 15 | ||||
| -rwxr-xr-x | scripts/build_db.py | 10 | ||||
| -rw-r--r-- | src/iso19111/coordinateoperation.cpp | 129 | ||||
| -rw-r--r-- | src/proj_constants.h | 8 | ||||
| -rw-r--r-- | test/unit/test_operation.cpp | 17 |
8 files changed, 181 insertions, 5 deletions
diff --git a/data/sql/grid_alternatives.sql b/data/sql/grid_alternatives.sql index b92dbaa0..b9c2e323 100644 --- a/data/sql/grid_alternatives.sql +++ b/data/sql/grid_alternatives.sql @@ -9,6 +9,7 @@ INSERT INTO grid_alternatives(original_grid_name, VALUES -- the PROJ grid is the reverse way of the EPSG one ('rgf93_ntf.gsb','fr_ign_ntf_r93.tif','ntf_r93.gsb','GTiff','hgridshift',1,NULL,'https://cdn.proj.org/fr_ign_ntf_r93.tif',1,1,NULL), +('gr3df97a.txt','fr_ign_gr3df97a.tif',NULL,'GTiff','geocentricoffset',0,NULL,'https://cdn.proj.org/fr_ign_gr3df97a.tif',1,1,NULL), ('NTv1_0.gsb','ca_nrc_ntv1_can.tif','ntv1_can.dat','GTiff','hgridshift',0,NULL,'https://cdn.proj.org/ca_nrc_ntv1_can.tif',1,1,NULL), -- just a case change ('NTv2_0.gsb','ca_nrc_ntv2_0.tif','ntv2_0.gsb','GTiff','hgridshift',0,NULL,'https://cdn.proj.org/ca_nrc_ntv2_0.tif',1,1,NULL), diff --git a/data/sql/grid_transformation.sql b/data/sql/grid_transformation.sql index 0498a2a1..5197cc9a 100644 --- a/data/sql/grid_transformation.sql +++ b/data/sql/grid_transformation.sql @@ -364,6 +364,10 @@ INSERT INTO "grid_transformation" VALUES('EPSG','9323','NZVD2016 height to Taran INSERT INTO "grid_transformation" VALUES('EPSG','9324','NZVD2016 height to Wellington 1953 height (2)','Derived at 137 control points. Mean offset 0.408m, standard deviation 0.054m, maximum difference from mean 0.112m. Supersedes NZVD2016 height to Wellington 1953 height (1) (code 7872) after change of grid file format.','Transformation between national and local height systems.','EPSG','1084','Vertical Offset by Grid Interpolation (gtx)','EPSG','7839','EPSG','5770','EPSG','3773',0.02,'EPSG','8732','Vertical offset file','wellht1953-nzvd2016.gtx',NULL,NULL,NULL,NULL,'EPSG','4167','LINZ-NZ WGTN gtx',0); INSERT INTO "grid_transformation" VALUES('EPSG','9325','NZGD2000 to NZVD2009 height (2)','Defines NZVD2009 vertical datum (datum code 1039, CRS code 4440). Supersedes NZGD2000 to NZVD2009 height (1) (code 4459) after change of grid file format.','Derivation of gravity-related heights from GPS observations.','EPSG','9665','Geographic3D to GravityRelatedHeight (gtx)','EPSG','4959','EPSG','4440','EPSG','1175',0.1,'EPSG','8666','Geoid (height correction) model file','nzgeoid2009.gtx',NULL,NULL,NULL,NULL,NULL,NULL,'LINZ-NZ 2009 gtx',0); INSERT INTO "grid_transformation" VALUES('EPSG','9326','NZGD2000 to NZVD2016 height (2)','Defines NZVD2016 vertical datum (datum code 1169, CRS code 7839). Supersedes NZGD2000 to NZVD2016 height (1) (code 7840) after change of grid file format.','Derivation of gravity-related heights from GPS observations.','EPSG','9665','Geographic3D to GravityRelatedHeight (gtx)','EPSG','4959','EPSG','7839','EPSG','1175',0.1,'EPSG','8666','Geoid (height correction) model file','nzgeoid2016.gtx',NULL,NULL,NULL,NULL,NULL,NULL,'LINZ-NZ 2016 gtx',0); +INSERT INTO "grid_transformation" VALUES('EPSG','9327','NTF to RGF93 (1)','May be emulated using NTv2 method - see tfm code 15958.','For applications requiring an accuracy of better than 1 metre.','EPSG','1087','Geocentric translation by Grid Interpolation (IGN)','EPSG','4275','EPSG','4171','EPSG','3694',1.0,'EPSG','8727','Geocentric translation file','gr3df97a.txt',NULL,NULL,NULL,NULL,'EPSG','4171','IGN-Fra 1m',0); +INSERT INTO "grid_transformation" VALUES('EPSG','9328','NEA74 Noumea to RGNC91-93 (3)','Developed in July 2002 and officially adopted in August 2005. May be emulated using NTv2 method - see RGNC91-93 to NEA74 Noumea (4) (code 1295).','Accuracy 5-10cm.','EPSG','1087','Geocentric translation by Grid Interpolation (IGN)','EPSG','4644','EPSG','4749','EPSG','2823',0.05,'EPSG','8727','Geocentric translation file','gr3dnc03a.mnt',NULL,NULL,NULL,NULL,'EPSG','4749','BGN-Ncl 0.05m',0); +INSERT INTO "grid_transformation" VALUES('EPSG','9329','IGN72 Grande Terre to RGNC91-93 (4)','Developed in July 2002 and officially adopted in August 2005. May be emulated using NTv2 method - see RGNC91-93 to IGN72 Grande Terre (6) (code 15962).','Accuracy better than +/- 0.1 metre.','EPSG','1087','Geocentric translation by Grid Interpolation (IGN)','EPSG','4662','EPSG','4749','EPSG','2822',0.1,'EPSG','8727','Geocentric translation file','gr3dnc01b.mnt',NULL,NULL,NULL,NULL,'EPSG','4749','BGN-Ncl 0.1m',0); +INSERT INTO "grid_transformation" VALUES('EPSG','9330','IGN72 Grande Terre to RGNC91-93 (5)','Developed in July 2002 and officially adopted in August 2005.','Accuracy 5-10cm.','EPSG','1087','Geocentric translation by Grid Interpolation (IGN)','EPSG','4662','EPSG','4749','EPSG','2823',0.05,'EPSG','8727','Geocentric translation file','gr3dnc02b.mnt',NULL,NULL,NULL,NULL,'EPSG','4749','BGN-Ncl Noum 0.05m',0); INSERT INTO "grid_transformation" VALUES('EPSG','10000','RGF93 to NGF IGN69 height (1)','May be used for transformations from WGS 84 to NGF IGN69. Accuracy at each 0.1 deg x 0.1 degree grid node is given within the geoid model file.','Derivation of gravity-related heights from GPS observations.','EPSG','9664','Geographic3D to GravityRelatedHeight (IGN1997)','EPSG','4965','EPSG','5720','EPSG','1326',0.5,'EPSG','8666','Geoid (height correction) model file','ggf97a.txt',NULL,NULL,NULL,NULL,NULL,NULL,'IGN Fra',0); INSERT INTO "grid_transformation" VALUES('EPSG','10001','ETRS89 to NGF IGN69 height (1)','Parameter values taken from RGF93 to NGF IGN69 (1) (code 10000) assuming that RGF93 is equivalent to ETRS89 within the accuracy of the transformation. Accuracy at each 0.1 deg x 0.1 degree grid node is given within the geoid model file.','Derivation of gravity-related heights from GPS observations.','EPSG','9664','Geographic3D to GravityRelatedHeight (IGN1997)','EPSG','4937','EPSG','5720','EPSG','1326',0.5,'EPSG','8666','Geoid (height correction) model file','ggf97a.txt',NULL,NULL,NULL,NULL,NULL,NULL,'IGN Fra',0); INSERT INTO "grid_transformation" VALUES('EPSG','10002','RGF93 to IGN78 Corsica height (1)','May be used for transformations from WGS 84 to IGN78 Corsica. Accuracy at each 0.1 deg x 0.1 degree grid node is given within the geoid model file.','Derivation of gravity-related heights from GPS observations.','EPSG','9664','Geographic3D to GravityRelatedHeight (IGN1997)','EPSG','4965','EPSG','5721','EPSG','1327',0.5,'EPSG','8666','Geoid (height correction) model file','ggf97a_corse.txt',NULL,NULL,NULL,NULL,NULL,NULL,'IGN Fra Cor',0); diff --git a/data/sql/proj_db_table_defs.sql b/data/sql/proj_db_table_defs.sql index 8de27a48..b820b207 100644 --- a/data/sql/proj_db_table_defs.sql +++ b/data/sql/proj_db_table_defs.sql @@ -1103,7 +1103,7 @@ CREATE TABLE grid_alternatives( CONSTRAINT fk_grid_alternatives_grid_packages FOREIGN KEY (package_name) REFERENCES grid_packages(package_name), CONSTRAINT check_grid_alternatives_grid_fromat CHECK (proj_grid_format IN ('GTiff', 'GTX', 'NTv2')), - CONSTRAINT check_grid_alternatives_proj_method CHECK (proj_method IN ('hgridshift', 'vgridshift', 'geoid_like')), + CONSTRAINT check_grid_alternatives_proj_method CHECK (proj_method IN ('hgridshift', 'vgridshift', 'geoid_like', 'geocentricoffset')), CONSTRAINT check_grid_alternatives_inverse_direction CHECK (NOT(proj_method = 'geoid_like' AND inverse_direction = 1)), CONSTRAINT check_grid_alternatives_package_name CHECK (package_name IS NULL), CONSTRAINT check_grid_alternatives_direct_download_url CHECK (NOT(direct_download IS NULL AND url IS NOT NULL)), diff --git a/include/proj/internal/coordinateoperation_constants.hpp b/include/proj/internal/coordinateoperation_constants.hpp index 349c1086..55ef0dcc 100644 --- a/include/proj/internal/coordinateoperation_constants.hpp +++ b/include/proj/internal/coordinateoperation_constants.hpp @@ -860,6 +860,7 @@ static const struct MethodNameCode { METHOD_NAME_CODE(GEOGRAPHIC3D_OFFSETS), METHOD_NAME_CODE(VERTICAL_OFFSET), METHOD_NAME_CODE(NTV2), METHOD_NAME_CODE(NTV1), METHOD_NAME_CODE(NADCON), METHOD_NAME_CODE(VERTCON), + METHOD_NAME_CODE(GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN), }; #define PARAM_NAME_CODE(method) \ @@ -920,6 +921,7 @@ static const struct ParamNameCode { PARAM_NAME_CODE(ORDINATE_1_EVAL_POINT), PARAM_NAME_CODE(ORDINATE_2_EVAL_POINT), PARAM_NAME_CODE(ORDINATE_3_EVAL_POINT), + PARAM_NAME_CODE(GEOCENTRIC_TRANSLATION_FILE), }; static const ParamMapping paramUnitConversionScalar = { @@ -1129,6 +1131,15 @@ static const ParamMapping paramLatitudeLongitudeDifferenceFile = { static const ParamMapping *const paramsNTV2[] = { ¶mLatitudeLongitudeDifferenceFile, nullptr}; +static const ParamMapping paramGeocentricTranslationFile = { + EPSG_NAME_PARAMETER_GEOCENTRIC_TRANSLATION_FILE, + EPSG_CODE_PARAMETER_GEOCENTRIC_TRANSLATION_FILE, nullptr, + common::UnitOfMeasure::Type::NONE, nullptr}; + +static const ParamMapping + *const paramsGeocentricTranslationGridInterpolationIGN[] = { + ¶mGeocentricTranslationFile, nullptr}; + static const ParamMapping paramLatitudeDifferenceFile = { EPSG_NAME_PARAMETER_LATITUDE_DIFFERENCE_FILE, EPSG_CODE_PARAMETER_LATITUDE_DIFFERENCE_FILE, nullptr, @@ -1288,6 +1299,10 @@ static const MethodMapping otherMethodMappings[] = { {EPSG_NAME_METHOD_NTV1, EPSG_CODE_METHOD_NTV1, nullptr, nullptr, nullptr, paramsNTV2}, + {EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN, + EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN, nullptr, + nullptr, nullptr, paramsGeocentricTranslationGridInterpolationIGN}, + {EPSG_NAME_METHOD_NADCON, EPSG_CODE_METHOD_NADCON, nullptr, nullptr, nullptr, paramsNADCON}, diff --git a/scripts/build_db.py b/scripts/build_db.py index c2203ecf..6eed3867 100755 --- a/scripts/build_db.py +++ b/scripts/build_db.py @@ -348,10 +348,10 @@ def fill_helmert_transformation(proj_db_cursor): '?,?,?, ?,?, ?,?,?, ?,?, ?,?, ?,?, ?, ?,?,?,?,?, ?,?,?,?,?, ?,?,?, ?,?,?,?,?, ?,?,?,?,?, ?,?,?, ?,?,?, ?,?,?,?,?, ?,?)', arg) def fill_grid_transformation(proj_db_cursor): - proj_db_cursor.execute("SELECT coord_op_code, coord_op_name, coord_op_method_code, coord_op_method_name, source_crs_code, target_crs_code, area_of_use_code, coord_op_accuracy, coord_tfm_version, epsg_coordoperation.deprecated, coord_op_scope, epsg_coordoperation.remarks FROM epsg.epsg_coordoperation LEFT JOIN epsg.epsg_coordoperationmethod USING (coord_op_method_code) WHERE coord_op_type = 'transformation' AND (coord_op_method_name LIKE 'Geographic3D to%' OR coord_op_method_name LIKE 'Geog3D to%' OR coord_op_method_name LIKE 'Point motion by grid%' OR coord_op_method_name LIKE 'Vertical Offset by Grid Interpolation%' OR coord_op_method_name IN ('NADCON', 'NADCON5 (2D)', 'NTv1', 'NTv2', 'VERTCON'))") + proj_db_cursor.execute("SELECT coord_op_code, coord_op_name, coord_op_method_code, coord_op_method_name, source_crs_code, target_crs_code, area_of_use_code, coord_op_accuracy, coord_tfm_version, epsg_coordoperation.deprecated, coord_op_scope, epsg_coordoperation.remarks FROM epsg.epsg_coordoperation LEFT JOIN epsg.epsg_coordoperationmethod USING (coord_op_method_code) WHERE coord_op_type = 'transformation' AND (coord_op_method_name LIKE 'Geographic3D to%' OR coord_op_method_name LIKE 'Geog3D to%' OR coord_op_method_name LIKE 'Point motion by grid%' OR coord_op_method_name LIKE 'Vertical Offset by Grid Interpolation%' OR coord_op_method_name IN ('NADCON', 'NADCON5 (2D)', 'NTv1', 'NTv2', 'VERTCON', 'Geocentric translation by Grid Interpolation (IGN)'))") for (code, name, method_code, method_name, source_crs_code, target_crs_code, area_of_use_code, coord_op_accuracy, coord_tfm_version, deprecated, scope, remarks) in proj_db_cursor.fetchall(): expected_order = 1 - max_n_params = 2 + max_n_params = 3 if method_name == 'Geocentric translation by Grid Interpolation (IGN)' else 2 param_auth_name = [None for i in range(max_n_params)] param_code = [None for i in range(max_n_params)] param_name = [None for i in range(max_n_params)] @@ -374,7 +374,7 @@ def fill_grid_transformation(proj_db_cursor): expected_order += 1 n_params = expected_order - 1 - assert param_code[0] in (1050, 8656, 8657, 8666, 8732), (code, param_code[0]) + assert param_code[0] in (1050, 8656, 8657, 8666, 8732, 8727), (code, param_code[0]) grid2_param_auth_name = None grid2_param_code = None @@ -403,6 +403,10 @@ def fill_grid_transformation(proj_db_cursor): assert param_code[1] == 1048, (code, method_code, param_code[1]) interpolation_crs_auth_name = EPSG_AUTHORITY interpolation_crs_code = str(int(param_value[1])) # needed to avoid codes like XXXX.0 + elif method_name == 'Geocentric translation by Grid Interpolation (IGN)': + assert param_code[1] == 1048, (code, method_code, param_code[1]) + interpolation_crs_auth_name = EPSG_AUTHORITY + interpolation_crs_code = str(int(param_value[1])) # needed to avoid codes like XXXX.0 else: assert n_params == 1, (code, method_code) diff --git a/src/iso19111/coordinateoperation.cpp b/src/iso19111/coordinateoperation.cpp index 8ca95223..53fa64bf 100644 --- a/src/iso19111/coordinateoperation.cpp +++ b/src/iso19111/coordinateoperation.cpp @@ -8471,6 +8471,33 @@ _getHorizontalShiftGTIFFFilename(const Transformation *op, bool allowInverse) { //! @cond Doxygen_Suppress static const std::string & +_getGeocentricTranslationFilename(const Transformation *op, bool allowInverse) { + + const auto &l_method = op->method(); + const auto &methodName = l_method->nameStr(); + if (l_method->getEPSGCode() == + EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN || + (allowInverse && + ci_equal( + methodName, + INVERSE_OF + + EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN))) { + const auto &fileParameter = + op->parameterValue(EPSG_NAME_PARAMETER_GEOCENTRIC_TRANSLATION_FILE, + EPSG_CODE_PARAMETER_GEOCENTRIC_TRANSLATION_FILE); + if (fileParameter && + fileParameter->type() == ParameterValue::Type::FILENAME) { + return fileParameter->valueFile(); + } + } + return nullString; +} +//! @endcond + +// --------------------------------------------------------------------------- + +//! @cond Doxygen_Suppress +static const std::string & _getHeightToGeographic3DFilename(const Transformation *op, bool allowInverse) { const auto &methodName = op->method()->nameStr(); @@ -8801,6 +8828,34 @@ TransformationNNPtr Transformation::substitutePROJAlternativeGridNames( } } + const auto &geocentricTranslationFilename = + _getGeocentricTranslationFilename(this, false); + if (!geocentricTranslationFilename.empty()) { + if (databaseContext->lookForGridAlternative( + geocentricTranslationFilename, projFilename, projGridFormat, + inverseDirection)) { + + if (inverseDirection) { + throw util::UnsupportedOperationException( + "Inverse direction for " + "GeocentricTranslation not supported"); + } + + if (geocentricTranslationFilename == projFilename) { + return self; + } + + auto parameters = + std::vector<OperationParameterNNPtr>{createOpParamNameEPSGCode( + EPSG_CODE_PARAMETER_GEOCENTRIC_TRANSLATION_FILE)}; + return create(createSimilarPropertiesTransformation(self), + sourceCRS(), targetCRS(), interpolationCRS(), + createSimilarPropertiesMethod(method()), parameters, + {ParameterValue::createFilename(projFilename)}, + coordinateOperationAccuracies()); + } + } + if (methodEPSGCode == EPSG_CODE_METHOD_VERTCON || methodEPSGCode == EPSG_CODE_METHOD_VERTICALGRID_NZLVD || methodEPSGCode == EPSG_CODE_METHOD_VERTICALGRID_GTX) { @@ -9423,6 +9478,80 @@ void Transformation::_exportToPROJString( return; } + const auto &geocentricTranslationFilename = + _getGeocentricTranslationFilename(this, true); + if (!geocentricTranslationFilename.empty()) { + auto sourceCRSGeog = + dynamic_cast<const crs::GeographicCRS *>(sourceCRS().get()); + if (!sourceCRSGeog) { + throw io::FormattingException( + concat("Can apply ", methodName, " only to GeographicCRS")); + } + + auto targetCRSGeog = + dynamic_cast<const crs::GeographicCRS *>(targetCRS().get()); + if (!targetCRSGeog) { + throw io::FormattingException( + concat("Can apply ", methodName, " only to GeographicCRS")); + } + + const auto &interpCRS = interpolationCRS(); + if (!interpCRS) { + throw io::FormattingException( + "InterpolationCRS required " + "for" + " " EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN); + } + const bool interpIsSrc = interpCRS->_isEquivalentTo( + sourceCRS().get(), util::IComparable::Criterion::EQUIVALENT); + const bool interpIsTarget = interpCRS->_isEquivalentTo( + targetCRS().get(), util::IComparable::Criterion::EQUIVALENT); + if (!interpIsSrc && !interpIsTarget) { + throw io::FormattingException( + "For" + " " EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN + ", interpolation CRS should be the source or target CRS"); + } + + formatter->startInversion(); + sourceCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + formatter->stopInversion(); + + if (isMethodInverseOf) { + formatter->startInversion(); + } + + formatter->addStep("push"); + formatter->addParam("v_3"); + + formatter->addStep("cart"); + sourceCRSGeog->ellipsoid()->_exportToPROJString(formatter); + + formatter->addStep("xyzgridshift"); + formatter->addParam("grids", geocentricTranslationFilename); + formatter->addParam("grid_ref", + interpIsTarget ? "output_crs" : "input_crs"); + (interpIsTarget ? targetCRSGeog : sourceCRSGeog) + ->ellipsoid() + ->_exportToPROJString(formatter); + + formatter->startInversion(); + formatter->addStep("cart"); + targetCRSGeog->ellipsoid()->_exportToPROJString(formatter); + formatter->stopInversion(); + + formatter->addStep("pop"); + formatter->addParam("v_3"); + + if (isMethodInverseOf) { + formatter->stopInversion(); + } + + targetCRSGeog->addAngularUnitConvertAndAxisSwap(formatter); + + return; + } + const auto &heightFilename = _getHeightToGeographic3DFilename(this, true); if (!heightFilename.empty()) { if (isMethodInverseOf) { diff --git a/src/proj_constants.h b/src/proj_constants.h index 54dc7873..91c7264c 100644 --- a/src/proj_constants.h +++ b/src/proj_constants.h @@ -501,6 +501,14 @@ "Geoid (height correction) model file" #define EPSG_CODE_PARAMETER_GEOID_CORRECTION_FILENAME 8666 +#define EPSG_NAME_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN \ + "Geocentric translation by Grid Interpolation (IGN)" +#define EPSG_CODE_METHOD_GEOCENTRIC_TRANSLATION_BY_GRID_INTERPOLATION_IGN 1087 + +#define EPSG_CODE_PARAMETER_GEOCENTRIC_TRANSLATION_FILE 8727 +#define EPSG_NAME_PARAMETER_GEOCENTRIC_TRANSLATION_FILE \ + "Geocentric translation file" + /* ------------------------------------------------------------------------ */ #define PROJ_WKT2_NAME_METHOD_HEIGHT_TO_GEOG3D \ diff --git a/test/unit/test_operation.cpp b/test/unit/test_operation.cpp index ebd306ba..d4d1768e 100644 --- a/test/unit/test_operation.cpp +++ b/test/unit/test_operation.cpp @@ -4826,7 +4826,7 @@ TEST(operation, geogCRS_to_geogCRS_context_concatenated_operation) { authFactory->createCoordinateReferenceSystem("4807"), // NTF(Paris) authFactory->createCoordinateReferenceSystem("4171"), // RGF93 ctxt); - ASSERT_EQ(list.size(), 3U); + ASSERT_EQ(list.size(), 5U); EXPECT_EQ(list[0]->nameStr(), "NTF (Paris) to RGF93 (2)"); EXPECT_EQ(list[0]->exportToPROJString(PROJStringFormatter::create().get()), "+proj=pipeline +step +proj=axisswap +order=2,1 +step " @@ -4835,6 +4835,21 @@ TEST(operation, geogCRS_to_geogCRS_context_concatenated_operation) { "+grids=fr_ign_ntf_r93.tif +step +proj=unitconvert +xy_in=rad " "+xy_out=deg +step +proj=axisswap +order=2,1"); + EXPECT_EQ(list[1]->nameStr(), "NTF (Paris) to NTF (1) + NTF to RGF93 (1)"); + EXPECT_EQ(list[1]->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=axisswap +order=2,1 " + "+step +proj=unitconvert +xy_in=grad +xy_out=rad " + "+step +inv +proj=longlat +ellps=clrk80ign +pm=paris " + "+step +proj=push +v_3 " + "+step +proj=cart +ellps=clrk80ign " + "+step +proj=xyzgridshift +grids=fr_ign_gr3df97a.tif " + "+grid_ref=output_crs +ellps=GRS80 " + "+step +inv +proj=cart +ellps=GRS80 " + "+step +proj=pop +v_3 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg " + "+step +proj=axisswap +order=2,1"); + EXPECT_TRUE(nn_dynamic_pointer_cast<ConcatenatedOperation>(list[0]) != nullptr); auto grids = list[0]->gridsNeeded(DatabaseContext::create(), false); |
