aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/c_api.cpp220
-rw-r--r--src/proj_experimental.h15
-rw-r--r--test/unit/test_c_api.cpp72
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> &parameters,
+ 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,
+ &param, 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,
+ &param, -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(