diff options
| -rw-r--r-- | src/c_api.cpp | 220 | ||||
| -rw-r--r-- | src/proj_experimental.h | 15 | ||||
| -rw-r--r-- | test/unit/test_c_api.cpp | 72 |
3 files changed, 249 insertions, 58 deletions
diff --git a/src/c_api.cpp b/src/c_api.cpp index 82b9f715..ed770e15 100644 --- a/src/c_api.cpp +++ b/src/c_api.cpp @@ -2629,6 +2629,77 @@ PJ_OBJ PROJ_DLL *proj_obj_create_engineering_crs(PJ_CONTEXT *ctx, // --------------------------------------------------------------------------- +//! @cond Doxygen_Suppress + +static void setSingleOperationElements( + const char *name, const char *auth_name, const char *code, + const char *method_name, const char *method_auth_name, + const char *method_code, int param_count, + const PJ_PARAM_DESCRIPTION *params, PropertyMap &propSingleOp, + PropertyMap &propMethod, std::vector<OperationParameterNNPtr> ¶meters, + std::vector<ParameterValueNNPtr> &values) { + propSingleOp.set(common::IdentifiedObject::NAME_KEY, + name ? name : "unnamed"); + if (auth_name && code) { + propSingleOp.set(metadata::Identifier::CODESPACE_KEY, auth_name) + .set(metadata::Identifier::CODE_KEY, code); + } + + propMethod.set(common::IdentifiedObject::NAME_KEY, + method_name ? method_name : "unnamed"); + if (method_auth_name && method_code) { + propMethod.set(metadata::Identifier::CODESPACE_KEY, method_auth_name) + .set(metadata::Identifier::CODE_KEY, method_code); + } + + for (int i = 0; i < param_count; i++) { + PropertyMap propParam; + propParam.set(common::IdentifiedObject::NAME_KEY, + params[i].name ? params[i].name : "unnamed"); + if (params[i].auth_name && params[i].code) { + propParam + .set(metadata::Identifier::CODESPACE_KEY, params[i].auth_name) + .set(metadata::Identifier::CODE_KEY, params[i].code); + } + parameters.emplace_back(OperationParameter::create(propParam)); + auto unit_type = UnitOfMeasure::Type::UNKNOWN; + switch (params[i].unit_type) { + case PJ_UT_ANGULAR: + unit_type = UnitOfMeasure::Type::ANGULAR; + break; + case PJ_UT_LINEAR: + unit_type = UnitOfMeasure::Type::LINEAR; + break; + case PJ_UT_SCALE: + unit_type = UnitOfMeasure::Type::SCALE; + break; + case PJ_UT_TIME: + unit_type = UnitOfMeasure::Type::TIME; + break; + case PJ_UT_PARAMETRIC: + unit_type = UnitOfMeasure::Type::PARAMETRIC; + break; + } + + Measure measure( + params[i].value, + params[i].unit_type == PJ_UT_ANGULAR + ? createAngularUnit(params[i].unit_name, + params[i].unit_conv_factor) + : params[i].unit_type == PJ_UT_LINEAR + ? createLinearUnit(params[i].unit_name, + params[i].unit_conv_factor) + : UnitOfMeasure(params[i].unit_name ? params[i].unit_name + : "unnamed", + params[i].unit_conv_factor, unit_type)); + values.emplace_back(ParameterValue::create(measure)); + } +} + +//! @endcond + +// --------------------------------------------------------------------------- + /** \brief Instanciate a Conversion * * The returned object must be unreferenced with proj_obj_unref() after @@ -2657,69 +2728,104 @@ PJ_OBJ *proj_obj_create_conversion(PJ_CONTEXT *ctx, const char *name, const PJ_PARAM_DESCRIPTION *params) { SANITIZE_CTX(ctx); try { - PropertyMap propConv; - propConv.set(common::IdentifiedObject::NAME_KEY, - name ? name : "unnamed"); - if (auth_name && code) { - propConv.set(metadata::Identifier::CODESPACE_KEY, auth_name) - .set(metadata::Identifier::CODE_KEY, code); - } + PropertyMap propSingleOp; PropertyMap propMethod; - propMethod.set(common::IdentifiedObject::NAME_KEY, - method_name ? method_name : "unnamed"); - if (method_auth_name && method_code) { - propMethod - .set(metadata::Identifier::CODESPACE_KEY, method_auth_name) - .set(metadata::Identifier::CODE_KEY, method_code); + std::vector<OperationParameterNNPtr> parameters; + std::vector<ParameterValueNNPtr> values; + + setSingleOperationElements( + name, auth_name, code, method_name, method_auth_name, method_code, + param_count, params, propSingleOp, propMethod, parameters, values); + + return PJ_OBJ::create( + Conversion::create(propSingleOp, propMethod, parameters, values)); + } catch (const std::exception &e) { + proj_log_error(ctx, __FUNCTION__, e.what()); + return nullptr; + } +} + +// --------------------------------------------------------------------------- + +/** \brief Instanciate a Transformation + * + * The returned object must be unreferenced with proj_obj_unref() after + * use. + * It should be used by at most one thread at a time. + * + * @param ctx PROJ context, or NULL for default context + * @param name Transformation name. Or NULL. + * @param auth_name Transformation authority name. Or NULL. + * @param code Transformation code. Or NULL. + * @param source_crs Object of type CRS representing the source CRS. + * Must not be NULL. + * @param target_crs Object of type CRS representing the target CRS. + * Must not be NULL. + * @param interpolation_crs Object of type CRS representing the interpolation + * CRS. Or NULL. + * @param method_name Method name. Or NULL. + * @param method_auth_name Method authority name. Or NULL. + * @param method_code Method code. Or NULL. + * @param param_count Number of parameters (size of params argument) + * @param params Parameter descriptions (array of size param_count) + * @param accuracy Accuracy of the transformation in meters. A negative + * values means unknown. + * + * @return Object that must be unreferenced with + * proj_obj_unref(), or NULL in case of error. + */ + +PJ_OBJ *proj_obj_create_transformation( + PJ_CONTEXT *ctx, const char *name, const char *auth_name, const char *code, + PJ_OBJ *source_crs, PJ_OBJ *target_crs, PJ_OBJ *interpolation_crs, + const char *method_name, const char *method_auth_name, + const char *method_code, int param_count, + const PJ_PARAM_DESCRIPTION *params, double accuracy) { + SANITIZE_CTX(ctx); + assert(source_crs); + assert(target_crs); + + auto l_sourceCRS = util::nn_dynamic_pointer_cast<CRS>(source_crs->obj); + if (!l_sourceCRS) { + proj_log_error(ctx, __FUNCTION__, "source_crs is not a CRS"); + return nullptr; + } + + auto l_targetCRS = util::nn_dynamic_pointer_cast<CRS>(target_crs->obj); + if (!l_targetCRS) { + proj_log_error(ctx, __FUNCTION__, "target_crs is not a CRS"); + return nullptr; + } + + CRSPtr l_interpolationCRS; + if (interpolation_crs) { + l_interpolationCRS = + util::nn_dynamic_pointer_cast<CRS>(interpolation_crs->obj); + if (!l_interpolationCRS) { + proj_log_error(ctx, __FUNCTION__, "interpolation_crs is not a CRS"); + return nullptr; } + } + + try { + PropertyMap propSingleOp; + PropertyMap propMethod; std::vector<OperationParameterNNPtr> parameters; std::vector<ParameterValueNNPtr> values; - for (int i = 0; i < param_count; i++) { - PropertyMap propParam; - propParam.set(common::IdentifiedObject::NAME_KEY, - params[i].name ? params[i].name : "unnamed"); - if (params[i].auth_name && params[i].code) { - propParam - .set(metadata::Identifier::CODESPACE_KEY, - params[i].auth_name) - .set(metadata::Identifier::CODE_KEY, params[i].code); - } - parameters.emplace_back(OperationParameter::create(propParam)); - auto unit_type = UnitOfMeasure::Type::UNKNOWN; - switch (params[i].unit_type) { - case PJ_UT_ANGULAR: - unit_type = UnitOfMeasure::Type::ANGULAR; - break; - case PJ_UT_LINEAR: - unit_type = UnitOfMeasure::Type::LINEAR; - break; - case PJ_UT_SCALE: - unit_type = UnitOfMeasure::Type::SCALE; - break; - case PJ_UT_TIME: - unit_type = UnitOfMeasure::Type::TIME; - break; - case PJ_UT_PARAMETRIC: - unit_type = UnitOfMeasure::Type::PARAMETRIC; - break; - } - Measure measure( - params[i].value, - params[i].unit_type == PJ_UT_ANGULAR - ? createAngularUnit(params[i].unit_name, - params[i].unit_conv_factor) - : params[i].unit_type == PJ_UT_LINEAR - ? createLinearUnit(params[i].unit_name, - params[i].unit_conv_factor) - : UnitOfMeasure( - params[i].unit_name ? params[i].unit_name - : "unnamed", - params[i].unit_conv_factor, unit_type)); - values.emplace_back(ParameterValue::create(measure)); + setSingleOperationElements( + name, auth_name, code, method_name, method_auth_name, method_code, + param_count, params, propSingleOp, propMethod, parameters, values); + + std::vector<metadata::PositionalAccuracyNNPtr> accuracies; + if (accuracy >= 0.0) { + accuracies.emplace_back( + PositionalAccuracy::create(toString(accuracy))); } - return PJ_OBJ::create( - Conversion::create(propConv, propMethod, parameters, values)); + + return PJ_OBJ::create(Transformation::create( + propSingleOp, NN_NO_CHECK(l_sourceCRS), NN_NO_CHECK(l_targetCRS), + l_interpolationCRS, propMethod, parameters, values, accuracies)); } catch (const std::exception &e) { proj_log_error(ctx, __FUNCTION__, e.what()); return nullptr; diff --git a/src/proj_experimental.h b/src/proj_experimental.h index c575b9ae..84ea31d7 100644 --- a/src/proj_experimental.h +++ b/src/proj_experimental.h @@ -240,6 +240,21 @@ PJ_OBJ PROJ_DLL *proj_obj_create_conversion(PJ_CONTEXT *ctx, int param_count, const PJ_PARAM_DESCRIPTION* params); +PJ_OBJ PROJ_DLL *proj_obj_create_transformation( + PJ_CONTEXT *ctx, + const char* name, + const char* auth_name, + const char* code, + PJ_OBJ* source_crs, + PJ_OBJ* target_crs, + PJ_OBJ* interpolation_crs, + const char* method_name, + const char* method_auth_name, + const char* method_code, + int param_count, + const PJ_PARAM_DESCRIPTION* params, + double accuracy); + PJ_OBJ PROJ_DLL *proj_obj_convert_conversion_to_other_method(PJ_CONTEXT *ctx, const PJ_OBJ *conversion, int new_method_epsg_code, diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp index c8086684..0e076912 100644 --- a/test/unit/test_c_api.cpp +++ b/test/unit/test_c_api.cpp @@ -430,7 +430,7 @@ TEST_F(CApi, proj_obj_crs_create_bound_crs_to_WGS84) { EXPECT_TRUE(proj_coordoperation_get_towgs84_values(m_ctxt, transf, values.data(), 7, true)); auto expected = std::vector<double>{2.329, -147.042, -92.08, -0.309, - 0.325, 0.497, 5.69}; + 0.325, 0.497, 5.69}; EXPECT_EQ(values, expected); auto res2 = @@ -2487,6 +2487,76 @@ TEST_F(CApi, proj_obj_create_projected_crs) { // --------------------------------------------------------------------------- +TEST_F(CApi, proj_obj_create_transformation) { + + PJ_PARAM_DESCRIPTION param; + param.name = "param name"; + param.auth_name = nullptr; + param.code = nullptr; + param.value = 0.99; + param.unit_name = nullptr; + param.unit_conv_factor = 1.0; + param.unit_type = PJ_UT_SCALE; + + auto geog_cs = proj_obj_create_ellipsoidal_2D_cs( + m_ctxt, PJ_ELLPS2D_LONGITUDE_LATITUDE, nullptr, 0); + ObjectKeeper keeper_geog_cs(geog_cs); + ASSERT_NE(geog_cs, nullptr); + + auto source_crs = proj_obj_create_geographic_crs( + m_ctxt, "Source CRS", "World Geodetic System 1984", "WGS 84", 6378137, + 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, geog_cs); + ObjectKeeper keeper_source_crs(source_crs); + ASSERT_NE(source_crs, nullptr); + + auto target_crs = proj_obj_create_geographic_crs( + m_ctxt, "WGS 84", "World Geodetic System 1984", "WGS 84", 6378137, + 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, geog_cs); + ObjectKeeper keeper_target_crs(target_crs); + ASSERT_NE(target_crs, nullptr); + + auto interp_crs = proj_obj_create_geographic_crs( + m_ctxt, "Interpolation CRS", "World Geodetic System 1984", "WGS 84", + 6378137, 298.257223563, "Greenwich", 0.0, "Degree", 0.0174532925199433, + geog_cs); + ObjectKeeper keeper_interp_crs(interp_crs); + ASSERT_NE(interp_crs, nullptr); + + { + auto transf = proj_obj_create_transformation( + m_ctxt, "transf", "transf auth", "transf code", source_crs, + target_crs, interp_crs, "method", "method auth", "method code", 1, + ¶m, 0); + ObjectKeeper keeper_transf(transf); + ASSERT_NE(transf, nullptr); + + EXPECT_EQ(proj_coordoperation_get_param_count(m_ctxt, transf), 1); + + auto got_source_crs = proj_obj_get_source_crs(m_ctxt, transf); + ObjectKeeper keeper_got_source_crs(got_source_crs); + ASSERT_NE(got_source_crs, nullptr); + EXPECT_TRUE(proj_obj_is_equivalent_to(source_crs, got_source_crs, + PJ_COMP_STRICT)); + + auto got_target_crs = proj_obj_get_target_crs(m_ctxt, transf); + ObjectKeeper keeper_got_target_crs(got_target_crs); + ASSERT_NE(got_target_crs, nullptr); + EXPECT_TRUE(proj_obj_is_equivalent_to(target_crs, got_target_crs, + PJ_COMP_STRICT)); + } + + { + auto transf = proj_obj_create_transformation( + m_ctxt, "transf", "transf auth", "transf code", source_crs, + target_crs, nullptr, "method", "method auth", "method code", 1, + ¶m, -1); + ObjectKeeper keeper_transf(transf); + ASSERT_NE(transf, nullptr); + } +} + +// --------------------------------------------------------------------------- + TEST_F(CApi, proj_obj_create_compound_crs) { auto horiz_cs = proj_obj_create_ellipsoidal_2D_cs( |
