aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/conversions/unitconvert.cpp6
-rw-r--r--src/pipeline.cpp59
-rw-r--r--test/gie/unitconvert.gie2
-rw-r--r--test/unit/CMakeLists.txt7
-rw-r--r--test/unit/Makefile.am9
-rw-r--r--test/unit/proj_angular_io_test.cpp101
6 files changed, 177 insertions, 7 deletions
diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp
index cbd81a7d..1e3372d6 100644
--- a/src/conversions/unitconvert.cpp
+++ b/src/conversions/unitconvert.cpp
@@ -457,6 +457,8 @@ PJ *CONVERSION(unitconvert,0) {
P->left = PJ_IO_UNITS_WHATEVER;
P->right = PJ_IO_UNITS_WHATEVER;
+ P->skip_fwd_prepare = 1;
+ P->skip_inv_prepare = 1;
/* if no time input/output unit is specified we can skip them */
Q->t_in_id = -1;
@@ -476,6 +478,8 @@ PJ *CONVERSION(unitconvert,0) {
}
if (f != 0.0)
Q->xy_factor *= f;
+ if (normalized_name != nullptr && strcmp(normalized_name, "Radian") == 0)
+ P->left = PJ_IO_UNITS_RADIANS;
}
if ((name = pj_param (P->ctx, P->params, "sxy_out").s) != nullptr) {
@@ -489,6 +493,8 @@ PJ *CONVERSION(unitconvert,0) {
}
if (f != 0.0)
Q->xy_factor /= f;
+ if (normalized_name != nullptr && strcmp(normalized_name, "Radian") == 0)
+ P->right= PJ_IO_UNITS_RADIANS;
}
if( xy_in_is_linear >= 0 && xy_out_is_linear >= 0 &&
diff --git a/src/pipeline.cpp b/src/pipeline.cpp
index 5f7efe08..b24f71e7 100644
--- a/src/pipeline.cpp
+++ b/src/pipeline.cpp
@@ -329,6 +329,33 @@ static void set_ellipsoid(PJ *P) {
}
+static enum pj_io_units get_next_non_whatever_unit(void *pipeline_data, int step, PJ_DIRECTION dir) {
+ PJ **pipeline = static_cast<struct pj_opaque*>(pipeline_data)->pipeline;
+ int nsteps = static_cast<struct pj_opaque*>(pipeline_data)->steps;
+ int i;
+
+ if (dir == PJ_FWD) {
+ for (i = step+1; i<=nsteps; i++) {
+ if (pj_left(pipeline[i]) != pj_right(pipeline[i]))
+ return pj_left(pipeline[i]);
+ if (pj_left(pipeline[i]) != PJ_IO_UNITS_WHATEVER)
+ return pj_left(pipeline[i]);
+ if (pj_right(pipeline[i]) != PJ_IO_UNITS_WHATEVER)
+ return pj_right(pipeline[i]);
+ }
+ } else {
+ for (i=step; i>1; i--) {
+ if (pj_right(pipeline[i]) != pj_left(pipeline[i]))
+ return pj_right(pipeline[i]);
+ if (pj_right(pipeline[i]) != PJ_IO_UNITS_WHATEVER)
+ return pj_right(pipeline[i]);
+ if (pj_left(pipeline[i]) != PJ_IO_UNITS_WHATEVER)
+ return pj_left(pipeline[i]);
+ }
+ }
+ return PJ_IO_UNITS_WHATEVER;
+}
+
PJ *OPERATION(pipeline,0) {
@@ -480,14 +507,36 @@ PJ *OPERATION(pipeline,0) {
}
}
- /* Check that output units from step i are compatible with expected units in step i+1 */
+
+ /* Replace PJ_IO_UNITS_WHATEVER with input/output units of neighbouring steps where */
+ /* it make sense. It does in most cases but not always, for instance */
+ /* proj=pipeline step proj=unitconvert xy_in=deg xy_out=rad step ... */
+ /* where the left-hand side units of the first step shouldn't be changed to RADIANS */
+ /* as it will result in deg->rad conversions in cs2cs and other applications. */
+ PJ **pipeline = static_cast<struct pj_opaque*>(P->opaque)->pipeline;
+ for (i=1; i<=nsteps; i++) {
+ if (pj_left(pipeline[i]) == PJ_IO_UNITS_WHATEVER && pj_right(pipeline[i]) == PJ_IO_UNITS_WHATEVER) {
+ pipeline[i]->left = get_next_non_whatever_unit(P->opaque, i, PJ_FWD);
+ pipeline[i]->right = get_next_non_whatever_unit(P->opaque, i, PJ_FWD);
+ }
+ }
+
+ for (i=nsteps; i>0; i--) {
+ if (pj_left(pipeline[i]) == PJ_IO_UNITS_WHATEVER && pj_right(pipeline[i]) == PJ_IO_UNITS_WHATEVER) {
+ pipeline[i]->right = get_next_non_whatever_unit(P->opaque, i, PJ_INV);
+ pipeline[i]->left = get_next_non_whatever_unit(P->opaque, i, PJ_INV);
+ }
+ }
+
+ /* Check that units between each steps match each other, fail if they don't */
for (i = 1; i < nsteps; i++) {
- enum pj_io_units unit_returned = pj_right (static_cast<struct pj_opaque*>(P->opaque)->pipeline[i]);
- enum pj_io_units unit_expected = pj_left (static_cast<struct pj_opaque*>(P->opaque)->pipeline[i+1]);
+ enum pj_io_units curr_step_output = pj_right (pipeline[i]);
+ enum pj_io_units next_step_input = pj_left (pipeline[i+1]);
- if ( unit_returned == PJ_IO_UNITS_WHATEVER || unit_expected == PJ_IO_UNITS_WHATEVER )
+ if ( curr_step_output == PJ_IO_UNITS_WHATEVER || next_step_input == PJ_IO_UNITS_WHATEVER )
continue;
- if ( unit_returned != unit_expected ) {
+
+ if ( curr_step_output != next_step_input ) {
proj_log_error (P, "Pipeline: Mismatched units between step %d and %d", i, i+1);
return destructor (P, PJD_ERR_MALFORMED_PIPELINE);
}
diff --git a/test/gie/unitconvert.gie b/test/gie/unitconvert.gie
index 7bbea49d..2a56ba59 100644
--- a/test/gie/unitconvert.gie
+++ b/test/gie/unitconvert.gie
@@ -28,7 +28,7 @@ expect 0.5 0.5 1 1
operation proj=unitconvert xy_in=deg xy_out=rad
tolerance 0.000000000001
accept 1 1 1 1
-expect 0.017453292519943296 0.017453292519943296 1 1
+expect 1 1 1 1 # gie does a rad->deg conversion behind the scenes
operation proj=unitconvert xy_in=grad xy_out=deg
tolerance 0.000000000001
diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt
index 68a6e60f..09405147 100644
--- a/test/unit/CMakeLists.txt
+++ b/test/unit/CMakeLists.txt
@@ -74,6 +74,13 @@ target_link_libraries(proj_errno_string_test
${PROJ_LIBRARIES})
add_test(NAME proj_errno_string_test COMMAND proj_errno_string_test)
+add_executable(proj_angular_io_test
+ main.cpp
+ proj_angular_io_test.cpp)
+target_link_libraries(proj_angular_io_test
+ gtest
+ ${PROJ_LIBRARIES})
+add_test(NAME proj_angular_io_test COMMAND proj_angular_io_test)
if (MSVC AND BUILD_LIBPROJ_SHARED)
# ph_phi2_test not compatible of a .dll build
diff --git a/test/unit/Makefile.am b/test/unit/Makefile.am
index f26e355d..e6d95e9c 100644
--- a/test/unit/Makefile.am
+++ b/test/unit/Makefile.am
@@ -12,6 +12,7 @@ PROJ_LIB ?= ../../data
noinst_PROGRAMS = pj_transform_test
noinst_PROGRAMS += pj_phi2_test
noinst_PROGRAMS += proj_errno_string_test
+noinst_PROGRAMS += proj_angular_io_test
noinst_PROGRAMS += test_cpp_api
noinst_PROGRAMS += gie_self_tests
noinst_PROGRAMS += include_proj_h_from_c
@@ -34,6 +35,12 @@ proj_errno_string_test_LDADD= ../../src/libproj.la ../../test/googletest/libgtes
proj_errno_string_test-check: proj_errno_string_test
./proj_errno_string_test
+proj_angular_io_test_SOURCES = proj_angular_io_test.cpp main.cpp
+proj_angular_io_test_LDADD = ../../src/libproj.la ../../test/googletest/libgtest.la
+
+proj_angular_io_test-check: proj_angular_io_test
+ ./proj_angular_io_test
+
test_cpp_api_SOURCES = test_util.cpp test_common.cpp test_crs.cpp test_metadata.cpp test_io.cpp test_operation.cpp test_datum.cpp test_factory.cpp test_c_api.cpp main.cpp
test_cpp_api_LDADD = ../../src/libproj.la ../../test/googletest/libgtest.la @SQLITE3_LDFLAGS@
@@ -48,4 +55,4 @@ gie_self_tests-check: gie_self_tests
include_proj_h_from_c_SOURCES = include_proj_h_from_c.c
-check-local: pj_transform_test-check pj_phi2_test-check proj_errno_string_test-check test_cpp_api-check gie_self_tests-check
+check-local: pj_transform_test-check pj_phi2_test-check proj_errno_string_test-check proj_angular_io_test-check test_cpp_api-check gie_self_tests-check
diff --git a/test/unit/proj_angular_io_test.cpp b/test/unit/proj_angular_io_test.cpp
new file mode 100644
index 00000000..fdb44704
--- /dev/null
+++ b/test/unit/proj_angular_io_test.cpp
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Project: PROJ
+ * Purpose: Test that in- and output units behave correctly, especially
+ * angular units that need special treatment.
+ * Author: Kristian Evers <kristianevers@gmail.com>
+ *
+ ******************************************************************************
+ * Copyright (c) 2019, Kristian Evers
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ****************************************************************************/
+
+#include "proj.h"
+
+#include "gtest_include.h"
+
+namespace {
+
+TEST(AngularUnits, Basic) {
+ auto ctx = proj_context_create();
+ auto P = proj_create(ctx, "proj=latlong");
+
+ EXPECT_TRUE(proj_angular_input(P, PJ_FWD));
+ EXPECT_TRUE(proj_angular_output(P, PJ_FWD));
+ EXPECT_TRUE(proj_angular_input(P, PJ_INV));
+ EXPECT_TRUE(proj_angular_output(P, PJ_INV));
+
+ proj_destroy(P);
+ proj_context_destroy(ctx);
+}
+
+TEST(AngularUnits, Pipelines) {
+ auto ctx = proj_context_create();
+ auto P = proj_create(ctx, "proj=pipeline +step +proj=axisswap +order=2,1 +step +proj=latlong +step +proj=axisswap +order=2,1");
+
+ EXPECT_TRUE(proj_angular_input(P, PJ_FWD));
+ EXPECT_TRUE(proj_angular_output(P, PJ_FWD));
+ EXPECT_TRUE(proj_angular_input(P, PJ_INV));
+ EXPECT_TRUE(proj_angular_output(P, PJ_INV));
+
+ proj_destroy(P);
+ proj_context_destroy(ctx);
+
+}
+
+TEST(AngularUnits, Pipelines2) {
+ auto ctx = proj_context_create();
+ auto P = proj_create(
+ ctx,
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=deg +xy_out=rad "
+ "+step +proj=tmerc +lat_0=0 +lon_0=-81 +k=0.9996 +x_0=500000.001016002 +y_0=0 +ellps=WGS84 "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=m +z_in=m +xy_out=us-ft +z_out=us-ft");
+
+ EXPECT_FALSE(proj_angular_input(P, PJ_FWD));
+ EXPECT_FALSE(proj_angular_output(P, PJ_FWD));
+
+ proj_destroy(P);
+ proj_context_destroy(ctx);
+
+}
+
+TEST(AngularUnits, Pipelines3) {
+ auto ctx = proj_context_create();
+ auto P = proj_create(
+ ctx,
+ "+proj=pipeline "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=tmerc +lat_0=0 +lon_0=-81 +k=0.9996 +x_0=500000.001016002 +y_0=0 +ellps=WGS84 "
+ "+step +proj=axisswap +order=2,1 "
+ "+step +proj=unitconvert +xy_in=m +z_in=m +xy_out=us-ft +z_out=us-ft");
+
+ EXPECT_TRUE(proj_angular_input(P, PJ_FWD));
+ EXPECT_FALSE(proj_angular_output(P, PJ_FWD));
+
+ proj_destroy(P);
+ proj_context_destroy(ctx);
+
+}
+
+
+} // namespace