Coverage for pygeodesy/trf.py: 95%

616 statements  

« prev     ^ index     » next       coverage.py v7.2.2, created at 2024-03-08 13:06 -0500

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-2022 JavaScript originals U{latlon-ellipsoidal-referenceframe.js 

9<https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe.js>} and 

10U{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, datum=Datums.GRS80) .Xforms=(0, -14) 

35@var RefFrames.ETRF2005: RefFrame(name='ETRF2005', epoch=2005, datum=Datums.GRS80) .Xforms=(0, -1) 

36@var RefFrames.ETRF2008: RefFrame(name='ETRF2008', epoch=2008, datum=Datums.GRS80) .Xforms=(0, 0) 

37@var RefFrames.ETRF2014: RefFrame(name='ETRF2014', epoch=2014, datum=Datums.GRS80) .Xforms=(0, -14) 

38@var RefFrames.ETRF2020: RefFrame(name='ETRF2020', epoch=2020, datum=Datums.GRS80) .Xforms=(0, -14) 

39@var RefFrames.ETRF88: RefFrame(name='ETRF88', epoch=1988, datum=Datums.GRS80) .Xforms=(0, 0) 

40@var RefFrames.ETRF89: RefFrame(name='ETRF89', epoch=1989, datum=Datums.GRS80) .Xforms=(0, -1) 

41@var RefFrames.ETRF90: RefFrame(name='ETRF90', epoch=1990, datum=Datums.GRS80) .Xforms=(0, -1) 

42@var RefFrames.ETRF91: RefFrame(name='ETRF91', epoch=1991, datum=Datums.GRS80) .Xforms=(0, -1) 

43@var RefFrames.ETRF92: RefFrame(name='ETRF92', epoch=1992, datum=Datums.GRS80) .Xforms=(0, -1) 

44@var RefFrames.ETRF93: RefFrame(name='ETRF93', epoch=1993, datum=Datums.GRS80) .Xforms=(0, -1) 

45@var RefFrames.ETRF94: RefFrame(name='ETRF94', epoch=1994, datum=Datums.GRS80) .Xforms=(0, -1) 

46@var RefFrames.ETRF96: RefFrame(name='ETRF96', epoch=1996, datum=Datums.GRS80) .Xforms=(0, -1) 

47@var RefFrames.ETRF97: RefFrame(name='ETRF97', epoch=1997, datum=Datums.GRS80) .Xforms=(0, -1) 

48@var RefFrames.GDA2020: RefFrame(name='GDA2020', epoch=2020, datum=Datums.GRS80) .Xforms=(0, -4) 

49@var RefFrames.GDA94: RefFrame(name='GDA94', epoch=1994, datum=Datums.GRS80) .Xforms=(0, -3) 

50@var RefFrames.ITRF2000: RefFrame(name='ITRF2000', epoch=1997, datum=Datums.GRS80) .Xforms=(15, -5) 

51@var RefFrames.ITRF2005: RefFrame(name='ITRF2005', epoch=2000, datum=Datums.GRS80) .Xforms=(8, -3) 

52@var RefFrames.ITRF2008: RefFrame(name='ITRF2008', epoch=2005, datum=Datums.GRS80) .Xforms=(17, -2) 

53@var RefFrames.ITRF2014: RefFrame(name='ITRF2014', epoch=2010, datum=Datums.GRS80) .Xforms=(16, -1) 

54@var RefFrames.ITRF2020: RefFrame(name='ITRF2020', epoch=2015, datum=Datums.GRS80) .Xforms=(16, 0) 

55@var RefFrames.ITRF88: RefFrame(name='ITRF88', epoch=1988, datum=Datums.GRS80) .Xforms=(3, -4) 

56@var RefFrames.ITRF89: RefFrame(name='ITRF89', epoch=1989, datum=Datums.GRS80) .Xforms=(4, -4) 

57@var RefFrames.ITRF90: RefFrame(name='ITRF90', epoch=1988, datum=Datums.GRS80) .Xforms=(6, -4) 

58@var RefFrames.ITRF91: RefFrame(name='ITRF91', epoch=1988, datum=Datums.GRS80) .Xforms=(4, -4) 

59@var RefFrames.ITRF92: RefFrame(name='ITRF92', epoch=1988, datum=Datums.GRS80) .Xforms=(4, -4) 

60@var RefFrames.ITRF93: RefFrame(name='ITRF93', epoch=1988, datum=Datums.GRS80) .Xforms=(4, -4) 

61@var RefFrames.ITRF94: RefFrame(name='ITRF94', epoch=1993, datum=Datums.GRS80) .Xforms=(4, -4) 

62@var RefFrames.ITRF96: RefFrame(name='ITRF96', epoch=1997, datum=Datums.GRS80) .Xforms=(5, -5) 

63@var RefFrames.ITRF97: RefFrame(name='ITRF97', epoch=1997, datum=Datums.GRS80) .Xforms=(5, -4) 

64@var RefFrames.NAD83: RefFrame(name='NAD83', epoch=1997, datum=Datums.GRS80) .Xforms=(0, -6) 

65@var RefFrames.NAD83cors96: RefFrame(name='NAD83cors96', epoch=1997, datum=Datums.GRS80) .Xforms=(1, 0) 

66@var RefFrames.WGS84: RefFrame(name='WGS84', epoch=1984, datum=Datums.GRS80) .Xforms=(0, -1) 

67@var RefFrames.WGS84g1150: RefFrame(name='WGS84g1150', epoch=2001, datum=Datums.GRS80) .Xforms=(1, 0) 

68@var RefFrames.WGS84g1674: RefFrame(name='WGS84g1674', epoch=2005, datum=Datums.GRS80) .Xforms=(0, 0) 

69@var RefFrames.WGS84g1762: RefFrame(name='WGS84g1762', epoch=2005, datum=Datums.GRS80) .Xforms=(0, 0) 

70''' 

71 

72from pygeodesy.basics import map1, neg, isidentifier, isstr, _xinstanceof, _xisscalar 

73from pygeodesy.constants import _float as _F, _0_0s, _0_0, _0_001, _0_5, _1_0 

74from pygeodesy.datums import Datums, _earth_datum, _equall, _GDA2020_, _Names7, \ 

75 _negastr, Transform, _WGS84, _EWGS84, _operator 

76# from pygeodesy.ellipsoids import _EWGS84 # from .datums 

77from pygeodesy.errors import TRFError, _xattr, _xellipsoidall, _xkwds, _xkwds_item2 

78from pygeodesy.interns import MISSING, NN, _AT_, _COMMASPACE_, _conversion_, \ 

79 _datum_, _DOT_, _exists_, _invalid_, _MINUS_, \ 

80 _NAD83_, _no_, _PLUS_, _reframe_, _s_, _SPACE_, \ 

81 _STAR_, _to_, _vs_, _WGS84_, _x_, _intern as _i 

82# from pygeodesy.lazily import _ALL_LAZY # from .units 

83from pygeodesy.named import ADict, classname, _lazyNamedEnumItem as _lazy, _Named, \ 

84 _NamedEnum, _NamedEnumItem, _NamedTuple, Fmt, unstr 

85from pygeodesy.props import deprecated_method, property_doc_, Property_RO, property_RO 

86# from pygeodesy.streprs import Fmt, unstr # from .named 

87from pygeodesy.units import Epoch, Float, _ALL_LAZY 

88# from pygeodesy.utily import sincos2d_ 

89 

90from math import ceil as _ceil 

91# import operator as _operator # from .datums 

92 

93__all__ = _ALL_LAZY.trf 

94__version__ = '24.03.08' 

95 

96_EP0CH = Epoch(0, low=0) 

97_Es = {_EP0CH: _EP0CH} # L{Epoch}s, deleted below 

98_GRS80 = Datums.GRS80 

99_inverse_ = 'inverse' 

100_MAS = _MM = _PPB = Float # Units 

101_MM2M = _0_001 # scale mm2m, ppB2ppM, mas2as 

102_mDays = (0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0) 

103_366_0 = _F(sum(_mDays)) 

104_rates_ = 'rates' # PYCHOK used! 

105_Rs = {} # L{TRFXform7Tuple}s de-dup, deleted below 

106_xform_ = 'xform' # PYCHOK used! 

107_Xs = {} # L{TRFXform7Tuple}s de-dup, deleted below 

108 

109_ETRF88_ = _i('ETRF88') 

110_ETRF89_ = _i('ETRF89') 

111_ETRF90_ = _i('ETRF90') 

112_ETRF91_ = _i('ETRF91') 

113_ETRF92_ = _i('ETRF92') 

114_ETRF93_ = _i('ETRF93') 

115_ETRF94_ = _i('ETRF94') 

116_ETRF96_ = _i('ETRF96') 

117_ETRF97_ = _i('ETRF97') 

118_ETRF2000_ = _i('ETRF2000') 

119_ETRF2005_ = _i('ETRF2005') 

120_ETRF2008_ = _i('ETRF2008') 

121_ETRF2014_ = _i('ETRF2014') 

122_ETRF2020_ = _i('ETRF2020') 

123_GDA94_ = _i('GDA94') 

124_ITRF_ = _i('ITRF') 

125_ITRF88_ = _i('ITRF88') 

126_ITRF89_ = _i('ITRF89') 

127_ITRF90_ = _i('ITRF90') 

128_ITRF91_ = _i('ITRF91') 

129_ITRF92_ = _i('ITRF92') 

130_ITRF93_ = _i('ITRF93') 

131_ITRF94_ = _i('ITRF94') 

132_ITRF96_ = _i('ITRF96') 

133_ITRF97_ = _i('ITRF97') 

134_ITRF2000_ = _i('ITRF2000') 

135_ITRF2005_ = _i('ITRF2005') 

136_ITRF2008_ = _i('ITRF2008') 

137_ITRF2014_ = _i('ITRF2014') 

138_ITRF2020_ = _i('ITRF2020') 

139_NAD83cors96_ = _i('NAD83cors96') 

140_WGS84g1150_ = _i('WGS84g1150') 

141_WGS84g1674_ = _i('WGS84g1674') 

142_WGS84g1762_ = _i('WGS84g1762') 

143 

144 

145def _E(epoch): # deleted below 

146 '''(INTERNAL) De-dup L{Epochs}s. 

147 ''' 

148 e = Epoch(_F(epoch)) 

149 return _Es.setdefault(e, e) # PYCHOK del 

150 

151 

152def _P(ps, name, _Ps): # deleted below 

153 '''(INTERNAL) De-dup L{TRFXform7Tuple}s. 

154 ''' 

155 t = TRFXform7Tuple(map(_F, ps), name=name) 

156 return _Ps.setdefault(t, t) 

157 

158 

159class RefFrame(_NamedEnumItem): 

160 '''Terrestrial Reference Frame (TRF) parameters. 

161 ''' 

162 _datum = _GRS80 # Datums.GRS80 or .WGS84 (L{Datum}) 

163 _epoch = _EP0CH # epoch, fractional year (L{Epoch}) 

164 

165 def __init__(self, epoch, datum=_GRS80, name=NN): 

166 '''New L{RefFrame}. 

167 

168 @arg epoch: Epoch, a fractional calendar year (C{scalar} or C{str}). 

169 @arg datum: Datum or ellipsoid (L{Datum}, {Ellipsoid}, L{Ellipsoid2} 

170 or L{a_f2Tuple}). 

171 @kwarg name: Unique, non-empty name (C{str}). 

172 

173 @raise NameError: A L{RefFrame} with that B{C{name}} already exists. 

174 

175 @raise TRFError: Invalid B{C{epoch}}. 

176 

177 @raise TypeError: Invalid B{C{datum}}. 

178 ''' 

179 if datum in (_GRS80, None): 

180 pass 

181 elif datum in (_WGS84, _EWGS84): 

182 self._datum = _WGS84 

183 else: 

184 _earth_datum(self, datum, raiser=_datum_) 

185 self._epoch = _Epoch(epoch) 

186 self._Xto = {} # dict of Xforms 

187 if name: 

188 self._register(RefFrames, _stref(name=name)) 

189 

190 def __eq__(self, other): 

191 return isinstance(other, RefFrame) and other.epoch == self.epoch \ 

192 and other.datum == self.datum \ 

193 and other.name == self.name 

194 

195 def __lt__(self, other): # for sorting 

196 return isinstance(other, RefFrame) and (self.name < other.name 

197 or self.epoch < other.epoch) 

198 

199 @deprecated_method # PYCHOK Python 3.5+ 

200 def __matmul__(self, point): 

201 '''DEPRECATED on 2024.02.16, use method C{B{point}.toRefFrame}.''' 

202 return _toRefFrame(point, self) 

203 

204 @property_RO 

205 def datum(self): 

206 '''Get this reference frame's datum (L{Datum}). 

207 ''' 

208 return self._datum 

209 

210 @property_RO 

211 def ellipsoid(self): 

212 '''Get this reference frame's ellipsoid (L{Ellipsoid} or L{Ellipsoid2}). 

213 ''' 

214 return self._datum.ellipsoid 

215 

216 @Property_RO 

217 def epoch(self): 

218 '''Get this reference frame's epoch (C{Epoch}). 

219 ''' 

220 return self._epoch 

221 

222 def toRefFrame(self, point, reframe2, **epoch2_epoch_name): 

223 '''Convert an ellipsoidal point from this reframe and from C{epoch} to 

224 an other C{reframe2} and C{epoch2 or epoch}. 

225 

226 @arg point: The point to convert (C{Cartesian} or C{LatLon}). 

227 @arg reframe2: Reference frame to convert I{to} (L{RefFrame}). 

228 @kwarg epoch2_epoch_name: Optional keyword arguments C{B{epoch2}=None}, 

229 C{B{epoch}=None} and C{B{name}=NN}. 

230 

231 @return: A copy of the B{C{point}}, converted or renamed. 

232 

233 @raise TypeError: Invalid B{C{point}}. 

234 

235 @note: The B{C{point}}'s C{reframe} and C{epoch} are overridden by 

236 this reframe respectively B{C{epoch}} or this reframe's epoch. 

237 

238 @see: Ellipsoidal methods L{toRefFrame<ellipsoidalBase.LatLonEllipsoidalBase.toRefFrame>} 

239 and L{toRefFrame<ellipsoidalBase.CartesianEllipsoidalBase.toRefFrame>} 

240 for more details. 

241 ''' 

242 return _toRefFrame(point, reframe2, reframe=self, 

243 **_xkwds(epoch2_epoch_name, name=self.name)) 

244 

245 def toStr(self, epoch=None, name=NN, **unused): # PYCHOK expected 

246 '''Return this reference frame as a string. 

247 

248 @kwarg epoch: Override this reframe's epoch (C{scalar} or C{str}). 

249 @kwarg name: Override name (C{str}) or C{None} to exclude the 

250 reframe's name. 

251 

252 @return: This L{RefFrame}'s attributes (C{str}). 

253 ''' 

254 D = self.datum 

255 e = self.epoch if epoch is None else _Epoch(epoch) 

256 t = (Fmt.EQUAL(name=repr(name or self.name)), 

257 Fmt.EQUAL(epoch=e), 

258 Fmt.EQUAL(datum=_DOT_(classname(D) + _s_, D.name))) 

259 return _COMMASPACE_.join(t[int(name is None):]) 

260 

261 def Xform(self, reframe2): 

262 '''Get the converter Xform I{from} this reference frame I{to} C{reframe2}. 

263 

264 @arg reframe2: Destination frame to convert I{to} (L{RefFrame} or C{str}). 

265 

266 @return: The L{TRFXform} instance or C{None} if not available. 

267 

268 @raise TypeError: Invalid B{C{reframe2}}. 

269 ''' 

270 _xinstanceof(RefFrame, str, reframe2=reframe2) 

271 n2 = reframe2 if isstr(reframe2) else reframe2.name 

272 return self._Xto.get(n2, None) 

273 

274 def Xforms(self, inverse=False): 

275 '''Return all Xforms converting I{from} or I{to} this reference frame or both. 

276 

277 @kwarg inverse: If C{True}, get all I{from} otherwise I{to} Xforms 

278 I{un-inverted} (C{bool}) or if C{B{inverse}=2} (C{int}) 

279 get all I{to} Xforms I{inverted} plus all I{from}s. 

280 

281 @return: An L{ADict} of C{name=}L{TRFXform}s I{from} this reframe or if 

282 C{B{inverse}=True} I{to} this reframe or both if C{B{inverse}=2}. 

283 ''' 

284 return ADict(self._Xitems(inverse, RefFrames)) 

285 

286 def _Xfrom(self, RFs, inverted): 

287 '''(INTERNAL) Yield all 2-tuples C{(name, I{from} Xform)} converting I{to} 

288 this reframe, inverted if C{inverted is True}. 

289 ''' 

290 n2 = self.name 

291 for n1, r in RFs.items(): 

292 X = r._Xto.get(n2, None) 

293 if X: 

294 yield n1, (X.inverse() if inverted else X) 

295 

296 def _Xitems(self, inverse, RFs): # in _eXhaustives, .Xforms 

297 '''(INTERNAL) Yield all C{._Xfrom} and C{._Xto}'s as 2-tuple items. 

298 ''' 

299 i = inverse == 2 

300 if i or inverse: 

301 for item in self._Xfrom(RFs, i): 

302 yield item 

303 if i or not inverse: 

304 for item in self._Xto.items(): 

305 yield item 

306 

307 

308class RefFrames(_NamedEnum): 

309 '''(INTERNAL) L{RefFrame} registry, I{must} be a sub-class 

310 to accommodate the L{_LazyNamedEnumItem} properties. 

311 ''' 

312 def _Lazy(self, epoch, datum=_GRS80, name=NN): 

313 '''(INTERNAL) Instantiate the L{RefFrame}. 

314 ''' 

315 return RefFrame(epoch, datum, name=name) 

316 

317RefFrames = RefFrames(RefFrame) # PYCHOK singleton 

318'''Some pre-defined L{RefFrame}s, all I{lazily} instantiated.''' 

319# <https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe.js> 

320RefFrames._assert( 

321 ETRF88 = _lazy(_ETRF88_, _E(1988)), # epoch, datum? 

322 ETRF89 = _lazy(_ETRF89_, _E(1989)), # epoch, datum? 

323 ETRF90 = _lazy(_ETRF90_, _E(1990)), # epoch, datum? 

324 ETRF91 = _lazy(_ETRF91_, _E(1991)), # epoch, datum? 

325 ETRF92 = _lazy(_ETRF92_, _E(1992)), # epoch, datum? 

326 ETRF93 = _lazy(_ETRF93_, _E(1993)), # epoch, datum? 

327 ETRF94 = _lazy(_ETRF94_, _E(1994)), # epoch, datum? 

328 ETRF96 = _lazy(_ETRF96_, _E(1996)), # epoch, datum? 

329 ETRF97 = _lazy(_ETRF97_, _E(1997)), # epoch, datum? 

330 ETRF2000 = _lazy(_ETRF2000_, _E(2005)), 

331 ETRF2005 = _lazy(_ETRF2005_, _E(2005)), # epoch, datum? 

332 ETRF2008 = _lazy(_ETRF2008_, _E(2008)), # epoch, datum? 

333 ETRF2014 = _lazy(_ETRF2014_, _E(2014)), # epoch, datum? 

334 ETRF2020 = _lazy(_ETRF2020_, _E(2020)), # epoch, datum? 

335 GDA94 = _lazy(_GDA94_, _E(1994)), # Australia 

336 GDA2020 = _lazy(_GDA2020_, _E(2020)), # Australia 

337 ITRF88 = _lazy(_ITRF88_, _E(1988)), 

338 ITRF89 = _lazy(_ITRF89_, _E(1989)), 

339 ITRF90 = _lazy(_ITRF90_, _E(1988)), 

340 ITRF91 = _lazy(_ITRF91_, _E(1988)), 

341 ITRF92 = _lazy(_ITRF92_, _E(1988)), 

342 ITRF93 = _lazy(_ITRF93_, _E(1988)), 

343 ITRF94 = _lazy(_ITRF94_, _E(1993)), 

344 ITRF96 = _lazy(_ITRF96_, _E(1997)), 

345 ITRF97 = _lazy(_ITRF97_, _E(1997)), 

346 ITRF2000 = _lazy(_ITRF2000_, _E(1997)), # aka ITRF00 

347 ITRF2005 = _lazy(_ITRF2005_, _E(2000)), 

348 ITRF2008 = _lazy(_ITRF2008_, _E(2005)), # aka ITRF08 

349 ITRF2014 = _lazy(_ITRF2014_, _E(2010)), 

350 ITRF2020 = _lazy(_ITRF2020_, _E(2015)), 

351 NAD83 = _lazy(_NAD83_, _E(1997)), 

352 NAD83cors96 = _lazy(_NAD83cors96_, _E(1997)), 

353 WGS84 = _lazy(_WGS84_, _E(1984), _WGS84), 

354 WGS84g1150 = _lazy(_WGS84g1150_, _E(2001), _WGS84), 

355 WGS84g1674 = _lazy(_WGS84g1674_, _E(2005), _WGS84), 

356 WGS84g1762 = _lazy(_WGS84g1762_, _E(2005), _WGS84)) # same epoch 

357 

358 

359class TransformXform(Transform): 

360 '''Helmert transformation, extended with an C{Xform} TRF converter. 

361 

362 @see: L{Transform<datums.Transform>} and L{Xform<TRFXform>}. 

363 ''' 

364 _Xform = None 

365 

366 def __init__(self, name=NN, **tx_ty_tz_s_sx_sy_sz): # PYCHOK signature 

367 '''New L{TransformXform}. 

368 

369 @kwarg name: Optional name (C{str}), I{not registered}. 

370 

371 @see: L{Transform<datums.Transform>} for details. 

372 

373 @note: This L{TransformXform}'s name starts with C{"-"} iff 

374 I{inversed}. 

375 ''' 

376 Transform.__init__(self, **tx_ty_tz_s_sx_sy_sz) 

377 if name: 

378 self.name = name # unregistered 

379 

380 def __eq__(self, other): 

381 return isinstance(other, TransformXform) and _equall(other, self) 

382 

383 def __hash__(self): 

384 return Transform.__hash__(self) 

385 

386 def inverse(self, name=NN): 

387 '''Return the inverse of this transform. 

388 

389 @kwarg name: Optional, unique name (C{str}). 

390 

391 @return: Inverse (L{TransformXform}), unregistered. 

392 ''' 

393 r = Transform.inverse(name=name) 

394 r._Xform = r.Xform.inverse() 

395 return r 

396 

397 def rename(self, name=NN): 

398 '''Change this transform's name. 

399 

400 @arg name: New name (C{str}), overriding this transform's Xform's name. 

401 

402 @return: The previous name (C{str}). 

403 ''' 

404 X = self.Xform 

405 n = name or (X.toStr() if X else NN) 

406 return Transform.rename(self, n) 

407 

408 def toRefFrame(self, point, name=NN): # PYCHOK signature 

409 '''Convert an ellipsoidal point using this transform and Xform. 

410 

411 @arg point: The point to convert (C{Cartesian} or C{LatLon}). 

412 

413 @return: A copy of the B{C{point}}, converted I{directly} to 

414 this transform's Xform's C{refName2} and C{epoch}. 

415 

416 @note: The B{C{point}}'s original C{reframe} and C{epoch} are 

417 I{ignored}, its C{datum} and C{height} are preserved 

418 but I{not} taken into account. 

419 ''' 

420 _ = _xellipsoidall(point) 

421 p = point.dup() if self.isunity else point.toTransform(self) 

422 X = self.Xform 

423 if X: # see _toRefFrame below 

424 p._reframe = X.reframe2 

425 p._epoch = X.epoch 

426 p.rename(name or self.name) 

427 return p 

428 

429 def toTransform(self, epoch1, **epoch2_inverse): 

430 '''Return this transform observed at B{C{epoch1}} as a Helmert 

431 L{TransformXform}, optionally at B{C{epoch2 or epoch1}}. 

432 

433 @arg epoch1: Epoch to observe I{from} (C{scalar}). 

434 @kwarg epoch2_inverse: Optional C{B{epoch2}=None} to observe 

435 I{to} and C{B{inverse}=False}, see method 

436 L{toTransform<TRFXform.toTransform>} from 

437 L{TRFXform}. 

438 

439 @return: The Helmert transform (L{TransformXform}). 

440 

441 @raise TRFError: Invalid B{C{epoch1}}, B{C{epoch2}} or 

442 missing Xform. 

443 ''' 

444 X = self.Xform 

445 if X is None: 

446 raise TRFError(Xform=X, txt=MISSING) 

447 return X.toTransform(epoch1, **epoch2_inverse) 

448 

449 def transform2(self, x, y, z, vx=0, vy=0, vz=0, inverse=False, factor=_MM2M, 

450 **Vector_and_kwds): 

451 '''Transform a (cartesian) position I{with} velocities, forward or inverse. 

452 

453 @arg x: X coordinate (C{meter}). 

454 @arg y: Y coordinate (C{meter}). 

455 @arg z: Z coordinate (C{meter}). 

456 @kwarg vx: X velocity (C{meter-per-year}). 

457 @kwarg vy: Y velocity (C{meter-per-year}). 

458 @kwarg vz: Z velocity (C{meter-per-year}). 

459 @kwarg inverse: If C{True}, apply the inverse transform (C{bool}). 

460 @kwarg factor: Factor to scale this Xform's C{rates} (C{scalar}), 

461 default from C{milli-meter-} to C{meter-per-year}, 

462 from C{milli-arc-} to C{arc-seconds-per-year} and 

463 from C{ppB-} to C{ppM-per-year}. 

464 @kwarg Vector_and_kwds: An optional, (3-D) C{B{Vector}=None} or cartesian 

465 class and additional C{B{Vector}} keyword arguments to 

466 return the transformed position and the I{velocities}. 

467 

468 @return: 2-Tuple C{(position, velocities)}, the tranformed C{position} 

469 and C{velocities}, each a L{Vector3Tuple}C{(x, y, z)} unless 

470 some B{C{Vector_and_kwds}} are specified. 

471 

472 @note: If this transform's Xform is missing, the returned C{velocities} 

473 are the given ones, I{un-transformed}. 

474 

475 @raise TypeError: Non-scalar B{C{factor}}. 

476 

477 @see: Soler, T. & Snay, R.A. "Transforming Positions and Velocities ...", U{equations 

478 (4) and (5)<https://www.NGS.NOAA.gov/CORS/Articles/SolerSnayASCE.pdf>} 

479 and HTDP functions C{VTRANF} and C{VTRANF_IERS} in file U{HTDP/hdtp.f 

480 <https://Geodesy.NOAA.gov/TOOLS/Htdp/Htdp.shtml>}. 

481 ''' 

482 p = self.transform(x, y, z, inverse=inverse, **Vector_and_kwds) 

483 X = self.Xform 

484 if X is not None: 

485 r = X.rates * factor # equ (4) ... 

486 # vx', vy', vz' = (.tx + x * .s + y * .rz - z * .ry, 

487 # .ty - x * .rz + y * .s + z * .rx, 

488 # .tz + x * .ry - y * .rx + z * .s) 

489 # using counter-/clockwise .rx, .ry, and .rz 

490 V = Transform(**dict(r.items())) # unregistered 

491 _ = V._s_s1(r.s) 

492 v = V.transform(p.x, p.y, p.z, inverse=inverse) 

493 # + (vx, vy, vz) like HTDP 

494 vx += v.x 

495 vy += v.y 

496 vz += v.z 

497 v = p.dup(x=vx, y=vy, z=vz, name=NN(p.name, _vs_)) 

498 return p, v 

499 

500 def velocities(self, factor=_MM2M, **Vector_and_kwds): 

501 '''Compute the X, Y and Z I{velocities} of this transform. 

502 

503 @kwarg factor: Factor to scale this Xform's C{rates} (C{scalar}), 

504 default from C{milli-meter-} to C{meter-per-year}, 

505 from C{milli-arc-} to C{arc-seconds-per-year} and 

506 from C{ppB-} to C{ppM-per-year}. 

507 @kwarg Vector_and_kwds: An optional, (3-D) C{B{Vector}=None} or 

508 cartesian class and additional C{B{Vector}} keyword 

509 arguments to return the I{velocities}. 

510 

511 @return: A L{Vector3Tuple}C{(x, y, z)} unless some B{C{Vector_and_kwds}} 

512 are specified or C{None} if this transform's Xform is missing. 

513 

514 @raise TypeError: Non-scalar B{C{factor}}. 

515 

516 @see: Altamimi, Z. "EUREF-TN-1-Jan-31-2024", U{Appendix A, equation (3) 

517 <http://ETRS89.ENSG.IGN.FR/pub/EUREF-TN-1-Jan-31-2024.pdf>} and 

518 method L{transform2<TransformXform.transform2>}. 

519 ''' 

520 v = X = self.Xform 

521 if X is not None: 

522 r = X.rates * factor # equ (3) ... 

523 V = self.dup(tx=r.sx, ty=r.sy, tz=r.sz, _Xform=None, # Xyy-dot 

524 name=NN(self.name, _vs_)) # unregistered 

525 _ = V._s_s1(0) 

526 v = V.transform(r.tx, r.ty, r.tz, inverse=False, # Xyy 

527 **Vector_and_kwds) 

528 return v 

529 

530 @property_doc_(''' the Xform (L{TRFXform}).''') 

531 def Xform(self): 

532 '''Get this Helmert transform's Xform (L{TRFXform} or C{None}). 

533 ''' 

534 return self._Xform 

535 

536 @Xform.setter # PYCHOK setter! 

537 def Xform(self, Xform): 

538 '''Set this Helmert transform's Xform (L{TRFXform}). 

539 

540 @raise TypeError: Invalid B{C{Xform}}. 

541 ''' 

542 _xinstanceof(TRFXform, Xform=Xform) 

543 self._Xform = Xform 

544 

545 

546class TRFXform7Tuple(_NamedTuple): 

547 '''7-Tuple C{(tx, ty, tz, s, sx, sy, sz)} of conversion parameters with 

548 translations C{tx}, C{ty} and C{tz} in C{milli-meter}, scale C{s} in 

549 C{ppB} and rotations C{sx}, C{sy} and C{sz} in C{milli-arc-seconds}. 

550 For C{rates} all are C{units-per-year}. 

551 

552 @note: The parameters are also named as C{(Tx, Ty, Tz, D, Rx, Ry, Rz)} 

553 or C{(T1, T2, T3, D, R1, R2, R3)}. 

554 

555 @see: Class L{TransformXform}'s matching keyword argument names. 

556 ''' 

557 _Names_ = _Names7 # ('tx', 'ty', 'tz', _s_, 'sx', 'sy', 'sz') == TransformXform.__init__ 

558 _Units_ = (_MM, _MM, _MM, _PPB, _MAS, _MAS, _MAS) 

559 

560 def __add__(self, other): 

561 return self._add_sub(other, True) 

562 

563 def __eq__(self, other): 

564 return isinstance(other, TRFXform7Tuple) and _equall(other, self) 

565 # PYCHOK and self.name == other.name 

566 

567 def __hash__(self): 

568 return _NamedTuple.__hash__(self) 

569 

570 def __mul__(self, factor): 

571 _xisscalar(factor=factor) 

572 return type(self)((x * factor for x in self), name=_STAR_) # .fsums._mul_op 

573 

574 def __neg__(self): 

575 return self.inverse() 

576 

577 def __sub__(self, other): 

578 return self._add_sub(other, False) 

579 

580 def _add_sub(self, other, p_): 

581 '''(INTERNAL) Return C{this +/- other} L{TRFXform7Tuple}. 

582 ''' 

583 _xinstanceof(TRFXform7Tuple, other=other) 

584 op = _operator.add if p_ else _operator.sub 

585 return type(self)(map(op, self, other), name=_PLUS_ if p_ else _MINUS_) 

586 

587 def inverse(self, name=NN): 

588 '''Return the inverse of this transform. 

589 

590 @kwarg name: Optional name (C{str}). 

591 

592 @return: Inverse (L{TransformXform}). 

593 ''' 

594 n = name or _negastr(self.name) 

595 return type(self)(map(neg, self), name=n) 

596 

597 @Property_RO 

598 def isunity(self): 

599 '''Is this a C{unity, identity} transform (C{bool}). 

600 ''' 

601 return not any(self) 

602 

603 

604class TRFXform(_Named): 

605 '''A Terrestrial Reference Frame (TRF) converter between two 

606 reference frames observed at an C{epoch}. 

607 ''' 

608 _epoch = _EP0CH 

609 _epoch_d = _0_0 

610 _indir_d = NN # refName 

611 _inver_d = False 

612 refName1 = \ 

613 refName2 = NN 

614 rates = \ 

615 xform = None 

616 

617 def __init__(self, refName1, refName2, epoch=None, xform=None, 

618 rates=None, name=NN): 

619 '''New L{TRFXform} TRF converter. 

620 

621 @arg refName1: Source reframe (C{str}), converting I{from}. 

622 @arg refName2: Destination reframe (C{str}), converting I{to}. 

623 @kwarg epoch: Epoch, a fractional year (L{Epoch}, C{scalar} or C{str}). 

624 @kwarg xform: I{Transform} parameters at B{C{epoch}} (L{TRFXform7Tuple}). 

625 @kwarg rates: I{Rate} parameters (L{TRFXform7Tuple}), like B{C{xform}}, 

626 but in C{units-per-year}. 

627 @kwarg name: Optional name (C{str}), overriding the default from method 

628 L{toStr<TRFXform.toStr>}. 

629 

630 @raise TRFError: Invalid B{C{refName1}}, B{C{refName2}} or B{C{epoch}}. 

631 

632 @raise TypeError: Invalid B{C{xform}} or B{C{rates}}. 

633 

634 @see: Functions L{trfXform}, L{trfTransform0} and L{trfTransforms}. 

635 ''' 

636 self.refName1 = _stref(refName1=refName1) 

637 self.refName2 = _stref(refName2=refName2) 

638 _xinstanceof(TRFXform7Tuple, xform=xform, rates=rates) 

639 self.epoch = epoch 

640 self.xform = xform 

641 self.rates = rates 

642 self.rename(name or self.toStr()) 

643 

644 def __add__(self, other): 

645 return self._add_sub(other, True) 

646 

647 def __eq__(self, other): 

648 return isinstance(other, TRFXform) and other.epoch == self.epoch \ 

649 and other.xform == self.xform \ 

650 and other.rates == self.rates 

651 

652# def __hash__(self): 

653# return hash((self.epoch, self.xform, self.rates)) 

654 

655 def __lt__(self, other): # for sorting 

656 return isinstance(other, TRFXform) and (self.refName1 < other.refName1 

657 or self.refName2 < other.refName2 

658 or self.epoch < other.epoch) 

659 

660 def __neg__(self): 

661 return self.inverse() 

662 

663 def __repr__(self): 

664 return self.toRepr() 

665 

666 def __str__(self): 

667 return self.toStr() 

668 

669 def __sub__(self, other): 

670 return self._add_sub(other, False) 

671 

672 def _add_sub(self, other, p_, *n1_n2_n): # in _indirects below 

673 '''(INTERNAL) Summate C{this +/- other} Xform at C{this.epoch}. 

674 

675 @see: U{Appendix, Table 7, last column "Sum of the previous ..." 

676 <https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf">} 

677 ''' 

678 _xinstanceof(TRFXform, other=other) 

679 X1 = self 

680 e1 = X1.epoch 

681 X2 = other.toEpoch(e1) # if other.epoch != e1 else other 

682 

683 n1, n2, n = n1_n2_n or _n1_n2_n3(X1, X2) 

684 

685 X = type(X1)(n1, n2, epoch=e1, xform=X1.xform._add_sub(X2.xform, p_), 

686 rates=X1.rates._add_sub(X2.rates, p_), 

687 name=_sumstr(X1.name, X2.name, p_)) 

688 X._epoch_d = X1.epoched + X2.epoched # max, abs? 

689 X._indir_d = n # reframe? 

690 X._inver_d = X1.inversed and X2.inversed 

691 return X 

692 

693 def _at(self, epoch): 

694 '''(INTERNAL) Return C{"self.nameB{@}epoch"}. 

695 ''' 

696 n = self.name 

697 if epoch != self.epoch: 

698 _e = _AT_(NN, epoch) 

699 if not n.endswith(_e): 

700 n = NN(n, _e) 

701 return n 

702 

703 @property_doc_(''' the epoch, fractional year (L{Epoch}).''') 

704 def epoch(self): 

705 '''Get the epoch (L{Epoch}). 

706 ''' 

707 return self._epoch 

708 

709 @epoch.setter # PYCHOK setter! 

710 def epoch(self, epoch): 

711 '''Set the epoch (L{Epoch}, C{scalar} or C{str}). 

712 

713 @raise TRFError: Invalid B{C{epoch}}. 

714 ''' 

715 e = _Epoch(epoch) 

716 if self._epoch != e: 

717 self.rename(self._at(e)) 

718 self._epoch = e 

719 

720 @property_RO 

721 def epoched(self): 

722 '''Get this Xform's aggregate I{epoch} deltas (C{float}). 

723 ''' 

724 return self._epoch_d 

725 

726 @property_RO 

727 def indirected(self): 

728 '''Is this an I{indirected} Xform? (C{str} of space-separated 

729 refNames) or C{NN}. 

730 ''' 

731 return self._indir_d 

732 

733 def inverse(self, name=NN): 

734 '''Return this Xform {inversed}, C{refName1} and C{-2} swapped. 

735 

736 @return: The inverse (L{TRFXform}). 

737 ''' 

738 n = name or _negastr(self.name) 

739 X = self.dup(refName1=self.refName2, xform=-self.xform, 

740 refName2=self.refName1, rates=-self.rates, 

741 name=n, _inver_d=not self.inversed) 

742# X = type(self)(self.refName2, self.refName1, epoch= self.epoch, 

743# xform=-self.xform, 

744# rates=-self.rates, name=n) 

745# if self.epoched: 

746# X._epoch_d = self.epoched 

747# if self.indirected: 

748# X._indir_d = self.indirected 

749# if not self.inversed: 

750# X._inver_d = True 

751 return X 

752 

753 @property_RO 

754 def inversed(self): 

755 '''Is this an I{inversed} Xform? (C{bool}). 

756 ''' 

757 return self._inver_d 

758 

759 def _reframe(self, name, datum=_GRS80): 

760 '''(INTERNAL) Get an un-/registered frame. 

761 ''' 

762 r = RefFrames.get(name) 

763 if r is None or r.datum != datum: 

764 r = RefFrame(self.epoch, datum) 

765 r.name = name # unregistered 

766 return r 

767 

768 @property_RO 

769 def reframe1(self): 

770 '''Get the un-/registered I{from} frame (C{RefFrame}). 

771 ''' 

772 return self._reframe(self.refName1) 

773 

774 @property_RO 

775 def reframe2(self): 

776 '''Get the un-/registered I{to} frame (C{RefFrame}). 

777 ''' 

778 return self._reframe(self.refName2) 

779 

780 def rename(self, name=NN): 

781 '''Change this Xform's name. 

782 

783 @arg name: New name (C{str}), overriding the base 

784 name C{"refName1B{@}epochB{x}refName2"}. 

785 

786 @return: The old name (C{str}). 

787 ''' 

788 return _Named.rename(self, name or self.toStr()) 

789 

790 def toEpoch(self, epoch): 

791 '''Convert this Xform to B{C{epoch}}, if needed. 

792 

793 @arg epoch: Epoch, fractional year (C{Epoch}, C{scalar} 

794 or C{str}). 

795 

796 @return: This Xform or a copy converted to B{C{epoch}}. 

797 

798 @raise TRFError: Invalid B{C{epoch}}. 

799 ''' 

800 e = _Epoch(epoch) 

801 X, d = self, e - self.epoch 

802 if d: 

803 t = X.xform + X.rates * d 

804 X = X.dup(epoch=e, xform=t, name=X._at(e)) 

805 X._epoch_d += d # max, abs(d)? 

806 return X 

807 

808 def toHelmert(self, factor=_MM2M): 

809 '''Return the Helmert transform from this Xform scaled accordingly. 

810 

811 @kwarg factor: Factor to scale this Xform's C{xform} (C{scalar}), 

812 default from C{milli-meter-} to C{meter-}, from 

813 C{milli-arc-} to C{arc-seconds} and from C{ppB} 

814 to C{ppM}. 

815 

816 @return: The Helmert transform (L{TransformXform}). 

817 ''' 

818 h = self.xform * factor 

819 H = TransformXform(**dict(h.items())) 

820 H.name = self.name # unregistered 

821 H.Xform = self 

822 return H 

823 

824 def toRefFrame(self, point, datum=_GRS80, **epoch_epoch2_name): 

825 '''Convert an ellipsoidal point from this Xform's C{refName1} and 

826 C{epoch} to this Xform's C{refName2} and C{epoch2 or epoch}. 

827 

828 @arg point: The point to convert (C{Cartesian} or C{LatLon}). 

829 @kwarg datum: Optional datum to define a temporary L{RefFrame} from 

830 this Xform's C{refName1} or C{refName2} (C{datum}). 

831 @kwarg epoch_epoch2_name: Optional keyword arguments C{B{epoch}=None}, 

832 B{C{epoch2}=None} and C{B{name}=refName1}. 

833 

834 @return: A copy of the B{C{point}}, converted or renamed. 

835 

836 @see: Method L{RefFrame.toRefFrame} for more details. 

837 ''' 

838 r1 = self._reframe(self.refName1, datum=datum) 

839 r2 = self._reframe(self.refName2, datum=datum) 

840 return _toRefFrame(point, r2, reframe=r1, 

841 **_xkwds(epoch_epoch2_name, name=r1.name)) 

842 

843 def toRepr(self, **unused): # PYCHOK signature 

844 '''Return the represention of this Xform (C{str}). 

845 ''' 

846 return unstr(self.classname, name=self.name, epoch=self.epoch) 

847 

848 def toStr(self, epoch=None, **unused): # PYCHOK signature 

849 '''Return this Xform as C{"refName1B{@}epochB{x}refName2"} (C{str}). 

850 

851 @kwarg epoch: Epoch (C{Epoch}, C{scalar} or C{str}), overriding 

852 this Xform's epoch. 

853 ''' 

854 e = self.epoch if epoch is None else _Epoch(epoch) 

855 return NN(_AT_(self.refName1, e), _x_, self.refName2) 

856 

857 def toTransform(self, epoch, epoch2=None, inverse=False): 

858 '''Combine this Xform observed at B{C{epoch}} into a Helmert 

859 L{TransformXform}, optionally at B{C{epoch2 or epoch}}. 

860 

861 @arg epoch: Epoch to observe I{from} (C{scalar}). 

862 @kwarg epoch2: Optional epoch to observe I{to} (C{scalar}). 

863 @kwarg inverse: Use the Xform's inverse (C{bool}). 

864 

865 @return: The Helmert transform (L{TransformXform}). 

866 

867 @raise TRFError: Invalid B{C{epoch}} or B{C{epoch2}}. 

868 

869 @see: Method L{toHelmert}. 

870 ''' 

871 # X=self.toEpoch(epoch); if epoch2: X=X.toEpoch(epoch2) 

872 e = epoch if epoch2 is None else Epoch(epoch2=epoch2) 

873 X = self.toEpoch(e) 

874 if inverse: 

875 X = X.inverse() 

876 return X.toHelmert() 

877 

878 

879def date2epoch(year, month, day): 

880 '''Return the C{epoch} for a calendar day. 

881 

882 @arg year: Year of the date (C{scalar}). 

883 @arg month: Month in the B{C{year}} (C{scalar}, 1..12). 

884 @arg day: Day in the B{C{month}} (C{scalar}, 1..31). 

885 

886 @return: Epoch, the fractional year (C{float}). 

887 

888 @raise TRFError: Invalid B{C{year}}, B{C{month}} or B{C{day}}. 

889 

890 @note: Any B{C{year}} is considered a leap year, i.e. having 

891 29 days in February. 

892 ''' 

893 try: 

894 y, m, d = map1(int, year, month, day) 

895 if y > 0 and 1 <= m <= 12 and 1 <= d <= _mDays[m]: 

896 e = y + float(sum(_mDays[:m]) + d) / _366_0 

897 return Epoch(e, low=0) 

898 

899 raise ValueError # _invalid_ 

900 except (TRFError, TypeError, ValueError) as x: 

901 raise TRFError(year=year, month=month, day=day, cause=x) 

902 

903 

904def _direct(n1, n2): 

905 '''(INTERNAL) Get the C{n1} to C{n2} Xform or C{None}. 

906 ''' 

907 r = RefFrames.get(n1) 

908 return r._Xto.get(n2, None) if r else None 

909 

910 

911def _Epoch(e, **kwds): 

912 '''(INTERNAL) Get the C{Epoch(B{e})}. 

913 ''' 

914 return e if isinstance(e, Epoch) and not kwds else Epoch(e, **kwds) 

915 

916 

917def epoch2date(epoch): 

918 '''Return the date for a reference frame C{epoch}. 

919 

920 @arg epoch: Fractional year (C{scalar}). 

921 

922 @return: 3-Tuple C{(year, month, day)}. 

923 

924 @raise TRFError: Invalid B{C{epoch}}. 

925 

926 @note: Any B{C{year}} is considered a leap year, i.e. having 

927 29 days in February. 

928 ''' 

929 e = Epoch(epoch, low=0) 

930 y = int(e) 

931 d = int(_ceil((e - y) * _366_0)) 

932 for m, n in enumerate(_mDays[1:]): 

933 if d > n: 

934 d -= n 

935 else: 

936 break 

937 return y, (m + 1), max(1, d) 

938 

939 

940def _eXhaustives(n1, n2): 

941 '''(INTERNAL) Yield all I{coalesced} Xforms from C{n1} to {n2} 

942 via I{any number of} intermediate reframe conversions. 

943 ''' 

944 def _k2(item): 

945 return -item[1].epoch # most recent first 

946 

947 R = dict(RefFrames) 

948 r = R.pop(n1, None) 

949 if r: 

950 Xs = list(sorted(tuple(r._Xitems(2, R)), key=_k2)) 

951 while Xs: 

952 n, X = Xs.pop(0) 

953 if n == n2: 

954 yield _n_pop(X) 

955 else: 

956 r = R.pop(n, None) 

957 if r: 

958 for n, x in r._Xitems(2, R): 

959 Xs.append((n, X + x)) 

960 

961 

962def _indirects(n1, n2): 

963 '''(INTERNAL) Yield all Xforms between C{n1} and C{n2} via 

964 I{one} intermediate reframe C{n} conversion. 

965 ''' 

966 def _X4(_Xto, n2): 

967 _d = _direct 

968 for n, X1 in _Xto.items(): 

969 X2 = _d(n, n2) 

970 if X2: 

971 yield X1, X2, n, True # X1 + X2 

972 X2 = _d(n2, n) 

973 if X2: 

974 yield X1, X2, n, False # X1 - X2 

975 

976 r1 = RefFrames.get(n1) 

977 if r1: 

978 for X1, X2, n, p_ in _X4(r1._Xto, n2): 

979 e1, e2 = X1.epoch, X2.epoch 

980 if e1 < e2: # X1 to e2 

981 X1 = X1.toEpoch(e2) 

982# elif e1 > e2: # X2 to e1 

983# X2 = X2.toEpoch(e1) 

984 yield X1._add_sub(X2, p_, n1, n2, n) 

985 

986 

987def _n1_n2_n3(X1, X2): 

988 '''(INTERNAL) L{TRFXform._add_sub} helper. 

989 ''' 

990 n = X1.indirected 

991 n = _SPACE_(n, X1.refName2) if n else X1.refName2 

992 return X1.refName1, X2.refName2, n 

993 

994 

995def _n_pop(X): 

996 '''(INTERNAL) Pop L{TRFXform.indirected}'s ends. 

997 ''' 

998 p, n = None, X.indirected.split() 

999 if n and n[-1] == X.refName2: 

1000 p = n.pop() 

1001 if n and n[ 0] == X.refName1: 

1002 p = n.pop(0) 

1003 if p: 

1004 X._indir_d = _SPACE_.join(n) if n else NN 

1005 return X 

1006 

1007 

1008def _reframe(**name_reframe): 

1009 '''(INTERNAL) Get a C{reframe}. 

1010 ''' 

1011 _, r = _xkwds_item2(name_reframe) 

1012 if isstr(r) and r: # not NN 

1013 r = RefFrames.get(r) 

1014 if r and isinstance(r, RefFrame): 

1015 return r 

1016 raise TRFError(**name_reframe) # _invalid_ 

1017 

1018 

1019def _stref(**name_refname): 

1020 '''(INTERNAL) Check a reference frame name. 

1021 ''' 

1022 _, n = _xkwds_item2(name_refname) 

1023 if isstr(n) and isidentifier(n): 

1024 return str(n) 

1025 raise TRFError(**name_refname) # _invalid_ 

1026 

1027 

1028def _sumstr(name1, name2, p_): 

1029 '''(INTERNAL) "Sum" of C{name1 + ('+' if p_ else '-') + name2}. 

1030 ''' 

1031 if name2: 

1032 n = name2 if p_ else _negastr(name2) 

1033 p = NN if n.startswith(_MINUS_) or \ 

1034 n.startswith(_PLUS_) else _PLUS_ 

1035 name1 = NN(name1, p, n) 

1036 return name1 

1037 

1038 

1039def _toRefFrame(point, reframe2, reframe=None, epoch=None, 

1040 epoch2=None, name=NN, **LatLon_kwds): 

1041 '''(INTERNAL) Convert an ellipsoidal point to C{reframe2} 

1042 and C{epoch2 or epoch or pont.epoch or reframe.epoch}. 

1043 ''' 

1044 ll = _xellipsoidall(point) 

1045 r1 = reframe or point.reframe 

1046 if not r1: 

1047 t = _SPACE_(_DOT_(repr(point), _reframe_), MISSING) 

1048 raise TRFError(_no_(_conversion_), txt=t) 

1049 

1050 _xinstanceof(RefFrame, reframe2=reframe2, reframe=r1) 

1051 

1052 e1 = _Epoch(epoch or point.epoch or r1.epoch) 

1053 e2 = e1 if epoch2 is None else Epoch(epoch2=epoch2) 

1054 t0 = _toTransform0(r1.name, e1, reframe2.name, e2) 

1055 if t0 is None: 

1056 t = _SPACE_(RefFrame.__name__, _AT_(r1.name, e1), 

1057 _to_, _AT_(reframe2.name, e2)) 

1058 raise TRFError(_no_(_conversion_), txt=t) 

1059 

1060 if t0: # is not () 

1061 if t0.isunity: 

1062 p = point.dup() 

1063 elif point.datum: 

1064 p = point.toCartesian() if ll else point 

1065 p = p.toDatum( r1.datum).toTransform(t0) \ 

1066 .toDatum(reframe2.datum).toDatum(point.datum) 

1067 if ll: 

1068 p = p.toLatLon(LatLon=point.classof, **LatLon_kwds) 

1069 elif ll: # and LatLon_kwds 

1070 p = point.toTransform(t0, **LatLon_kwds) 

1071 else: 

1072 p = point.toTransform(t0) 

1073 p._reframe = reframe2 # see TRFXform.toRefFrame above 

1074 p._epoch = _xattr(t0.Xform, epoch=e2) 

1075 p.rename(name or reframe2.name) 

1076 else: 

1077 p = point.dup(name=name) if name else point 

1078 return p 

1079 

1080 

1081def _toTransform0(n1, e1, n2, e2, **indirect_inverse): 

1082 '''(INTERNAL) Return a L{TransformXform}, 0-tuple or C{None}. 

1083 ''' 

1084 if n1 == n2 and e1 == e2: 

1085 return () # unity? 

1086 

1087 for X in _toTransforms(n1, e1, n2, e2, **indirect_inverse): 

1088 return X # first OK? 

1089 

1090 if (n1.startswith(_ITRF_) and n2.startswith(_WGS84_)) or \ 

1091 (n2.startswith(_ITRF_) and n1.startswith(_WGS84_)): 

1092 return () # unity? 

1093 

1094 return None 

1095 

1096 

1097def _toTransforms(n1, e1, n2, e2, indirect=True, inverse=True, exhaust=False): # MCCABE 16 

1098 '''(INTERNAL) Yield all possible Helmert transforms, if any. 

1099 ''' 

1100 class Ts(list): # L{TransformXform}s de-dup 

1101 def __call__(self, Xs, e1=e1, e2=e2, **inverse): 

1102 for X in Xs: 

1103 if X: 

1104 T = X.toTransform(e1, epoch2=e2, **inverse) 

1105 if T not in self: 

1106 self.append(T) 

1107 yield T 

1108 

1109# def __contains__(self, T): 

1110# _xinstanceof(TransformXform, T=T) 

1111# return any(t == T for t in self) 

1112 

1113 def _k(X): 

1114 return -X.epoch # most recent first 

1115 

1116 _Ts = Ts() 

1117 

1118 for T in _Ts((_direct(n1, n2),), inverse=False): 

1119 yield T 

1120 if inverse: 

1121 for T in _Ts((_direct(n2, n1),), inverse=True): 

1122 yield T 

1123 

1124 if indirect: 

1125 for T in _Ts(sorted(_indirects(n1, n2), key=_k), inverse=False): 

1126 yield T 

1127 if inverse: 

1128 for T in _Ts(sorted(_indirects(n2, n1), key=_k), inverse=True): 

1129 yield T 

1130 

1131 if exhaust: 

1132 for T in _Ts(_eXhaustives(n1, n2), inverse=False): 

1133 yield T 

1134 for T in _Ts(_eXhaustives(n2, n1), inverse=True): 

1135 yield T 

1136 

1137 

1138def trfTransform0(reframe, reframe2, epoch=None, epoch2=None, indirect=True, inverse=True, exhaust=False): 

1139 '''Get a Helmert transform to convert one C{reframe} observed at C{epoch} 

1140 to an other C{reframe2} at observed at C{epoch2 or epoch}. 

1141 

1142 @return: A L{TransformXform} instance, a C{0-tuple} for I{unity, identity} or 

1143 C{None} if no conversion exists. 

1144 

1145 @see: Function L{trfTransforms} for futher details. 

1146 ''' 

1147 return _trfT0s(_toTransform0, reframe, reframe2, epoch, epoch2, 

1148 indirect=indirect, inverse=inverse, exhaust=exhaust) 

1149 

1150 

1151def trfTransforms(reframe, reframe2, epoch=None, epoch2=None, indirect=True, inverse=True, exhaust=False): 

1152 '''Yield all Helmert transform to convert one C{reframe} observed at C{epoch} 

1153 to an other C{reframe2} at observed at C{epoch2 or epoch}. 

1154 

1155 @arg reframe: The frame to convert I{from} (L{RefFrame} or C{str}). 

1156 @arg reframe2: The frame to convert I{to} (L{RefFrame} or C{str}). 

1157 @arg epoch: Epoch to observe I{from} (L{Epoch}, C{scalar} or C{str}), 

1158 otherwise C{B{reframe}}'s C{epoch}. 

1159 @kwarg epoch2: Optional epoch to observe to observe I{to} (L{Epoch}, C{scalar} or 

1160 C{str}), otherwise B{C{epoch}} or C{B{reframe}}'s C{epoch}. 

1161 @kwarg indirect: If C{True}, include transforms via I{one} intermediate reframe, 

1162 otherwise only I{direct} B{C{reframe}} to B{C{reframe2}} 

1163 transforms (C{bool}). 

1164 @kwarg inverse: If C{True}, include inverse, otherwise only forward transforms 

1165 (C{bool}). 

1166 @kwarg exhaust: If C{True}, exhaustively generate all transforms, forward and 

1167 inverse and via any number of intermediate reframes (C{bool}). 

1168 

1169 @return: A L{TransformXform} instance for each available conversion, without 

1170 duplicates. 

1171 

1172 @raise TRFError: Invalid B{C{reframe}}, B{C{reframe2}}, B{C{epoch}} or B{C{epoch2}}. 

1173 

1174 @raise TypeError: Invalid B{C{reframe}} or B{C{reframe2}}. 

1175 ''' 

1176 return _trfT0s(_toTransforms, reframe, reframe2, epoch, epoch2, 

1177 indirect=indirect, inverse=inverse, exhaust=exhaust) 

1178 

1179 

1180def _trfT0s(_toT0s, reframe, reframe2, epoch, epoch2, **indirect_inverse_exhaust): 

1181 '''(INTERNAL) Handle C{trfTransforms0} and C{trfTransforms} calls. 

1182 ''' 

1183 r1 = _reframe(reframe=reframe) 

1184 e1 = r1.epoch if epoch is None else _Epoch(epoch) 

1185 r2 = _reframe(reframe2=reframe2) 

1186 e2 = e1 if epoch2 is None else Epoch(epoch2=epoch2) 

1187 return _toT0s(r1.name, e1, r2.name, e2, **indirect_inverse_exhaust) 

1188 

1189 

1190def trfXform(reframe1, reframe2, epoch=None, xform=None, rates=None, raiser=True): 

1191 '''Define a new Terrestrial Reference Frame (TRF) converter or get an 

1192 existing one. 

1193 

1194 @arg reframe1: Source frame (L{RefFrame} or C{str}), converting I{from}. 

1195 @arg reframe2: Destination frame (L{RefFrame} or C{str}), converting I{to}. 

1196 @kwarg epoch: Epoch, a fractional year (L{Epoch}, C{scalar} or C{str}) 

1197 or C{None} for C{B{reframe2}}'s epoch. 

1198 @kwarg xform: I{Transform} parameters (L{TRFXform7Tuple}). 

1199 @kwarg rates: I{Rate} parameters (L{TRFXform7Tuple}), as B{C{xform}}, 

1200 but in C{units-per-year}. 

1201 @kwarg raiser: If C{False}, do not raise an error if the converter 

1202 exists, replace it (C{bool}). 

1203 

1204 @return: The new TRF converter (L{TRFXform}) or if no B{C{epoch}}, 

1205 B{C{xform}} and B{C{rates}} are given, return the existing 

1206 one (L{TRFXform}) or C{None} if not available. 

1207 

1208 @raise TRFError: Invalid B{C{reframe1}}, B{C{reframe2}}, B{C{epoch}}, 

1209 B{C{xform}} or B{C{rates}} or the TRF converter 

1210 already exists. 

1211 ''' 

1212 try: 

1213 r1 = _reframe(reframe1=reframe1) 

1214 r2 = _reframe(reframe2=reframe2) 

1215 if epoch is None: 

1216 if xform is rates is None: 

1217 return r1._Xto.get(r2.name, None) 

1218 e = r2.epoch 

1219 else: 

1220 e = _Epoch(epoch) 

1221 return _trfX(r1.name, r2.name, raiser=raiser, epoch=e, 

1222 xform=xform, rates=rates) 

1223 except (TypeError, ValueError) as x: 

1224 t = unstr(trfXform, reframe1, reframe2, epoch=epoch) 

1225 raise TRFError(t, cause=x) 

1226 

1227 

1228def _trfX(n1, n2, raiser=True, **epoch_xform_rates): 

1229 '''(INTERNAL) New, I{unique} L{TRFXform} converter. 

1230 ''' 

1231 r1 = RefFrames.get(n1) 

1232 if r1 is None: 

1233 raise ValueError(_invalid_) 

1234 r2 = RefFrames.get(n2) 

1235 if r2 is None: 

1236 raise ValueError(_invalid_) 

1237 if raiser: 

1238 if n2 in r1._Xto: 

1239 raise ValueError(_exists_) 

1240 if n1 in r2._Xto: 

1241 raise ValueError(_SPACE_(_inverse_, _exists_)) 

1242 r1._Xto[n2] = X = TRFXform(n1, n2, **epoch_xform_rates) 

1243 return X 

1244 

1245 

1246# def velocities2neu(vx, vy, vz, lat=0, lon=0): 

1247# '''Convert X, Y, and Z I{velocities} to North, East, Up. 

1248# 

1249# @arg vx: X velocity (C{meter-per-time}). 

1250# @arg vx: Y velocity (C{meter-per-time}). 

1251# @arg vx: Z velocity (C{meter-per-time}). 

1252# @kwarg lat: Latitude (C{degrees}). 

1253# @kwarg lon: Longitude (C{degrees}). 

1254# 

1255# @return: 3-Tuple C{(vnorth, veast, vup)} with the 

1256# North, East and Up velocities, same units 

1257# as B{C{vx}, B{C{vy}} and B{C{vx}}. 

1258# ''' 

1259# sa, ca, sb, cb = sincos2d_(lat, lon) 

1260# ve = cb * vy - sb * vx 

1261# v = cb * vx + sb * vy 

1262# vn = ca * vz - sa * v 

1263# vu = sa * vz + ca * v 

1264# return vn, ve, vu 

1265 

1266 

1267# def velocities2xyz(vn, ve, vu, lat=0, lon=0): 

1268# '''Convert North, East and Up I{velocities} to X, Y, Z. 

1269# 

1270# @arg vn: North velocity (C{meter-per-time}). 

1271# @arg ve: East velocity (C{meter-per-time}). 

1272# @arg vu: Up velocity (C{meter-per-time}). 

1273# @kwarg lat: Latitude (C{degrees}). 

1274# @kwarg lon: Longitude (C{degrees}). 

1275# 

1276# @return: 3-Tuple C{(vx, vy, vz)} with the X, Y 

1277# and Z velocities, same units as B{C{vn}, 

1278# B{C{ve}} and B{C{vu}}. 

1279# ''' 

1280# sa, ca, sb, cb = sincos2d_(lat, lon) 

1281# vz = ca * vn + sa * vu 

1282# v = ca * vu - sa * vn 

1283# vx = cb * v - sb * ve 

1284# vy = sb * v + cb * ve 

1285# return vx, vy, vz 

1286 

1287 

1288def _X(*ps): # deleted below 

1289 return _P(ps, _xform_, _Xs) # PYCHOK del 

1290 

1291 

1292def _R(*ps): # deleted below 

1293 return _P(ps, _rates_, _Rs) # PYCHOK del 

1294 

1295 

1296_P_0_0s = TRFXform7Tuple(_0_0s(len(_Names7)), name='unity') 

1297 

1298# TRF conversions specified as an epoch and 2 sets of 7 parameters. Most from Altamimi, Z. U{"EUREF Technical 

1299# Note 1: Relationship and Transformation between the International and the European Terrestrial Reference 

1300# Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Appendix A, more at U{Quinsy QPS <https:// 

1301# confluence.QPS.NL/qinsy/files/latest/en/182618383/182618384/1/1579182881000/ITRF_Transformation_Parameters.xlsx>}. 

1302# See also U{Quinsy International Terrestrial Reference Frame 2014 (ITRF2014)<https://confluence.QPS.NL/qinsy/latest/ 

1303# en/international-terrestrial-reference-frame-2014-itrf2014-182618383.html>}. 

1304_trfX(_ITRF2020_, _ITRF2014_, epoch=_E(2015), # <https://ITRF.IGN.Fr/docs/solutions/itrf2020/Transfo-ITRF2020_TRFs.txt> 

1305 xform=_X( -1.4, -0.9, 1.4, -0.42, _0_0, _0_0, _0_0), 

1306 rates=_R( _0_0, -0.1, 0.2, _0_0, _0_0, _0_0, _0_0)) 

1307_trfX(_ITRF2020_, _ITRF2008_, epoch=_E(2015), 

1308 xform=_X( 0.2, 1.0, 3.3, -0.29, _0_0, _0_0, _0_0), 

1309 rates=_R( _0_0, -0.1, 0.1, 0.03, _0_0, _0_0, _0_0)) 

1310_trfX(_ITRF2020_, _ITRF2005_, epoch=_E(2015), 

1311 xform=_X( 2.7, 0.1, -1.4, 0.65, _0_0, _0_0, _0_0), 

1312 rates=_R( 0.3, -0.1, 0.1, 0.03, _0_0, _0_0, _0_0)) 

1313_trfX(_ITRF2020_, _ITRF2000_, epoch=_E(2015), 

1314 xform=_X( -0.2, 0.8, -34.2, 2.25, _0_0, _0_0, _0_0), 

1315 rates=_R( 0.1, _0_0, -1.7, 0.11, _0_0, _0_0, _0_0)) 

1316_trfX(_ITRF2020_, _ITRF97_, epoch=_E(2015), 

1317 xform=_X( 6.5, -3.9, -77.9, 3.98, _0_0, _0_0, 0.36), 

1318 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1319_trfX(_ITRF2020_, _ITRF96_, epoch=_E(2015), 

1320 xform=_X( 6.5, -3.9, -77.9, 3.98, _0_0, _0_0, 0.36), 

1321 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1322_trfX(_ITRF2020_, _ITRF94_, epoch=_E(2015), 

1323 xform=_X( 6.5, -3.9, -77.9, 3.98, _0_0, _0_0, 0.36), 

1324 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1325_trfX(_ITRF2020_, _ITRF93_, epoch=_E(2015), 

1326 xform=_X( -65.8, 1.9, -71.3, 4.47, -3.36, -4.33, 0.75), 

1327 rates=_R( -2.8, -0.2, -2.3, 0.12, -0.11, -0.19, 0.07)) 

1328_trfX(_ITRF2020_, _ITRF92_, epoch=_E(2015), 

1329 xform=_X( 14.5, -1.9, -85.9, 3.27, _0_0, _0_0, 0.36), 

1330 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1331_trfX(_ITRF2020_, _ITRF91_, epoch=_E(2015), 

1332 xform=_X( 26.5, 12.1, -91.9, 4.67, _0_0, _0_0, 0.36), 

1333 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1334_trfX(_ITRF2020_, _ITRF90_, epoch=_E(2015), 

1335 xform=_X( 24.5, 8.1, -107.9, 4.97, _0_0, _0_0, 0.36), 

1336 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1337_trfX(_ITRF2020_, _ITRF89_, epoch=_E(2015), 

1338 xform=_X( 29.5, 32.1, -145.9, 8.37, _0_0, _0_0, 0.36), 

1339 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1340_trfX(_ITRF2020_, _ITRF88_, epoch=_E(2015), 

1341 xform=_X( 24.5, -3.9, -169.9, 11.47, 0.1, _0_0, 0.36), 

1342 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02)) 

1343 

1344# see U{Transformation Parameters ITRF2014<http://ITRF.IGN.Fr/doc_ITRF/Transfo-ITRF2014_ITRFs.txt>} and 

1345# Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and 

1346# the European Terrestrial Reference Systems"<https://ERTS89.ENSG,IFN.Fr/pub/EUREF-TN-1.pdf>} Appendix A. 

1347_trfX(_ITRF2014_, _ITRF2008_, epoch=(2010), # <http://ITRF.ENSG.IGN.Fr/ITRF_solutions/2014/tp_14-08.php> 

1348 xform=_X( 1.6, 1.9, 2.4, -0.02, _0_0, _0_0, _0_0), 

1349 rates=_R( _0_0, _0_0, -0.1, 0.03, _0_0, _0_0, _0_0)) 

1350_trfX(_ITRF2014_, _ITRF2005_, epoch=_E(2010), 

1351 xform=_X( 2.6, _1_0, -2.3, 0.92, _0_0, _0_0, _0_0), 

1352 rates=_R( 0.3, _0_0, -0.1, 0.03, _0_0, _0_0, _0_0)) 

1353_trfX(_ITRF2014_, _ITRF2000_, epoch=_E(2010), 

1354 xform=_X( 0.7, 1.2, -26.1, 2.12, _0_0, _0_0, _0_0), 

1355 rates=_R( 0.1, 0.1, -1.9, 0.11, _0_0, _0_0, _0_0)) 

1356_trfX(_ITRF2014_, _ITRF97_, epoch=_E(2010), 

1357 xform=_X( 7.4, -0.5, -62.8, 3.8, _0_0, _0_0, 0.26), 

1358 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1359_trfX(_ITRF2014_, _ITRF96_, epoch=_E(2010), 

1360 xform=_X( 7.4, -0.5, -62.8, 3.8, _0_0, _0_0, 0.26), 

1361 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1362_trfX(_ITRF2014_, _ITRF94_, epoch=_E(2010), 

1363 xform=_X( 7.4, -0.5, -62.8, 3.8, _0_0, _0_0, 0.26), 

1364 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1365_trfX(_ITRF2014_, _ITRF93_, epoch=_E(2010), 

1366 xform=_X( -50.4, 3.3, -60.2, 4.29, -2.81, -3.38, 0.4), 

1367 rates=_R( -2.8, -0.1, -2.5, 0.12, -0.11, -0.19, 0.07)) 

1368_trfX(_ITRF2014_, _ITRF92_, epoch=_E(2010), 

1369 xform=_X( 15.4, 1.5, -70.8, 3.09, _0_0, _0_0, 0.26), 

1370 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1371_trfX(_ITRF2014_, _ITRF91_, epoch=_E(2010), 

1372 xform=_X( 27.4, 15.5, -76.8, 4.49, _0_0, _0_0, 0.26), 

1373 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1374_trfX(_ITRF2014_, _ITRF90_, epoch=_E(2010), 

1375 xform=_X( 25.4, 11.5, -92.8, 4.79, _0_0, _0_0, 0.26), 

1376 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1377_trfX(_ITRF2014_, _ITRF89_, epoch=_E(2010), 

1378 xform=_X( 30.4, 35.5, -130.8, 8.19, _0_0, _0_0, 0.26), 

1379 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1380_trfX(_ITRF2014_, _ITRF88_, epoch=_E(2010), 

1381 xform=_X( 25.4, -0.5, -154.8, 11.29, 0.1, _0_0, 0.26), 

1382 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02)) 

1383 

1384# Pearson, C. & Snay, R. U{"Introducing HTDP 3.1 to transform coordinates across time and spatial reference 

1385# frames"<https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 1st and 2nd column 

1386_trfX(_ITRF2008_, _ITRF2005_, epoch=_E(2005), 

1387 xform=_X( -0.5, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0), 

1388 rates=_R( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0)) 

1389# _trfX(_ITRF2008_, _ITRF2005_, epoch=_E(1997), 

1390# xform=_X( -2.9, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0), 

1391# rates=_R( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0)) 

1392# see U{Transformation Parameters ITRF2008<http://ITRF.IGN.Fr/doc_ITRF/Transfo-ITRF2008_ITRFs.txt>} 

1393# _trfX(_ITRF2008_, _ITRF2005_, epoch=_E(2000), # <http://ITRF.ENSG.IGN.Fr/ITRF_solutions/2008/tp_08-05.php> 

1394# xform=_X( -2.0, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0), 

1395# rates=_R( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0)) 

1396_trfX(_ITRF2008_, _ITRF2000_, epoch=_E(2000), 

1397 xform=_X( -1.9, -1.7, -10.5, 1.34, _0_0, _0_0, _0_0), 

1398 rates=_R( 0.1, 0.1, -1.8, 0.08, _0_0, _0_0, _0_0)) 

1399_trfX(_ITRF2008_, _ITRF97_, epoch=_E(2000), 

1400 xform=_X( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, 0.06), 

1401 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1402_trfX(_ITRF2008_, _ITRF96_, epoch=_E(2000), 

1403 xform=_X( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, 0.06), 

1404 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1405_trfX(_ITRF2008_, _ITRF94_, epoch=_E(2000), 

1406 xform=_X( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, 0.06), 

1407 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1408_trfX(_ITRF2008_, _ITRF93_, epoch=_E(2000), 

1409 xform=_X( -24.0, 2.4, -38.6, 3.41, -1.71, -1.48, -0.3), 

1410 rates=_R( -2.8, -0.1, -2.4, 0.09, -0.11, -0.19, 0.07)) 

1411_trfX(_ITRF2008_, _ITRF92_, epoch=_E(2000), 

1412 xform=_X( 12.8, 4.6, -41.2, 2.21, _0_0, _0_0, 0.06), 

1413 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1414_trfX(_ITRF2008_, _ITRF91_, epoch=_E(2000), 

1415 xform=_X( 24.8, 18.6, -47.2, 3.61, _0_0, _0_0, 0.06), 

1416 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1417_trfX(_ITRF2008_, _ITRF90_, epoch=_E(2000), 

1418 xform=_X( 22.8, 14.6, -63.2, 3.91, _0_0, _0_0, 0.06), 

1419 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1420_trfX(_ITRF2008_, _ITRF89_, epoch=_E(2000), 

1421 xform=_X( 27.8, 38.6, -101.2, 7.31, _0_0, _0_0, 0.06), 

1422 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1423_trfX(_ITRF2008_, _ITRF88_, epoch=_E(2000), 

1424 xform=_X( 22.8, 2.6, -125.2, 10.41, 0.1, _0_0, 0.06), 

1425 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02)) 

1426 

1427# Pearson, C. & Snay, R. U{"Introducing HTDP 3.1 to transform coordinates across time and spatial reference 

1428# frames"<https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 3rd column 

1429# _trfX(_ITRF2005_, _ITRF2000_, epoch=_E(1997), 

1430# xform=_X( 0.7, -1.1, -0.4, 0.16, -0.2, 0.1 -1.8), 

1431# rates=_R( -0.2, 0.1, -1.8, 0.08, _0_0, _0_0, _0_0)) 

1432_trfX(_ITRF2005_, _ITRF2000_, epoch=_E(2000), # <http://ITRF.ENSG.IGN.Fr/ITRF_solutions/2005/tp_05-00.php> 

1433 xform=_X( 0.1, -0.8, -5.8, 0.4, _0_0, _0_0, _0_0), 

1434 rates=_R( -0.2, 0.1, -1.8, 0.08, _0_0, _0_0, _0_0)) 

1435 

1436_trfX(_ITRF2000_, _ITRF97_, epoch=_E(1997), 

1437 xform=_X( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0), 

1438 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, -0.02)) # 0.02? 

1439_trfX(_ITRF2000_, _ITRF96_, epoch=_E(1997), 

1440 xform=_X( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0), 

1441 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02)) 

1442_trfX(_ITRF2000_, _ITRF94_, epoch=_E(1997), 

1443 xform=_X( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0), 

1444 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02)) 

1445_trfX(_ITRF2000_, _ITRF93_, epoch=_E(1988), 

1446 xform=_X( 12.7, 6.5, -20.9, 1.95, -0.39, 0.8, -1.14), 

1447 rates=_R( -2.9, -0.2, -0.6, 0.01, -0.11, -0.19, 0.07)) 

1448_trfX(_ITRF2000_, _ITRF92_, epoch=_E(1988), 

1449 xform=_X( 1.47, 1.35, -1.39, 0.75, _0_0, _0_0, -0.18), 

1450 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02)) 

1451_trfX(_ITRF2000_, _ITRF91_, epoch=_E(1988), 

1452 xform=_X( 26.7, 27.5, -19.9, 2.15, _0_0, _0_0, -0.18), 

1453 rates=_R( _0_0, -0.6, -1.4, 0.01, _0_0, _0_0, 0.02)) 

1454_trfX(_ITRF2000_, _ITRF90_, epoch=_E(1988), 

1455 xform=_X( 2.47, 2.35, -3.59, 2.45, _0_0, _0_0, -0.18), 

1456 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02)) 

1457_trfX(_ITRF2000_, _ITRF89_, epoch=_E(1988), 

1458 xform=_X( 2.97, 4.75, -7.39, 5.85, _0_0, _0_0, -0.18), 

1459 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02)) 

1460_trfX(_ITRF2000_, _ITRF88_, epoch=_E(1988), 

1461 xform=_X( 2.47, 1.15, -9.79, 8.95, 0.1, _0_0, -0.18), 

1462 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02)) 

1463 

1464# Soler, T .& Snay R.A. U{"Transforming Positions and Velocities between the International Terrestrial 

1465# Reference Frame of 2000 and North American Datum of 1983"<https://www.ResearchGate.net/publication/245291390>}, 

1466# Pearson, C. & Snay, R. U{"Introducing HTDP 3.1 to transform coordinates across time and spatial reference 

1467# frames"<https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 5th and 6th column 

1468_trfX(_ITRF97_, _ITRF96_, epoch=_E(1997), 

1469 xform=_X( -2.07, -0.21, 9.95, -0.93496, 0.1267, -0.22355, -0.06065,), 

1470 rates=_R( 0.69, -0.1, 1.86, -0.19201, 0.01347, -0.01514, 0.00027)) 

1471_trfX(_ITRF96_, _NAD83_, epoch=_E(1997), 

1472 xform=_X( 991.0, -190.72, -512.9, _0_0, 25.79, 9.65, 11.66,), 

1473 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.0532, -0.7423, -0.0316,)) 

1474 

1475# see Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and 

1476# the European Terrestrial Reference Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 1. 

1477# _trfX(_ITRF2020_, _ETRF2020_, epoch=_E(1989), # see Table 2 below 

1478# xform=_P_0_0s, 

1479# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.086, 0.519, -0.753)) 

1480# _trfX(_ITRF2014_, _ETRF2014_, epoch=_E(1989), # see Table 3 below 

1481# xform=_P_0_0s, 

1482# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.085, 0.531, -0.77)) 

1483_trfX(_ITRF2005_, _ETRF2005_, epoch=_E(1989), 

1484 xform=_X( 56.0, 48.0, -37.0, _0_0, _0_0, _0_0, _0_0), 

1485 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.054, 0.518, -0.781)) 

1486# _trfX(_ITRF2000_, _ETRF2000_, epoch=_E(1989), # see Table 4 below 

1487# xform=_X( 54.0, 51.0, -48.0, _0_0, _0_0, _0_0, _0_0), 

1488# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.081, 0.49, -0.792)) 

1489_trfX(_ITRF97_, _ETRF97_, epoch=_E(1989), 

1490 xform=_X( 41.0, 41.0, -49.0, _0_0, _0_0, _0_0, _0_0), 

1491 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.2, 0.5, -0.65)) 

1492_trfX(_ITRF96_, _ETRF96_, epoch=_E(1989), 

1493 xform=_X( 41.0, 41.0, -49.0, _0_0, _0_0, _0_0, _0_0), 

1494 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.2, 0.5, -0.65)) 

1495_trfX(_ITRF94_, _ETRF94_, epoch=_E(1989), 

1496 xform=_X( 41.0, 41.0, -49.0, _0_0, _0_0, _0_0, _0_0), 

1497 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.2, 0.5, -0.65)) 

1498_trfX(_ITRF93_, _ETRF93_, epoch=_E(1989), 

1499 xform=_X( 19.0, 53.0, -21.0, _0_0, _0_0, _0_0, _0_0), 

1500 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.32, 0.78, -0.67)) 

1501_trfX(_ITRF92_, _ETRF92_, epoch=_E(1989), 

1502 xform=_X( 38.0, 40.0, -37.0, 0.0, 0.0, 0.0, 0.0), 

1503 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.21, 0.52, -0.68)) 

1504_trfX(_ITRF91_, _ETRF91_, epoch=_E(1989), 

1505 xform=_X( 21.0, 25.0, -37.0, _0_0, _0_0, _0_0, _0_0), 

1506 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.21, 0.52, -0.68)) 

1507_trfX(_ITRF90_, _ETRF90_, epoch=_E(1989), 

1508 xform=_X( 19.0, 28.0, -23.0, _0_0, _0_0, _0_0, _0_0), 

1509 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.11, 0.57, -0.71)) 

1510_trfX(_ITRF89_, _ETRF89_, epoch=_E(1989), 

1511 xform=_P_0_0s, 

1512 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.11, 0.57, -0.71)) 

1513 

1514# see Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and 

1515# the European Terrestrial Reference Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 2. 

1516_trfX(_ITRF2020_, _ETRF2020_, epoch=_E(2015), 

1517 xform=_X( _0_0, _0_0, _0_0, _0_0, 2.236, 13.494, -19.578), 

1518 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.086, 0.519, -0.753)) 

1519_trfX(_ITRF2014_, _ETRF2020_, epoch=_E(2015), 

1520 xform=_X( 1.4, 0.9, -1.4, 0.42, 2.236, 13.494, -19.578), 

1521 rates=_R( _0_0, 0.1, -0.2, _0_0, 0.086, 0.519, -0.753)) 

1522_trfX(_ITRF2008_, _ETRF2020_, epoch=_E(2015), 

1523 xform=_X( 3.0, 2.8, 0.5, 0.55, 2.236, 13.494, -19.578), 

1524 rates=_R( _0_0, 0.1, -0.3, 0.03, 0.086, 0.519, -0.753)) 

1525_trfX(_ITRF2005_, _ETRF2020_, epoch=_E(2015), 

1526 xform=_X( 5.5, 1.9, -4.2, 1.49, 2.236, 13.494, -19.578), 

1527 rates=_R( 0.3, 0.1, -0.3, 0.03, 0.086, 0.519, -0.753)) 

1528_trfX(_ITRF2000_, _ETRF2020_, epoch=_E(2015), 

1529 xform=_X( 2.6, 2.6, -37.0, 3.09, 2.236, 13.494, -19.578), 

1530 rates=_R( 0.1, 0.2, -2.1, 0.11, 0.086, 0.519, -0.753)) 

1531_trfX(_ITRF97_, _ETRF2020_, epoch=_E(2015), 

1532 xform=_X( 9.3, -2.1, -80.7, 4.82, 2.236, 13.494, -19.218), 

1533 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1534_trfX(_ITRF96_, _ETRF2020_, epoch=_E(2015), 

1535 xform=_X( 9.3, -2.1, -80.7, 4.82, 2.236, 13.494, -19.218), 

1536 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1537_trfX(_ITRF94_, _ETRF2020_, epoch=_E(2015), 

1538 xform=_X( 9.3, -2.1, -80.7, 4.82, 2.236, 13.494, -19.218), 

1539 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1540_trfX(_ITRF93_, _ETRF2020_, epoch=_E(2015), 

1541 xform=_X( -63.0, 3.7, -74.1, 5.31, -1.124, 9.164, -18.828), 

1542 rates=_R( -2.8, _0_0, -2.7, 0.12, -0.024, 0.329, -0.683)) 

1543_trfX(_ITRF92_, _ETRF2020_, epoch=_E(2015), 

1544 xform=_X( 17.3, -0.1, -88.7, 4.11, 2.236, 13.494, -19.218), 

1545 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1546_trfX(_ITRF91_, _ETRF2020_, epoch=_E(2015), 

1547 xform=_X( 29.3, 13.9, -94.7, 5.51, 2.236, 13.494, -19.218), 

1548 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1549_trfX(_ITRF90_, _ETRF2020_, epoch=_E(2015), 

1550 xform=_X( 27.3, 9.9, -110.7, 5.81, 2.236, 13.494, -19.218), 

1551 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1552_trfX(_ITRF89_, _ETRF2020_, epoch=_E(2015), 

1553 xform=_X( 32.3, 33.9, -148.7, 9.21, 2.236, 13.494, -19.218), 

1554 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1555_trfX(_ITRF88_, _ETRF2020_, epoch=_E(2015), 

1556 xform=_X( 27.3, -2.1, -172.7, 12.31, 2.336, 13.494, -19.218), 

1557 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733)) 

1558 

1559# see Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and 

1560# the European Terrestrial Reference Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 3. 

1561_trfX(_ITRF2020_, _ETRF2014_, epoch=_E(2015), 

1562 xform=_X( -1.4, -0.9, 1.4, 0.42, 2.21, 13.806, -20.02), 

1563 rates=_R( _0_0, -0.1, 0.2, _0_0, 0.085, 0.531, -0.77)) 

1564_trfX(_ITRF2014_, _ETRF2014_, epoch=_E(2015), 

1565 xform=_X( _0_0, _0_0, _0_0, _0_0, 2.21, 13.806, -20.02), 

1566 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.085, 0.531, -0.77)) 

1567_trfX(_ITRF2008_, _ETRF2014_, epoch=_E(2015), 

1568 xform=_X( -1.6, -1.9, -1.9, -0.13, 2.21, 13.806, -20.02), 

1569 rates=_R( _0_0, _0_0, 0.1, -0.03, 0.085, 0.531, -0.77)) 

1570_trfX(_ITRF2005_, _ETRF2014_, epoch=_E(2015), 

1571 xform=_X( -4.1, -1.0, 2.8, -1.07, 2.21, 13.806, -20.02), 

1572 rates=_R( -0.3, _0_0, 0.1, -0.03, 0.085, 0.531, -0.77)) 

1573_trfX(_ITRF2000_, _ETRF2014_, epoch=_E(2015), 

1574 xform=_X( -1.2, -1.7, 35.6, -2.67, 2.21, 13.806, -20.02), 

1575 rates=_R( -0.1, -0.1, 1.9, -0.11, 0.085, 0.531, -0.77)) 

1576_trfX(_ITRF97_, _ETRF2014_, epoch=_E(2015), 

1577 xform=_X( -7.9, 3.0, 79.3, -4.40, 2.210, 13.806, -20.38), 

1578 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1579_trfX(_ITRF96_, _ETRF2014_, epoch=_E(2015), 

1580 xform=_X( -7.9, 3.0, 79.3, -4.40, 2.210, 13.806, -20.38), 

1581 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1582_trfX(_ITRF94_, _ETRF2014_, epoch=_E(2015), 

1583 xform=_X( -7.9, 3.0, 79.3, -4.40, 2.210, 13.806, -20.38), 

1584 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1585_trfX(_ITRF93_, _ETRF2014_, epoch=_E(2015), 

1586 xform=_X( 64.4, -2.8, 72.7, -4.89, 5.570, 18.136, -20.77), 

1587 rates=_R( 2.8, 0.1, 2.5, -0.12, 0.195, 0.721, -0.84)) 

1588_trfX(_ITRF92_, _ETRF2014_, epoch=_E(2015), 

1589 xform=_X( -15.9, 1.0, 87.3, -3.69, 2.21, 13.806, -20.38), 

1590 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1591_trfX(_ITRF91_, _ETRF2014_, epoch=_E(2015), 

1592 xform=_X( -27.9, -13.0, 93.3, -5.09, 2.21, 13.806, -20.38), 

1593 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1594_trfX(_ITRF90_, _ETRF2014_, epoch=_E(2015), 

1595 xform=_X( -25.9, -9.0, 109.3, -5.39, 2.21, 13.806, -20.38), 

1596 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1597_trfX(_ITRF89_, _ETRF2014_, epoch=_E(2015), 

1598 xform=_X( -30.9, -33.0, 147.3, -8.79, 2.21, 13.806, -20.38), 

1599 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1600_trfX(_ITRF88_, _ETRF2014_, epoch=_E(2015), 

1601 xform=_X( -25.9, 3.0, 171.3, -11.89, 2.11, 13.806, -20.38), 

1602 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79)) 

1603 

1604# see U{Altamimi, Z. "EUREF Technical Note 1: Relationship and Transformation between the International and 

1605# the European Terrestrial Reference Systems"<https://ERTS89.ENSG,IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 4, 

1606# U{Boucher, C. & Altamimi, Z. "Memo: Specifications for reference frame fixing in the analysis of a EUREF GPS 

1607# campaign" (2011) <https://ETRS89.ENSG.IGN.Fr/memo-V8.pdf>} and U{Altamimi, Z. "Key results of ITRF2014 and 

1608# implication to ETRS89 realization", EUREF2016<https://www.EUREF.EU/symposia/2016SanSebastian/01-02-Altamimi.pdf>}. 

1609_trfX(_ITRF2020_, _ETRF2000_, epoch=_E(2015), 

1610 xform=_X( 53.8, 51.8, -82.2, 2.25, 2.106, 12.74, -20.592), 

1611 rates=_R( 0.1, _0_0, -1.7, 0.11, 0.081, 0.49, -0.792)) 

1612# _trfX(_ITRF2014_, _ETRF2000_, epoch=_E(2000), 

1613# xform=_X( 53.7, 51.2, -55.1, 1.02, 0.891, 5.39, -8.712), 

1614# rates=_R( 0.1, 0.1, -1.9, 0.11, 0.081, 0.49, -0.792)) 

1615_trfX(_ITRF2014_, _ETRF2000_, epoch=_E(2015), 

1616 xform=_X( 55.2, 52.7, -83.6, 2.67, 2.106, 12.74, -20.592), 

1617 rates=_R( 0.1, 0.1, -1.9, 0.11, 0.081, 0.49, -0.792)) 

1618# _trfX(_ITRF2008_, _ETRF2000_, epoch=_E(2000), 

1619# xform=_X( 52.1, 49.3, -58.5, 1.34, 0.891, 5.39, -8.712), 

1620# rates=_R( 0.1, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792)) 

1621_trfX(_ITRF2008_, _ETRF2000_, epoch=_E(2015), 

1622 xform=_X( 53.6, 50.8, -85.5, 2.54, 2.106, 12.74, -20.592), 

1623 rates=_R( 0.1, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792)) 

1624# _trfX(_ITRF2005_, _ETRF2000_, epoch=_E(2000), 

1625# xform=_X( 54.1, 50.2, -53.8, 0.4, 0.891, 5.39, -8.712), 

1626# rates=_R( -0.2, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792)) 

1627_trfX(_ITRF2005_, _ETRF2000_, epoch=_E(2015), 

1628 xform=_X( 51.1, 51.7, -80.8, 1.6, 2.106, 12.74, -20.592), 

1629 rates=_R( -0.2, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792)) 

1630# _trfX(_ITRF2000_, _ETRF2000_, epoch=_E(2000), 

1631# xform=_X( 54.0, 51.0, -48.0, _0_0, 0.891, 5.39, -8.712), 

1632# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.081, 0.49, -0.792)) 

1633_trfX(_ITRF2000_, _ETRF2000_, epoch=_E(2015), 

1634 xform=_X( 54.0, 51.0, -48.0, _0_0, 2.106, 12.74, -20.592), 

1635 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.081, 0.49, -0.792)) 

1636_trfX(_ITRF97_, _ETRF2000_, epoch=_E(2015), 

1637 xform=_X( 47.3, 55.7, -4.3, -1.73, 2.106, 12.74, -20.952), 

1638 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1639_trfX(_ITRF96_, _ETRF2000_, epoch=_E(2015), 

1640 xform=_X( 47.3, 55.7, -4.3, -1.73, 2.106, 12.74, -20.952), 

1641 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1642_trfX(_ITRF94_, _ETRF2000_, epoch=_E(2015), 

1643 xform=_X( 47.3, 55.7, -4.3, -1.73, 2.106, 12.74, -20.952), 

1644 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1645_trfX(_ITRF93_, _ETRF2000_, epoch=_E(2015), 

1646 xform=_X( 119.6, 49.9, -10.9, -2.22, 5.466, 17.07, -21.342), 

1647 rates=_R( 2.9, 0.2, 0.6, -0.01, 0.191, 0.68, -0.862)) 

1648_trfX(_ITRF92_, _ETRF2000_, epoch=_E(2015), 

1649 xform=_X( 39.3, 53.7, 3.7, -1.02, 2.106, 12.74, -20.952), 

1650 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1651_trfX(_ITRF91_, _ETRF2000_, epoch=_E(2015), 

1652 xform=_X( 27.3, 39.7, 9.7, -2.42, 2.106, 12.74, -20.952), 

1653 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1654_trfX(_ITRF90_, _ETRF2000_, epoch=_E(2015), 

1655 xform=_X( 29.3, 43.7, 25.7, -2.72, 2.106, 12.74, -20.952), 

1656 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1657_trfX(_ITRF89_, _ETRF2000_, epoch=_E(2015), 

1658 xform=_X( 24.3, 19.7, 63.7, -6.12, 2.106, 12.74, -20.952), 

1659 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1660_trfX(_ITRF88_, _ETRF2000_, epoch=_E(2015), 

1661 xform=_X( 29.3, 55.7, 87.7, -9.22, 2.006, 12.74, -20.952), 

1662 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812)) 

1663 

1664# GDA2020 "Geocentric Datum of Australia 2020 Technical Manual", v1.5, 2020-12-09, Table 3.3 and 3.4 

1665# <https://www.ICSM.gov.AU/sites/default/files/2020-12/GDA2020%20Technical%20Manual%20V1.5_4.pdf> 

1666# (the GDA2020 xforms are different but the rates are the same as GDA94, further below) 

1667_trfX(_ITRF2014_, _GDA2020_, epoch=_E(2020), 

1668 xform=_P_0_0s, 

1669 rates=_R( _0_0, _0_0, _0_0, _0_0, 1.50379, 1.18346, 1.20716)) 

1670_trfX(_ITRF2008_, _GDA2020_, epoch=_E(2020), 

1671 xform=_X( 13.79, 4.55, 15.22, 2.5, 0.2808, 0.2677, -0.4638), 

1672 rates=_R( 1.42, 1.34, 0.9, 0.109, 1.5461, 1.182, 1.1551)) 

1673_trfX(_ITRF2005_, _GDA2020_, epoch=_E(2020), 

1674 xform=_X( 40.32, -33.85, -16.72, 4.286, -1.2893, -0.8492, -0.3342), 

1675 rates=_R( 2.25, -0.62, -0.56, 0.294, -1.4707, -1.1443, -1.1701)) 

1676_trfX(_ITRF2000_, _GDA2020_, epoch=_E(2020), 

1677 xform=_X(-105.52, 51.58, 231.68, 3.55, 4.2175, 6.3941, 0.8617), 

1678 rates=_R( -4.66, 3.55, 11.24, 0.249, 1.7454, 1.4868, 1.224)) 

1679 

1680# see Table 2 in U{Dawson, J. & Woods, A. "ITRF to GDA94 coordinate transformations", Journal of Applied 

1681# Geodesy 4 (2010), 189-199<https://www.ResearchGate.net/publication/258401581_ITRF_to_GDA94_coordinate_transformations>} 

1682# (note, sign of rotations for GDA94 reversed as "Australia assumes rotation to be of coordinate axes", 

1683# rather than the more conventional "position around the coordinate axes") 

1684_trfX(_ITRF2008_, _GDA94_, epoch=_E(1994), 

1685 xform=_X( -84.68, -19.42, 32.01, 9.71, -0.4254, 2.2578, 2.4015), 

1686 rates=_R( 1.42, 1.34, 0.9, 0.109, 1.5461, 1.182, 1.1551)) 

1687_trfX(_ITRF2005_, _GDA94_, epoch=_E(1994), 

1688 xform=_X( -79.73, -6.86, 38.03, 6.636, 0.0351, -2.1211, -2.1411), 

1689 rates=_R( 2.25, -0.62, -0.56, 0.294, -1.4707, -1.1443, -1.1701)) 

1690_trfX(_ITRF2000_, _GDA94_, epoch=_E(1994), 

1691 xform=_X( -45.91, -29.85, -20.37, 7.07, -1.6705, 0.4594, 1.9356), 

1692 rates=_R( -4.66, 3.55, 11.24, 0.249, 1.7454, 1.4868, 1.224)) 

1693 

1694# see U{Quinsy QPS<https://confluence.QPS.NL/qinsy/files/latest/en/182618383/182618384/1/1579182881000/ 

1695# ITRF_Transformation_Parameters.xlsx>}, sheets ITRF and NAD83 and Pearson, C. & Snay, R. U{"Introducing 

1696# HTDP 3.1 to transform coordinates across time and spatial reference frames"<https://Geodesy.NOAA.gov/ 

1697# TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 7th column 

1698_trfX(_ITRF2008_, _NAD83_, epoch=_E(1997), 

1699 xform=_X( 993.43, -1903.31, -526.55, 1.71504, -25.91467, -9.42645, -11.59935), 

1700 rates=_R( 0.79, -0.6, -1.34, -0.10201, -0.06667, 0.75744, 0.05133)) 

1701# see U{Quinsy QPS<https://confluence.QPS.NL/qinsy/files/latest/en/182618383/182618384/1/1579182881000/ 

1702# ITRF_Transformation_Parameters.xlsx>}, sheets ITRF and NAD83 

1703_trfX(_ITRF2005_, _NAD83_, epoch=_E(1997), 

1704 xform=_X( 996.3, -1902.4, -521.9, 0.775, -25.915, -9.426, -11.599), 

1705 rates=_R( 0.5, -0.6, -1.3, -0.10201, -0.06667, 0.75744, 0.05133)) 

1706# see U{Solar, T. & Snay, R.A. "Transforming Positions and Velocities between the International Terrestrial Reference 

1707# Frame of 2000 and North American Datum of 1983" (2004)<https://www.NGS.NOAA.gov/CORS/Articles/SolerSnayASCE.pdf>} 

1708_trfX(_ITRF2000_, _NAD83_, epoch=_E(1997), # note NAD83(CORS96) 

1709 xform=_X( 995.6, -1901.3, -521.5, 0.615, -25.915, -9.426, -11.599), 

1710 rates=_R( 0.7, -0.7, _0_5, -0.182, -0.06667, 0.75744, 0.05133)) 

1711_trfX(_ITRF90_, _NAD83_, epoch=_E(1997), 

1712 xform=_X( 973.0, -1919.2, -482.9, -0.9, -25.79, -9.65, -11.66), 

1713 rates=_R( _0_0, _0_0, _0_0, _0_0, -0.053, 0.742, 0.032)) 

1714_trfX(_ITRF90_, _WGS84_, epoch=_E(1984), # coverage 

1715 xform=_X( 60.0, -517.0, -223.0, -11.0, 18.3, -0.3, 7.0), 

1716 rates=_P_0_0s) 

1717 

1718# equivalents U{"Transformations Between NAD83 and WGS84"<https://www.NGS.NOAA.gov/CORS/Articles/WGS84NAD83.pdf>} 

1719trfXform(_NAD83cors96_, _NAD83_, epoch=_E(1997), xform=_P_0_0s, rates=_P_0_0s) 

1720trfXform(_WGS84g1150_, _ITRF2000_, epoch=_E(2004), xform=_P_0_0s, rates=_P_0_0s) 

1721 

1722del _E, _Es, _i, _P, _P_0_0s, _R, _Rs, _X, _Xs 

1723 

1724if __name__ == '__main__': 

1725 

1726 def _main(): 

1727 from pygeodesy.basics import _args_kwds_names 

1728 from pygeodesy.interns import _COLONSPACE_,_COMMA_, _NL_, _NLATvar_, _vs_ 

1729 from pygeodesy.lazily import printf 

1730 from time import localtime 

1731 

1732 D = date2epoch.__name__ 

1733 E = epoch2date.__name__ 

1734 y = localtime()[0] 

1735 for m in range(1, 13): 

1736 for d in (1, 15, _mDays[m] - 1, _mDays[m]): 

1737 f = '%s(%d,%3d,%3d)' % (D, y, m, d) 

1738 e = date2epoch(y, m, d) 

1739 t = epoch2date(e) 

1740 x = NN if t == (y, m, d) else _STAR_ 

1741 e = '%.3f' % (e,) 

1742 e = '%s, %s(%s)' % (e, E, e) 

1743 t = '%d,%3d,%3d' % t 

1744 printf('# %s = %s = %s %s', f, e, t, x) 

1745 

1746 # __doc__ of this file, force all into registery 

1747 def _RFs(): 

1748 yield NN 

1749 for t in RefFrames.toRepr(all=True).split(_NL_): 

1750 t = t.strip(_COMMA_) 

1751 n = t.split(_COLONSPACE_)[0].split(_DOT_)[1] 

1752 r = RefFrames.get(n) 

1753 x = len(r.Xforms()), -len(r.Xforms(inverse=True)) 

1754 yield '%s .Xforms=%s' % (t, x) 

1755 

1756 printf(_NLATvar_.join(sorted(_RFs())), nt=1) 

1757 

1758 X, t = (), 0 # all form 

1759 for r in RefFrames.values(): 

1760 X += tuple(r._Xto.values()) 

1761 for X in sorted(X): 

1762 t += 1 

1763 printf('#%4d %-24s xform=%r', t, X.name, X.xform) 

1764 printf('#%29s rates=%r', _SPACE_, X.rates) 

1765 

1766 t = _args_kwds_names(Transform.__init__) 

1767 for n in TRFXform7Tuple._Names_: 

1768 if n not in t: 

1769 raise AssertionError(_SPACE_(n, _vs_, t)) 

1770 

1771 _main() 

1772 del _main 

1773 

1774# **) MIT License 

1775# 

1776# Copyright (C) 2016-2024 -- mrJean1 at Gmail -- All Rights Reserved. 

1777# 

1778# Permission is hereby granted, free of charge, to any person obtaining a 

1779# copy of this software and associated documentation files (the "Software"), 

1780# to deal in the Software without restriction, including without limitation 

1781# the rights to use, copy, modify, merge, publish, distribute, sublicense, 

1782# and/or sell copies of the Software, and to permit persons to whom the 

1783# Software is furnished to do so, subject to the following conditions: 

1784# 

1785# The above copyright notice and this permission notice shall be included 

1786# in all copies or substantial portions of the Software. 

1787# 

1788# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 

1789# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

1790# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 

1791# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 

1792# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 

1793# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 

1794# OTHER DEALINGS IN THE SOFTWARE. 

1795 

1796# % python -m pygeodesy.trf 

1797# 

1798# date2epoch(2024, 1, 1) = 2024.003, epoch2date(2024.003) = 2024, 1, 1 

1799# date2epoch(2024, 1, 15) = 2024.041, epoch2date(2024.041) = 2024, 1, 15 

1800# date2epoch(2024, 1, 30) = 2024.082, epoch2date(2024.082) = 2024, 1, 30 

1801# date2epoch(2024, 1, 31) = 2024.085, epoch2date(2024.085) = 2024, 1, 31 

1802# date2epoch(2024, 2, 1) = 2024.087, epoch2date(2024.087) = 2024, 2, 2 * 

1803# date2epoch(2024, 2, 15) = 2024.126, epoch2date(2024.126) = 2024, 2, 16 * 

1804# date2epoch(2024, 2, 28) = 2024.161, epoch2date(2024.161) = 2024, 2, 28 

1805# date2epoch(2024, 2, 29) = 2024.164, epoch2date(2024.164) = 2024, 3, 1 * 

1806# date2epoch(2024, 3, 1) = 2024.167, epoch2date(2024.167) = 2024, 3, 2 * 

1807# date2epoch(2024, 3, 15) = 2024.205, epoch2date(2024.205) = 2024, 3, 16 * 

1808# date2epoch(2024, 3, 30) = 2024.246, epoch2date(2024.246) = 2024, 3, 31 * 

1809# date2epoch(2024, 3, 31) = 2024.249, epoch2date(2024.249) = 2024, 4, 1 * 

1810# date2epoch(2024, 4, 1) = 2024.251, epoch2date(2024.251) = 2024, 4, 1 

1811# date2epoch(2024, 4, 15) = 2024.290, epoch2date(2024.290) = 2024, 4, 15 

1812# date2epoch(2024, 4, 29) = 2024.328, epoch2date(2024.328) = 2024, 4, 29 

1813# date2epoch(2024, 4, 30) = 2024.331, epoch2date(2024.331) = 2024, 4, 30 

1814# date2epoch(2024, 5, 1) = 2024.333, epoch2date(2024.333) = 2024, 5, 1 

1815# date2epoch(2024, 5, 15) = 2024.372, epoch2date(2024.372) = 2024, 5, 15 

1816# date2epoch(2024, 5, 30) = 2024.413, epoch2date(2024.413) = 2024, 5, 30 

1817# date2epoch(2024, 5, 31) = 2024.415, epoch2date(2024.415) = 2024, 6, 1 * 

1818# date2epoch(2024, 6, 1) = 2024.418, epoch2date(2024.418) = 2024, 6, 2 * 

1819# date2epoch(2024, 6, 15) = 2024.456, epoch2date(2024.456) = 2024, 6, 16 * 

1820# date2epoch(2024, 6, 29) = 2024.495, epoch2date(2024.495) = 2024, 6, 30 * 

1821# date2epoch(2024, 6, 30) = 2024.497, epoch2date(2024.497) = 2024, 7, 1 * 

1822# date2epoch(2024, 7, 1) = 2024.500, epoch2date(2024.500) = 2024, 7, 1 

1823# date2epoch(2024, 7, 15) = 2024.538, epoch2date(2024.538) = 2024, 7, 16 * 

1824# date2epoch(2024, 7, 30) = 2024.579, epoch2date(2024.579) = 2024, 7, 30 

1825# date2epoch(2024, 7, 31) = 2024.582, epoch2date(2024.582) = 2024, 7, 31 

1826# date2epoch(2024, 8, 1) = 2024.585, epoch2date(2024.585) = 2024, 8, 1 

1827# date2epoch(2024, 8, 15) = 2024.623, epoch2date(2024.623) = 2024, 8, 15 

1828# date2epoch(2024, 8, 30) = 2024.664, epoch2date(2024.664) = 2024, 8, 31 * 

1829# date2epoch(2024, 8, 31) = 2024.667, epoch2date(2024.667) = 2024, 9, 1 * 

1830# date2epoch(2024, 9, 1) = 2024.669, epoch2date(2024.669) = 2024, 9, 2 * 

1831# date2epoch(2024, 9, 15) = 2024.708, epoch2date(2024.708) = 2024, 9, 16 * 

1832# date2epoch(2024, 9, 29) = 2024.746, epoch2date(2024.746) = 2024, 9, 30 * 

1833# date2epoch(2024, 9, 30) = 2024.749, epoch2date(2024.749) = 2024, 10, 1 * 

1834# date2epoch(2024, 10, 1) = 2024.751, epoch2date(2024.751) = 2024, 10, 1 

1835# date2epoch(2024, 10, 15) = 2024.790, epoch2date(2024.790) = 2024, 10, 15 

1836# date2epoch(2024, 10, 30) = 2024.831, epoch2date(2024.831) = 2024, 10, 30 

1837# date2epoch(2024, 10, 31) = 2024.833, epoch2date(2024.833) = 2024, 10, 31 

1838# date2epoch(2024, 11, 1) = 2024.836, epoch2date(2024.836) = 2024, 11, 1 

1839# date2epoch(2024, 11, 15) = 2024.874, epoch2date(2024.874) = 2024, 11, 15 

1840# date2epoch(2024, 11, 29) = 2024.913, epoch2date(2024.913) = 2024, 11, 29 

1841# date2epoch(2024, 11, 30) = 2024.915, epoch2date(2024.915) = 2024, 12, 1 * 

1842# date2epoch(2024, 12, 1) = 2024.918, epoch2date(2024.918) = 2024, 12, 2 * 

1843# date2epoch(2024, 12, 15) = 2024.956, epoch2date(2024.956) = 2024, 12, 16 * 

1844# date2epoch(2024, 12, 30) = 2024.997, epoch2date(2024.997) = 2024, 12, 31 * 

1845# date2epoch(2024, 12, 31) = 2025.000, epoch2date(2025.000) = 2025, 1, 1 * 

1846 

1847# 1 WGS84g1150@2004xITRF2000 xform=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1848# rates=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1849# 2 NAD83cors96@1997xNAD83 xform=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1850# rates=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1851# 3 ITRF88@2015xETRF2014 xform=xform(tx=-25.9, ty=3.0, tz=171.3, s=-11.89, sx=2.11, sy=13.806, sz=-20.38) 

1852# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1853# 4 ITRF89@2015xETRF2000 xform=xform(tx=24.3, ty=19.7, tz=63.7, s=-6.12, sx=2.106, sy=12.74, sz=-20.952) 

1854# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1855# 5 ITRF89@2015xETRF2014 xform=xform(tx=-30.9, ty=-33.0, tz=147.3, s=-8.79, sx=2.21, sy=13.806, sz=-20.38) 

1856# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1857# 6 ITRF89@2015xETRF2020 xform=xform(tx=32.3, ty=33.9, tz=-148.7, s=9.21, sx=2.236, sy=13.494, sz=-19.218) 

1858# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1859# 7 ITRF89@1989xETRF89 xform=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1860# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.11, sy=0.57, sz=-0.71) 

1861# 8 ITRF90@1984xWGS84 xform=xform(tx=60.0, ty=-517.0, tz=-223.0, s=-11.0, sx=18.3, sy=-0.3, sz=7.0) 

1862# rates=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1863# 9 ITRF90@2015xETRF2000 xform=xform(tx=29.3, ty=43.7, tz=25.7, s=-2.72, sx=2.106, sy=12.74, sz=-20.952) 

1864# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1865# 10 ITRF90@1989xETRF90 xform=xform(tx=19.0, ty=28.0, tz=-23.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1866# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.11, sy=0.57, sz=-0.71) 

1867# 11 ITRF90@1997xNAD83 xform=xform(tx=973.0, ty=-1919.2, tz=-482.9, s=-0.9, sx=-25.79, sy=-9.65, sz=-11.66) 

1868# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=-0.053, sy=0.742, sz=0.032) 

1869# 12 ITRF91@2015xETRF2000 xform=xform(tx=27.3, ty=39.7, tz=9.7, s=-2.42, sx=2.106, sy=12.74, sz=-20.952) 

1870# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1871# 13 ITRF91@1989xETRF91 xform=xform(tx=21.0, ty=25.0, tz=-37.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1872# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.21, sy=0.52, sz=-0.68) 

1873# 14 ITRF92@2015xETRF2000 xform=xform(tx=39.3, ty=53.7, tz=3.7, s=-1.02, sx=2.106, sy=12.74, sz=-20.952) 

1874# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1875# 15 ITRF92@2015xETRF2014 xform=xform(tx=-15.9, ty=1.0, tz=87.3, s=-3.69, sx=2.21, sy=13.806, sz=-20.38) 

1876# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1877# 16 ITRF92@2015xETRF2020 xform=xform(tx=17.3, ty=-0.1, tz=-88.7, s=4.11, sx=2.236, sy=13.494, sz=-19.218) 

1878# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1879# 17 ITRF92@1989xETRF92 xform=xform(tx=38.0, ty=40.0, tz=-37.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1880# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.21, sy=0.52, sz=-0.68) 

1881# 18 ITRF93@2015xETRF2000 xform=xform(tx=119.6, ty=49.9, tz=-10.9, s=-2.22, sx=5.466, sy=17.07, sz=-21.342) 

1882# rates=rates(tx=2.9, ty=0.2, tz=0.6, s=-0.01, sx=0.191, sy=0.68, sz=-0.862) 

1883# 19 ITRF93@2015xETRF2014 xform=xform(tx=64.4, ty=-2.8, tz=72.7, s=-4.89, sx=5.57, sy=18.136, sz=-20.77) 

1884# rates=rates(tx=2.8, ty=0.1, tz=2.5, s=-0.12, sx=0.195, sy=0.721, sz=-0.84) 

1885# 20 ITRF93@2015xETRF2020 xform=xform(tx=-63.0, ty=3.7, tz=-74.1, s=5.31, sx=-1.124, sy=9.164, sz=-18.828) 

1886# rates=rates(tx=-2.8, ty=0.0, tz=-2.7, s=0.12, sx=-0.024, sy=0.329, sz=-0.683) 

1887# 21 ITRF93@1989xETRF93 xform=xform(tx=19.0, ty=53.0, tz=-21.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1888# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.32, sy=0.78, sz=-0.67) 

1889# 22 ITRF94@2015xETRF2000 xform=xform(tx=47.3, ty=55.7, tz=-4.3, s=-1.73, sx=2.106, sy=12.74, sz=-20.952) 

1890# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1891# 23 ITRF94@2015xETRF2014 xform=xform(tx=-7.9, ty=3.0, tz=79.3, s=-4.4, sx=2.21, sy=13.806, sz=-20.38) 

1892# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1893# 24 ITRF94@2015xETRF2020 xform=xform(tx=9.3, ty=-2.1, tz=-80.7, s=4.82, sx=2.236, sy=13.494, sz=-19.218) 

1894# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1895# 25 ITRF94@1989xETRF94 xform=xform(tx=41.0, ty=41.0, tz=-49.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1896# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.2, sy=0.5, sz=-0.65) 

1897# 26 ITRF96@1989xETRF96 xform=xform(tx=41.0, ty=41.0, tz=-49.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1898# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.2, sy=0.5, sz=-0.65) 

1899# 27 ITRF97@1989xETRF97 xform=xform(tx=41.0, ty=41.0, tz=-49.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1900# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.2, sy=0.5, sz=-0.65) 

1901# 28 ITRF2000@1994xGDA94 xform=xform(tx=-45.91, ty=-29.85, tz=-20.37, s=7.07, sx=-1.6705, sy=0.4594, sz=1.9356) 

1902# rates=rates(tx=-4.66, ty=3.55, tz=11.24, s=0.249, sx=1.7454, sy=1.4868, sz=1.224) 

1903# 29 ITRF2000@2015xETRF2000 xform=xform(tx=54.0, ty=51.0, tz=-48.0, s=0.0, sx=2.106, sy=12.74, sz=-20.592) 

1904# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.081, sy=0.49, sz=-0.792) 

1905# 30 ITRF88@2015xETRF2000 xform=xform(tx=29.3, ty=55.7, tz=87.7, s=-9.22, sx=2.006, sy=12.74, sz=-20.952) 

1906# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1907# 31 ITRF88@2015xETRF2020 xform=xform(tx=27.3, ty=-2.1, tz=-172.7, s=12.31, sx=2.336, sy=13.494, sz=-19.218) 

1908# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1909# 32 ITRF96@2015xETRF2000 xform=xform(tx=47.3, ty=55.7, tz=-4.3, s=-1.73, sx=2.106, sy=12.74, sz=-20.952) 

1910# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1911# 33 ITRF97@2015xETRF2000 xform=xform(tx=47.3, ty=55.7, tz=-4.3, s=-1.73, sx=2.106, sy=12.74, sz=-20.952) 

1912# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812) 

1913# 34 ITRF2000@2015xETRF2014 xform=xform(tx=-1.2, ty=-1.7, tz=35.6, s=-2.67, sx=2.21, sy=13.806, sz=-20.02) 

1914# rates=rates(tx=-0.1, ty=-0.1, tz=1.9, s=-0.11, sx=0.085, sy=0.531, sz=-0.77) 

1915# 35 ITRF90@2015xETRF2014 xform=xform(tx=-25.9, ty=-9.0, tz=109.3, s=-5.39, sx=2.21, sy=13.806, sz=-20.38) 

1916# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1917# 36 ITRF90@2015xETRF2020 xform=xform(tx=27.3, ty=9.9, tz=-110.7, s=5.81, sx=2.236, sy=13.494, sz=-19.218) 

1918# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1919# 37 ITRF91@2015xETRF2014 xform=xform(tx=-27.9, ty=-13.0, tz=93.3, s=-5.09, sx=2.21, sy=13.806, sz=-20.38) 

1920# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1921# 38 ITRF96@2015xETRF2014 xform=xform(tx=-7.9, ty=3.0, tz=79.3, s=-4.4, sx=2.21, sy=13.806, sz=-20.38) 

1922# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1923# 39 ITRF97@2015xETRF2014 xform=xform(tx=-7.9, ty=3.0, tz=79.3, s=-4.4, sx=2.21, sy=13.806, sz=-20.38) 

1924# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79) 

1925# 40 ITRF2000@2015xETRF2020 xform=xform(tx=2.6, ty=2.6, tz=-37.0, s=3.09, sx=2.236, sy=13.494, sz=-19.578) 

1926# rates=rates(tx=0.1, ty=0.2, tz=-2.1, s=0.11, sx=0.086, sy=0.519, sz=-0.753) 

1927# 41 ITRF91@2015xETRF2020 xform=xform(tx=29.3, ty=13.9, tz=-94.7, s=5.51, sx=2.236, sy=13.494, sz=-19.218) 

1928# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1929# 42 ITRF96@2015xETRF2020 xform=xform(tx=9.3, ty=-2.1, tz=-80.7, s=4.82, sx=2.236, sy=13.494, sz=-19.218) 

1930# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1931# 43 ITRF97@2015xETRF2020 xform=xform(tx=9.3, ty=-2.1, tz=-80.7, s=4.82, sx=2.236, sy=13.494, sz=-19.218) 

1932# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733) 

1933# 44 ITRF2000@2020xGDA2020 xform=xform(tx=-105.52, ty=51.58, tz=231.68, s=3.55, sx=4.2175, sy=6.3941, sz=0.8617) 

1934# rates=rates(tx=-4.66, ty=3.55, tz=11.24, s=0.249, sx=1.7454, sy=1.4868, sz=1.224) 

1935# 45 ITRF2000@1988xITRF88 xform=xform(tx=2.47, ty=1.15, tz=-9.79, s=8.95, sx=0.1, sy=0.0, sz=-0.18) 

1936# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02) 

1937# 46 ITRF2000@1988xITRF89 xform=xform(tx=2.97, ty=4.75, tz=-7.39, s=5.85, sx=0.0, sy=0.0, sz=-0.18) 

1938# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02) 

1939# 47 ITRF2000@1988xITRF90 xform=xform(tx=2.47, ty=2.35, tz=-3.59, s=2.45, sx=0.0, sy=0.0, sz=-0.18) 

1940# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02) 

1941# 48 ITRF2000@1988xITRF91 xform=xform(tx=26.7, ty=27.5, tz=-19.9, s=2.15, sx=0.0, sy=0.0, sz=-0.18) 

1942# rates=rates(tx=0.0, ty=-0.6, tz=-1.4, s=0.01, sx=0.0, sy=0.0, sz=0.02) 

1943# 49 ITRF2000@1988xITRF92 xform=xform(tx=1.47, ty=1.35, tz=-1.39, s=0.75, sx=0.0, sy=0.0, sz=-0.18) 

1944# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02) 

1945# 50 ITRF2000@1988xITRF93 xform=xform(tx=12.7, ty=6.5, tz=-20.9, s=1.95, sx=-0.39, sy=0.8, sz=-1.14) 

1946# rates=rates(tx=-2.9, ty=-0.2, tz=-0.6, s=0.01, sx=-0.11, sy=-0.19, sz=0.07) 

1947# 51 ITRF2000@1997xITRF94 xform=xform(tx=0.67, ty=0.61, tz=-1.85, s=1.55, sx=0.0, sy=0.0, sz=0.0) 

1948# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02) 

1949# 52 ITRF2000@1997xITRF96 xform=xform(tx=0.67, ty=0.61, tz=-1.85, s=1.55, sx=0.0, sy=0.0, sz=0.0) 

1950# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02) 

1951# 53 ITRF97@1997xITRF96 xform=xform(tx=-2.07, ty=-0.21, tz=9.95, s=-0.93496, sx=0.1267, sy=-0.22355, sz=-0.06065) 

1952# rates=rates(tx=0.69, ty=-0.1, tz=1.86, s=-0.19201, sx=0.01347, sy=-0.01514, sz=0.00027) 

1953# 54 ITRF2000@1997xITRF97 xform=xform(tx=0.67, ty=0.61, tz=-1.85, s=1.55, sx=0.0, sy=0.0, sz=0.0) 

1954# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=-0.02) 

1955# 55 ITRF2000@1997xNAD83 xform=xform(tx=995.6, ty=-1901.3, tz=-521.5, s=0.615, sx=-25.915, sy=-9.426, sz=-11.599) 

1956# rates=rates(tx=0.7, ty=-0.7, tz=0.5, s=-0.182, sx=-0.06667, sy=0.75744, sz=0.05133) 

1957# 56 ITRF2005@2015xETRF2000 xform=xform(tx=51.1, ty=51.7, tz=-80.8, s=1.6, sx=2.106, sy=12.74, sz=-20.592) 

1958# rates=rates(tx=-0.2, ty=0.1, tz=-1.8, s=0.08, sx=0.081, sy=0.49, sz=-0.792) 

1959# 57 ITRF2005@1989xETRF2005 xform=xform(tx=56.0, ty=48.0, tz=-37.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

1960# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.054, sy=0.518, sz=-0.781) 

1961# 58 ITRF2005@1994xGDA94 xform=xform(tx=-79.73, ty=-6.86, tz=38.03, s=6.636, sx=0.0351, sy=-2.1211, sz=-2.1411) 

1962# rates=rates(tx=2.25, ty=-0.62, tz=-0.56, s=0.294, sx=-1.4707, sy=-1.1443, sz=-1.1701) 

1963# 59 ITRF2005@1997xNAD83 xform=xform(tx=996.3, ty=-1902.4, tz=-521.9, s=0.775, sx=-25.915, sy=-9.426, sz=-11.599) 

1964# rates=rates(tx=0.5, ty=-0.6, tz=-1.3, s=-0.10201, sx=-0.06667, sy=0.75744, sz=0.05133) 

1965# 60 ITRF2005@2015xETRF2014 xform=xform(tx=-4.1, ty=-1.0, tz=2.8, s=-1.07, sx=2.21, sy=13.806, sz=-20.02) 

1966# rates=rates(tx=-0.3, ty=0.0, tz=0.1, s=-0.03, sx=0.085, sy=0.531, sz=-0.77) 

1967# 61 ITRF2005@2015xETRF2020 xform=xform(tx=5.5, ty=1.9, tz=-4.2, s=1.49, sx=2.236, sy=13.494, sz=-19.578) 

1968# rates=rates(tx=0.3, ty=0.1, tz=-0.3, s=0.03, sx=0.086, sy=0.519, sz=-0.753) 

1969# 62 ITRF2005@2020xGDA2020 xform=xform(tx=40.32, ty=-33.85, tz=-16.72, s=4.286, sx=-1.2893, sy=-0.8492, sz=-0.3342) 

1970# rates=rates(tx=2.25, ty=-0.62, tz=-0.56, s=0.294, sx=-1.4707, sy=-1.1443, sz=-1.1701) 

1971# 63 ITRF2005@2000xITRF2000 xform=xform(tx=0.1, ty=-0.8, tz=-5.8, s=0.4, sx=0.0, sy=0.0, sz=0.0) 

1972# rates=rates(tx=-0.2, ty=0.1, tz=-1.8, s=0.08, sx=0.0, sy=0.0, sz=0.0) 

1973# 64 ITRF2008@1994xGDA94 xform=xform(tx=-84.68, ty=-19.42, tz=32.01, s=9.71, sx=-0.4254, sy=2.2578, sz=2.4015) 

1974# rates=rates(tx=1.42, ty=1.34, tz=0.9, s=0.109, sx=1.5461, sy=1.182, sz=1.1551) 

1975# 65 ITRF2008@1997xNAD83 xform=xform(tx=993.43, ty=-1903.31, tz=-526.55, s=1.71504, sx=-25.91467, sy=-9.42645, sz=-11.59935) 

1976# rates=rates(tx=0.79, ty=-0.6, tz=-1.34, s=-0.10201, sx=-0.06667, sy=0.75744, sz=0.05133) 

1977# 66 ITRF96@1997xNAD83 xform=xform(tx=991.0, ty=-190.72, tz=-512.9, s=0.0, sx=25.79, sy=9.65, sz=11.66) 

1978# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0532, sy=-0.7423, sz=-0.0316) 

1979# 67 ITRF2008@2015xETRF2000 xform=xform(tx=53.6, ty=50.8, tz=-85.5, s=2.54, sx=2.106, sy=12.74, sz=-20.592) 

1980# rates=rates(tx=0.1, ty=0.1, tz=-1.8, s=0.08, sx=0.081, sy=0.49, sz=-0.792) 

1981# 68 ITRF2008@2015xETRF2014 xform=xform(tx=-1.6, ty=-1.9, tz=-1.9, s=-0.13, sx=2.21, sy=13.806, sz=-20.02) 

1982# rates=rates(tx=0.0, ty=0.0, tz=0.1, s=-0.03, sx=0.085, sy=0.531, sz=-0.77) 

1983# 69 ITRF2008@2015xETRF2020 xform=xform(tx=3.0, ty=2.8, tz=0.5, s=0.55, sx=2.236, sy=13.494, sz=-19.578) 

1984# rates=rates(tx=0.0, ty=0.1, tz=-0.3, s=0.03, sx=0.086, sy=0.519, sz=-0.753) 

1985# 70 ITRF2008@2020xGDA2020 xform=xform(tx=13.79, ty=4.55, tz=15.22, s=2.5, sx=0.2808, sy=0.2677, sz=-0.4638) 

1986# rates=rates(tx=1.42, ty=1.34, tz=0.9, s=0.109, sx=1.5461, sy=1.182, sz=1.1551) 

1987# 71 ITRF2008@2000xITRF2000 xform=xform(tx=-1.9, ty=-1.7, tz=-10.5, s=1.34, sx=0.0, sy=0.0, sz=0.0) 

1988# rates=rates(tx=0.1, ty=0.1, tz=-1.8, s=0.08, sx=0.0, sy=0.0, sz=0.0) 

1989# 72 ITRF2008@2000xITRF88 xform=xform(tx=22.8, ty=2.6, tz=-125.2, s=10.41, sx=0.1, sy=0.0, sz=0.06) 

1990# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

1991# 73 ITRF2008@2000xITRF89 xform=xform(tx=27.8, ty=38.6, tz=-101.2, s=7.31, sx=0.0, sy=0.0, sz=0.06) 

1992# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

1993# 74 ITRF2008@2000xITRF90 xform=xform(tx=22.8, ty=14.6, tz=-63.2, s=3.91, sx=0.0, sy=0.0, sz=0.06) 

1994# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

1995# 75 ITRF2008@2000xITRF91 xform=xform(tx=24.8, ty=18.6, tz=-47.2, s=3.61, sx=0.0, sy=0.0, sz=0.06) 

1996# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

1997# 76 ITRF2008@2000xITRF92 xform=xform(tx=12.8, ty=4.6, tz=-41.2, s=2.21, sx=0.0, sy=0.0, sz=0.06) 

1998# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

1999# 77 ITRF2008@2000xITRF93 xform=xform(tx=-24.0, ty=2.4, tz=-38.6, s=3.41, sx=-1.71, sy=-1.48, sz=-0.3) 

2000# rates=rates(tx=-2.8, ty=-0.1, tz=-2.4, s=0.09, sx=-0.11, sy=-0.19, sz=0.07) 

2001# 78 ITRF2008@2000xITRF94 xform=xform(tx=4.8, ty=2.6, tz=-33.2, s=2.92, sx=0.0, sy=0.0, sz=0.06) 

2002# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

2003# 79 ITRF2008@2000xITRF96 xform=xform(tx=4.8, ty=2.6, tz=-33.2, s=2.92, sx=0.0, sy=0.0, sz=0.06) 

2004# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

2005# 80 ITRF2008@2000xITRF97 xform=xform(tx=4.8, ty=2.6, tz=-33.2, s=2.92, sx=0.0, sy=0.0, sz=0.06) 

2006# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02) 

2007# 81 ITRF2008@2005xITRF2005 xform=xform(tx=-0.5, ty=-0.9, tz=-4.7, s=0.94, sx=0.0, sy=0.0, sz=0.0) 

2008# rates=rates(tx=0.3, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

2009# 82 ITRF2014@2015xETRF2000 xform=xform(tx=55.2, ty=52.7, tz=-83.6, s=2.67, sx=2.106, sy=12.74, sz=-20.592) 

2010# rates=rates(tx=0.1, ty=0.1, tz=-1.9, s=0.11, sx=0.081, sy=0.49, sz=-0.792) 

2011# 83 ITRF2014@2015xETRF2014 xform=xform(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=2.21, sy=13.806, sz=-20.02) 

2012# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.085, sy=0.531, sz=-0.77) 

2013# 84 ITRF2014@2015xETRF2020 xform=xform(tx=1.4, ty=0.9, tz=-1.4, s=0.42, sx=2.236, sy=13.494, sz=-19.578) 

2014# rates=rates(tx=0.0, ty=0.1, tz=-0.2, s=0.0, sx=0.086, sy=0.519, sz=-0.753) 

2015# 85 ITRF2014@2020xGDA2020 xform=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

2016# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=1.50379, sy=1.18346, sz=1.20716) 

2017# 86 ITRF2014@2010xITRF2000 xform=xform(tx=0.7, ty=1.2, tz=-26.1, s=2.12, sx=0.0, sy=0.0, sz=0.0) 

2018# rates=rates(tx=0.1, ty=0.1, tz=-1.9, s=0.11, sx=0.0, sy=0.0, sz=0.0) 

2019# 87 ITRF2014@2010xITRF2005 xform=xform(tx=2.6, ty=1.0, tz=-2.3, s=0.92, sx=0.0, sy=0.0, sz=0.0) 

2020# rates=rates(tx=0.3, ty=0.0, tz=-0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0) 

2021# 88 ITRF2014@2010xITRF2008 xform=xform(tx=1.6, ty=1.9, tz=2.4, s=-0.02, sx=0.0, sy=0.0, sz=0.0) 

2022# rates=rates(tx=0.0, ty=0.0, tz=-0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0) 

2023# 89 ITRF2014@2010xITRF88 xform=xform(tx=25.4, ty=-0.5, tz=-154.8, s=11.29, sx=0.1, sy=0.0, sz=0.26) 

2024# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2025# 90 ITRF2014@2010xITRF89 xform=xform(tx=30.4, ty=35.5, tz=-130.8, s=8.19, sx=0.0, sy=0.0, sz=0.26) 

2026# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2027# 91 ITRF2014@2010xITRF90 xform=xform(tx=25.4, ty=11.5, tz=-92.8, s=4.79, sx=0.0, sy=0.0, sz=0.26) 

2028# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2029# 92 ITRF2014@2010xITRF91 xform=xform(tx=27.4, ty=15.5, tz=-76.8, s=4.49, sx=0.0, sy=0.0, sz=0.26) 

2030# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2031# 93 ITRF2014@2010xITRF92 xform=xform(tx=15.4, ty=1.5, tz=-70.8, s=3.09, sx=0.0, sy=0.0, sz=0.26) 

2032# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2033# 94 ITRF2014@2010xITRF93 xform=xform(tx=-50.4, ty=3.3, tz=-60.2, s=4.29, sx=-2.81, sy=-3.38, sz=0.4) 

2034# rates=rates(tx=-2.8, ty=-0.1, tz=-2.5, s=0.12, sx=-0.11, sy=-0.19, sz=0.07) 

2035# 95 ITRF2014@2010xITRF94 xform=xform(tx=7.4, ty=-0.5, tz=-62.8, s=3.8, sx=0.0, sy=0.0, sz=0.26) 

2036# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2037# 96 ITRF2014@2010xITRF96 xform=xform(tx=7.4, ty=-0.5, tz=-62.8, s=3.8, sx=0.0, sy=0.0, sz=0.26) 

2038# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2039# 97 ITRF2014@2010xITRF97 xform=xform(tx=7.4, ty=-0.5, tz=-62.8, s=3.8, sx=0.0, sy=0.0, sz=0.26) 

2040# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2041# 98 ITRF2020@2015xETRF2000 xform=xform(tx=53.8, ty=51.8, tz=-82.2, s=2.25, sx=2.106, sy=12.74, sz=-20.592) 

2042# rates=rates(tx=0.1, ty=0.0, tz=-1.7, s=0.11, sx=0.081, sy=0.49, sz=-0.792) 

2043# 99 ITRF2020@2015xETRF2014 xform=xform(tx=-1.4, ty=-0.9, tz=1.4, s=0.42, sx=2.21, sy=13.806, sz=-20.02) 

2044# rates=rates(tx=0.0, ty=-0.1, tz=0.2, s=0.0, sx=0.085, sy=0.531, sz=-0.77) 

2045# 100 ITRF2020@2015xETRF2020 xform=xform(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=2.236, sy=13.494, sz=-19.578) 

2046# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.086, sy=0.519, sz=-0.753) 

2047# 101 ITRF2020@2015xITRF2000 xform=xform(tx=-0.2, ty=0.8, tz=-34.2, s=2.25, sx=0.0, sy=0.0, sz=0.0) 

2048# rates=rates(tx=0.1, ty=0.0, tz=-1.7, s=0.11, sx=0.0, sy=0.0, sz=0.0) 

2049# 102 ITRF2020@2015xITRF2005 xform=xform(tx=2.7, ty=0.1, tz=-1.4, s=0.65, sx=0.0, sy=0.0, sz=0.0) 

2050# rates=rates(tx=0.3, ty=-0.1, tz=0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0) 

2051# 103 ITRF2020@2015xITRF2008 xform=xform(tx=0.2, ty=1.0, tz=3.3, s=-0.29, sx=0.0, sy=0.0, sz=0.0) 

2052# rates=rates(tx=0.0, ty=-0.1, tz=0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0) 

2053# 104 ITRF2020@2015xITRF2014 xform=xform(tx=-1.4, ty=-0.9, tz=1.4, s=-0.42, sx=0.0, sy=0.0, sz=0.0) 

2054# rates=rates(tx=0.0, ty=-0.1, tz=0.2, s=0.0, sx=0.0, sy=0.0, sz=0.0) 

2055# 105 ITRF2020@2015xITRF88 xform=xform(tx=24.5, ty=-3.9, tz=-169.9, s=11.47, sx=0.1, sy=0.0, sz=0.36) 

2056# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2057# 106 ITRF2020@2015xITRF89 xform=xform(tx=29.5, ty=32.1, tz=-145.9, s=8.37, sx=0.0, sy=0.0, sz=0.36) 

2058# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2059# 107 ITRF2020@2015xITRF90 xform=xform(tx=24.5, ty=8.1, tz=-107.9, s=4.97, sx=0.0, sy=0.0, sz=0.36) 

2060# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2061# 108 ITRF2020@2015xITRF91 xform=xform(tx=26.5, ty=12.1, tz=-91.9, s=4.67, sx=0.0, sy=0.0, sz=0.36) 

2062# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2063# 109 ITRF2020@2015xITRF92 xform=xform(tx=14.5, ty=-1.9, tz=-85.9, s=3.27, sx=0.0, sy=0.0, sz=0.36) 

2064# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2065# 110 ITRF2020@2015xITRF93 xform=xform(tx=-65.8, ty=1.9, tz=-71.3, s=4.47, sx=-3.36, sy=-4.33, sz=0.75) 

2066# rates=rates(tx=-2.8, ty=-0.2, tz=-2.3, s=0.12, sx=-0.11, sy=-0.19, sz=0.07) 

2067# 111 ITRF2020@2015xITRF94 xform=xform(tx=6.5, ty=-3.9, tz=-77.9, s=3.98, sx=0.0, sy=0.0, sz=0.36) 

2068# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2069# 112 ITRF2020@2015xITRF96 xform=xform(tx=6.5, ty=-3.9, tz=-77.9, s=3.98, sx=0.0, sy=0.0, sz=0.36) 

2070# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02) 

2071# 113 ITRF2020@2015xITRF97 xform=xform(tx=6.5, ty=-3.9, tz=-77.9, s=3.98, sx=0.0, sy=0.0, sz=0.36) 

2072# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)