1 2# -*- coding: utf-8 -*- 3 4u'''I{Veness}' Terrestrial Reference Frames (TRF). 5 6Classes L{RefFrame}, registry L{RefFrames} and L{TRFError}. 7 8Transcoded from I{Chris Veness'} (C) 2006-2019 JavaScript originals 9U{latlon-ellipsoidal-referenceframe.js<https://GitHub.com/ChrisVeness/geodesy/blob/master/ 10latlon-ellipsoidal-referenceframe.js>} and U{latlon-ellipsoidal-referenceframe-txparams.js 11<https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe-txparams.js>}. 12 13Following is a copy of the comments in I{Veness}' U{latlon-ellipsoidal-referenceframe.js 14<https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe.js>}. 15 16Modern geodetic reference frames: a latitude/longitude point defines a geographic location on, 17above or below the earth’s surface, measured in degrees from the equator and the U{International 18Reference Meridian<https://WikiPedia.org/wiki/IERS_Reference_Meridian>} (IRM) and metres above 19the ellipsoid within a given I{Terrestrial Reference Frame} at a given I{epoch}. 20 21This is scratching the surface of complexities involved in high precision geodesy, but may 22be of interest and/or value to those with less demanding requirements. More information U{here 23<https://www.Movable-Type.co.UK/scripts/geodesy-library.html>} and U{here 24<https://www.Movable-Type.co.UK/scripts/geodesy-library.html#latlon-ellipsoidal-referenceframe>}. 25 26Note that I{ITRF solutions} do not directly use an ellipsoid, but are specified by Cartesian 27coordinates. The GRS80 ellipsoid is recommended for transformations to geographical coordinates. 28 29Note WGS84(G730/G873/G1150) are coincident with ITRF at 10-centimetre level, see also U{here 30<ftp://ITRF.ENSG.IGN.FR/pub/itrf/WGS84.TXT>}. WGS84(G1674) and ITRF20014 / ITRF2008 I{"are likely 31to agree at the centimeter level"}, see also U{QPS/Qinsy<https://Confluence.QPS.NL/qinsy/ 32en/how-to-deal-with-etrs89-datum-and-time-dependent-transformation-parameters-45353274.html>}. 33 34@var RefFrames.ETRF2000: RefFrame(name='ETRF2000', epoch=2005, ellipsoid=Ellipsoid(name='GRS80') 35@var RefFrames.GDA2020: RefFrame(name='GDA2020', epoch=2020, ellipsoid=Ellipsoid(name='GRS80') 36@var RefFrames.GDA94: RefFrame(name='GDA94', epoch=1994, ellipsoid=Ellipsoid(name='GRS80') 37@var RefFrames.ITRF2000: RefFrame(name='ITRF2000', epoch=1997, ellipsoid=Ellipsoid(name='GRS80') 38@var RefFrames.ITRF2005: RefFrame(name='ITRF2005', epoch=2000, ellipsoid=Ellipsoid(name='GRS80') 39@var RefFrames.ITRF2008: RefFrame(name='ITRF2008', epoch=2005, ellipsoid=Ellipsoid(name='GRS80') 40@var RefFrames.ITRF2014: RefFrame(name='ITRF2014', epoch=2010, ellipsoid=Ellipsoid(name='GRS80') 41@var RefFrames.ITRF91: RefFrame(name='ITRF91', epoch=1988, ellipsoid=Ellipsoid(name='GRS80') 42@var RefFrames.ITRF93: RefFrame(name='ITRF93', epoch=1988, ellipsoid=Ellipsoid(name='GRS80') 43@var RefFrames.NAD83: RefFrame(name='NAD83', epoch=1997, ellipsoid=Ellipsoid(name='GRS80') 44@var RefFrames.WGS84g1150: RefFrame(name='WGS84g1150', epoch=2001, ellipsoid=Ellipsoid(name='WGS84') 45@var RefFrames.WGS84g1674: RefFrame(name='WGS84g1674', epoch=2005, ellipsoid=Ellipsoid(name='WGS84') 46@var RefFrames.WGS84g1762: RefFrame(name='WGS84g1762', epoch=2005, ellipsoid=Ellipsoid(name='WGS84') 47''' 48 49from pygeodesy.basics import map1, _xinstanceof 50from pygeodesy.datums import _ellipsoid, Transform 51from pygeodesy.ellipsoids import Ellipsoids 52from pygeodesy.errors import TRFError 53from pygeodesy.interns import NN, _COMMASPACE_, _conversion_, _ellipsoid_, \ 54 _epoch_, _exists_, _float as _F, _GRS80_, _NAD83_, \ 55 _name_, _no_, _s_, _SPACE_, _sx_, _sy_, _sz_, \ 56 _to_, _tx_, _ty_, _tz_, _WGS84_, _0_0, _0_001, \ 57 _0_01, _0_1, _0_26, _0_5, _1_0 58from pygeodesy.lazily import _ALL_LAZY 59from pygeodesy.named import classname, _lazyNamedEnumItem as _lazy, \ 60 _NamedDict as _XD, _NamedEnum, _NamedEnumItem, \ 61 _NamedTuple 62from pygeodesy.props import Property_RO 63from pygeodesy.streprs import Fmt 64from pygeodesy.units import Epoch, Float 65 66from math import ceil 67 68__all__ = _ALL_LAZY.trf 69__version__ = '21.08.12' 70 71_0_02 = _F( 0.02) 72_0_06 = _F( 0.06) 73_0_09 = _F( 0.09) 74_366_0 = _F(366) 75_mDays = (0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0) 76 77_ETRF2000_ = 'ETRF2000' 78_GDA2020_ = 'GDA2020' 79_GDA94_ = 'GDA94' 80_ITRF_ = 'ITRF' 81_ITRF88_ = 'ITRF88' 82_ITRF89_ = 'ITRF89' 83_ITRF90_ = 'ITRF90' 84_ITRF91_ = 'ITRF91' 85_ITRF92_ = 'ITRF92' 86_ITRF93_ = 'ITRF93' 87_ITRF94_ = 'ITRF94' 88_ITRF96_ = 'ITRF96' 89_ITRF97_ = 'ITRF97' 90_ITRF2000_ = 'ITRF2000' 91_ITRF2005_ = 'ITRF2005' 92_ITRF2008_ = 'ITRF2008' 93_ITRF2014_ = 'ITRF2014' 94_WGS84g1150_ = 'WGS84g1150' 95_WGS84g1674_ = 'WGS84g1674' 96_WGS84g1762_ = 'WGS84g1762' 97 98 99class RefFrame(_NamedEnumItem): 100 '''Terrestrial Reference Frame (TRF) parameters. 101 ''' 102 _ellipsoid = None # ellipsoid GRS80 or WGS84 (L{Ellipsoid} or L{Ellipsoid2}) 103 _epoch = _0_0 # epoch, calendar year (L{Epoch} or C{float}) 104 105 def __init__(self, epoch, ellipsoid, name=NN): 106 '''New L{RefFrame}. 107 108 @arg epoch: Epoch, a fractional calendar year (C{scalar} or C{str}). 109 @arg ellipsoid: The ellipsoid (L{Ellipsoid}, L{Ellipsoid2}, 110 L{datum} or L{a_f2Tuple}). 111 @kwarg name: Optional, unique name (C{str}). 112 113 @raise NameError: A L{RefFrame} with that B{C{name}} 114 already exists. 115 116 @raise TRFError: Invalid B{C{epoch}}. 117 118 @raise TypeError: Invalid B{C{ellipsoid}}. 119 ''' 120 self._ellipsoid = _ellipsoid(ellipsoid, name=name) 121 self._epoch = Epoch(epoch) 122 self._register(RefFrames, name) 123 124 @Property_RO 125 def ellipsoid(self): 126 '''Get this reference frame's ellipsoid (L{Ellipsoid} or L{Ellipsoid2}). 127 ''' 128 return self._ellipsoid 129 130 @Property_RO 131 def epoch(self): 132 '''Get this reference frame's epoch (C{Epoch}). 133 ''' 134 return self._epoch 135 136 def toStr(self, **unused): # PYCHOK expected 137 '''Return this reference frame as a text string. 138 139 @return: This L{RefFrame}'s attributes (C{str}). 140 ''' 141 e = self.ellipsoid 142 t = (Fmt.EQUAL(_name_, repr(self.name)), 143 Fmt.EQUAL(_epoch_, self.epoch), 144 Fmt.PAREN(Fmt.EQUAL(_ellipsoid_, classname(e)), 145 Fmt.EQUAL(_name_, repr(e.name)))) 146 return _COMMASPACE_.join(t) 147 148 149class RefFrames(_NamedEnum): 150 '''(INTERNAL) L{RefFrame} registry, I{must} be a sub-class 151 to accommodate the L{_LazyNamedEnumItem} properties. 152 ''' 153 def _Lazy(self, epoch, ellipsoid_name, name=NN): 154 '''(INTERNAL) Instantiate the L{RefFrame}. 155 ''' 156 return RefFrame(epoch, Ellipsoids.get(ellipsoid_name), name=name) 157 158RefFrames = RefFrames(RefFrame) # PYCHOK singleton 159'''Some pre-defined L{RefFrame}s, all I{lazily} instantiated.''' 160# <https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe.js> 161RefFrames._assert( 162 ETRF2000 = _lazy(_ETRF2000_, _F(2005), _GRS80_), # ETRF2000(R08) 163 GDA2020 = _lazy(_GDA2020_, _F(2020), _GRS80_), # Australia 164 GDA94 = _lazy(_GDA94_, _F(1994), _GRS80_), # Australia 165 ITRF2000 = _lazy(_ITRF2000_, _F(1997), _GRS80_), 166 ITRF2005 = _lazy(_ITRF2005_, _F(2000), _GRS80_), 167 ITRF2008 = _lazy(_ITRF2008_, _F(2005), _GRS80_), # aks ITRF08 168 ITRF2014 = _lazy(_ITRF2014_, _F(2010), _GRS80_), 169 ITRF91 = _lazy(_ITRF91_, _F(1988), _GRS80_), 170 ITRF93 = _lazy(_ITRF93_, _F(1988), _GRS80_), 171 NAD83 = _lazy(_NAD83_, _F(1997), _GRS80_), # CORS96 172 WGS84g1150 = _lazy(_WGS84g1150_, _F(2001), _WGS84_), 173 WGS84g1674 = _lazy(_WGS84g1674_, _F(2005), _WGS84_), 174 WGS84g1762 = _lazy(_WGS84g1762_, _F(2005), _WGS84_)) # same epoch 175 176 177def date2epoch(year, month, day): 178 '''Return the reference frame C{epoch} for a calendar day. 179 180 @arg year: Year of the date (C{scalar}). 181 @arg month: Month in the B{C{year}} (C{scalar}, 1..12). 182 @arg day: Day in the B{C{month}} (C{scalar}, 1..31). 183 184 @return: Epoch, the fractional year (C{float}). 185 186 @raise TRFError: Invalid B{C{year}}, B{C{month}} or B{C{day}}. 187 188 @note: Any B{C{year}} is considered a leap year, i.e. having 189 29 days in February. 190 ''' 191 try: 192 y, m, d = map1(int, year, month, day) 193 if y > 0 and 1 <= m <= 12 and 1 <= d <= _mDays[m]: 194 return Epoch(y + float(sum(_mDays[:m]) + d) / _366_0, low=0) 195 196 t = NN # _invalid_ 197 except (TRFError, TypeError, ValueError) as x: 198 t = str(x) 199 raise TRFError(year=year, month=month, day=day, txt=t) 200 201 202def epoch2date(epoch): 203 '''Return the date for a reference frame C{epoch}. 204 205 @arg epoch: Fractional year (C{scalar}). 206 207 @return: 3-Tuple C{(year, month, day)}. 208 209 @raise TRFError: Invalid B{C{epoch}}. 210 211 @note: Any B{C{year}} is considered a leap year, i.e. having 212 29 days in February. 213 ''' 214 e = Epoch(epoch, Error=TRFError, low=0) 215 y = int(e) 216 d = int(ceil(_366_0 * (e - y))) 217 for m, n in enumerate(_mDays[1:]): 218 if d > n: 219 d -= n 220 else: 221 break 222 return y, (m + 1), max(1, d) 223 224 225_mas = _mm = _ppb = Float # as == arcseconds 226_Forward = _0_001 # mm2m, ppb2ppM, mas2as 227_Inverse = -_0_001 # same, inverse transforms 228 229 230def _intermediate(n1, n2): 231 '''(INTERNAL) Find a trf* "in between" C{n1} and C{n2}. 232 ''' 233 f1 = set(m for n, m in _trfXs.keys() if n == n1) # from trf1 234 t2 = set(n for n, m in _trfXs.keys() if m == n2) # to trf2 235 n = f1.intersection(t2) 236 return n.pop() if n else NN 237 238 239def _reframeTransforms2(rf2, rf, epoch): 240 '''(INTERNAL) Get 0, 1 or 2 Helmert L{Transform}s to convert 241 reference frame B{C{rf}} observed at B{C{epoch}} into B{C{rf2}}. 242 ''' 243 e = rf.epoch if epoch is None else Epoch(epoch) 244 245 n2 = rf2.name # .upper() 246 n1 = rf.name # .upper() 247 if n1 == n2 or (n1.startswith(_ITRF_) and n2.startswith(_WGS84_)) \ 248 or (n2.startswith(_ITRF_) and n1.startswith(_WGS84_)): 249 return e, () # PYCHOK returns 250 251 if (n1, n2) in _trfXs: 252 return e, (_2Transform((n1, n2), e, _Forward),) # PYCHOK returns 253 254 if (n2, n1) in _trfXs: 255 return e, (_2Transform((n2, n1), e, _Inverse),) # PYCHOK returns 256 257 n = _intermediate(n1, n2) 258 if n: 259 return e, (_2Transform((n1, n), e, _Forward), # PYCHOK returns 260 _2Transform((n, n2), e, _Forward)) 261 262 n = _intermediate(n2, n1) 263 if n: 264 return e, (_2Transform((n, n1), e, _Inverse), # PYCHOK returns 265 _2Transform((n2, n), e, _Inverse)) 266 267 t = _SPACE_(RefFrame.__name__, repr(n1), _to_, repr(n2)) 268 raise TRFError(_no_(_conversion_), txt=t) 269 270 271def _2Transform(n1_n2, epoch, _Forward_Inverse): 272 '''(INTERNAL) Combine the dual Helmert transforms from TRF 273 conversion C{_trfXs[n1_n2]} into a into a single Helmert 274 L{Transform} observed at B{C{epoch}}. 275 276 @note: Translations in C{millimeter} are converted to 277 C{meter} and rotations in C{milliarcseconds} to 278 C{arcseconds}. 279 ''' 280 X = _trfXs[n1_n2] 281 e = epoch - X.epoch # fractional delta years 282 d = dict((n, (x + r * e) * _Forward_Inverse) for 283 n, x, r in zip(Transform7Tuple._Names_, X.xform, X.rates)) 284 return Transform(**d) 285 286 287class Transform7Tuple(_NamedTuple): 288 '''7-Tuple C{(tx, ty, tz, s, sx, sy, sz)} Helmert transformation 289 with translations C{tx}, C{ty} and C{tz} in C{millimeter}, 290 scale C{s} in C{ppb} and rotations C{sx}, C{sy} and C{sz} in 291 C{milliarcseconds}. 292 293 @see: L{Transform}. 294 ''' 295 _Names_ = (_tx_, _ty_, _tz_, _s_, _sx_, _sy_, _sz_) 296 _Units_ = (_mm, _mm, _mm, _ppb, _mas, _mas, _mas) 297 298 def __new__(cls, tx=_0_0, ty=_0_0, tz=_0_0, s=_0_0, 299 sx=_0_0, sy=_0_0, sz=_0_0, name=NN): 300 '''New L{Transform7Tuple}. 301 302 @kwarg tx: Optional X translation (C{millimeter}). 303 @kwarg ty: Optional Y translation (C{millimeter}). 304 @kwarg tz: Optional Z translation (C{millimeter}). 305 @kwarg s: Optional scale (C{float}), ppb. 306 @kwarg sx: Optional X rotation (C{milliarcseconds}). 307 @kwarg sy: Optional Y rotation (C{milliarcseconds}). 308 @kwarg sz: Optional Z rotation (C{milliarcseconds}). 309 @kwarg name: Optional name (C{str}). 310 ''' 311 t = map1(_F, tx, ty, tz, s, sx, sy, sz) 312 return _NamedTuple.__new__(cls, *t, name=name) 313 314 315def trfXform(reframe1, reframe2, epoch=None, xform=None, rates=None): 316 '''Define a new Terrestrial Reference Frame (TRF) conversion. 317 318 @arg reframe1: Source reframe (L{RefFrame}), converting I{from}. 319 @arg reframe2: Destination reframe (L{RefFrame}), converting I{to}. 320 @kwarg epoch: Epoch, a fractional calendar year (C{scalar} or C{str}) 321 or C{None} for C{B{reframe2}.epoch}. 322 @kwarg xform: Helmert transform (C{Tranform7Tuple}). 323 @kwarg rates: Helmert transform (C{Tranform7Tuple}). 324 325 @raise TRFError: Invalid B{C{epoch}} or TRF conversion already exists. 326 ''' 327 _xinstanceof(RefFrame, reframe1=reframe1, reframe2=reframe2) 328 e = reframe2.epoch if epoch is None else Epoch(epoch=epoch, Error=TRFError) 329 _xinstanceof(Transform7Tuple, xform=xform, rates=rates) 330 _trfX(reframe1.name, reframe2.name, epoch=e, xform=xform, rates=rates) 331 332 333def _trfX(n1, n2, **epoch_xform_rates): 334 '''(INTERNAL) New C{_trfXs} entry. 335 ''' 336 n1_n2 = n1, n2 337 if n1_n2 in _trfXs: 338 raise TRFError(trfX=n1_n2, txt=_exists_) # _NameError 339 _trfXs[n1_n2] = _XD(X=n1_n2, **epoch_xform_rates) 340 341 342_T = Transform7Tuple 343# TRF conversions specified as an epoch and dual 7-parameter Helmert transforms. Most 344# from U{Transformation Parameters<http://ITRF.IGN.FR/trans_para.php>}, more at U{QPS 345# <https://Confluence.QPS.NL/qinsy/files/en/29856813/45482834/2/1453459502000/ITRF_Transformation_Parameters.xlsx>}. 346_trfXs = dict() # key is [(from_TRF, to_TRF)] 2-tuple 347# see U{Transformation Parameters ITRF2014<http://ITRF.IGN.FR/doc_ITRF/Transfo-ITRF2014_ITRFs.txt>} 348_trfX(_ITRF2014_, _ITRF2008_, epoch=_F(2010), # <http://ITRF.ENSG.IGN.FR/ITRF_solutions/2014/tp_14-08.php> 349 xform=_T( 1.6, 1.9, 2.4, -0.02, _0_0, _0_0, _0_0), 350 rates=_T( _0_0, _0_0, -_0_1, 0.03, _0_0, _0_0, _0_0)) 351_trfX(_ITRF2014_, _ITRF2005_, epoch=_F(2010), 352 xform=_T( 2.6, _1_0, -2.3, 0.92, _0_0, _0_0, _0_0), 353 rates=_T( 0.3, _0_0, -_0_1, 0.03, _0_0, _0_0, _0_0)) 354_trfX(_ITRF2014_, _ITRF2000_, epoch=_F(2010), 355 xform=_T( 0.7, 1.2, -26.1, 2.12, _0_0, _0_0, _0_0), 356 rates=_T( _0_1, _0_1, -1.9, 0.11, _0_0, _0_0, _0_0)) 357_trfX(_ITRF2014_, _ITRF97_, epoch=_F(2010), 358 xform=_T( 7.4, -_0_5, -62.8, 3.8, _0_0, _0_0, _0_26), 359 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 360_trfX(_ITRF2014_, _ITRF96_, epoch=_F(2010), 361 xform=_T( 7.4, -_0_5, -62.8, 3.8, _0_0, _0_0, _0_26), 362 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 363_trfX(_ITRF2014_, _ITRF94_, epoch=_F(2010), 364 xform=_T( 7.4, -_0_5, -62.8, 3.8, _0_0, _0_0, _0_26), 365 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 366_trfX(_ITRF2014_, _ITRF93_, epoch=_F(2010), 367 xform=_T(-50.4, 3.3, -60.2, 4.29, -2.81, -3.38, 0.4), 368 rates=_T( -2.8, -_0_1, -2.5, 0.12, -0.11, -0.19, 0.07)) 369_trfX(_ITRF2014_, _ITRF92_, epoch=_F(2010), 370 xform=_T( 15.4, 1.5, -70.8, 3.09, _0_0, _0_0, _0_26), 371 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 372_trfX(_ITRF2014_, _ITRF91_, epoch=_F(2010), 373 xform=_T( 27.4, 15.5, -76.8, 4.49, _0_0, _0_0, _0_26), 374 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 375_trfX(_ITRF2014_, _ITRF90_, epoch=_F(2010), 376 xform=_T( 25.4, 11.5, -92.8, 4.79, _0_0, _0_0, _0_26), 377 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 378_trfX(_ITRF2014_, _ITRF89_, epoch=_F(2010), 379 xform=_T( 30.4, 35.5, -130.8, 8.19, _0_0, _0_0, _0_26), 380 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 381_trfX(_ITRF2014_, _ITRF88_, epoch=_F(2010), 382 xform=_T( 25.4, -_0_5, -154.8, 11.29, _0_1, _0_0, _0_26), 383 rates=_T( _0_1, -_0_5, -3.3, 0.12, _0_0, _0_0, _0_02)) 384 385# see U{Transformation Parameters ITRF2008<http://ITRF.IGN.FR/doc_ITRF/Transfo-ITRF2008_ITRFs.txt>} 386# _trfX(_ITRF2008_, _ITRF2005_, epoch=_F(2005), # <http://ITRF.ENSG.IGN.FR/ITRF_solutions/2008/tp_08-05.php> 387# xform=_T(-_0_5, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0), 388# rates=_T( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0)) 389_trfX(_ITRF2008_, _ITRF2005_, epoch=_F(2000), 390 xform=_T( -2.0, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0), 391 rates=_T( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0)) 392_trfX(_ITRF2008_, _ITRF2000_, epoch=_F(2000), 393 xform=_T( -1.9, -1.7, -10.5, 1.34, _0_0, _0_0, _0_0), 394 rates=_T( _0_1, _0_1, -1.8, 0.08, _0_0, _0_0, _0_0)) 395_trfX(_ITRF2008_, _ITRF97_, epoch=_F(2000), 396 xform=_T( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, _0_06), 397 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 398_trfX(_ITRF2008_, _ITRF96_, epoch=_F(2000), 399 xform=_T( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, _0_06), 400 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 401_trfX(_ITRF2008_, _ITRF94_, epoch=_F(2000), 402 xform=_T( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, _0_06), 403 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 404_trfX(_ITRF2008_, _ITRF93_, epoch=_F(2000), 405 xform=_T(-24.0, 2.4, -38.6, 3.41, -1.71, -1.48, -0.3), 406 rates=_T( -2.8, -_0_1, -2.4, _0_09, -0.11, -0.19, 0.07)) 407_trfX(_ITRF2008_, _ITRF92_, epoch=_F(2000), 408 xform=_T( 12.8, 4.6, -41.2, 2.21, _0_0, _0_0, _0_06), 409 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 410_trfX(_ITRF2008_, _ITRF91_, epoch=_F(2000), 411 xform=_T( 24.8, 18.6, -47.2, 3.61, _0_0, _0_0, _0_06), 412 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 413_trfX(_ITRF2008_, _ITRF90_, epoch=_F(2000), 414 xform=_T( 22.8, 14.6, -63.2, 3.91, _0_0, _0_0, _0_06), 415 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 416_trfX(_ITRF2008_, _ITRF89_, epoch=_F(2000), 417 xform=_T( 27.8, 38.6, -101.2, 7.31, _0_0, _0_0, _0_06), 418 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 419_trfX(_ITRF2008_, _ITRF88_, epoch=_F(2000), 420 xform=_T( 22.8, 2.6, -125.2, 10.41, _0_1, _0_0, _0_06), 421 rates=_T( _0_1, -_0_5, -3.2, _0_09, _0_0, _0_0, _0_02)) 422 423_trfX(_ITRF2005_, _ITRF2000_, epoch=_F(2000), # <http://ITRF.ENSG.IGN.FR/ITRF_solutions/2005/tp_05-00.php> 424 xform=_T( _0_1, -0.8, -5.8, 0.4, _0_0, _0_0, _0_0), 425 rates=_T( -0.2, _0_1, -1.8, 0.08, _0_0, _0_0, _0_0)) 426 427_trfX(_ITRF2000_, _ITRF97_, epoch=_F(1997), 428 xform=_T( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0), 429 rates=_T(_0_0, -0.06, -0.14, _0_01, _0_0, _0_0, _0_02)) 430_trfX(_ITRF2000_, _ITRF96_, epoch=_F(1997), 431 xform=_T( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0), 432 rates=_T(_0_0, -0.06, -0.14, _0_01, _0_0, _0_0, _0_02)) 433_trfX(_ITRF2000_, _ITRF94_, epoch=_F(1997), 434 xform=_T( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0), 435 rates=_T(_0_0, -0.06, -0.14, _0_01, _0_0, _0_0, _0_02)) 436_trfX(_ITRF2000_, _ITRF93_, epoch=_F(1988), 437 xform=_T( 12.7, 6.5, -20.9, 1.95, -0.39, 0.8, -1.14), 438 rates=_T( -2.9, -0.2, -0.6, _0_01, -0.11, -0.19, 0.07)) 439_trfX(_ITRF2000_, _ITRF92_, epoch=_F(1988), 440 xform=_T( 1.47, 1.35, -1.39, 0.75, _0_0, _0_0, -0.18), 441 rates=_T(_0_0, -0.06, -0.14, _0_01, _0_0, _0_0, _0_02)) 442_trfX(_ITRF2000_, _ITRF91_, epoch=_F(1988), 443 xform=_T( 26.7, 27.5, -19.9, 2.15, _0_0, _0_0, -0.18), 444 rates=_T( _0_0, -0.6, -1.4, _0_01, _0_0, _0_0, _0_02)) 445_trfX(_ITRF2000_, _ITRF90_, epoch=_F(1988), 446 xform=_T( 2.47, 2.35, -3.59, 2.45, _0_0, _0_0, -0.18), 447 rates=_T(_0_0, -0.06, -0.14, _0_01, _0_0, _0_0, _0_02)) 448_trfX(_ITRF2000_, _ITRF89_, epoch=_F(1988), 449 xform=_T( 2.97, 4.75, -7.39, 5.85, _0_0, _0_0, -0.18), 450 rates=_T(_0_0, -0.06, -0.14, _0_01, _0_0, _0_0, _0_02)) 451_trfX(_ITRF2000_, _ITRF88_, epoch=_F(1988), 452 xform=_T( 2.47, 1.15, -9.79, 8.95, _0_1, _0_0, -0.18), 453 rates=_T(_0_0, -0.06, -0.14, _0_01, _0_0, _0_0, _0_02)) 454 455# see U{Boucher, C. & Altamimi, Z. "Memo: Specifications for reference frame fixing in the 456# analysis of a EUREF GPS campaign" (2011) <https://ETRS89.ENSG.IGN.FR/memo-V8.pdf>} and 457# Altamimi, Z. U{"Key results of ITRF2014 and implication to ETRS89 realization", EUREF2016 458# <https://www.EUREF.EU/symposia/2016SanSebastian/01-02-Altamimi.pdf>}. 459_trfX(_ITRF2014_, _ETRF2000_, epoch=_F(2000), 460 xform=_T( 53.7, 51.2, -55.1, 1.02, 0.891, 5.39, -8.712), 461 rates=_T( _0_1, _0_1, -1.9, 0.11, 0.081, 0.49, -0.792)) 462_trfX(_ITRF2008_, _ETRF2000_, epoch=_F(2000), 463 xform=_T( 52.1, 49.3, -58.5, 1.34, 0.891, 5.39, -8.712), 464 rates=_T( _0_1, _0_1, -1.8, 0.08, 0.081, 0.49, -0.792)) 465_trfX(_ITRF2005_, _ETRF2000_, epoch=_F(2000), 466 xform=_T( 54.1, 50.2, -53.8, 0.4, 0.891, 5.39, -8.712), 467 rates=_T( -0.2, _0_1, -1.8, 0.08, 0.081, 0.49, -0.792)) 468_trfX(_ITRF2000_, _ETRF2000_, epoch=_F(2000), 469 xform=_T( 54.0, 51.0, -48.0, _0_0, 0.891, 5.39, -8.712), 470 rates=_T( _0_0, _0_0, _0_0, _0_0, 0.081, 0.49, -0.792)) 471 472# see U{Solar, T. & Snay, R.A. "Transforming Positions and Velocities between the 473# International Terrestrial Reference Frame of 2000 and North American Datum of 1983" 474# (2004)<https://www.NGS.NOAA.gov/CORS/Articles/SolerSnayASCE.pdf>} 475_trfX(_ITRF2000_, _NAD83_, epoch=_F(1997), # note NAD83(CORS96) 476 xform=_T(995.6, -1901.3, -521.5, 0.62, 25.915, 9.426, 11.599), 477 rates=_T( 0.7, -0.7, _0_5, -0.18, 0.067, -0.757, -0.051)) 478 479# GDA2020 "Geocentric Datum of Australia 2020 Technical Manual", v1.5, 2020-12-09, Table 3.3 and 3.4 480# <https://www.ICSM.gov.AU/sites/default/files/2020-12/GDA2020%20Technical%20Manual%20V1.5_4.pdf> 481# (the GDA2020 xforms are different but the rates are the same as GDA94, further below) 482_trfX(_ITRF2014_, _GDA2020_, epoch=_F(2020), 483 xform=_T( _0_0, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0), 484 rates=_T( _0_0, _0_0, _0_0, _0_0, 1.50379, 1.18346, 1.20716)) 485_trfX(_ITRF2008_, _GDA2020_, epoch=_F(2020), 486 xform=_T( 13.79, 4.55, 15.22, 2.5, 0.2808, 0.2677, -0.4638), 487 rates=_T( 1.42, 1.34, 0.9, 0.109, 1.5461, 1.182, 1.1551)) 488_trfX(_ITRF2005_, _GDA2020_, epoch=_F(2020), 489 xform=_T( 40.32, -33.85, -16.72, 4.286, -1.2893, -0.8492, -0.3342), 490 rates=_T( 2.25, -0.62, -0.56, 0.294, -1.4707, -1.1443, -1.1701)) 491_trfX(_ITRF2000_, _GDA2020_, epoch=_F(2020), 492 xform=_T(-105.52, 51.58, 231.68, 3.55, 4.2175, 6.3941, 0.8617), 493 rates=_T( -4.66, 3.55, 11.24, 0.249, 1.7454, 1.4868, 1.224)) 494 495# see Table 2 in U{Dawson, J. & Woods, A. "ITRF to GDA94 coordinate transformations", Journal of Applied 496# Geodesy 4 (2010), 189-199<https://www.ResearchGate.net/publication/258401581_ITRF_to_GDA94_coordinate_transformations>} 497# (note, sign of rotations for GDA94 reversed as "Australia assumes rotation to be of coordinate axes", 498# rather than the more conventional "position around the coordinate axes") 499_trfX(_ITRF2008_, _GDA94_, epoch=_F(1994), 500 xform=_T(-84.68, -19.42, 32.01, 9.71, -0.4254, 2.2578, 2.4015), 501 rates=_T( 1.42, 1.34, 0.9, 0.109, 1.5461, 1.182, 1.1551)) 502_trfX(_ITRF2005_, _GDA94_, epoch=_F(1994), 503 xform=_T(-79.73, -6.86, 38.03, 6.636, 0.0351, -2.1211, -2.1411), 504 rates=_T( 2.25, -0.62, -0.56, 0.294, -1.4707, -1.1443, -1.1701)) 505_trfX(_ITRF2000_, _GDA94_, epoch=_F(1994), 506 xform=_T(-45.91, -29.85, -20.37, 7.07, -1.6705, 0.4594, 1.9356), 507 rates=_T( -4.66, 3.55, 11.24, 0.249, 1.7454, 1.4868, 1.224)) 508del _T 509 510if __name__ == '__main__': 511 512 from pygeodesy.interns import _COMMA_, _NL_, _NL_var_, _STAR_ 513 514 D = date2epoch.__name__ 515 E = epoch2date.__name__ 516 y = 2021 517 for m in range(1, 13): 518 for d in (1, _mDays[m] - 1, _mDays[m]): 519 f = '%s(%d,%3d,%3d)' % (D, y, m, d) 520 e = date2epoch(y, m, d) 521 t = epoch2date(e) 522 x = NN if t == (y, m, d) else _STAR_ 523 e = '%.3f' % (e,) 524 e = '%s, %s(%s)' % (e, E, e) 525 t = '%d,%3d,%3d' % t 526 print('# %s = %s = %s %s' % (f, e, t, x)) 527 528 # __doc__ of this file, force all into registery 529 t = [NN] + RefFrames.toRepr(all=True).split(_NL_) 530 print(_NL_var_.join(i.strip(_COMMA_) for i in t)) 531 532# **) MIT License 533# 534# Copyright (C) 2016-2021 -- mrJean1 at Gmail -- All Rights Reserved. 535# 536# Permission is hereby granted, free of charge, to any person obtaining a 537# copy of this software and associated documentation files (the "Software"), 538# to deal in the Software without restriction, including without limitation 539# the rights to use, copy, modify, merge, publish, distribute, sublicense, 540# and/or sell copies of the Software, and to permit persons to whom the 541# Software is furnished to do so, subject to the following conditions: 542# 543# The above copyright notice and this permission notice shall be included 544# in all copies or substantial portions of the Software. 545# 546# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 547# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 548# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 549# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 550# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 551# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 552# OTHER DEALINGS IN THE SOFTWARE. 553 554# % python -m pygeodesy.trf 555# 556# date2epoch(2021, 1, 1) = 2021.003, epoch2date(2021.003) = 2021, 1, 1 557# date2epoch(2021, 1, 30) = 2021.082, epoch2date(2021.082) = 2021, 1, 30 558# date2epoch(2021, 1, 31) = 2021.085, epoch2date(2021.085) = 2021, 1, 31 559# date2epoch(2021, 2, 1) = 2021.087, epoch2date(2021.087) = 2021, 2, 2 * 560# date2epoch(2021, 2, 28) = 2021.161, epoch2date(2021.161) = 2021, 2, 28 561# date2epoch(2021, 2, 29) = 2021.164, epoch2date(2021.164) = 2021, 3, 1 * 562# date2epoch(2021, 3, 1) = 2021.167, epoch2date(2021.167) = 2021, 3, 2 * 563# date2epoch(2021, 3, 30) = 2021.246, epoch2date(2021.246) = 2021, 3, 31 * 564# date2epoch(2021, 3, 31) = 2021.249, epoch2date(2021.249) = 2021, 4, 1 * 565# date2epoch(2021, 4, 1) = 2021.251, epoch2date(2021.251) = 2021, 4, 1 566# date2epoch(2021, 4, 29) = 2021.328, epoch2date(2021.328) = 2021, 4, 29 567# date2epoch(2021, 4, 30) = 2021.331, epoch2date(2021.331) = 2021, 4, 30 568# date2epoch(2021, 5, 1) = 2021.333, epoch2date(2021.333) = 2021, 5, 1 569# date2epoch(2021, 5, 30) = 2021.413, epoch2date(2021.413) = 2021, 5, 30 570# date2epoch(2021, 5, 31) = 2021.415, epoch2date(2021.415) = 2021, 6, 1 * 571# date2epoch(2021, 6, 1) = 2021.418, epoch2date(2021.418) = 2021, 6, 2 * 572# date2epoch(2021, 6, 29) = 2021.495, epoch2date(2021.495) = 2021, 6, 30 * 573# date2epoch(2021, 6, 30) = 2021.497, epoch2date(2021.497) = 2021, 7, 1 * 574# date2epoch(2021, 7, 1) = 2021.500, epoch2date(2021.500) = 2021, 7, 1 575# date2epoch(2021, 7, 30) = 2021.579, epoch2date(2021.579) = 2021, 7, 30 576# date2epoch(2021, 7, 31) = 2021.582, epoch2date(2021.582) = 2021, 7, 31 577# date2epoch(2021, 8, 1) = 2021.585, epoch2date(2021.585) = 2021, 8, 1 578# date2epoch(2021, 8, 30) = 2021.664, epoch2date(2021.664) = 2021, 8, 31 * 579# date2epoch(2021, 8, 31) = 2021.667, epoch2date(2021.667) = 2021, 9, 1 * 580# date2epoch(2021, 9, 1) = 2021.669, epoch2date(2021.669) = 2021, 9, 2 * 581# date2epoch(2021, 9, 29) = 2021.746, epoch2date(2021.746) = 2021, 9, 30 * 582# date2epoch(2021, 9, 30) = 2021.749, epoch2date(2021.749) = 2021, 10, 1 * 583# date2epoch(2021, 10, 1) = 2021.751, epoch2date(2021.751) = 2021, 10, 1 584# date2epoch(2021, 10, 30) = 2021.831, epoch2date(2021.831) = 2021, 10, 30 585# date2epoch(2021, 10, 31) = 2021.833, epoch2date(2021.833) = 2021, 10, 31 586# date2epoch(2021, 11, 1) = 2021.836, epoch2date(2021.836) = 2021, 11, 1 587# date2epoch(2021, 11, 29) = 2021.913, epoch2date(2021.913) = 2021, 11, 29 588# date2epoch(2021, 11, 30) = 2021.915, epoch2date(2021.915) = 2021, 12, 1 * 589# date2epoch(2021, 12, 1) = 2021.918, epoch2date(2021.918) = 2021, 12, 2 * 590# date2epoch(2021, 12, 30) = 2021.997, epoch2date(2021.997) = 2021, 12, 31 * 591# date2epoch(2021, 12, 31) = 2022.000, epoch2date(2022.000) = 2022, 1, 1 * 592