diff --git a/docs/source/operations/conversions/unitconvert.rst b/docs/source/operations/conversions/unitconvert.rst index 6c8605fe3c..616071ea0a 100644 --- a/docs/source/operations/conversions/unitconvert.rst +++ b/docs/source/operations/conversions/unitconvert.rst @@ -6,7 +6,7 @@ Unit conversion .. versionadded:: 5.0.0 -Convert between various distance and time units. +Convert between various distance, angular and time units. +---------------------+--------------------------------------------------------+ | **Alias** | unitconvert | @@ -41,25 +41,29 @@ expected to be in units of decimalyears. This can be fixed with `unitconvert`:: Parameters ################################################################################ -.. option:: +xy_in= +.. option:: +xy_in= or - Horizontal input units. See :ref:`distance_units` for a list of available - units. + Horizontal input units. See :ref:`distance_units` and :ref:`angular_units` + for a list of available units. `` is the conversion factor + from the input unit to the International System unit. -.. option:: +xy_out= +.. option:: +xy_out= or - Horizontal output units. See :ref:`distance_units` for a list of available - units. + Horizontal output units. See :ref:`distance_units` and :ref:`angular_units` + for a list of available units. `` is the conversion factor + from the output unit to the International System unit. -.. option:: +z_in= +.. option:: +z_in= or - Vertical output units. See :ref:`distance_units` for a list of available - units. + Vertical output units. See :ref:`distance_units` and :ref:`angular_units` + for a list of available units. `` is the conversion factor + from the input unit to the International System unit. -.. option:: +z_out= +.. option:: +z_out= or - Vertical output units. See :ref:`distance_units` for a list of available - units. + Vertical output units. See :ref:`distance_units` and :ref:`angular_units` + for a list of available units. `` is the conversion factor + from the output unit to the International System unit. .. option:: +t_in= @@ -74,7 +78,7 @@ Parameters Distance units ############################################################################### -In the table below all distance units supported by PROJ is listed. +In the table below all distance units supported by PROJ are listed. The same list can also be produced on the command line with :program:`proj` or :program:`cs2cs`, by adding the `-lu` flag when calling the utility. @@ -124,12 +128,30 @@ The same list can also be produced on the command line with :program:`proj` or | ind-ch | Indian Chain | +----------+---------------------------------+ +.. _angular_units: + +Angular units +############################################################################### + +In the table below all angular units supported by PROJ `unitconvert` are listed. +(since PROJ 5.2.0) + ++----------+---------------------------------+ +| **Label**| **Name** | ++----------+---------------------------------+ +| deg | Degree | ++----------+---------------------------------+ +| grad | Grad | ++----------+---------------------------------+ +| rad | Radian | ++----------+---------------------------------+ + .. _time_units: Time units ############################################################################### -In the table below all time units supported by PROJ is listed. +In the table below all time units supported by PROJ are listed. +--------------+-----------------------------+ | **label** | **Name** | diff --git a/src/PJ_unitconvert.c b/src/PJ_unitconvert.c index 25bdc2e73a..010027161e 100644 --- a/src/PJ_unitconvert.c +++ b/src/PJ_unitconvert.c @@ -382,6 +382,49 @@ static PJ_COORD reverse_4d(PJ_COORD obs, PJ *P) { return out; } +/* M_PI / 200 */ +#define GRAD_TO_RAD 0.015707963267948967 + +static const struct PJ_UNITS +pj_angular_units[] = { + {"rad", "1.0", "Radian", 1.0}, + {"deg", "0.017453292519943296", "Degree", DEG_TO_RAD}, + {"grad", "0.015707963267948967", "Grad", GRAD_TO_RAD}, + {NULL, NULL, NULL, 0.0} +}; + + +/***********************************************************************/ +static double getUnitConversionFactor(const char* name, + const char** p_normalized_name) { +/***********************************************************************/ + int i; + const char* s; + + /* Try first with linear units */ + for (i = 0; (s = pj_units[i].id) ; ++i) { + if ( strcmp(s, name) == 0 ) { + if( p_normalized_name ) { + *p_normalized_name = pj_units[i].name; + } + return pj_units[i].factor; + } + } + + /* And then angular units */ + for (i = 0; (s = pj_angular_units[i].id) ; ++i) { + if ( strcmp(s, name) == 0 ) { + if( p_normalized_name ) { + *p_normalized_name = pj_angular_units[i].name; + } + return pj_angular_units[i].factor; + } + } + if( p_normalized_name ) { + *p_normalized_name = NULL; + } + return 0.0; +} /***********************************************************************/ PJ *CONVERSION(unitconvert,0) { @@ -413,11 +456,10 @@ PJ *CONVERSION(unitconvert,0) { Q->z_factor = 1.0; if ((name = pj_param (P->ctx, P->params, "sxy_in").s) != NULL) { - for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - - if (s) { - f = pj_units[i].factor; - proj_log_debug(P, "xy_in unit: %s", pj_units[i].name); + const char* normalized_name = NULL; + f = getUnitConversionFactor(name, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "xy_in unit: %s", normalized_name); } else { if ( (f = pj_param (P->ctx, P->params, "dxy_in").f) == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); @@ -427,11 +469,10 @@ PJ *CONVERSION(unitconvert,0) { } if ((name = pj_param (P->ctx, P->params, "sxy_out").s) != NULL) { - for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - - if (s) { - f = pj_units[i].factor; - proj_log_debug(P, "xy_out unit: %s", pj_units[i].name); + const char* normalized_name = NULL; + f = getUnitConversionFactor(name, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "xy_out unit: %s", normalized_name); } else { if ( (f = pj_param (P->ctx, P->params, "dxy_out").f) == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); @@ -441,11 +482,10 @@ PJ *CONVERSION(unitconvert,0) { } if ((name = pj_param (P->ctx, P->params, "sz_in").s) != NULL) { - for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - - if (s) { - f = pj_units[i].factor; - proj_log_debug(P, "z_in unit: %s", pj_units[i].name); + const char* normalized_name = NULL; + f = getUnitConversionFactor(name, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "z_in unit: %s", normalized_name); } else { if ( (f = pj_param (P->ctx, P->params, "dz_in").f) == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); @@ -455,11 +495,10 @@ PJ *CONVERSION(unitconvert,0) { } if ((name = pj_param (P->ctx, P->params, "sz_out").s) != NULL) { - for (i = 0; (s = pj_units[i].id) && strcmp(name, s) ; ++i); - - if (s) { - f = pj_units[i].factor; - proj_log_debug(P, "z_out unit: %s", pj_units[i].name); + const char* normalized_name = NULL; + f = getUnitConversionFactor(name, &normalized_name); + if (f != 0.0) { + proj_log_debug(P, "z_out unit: %s", normalized_name); } else { if ( (f = pj_param (P->ctx, P->params, "dz_out").f) == 0.0) return pj_default_destructor(P, PJD_ERR_UNKNOWN_UNIT_ID); diff --git a/test/gie/unitconvert.gie b/test/gie/unitconvert.gie index 30d9dc0bf0..ff6dc96f5d 100644 --- a/test/gie/unitconvert.gie +++ b/test/gie/unitconvert.gie @@ -25,4 +25,15 @@ tolerance 0.1 accept 1 1 1 1 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 + +operation proj=unitconvert xy_in=grad xy_out=deg +tolerance 0.000000000001 +accept 50 50 1 1 +expect 45 45 1 1 + +