From 16e8827ff6dfd9e9e44c1c33fea3b3f270cfa4a3 Mon Sep 17 00:00:00 2001 From: Even Rouault Date: Tue, 21 Aug 2018 14:38:04 +0200 Subject: [PATCH] [BREAKING] Hermert: add +convention=position_vector/coordinate_frame, forbids +transpose (fixes #1091) As identified in #1091, Helmert implementation in PROJ 5.0 and 5.1 is confusing. It happens that by default it used the coordinate_frame convention, contrary to the position_vector convention used traditionaly for +towgs84. The documentation of Helmert was also wrongly specifying that the default convention was position_vector. This commit: - bans the confusing +transpose parameter - removes the concept of a default convention, since in practice both are equally found, and requires +convention as soon as a rotational term parameter is present. For translation only, convention is ignored and optional, as having no effect. - fixes all the identified uses of proj=helmert in code, doc and tests This is obviously a breaking change: - users will have to adapt their pipeline expressions - in particular, init files that would use helmert must be adapted However, as designed, the break will be explicit, and not silent. --- .../transformations/deformation.rst | 4 +- .../operations/transformations/helmert.rst | 77 +++++++++++++------ docs/source/resource_files.rst | 2 +- docs/source/usage/transformation.rst | 11 ++- nad/ITRF2000 | 20 ++--- nad/ITRF2008 | 50 ++++++------ nad/ITRF2014 | 46 +++++------ src/PJ_helmert.c | 67 ++++++++++++---- src/proj_4D_api.c | 2 +- test/gie/GDA.gie | 4 +- test/gie/more_builtins.gie | 30 ++++++-- 11 files changed, 202 insertions(+), 111 deletions(-) diff --git a/docs/source/operations/transformations/deformation.rst b/docs/source/operations/transformations/deformation.rst index 79d9b7b8f7..87b084532e 100644 --- a/docs/source/operations/transformations/deformation.rst +++ b/docs/source/operations/transformations/deformation.rst @@ -51,7 +51,7 @@ to the Danish realisation of ETRS89 is in PROJ described as:: # ITRF2008@t_obs -> ITRF2000@t_obs step init = ITRF2008:ITRF2000 # ITRF2000@t_obs -> ETRF2000@t_obs - step proj=helmert t_epoch = 2000.0 transpose + step proj=helmert t_epoch = 2000.0 convention=position_vector x = 0.054 rx = 0.000891 drx = 8.1e-05 y = 0.051 ry = 0.00539 dry = 0.00049 z = -0.048 rz = -0.008712 drz = -0.000792 @@ -60,7 +60,7 @@ to the Danish realisation of ETRS89 is in PROJ described as:: xy_grids = ./nkgrf03vel_realigned_xy.ct2 z_grids = ./nkgrf03vel_realigned_z.gtx # NKG_ETRF@2000.0 -> ETRF92@2000.0 - step proj=helmert transpose s = -0.009420e + step proj=helmert convention=position_vector s = -0.009420e x = 0.03863 rx = 0.00617753 y = 0.147 ry = 5.064e-05 z = 0.02776 rz = 4.729e-05 diff --git a/docs/source/operations/transformations/helmert.rst b/docs/source/operations/transformations/helmert.rst index 69776285eb..6adeaa1712 100644 --- a/docs/source/operations/transformations/helmert.rst +++ b/docs/source/operations/transformations/helmert.rst @@ -53,25 +53,25 @@ Transforming coordinates from NAD72 to NAD83 using the 4 parameter 2D Helmert: :: - proj=helmert x=-9597.3572 y=.6112 s=0.304794780637 theta=-1.244048 + proj=helmert convention=coordinate_frame x=-9597.3572 y=.6112 s=0.304794780637 theta=-1.244048 Simplified transformations from ITRF2008/IGS08 to ETRS89 using 7 parameters: :: - proj=helmert x=0.67678 y=0.65495 z=-0.52827 + proj=helmert convention=coordinate_frame x=0.67678 y=0.65495 z=-0.52827 rx=-0.022742 ry=0.012667 rz=0.022704 s=-0.01070 Transformation from `ITRF2000@2017.0` to `ITRF93@2017.0` using 15 parameters: :: - proj=helmert + proj=helmert convention=position_vector x=0.0127 y=0.0065 z=-0.0209 s=0.00195 dx=-0.0029 dy=-0.0002 dz=-0.0006 ds=0.00001 rx=-0.00039 ry=0.00080 rz=-0.00114 drx=-0.00011 dry=-0.00019 drz=0.00007 - t_epoch=1988.0 t_obs=2017.0 transpose + t_epoch=1988.0 t_obs=2017.0 Parameters +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -81,6 +81,36 @@ Parameters All parameters are optional but at least one should be used, otherwise the operation will return the coordinates unchanged. +.. option:: +convention=coordinate_frame/position_vector + + .. versionadded:: 5.2.0 + + Indicates the convention to express the rotational terms when a 3D-Helmert / + 7-parameter more transform is involved. As soon as a rotational parameter + is specified (one of ``rx``, ``ry``, ``rz``, ``drx``, ``dry``, ``drz``), + ``convention`` is required. + + The two conventions are equally popular and a frequent source of confusion. + The coordinate frame convention is also described as an clockwise + rotation of the coordinate frame. It corresponds to EPSG method code + 1032 (in the geocentric domain) or 9607 (in the geographic domain) + The position vector convention is also described as an anticlockwise + (counter-clockwise) rotation of the coordinate frame. + It corresponds to as EPSG method code 1033 (in the geocentric domain) or + 9606 (in the geographic domain). + + This parameter is ignored when only a 3-parameter + (translation terms only: ``x``, ``y``, ``z``) , 4-parameter (3-parameter + and ``theta``) or 6-parameter (3-parameter and their derivative terms) + is used. + + The result obtained with parameters specified in a given convention + can be obtained in the other convention by negating the rotational parameters + (``rx``, ``ry``, ``rz``, ``drx``, ``dry``, ``drz``) + + .. note:: This parameter obsoletes ``transpose`` which was present in + PROJ 5.0 and 5.1, and is forbidden starting with PROJ 5.2 + .. option:: +x= Translation of the x-axis given in meters. @@ -161,13 +191,6 @@ Parameters See :eq:`rot_exact` -.. option:: +transpose - - Transpose rotation matrix and follow the **Cordinate Frame** rotation - convention. If :option:`+transpose` is not added the **Position Vector** - rotation convention is used. - - Mathematical description +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ @@ -278,24 +301,30 @@ is the scaling factor and :math:`\mathbf{R}` is a rotation matrix. :math:`V^A` a :math:`V^B` are coordinate vectors, with :math:`V^A` being the input coordinate and :math:`V^B` is the output coordinate. -The rotation matrix is composed of three rotation matrices, one for each axis: +In the *Position Vector* convention, we define :math:`R_x = radians \left( rx \right)`, +:math:`R_z = radians \left( ry \right)` and :math:`R_z = radians \left( rz \right)` + +In the *Coordinate Frame* convention, :math:`R_x = - radians \left( rx \right)`, +:math:`R_z = - radians \left( ry \right)` and :math:`R_z = - radians \left( rz \right)` + +The rotation matrix is composed of three rotation matrices, one for each axis. .. math:: \begin{align} - \mathbf{R}_X &= \begin{bmatrix} 1 & 0 & 0\\ 0 & \cos\phi & -\sin\phi\\ 0 & \sin\phi & \cos\phi \end{bmatrix} + \mathbf{R}_X &= \begin{bmatrix} 1 & 0 & 0\\ 0 & \cos R_x & -\sin R_x \\ 0 & \sin R_x & \cos R_x \end{bmatrix} \end{align} .. math:: \begin{align} - \mathbf{R}_Y &= \begin{bmatrix} \cos\theta & 0 & \sin\theta\\ 0 & 1 & 0\\ -\sin\theta & 0 & \cos\theta \end{bmatrix} + \mathbf{R}_Y &= \begin{bmatrix} \cos R_y & 0 & \sin R_y\\ 0 & 1 & 0\\ -\sin R_y & 0 & \cos R_y \end{bmatrix} \end{align} .. math:: \begin{align} - \mathbf{R}_Z &= \begin{bmatrix} \cos\psi & -\sin\psi & 0\\ \sin\psi & \cos\psi & 0\\ 0 & 0 & 1 \end{bmatrix} + \mathbf{R}_Z &= \begin{bmatrix} \cos R_z & -\sin R_z & 0\\ \sin R_z & \cos R_z & 0\\ 0 & 0 & 1 \end{bmatrix} \end{align} The three rotation matrices can be combined in one: @@ -313,9 +342,11 @@ For :math:`\mathbf{R}`, this yields: :label: rot_exact \begin{bmatrix} - \cos\theta \cos\psi & -\cos\phi \sin\psi + \sin\phi \sin\theta \cos\psi & \sin\phi \sin\psi + \cos\phi \sin\theta \cos\psi \\ - \cos\theta\sin\psi & \cos\phi \cos\psi + \sin\phi \sin\theta \sin\psi & - \sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\ - -\sin\theta & \sin\phi \cos\theta & \cos\phi \cos\theta \\ + \cos R_y \cos R_z & -\cos R_x \sin R_z + & \sin R_x \sin R_z + \\ + & \sin R_x \sin R_y \cos R_z & \cos R_x \sin R_y \cos R_z \\ + \cos R_y\sin R_z & \cos R_x \cos R_z + & - \sin R_x \cos R_z + \\ + & \sin R_x \sin R_y \sin R_z & \cos R_x \sin R_y \sin R_z \\ + -\sin R_y & \sin R_x \cos R_y & \cos R_x \cos R_y \\ \end{bmatrix} @@ -363,12 +394,10 @@ using the approximated rotation matrix: \end{bmatrix}^A \end{align} -If the rotation matrix is transposed the transformation is effectively reversed. -This is cause for some confusion since there is no correct way of defining the -rotation matrix. Two conventions exists and they seem to be equally popular. PROJ -uses the **Position Vector** rotation convention. The rotation matrix can be transposed by -adding the :option:`+transpose` flag in the transformation setup which makes PROJ -follow the **Coordinate Frame** rotation convention. +If the rotation matrix is transposed, or the sign of the rotation terms negated, +the rotational part of the transformation is effectively reversed. +This is what happens when switching between the 2 conventions ``position_vector`` +and ``coordinate_frame`` Applying :eq:`propagation` we get the kinematic version of the approximated 3D Helmert: diff --git a/docs/source/resource_files.rst b/docs/source/resource_files.rst index 10cbcb7b1f..c0321b1866 100644 --- a/docs/source/resource_files.rst +++ b/docs/source/resource_files.rst @@ -412,7 +412,7 @@ which then expands to +proj=helmert +x=-0.0001 +y=0.0008 +z=0.0058 +s=-0.0004 +dx=0.0002 +dy=-0.0001 +dz=0.0018 +ds=-0.000008 - +t_epoch=2000.0 +transpose + +t_epoch=2000.0 +convention=position_vector +t_obs=2010.5 Below is a list of the init files that are packaged with PROJ. diff --git a/docs/source/usage/transformation.rst b/docs/source/usage/transformation.rst index acec0bb52f..b4ed703128 100644 --- a/docs/source/usage/transformation.rst +++ b/docs/source/usage/transformation.rst @@ -75,7 +75,7 @@ the introduction). In PROJ it can be implemented as proj=pipeline step proj=cart ellps=intl - step proj=helmert + step proj=helmert convention=coordinate_frame x=-81.0703 y=-89.3603 z=-115.7526 rx=-0.48488 ry=-0.02436 rz=-0.41321 s=-0.540645 step proj=cart inv ellps=GRS80 @@ -101,7 +101,7 @@ deprecated system with decimeter level tensions. step init=./s45b.pol:s45b_tc32 step proj=utm inv ellps=intl zone=32 step proj=cart ellps=intl - step proj=helmert + step proj=helmert convention=coordinate_frame x=-81.0703 y=-89.3603 z=-115.7526 rx=-0.48488 ry=-0.02436 rz=-0.41321 s=-0.540645 step proj=cart inv ellps=GRS80 @@ -116,16 +116,15 @@ data, but the 14-parameter Helmert transform expects temporal units in decimalye Hence the first step in the pipeline is the unitconvert pseudo-projection that makes sure the correct units are passed along to the Helmert transform. Most parameters of the Helmert transform are taken from :cite:`Altamimi2002`, -except the epoch which is the epoch of the transformation. The default setting is to -use “coordinate frame” convention of the Helmert transform, but “position vector” -convention can also be used. The last step in the pipeline is converting the +except the epoch which is the epoch of the transformation. +The last step in the pipeline is converting the coordinate timestamps back to GPS weeks. :: proj=pipeline step proj=unitconvert t_in=gps_week t_out=decimalyear - step proj=helmert + step proj=helmert convention=coordinate_frame x=0.0127 y=0.0065 z=-0.0209 s=0.00195 rx=0.00039 ry=-0.00080 rz=0.00114 dx=-0.0029 dy=-0.0002 dz=-0.0006 ds=0.00001 diff --git a/nad/ITRF2000 b/nad/ITRF2000 index f0a80db6a9..a7064f3ba1 100644 --- a/nad/ITRF2000 +++ b/nad/ITRF2000 @@ -3,22 +3,22 @@ # ITRF2000 -> ITRF2005 is only defined the opposite way, so we flip the sign on all # parameters to get the opposite transformation. Parameters from http://itrf.ign.fr/ITRF_solutions/2005/tp_05-00.php - +proj=helmert +x=-0.0001 +y=0.0008 +z=0.0058 +s=-0.0004 +dx=0.0002 +dy=-0.0001 +dz=0.0018 +ds=-0.000008 +t_epoch=2000.0 +transpose + +proj=helmert +x=-0.0001 +y=0.0008 +z=0.0058 +s=-0.0004 +dx=0.0002 +dy=-0.0001 +dz=0.0018 +ds=-0.000008 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0067 +y=0.0061 +z=-0.0185 +s=0.00155 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1997.0 +transpose + +proj=helmert +x=0.0067 +y=0.0061 +z=-0.0185 +s=0.00155 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1997.0 +convention=position_vector - +proj=helmert +x=0.0067 +y=0.0061 +z=-0.0185 +s=0.00155 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1997.0 +transpose + +proj=helmert +x=0.0067 +y=0.0061 +z=-0.0185 +s=0.00155 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1997.0 +convention=position_vector - +proj=helmert +x=0.0067 +y=0.0061 +z=-0.0185 +s=0.00155 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1997.0 +transpose + +proj=helmert +x=0.0067 +y=0.0061 +z=-0.0185 +s=0.00155 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1997.0 +convention=position_vector - +proj=helmert +x=0.0127 +y=0.0065 +z=-0.0209 +s=0.00195 +rx=-0.00039 +ry=0.00080 +rz=-0.00114 +dx=-0.0029 +dy=-0.0002 +dz=-0.0006 +ds=0.00001 +drx=-0.00011 +dry=-0.00019 +drz=0.00007 +t_epoch=1988.0 +transpose + +proj=helmert +x=0.0127 +y=0.0065 +z=-0.0209 +s=0.00195 +rx=-0.00039 +ry=0.00080 +rz=-0.00114 +dx=-0.0029 +dy=-0.0002 +dz=-0.0006 +ds=0.00001 +drx=-0.00011 +dry=-0.00019 +drz=0.00007 +t_epoch=1988.0 +convention=position_vector - +proj=helmert +x=0.0147 +y=0.0135 +z=-0.0139 +s=0.00075 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +transpose + +proj=helmert +x=0.0147 +y=0.0135 +z=-0.0139 +s=0.00075 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +convention=position_vector - +proj=helmert +x=0.0267 +y=0.0275 +z=-0.0199 +s=0.00215 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +transpose + +proj=helmert +x=0.0267 +y=0.0275 +z=-0.0199 +s=0.00215 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +convention=position_vector - +proj=helmert +x=0.0247 +y=0.0235 +z=-0.0359 +s=0.00245 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +transpose + +proj=helmert +x=0.0247 +y=0.0235 +z=-0.0359 +s=0.00245 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +convention=position_vector - +proj=helmert +x=0.0297 +y=0.0475 +z=-0.0739 +s=0.00585 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +transpose + +proj=helmert +x=0.0297 +y=0.0475 +z=-0.0739 +s=0.00585 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +convention=position_vector - +proj=helmert +x=0.0247 +y=0.0115 +z=-0.0979 +s=0.00895 +rx=0.0001 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +transpose + +proj=helmert +x=0.0247 +y=0.0115 +z=-0.0979 +s=0.00895 +rx=0.0001 +rz=-0.00018 +dy=-0.0006 +dz=-0.0014 +ds=0.00001 +drz=0.00002 +t_epoch=1988.0 +convention=position_vector diff --git a/nad/ITRF2008 b/nad/ITRF2008 index 2d730d6e7d..33964d9d8d 100644 --- a/nad/ITRF2008 +++ b/nad/ITRF2008 @@ -1,27 +1,27 @@ # ITRF2008 params are in mm/year, PJ_helmert uses m/year +version=1.0.0 +origin=http://itrf.ign.fr/doc_ITRF/Transfo-ITRF2008_ITRFs.txt +lastupdate=2017-07-26 - +proj=helmert +x=-0.002 +y=-0.0009 +z=-0.0047 +s=0.00094 +dx=0.0003 +t_epoch=2000.0 +transpose + +proj=helmert +x=-0.002 +y=-0.0009 +z=-0.0047 +s=0.00094 +dx=0.0003 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=-0.0019 +y=-0.0017 +z=-0.0105 +s=0.00134 +dx=0.0001 +dy=0.0001 +dz=-0.0018 +ds=0.00008 +t_epoch=2000.0 +transpose + +proj=helmert +x=-0.0019 +y=-0.0017 +z=-0.0105 +s=0.00134 +dx=0.0001 +dy=0.0001 +dz=-0.0018 +ds=0.00008 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0048 +y=0.0026 +z=-0.0332 +s=0.00292 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0048 +y=0.0026 +z=-0.0332 +s=0.00292 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0048 +y=0.0026 +z=-0.0332 +s=0.00292 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0048 +y=0.0026 +z=-0.0332 +s=0.00292 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0048 +y=0.0026 +z=-0.0332 +s=0.00292 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0048 +y=0.0026 +z=-0.0332 +s=0.00292 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=-0.024 +y=0.0024 +z=-0.00386 +s=0.00341 +rx=-0.00171 +ry=-0.00148 +rz=-0.0003 +dx=-0.0028 +dy=-0.0001 +dz=-0.0024 +ds=0.00009 +drx=-0.00011 +dry=-0.00019 +drz=0.00007 +t_epoch=2000.0 +transpose + +proj=helmert +x=-0.024 +y=0.0024 +z=-0.00386 +s=0.00341 +rx=-0.00171 +ry=-0.00148 +rz=-0.0003 +dx=-0.0028 +dy=-0.0001 +dz=-0.0024 +ds=0.00009 +drx=-0.00011 +dry=-0.00019 +drz=0.00007 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0128 +y=0.0046 +z=-0.0412 +s=0.00221 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0128 +y=0.0046 +z=-0.0412 +s=0.00221 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0248 +y=0.0186 +z=-0.0472 +s=0.00361 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0248 +y=0.0186 +z=-0.0472 +s=0.00361 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0228 +y=0.0146 +z=-0.0632 +s=0.00391 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0228 +y=0.0146 +z=-0.0632 +s=0.00391 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0278 +y=0.0386 +z=-0.1012 +s=0.00731 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0278 +y=0.0386 +z=-0.1012 +s=0.00731 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector - +proj=helmert +x=0.0228 +y=0.0026 +z=-0.1252 +s=0.01041 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +transpose + +proj=helmert +x=0.0228 +y=0.0026 +z=-0.1252 +s=0.01041 +rz=0.00006 +dx=0.0001 +dy=-0.0005 +dz=-0.0032 +ds=0.00009 +drz=0.00002 +t_epoch=2000.0 +convention=position_vector # ITRF2008 Plate Motion Model parameters @@ -32,30 +32,30 @@ # J. Geophys. Res., 117, B07402, doi:10.1029/2011JB008930. - +proj=helmert +drx=-0.000190 +dry=-0.000442 +drz=0.000915 + +proj=helmert +drx=-0.000190 +dry=-0.000442 +drz=0.000915 +convention=coordinate_frame - +proj=helmert +drx=-0.000252 +dry=-0.000302 +drz=0.000643 + +proj=helmert +drx=-0.000252 +dry=-0.000302 +drz=0.000643 +convention=coordinate_frame - +proj=helmert +drx=0.001202 +dry=-0.000054 +drz=0.001485 + +proj=helmert +drx=0.001202 +dry=-0.000054 +drz=0.001485 +convention=coordinate_frame - +proj=helmert +drx=0.001504 +dry=0.001172 +drz=0.001228 + +proj=helmert +drx=0.001504 +dry=0.001172 +drz=0.001228 +convention=coordinate_frame - +proj=helmert +drx=0.000049 +dry=-0.001088 +drz=0.000664 + +proj=helmert +drx=0.000049 +dry=-0.001088 +drz=0.000664 +convention=coordinate_frame - +proj=helmert +drx=-0.000083 +dry=0.000534 +drz=0.000750 + +proj=helmert +drx=-0.000083 +dry=0.000534 +drz=0.000750 +convention=coordinate_frame - +proj=helmert +drx=0.001232 +dry=0.000303 +drz=0.001540 + +proj=helmert +drx=0.001232 +dry=0.000303 +drz=0.001540 +convention=coordinate_frame - +proj=helmert +drx=-0.000330 +dry=-0.001551 +drz=0.001625 + +proj=helmert +drx=-0.000330 +dry=-0.001551 +drz=0.001625 +convention=coordinate_frame - +proj=helmert +drx=0.000035 +dry=-0.000662 +drz=0.0001 + +proj=helmert +drx=0.000035 +dry=-0.000662 +drz=0.0001 +convention=coordinate_frame - +proj=helmert +drx=0.000095 +dry=-0.000598 +drz=0.000723 + +proj=helmert +drx=0.000095 +dry=-0.000598 +drz=0.000723 +convention=coordinate_frame - +proj=helmert +drx=0.000411 +dry=0.001036 +drz=-0.002166 + +proj=helmert +drx=0.000411 +dry=0.001036 +drz=-0.002166 +convention=coordinate_frame - +proj=helmert +drx=-0.000243 +dry=-0.000311 +drz=-0.000154 + +proj=helmert +drx=-0.000243 +dry=-0.000311 +drz=-0.000154 +convention=coordinate_frame - +proj=helmert +drx=-0.000080 +dry=-0.000745 +drz=0.000897 + +proj=helmert +drx=-0.000080 +dry=-0.000745 +drz=0.000897 +convention=coordinate_frame - +proj=helmert +drx=0.000047 +dry=-0.001 +drz=0.000975 + +proj=helmert +drx=0.000047 +dry=-0.001 +drz=0.000975 +convention=coordinate_frame diff --git a/nad/ITRF2014 b/nad/ITRF2014 index 3465ec787b..6dce0320be 100644 --- a/nad/ITRF2014 +++ b/nad/ITRF2014 @@ -1,29 +1,29 @@ # ITRF2014 params are in mm/year, PJ_helmert uses m/year +version=1.0.0 +origin=http://itrf.ign.fr/doc_ITRF/Transfo-ITRF2014_ITRFs.txt +lastupdate=2017-07-26 - +proj=helmert +x=0.0016 +y=0.0019 +z=0.0024 +s=-0.00002 +dz=-0.0001 +ds=0.00003 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0016 +y=0.0019 +z=0.0024 +s=-0.00002 +dz=-0.0001 +ds=0.00003 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0026 +y=0.001 +z=-0.0023 +s=0.00092 +dx=0.0003 +dz=-0.0001 +ds=0.00003 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0026 +y=0.001 +z=-0.0023 +s=0.00092 +dx=0.0003 +dz=-0.0001 +ds=0.00003 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0007 +y=0.0012 +z=-0.0261 +s=0.00212 +dx=0.0001 +dy=0.0001 +dz=-0.0019 +ds=0.00011 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0007 +y=0.0012 +z=-0.0261 +s=0.00212 +dx=0.0001 +dy=0.0001 +dz=-0.0019 +ds=0.00011 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0074 +y=-0.0005 +z=-0.0628 +d=0.0038 +rz=0.00026 +dx0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0074 +y=-0.0005 +z=-0.0628 +d=0.0038 +rz=0.00026 +dx0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0074 +y=-0.0005 +z=-0.0628 +s=0.0038 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0074 +y=-0.0005 +z=-0.0628 +s=0.0038 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0074 +y=-0.0005 +z=-0.0628 +s=0.0038 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0074 +y=-0.0005 +z=-0.0628 +s=0.0038 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=-0.0504 +y=0.0033 +z=-0.0602 +s=0.00429 +rx=-0.00281 +ry=-0.00338 +rz=0.0004 +dx=-0.0028 +dy=-0.0001 +dz=-0.0025 +ds=0.00012 +drx=-0.00011 +dry=-0.00019 +drz=0.00007 +t_epoch=2010.0 +transpose + +proj=helmert +x=-0.0504 +y=0.0033 +z=-0.0602 +s=0.00429 +rx=-0.00281 +ry=-0.00338 +rz=0.0004 +dx=-0.0028 +dy=-0.0001 +dz=-0.0025 +ds=0.00012 +drx=-0.00011 +dry=-0.00019 +drz=0.00007 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0154 +y=0.0015 +z=-0.0708 +s=0.00309 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0154 +y=0.0015 +z=-0.0708 +s=0.00309 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0274 +y=0.0155 +z=-0.0768 +s=0.00449 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0274 +y=0.0155 +z=-0.0768 +s=0.00449 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0254 +y=0.0115 +z=-0.0928 +s=0.00479 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0254 +y=0.0115 +z=-0.0928 +s=0.00479 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0304 +y=0.0355 +z=-0.1308 +s=0.00819 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0304 +y=0.0355 +z=-0.1308 +s=0.00819 +rz=0.00026 +dx=0.0001 +dy=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +convention=position_vector - +proj=helmert +x=0.0254 +y=-0.0005 +z=-0.1548 +s=0.01129 +rx=0.0001 +rz= +dx=0.00026 +dy=0.0001 +dx=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +transpose + +proj=helmert +x=0.0254 +y=-0.0005 +z=-0.1548 +s=0.01129 +rx=0.0001 +rz= +dx=0.00026 +dy=0.0001 +dx=-0.0005 +dz=-0.0033 +ds=0.00012 +drz=0.00002 +t_epoch=2010.0 +convention=position_vector # ITRF2014 Plate Motion Model parameters # @@ -32,24 +32,24 @@ # Z. Altamimi et al, 2017, ITRF2014 plate motion model, # doi: 10.1093/gji/ggx136 - +proj=helmert +drx=−0.000248 +dry=−0.000324 +drz=0.000675 + +proj=helmert +drx=−0.000248 +dry=−0.000324 +drz=0.000675 +convention=coordinate_frame - +proj=helmert +drx=0.001154 +dry=−0.000136 +drz=0.001444 + +proj=helmert +drx=0.001154 +dry=−0.000136 +drz=0.001444 +convention=coordinate_frame - +proj=helmert +drx=0.001510 +dry=0.001182 +drz=0.001215 + +proj=helmert +drx=0.001510 +dry=0.001182 +drz=0.001215 +convention=coordinate_frame - +proj=helmert +drx=−0.000085 +dry=−0.000531 +drz=0.000770 + +proj=helmert +drx=−0.000085 +dry=−0.000531 +drz=0.000770 +convention=coordinate_frame - +proj=helmert +drx=0.001154 +dry=−0.000005 +drz=0.001454 + +proj=helmert +drx=0.001154 +dry=−0.000005 +drz=0.001454 +convention=coordinate_frame - +proj=helmert +drx=−0.000333 +dry=−0.001544 +drz=0.001623 + +proj=helmert +drx=−0.000333 +dry=−0.001544 +drz=0.001623 +convention=coordinate_frame - +proj=helmert +drx=0.000024 +dry=-0.000694 +drz=-0.000063 + +proj=helmert +drx=0.000024 +dry=-0.000694 +drz=-0.000063 +convention=coordinate_frame - +proj=helmert +drx=0.000099 +dry=−0.000614 +drz=0.000733 + +proj=helmert +drx=0.000099 +dry=−0.000614 +drz=0.000733 +convention=coordinate_frame - +proj=helmert +drx=−0.000409 +dry=0.001047 +drz=-0.002169 + +proj=helmert +drx=−0.000409 +dry=0.001047 +drz=-0.002169 +convention=coordinate_frame - +proj=helmert +drx=−0.000270 +dry=−0.000301 +drz=−0.000140 + +proj=helmert +drx=−0.000270 +dry=−0.000301 +drz=−0.000140 +convention=coordinate_frame - +proj=helmert +drx=−0.000121 +dry=−0.000794 +drz=0.000884 + +proj=helmert +drx=−0.000121 +dry=−0.000794 +drz=0.000884 +convention=coordinate_frame diff --git a/src/PJ_helmert.c b/src/PJ_helmert.c index 490bc2c48d..b801d91655 100644 --- a/src/PJ_helmert.c +++ b/src/PJ_helmert.c @@ -77,7 +77,8 @@ struct pj_opaque_helmert { double dtheta; double R[3][3]; double t_epoch, t_obs; - int no_rotation, exact, transpose, fourparam; + int no_rotation, exact, fourparam; + int is_position_vector; // 1 = position_vector, 0 = coordinate_frame }; @@ -200,7 +201,7 @@ static void build_rot_matrix(PJ *P) { Sign conventions ---------------- - Take care: Two different sign conventions exist. + Take care: Two different sign conventions exist for the rotation terms. Conceptually they relate to whether we rotate the coordinate system or the "position vector" (the vector going from the coordinate system @@ -213,7 +214,7 @@ static void build_rot_matrix(PJ *P) { the rotation matrix. Hence, as geodetic constants should preferably be referred to exactly - as published, the "transpose" option provides the ability to switch + as published, the "convention" option provides the ability to switch between the conventions. ***************************************************************************/ @@ -228,6 +229,8 @@ static void build_rot_matrix(PJ *P) { t = Q->opk.p; p = Q->opk.k; + /* Those equations are given assuming coordinate frame convention. */ + /* For the position vector convention, we transpose the matrix just after. */ if (Q->exact) { cf = cos(f); sf = sin(f); @@ -290,7 +293,7 @@ static void build_rot_matrix(PJ *P) { */ - if (Q->transpose) { + if (Q->is_position_vector) { double r; r = R01; R01 = R10; R10 = r; r = R02; R02 = R20; R20 = r; @@ -461,7 +464,6 @@ static PJ_COORD helmert_reverse_4d (PJ_COORD point, PJ *P) { return point; } - /* Arcsecond to radians */ #define ARCSEC_TO_RAD (DEG_TO_RAD / 3600.0) @@ -489,6 +491,13 @@ PJ *TRANSFORMATION(helmert, 0) { P->right = PJ_IO_UNITS_PROJECTED; } + /* Detect obsolete transpose flag and error out if found */ + if (pj_param (P->ctx, P->params, "ttranspose").i) { + proj_log_error (P, "helmert: 'transpose' argument is no longer valid. " + "Use convention=position_vector/coordinate_frame"); + return pj_default_destructor (P, PJD_ERR_INVALID_ARG); + } + /* Support the classic PROJ towgs84 parameter, but allow later overrides.*/ /* Note that if towgs84 is specified, the datum_params array is set up */ /* for us automagically by the pj_datum_set call in pj_init_ctx */ @@ -580,30 +589,62 @@ PJ *TRANSFORMATION(helmert, 0) { if (pj_param (P->ctx, P->params, "bexact").i) Q->exact = 1; - /* Use "other" rotation sign convention? */ - if (pj_param (P->ctx, P->params, "ttranspose").i) - Q->transpose = 1; - Q->xyz = Q->xyz_0; Q->opk = Q->opk_0; Q->scale = Q->scale_0; Q->theta = Q->theta_0; + if ((Q->opk.o==0) && (Q->opk.p==0) && (Q->opk.k==0) && (Q->scale==0) && + (Q->dopk.o==0) && (Q->dopk.p==0) && (Q->dopk.k==0)) { + Q->no_rotation = 1; + } + + /* In case there are rotational terms, we require an explicit convention + * to be provided. */ + if (!Q->no_rotation) { + const char* convention = pj_param (P->ctx, P->params, "sconvention").s; + if( !convention ) { + proj_log_error (P, "helmert: missing 'convention' argument"); + return pj_default_destructor (P, PJD_ERR_MISSING_ARGS); + } + if( strcmp(convention, "position_vector") == 0 ) { + Q->is_position_vector = 1; + } + else if( strcmp(convention, "coordinate_frame") == 0 ) { + Q->is_position_vector = 0; + } + else { + proj_log_error (P, "helmert: invalid value for 'convention' argument"); + return pj_default_destructor (P, PJD_ERR_INVALID_ARG); + } + + /* historically towgs84 in PROJ has always been using position_vector + * convention. Accepting coordinate_frame would be confusing. */ + if (pj_param_exists (P->params, "towgs84")) { + if( !Q->is_position_vector ) { + proj_log_error (P, "helmert: towgs84 should only be used with " + "convention=position_vector"); + return pj_default_destructor (P, PJD_ERR_INVALID_ARG); + } + } + } + /* Let's help with debugging */ if (proj_log_level(P->ctx, PJ_LOG_TELL) >= PJ_LOG_DEBUG) { proj_log_debug(P, "Helmert parameters:"); proj_log_debug(P, "x= %8.5f y= %8.5f z= %8.5f", Q->xyz.x, Q->xyz.y, Q->xyz.z); proj_log_debug(P, "rx= %8.5f ry= %8.5f rz= %8.5f", Q->opk.o / ARCSEC_TO_RAD, Q->opk.p / ARCSEC_TO_RAD, Q->opk.k / ARCSEC_TO_RAD); - proj_log_debug(P, "s= %8.5f exact=%d transpose=%d", Q->scale, Q->exact, Q->transpose); + proj_log_debug(P, "s= %8.5f exact=%d%s", Q->scale, Q->exact, + Q->no_rotation ? "" : + Q->is_position_vector ? " convention=position_vector" : + " convention=coordinate_frame"); proj_log_debug(P, "dx= %8.5f dy= %8.5f dz= %8.5f", Q->dxyz.x, Q->dxyz.y, Q->dxyz.z); proj_log_debug(P, "drx=%8.5f dry=%8.5f drz=%8.5f", Q->dopk.o, Q->dopk.p, Q->dopk.k); proj_log_debug(P, "ds= %8.5f t_epoch=%8.5f t_obs=%8.5f", Q->dscale, Q->t_epoch, Q->t_obs); } - if ((Q->opk.o==0) && (Q->opk.p==0) && (Q->opk.k==0) && (Q->scale==0) && - (Q->dopk.o==0) && (Q->dopk.p==0) && (Q->dopk.k==0)) { - Q->no_rotation = 1; + if (Q->no_rotation) { return P; } diff --git a/src/proj_4D_api.c b/src/proj_4D_api.c index a6a8dc274c..f0543893fc 100644 --- a/src/proj_4D_api.c +++ b/src/proj_4D_api.c @@ -503,7 +503,7 @@ Returns 1 on success, 0 on failure def = malloc (100+n); if (0==def) return 0; - sprintf (def, "break_cs2cs_recursion proj=helmert exact %s transpose", s); + sprintf (def, "break_cs2cs_recursion proj=helmert exact %s convention=position_vector", s); Q = proj_create (P->ctx, def); pj_inherit_ellipsoid_def (P, Q); free (def); diff --git a/test/gie/GDA.gie b/test/gie/GDA.gie index 3157eef61d..beec7c9cb6 100644 --- a/test/gie/GDA.gie +++ b/test/gie/GDA.gie @@ -26,6 +26,7 @@ GDA94 to GDA2020 Just the Helmert transformation, to verify that we are within 100 um ----------------------------------------------------------------------------------- operation proj=helmert + convention=coordinate_frame x = 0.06155 rx = -0.0394924 y = -0.01087 ry = -0.0327221 z = -0.04019 rz = -0.0328979 s = -0.009994 @@ -45,6 +46,7 @@ All the way from geographic-to-cartesian-and-back-to-geographic operation proj = pipeline ellps=GRS80; step proj = cart; step proj = helmert + convention=coordinate_frame x = 0.06155; rx = -0.0394924; y = -0.01087; ry = -0.0327221; z = -0.04019; rz = -0.0328979; s = -0.009994; @@ -61,7 +63,7 @@ ITRF2014@2018 to GDA2020 - Test point ALIC (Alice Springs) ----------------------------------------------------------------------------------- Just the Helmert transformation, to verify that we are within 100 um ----------------------------------------------------------------------------------- -operation proj = helmert exact +operation proj = helmert exact convention=coordinate_frame x = 0 rx = 0 dx = 0 drx = 0.00150379 y = 0 ry = 0 dy = 0 dry = 0.00118346 diff --git a/test/gie/more_builtins.gie b/test/gie/more_builtins.gie index 2908fd633e..d3771255e8 100644 --- a/test/gie/more_builtins.gie +++ b/test/gie/more_builtins.gie @@ -253,7 +253,7 @@ A number of tests from PJ_helmert.c This example is from Lotti Jivall: "Simplified transformations from ITRF2008/IGS08 to ETRS89 for maritime applications" ------------------------------------------------------------------------------- -operation proj=helmert +operation proj=helmert convention=coordinate_frame x=0.67678 y=0.65495 z=-0.52827 rx=-0.022742 ry=0.012667 rz=0.022704 s=-0.01070 ------------------------------------------------------------------------------- @@ -266,7 +266,7 @@ expect 3565285.41342351 855948.67986759 5201382.72939791 ------------------------------------------------------------------------------- This example is a random point, transformed from ED50 to ETRS89 using KMStrans2 ------------------------------------------------------------------------------- -operation proj=helmert exact +operation proj=helmert exact convention=coordinate_frame x=-081.0703 rx=-0.48488 y=-089.3603 ry=-0.02436 z=-115.7526 rz=-0.41321 s=-0.540645 @@ -284,7 +284,7 @@ Sweden transformed from ITRF2000 @ 2017.0 to ITRF93 @ 2017.0. The test coordinate was transformed using GNSStrans, using transformation parameters published by ITRF: ftp://itrf.ensg.ign.fr/pub/itrf/ITRF.TP ------------------------------------------------------------------------------- -operation proj=helmert transpose +operation proj=helmert convention=position_vector x = 0.0127 dx = -0.0029 rx = -0.00039 drx = -0.00011 y = 0.0065 dy = -0.0002 ry = 0.00080 dry = -0.00019 z = -0.0209 dz = -0.0006 rz = -0.00114 drz = 0.00007 @@ -306,7 +306,7 @@ The test data is taken from p. 29. Here we are using point 203 and converting it from NAD27 (ft) -> NAD83 (m). The paper reports a difference of 0.0014 m from measured to computed coordinates, hence the test tolerance is set accordingly. ------------------------------------------------------------------------------- -operation proj=helmert +operation proj=helmert convention=coordinate_frame x=-9597.3572 y=.6112 s=0.304794780637 theta=-1.244048 ------------------------------------------------------------------------------- @@ -322,7 +322,7 @@ rotation matrix is updated when necessary. Test coordinates from GNSStrans. ------------------------------------------------------------------------------- -operation proj=helmert transpose +operation proj=helmert convention=position_vector x = 0.01270 dx =-0.0029 rx =-0.00039 drx =-0.00011 y = 0.00650 dy =-0.0002 ry = 0.00080 dry =-0.00019 z =-0.0209 dz =-0.0006 rz =-0.00114 drz = 0.00007 @@ -336,6 +336,26 @@ accept 3370658.378 711877.314 5349787.086 2018.0 expect 3370658.18087 711877.42750 5349787.12648 2018.0 ------------------------------------------------------------------------------- +------------------------------------------------------------------------------- +Test error cases of helmert +------------------------------------------------------------------------------- +# A rotational term implies an explicit convention to be specified +operation proj=helmert rx=1 +expect failure errno missing_arg + +operation proj=helmert rx=1 convention=foo +expect failure errno invalid_arg + +operation proj=helmert rx=1 convention=1 +expect failure errno invalid_arg + +# towgs84 in helmert context should alwas be position_vector +operation proj=helmert towgs84=1,2,3,4,5,6,7 convention=coordinate_frame +expect failure errno invalid_arg + +# Transpose no longer accepted +operation proj=helmert transpose +expect failure errno invalid_arg -------------------------------------------------------------------------------