diff options
| -rw-r--r-- | docs/source/operations/conversions/unitconvert.rst | 10 | ||||
| -rw-r--r-- | src/conversions/unitconvert.cpp | 19 | ||||
| -rw-r--r-- | src/iso19111/crs.cpp | 3 | ||||
| -rw-r--r-- | test/unit/gie_self_tests.cpp | 31 | ||||
| -rw-r--r-- | test/unit/test_operationfactory.cpp | 26 |
5 files changed, 78 insertions, 11 deletions
diff --git a/docs/source/operations/conversions/unitconvert.rst b/docs/source/operations/conversions/unitconvert.rst index f1488d9a..13ca9228 100644 --- a/docs/source/operations/conversions/unitconvert.rst +++ b/docs/source/operations/conversions/unitconvert.rst @@ -158,6 +158,16 @@ Time units In the table below all time units supported by PROJ are listed. + .. note:: + + When converting time units from a date-only format (`yyyymmdd`), PROJ + assumes a time value of 00:00 midnight. When converting time units + to a date-only format, PROJ rounds to the *nearest* date at 00:00 + midnight. That is, any time values less than 12:00 noon will round to + 00:00 on the same day. Time values greater than or equal to 12:00 noon + will round to 00:00 on the following day. + + +--------------+-----------------------------+ | Label | Name | +==============+=============================+ diff --git a/src/conversions/unitconvert.cpp b/src/conversions/unitconvert.cpp index d584d93f..991eb2e0 100644 --- a/src/conversions/unitconvert.cpp +++ b/src/conversions/unitconvert.cpp @@ -252,21 +252,22 @@ static double yyyymmdd_to_mjd(double yyyymmdd) { /***********************************************************************/ static double mjd_to_yyyymmdd(double mjd) { /************************************************************************ - Date given in YYYY-MM-DD format. + Date returned in YYYY-MM-DD format. ************************************************************************/ - double mjd_iter = 14 + 31; - int year = 1859, month=0, day=0; + unsigned int date_iter = 14 + 31; + unsigned int year = 1859, month = 0, day = 0; + unsigned int date = (int) lround(mjd); - for (; mjd >= mjd_iter; year++) { - mjd_iter += days_in_year(year); + for (; date >= date_iter; year++) { + date_iter += days_in_year(year); } year--; - mjd_iter -= days_in_year(year); + date_iter -= days_in_year(year); - for (month=1; mjd_iter + days_in_month(year, month) <= mjd; month++) - mjd_iter += days_in_month(year, month); + for (month=1; date_iter + days_in_month(year, month) <= date; month++) + date_iter += days_in_month(year, month); - day = (int)(mjd - mjd_iter + 1); + day = date - date_iter + 1; return year*10000.0 + month*100.0 + day; } diff --git a/src/iso19111/crs.cpp b/src/iso19111/crs.cpp index 881aec0b..e4b8094f 100644 --- a/src/iso19111/crs.cpp +++ b/src/iso19111/crs.cpp @@ -4404,7 +4404,8 @@ void ProjectedCRS::addUnitConvertAndAxisSwap(io::PROJStringFormatter *formatter, formatter->addParam("units", "m"); } - if (!axisSpecFound && !formatter->getCRSExport()) { + if (!axisSpecFound && + (!formatter->getCRSExport() || formatter->getLegacyCRSToCRSContext())) { const auto &dir0 = axisList[0]->direction(); const auto &dir1 = axisList[1]->direction(); if (!(&dir0 == &cs::AxisDirection::EAST && diff --git a/test/unit/gie_self_tests.cpp b/test/unit/gie_self_tests.cpp index 71df8fe1..5c14d747 100644 --- a/test/unit/gie_self_tests.cpp +++ b/test/unit/gie_self_tests.cpp @@ -618,7 +618,6 @@ static void test_time(const char *args, double tol, double t_in, double t_exp) { // --------------------------------------------------------------------------- TEST(gie, unitconvert_selftest) { - char args1[] = "+proj=unitconvert +t_in=decimalyear +t_out=decimalyear"; double in1 = 2004.25; @@ -641,6 +640,36 @@ TEST(gie, unitconvert_selftest) { test_time(args5, 1e-6, in5, in5); } +static void test_date(const char *args, double tol, double t_in, double t_exp) { + PJ_COORD in, out; + PJ *P = proj_create(PJ_DEFAULT_CTX, args); + + ASSERT_TRUE(P != 0); + + in = proj_coord(0.0, 0.0, 0.0, t_in); + + out = proj_trans(P, PJ_FWD, in); + EXPECT_NEAR(out.xyzt.t, t_exp, tol); + + proj_destroy(P); + + proj_log_level(NULL, PJ_LOG_NONE); +} + +TEST(gie, unitconvert_selftest_date) { + char args[] = "+proj=unitconvert +t_in=decimalyear +t_out=yyyymmdd"; + test_date(args, 1e-6, 2022.0027, 20220102); + test_date(args, 1e-6, 1990.0, 19900101); + test_date(args, 1e-6, 2004.1612, 20040229); + test_date(args, 1e-6, 1899.999, 19000101); + + strcpy(&args[18], "+t_in=yyyymmdd +t_out=decimalyear"); + test_date(args, 1e-6, 20220102, 2022.0027397); + test_date(args, 1e-6, 19900101, 1990.0); + test_date(args, 1e-6, 20040229, 2004.1612022); + test_date(args, 1e-6, 18991231, 1899.9972603); +} + static const char tc32_utm32[] = { " +proj=horner" " +ellps=intl" diff --git a/test/unit/test_operationfactory.cpp b/test/unit/test_operationfactory.cpp index 89c4e7c4..0c3ecae4 100644 --- a/test/unit/test_operationfactory.cpp +++ b/test/unit/test_operationfactory.cpp @@ -6569,6 +6569,32 @@ TEST(operation, createOperation_on_crs_with_bound_crs_and_wktext) { // --------------------------------------------------------------------------- +TEST(operation, + createOperation_fallback_to_proj4_strings_with_axis_inverted_projCRS) { + auto objSrc = + createFromUserInput("EPSG:2193", DatabaseContext::create(), false); + auto src = nn_dynamic_pointer_cast<CRS>(objSrc); + ASSERT_TRUE(src != nullptr); + + auto objDest = PROJStringParser().createFromPROJString( + "+proj=longlat +ellps=WGS84 +lon_wrap=180 +type=crs"); + auto dest = nn_dynamic_pointer_cast<GeographicCRS>(objDest); + ASSERT_TRUE(dest != nullptr); + + auto op = CoordinateOperationFactory::create()->createOperation( + NN_CHECK_ASSERT(src), NN_CHECK_ASSERT(dest)); + ASSERT_TRUE(op != nullptr); + EXPECT_EQ(op->exportToPROJString(PROJStringFormatter::create().get()), + "+proj=pipeline " + "+step +proj=axisswap +order=2,1 " + "+step +inv +proj=tmerc +lat_0=0 +lon_0=173 +k=0.9996 " + "+x_0=1600000 +y_0=10000000 +ellps=GRS80 " + "+step +proj=longlat +ellps=WGS84 +lon_wrap=180 " + "+step +proj=unitconvert +xy_in=rad +xy_out=deg"); +} + +// --------------------------------------------------------------------------- + TEST(operation, compoundCRS_to_proj_string_with_non_metre_height) { auto objSrc = createFromUserInput("EPSG:6318+5703", DatabaseContext::create(), false); |
