From 74932008096b3135317d8c45cb9c9fabb5ab8c6b Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Mon, 1 Jul 2019 11:22:54 +0200 Subject: [PATCH] C API: add proj_concatoperation_get_step_count() and proj_concatoperation_get_step() --- scripts/reference_exported_symbols.txt | 2 + src/iso19111/c_api.cpp | 59 ++++++++++++++++++++++ src/proj.h | 7 +++ test/unit/test_c_api.cpp | 69 ++++++++++++++++++++++++++ 4 files changed, 137 insertions(+) diff --git a/scripts/reference_exported_symbols.txt b/scripts/reference_exported_symbols.txt index b759c96a1d..f3d13bd7c9 100644 --- a/scripts/reference_exported_symbols.txt +++ b/scripts/reference_exported_symbols.txt @@ -762,6 +762,8 @@ proj_as_proj_string proj_assign_context proj_as_wkt proj_clone +proj_concatoperation_get_step +proj_concatoperation_get_step_count proj_context_create proj_context_delete_cpp_context(projCppContext*) proj_context_destroy diff --git a/src/iso19111/c_api.cpp b/src/iso19111/c_api.cpp index bc1d0bd8e1..7a77ccfb69 100644 --- a/src/iso19111/c_api.cpp +++ b/src/iso19111/c_api.cpp @@ -6976,3 +6976,62 @@ PJ *proj_normalize_for_visualization(PJ_CONTEXT *ctx, const PJ *obj) { return nullptr; } } + +// --------------------------------------------------------------------------- + +/** \brief Returns the number of steps of a concatenated operation. + * + * The input object must be a concatenated operation. + * + * @param ctx PROJ context, or NULL for default context + * @param concatoperation Concatenated operation (must not be NULL) + * @return the number of steps, or 0 in case of error. + */ +int proj_concatoperation_get_step_count(PJ_CONTEXT *ctx, + const PJ *concatoperation) { + SANITIZE_CTX(ctx); + assert(concatoperation); + auto l_co = dynamic_cast( + concatoperation->iso_obj.get()); + if (!l_co) { + proj_log_error(ctx, __FUNCTION__, + "Object is not a ConcatenatedOperation"); + return false; + } + return static_cast(l_co->operations().size()); +} +// --------------------------------------------------------------------------- + +/** \brief Returns a step of a concatenated operation. + * + * The input object must be a concatenated operation. + * + * The returned object must be unreferenced with proj_destroy() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param concatoperation Concatenated operation (must not be NULL) + * @param i_step Index of the step to extract. Between 0 and + * proj_concatoperation_get_step_count()-1 + * @return Object that must be unreferenced with proj_destroy(), or NULL + * in case of error. + */ +PJ *proj_concatoperation_get_step(PJ_CONTEXT *ctx, const PJ *concatoperation, + int i_step) { + SANITIZE_CTX(ctx); + assert(concatoperation); + auto l_co = dynamic_cast( + concatoperation->iso_obj.get()); + if (!l_co) { + proj_log_error(ctx, __FUNCTION__, + "Object is not a ConcatenatedOperation"); + return nullptr; + } + const auto &steps = l_co->operations(); + if (i_step < 0 || static_cast(i_step) >= steps.size()) { + proj_log_error(ctx, __FUNCTION__, "Invalid step index"); + return nullptr; + } + return pj_obj_create(ctx, steps[i_step]); +} diff --git a/src/proj.h b/src/proj.h index 0282ddfef9..25cd981c6f 100644 --- a/src/proj.h +++ b/src/proj.h @@ -1064,6 +1064,13 @@ int PROJ_DLL proj_coordoperation_get_towgs84_values(PJ_CONTEXT *ctx, int value_count, int emit_error_if_incompatible); +int PROJ_DLL proj_concatoperation_get_step_count(PJ_CONTEXT *ctx, + const PJ *concatoperation); + +PJ PROJ_DLL *proj_concatoperation_get_step(PJ_CONTEXT *ctx, + const PJ *concatoperation, + int i_step); + /**@}*/ #ifdef __cplusplus diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index 99904fd42e..82974e133a 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -3420,4 +3420,73 @@ TEST_F(CApi, proj_get_scope) { } } +// --------------------------------------------------------------------------- + +TEST_F(CApi, proj_concatoperation_get_step) { + // Test on a non concatenated operation + { + auto co = proj_create_from_database(m_ctxt, "EPSG", "8048", + PJ_CATEGORY_COORDINATE_OPERATION, + false, nullptr); + ObjectKeeper keeper(co); + ASSERT_NE(co, nullptr); + ASSERT_NE(proj_get_type(co), PJ_TYPE_CONCATENATED_OPERATION); + + ASSERT_EQ(proj_concatoperation_get_step_count(m_ctxt, co), 0); + ASSERT_EQ(proj_concatoperation_get_step(m_ctxt, co, 0), nullptr); + } + // Test on a concatenated operation + { + auto ctxt = proj_create_operation_factory_context(m_ctxt, nullptr); + ASSERT_NE(ctxt, nullptr); + ContextKeeper keeper_ctxt(ctxt); + + // GDA94 / MGA zone 56 + auto source_crs = proj_create_from_database( + m_ctxt, "EPSG", "28356", PJ_CATEGORY_CRS, false, nullptr); + ASSERT_NE(source_crs, nullptr); + ObjectKeeper keeper_source_crs(source_crs); + + // GDA2020 / MGA zone 56 + auto target_crs = proj_create_from_database( + m_ctxt, "EPSG", "7856", PJ_CATEGORY_CRS, false, nullptr); + ASSERT_NE(target_crs, nullptr); + ObjectKeeper keeper_target_crs(target_crs); + + proj_operation_factory_context_set_spatial_criterion( + m_ctxt, ctxt, PROJ_SPATIAL_CRITERION_PARTIAL_INTERSECTION); + + proj_operation_factory_context_set_grid_availability_use( + m_ctxt, ctxt, PROJ_GRID_AVAILABILITY_IGNORED); + + auto res = proj_create_operations(m_ctxt, source_crs, target_crs, ctxt); + ASSERT_NE(res, nullptr); + ObjListKeeper keeper_res(res); + + ASSERT_GT(proj_list_get_count(res), 0); + + auto op = proj_list_get(m_ctxt, res, 0); + ASSERT_NE(op, nullptr); + ObjectKeeper keeper_op(op); + + ASSERT_EQ(proj_get_type(op), PJ_TYPE_CONCATENATED_OPERATION); + ASSERT_EQ(proj_concatoperation_get_step_count(m_ctxt, op), 3); + + EXPECT_EQ(proj_concatoperation_get_step(m_ctxt, op, -1), nullptr); + EXPECT_EQ(proj_concatoperation_get_step(m_ctxt, op, 3), nullptr); + + auto step = proj_concatoperation_get_step(m_ctxt, op, 1); + ASSERT_NE(step, nullptr); + ObjectKeeper keeper_step(step); + + const char* scope = proj_get_scope(step); + EXPECT_NE(scope, nullptr); + EXPECT_NE(std::string(scope), std::string()); + + const char* remarks = proj_get_remarks(step); + EXPECT_NE(remarks, nullptr); + EXPECT_NE(std::string(remarks), std::string()); + } +} + } // namespace