From 11869e2c4d29f0e607a0f78fb289d253fccd9a16 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Thu, 22 Aug 2019 22:52:48 +0200 Subject: [PATCH] Add proj_create_crs_to_crs_from_pj() I've been frustrated a number of times with proj_create_crs_to_crs() not accepting a PJ* object for the source and target CRS. And thus constraining to go back to WKT2 in a artificial way. --- .../development/reference/functions.rst | 12 +++++ scripts/reference_exported_symbols.txt | 1 + src/4D_api.cpp | 46 ++++++++++--------- src/proj.h | 5 ++ test/unit/test_c_api.cpp | 26 +++++++++++ 5 files changed, 69 insertions(+), 21 deletions(-) diff --git a/docs/source/development/reference/functions.rst b/docs/source/development/reference/functions.rst index 64a4e8caab..e5f4843953 100644 --- a/docs/source/development/reference/functions.rst +++ b/docs/source/development/reference/functions.rst @@ -153,6 +153,18 @@ paragraph for more details. :type `area`: PJ_AREA :returns: :c:type:`PJ*` +.. c:function:: PJ* proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, PJ *source_crs, PJ *target_crs, PJ_AREA *area, const char* const *options) + + .. versionadded:: 6.2.0 + + Create a transformation object that is a pipeline between two known + coordinate reference systems. + + This is the same as :c:func:`proj_create_crs_to_crs` except that the source and + target CRS are passed as PJ* objects which must of the CRS variety. + + :param `options`: should be set to NULL currently. + .. c:function:: PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ* obj) .. versionadded:: 6.1.0 diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index fa6b16a4ca..6df840999d 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -874,6 +874,7 @@ proj_create_conversion_wagner_v proj_create_conversion_wagner_vi proj_create_conversion_wagner_vii proj_create_crs_to_crs +proj_create_crs_to_crs_from_pj proj_create_cs proj_create_ellipsoidal_2D_cs proj_create_engineering_crs diff --git a/src/4D_api.cpp b/src/4D_api.cpp index 07ccfd919f..3a9582e64b 100644 --- a/src/4D_api.cpp +++ b/src/4D_api.cpp @@ -1045,10 +1045,27 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char return nullptr; } + auto ret = proj_create_crs_to_crs_from_pj(ctx, src, dst, area, nullptr); + proj_destroy(src); + proj_destroy(dst); + return ret; +} + +/*****************************************************************************/ +PJ *proj_create_crs_to_crs_from_pj (PJ_CONTEXT *ctx, PJ *source_crs, PJ *target_crs, PJ_AREA *area, const char* const *) { +/****************************************************************************** + Create a transformation pipeline between two known coordinate reference + systems. + + See docs/source/development/reference/functions.rst + +******************************************************************************/ + if( !ctx ) { + ctx = pj_get_default_ctx(); + } + auto operation_ctx = proj_create_operation_factory_context(ctx, nullptr); if( !operation_ctx ) { - proj_destroy(src); - proj_destroy(dst); return nullptr; } @@ -1067,12 +1084,10 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char proj_operation_factory_context_set_grid_availability_use( ctx, operation_ctx, PROJ_GRID_AVAILABILITY_DISCARD_OPERATION_IF_MISSING_GRID); - auto op_list = proj_create_operations(ctx, src, dst, operation_ctx); + auto op_list = proj_create_operations(ctx, source_crs, target_crs, operation_ctx); if( !op_list ) { proj_operation_factory_context_destroy(operation_ctx); - proj_destroy(src); - proj_destroy(dst); return nullptr; } @@ -1080,8 +1095,7 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char if( op_count == 0 ) { proj_list_destroy(op_list); proj_operation_factory_context_destroy(operation_ctx); - proj_destroy(src); - proj_destroy(dst); + proj_context_log_debug(ctx, "No operation found matching criteria"); return nullptr; } @@ -1090,35 +1104,29 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char assert(P); if( P == nullptr || op_count == 1 || (area && area->bbox_set) || - proj_get_type(src) == PJ_TYPE_GEOCENTRIC_CRS || - proj_get_type(dst) == PJ_TYPE_GEOCENTRIC_CRS ) { + proj_get_type(source_crs) == PJ_TYPE_GEOCENTRIC_CRS || + proj_get_type(target_crs) == PJ_TYPE_GEOCENTRIC_CRS ) { proj_list_destroy(op_list); proj_operation_factory_context_destroy(operation_ctx); - proj_destroy(src); - proj_destroy(dst); return P; } - auto pjGeogToSrc = create_operation_to_base_geog_crs(ctx, src); + auto pjGeogToSrc = create_operation_to_base_geog_crs(ctx, source_crs); if( !pjGeogToSrc ) { proj_list_destroy(op_list); proj_operation_factory_context_destroy(operation_ctx); - proj_destroy(src); - proj_destroy(dst); proj_context_log_debug(ctx, "Cannot create transformation from geographic CRS of source CRS to source CRS"); proj_destroy(P); return nullptr; } - auto pjGeogToDst = create_operation_to_base_geog_crs(ctx, dst); + auto pjGeogToDst = create_operation_to_base_geog_crs(ctx, target_crs); if( !pjGeogToDst ) { proj_list_destroy(op_list); proj_operation_factory_context_destroy(operation_ctx); - proj_destroy(src); - proj_destroy(dst); proj_context_log_debug(ctx, "Cannot create transformation from geographic CRS of target CRS to target CRS"); proj_destroy(P); @@ -1177,8 +1185,6 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char proj_list_destroy(op_list); proj_operation_factory_context_destroy(operation_ctx); - proj_destroy(src); - proj_destroy(dst); proj_destroy(pjGeogToSrc); proj_destroy(pjGeogToDst); @@ -1205,8 +1211,6 @@ PJ *proj_create_crs_to_crs (PJ_CONTEXT *ctx, const char *source_crs, const char { proj_list_destroy(op_list); proj_operation_factory_context_destroy(operation_ctx); - proj_destroy(src); - proj_destroy(dst); proj_destroy(pjGeogToSrc); proj_destroy(pjGeogToDst); proj_destroy(P); diff --git a/src/proj.h b/src/proj.h index 4a3e4c59f5..9cf83df714 100644 --- a/src/proj.h +++ b/src/proj.h @@ -357,6 +357,11 @@ int PROJ_DLL proj_context_get_use_proj4_init_rules(PJ_CONTEXT *ctx, int from_leg PJ PROJ_DLL *proj_create (PJ_CONTEXT *ctx, const char *definition); PJ PROJ_DLL *proj_create_argv (PJ_CONTEXT *ctx, int argc, char **argv); PJ PROJ_DLL *proj_create_crs_to_crs(PJ_CONTEXT *ctx, const char *source_crs, const char *target_crs, PJ_AREA *area); +PJ PROJ_DLL *proj_create_crs_to_crs_from_pj(PJ_CONTEXT *ctx, + PJ *source_crs, + PJ *target_crs, + PJ_AREA *area, + const char* const *options); PJ PROJ_DLL *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ* obj); PJ PROJ_DLL *proj_destroy (PJ *P); diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 74377738b9..2a1c857720 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -3711,4 +3711,30 @@ TEST_F(Fixture_proj_context_set_autoclose_database, proj_context_set_autoclose_database_false) { test(false); } + +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_create_crs_to_crs_from_pj) { + + auto src = proj_create(m_ctxt, "EPSG:4326"); + ObjectKeeper keeper_src(src); + ASSERT_NE(src, nullptr); + + auto dst = proj_create(m_ctxt, "EPSG:32631"); + ObjectKeeper keeper_dst(dst); + ASSERT_NE(dst, nullptr); + + auto P = proj_create_crs_to_crs_from_pj(m_ctxt, src, dst, nullptr, nullptr); + ObjectKeeper keeper_P(P); + ASSERT_NE(P, nullptr); + auto Pnormalized = proj_normalize_for_visualization(m_ctxt, P); + ObjectKeeper keeper_Pnormalized(Pnormalized); + ASSERT_NE(Pnormalized, nullptr); + auto projstr = proj_as_proj_string(m_ctxt, Pnormalized, PJ_PROJ_5, nullptr); + ASSERT_NE(projstr, nullptr); + EXPECT_EQ(std::string(projstr), + "+proj=pipeline +step +proj=unitconvert +xy_in=deg +xy_out=rad " + "+step +proj=utm +zone=31 +ellps=WGS84"); +} + } // namespace