Skip to content

Commit

Permalink
C API: add proj_concatoperation_get_step_count() and proj_concatopera…
Browse files Browse the repository at this point in the history
…tion_get_step()
  • Loading branch information
rouault committed Jul 1, 2019
1 parent a9c3567 commit 7493200
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
2 changes: 2 additions & 0 deletions scripts/reference_exported_symbols.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions src/iso19111/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<const ConcatenatedOperation *>(
concatoperation->iso_obj.get());
if (!l_co) {
proj_log_error(ctx, __FUNCTION__,
"Object is not a ConcatenatedOperation");
return false;
}
return static_cast<int>(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<const ConcatenatedOperation *>(
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<size_t>(i_step) >= steps.size()) {
proj_log_error(ctx, __FUNCTION__, "Invalid step index");
return nullptr;
}
return pj_obj_create(ctx, steps[i_step]);
}
7 changes: 7 additions & 0 deletions src/proj.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
69 changes: 69 additions & 0 deletions test/unit/test_c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 7493200

Please sign in to comment.