aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEven Rouault <even.rouault@spatialys.com>2018-12-06 00:20:30 +0100
committerEven Rouault <even.rouault@spatialys.com>2018-12-06 00:20:30 +0100
commite699ae83eada3aa706e06215f5370dafc3235f7b (patch)
tree654b2fa264cce5be734673d06f11407388467e55
parent095d44a4a6dd4244bd8c42b28ee1a3bb521fe4b9 (diff)
parentdccf4658ac4cf9194682350ec292a086a2bb24a1 (diff)
downloadPROJ-e699ae83eada3aa706e06215f5370dafc3235f7b.tar.gz
PROJ-e699ae83eada3aa706e06215f5370dafc3235f7b.zip
Merge remote-tracking branch 'rouault/gdalbarn'
-rw-r--r--src/c_api.cpp67
-rw-r--r--src/proj_experimental.h5
-rw-r--r--test/unit/test_c_api.cpp77
3 files changed, 149 insertions, 0 deletions
diff --git a/src/c_api.cpp b/src/c_api.cpp
index a5ed1509..fed91750 100644
--- a/src/c_api.cpp
+++ b/src/c_api.cpp
@@ -55,6 +55,7 @@
#include "proj_experimental.h"
#include "projects.h"
// clang-format on
+#include "proj_constants.h"
using namespace NS_PROJ::common;
using namespace NS_PROJ::crs;
@@ -2526,6 +2527,72 @@ PJ_OBJ *proj_obj_create_conversion(PJ_CONTEXT *ctx, const char *name,
// ---------------------------------------------------------------------------
+/**
+ * \brief Return an equivalent projection.
+ *
+ * Currently implemented:
+ * <ul>
+ * <li>EPSG_CODE_METHOD_MERCATOR_VARIANT_A (1SP) to
+ * EPSG_CODE_METHOD_MERCATOR_VARIANT_B (2SP)</li>
+ * <li>EPSG_CODE_METHOD_MERCATOR_VARIANT_B (2SP) to
+ * EPSG_CODE_METHOD_MERCATOR_VARIANT_A (1SP)</li>
+ * <li>EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP to
+ * EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP</li>
+ * <li>EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP to
+ * EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP</li>
+ * </ul>
+ *
+ * @param ctx PROJ context, or NULL for default context
+ * @param conversion Object of type Conversion. Must not be NULL.
+ * @param new_method_epsg_code EPSG code of the target method. Or 0 (in which
+ * case new_method_name must be specified).
+ * @param new_method_name EPSG or PROJ target method name. Or nullptr (in which
+ * case new_method_epsg_code must be specified).
+ * @return new conversion that must be unreferenced with
+ * proj_obj_unref(), or NULL in case of error.
+ */
+PJ_OBJ *proj_obj_convert_conversion_to_other_method(
+ PJ_CONTEXT *ctx, const PJ_OBJ *conversion, int new_method_epsg_code,
+ const char *new_method_name) {
+ SANITIZE_CTX(ctx);
+ auto conv = dynamic_cast<const Conversion *>(conversion->obj.get());
+ if (!conv) {
+ proj_log_error(ctx, __FUNCTION__, "not a Conversion");
+ return nullptr;
+ }
+ if (new_method_epsg_code == 0) {
+ if (!new_method_name) {
+ return nullptr;
+ }
+ if (metadata::Identifier::isEquivalentName(
+ new_method_name, EPSG_NAME_METHOD_MERCATOR_VARIANT_A)) {
+ new_method_epsg_code = EPSG_CODE_METHOD_MERCATOR_VARIANT_A;
+ } else if (metadata::Identifier::isEquivalentName(
+ new_method_name, EPSG_NAME_METHOD_MERCATOR_VARIANT_B)) {
+ new_method_epsg_code = EPSG_CODE_METHOD_MERCATOR_VARIANT_B;
+ } else if (metadata::Identifier::isEquivalentName(
+ new_method_name,
+ EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_1SP)) {
+ new_method_epsg_code = EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_1SP;
+ } else if (metadata::Identifier::isEquivalentName(
+ new_method_name,
+ EPSG_NAME_METHOD_LAMBERT_CONIC_CONFORMAL_2SP)) {
+ new_method_epsg_code = EPSG_CODE_METHOD_LAMBERT_CONIC_CONFORMAL_2SP;
+ }
+ }
+ try {
+ auto new_conv = conv->convertToOtherMethod(new_method_epsg_code);
+ if (!new_conv)
+ return nullptr;
+ return PJ_OBJ::create(NN_NO_CHECK(new_conv));
+ } catch (const std::exception &e) {
+ proj_log_error(ctx, __FUNCTION__, e.what());
+ return nullptr;
+ }
+}
+
+// ---------------------------------------------------------------------------
+
//! @cond Doxygen_Suppress
static CoordinateSystemAxisNNPtr createAxis(const PJ_AXIS_DESCRIPTION &axis) {
diff --git a/src/proj_experimental.h b/src/proj_experimental.h
index 19cde6fc..b8c37054 100644
--- a/src/proj_experimental.h
+++ b/src/proj_experimental.h
@@ -227,6 +227,11 @@ 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_convert_conversion_to_other_method(PJ_CONTEXT *ctx,
+ const PJ_OBJ *conversion,
+ int new_method_epsg_code,
+ const char *new_method_name);
+
PJ_OBJ PROJ_DLL *proj_obj_create_projected_crs(PJ_CONTEXT *ctx,
const char* crs_name,
const PJ_OBJ* geodetic_crs,
diff --git a/test/unit/test_c_api.cpp b/test/unit/test_c_api.cpp
index 57ade07f..42d00fa6 100644
--- a/test/unit/test_c_api.cpp
+++ b/test/unit/test_c_api.cpp
@@ -29,6 +29,7 @@
#include "gtest_include.h"
#include "proj.h"
+#include "proj_constants.h"
#include "proj_experimental.h"
#include "proj/common.hpp"
@@ -2475,4 +2476,80 @@ TEST_F(CApi, proj_obj_create_compound_crs) {
proj_obj_is_equivalent_to(subcrs_vert, vert_crs, PJ_COMP_STRICT));
}
+// ---------------------------------------------------------------------------
+
+TEST_F(CApi, proj_obj_convert_conversion_to_other_method) {
+ {
+ 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 geogCRS = 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_geogCRS(geogCRS);
+ ASSERT_NE(geogCRS, nullptr);
+
+ auto cs = proj_obj_create_cartesian_2D_cs(
+ m_ctxt, PJ_CART2D_EASTING_NORTHING, nullptr, 0);
+ ObjectKeeper keeper_cs(cs);
+ ASSERT_NE(cs, nullptr);
+
+ auto conv = proj_obj_create_conversion_mercator_variant_a(
+ m_ctxt, 0, 1, 0.99, 2, 3, "Degree", 0.0174532925199433, "Metre",
+ 1.0);
+ ObjectKeeper keeper_conv(conv);
+ ASSERT_NE(conv, nullptr);
+
+ auto projCRS =
+ proj_obj_create_projected_crs(m_ctxt, "my CRS", geogCRS, conv, cs);
+ ObjectKeeper keeper_projCRS(projCRS);
+ ASSERT_NE(projCRS, nullptr);
+
+ // Wrong object type
+ EXPECT_EQ(
+ proj_obj_convert_conversion_to_other_method(
+ m_ctxt, projCRS, EPSG_CODE_METHOD_MERCATOR_VARIANT_B, nullptr),
+ nullptr);
+
+ auto conv_in_proj = proj_obj_crs_get_coordoperation(
+ m_ctxt, projCRS, nullptr, nullptr, nullptr);
+ ObjectKeeper keeper_conv_in_proj(conv_in_proj);
+ ASSERT_NE(conv_in_proj, nullptr);
+
+ // 3rd and 4th argument both 0/null
+ EXPECT_EQ(proj_obj_convert_conversion_to_other_method(
+ m_ctxt, conv_in_proj, 0, nullptr),
+ nullptr);
+
+ auto new_conv = proj_obj_convert_conversion_to_other_method(
+ m_ctxt, conv_in_proj, EPSG_CODE_METHOD_MERCATOR_VARIANT_B, nullptr);
+ ObjectKeeper keeper_new_conv(new_conv);
+ ASSERT_NE(new_conv, nullptr);
+
+ EXPECT_FALSE(
+ proj_obj_is_equivalent_to(new_conv, conv_in_proj, PJ_COMP_STRICT));
+ EXPECT_TRUE(proj_obj_is_equivalent_to(new_conv, conv_in_proj,
+ PJ_COMP_EQUIVALENT));
+
+ auto new_conv_from_name = proj_obj_convert_conversion_to_other_method(
+ m_ctxt, conv_in_proj, 0, EPSG_NAME_METHOD_MERCATOR_VARIANT_B);
+ ObjectKeeper keeper_new_conv_from_name(new_conv_from_name);
+ ASSERT_NE(new_conv_from_name, nullptr);
+
+ EXPECT_TRUE(proj_obj_is_equivalent_to(new_conv, new_conv_from_name,
+ PJ_COMP_STRICT));
+
+ auto new_conv_back = proj_obj_convert_conversion_to_other_method(
+ m_ctxt, conv_in_proj, 0, EPSG_NAME_METHOD_MERCATOR_VARIANT_A);
+ ObjectKeeper keeper_new_conv_back(new_conv_back);
+ ASSERT_NE(new_conv_back, nullptr);
+
+ EXPECT_TRUE(proj_obj_is_equivalent_to(conv_in_proj, new_conv_back,
+ PJ_COMP_STRICT));
+ }
+}
+
} // namespace