Coverage for pygeodesy/trf.py: 95%
622 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-04-25 13:15 -0400
« prev ^ index » next coverage.py v7.6.1, created at 2025-04-25 13:15 -0400
2# -*- coding: utf-8 -*-
4u'''I{Veness}' Terrestrial Reference Frames (TRF).
6Classes L{RefFrame}, registry L{RefFrames} and L{TRFError}.
8Transcoded from I{Chris Veness'} (C) 2006-2024 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>}.
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>}.
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}.
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>}.
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.
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>}.
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'''
72from pygeodesy.basics import _isin, map1, neg, isidentifier, isstr, _xinstanceof, \
73 _xscalar, typename
74from pygeodesy.constants import _float as _F, _0_0s, _0_0, _0_001, _0_5, _1_0
75from pygeodesy.datums import Datums, _earth_datum, _equall, _GDA2020_, _Names7, \
76 _negastr, Transform, _WGS84, _EWGS84, _operator
77# from pygeodesy.ellipsoids import _EWGS84 # from .datums
78from pygeodesy.errors import TRFError, _xattr, _xellipsoidall, _xkwds, _xkwds_item2
79# from pygeodesy.internals import typename # from .basics
80from pygeodesy.interns import MISSING, NN, _AT_, _COMMASPACE_, _conversion_, \
81 _datum_, _DMAIN_, _DOT_, _exists_, _invalid_, _MINUS_, \
82 _NAD83_, _no_, _PLUS_, _reframe_, _s_, _SPACE_, _to_, \
83 _STAR_, _vs_, _WGS84_, _x_, _intern as _i
84# from pygeodesy.lazily import _ALL_LAZY # from .units
85from pygeodesy.named import ADict, classname, _lazyNamedEnumItem as _lazy, _name2__, \
86 _Named, _NamedEnum, _NamedEnumItem, _NamedTuple, Fmt, unstr
87from pygeodesy.props import deprecated_method, property_doc_, Property_RO, property_RO
88# from pygeodesy.streprs import Fmt, unstr # from .named
89from pygeodesy.units import Epoch, Float, _ALL_LAZY
90# from pygeodesy.utily import sincos2d_
92from math import ceil as _ceil, fabs
93# import operator as _operator # from .datums
95__all__ = _ALL_LAZY.trf
96__version__ = '25.04.14'
98_EP0CH = Epoch(0, low=0)
99_Es = {_EP0CH: _EP0CH} # L{Epoch}s, deleted below
100_GRS80 = Datums.GRS80
101_inverse_ = 'inverse'
102_MAS = _MM = _PPB = Float # Units
103_MM2M = _0_001 # scale mm2m, ppB2ppM, mas2as
104_mDays = (0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, 0)
105_366_0 = _F(sum(_mDays))
106_rates_ = 'rates' # PYCHOK used!
107_Rs = {} # L{TRFXform7Tuple}s de-dup, deleted below
108_xform_ = 'xform' # PYCHOK used!
109_Xs = {} # L{TRFXform7Tuple}s de-dup, deleted below
111_ETRF88_ = _i('ETRF88')
112_ETRF89_ = _i('ETRF89')
113_ETRF90_ = _i('ETRF90')
114_ETRF91_ = _i('ETRF91')
115_ETRF92_ = _i('ETRF92')
116_ETRF93_ = _i('ETRF93')
117_ETRF94_ = _i('ETRF94')
118_ETRF96_ = _i('ETRF96')
119_ETRF97_ = _i('ETRF97')
120_ETRF2000_ = _i('ETRF2000')
121_ETRF2005_ = _i('ETRF2005')
122_ETRF2008_ = _i('ETRF2008')
123_ETRF2014_ = _i('ETRF2014')
124_ETRF2020_ = _i('ETRF2020')
125_GDA94_ = _i('GDA94')
126_ITRF_ = _i('ITRF')
127_ITRF88_ = _i('ITRF88')
128_ITRF89_ = _i('ITRF89')
129_ITRF90_ = _i('ITRF90')
130_ITRF91_ = _i('ITRF91')
131_ITRF92_ = _i('ITRF92')
132_ITRF93_ = _i('ITRF93')
133_ITRF94_ = _i('ITRF94')
134_ITRF96_ = _i('ITRF96')
135_ITRF97_ = _i('ITRF97')
136_ITRF2000_ = _i('ITRF2000')
137_ITRF2005_ = _i('ITRF2005')
138_ITRF2008_ = _i('ITRF2008')
139_ITRF2014_ = _i('ITRF2014')
140_ITRF2020_ = _i('ITRF2020')
141_NAD83cors96_ = _i('NAD83cors96')
142_WGS84g1150_ = _i('WGS84g1150')
143_WGS84g1674_ = _i('WGS84g1674')
144_WGS84g1762_ = _i('WGS84g1762')
147def _E(epoch): # deleted below
148 '''(INTERNAL) De-dup L{Epochs}s.
149 '''
150 e = Epoch(_F(epoch))
151 return _Es.setdefault(e, e) # PYCHOK del
154def _P(ps, name, _Ps): # deleted below
155 '''(INTERNAL) De-dup L{TRFXform7Tuple}s.
156 '''
157 t = TRFXform7Tuple(map(_F, ps), name=name)
158 return _Ps.setdefault(t, t)
161class RefFrame(_NamedEnumItem):
162 '''Terrestrial Reference Frame (TRF) parameters.
163 '''
164 _datum = _GRS80 # Datums.GRS80 or .WGS84 (L{Datum})
165 _epoch = _EP0CH # epoch, fractional year (L{Epoch})
167 def __init__(self, epoch, datum=_GRS80, name=NN):
168 '''New L{RefFrame}.
170 @arg epoch: Epoch, a fractional calendar year (C{scalar} or C{str}).
171 @arg datum: Datum or ellipsoid (L{Datum}, {Ellipsoid}, L{Ellipsoid2}
172 or L{a_f2Tuple}).
173 @kwarg name: Unique, non-empty name (C{str}).
175 @raise NameError: A L{RefFrame} with that B{C{name}} already exists.
177 @raise TRFError: Invalid B{C{epoch}}.
179 @raise TypeError: Invalid B{C{datum}}.
180 '''
181 if _isin(datum, None, _GRS80):
182 pass
183 elif _isin(datum, _WGS84, _EWGS84):
184 self._datum = _WGS84
185 else:
186 _earth_datum(self, datum, raiser=_datum_)
187 self._epoch = _Epoch(epoch)
188 self._Xto = {} # dict of Xforms
189 if name:
190 self._register(RefFrames, _stref(name=name))
192 def __eq__(self, other):
193 return isinstance(other, RefFrame) and other.epoch == self.epoch \
194 and other.datum == self.datum \
195 and other.name == self.name
197 def __lt__(self, other): # for sorting
198 return isinstance(other, RefFrame) and (self.name < other.name
199 or self.epoch < other.epoch)
201 @deprecated_method # PYCHOK Python 3.5+
202 def __matmul__(self, point):
203 '''DEPRECATED on 2024.02.16, use method C{B{point}.toRefFrame}.'''
204 return _toRefFrame(point, self)
206 @property_RO
207 def datum(self):
208 '''Get this reference frame's datum (L{Datum}).
209 '''
210 return self._datum
212 @property_RO
213 def ellipsoid(self):
214 '''Get this reference frame's ellipsoid (L{Ellipsoid} or L{Ellipsoid2}).
215 '''
216 return self._datum.ellipsoid
218 @Property_RO
219 def epoch(self):
220 '''Get this reference frame's epoch (C{Epoch}).
221 '''
222 return self._epoch
224 def toRefFrame(self, point, reframe2, **epoch_epoch2_name):
225 '''Convert an ellipsoidal point from this reframe and from C{epoch} to
226 an other C{reframe2} and C{epoch2 or epoch}.
228 @arg point: The point to convert (C{LatLon} or C{Cartesian}).
229 @arg reframe2: Reference frame to convert I{to} (L{RefFrame}).
230 @kwarg epoch_epoch2_name: Optional keyword arguments C{B{epoch}=None},
231 C{B{epoch2}=None} and C{B{name}=B{reframe2}.name}.
233 @return: A copy of the B{C{point}}, converted and renamed.
235 @raise TypeError: Invalid B{C{point}}.
237 @note: The C{B{point}.reframe} is overridden by this reframe and
238 C{B{point}.epoch} by C{B{epoch}} or this reframe.C{epoch}.
240 @see: Methods L{LatLon.toRefFrame<ellipsoidalBase.LatLonEllipsoidalBase.toRefFrame>}
241 and L{Cartesian.toRefFrame<ellipsoidalBase.CartesianEllipsoidalBase.toRefFrame>}
242 for more details.
243 '''
244 return _toRefFrame(point, reframe2, reframe=self, **_xkwds(epoch_epoch2_name,
245 name=_xattr(reframe2, name=self.name)))
247 def toStr(self, epoch=None, name=NN, **unused): # PYCHOK signature
248 '''Return this reference frame as a string.
250 @kwarg epoch: Override this reframe's epoch (C{scalar} or C{str}).
251 @kwarg name: Override name (C{str}) or C{None} to exclude the
252 reframe's name.
254 @return: This L{RefFrame}'s attributes (C{str}).
255 '''
256 D = self.datum
257 e = self.epoch if epoch is None else _Epoch(epoch)
258 t = (Fmt.EQUAL(name=repr(self._name__(name))),
259 Fmt.EQUAL(epoch=e),
260 Fmt.EQUAL(datum=_DOT_(classname(D) + _s_, D.name)))
261 return _COMMASPACE_.join(t[int(name is None):])
263 def Xform(self, reframe2):
264 '''Get the converter Xform I{from} this reference frame I{to} C{reframe2}.
266 @arg reframe2: Destination frame to convert I{to} (L{RefFrame} or C{str}).
268 @return: The L{TRFXform} instance or C{None} if not available.
270 @raise TypeError: Invalid B{C{reframe2}}.
271 '''
272 _xinstanceof(RefFrame, str, reframe2=reframe2)
273 n2 = reframe2 if isstr(reframe2) else reframe2.name
274 return self._Xto.get(n2, None)
276 def Xforms(self, inverse=False):
277 '''Return all Xforms converting I{from} or I{to} this reference frame or both.
279 @kwarg inverse: If C{True}, get all I{from} otherwise I{to} Xforms
280 I{un-inverted} (C{bool}) or if C{B{inverse}=2} (C{int})
281 get all I{to} Xforms I{inverted} plus all I{from}s.
283 @return: An L{ADict} of C{name=}L{TRFXform}s I{from} this reframe or if
284 C{B{inverse}=True} I{to} this reframe or both if C{B{inverse}=2}.
285 '''
286 return ADict(self._Xitems(inverse, RefFrames))
288 def _Xfrom(self, RFs, inverted):
289 '''(INTERNAL) Yield all 2-tuples C{(name, I{from} Xform)} converting I{to}
290 this reframe, inverted if C{inverted is True}.
291 '''
292 n2 = self.name
293 for n1, r in RFs.items():
294 X = r._Xto.get(n2, None)
295 if X:
296 yield n1, (X.inverse() if inverted else X)
298 def _Xitems(self, inverse, RFs): # in _eXhaustives, .Xforms
299 '''(INTERNAL) Yield all C{._Xfrom} and C{._Xto}'s as 2-tuple items.
300 '''
301 i = inverse == 2
302 if i or inverse:
303 for item in self._Xfrom(RFs, i):
304 yield item
305 if i or not inverse:
306 for item in self._Xto.items():
307 yield item
310class RefFrames(_NamedEnum):
311 '''(INTERNAL) L{RefFrame} registry, I{must} be a sub-class
312 to accommodate the L{_LazyNamedEnumItem} properties.
313 '''
314 def _Lazy(self, epoch, datum=_GRS80, name=NN):
315 '''(INTERNAL) Instantiate the L{RefFrame}.
316 '''
317 return RefFrame(epoch, datum, name=name)
319RefFrames = RefFrames(RefFrame) # PYCHOK singleton
320'''Some pre-defined L{RefFrame}s, all I{lazily} instantiated.'''
321# <https://GitHub.com/ChrisVeness/geodesy/blob/master/latlon-ellipsoidal-referenceframe.js>
322RefFrames._assert(
323 ETRF88 = _lazy(_ETRF88_, _E(1988)), # epoch, datum?
324 ETRF89 = _lazy(_ETRF89_, _E(1989)), # epoch, datum?
325 ETRF90 = _lazy(_ETRF90_, _E(1990)), # epoch, datum?
326 ETRF91 = _lazy(_ETRF91_, _E(1991)), # epoch, datum?
327 ETRF92 = _lazy(_ETRF92_, _E(1992)), # epoch, datum?
328 ETRF93 = _lazy(_ETRF93_, _E(1993)), # epoch, datum?
329 ETRF94 = _lazy(_ETRF94_, _E(1994)), # epoch, datum?
330 ETRF96 = _lazy(_ETRF96_, _E(1996)), # epoch, datum?
331 ETRF97 = _lazy(_ETRF97_, _E(1997)), # epoch, datum?
332 ETRF2000 = _lazy(_ETRF2000_, _E(2005)),
333 ETRF2005 = _lazy(_ETRF2005_, _E(2005)), # epoch, datum?
334 ETRF2008 = _lazy(_ETRF2008_, _E(2008)), # epoch, datum?
335 ETRF2014 = _lazy(_ETRF2014_, _E(2014)), # epoch, datum?
336 ETRF2020 = _lazy(_ETRF2020_, _E(2020)), # epoch, datum?
337 GDA94 = _lazy(_GDA94_, _E(1994)), # Australia
338 GDA2020 = _lazy(_GDA2020_, _E(2020)), # Australia
339 ITRF88 = _lazy(_ITRF88_, _E(1988)),
340 ITRF89 = _lazy(_ITRF89_, _E(1989)),
341 ITRF90 = _lazy(_ITRF90_, _E(1988)),
342 ITRF91 = _lazy(_ITRF91_, _E(1988)),
343 ITRF92 = _lazy(_ITRF92_, _E(1988)),
344 ITRF93 = _lazy(_ITRF93_, _E(1988)),
345 ITRF94 = _lazy(_ITRF94_, _E(1993)),
346 ITRF96 = _lazy(_ITRF96_, _E(1997)),
347 ITRF97 = _lazy(_ITRF97_, _E(1997)),
348 ITRF2000 = _lazy(_ITRF2000_, _E(1997)), # aka ITRF00
349 ITRF2005 = _lazy(_ITRF2005_, _E(2000)),
350 ITRF2008 = _lazy(_ITRF2008_, _E(2005)), # aka ITRF08
351 ITRF2014 = _lazy(_ITRF2014_, _E(2010)),
352 ITRF2020 = _lazy(_ITRF2020_, _E(2015)),
353 NAD83 = _lazy(_NAD83_, _E(1997)),
354 NAD83cors96 = _lazy(_NAD83cors96_, _E(1997)),
355 WGS84 = _lazy(_WGS84_, _E(1984), _WGS84),
356 WGS84g1150 = _lazy(_WGS84g1150_, _E(2001), _WGS84),
357 WGS84g1674 = _lazy(_WGS84g1674_, _E(2005), _WGS84),
358 WGS84g1762 = _lazy(_WGS84g1762_, _E(2005), _WGS84)) # same epoch
361class TransformXform(Transform):
362 '''Helmert transformation, extended with an C{Xform} TRF converter.
364 @see: L{Transform<datums.Transform>} and L{Xform<TRFXform>}.
365 '''
366 _Xform = None
368 def __init__(self, name=NN, **tx_ty_tz_s_sx_sy_sz): # PYCHOK signature
369 '''New L{TransformXform}.
371 @kwarg name: Optional name (C{str}), I{not registered}.
373 @see: L{Transform<datums.Transform>} for details.
375 @note: This L{TransformXform}'s name starts with C{"-"} iff
376 I{inversed}.
377 '''
378 Transform.__init__(self, **tx_ty_tz_s_sx_sy_sz)
379 if name:
380 self.name = name # unregistered
382 def __eq__(self, other):
383 return isinstance(other, TransformXform) and _equall(other, self)
385 def __hash__(self):
386 return Transform.__hash__(self)
388 def inverse(self, **name):
389 '''Return the inverse of this transform.
391 @kwarg name: Optional, unique C{B{name}=NN} (C{str}).
393 @return: Inverse (L{TransformXform}), unregistered.
394 '''
395 r = Transform.inverse(self, **name)
396 X = self.Xform
397 if X: # unregistered
398 r._Xform = X.inverse()
399 return r
401 def rename(self, name=NN):
402 '''Change this transform's name.
404 @arg name: New name (C{str}), overriding this transform's Xform's name.
406 @return: The previous name (C{str}).
407 '''
408 X = self.Xform
409 n = name or (X.toStr() if X else NN)
410 return Transform.rename(self, n)
412 def toRefFrame(self, point, **name): # PYCHOK signature
413 '''Convert an ellipsoidal point using this transform and Xform.
415 @arg point: The point to convert (C{Cartesian} or C{LatLon}).
416 @kwarg name: Optional C{B{name}=NN} (C{str}).
418 @return: A copy of the B{C{point}}, converted I{directly} to
419 this transform's Xform's C{refName2} and C{epoch}.
421 @note: The B{C{point}}'s original C{reframe} and C{epoch} are
422 I{ignored}, its C{datum} and C{height} are preserved
423 but I{not} taken into account.
424 '''
425 _ = _xellipsoidall(point)
426 p = point.dup() if self.isunity else point.toTransform(self)
427 X = self.Xform
428 if X: # see _toRefFrame below
429 p._reframe = X.reframe2
430 p._epoch = X.epoch
431 p.rename(self._name__(name))
432 return p
434 def toTransform(self, epoch1, **epoch2_inverse):
435 '''Return this transform observed at B{C{epoch1}} as a Helmert
436 L{TransformXform}, optionally at B{C{epoch2 or epoch1}}.
438 @arg epoch1: Epoch to observe I{from} (C{scalar}).
439 @kwarg epoch2_inverse: Optional C{B{epoch2}=None} to observe
440 I{to} and C{B{inverse}=False}, see method
441 L{toTransform<TRFXform.toTransform>} from
442 L{TRFXform}.
444 @return: The Helmert transform (L{TransformXform}).
446 @raise TRFError: Invalid B{C{epoch1}}, B{C{epoch2}} or
447 missing Xform.
448 '''
449 X = self.Xform
450 if X is None:
451 raise TRFError(Xform=X, txt=MISSING)
452 return X.toTransform(epoch1, **epoch2_inverse)
454 def transform2(self, x, y, z, vx=0, vy=0, vz=0, inverse=False, factor=_MM2M,
455 **Vector_and_kwds):
456 '''Transform a (cartesian) position I{with} velocities, forward or inverse.
458 @arg x: X coordinate (C{meter}).
459 @arg y: Y coordinate (C{meter}).
460 @arg z: Z coordinate (C{meter}).
461 @kwarg vx: X velocity (C{meter-per-year}).
462 @kwarg vy: Y velocity (C{meter-per-year}).
463 @kwarg vz: Z velocity (C{meter-per-year}).
464 @kwarg inverse: If C{True}, apply the inverse transform (C{bool}).
465 @kwarg factor: Factor to scale this Xform's C{rates} (C{scalar}),
466 default from C{milli-meter-} to C{meter-per-year},
467 from C{milli-arc-} to C{arc-seconds-per-year} and
468 from C{ppB-} to C{ppM-per-year}.
469 @kwarg Vector_and_kwds: An optional, (3-D) C{B{Vector}=None} or cartesian
470 class and additional C{B{Vector}} keyword arguments to
471 return the transformed position and the I{velocities}.
473 @return: 2-Tuple C{(position, velocities)}, the tranformed C{position}
474 and C{velocities}, each a L{Vector3Tuple}C{(x, y, z)} unless
475 some B{C{Vector_and_kwds}} are specified.
477 @note: If this transform's Xform is missing, the returned C{velocities}
478 are the given ones, I{un-transformed}.
480 @raise TypeError: Non-scalar B{C{factor}}.
482 @see: Soler, T. & Snay, R.A. "Transforming Positions and Velocities ...", U{equations
483 (4) and (5)<https://www.NGS.NOAA.gov/CORS/Articles/SolerSnayASCE.pdf>}
484 and HTDP functions C{VTRANF} and C{VTRANF_IERS} in file U{HTDP/hdtp.f
485 <https://Geodesy.NOAA.gov/TOOLS/Htdp/Htdp.shtml>}.
486 '''
487 p = self.transform(x, y, z, inverse=inverse, **Vector_and_kwds)
488 X = self.Xform
489 if X is not None:
490 r = X.rates * factor # equ (4) ...
491 # vx', vy', vz' = (.tx + x * .s + y * .rz - z * .ry,
492 # .ty - x * .rz + y * .s + z * .rx,
493 # .tz + x * .ry - y * .rx + z * .s)
494 # using counter-/clockwise .rx, .ry, and .rz
495 V = Transform(**dict(r.items())) # unregistered
496 _ = V._s_s1(0) # XXX r.s?
497 v = V.transform(p.x, p.y, p.z, inverse=inverse)
498 # + (vx, vy, vz) like HTDP
499 vx += v.x
500 vy += v.y
501 vz += v.z
502 v = p.dup(x=vx, y=vy, z=vz, name=NN(p.name, _vs_))
503 return p, v
505 def velocities(self, factor=_MM2M, **Vector_and_kwds):
506 '''Compute the X, Y and Z I{velocities} of this transform.
508 @kwarg factor: Factor to scale this Xform's C{rates} (C{scalar}),
509 default from C{milli-meter-} to C{meter-per-year},
510 from C{milli-arc-} to C{arc-seconds-per-year} and
511 from C{ppB-} to C{ppM-per-year}.
512 @kwarg Vector_and_kwds: An optional, (3-D) C{B{Vector}=None} or
513 cartesian class and additional C{B{Vector}} keyword
514 arguments to return the I{velocities}.
516 @return: A L{Vector3Tuple}C{(x, y, z)} unless some B{C{Vector_and_kwds}}
517 are specified or C{None} if this transform's Xform is missing.
519 @raise TypeError: Non-scalar B{C{factor}}.
521 @see: Altamimi, Z. "EUREF-TN-1-Jan-31-2024", U{Appendix A, equation (3)
522 <http://ETRS89.ENSG.IGN.FR/pub/EUREF-TN-1-Jan-31-2024.pdf>} and
523 method L{transform2<TransformXform.transform2>}.
524 '''
525 v = X = self.Xform
526 if X is not None:
527 r = X.rates * factor # equ (3) ...
528 V = self.dup(tx=r.sx, ty=r.sy, tz=r.sz, _Xform=None, # Xyy-dot
529 name=NN(self.name, _vs_)) # unregistered
530 _ = V._s_s1(0)
531 v = V.transform(r.tx, r.ty, r.tz, inverse=False, # Xyy
532 **Vector_and_kwds)
533 return v
535 @property_doc_(''' the Xform (L{TRFXform}).''')
536 def Xform(self):
537 '''Get this Helmert transform's Xform (L{TRFXform} or C{None}).
538 '''
539 return self._Xform
541 @Xform.setter # PYCHOK setter!
542 def Xform(self, Xform):
543 '''Set this Helmert transform's Xform (L{TRFXform}).
545 @raise TypeError: Invalid B{C{Xform}}.
546 '''
547 _xinstanceof(TRFXform, Xform=Xform)
548 self._Xform = Xform
551class TRFXform7Tuple(_NamedTuple):
552 '''7-Tuple C{(tx, ty, tz, s, sx, sy, sz)} of conversion parameters with
553 translations C{tx}, C{ty} and C{tz} in C{milli-meter}, scale C{s} in
554 C{ppB} and rotations C{sx}, C{sy} and C{sz} in C{milli-arc-seconds}.
555 For C{rates} all are C{units-per-year}.
557 @note: The parameters are also named as C{(Tx, Ty, Tz, D, Rx, Ry, Rz)}
558 or C{(T1, T2, T3, D, R1, R2, R3)}.
560 @see: Class L{TransformXform}'s matching keyword argument names.
561 '''
562 _Names_ = _Names7 # ('tx', 'ty', 'tz', _s_, 'sx', 'sy', 'sz') == TransformXform.__init__
563 _Units_ = (_MM, _MM, _MM, _PPB, _MAS, _MAS, _MAS)
565 def __add__(self, other):
566 return self._add_sub(other, True)
568 def __eq__(self, other):
569 return isinstance(other, TRFXform7Tuple) and _equall(other, self)
570 # PYCHOK and self.name == other.name
572 def __hash__(self):
573 return _NamedTuple.__hash__(self)
575 def __mul__(self, factor):
576 _xscalar(factor=factor)
577 return type(self)((x * factor for x in self), name=_STAR_) # .fsums._mul_op
579 def __neg__(self):
580 return self.inverse()
582 def __sub__(self, other):
583 return self._add_sub(other, False)
585 def _add_sub(self, other, p_):
586 '''(INTERNAL) Return C{this +/- other} L{TRFXform7Tuple}.
587 '''
588 _xinstanceof(TRFXform7Tuple, other=other)
589 op = _operator.add if p_ else _operator.sub
590 return type(self)(map(op, self, other), name=_PLUS_ if p_ else _MINUS_)
592 def inverse(self, name=NN):
593 '''Return the inverse of this transform.
595 @kwarg name: Optional name (C{str}).
597 @return: Inverse (L{TransformXform}).
598 '''
599 n = name or _negastr(self.name)
600 return type(self)(map(neg, self), name=n)
602 @Property_RO
603 def isunity(self):
604 '''Is this a C{unity, identity} transform (C{bool}).
605 '''
606 return not any(self)
609class TRFXform(_Named):
610 '''A Terrestrial Reference Frame (TRF) converter between two
611 reference frames observed at an C{epoch}.
612 '''
613 _epoch = _EP0CH
614 _epoch_d = _0_0
615 _indir_d = NN # refName
616 _inver_d = False
617 refName1 = \
618 refName2 = NN
619 rates = \
620 xform = None
622 def __init__(self, refName1, refName2, epoch=None, xform=None,
623 rates=None, name=NN):
624 '''New L{TRFXform} TRF converter.
626 @arg refName1: Source reframe (C{str}), converting I{from}.
627 @arg refName2: Destination reframe (C{str}), converting I{to}.
628 @kwarg epoch: Epoch, a fractional year (L{Epoch}, C{scalar} or C{str}).
629 @kwarg xform: I{Transform} parameters at B{C{epoch}} (L{TRFXform7Tuple}).
630 @kwarg rates: I{Rate} parameters (L{TRFXform7Tuple}), like B{C{xform}},
631 but in C{units-per-year}.
632 @kwarg name: Optional name (C{str}), overriding the default from method
633 L{toStr<TRFXform.toStr>}.
635 @raise TRFError: Invalid B{C{refName1}}, B{C{refName2}} or B{C{epoch}}.
637 @raise TypeError: Invalid B{C{xform}} or B{C{rates}}.
639 @see: Functions L{trfXform}, L{trfTransform0} and L{trfTransforms}.
640 '''
641 self.refName1 = _stref(refName1=refName1)
642 self.refName2 = _stref(refName2=refName2)
643 _xinstanceof(TRFXform7Tuple, xform=xform, rates=rates)
644 self.epoch = epoch
645 self.xform = xform
646 self.rates = rates
647 self.rename(name or self.toStr())
649 def __add__(self, other):
650 return self._add_sub(other, True)
652 def __eq__(self, other):
653 return isinstance(other, TRFXform) and other.epoch == self.epoch \
654 and other.xform == self.xform \
655 and other.rates == self.rates
657# def __hash__(self):
658# return hash((self.epoch, self.xform, self.rates))
660 def __lt__(self, other): # for sorting
661 return isinstance(other, TRFXform) and (self.refName1 < other.refName1
662 or self.refName2 < other.refName2
663 or self.epoch < other.epoch)
665 def __neg__(self):
666 return self.inverse()
668 def __repr__(self):
669 return self.toRepr()
671 def __str__(self):
672 return self.toStr()
674 def __sub__(self, other):
675 return self._add_sub(other, False)
677 def _add_sub(self, other, p_, *n1_n2_n): # in _indirects below
678 '''(INTERNAL) Summate C{this +/- other} Xform at C{this.epoch}.
680 @see: U{Appendix, Table 7, last column "Sum of the previous ..."
681 <https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf">}
682 '''
683 _xinstanceof(TRFXform, other=other)
684 X1 = self
685 e1 = X1.epoch
686 X2 = other.toEpoch(e1) # if other.epoch != e1 else other
688 n1, n2, n = n1_n2_n or _n1_n2_n3(X1, X2)
690 X = type(X1)(n1, n2, epoch=e1, xform=X1.xform._add_sub(X2.xform, p_),
691 rates=X1.rates._add_sub(X2.rates, p_),
692 name=_sumstr(X1.name, X2.name, p_))
693 X._epoch_d = X1.epoched + X2.epoched
694 X._indir_d = n # reframe?
695 X._inver_d = X1.inversed and X2.inversed
696 return X
698 def _at(self, epoch):
699 '''(INTERNAL) Return C{"self.nameB{@}epoch"}.
700 '''
701 n = self.name
702 if epoch != self.epoch:
703 _e = _AT_(NN, epoch)
704 if not n.endswith(_e):
705 n = NN(n, _e)
706 return n
708 @property_doc_(''' the epoch, fractional year (L{Epoch}).''')
709 def epoch(self):
710 '''Get the epoch (L{Epoch}).
711 '''
712 return self._epoch
714 @epoch.setter # PYCHOK setter!
715 def epoch(self, epoch):
716 '''Set the epoch (L{Epoch}, C{scalar} or C{str}).
718 @raise TRFError: Invalid B{C{epoch}}.
719 '''
720 e = _Epoch(epoch)
721 if self._epoch != e:
722 self.rename(self._at(e))
723 self._epoch = e
725 @property_RO
726 def epoched(self):
727 '''Get this Xform's aggregate I{epoch} deltas (C{float}).
728 '''
729 return self._epoch_d
731 @property_RO
732 def indirected(self):
733 '''Is this an I{indirected} Xform? (C{str} of space-separated
734 refNames) or C{NN}.
735 '''
736 return self._indir_d
738 def inverse(self, name=NN):
739 '''Return this Xform {inversed}, C{refName1} and C{-2} swapped.
741 @return: The inverse (L{TRFXform}).
742 '''
743 n = name or _negastr(self.name)
744 X = self.dup(refName1=self.refName2, xform=-self.xform,
745 refName2=self.refName1, rates=-self.rates,
746 name=n, _inver_d=not self.inversed)
747# X = type(self)(self.refName2, self.refName1, epoch= self.epoch,
748# xform=-self.xform,
749# rates=-self.rates, name=n)
750# if self.epoched:
751# X._epoch_d = self.epoched
752# if self.indirected:
753# X._indir_d = self.indirected
754# if not self.inversed:
755# X._inver_d = True
756 return X
758 @property_RO
759 def inversed(self):
760 '''Is this an I{inversed} Xform? (C{bool}).
761 '''
762 return self._inver_d
764 def _reframe(self, name, datum=_GRS80):
765 '''(INTERNAL) Get an un-/registered frame.
766 '''
767 r = RefFrames.get(name)
768 if r is None or r.datum != datum:
769 r = RefFrame(self.epoch, datum)
770 r.name = name # unregistered
771 return r
773 @property_RO
774 def reframe1(self):
775 '''Get the un-/registered I{from} frame (C{RefFrame}).
776 '''
777 return self._reframe(self.refName1)
779 @property_RO
780 def reframe2(self):
781 '''Get the un-/registered I{to} frame (C{RefFrame}).
782 '''
783 return self._reframe(self.refName2)
785 def rename(self, name=NN):
786 '''Change this Xform's name.
788 @arg name: New name (C{str}), overriding the base
789 name C{"refName1B{@}epochB{x}refName2"}.
791 @return: The old name (C{str}).
792 '''
793 return _Named.rename(self, name or self.toStr())
795 def toEpoch(self, epoch):
796 '''Convert this Xform to B{C{epoch}}, if needed.
798 @arg epoch: Epoch, fractional year (C{Epoch}, C{scalar}
799 or C{str}).
801 @return: This Xform or a copy converted to B{C{epoch}}.
803 @raise TRFError: Invalid B{C{epoch}}.
804 '''
805 e = _Epoch(epoch)
806 X, d = self, e - self.epoch
807 if d:
808 t = X.xform + X.rates * d
809 X = X.dup(epoch=e, xform=t, name=X._at(e))
810 X._epoch_d += fabs(d)
811 return X
813 def toHelmert(self, factor=_MM2M):
814 '''Return the Helmert transform from this Xform scaled accordingly.
816 @kwarg factor: Factor to scale this Xform's C{xform} (C{scalar}),
817 default from C{milli-meter-} to C{meter-}, from
818 C{milli-arc-} to C{arc-seconds} and from C{ppB}
819 to C{ppM}.
821 @return: The Helmert transform (L{TransformXform}).
822 '''
823 h = self.xform * factor
824 H = TransformXform(**dict(h.items()))
825 H.name = self.name # unregistered
826 H.Xform = self
827 return H
829 def toRefFrame(self, point, datum=_GRS80, **epoch_epoch2_name):
830 '''Convert an ellipsoidal point from this Xform's C{refName1} and
831 C{epoch} to this Xform's C{refName2} and C{epoch2 or epoch}.
833 @arg point: The point to convert (C{Cartesian} or C{LatLon}).
834 @kwarg datum: Optional datum to define a temporary L{RefFrame} from
835 this Xform's C{refName1} or C{refName2} (C{datum}).
836 @kwarg epoch_epoch2_name: Optional keyword arguments C{B{epoch}=None},
837 B{C{epoch2}=None} and C{B{name}=refName1}.
839 @return: A copy of the B{C{point}}, converted and renamed.
841 @see: Method L{RefFrame.toRefFrame} for more details.
842 '''
843 r1 = self._reframe(self.refName1, datum=datum)
844 r2 = self._reframe(self.refName2, datum=datum)
845 return _toRefFrame(point, r2, reframe=r1,
846 **_xkwds(epoch_epoch2_name, name=r1.name))
848 def toRepr(self, **unused): # PYCHOK signature
849 '''Return the represention of this Xform (C{str}).
850 '''
851 return unstr(self.classname, name=self.name, epoch=self.epoch)
853 def toStr(self, epoch=None, **unused): # PYCHOK signature
854 '''Return this Xform as C{"refName1B{@}epochB{x}refName2"} (C{str}).
856 @kwarg epoch: Epoch (C{Epoch}, C{scalar} or C{str}), overriding
857 this Xform's epoch.
858 '''
859 e = self.epoch if epoch is None else _Epoch(epoch)
860 return NN(_AT_(self.refName1, e), _x_, self.refName2)
862 def toTransform(self, epoch=None, epoch2=None, inverse=False):
863 '''Combine this Xform observed at B{C{epoch}} into a Helmert
864 L{TransformXform}, optionally at B{C{epoch2 or epoch}}.
866 @kwarg epoch: Epoch to observe I{from} (C{scalar}),
867 overriding this converter's epoch.
868 @kwarg epoch2: Optional epoch to observe I{to} (C{scalar}),
869 overriding B{C{epoch}}.
870 @kwarg inverse: Use the Xform's inverse (C{bool}).
872 @return: The Helmert transform (L{TransformXform}).
874 @raise TRFError: Invalid B{C{epoch}} or B{C{epoch2}}.
876 @see: Method L{toHelmert}.
877 '''
878 if epoch2 is None:
879 e = self.epoch if epoch is None else epoch
880 elif isinstance(epoch2, Epoch):
881 e = epoch2
882 else:
883 e = Epoch(epoch2=epoch2)
884 X = self.toEpoch(e)
885 if inverse:
886 X = X.inverse()
887 return X.toHelmert()
890def date2epoch(year, month, day):
891 '''Return the C{epoch} for a calendar day.
893 @arg year: Year of the date (C{scalar}).
894 @arg month: Month in the B{C{year}} (C{scalar}, 1..12).
895 @arg day: Day in the B{C{month}} (C{scalar}, 1..31).
897 @return: Epoch, the fractional year (C{float}).
899 @raise TRFError: Invalid B{C{year}}, B{C{month}} or B{C{day}}.
901 @note: Any B{C{year}} is considered a leap year, i.e. having
902 29 days in February.
903 '''
904 try:
905 y, m, d = map1(int, year, month, day)
906 if y > 0 and 1 <= m <= 12 and 1 <= d <= _mDays[m]:
907 e = y + float(sum(_mDays[:m]) + d) / _366_0
908 return Epoch(e, low=0)
910 raise ValueError() # _invalid_
911 except (TRFError, TypeError, ValueError) as x:
912 raise TRFError(year=year, month=month, day=day, cause=x)
915def _direct(n1, n2):
916 '''(INTERNAL) Get the C{n1} to C{n2} Xform or C{None}.
917 '''
918 r = RefFrames.get(n1)
919 return r._Xto.get(n2, None) if r else None
922def _Epoch(e, **kwds):
923 '''(INTERNAL) Get the C{Epoch(B{e})}.
924 '''
925 return e if isinstance(e, Epoch) and not kwds else Epoch(e, **kwds)
928def epoch2date(epoch):
929 '''Return the date for a reference frame C{epoch}.
931 @arg epoch: Fractional year (C{scalar}).
933 @return: 3-Tuple C{(year, month, day)}.
935 @raise TRFError: Invalid B{C{epoch}}.
937 @note: Any B{C{year}} is considered a leap year, i.e. having
938 29 days in February.
939 '''
940 e = Epoch(epoch, low=0)
941 y = int(e)
942 d = int(_ceil((e - y) * _366_0))
943 for m, n in enumerate(_mDays[1:]):
944 if d > n:
945 d -= n
946 else:
947 break
948 return y, (m + 1), max(1, d)
951def _eXhaustives(n1, n2):
952 '''(INTERNAL) Yield all I{coalesced} Xforms from C{n1} to {n2}
953 via I{any number of} intermediate reframe conversions.
954 '''
955 def _k2(item):
956 return -item[1].epoch # most recent first
958 R = dict(RefFrames)
959 r = R.pop(n1, None)
960 if r:
961 Xs = list(sorted(tuple(r._Xitems(2, R)), key=_k2))
962 while Xs:
963 n, X = Xs.pop(0)
964 if n == n2:
965 yield _n_pop(X)
966 else:
967 r = R.pop(n, None)
968 if r:
969 for n, x in r._Xitems(2, R):
970 Xs.append((n, X + x))
973def _indirects(n1, n2):
974 '''(INTERNAL) Yield all Xforms between C{n1} and C{n2} via
975 I{one} intermediate reframe C{n} conversion.
976 '''
977 def _X4(_Xto, n2):
978 _d = _direct
979 for n, X1 in _Xto.items():
980 X2 = _d(n, n2)
981 if X2:
982 yield X1, X2, n, True # X1 + X2
983 X2 = _d(n2, n)
984 if X2:
985 yield X1, X2, n, False # X1 - X2
987 r1 = RefFrames.get(n1)
988 if r1:
989 for X1, X2, n, p_ in _X4(r1._Xto, n2):
990 e1, e2 = X1.epoch, X2.epoch
991 if e1 < e2: # X1 to e2
992 X1 = X1.toEpoch(e2)
993# elif e1 > e2: # X2 to e1
994# X2 = X2.toEpoch(e1)
995 yield X1._add_sub(X2, p_, n1, n2, n)
998def _n1_n2_n3(X1, X2):
999 '''(INTERNAL) L{TRFXform._add_sub} helper.
1000 '''
1001 n = X1.indirected
1002 n = _SPACE_(n, X1.refName2) if n else X1.refName2
1003 return X1.refName1, X2.refName2, n
1006def _n_pop(X):
1007 '''(INTERNAL) Pop L{TRFXform.indirected}'s ends.
1008 '''
1009 p, n = None, X.indirected.split()
1010 if n and n[-1] == X.refName2:
1011 p = n.pop()
1012 if n and n[ 0] == X.refName1:
1013 p = n.pop(0)
1014 if p:
1015 X._indir_d = _SPACE_.join(n) if n else NN
1016 return X
1019def _reframe(**name_reframe):
1020 '''(INTERNAL) Get a C{reframe}.
1021 '''
1022 _, r = _xkwds_item2(name_reframe)
1023 if isstr(r) and r: # not NN
1024 r = RefFrames.get(r)
1025 if r and isinstance(r, RefFrame):
1026 return r
1027 raise TRFError(**name_reframe) # _invalid_
1030def _stref(**name_refname):
1031 '''(INTERNAL) Check a reference frame name.
1032 '''
1033 _, n = _xkwds_item2(name_refname)
1034 if isstr(n) and isidentifier(n):
1035 return str(n)
1036 raise TRFError(**name_refname) # _invalid_
1039def _sumstr(name1, name2, p_):
1040 '''(INTERNAL) "Sum" of C{name1 + ('+' if p_ else '-') + name2}.
1041 '''
1042 if name2:
1043 n = name2 if p_ else _negastr(name2)
1044 p = NN if n.startswith(_MINUS_) or \
1045 n.startswith(_PLUS_) else _PLUS_
1046 name1 = NN(name1, p, n)
1047 return name1
1050def _toRefFrame(point, reframe2, reframe=None, epoch=None,
1051 epoch2=None, **name_LatLon_kwds):
1052 '''(INTERNAL) Convert an ellipsoidal point to C{reframe2}
1053 and C{epoch2 or epoch or pont.epoch or reframe.epoch}.
1054 '''
1055 ll = _xellipsoidall(point)
1056 r1 = reframe or point.reframe
1057 if not r1:
1058 t = _SPACE_(_DOT_(repr(point), _reframe_), MISSING)
1059 raise TRFError(_no_(_conversion_), txt=t)
1061 _xinstanceof(RefFrame, reframe2=reframe2, reframe=r1)
1063 e1 = _Epoch(epoch or point.epoch or r1.epoch)
1064 e2 = e1 if epoch2 is None else Epoch(epoch2=epoch2)
1065 t0 = _toTransform0(r1.name, e1, reframe2.name, e2)
1066 if t0 is None:
1067 t = _SPACE_(typename(RefFrame), _AT_(r1.name, e1),
1068 _to_, _AT_(reframe2.name, e2))
1069 raise TRFError(_no_(_conversion_), txt=t)
1071 name, LatLon_kwds = _name2__(name_LatLon_kwds)
1072 if t0: # is not ()
1073 if t0.isunity:
1074 p = point.dup()
1075 elif point.datum:
1076 p = point.toCartesian() if ll else point
1077 p = p.toDatum( r1.datum).toTransform(t0) \
1078 .toDatum(reframe2.datum).toDatum(point.datum)
1079 if ll:
1080 p = p.toLatLon(LatLon=point.classof, **LatLon_kwds)
1081 elif ll: # and LatLon_kwds
1082 p = point.toTransform(t0, **LatLon_kwds)
1083 else:
1084 p = point.toTransform(t0)
1085 p._reframe = reframe2 # see TRFXform.toRefFrame above
1086 p._epoch = _xattr(t0.Xform, epoch=e2)
1087 p.rename(reframe2._name__(name))
1088 else:
1089 p = point.dup(_reframe=reframe2, # ditto
1090 _epoch=e2, name=name) if name else point
1091 return p
1094def _toTransform0(n1, e1, n2, e2, **indirect_inverse):
1095 '''(INTERNAL) Return a L{TransformXform}, 0-tuple or C{None}.
1096 '''
1097 if n1 == n2 and e1 == e2:
1098 return () # unity?
1100 for X in _toTransforms(n1, e1, n2, e2, **indirect_inverse):
1101 return X # first OK?
1103 if (n1.startswith(_ITRF_) and n2.startswith(_WGS84_)) or \
1104 (n2.startswith(_ITRF_) and n1.startswith(_WGS84_)): # and e1 == e2?
1105 return () # unity?
1107 return None
1110def _toTransforms(n1, e1, n2, e2, indirect=True, inverse=True, exhaust=False): # MCCABE 16
1111 '''(INTERNAL) Yield all possible Helmert transforms, if any.
1112 '''
1113 class Ts(list): # L{TransformXform}s de-dup
1114 def __call__(self, Xs, e1=e1, e2=e2, **inverse):
1115 for X in Xs:
1116 if X:
1117 T = X.toTransform(e1, epoch2=e2, **inverse)
1118 if T not in self:
1119 self.append(T)
1120 yield T
1122# def __contains__(self, T):
1123# _xinstanceof(TransformXform, T=T)
1124# return any(t == T for t in self)
1126 def _k(X):
1127 return -X.epoch # most recent first
1129 _Ts = Ts()
1131 for T in _Ts((_direct(n1, n2),), inverse=False):
1132 yield T
1133 if inverse:
1134 for T in _Ts((_direct(n2, n1),), inverse=True):
1135 yield T
1137 if indirect:
1138 for T in _Ts(sorted(_indirects(n1, n2), key=_k), inverse=False):
1139 yield T
1140 if inverse:
1141 for T in _Ts(sorted(_indirects(n2, n1), key=_k), inverse=True):
1142 yield T
1144 if exhaust:
1145 for T in _Ts(_eXhaustives(n1, n2), inverse=False):
1146 yield T
1147 for T in _Ts(_eXhaustives(n2, n1), inverse=True):
1148 yield T
1151def trfTransform0(reframe, reframe2, epoch=None, epoch2=None, indirect=True, inverse=True, exhaust=False):
1152 '''Get a Helmert transform to convert one C{reframe} observed at C{epoch}
1153 to an other C{reframe2} at observed at C{epoch2 or epoch}.
1155 @return: A L{TransformXform} instance, a C{0-tuple} for I{unity, identity} or
1156 C{None} if no conversion exists.
1158 @see: Function L{trfTransforms} for futher details.
1159 '''
1160 return _trfT0s(_toTransform0, reframe, reframe2, epoch, epoch2,
1161 indirect=indirect, inverse=inverse, exhaust=exhaust)
1164def trfTransforms(reframe, reframe2, epoch=None, epoch2=None, indirect=True, inverse=True, exhaust=False):
1165 '''Yield all Helmert transform to convert one C{reframe} observed at C{epoch}
1166 to an other C{reframe2} at observed at C{epoch2 or epoch}.
1168 @arg reframe: The frame to convert I{from} (L{RefFrame} or C{str}).
1169 @arg reframe2: The frame to convert I{to} (L{RefFrame} or C{str}).
1170 @arg epoch: Epoch to observe I{from} (L{Epoch}, C{scalar} or C{str}),
1171 otherwise C{B{reframe}}'s C{epoch}.
1172 @kwarg epoch2: Optional epoch to observe I{to} (L{Epoch}, C{scalar} or C{str}),
1173 otherwise B{C{epoch}}.
1174 @kwarg indirect: If C{True}, include transforms via I{one} intermediate reframe,
1175 otherwise only I{direct} B{C{reframe}} to B{C{reframe2}}
1176 transforms (C{bool}).
1177 @kwarg inverse: If C{True}, include inverse, otherwise only forward transforms
1178 (C{bool}).
1179 @kwarg exhaust: If C{True}, exhaustively generate all transforms, forward and
1180 inverse and via any number of intermediate reframes (C{bool}).
1182 @return: A L{TransformXform} instance for each available conversion, without
1183 duplicates.
1185 @raise TRFError: Invalid B{C{reframe}}, B{C{reframe2}}, B{C{epoch}} or B{C{epoch2}}.
1187 @raise TypeError: Invalid B{C{reframe}} or B{C{reframe2}}.
1188 '''
1189 return _trfT0s(_toTransforms, reframe, reframe2, epoch, epoch2,
1190 indirect=indirect, inverse=inverse, exhaust=exhaust)
1193def _trfT0s(_toT0s, reframe, reframe2, epoch, epoch2, **indirect_inverse_exhaust):
1194 '''(INTERNAL) Handle C{trfTransforms0} and C{trfTransforms} calls.
1195 '''
1196 r1 = _reframe(reframe=reframe)
1197 e1 = r1.epoch if epoch is None else _Epoch(epoch)
1198 r2 = _reframe(reframe2=reframe2)
1199 e2 = e1 if epoch2 is None else Epoch(epoch2=epoch2)
1200 return _toT0s(r1.name, e1, r2.name, e2, **indirect_inverse_exhaust)
1203def trfXform(reframe1, reframe2, epoch=None, xform=None, rates=None, raiser=True):
1204 '''Define a new Terrestrial Reference Frame (TRF) converter or get an
1205 existing one.
1207 @arg reframe1: Source frame (L{RefFrame} or C{str}), converting I{from}.
1208 @arg reframe2: Destination frame (L{RefFrame} or C{str}), converting I{to}.
1209 @kwarg epoch: Epoch, a fractional year (L{Epoch}, C{scalar} or C{str})
1210 or C{None} for C{B{reframe2}}'s epoch.
1211 @kwarg xform: I{Transform} parameters (L{TRFXform7Tuple}).
1212 @kwarg rates: I{Rate} parameters (L{TRFXform7Tuple}), as B{C{xform}},
1213 but in C{units-per-year}.
1214 @kwarg raiser: If C{False}, do not raise an error if the converter
1215 exists, replace it (C{bool}).
1217 @return: The new TRF converter (L{TRFXform}) or if no B{C{epoch}},
1218 B{C{xform}} and B{C{rates}} are given, return the existing
1219 one (L{TRFXform}) or C{None} if not available.
1221 @raise TRFError: Invalid B{C{reframe1}}, B{C{reframe2}}, B{C{epoch}},
1222 B{C{xform}} or B{C{rates}} or the TRF converter
1223 already exists.
1224 '''
1225 try:
1226 r1 = _reframe(reframe1=reframe1)
1227 r2 = _reframe(reframe2=reframe2)
1228 if epoch is None:
1229 if xform is rates is None:
1230 return r1._Xto.get(r2.name, None)
1231 e = r2.epoch
1232 else:
1233 e = _Epoch(epoch)
1234 return _trfX(r1.name, r2.name, raiser=raiser, epoch=e,
1235 xform=xform, rates=rates)
1236 except (TypeError, ValueError) as x:
1237 t = unstr(trfXform, reframe1, reframe2, epoch=epoch)
1238 raise TRFError(t, cause=x)
1241def _trfX(n1, n2, raiser=True, **epoch_xform_rates):
1242 '''(INTERNAL) New, I{unique} L{TRFXform} converter.
1243 '''
1244 r1 = RefFrames.get(n1)
1245 if r1 is None:
1246 raise ValueError(_invalid_)
1247 r2 = RefFrames.get(n2)
1248 if r2 is None:
1249 raise ValueError(_invalid_)
1250 if raiser:
1251 if n2 in r1._Xto:
1252 raise ValueError(_exists_)
1253 if n1 in r2._Xto:
1254 raise ValueError(_SPACE_(_inverse_, _exists_))
1255 r1._Xto[n2] = X = TRFXform(n1, n2, **epoch_xform_rates)
1256 return X
1259# def velocities2neu(vx, vy, vz, lat=0, lon=0):
1260# '''Convert X, Y, and Z I{velocities} to North, East, Up.
1261#
1262# @arg vx: X velocity (C{meter-per-time}).
1263# @arg vx: Y velocity (C{meter-per-time}).
1264# @arg vx: Z velocity (C{meter-per-time}).
1265# @kwarg lat: Latitude (C{degrees}).
1266# @kwarg lon: Longitude (C{degrees}).
1267#
1268# @return: 3-Tuple C{(vnorth, veast, vup)} with the
1269# North, East and Up velocities, same units
1270# as B{C{vx}, B{C{vy}} and B{C{vx}}.
1271# '''
1272# sa, ca, sb, cb = sincos2d_(lat, lon)
1273# ve = cb * vy - sb * vx
1274# v = cb * vx + sb * vy
1275# vn = ca * vz - sa * v
1276# vu = sa * vz + ca * v
1277# return vn, ve, vu
1280# def velocities2xyz(vn, ve, vu, lat=0, lon=0):
1281# '''Convert North, East and Up I{velocities} to X, Y, Z.
1282#
1283# @arg vn: North velocity (C{meter-per-time}).
1284# @arg ve: East velocity (C{meter-per-time}).
1285# @arg vu: Up velocity (C{meter-per-time}).
1286# @kwarg lat: Latitude (C{degrees}).
1287# @kwarg lon: Longitude (C{degrees}).
1288#
1289# @return: 3-Tuple C{(vx, vy, vz)} with the X, Y
1290# and Z velocities, same units as B{C{vn},
1291# B{C{ve}} and B{C{vu}}.
1292# '''
1293# sa, ca, sb, cb = sincos2d_(lat, lon)
1294# vz = ca * vn + sa * vu
1295# v = ca * vu - sa * vn
1296# vx = cb * v - sb * ve
1297# vy = sb * v + cb * ve
1298# return vx, vy, vz
1301def _X(*ps): # deleted below
1302 return _P(ps, _xform_, _Xs) # PYCHOK del
1305def _R(*ps): # deleted below
1306 return _P(ps, _rates_, _Rs) # PYCHOK del
1309_P_0_0s = TRFXform7Tuple(_0_0s(len(_Names7)), name='unity')
1311# TRF conversions specified as an epoch and 2 sets of 7 parameters. Most from Altamimi, Z. U{"EUREF Technical
1312# Note 1: Relationship and Transformation between the International and the European Terrestrial Reference
1313# Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Appendix A, more at U{Quinsy QPS <https://
1314# confluence.QPS.NL/qinsy/files/latest/en/182618383/182618384/1/1579182881000/ITRF_Transformation_Parameters.xlsx>}.
1315# See also U{Quinsy International Terrestrial Reference Frame 2014 (ITRF2014)<https://confluence.QPS.NL/qinsy/latest/
1316# en/international-terrestrial-reference-frame-2014-itrf2014-182618383.html>}.
1317_trfX(_ITRF2020_, _ITRF2014_, epoch=_E(2015), # <https://ITRF.IGN.Fr/docs/solutions/itrf2020/Transfo-ITRF2020_TRFs.txt>
1318 xform=_X( -1.4, -0.9, 1.4, -0.42, _0_0, _0_0, _0_0),
1319 rates=_R( _0_0, -0.1, 0.2, _0_0, _0_0, _0_0, _0_0))
1320_trfX(_ITRF2020_, _ITRF2008_, epoch=_E(2015),
1321 xform=_X( 0.2, 1.0, 3.3, -0.29, _0_0, _0_0, _0_0),
1322 rates=_R( _0_0, -0.1, 0.1, 0.03, _0_0, _0_0, _0_0))
1323_trfX(_ITRF2020_, _ITRF2005_, epoch=_E(2015),
1324 xform=_X( 2.7, 0.1, -1.4, 0.65, _0_0, _0_0, _0_0),
1325 rates=_R( 0.3, -0.1, 0.1, 0.03, _0_0, _0_0, _0_0))
1326_trfX(_ITRF2020_, _ITRF2000_, epoch=_E(2015),
1327 xform=_X( -0.2, 0.8, -34.2, 2.25, _0_0, _0_0, _0_0),
1328 rates=_R( 0.1, _0_0, -1.7, 0.11, _0_0, _0_0, _0_0))
1329_trfX(_ITRF2020_, _ITRF97_, epoch=_E(2015),
1330 xform=_X( 6.5, -3.9, -77.9, 3.98, _0_0, _0_0, 0.36),
1331 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1332_trfX(_ITRF2020_, _ITRF96_, epoch=_E(2015),
1333 xform=_X( 6.5, -3.9, -77.9, 3.98, _0_0, _0_0, 0.36),
1334 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1335_trfX(_ITRF2020_, _ITRF94_, epoch=_E(2015),
1336 xform=_X( 6.5, -3.9, -77.9, 3.98, _0_0, _0_0, 0.36),
1337 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1338_trfX(_ITRF2020_, _ITRF93_, epoch=_E(2015),
1339 xform=_X( -65.8, 1.9, -71.3, 4.47, -3.36, -4.33, 0.75),
1340 rates=_R( -2.8, -0.2, -2.3, 0.12, -0.11, -0.19, 0.07))
1341_trfX(_ITRF2020_, _ITRF92_, epoch=_E(2015),
1342 xform=_X( 14.5, -1.9, -85.9, 3.27, _0_0, _0_0, 0.36),
1343 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1344_trfX(_ITRF2020_, _ITRF91_, epoch=_E(2015),
1345 xform=_X( 26.5, 12.1, -91.9, 4.67, _0_0, _0_0, 0.36),
1346 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1347_trfX(_ITRF2020_, _ITRF90_, epoch=_E(2015),
1348 xform=_X( 24.5, 8.1, -107.9, 4.97, _0_0, _0_0, 0.36),
1349 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1350_trfX(_ITRF2020_, _ITRF89_, epoch=_E(2015),
1351 xform=_X( 29.5, 32.1, -145.9, 8.37, _0_0, _0_0, 0.36),
1352 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1353_trfX(_ITRF2020_, _ITRF88_, epoch=_E(2015),
1354 xform=_X( 24.5, -3.9, -169.9, 11.47, 0.1, _0_0, 0.36),
1355 rates=_R( 0.1, -0.6, -3.1, 0.12, _0_0, _0_0, 0.02))
1357# see U{Transformation Parameters ITRF2014<http://ITRF.IGN.Fr/doc_ITRF/Transfo-ITRF2014_ITRFs.txt>} and
1358# Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and
1359# the European Terrestrial Reference Systems"<https://ERTS89.ENSG,IFN.Fr/pub/EUREF-TN-1.pdf>} Appendix A.
1360_trfX(_ITRF2014_, _ITRF2008_, epoch=(2010), # <http://ITRF.ENSG.IGN.Fr/ITRF_solutions/2014/tp_14-08.php>
1361 xform=_X( 1.6, 1.9, 2.4, -0.02, _0_0, _0_0, _0_0),
1362 rates=_R( _0_0, _0_0, -0.1, 0.03, _0_0, _0_0, _0_0))
1363_trfX(_ITRF2014_, _ITRF2005_, epoch=_E(2010),
1364 xform=_X( 2.6, _1_0, -2.3, 0.92, _0_0, _0_0, _0_0),
1365 rates=_R( 0.3, _0_0, -0.1, 0.03, _0_0, _0_0, _0_0))
1366_trfX(_ITRF2014_, _ITRF2000_, epoch=_E(2010),
1367 xform=_X( 0.7, 1.2, -26.1, 2.12, _0_0, _0_0, _0_0),
1368 rates=_R( 0.1, 0.1, -1.9, 0.11, _0_0, _0_0, _0_0))
1369_trfX(_ITRF2014_, _ITRF97_, epoch=_E(2010),
1370 xform=_X( 7.4, -0.5, -62.8, 3.8, _0_0, _0_0, 0.26),
1371 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1372_trfX(_ITRF2014_, _ITRF96_, epoch=_E(2010),
1373 xform=_X( 7.4, -0.5, -62.8, 3.8, _0_0, _0_0, 0.26),
1374 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1375_trfX(_ITRF2014_, _ITRF94_, epoch=_E(2010),
1376 xform=_X( 7.4, -0.5, -62.8, 3.8, _0_0, _0_0, 0.26),
1377 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1378_trfX(_ITRF2014_, _ITRF93_, epoch=_E(2010),
1379 xform=_X( -50.4, 3.3, -60.2, 4.29, -2.81, -3.38, 0.4),
1380 rates=_R( -2.8, -0.1, -2.5, 0.12, -0.11, -0.19, 0.07))
1381_trfX(_ITRF2014_, _ITRF92_, epoch=_E(2010),
1382 xform=_X( 15.4, 1.5, -70.8, 3.09, _0_0, _0_0, 0.26),
1383 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1384_trfX(_ITRF2014_, _ITRF91_, epoch=_E(2010),
1385 xform=_X( 27.4, 15.5, -76.8, 4.49, _0_0, _0_0, 0.26),
1386 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1387_trfX(_ITRF2014_, _ITRF90_, epoch=_E(2010),
1388 xform=_X( 25.4, 11.5, -92.8, 4.79, _0_0, _0_0, 0.26),
1389 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1390_trfX(_ITRF2014_, _ITRF89_, epoch=_E(2010),
1391 xform=_X( 30.4, 35.5, -130.8, 8.19, _0_0, _0_0, 0.26),
1392 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1393_trfX(_ITRF2014_, _ITRF88_, epoch=_E(2010),
1394 xform=_X( 25.4, -0.5, -154.8, 11.29, 0.1, _0_0, 0.26),
1395 rates=_R( 0.1, -0.5, -3.3, 0.12, _0_0, _0_0, 0.02))
1397# Pearson, C. & Snay, R. U{"Introducing HTDP 3.1 to transform coordinates across time and spatial reference
1398# frames"<https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 1st and 2nd column
1399_trfX(_ITRF2008_, _ITRF2005_, epoch=_E(2005),
1400 xform=_X( -0.5, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0),
1401 rates=_R( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0))
1402# _trfX(_ITRF2008_, _ITRF2005_, epoch=_E(1997),
1403# xform=_X( -2.9, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0),
1404# rates=_R( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0))
1405# see U{Transformation Parameters ITRF2008<http://ITRF.IGN.Fr/doc_ITRF/Transfo-ITRF2008_ITRFs.txt>}
1406# _trfX(_ITRF2008_, _ITRF2005_, epoch=_E(2000), # <http://ITRF.ENSG.IGN.Fr/ITRF_solutions/2008/tp_08-05.php>
1407# xform=_X( -2.0, -0.9, -4.7, 0.94, _0_0, _0_0, _0_0),
1408# rates=_R( 0.3, _0_0, _0_0, _0_0, _0_0, _0_0, _0_0))
1409_trfX(_ITRF2008_, _ITRF2000_, epoch=_E(2000),
1410 xform=_X( -1.9, -1.7, -10.5, 1.34, _0_0, _0_0, _0_0),
1411 rates=_R( 0.1, 0.1, -1.8, 0.08, _0_0, _0_0, _0_0))
1412_trfX(_ITRF2008_, _ITRF97_, epoch=_E(2000),
1413 xform=_X( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, 0.06),
1414 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1415_trfX(_ITRF2008_, _ITRF96_, epoch=_E(2000),
1416 xform=_X( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, 0.06),
1417 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1418_trfX(_ITRF2008_, _ITRF94_, epoch=_E(2000),
1419 xform=_X( 4.8, 2.6, -33.2, 2.92, _0_0, _0_0, 0.06),
1420 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1421_trfX(_ITRF2008_, _ITRF93_, epoch=_E(2000),
1422 xform=_X( -24.0, 2.4, -38.6, 3.41, -1.71, -1.48, -0.3),
1423 rates=_R( -2.8, -0.1, -2.4, 0.09, -0.11, -0.19, 0.07))
1424_trfX(_ITRF2008_, _ITRF92_, epoch=_E(2000),
1425 xform=_X( 12.8, 4.6, -41.2, 2.21, _0_0, _0_0, 0.06),
1426 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1427_trfX(_ITRF2008_, _ITRF91_, epoch=_E(2000),
1428 xform=_X( 24.8, 18.6, -47.2, 3.61, _0_0, _0_0, 0.06),
1429 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1430_trfX(_ITRF2008_, _ITRF90_, epoch=_E(2000),
1431 xform=_X( 22.8, 14.6, -63.2, 3.91, _0_0, _0_0, 0.06),
1432 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1433_trfX(_ITRF2008_, _ITRF89_, epoch=_E(2000),
1434 xform=_X( 27.8, 38.6, -101.2, 7.31, _0_0, _0_0, 0.06),
1435 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1436_trfX(_ITRF2008_, _ITRF88_, epoch=_E(2000),
1437 xform=_X( 22.8, 2.6, -125.2, 10.41, 0.1, _0_0, 0.06),
1438 rates=_R( 0.1, -0.5, -3.2, 0.09, _0_0, _0_0, 0.02))
1440# Pearson, C. & Snay, R. U{"Introducing HTDP 3.1 to transform coordinates across time and spatial reference
1441# frames"<https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 3rd column
1442# _trfX(_ITRF2005_, _ITRF2000_, epoch=_E(1997),
1443# xform=_X( 0.7, -1.1, -0.4, 0.16, -0.2, 0.1 -1.8),
1444# rates=_R( -0.2, 0.1, -1.8, 0.08, _0_0, _0_0, _0_0))
1445_trfX(_ITRF2005_, _ITRF2000_, epoch=_E(2000), # <http://ITRF.ENSG.IGN.Fr/ITRF_solutions/2005/tp_05-00.php>
1446 xform=_X( 0.1, -0.8, -5.8, 0.4, _0_0, _0_0, _0_0),
1447 rates=_R( -0.2, 0.1, -1.8, 0.08, _0_0, _0_0, _0_0))
1449_trfX(_ITRF2000_, _ITRF97_, epoch=_E(1997),
1450 xform=_X( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0),
1451 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, -0.02)) # 0.02?
1452_trfX(_ITRF2000_, _ITRF96_, epoch=_E(1997),
1453 xform=_X( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0),
1454 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02))
1455_trfX(_ITRF2000_, _ITRF94_, epoch=_E(1997),
1456 xform=_X( 0.67, 0.61, -1.85, 1.55, _0_0, _0_0, _0_0),
1457 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02))
1458_trfX(_ITRF2000_, _ITRF93_, epoch=_E(1988),
1459 xform=_X( 12.7, 6.5, -20.9, 1.95, -0.39, 0.8, -1.14),
1460 rates=_R( -2.9, -0.2, -0.6, 0.01, -0.11, -0.19, 0.07))
1461_trfX(_ITRF2000_, _ITRF92_, epoch=_E(1988),
1462 xform=_X( 1.47, 1.35, -1.39, 0.75, _0_0, _0_0, -0.18),
1463 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02))
1464_trfX(_ITRF2000_, _ITRF91_, epoch=_E(1988),
1465 xform=_X( 26.7, 27.5, -19.9, 2.15, _0_0, _0_0, -0.18),
1466 rates=_R( _0_0, -0.6, -1.4, 0.01, _0_0, _0_0, 0.02))
1467_trfX(_ITRF2000_, _ITRF90_, epoch=_E(1988),
1468 xform=_X( 2.47, 2.35, -3.59, 2.45, _0_0, _0_0, -0.18),
1469 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02))
1470_trfX(_ITRF2000_, _ITRF89_, epoch=_E(1988),
1471 xform=_X( 2.97, 4.75, -7.39, 5.85, _0_0, _0_0, -0.18),
1472 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02))
1473_trfX(_ITRF2000_, _ITRF88_, epoch=_E(1988),
1474 xform=_X( 2.47, 1.15, -9.79, 8.95, 0.1, _0_0, -0.18),
1475 rates=_R( _0_0, -0.06, -0.14, 0.01, _0_0, _0_0, 0.02))
1477# Soler, T .& Snay R.A. U{"Transforming Positions and Velocities between the International Terrestrial
1478# Reference Frame of 2000 and North American Datum of 1983"<https://www.ResearchGate.net/publication/245291390>},
1479# Pearson, C. & Snay, R. U{"Introducing HTDP 3.1 to transform coordinates across time and spatial reference
1480# frames"<https://Geodesy.NOAA.gov/TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 5th and 6th column
1481_trfX(_ITRF97_, _ITRF96_, epoch=_E(1997),
1482 xform=_X( -2.07, -0.21, 9.95, -0.93496, 0.1267, -0.22355, -0.06065,),
1483 rates=_R( 0.69, -0.1, 1.86, -0.19201, 0.01347, -0.01514, 0.00027))
1484_trfX(_ITRF96_, _NAD83_, epoch=_E(1997),
1485 xform=_X( 991.0, -190.72, -512.9, _0_0, 25.79, 9.65, 11.66,),
1486 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.0532, -0.7423, -0.0316,))
1488# see Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and
1489# the European Terrestrial Reference Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 1.
1490# _trfX(_ITRF2020_, _ETRF2020_, epoch=_E(1989), # see Table 2 below
1491# xform=_P_0_0s,
1492# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.086, 0.519, -0.753))
1493# _trfX(_ITRF2014_, _ETRF2014_, epoch=_E(1989), # see Table 3 below
1494# xform=_P_0_0s,
1495# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.085, 0.531, -0.77))
1496_trfX(_ITRF2005_, _ETRF2005_, epoch=_E(1989),
1497 xform=_X( 56.0, 48.0, -37.0, _0_0, _0_0, _0_0, _0_0),
1498 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.054, 0.518, -0.781))
1499# _trfX(_ITRF2000_, _ETRF2000_, epoch=_E(1989), # see Table 4 below
1500# xform=_X( 54.0, 51.0, -48.0, _0_0, _0_0, _0_0, _0_0),
1501# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.081, 0.49, -0.792))
1502_trfX(_ITRF97_, _ETRF97_, epoch=_E(1989),
1503 xform=_X( 41.0, 41.0, -49.0, _0_0, _0_0, _0_0, _0_0),
1504 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.2, 0.5, -0.65))
1505_trfX(_ITRF96_, _ETRF96_, epoch=_E(1989),
1506 xform=_X( 41.0, 41.0, -49.0, _0_0, _0_0, _0_0, _0_0),
1507 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.2, 0.5, -0.65))
1508_trfX(_ITRF94_, _ETRF94_, epoch=_E(1989),
1509 xform=_X( 41.0, 41.0, -49.0, _0_0, _0_0, _0_0, _0_0),
1510 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.2, 0.5, -0.65))
1511_trfX(_ITRF93_, _ETRF93_, epoch=_E(1989),
1512 xform=_X( 19.0, 53.0, -21.0, _0_0, _0_0, _0_0, _0_0),
1513 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.32, 0.78, -0.67))
1514_trfX(_ITRF92_, _ETRF92_, epoch=_E(1989),
1515 xform=_X( 38.0, 40.0, -37.0, 0.0, 0.0, 0.0, 0.0),
1516 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.21, 0.52, -0.68))
1517_trfX(_ITRF91_, _ETRF91_, epoch=_E(1989),
1518 xform=_X( 21.0, 25.0, -37.0, _0_0, _0_0, _0_0, _0_0),
1519 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.21, 0.52, -0.68))
1520_trfX(_ITRF90_, _ETRF90_, epoch=_E(1989),
1521 xform=_X( 19.0, 28.0, -23.0, _0_0, _0_0, _0_0, _0_0),
1522 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.11, 0.57, -0.71))
1523_trfX(_ITRF89_, _ETRF89_, epoch=_E(1989),
1524 xform=_P_0_0s,
1525 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.11, 0.57, -0.71))
1527# see Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and
1528# the European Terrestrial Reference Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 2.
1529_trfX(_ITRF2020_, _ETRF2020_, epoch=_E(2015),
1530 xform=_X( _0_0, _0_0, _0_0, _0_0, 2.236, 13.494, -19.578),
1531 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.086, 0.519, -0.753))
1532_trfX(_ITRF2014_, _ETRF2020_, epoch=_E(2015),
1533 xform=_X( 1.4, 0.9, -1.4, 0.42, 2.236, 13.494, -19.578),
1534 rates=_R( _0_0, 0.1, -0.2, _0_0, 0.086, 0.519, -0.753))
1535_trfX(_ITRF2008_, _ETRF2020_, epoch=_E(2015),
1536 xform=_X( 3.0, 2.8, 0.5, 0.55, 2.236, 13.494, -19.578),
1537 rates=_R( _0_0, 0.1, -0.3, 0.03, 0.086, 0.519, -0.753))
1538_trfX(_ITRF2005_, _ETRF2020_, epoch=_E(2015),
1539 xform=_X( 5.5, 1.9, -4.2, 1.49, 2.236, 13.494, -19.578),
1540 rates=_R( 0.3, 0.1, -0.3, 0.03, 0.086, 0.519, -0.753))
1541_trfX(_ITRF2000_, _ETRF2020_, epoch=_E(2015),
1542 xform=_X( 2.6, 2.6, -37.0, 3.09, 2.236, 13.494, -19.578),
1543 rates=_R( 0.1, 0.2, -2.1, 0.11, 0.086, 0.519, -0.753))
1544_trfX(_ITRF97_, _ETRF2020_, epoch=_E(2015),
1545 xform=_X( 9.3, -2.1, -80.7, 4.82, 2.236, 13.494, -19.218),
1546 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1547_trfX(_ITRF96_, _ETRF2020_, epoch=_E(2015),
1548 xform=_X( 9.3, -2.1, -80.7, 4.82, 2.236, 13.494, -19.218),
1549 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1550_trfX(_ITRF94_, _ETRF2020_, epoch=_E(2015),
1551 xform=_X( 9.3, -2.1, -80.7, 4.82, 2.236, 13.494, -19.218),
1552 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1553_trfX(_ITRF93_, _ETRF2020_, epoch=_E(2015),
1554 xform=_X( -63.0, 3.7, -74.1, 5.31, -1.124, 9.164, -18.828),
1555 rates=_R( -2.8, _0_0, -2.7, 0.12, -0.024, 0.329, -0.683))
1556_trfX(_ITRF92_, _ETRF2020_, epoch=_E(2015),
1557 xform=_X( 17.3, -0.1, -88.7, 4.11, 2.236, 13.494, -19.218),
1558 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1559_trfX(_ITRF91_, _ETRF2020_, epoch=_E(2015),
1560 xform=_X( 29.3, 13.9, -94.7, 5.51, 2.236, 13.494, -19.218),
1561 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1562_trfX(_ITRF90_, _ETRF2020_, epoch=_E(2015),
1563 xform=_X( 27.3, 9.9, -110.7, 5.81, 2.236, 13.494, -19.218),
1564 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1565_trfX(_ITRF89_, _ETRF2020_, epoch=_E(2015),
1566 xform=_X( 32.3, 33.9, -148.7, 9.21, 2.236, 13.494, -19.218),
1567 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1568_trfX(_ITRF88_, _ETRF2020_, epoch=_E(2015),
1569 xform=_X( 27.3, -2.1, -172.7, 12.31, 2.336, 13.494, -19.218),
1570 rates=_R( 0.1, -0.4, -3.5, 0.12, 0.086, 0.519, -0.733))
1572# see Altamimi, Z. U{"EUREF Technical Note 1: Relationship and Transformation between the International and
1573# the European Terrestrial Reference Systems"<https://ERTS89.ENSG.IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 3.
1574_trfX(_ITRF2020_, _ETRF2014_, epoch=_E(2015),
1575 xform=_X( -1.4, -0.9, 1.4, 0.42, 2.21, 13.806, -20.02),
1576 rates=_R( _0_0, -0.1, 0.2, _0_0, 0.085, 0.531, -0.77))
1577_trfX(_ITRF2014_, _ETRF2014_, epoch=_E(2015),
1578 xform=_X( _0_0, _0_0, _0_0, _0_0, 2.21, 13.806, -20.02),
1579 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.085, 0.531, -0.77))
1580_trfX(_ITRF2008_, _ETRF2014_, epoch=_E(2015),
1581 xform=_X( -1.6, -1.9, -1.9, -0.13, 2.21, 13.806, -20.02),
1582 rates=_R( _0_0, _0_0, 0.1, -0.03, 0.085, 0.531, -0.77))
1583_trfX(_ITRF2005_, _ETRF2014_, epoch=_E(2015),
1584 xform=_X( -4.1, -1.0, 2.8, -1.07, 2.21, 13.806, -20.02),
1585 rates=_R( -0.3, _0_0, 0.1, -0.03, 0.085, 0.531, -0.77))
1586_trfX(_ITRF2000_, _ETRF2014_, epoch=_E(2015),
1587 xform=_X( -1.2, -1.7, 35.6, -2.67, 2.21, 13.806, -20.02),
1588 rates=_R( -0.1, -0.1, 1.9, -0.11, 0.085, 0.531, -0.77))
1589_trfX(_ITRF97_, _ETRF2014_, epoch=_E(2015),
1590 xform=_X( -7.9, 3.0, 79.3, -4.40, 2.210, 13.806, -20.38),
1591 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1592_trfX(_ITRF96_, _ETRF2014_, epoch=_E(2015),
1593 xform=_X( -7.9, 3.0, 79.3, -4.40, 2.210, 13.806, -20.38),
1594 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1595_trfX(_ITRF94_, _ETRF2014_, epoch=_E(2015),
1596 xform=_X( -7.9, 3.0, 79.3, -4.40, 2.210, 13.806, -20.38),
1597 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1598_trfX(_ITRF93_, _ETRF2014_, epoch=_E(2015),
1599 xform=_X( 64.4, -2.8, 72.7, -4.89, 5.570, 18.136, -20.77),
1600 rates=_R( 2.8, 0.1, 2.5, -0.12, 0.195, 0.721, -0.84))
1601_trfX(_ITRF92_, _ETRF2014_, epoch=_E(2015),
1602 xform=_X( -15.9, 1.0, 87.3, -3.69, 2.21, 13.806, -20.38),
1603 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1604_trfX(_ITRF91_, _ETRF2014_, epoch=_E(2015),
1605 xform=_X( -27.9, -13.0, 93.3, -5.09, 2.21, 13.806, -20.38),
1606 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1607_trfX(_ITRF90_, _ETRF2014_, epoch=_E(2015),
1608 xform=_X( -25.9, -9.0, 109.3, -5.39, 2.21, 13.806, -20.38),
1609 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1610_trfX(_ITRF89_, _ETRF2014_, epoch=_E(2015),
1611 xform=_X( -30.9, -33.0, 147.3, -8.79, 2.21, 13.806, -20.38),
1612 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1613_trfX(_ITRF88_, _ETRF2014_, epoch=_E(2015),
1614 xform=_X( -25.9, 3.0, 171.3, -11.89, 2.11, 13.806, -20.38),
1615 rates=_R( -0.1, 0.5, 3.3, -0.12, 0.085, 0.531, -0.79))
1617# see U{Altamimi, Z. "EUREF Technical Note 1: Relationship and Transformation between the International and
1618# the European Terrestrial Reference Systems"<https://ERTS89.ENSG,IFN.Fr/pub/EUREF-TN-1-Jan-31-2024.pdf>} Table 4,
1619# U{Boucher, C. & Altamimi, Z. "Memo: Specifications for reference frame fixing in the analysis of a EUREF GPS
1620# campaign" (2011) <https://ETRS89.ENSG.IGN.Fr/memo-V8.pdf>} and U{Altamimi, Z. "Key results of ITRF2014 and
1621# implication to ETRS89 realization", EUREF2016<https://www.EUREF.EU/symposia/2016SanSebastian/01-02-Altamimi.pdf>}.
1622_trfX(_ITRF2020_, _ETRF2000_, epoch=_E(2015),
1623 xform=_X( 53.8, 51.8, -82.2, 2.25, 2.106, 12.74, -20.592),
1624 rates=_R( 0.1, _0_0, -1.7, 0.11, 0.081, 0.49, -0.792))
1625# _trfX(_ITRF2014_, _ETRF2000_, epoch=_E(2000),
1626# xform=_X( 53.7, 51.2, -55.1, 1.02, 0.891, 5.39, -8.712),
1627# rates=_R( 0.1, 0.1, -1.9, 0.11, 0.081, 0.49, -0.792))
1628_trfX(_ITRF2014_, _ETRF2000_, epoch=_E(2015),
1629 xform=_X( 55.2, 52.7, -83.6, 2.67, 2.106, 12.74, -20.592),
1630 rates=_R( 0.1, 0.1, -1.9, 0.11, 0.081, 0.49, -0.792))
1631# _trfX(_ITRF2008_, _ETRF2000_, epoch=_E(2000),
1632# xform=_X( 52.1, 49.3, -58.5, 1.34, 0.891, 5.39, -8.712),
1633# rates=_R( 0.1, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792))
1634_trfX(_ITRF2008_, _ETRF2000_, epoch=_E(2015),
1635 xform=_X( 53.6, 50.8, -85.5, 2.54, 2.106, 12.74, -20.592),
1636 rates=_R( 0.1, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792))
1637# _trfX(_ITRF2005_, _ETRF2000_, epoch=_E(2000),
1638# xform=_X( 54.1, 50.2, -53.8, 0.4, 0.891, 5.39, -8.712),
1639# rates=_R( -0.2, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792))
1640_trfX(_ITRF2005_, _ETRF2000_, epoch=_E(2015),
1641 xform=_X( 51.1, 51.7, -80.8, 1.6, 2.106, 12.74, -20.592),
1642 rates=_R( -0.2, 0.1, -1.8, 0.08, 0.081, 0.49, -0.792))
1643# _trfX(_ITRF2000_, _ETRF2000_, epoch=_E(2000),
1644# xform=_X( 54.0, 51.0, -48.0, _0_0, 0.891, 5.39, -8.712),
1645# rates=_R( _0_0, _0_0, _0_0, _0_0, 0.081, 0.49, -0.792))
1646_trfX(_ITRF2000_, _ETRF2000_, epoch=_E(2015),
1647 xform=_X( 54.0, 51.0, -48.0, _0_0, 2.106, 12.74, -20.592),
1648 rates=_R( _0_0, _0_0, _0_0, _0_0, 0.081, 0.49, -0.792))
1649_trfX(_ITRF97_, _ETRF2000_, epoch=_E(2015),
1650 xform=_X( 47.3, 55.7, -4.3, -1.73, 2.106, 12.74, -20.952),
1651 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1652_trfX(_ITRF96_, _ETRF2000_, epoch=_E(2015),
1653 xform=_X( 47.3, 55.7, -4.3, -1.73, 2.106, 12.74, -20.952),
1654 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1655_trfX(_ITRF94_, _ETRF2000_, epoch=_E(2015),
1656 xform=_X( 47.3, 55.7, -4.3, -1.73, 2.106, 12.74, -20.952),
1657 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1658_trfX(_ITRF93_, _ETRF2000_, epoch=_E(2015),
1659 xform=_X( 119.6, 49.9, -10.9, -2.22, 5.466, 17.07, -21.342),
1660 rates=_R( 2.9, 0.2, 0.6, -0.01, 0.191, 0.68, -0.862))
1661_trfX(_ITRF92_, _ETRF2000_, epoch=_E(2015),
1662 xform=_X( 39.3, 53.7, 3.7, -1.02, 2.106, 12.74, -20.952),
1663 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1664_trfX(_ITRF91_, _ETRF2000_, epoch=_E(2015),
1665 xform=_X( 27.3, 39.7, 9.7, -2.42, 2.106, 12.74, -20.952),
1666 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1667_trfX(_ITRF90_, _ETRF2000_, epoch=_E(2015),
1668 xform=_X( 29.3, 43.7, 25.7, -2.72, 2.106, 12.74, -20.952),
1669 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1670_trfX(_ITRF89_, _ETRF2000_, epoch=_E(2015),
1671 xform=_X( 24.3, 19.7, 63.7, -6.12, 2.106, 12.74, -20.952),
1672 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1673_trfX(_ITRF88_, _ETRF2000_, epoch=_E(2015),
1674 xform=_X( 29.3, 55.7, 87.7, -9.22, 2.006, 12.74, -20.952),
1675 rates=_R( _0_0, 0.6, 1.4, -0.01, 0.081, 0.49, -0.812))
1677# GDA2020 "Geocentric Datum of Australia 2020 Technical Manual", v1.5, 2020-12-09, Table 3.3 and 3.4
1678# <https://www.ICSM.gov.AU/sites/default/files/2020-12/GDA2020%20Technical%20Manual%20V1.5_4.pdf>
1679# (the GDA2020 xforms are different but the rates are the same as GDA94, further below)
1680_trfX(_ITRF2014_, _GDA2020_, epoch=_E(2020),
1681 xform=_P_0_0s,
1682 rates=_R( _0_0, _0_0, _0_0, _0_0, 1.50379, 1.18346, 1.20716))
1683_trfX(_ITRF2008_, _GDA2020_, epoch=_E(2020),
1684 xform=_X( 13.79, 4.55, 15.22, 2.5, 0.2808, 0.2677, -0.4638),
1685 rates=_R( 1.42, 1.34, 0.9, 0.109, 1.5461, 1.182, 1.1551))
1686_trfX(_ITRF2005_, _GDA2020_, epoch=_E(2020),
1687 xform=_X( 40.32, -33.85, -16.72, 4.286, -1.2893, -0.8492, -0.3342),
1688 rates=_R( 2.25, -0.62, -0.56, 0.294, -1.4707, -1.1443, -1.1701))
1689_trfX(_ITRF2000_, _GDA2020_, epoch=_E(2020),
1690 xform=_X(-105.52, 51.58, 231.68, 3.55, 4.2175, 6.3941, 0.8617),
1691 rates=_R( -4.66, 3.55, 11.24, 0.249, 1.7454, 1.4868, 1.224))
1693# see Table 2 in U{Dawson, J. & Woods, A. "ITRF to GDA94 coordinate transformations", Journal of Applied
1694# Geodesy 4 (2010), 189-199<https://www.ResearchGate.net/publication/258401581_ITRF_to_GDA94_coordinate_transformations>}
1695# (note, sign of rotations for GDA94 reversed as "Australia assumes rotation to be of coordinate axes",
1696# rather than the more conventional "position around the coordinate axes")
1697_trfX(_ITRF2008_, _GDA94_, epoch=_E(1994),
1698 xform=_X( -84.68, -19.42, 32.01, 9.71, -0.4254, 2.2578, 2.4015),
1699 rates=_R( 1.42, 1.34, 0.9, 0.109, 1.5461, 1.182, 1.1551))
1700_trfX(_ITRF2005_, _GDA94_, epoch=_E(1994),
1701 xform=_X( -79.73, -6.86, 38.03, 6.636, 0.0351, -2.1211, -2.1411),
1702 rates=_R( 2.25, -0.62, -0.56, 0.294, -1.4707, -1.1443, -1.1701))
1703_trfX(_ITRF2000_, _GDA94_, epoch=_E(1994),
1704 xform=_X( -45.91, -29.85, -20.37, 7.07, -1.6705, 0.4594, 1.9356),
1705 rates=_R( -4.66, 3.55, 11.24, 0.249, 1.7454, 1.4868, 1.224))
1707# see U{Quinsy QPS<https://confluence.QPS.NL/qinsy/files/latest/en/182618383/182618384/1/1579182881000/
1708# ITRF_Transformation_Parameters.xlsx>}, sheets ITRF and NAD83 and Pearson, C. & Snay, R. U{"Introducing
1709# HTDP 3.1 to transform coordinates across time and spatial reference frames"<https://Geodesy.NOAA.gov/
1710# TOOLS/Htdp/Pearson_Snay_2012.pdf> Table 7, 7th column
1711_trfX(_ITRF2008_, _NAD83_, epoch=_E(1997),
1712 xform=_X( 993.43, -1903.31, -526.55, 1.71504, -25.91467, -9.42645, -11.59935),
1713 rates=_R( 0.79, -0.6, -1.34, -0.10201, -0.06667, 0.75744, 0.05133))
1714# see U{Quinsy QPS<https://confluence.QPS.NL/qinsy/files/latest/en/182618383/182618384/1/1579182881000/
1715# ITRF_Transformation_Parameters.xlsx>}, sheets ITRF and NAD83
1716_trfX(_ITRF2005_, _NAD83_, epoch=_E(1997),
1717 xform=_X( 996.3, -1902.4, -521.9, 0.775, -25.915, -9.426, -11.599),
1718 rates=_R( 0.5, -0.6, -1.3, -0.10201, -0.06667, 0.75744, 0.05133))
1719# see U{Solar, T. & Snay, R.A. "Transforming Positions and Velocities between the International Terrestrial Reference
1720# Frame of 2000 and North American Datum of 1983" (2004)<https://www.NGS.NOAA.gov/CORS/Articles/SolerSnayASCE.pdf>}
1721_trfX(_ITRF2000_, _NAD83_, epoch=_E(1997), # note NAD83(CORS96)
1722 xform=_X( 995.6, -1901.3, -521.5, 0.615, -25.915, -9.426, -11.599),
1723 rates=_R( 0.7, -0.7, _0_5, -0.182, -0.06667, 0.75744, 0.05133))
1724_trfX(_ITRF90_, _NAD83_, epoch=_E(1997),
1725 xform=_X( 973.0, -1919.2, -482.9, -0.9, -25.79, -9.65, -11.66),
1726 rates=_R( _0_0, _0_0, _0_0, _0_0, -0.053, 0.742, 0.032))
1727_trfX(_ITRF90_, _WGS84_, epoch=_E(1984), # coverage
1728 xform=_X( 60.0, -517.0, -223.0, -11.0, 18.3, -0.3, 7.0),
1729 rates=_P_0_0s)
1731# equivalents U{"Transformations Between NAD83 and WGS84"<https://www.NGS.NOAA.gov/CORS/Articles/WGS84NAD83.pdf>}
1732trfXform(_NAD83cors96_, _NAD83_, epoch=_E(1997), xform=_P_0_0s, rates=_P_0_0s)
1733trfXform(_WGS84g1150_, _ITRF2000_, epoch=_E(2004), xform=_P_0_0s, rates=_P_0_0s)
1735del _E, _Es, _i, _P, _P_0_0s, _R, _Rs, _X, _Xs
1737if __name__ == _DMAIN_:
1739 def _main():
1740 from pygeodesy.basics import _args_kwds_names
1741 from pygeodesy.interns import _COLONSPACE_,_COMMA_, _NL_, _NLATvar_, _vs_
1742 from pygeodesy import printf
1743 from time import localtime
1745 D = typename(date2epoch)
1746 E = typename(epoch2date)
1747 y = localtime()[0]
1748 for m in range(1, 13):
1749 for d in (1, 15, _mDays[m] - 1, _mDays[m]):
1750 f = '%s(%d,%3d,%3d)' % (D, y, m, d)
1751 e = date2epoch(y, m, d)
1752 t = epoch2date(e)
1753 x = NN if t == (y, m, d) else _STAR_
1754 e = '%.3f' % (e,)
1755 e = '%s, %s(%s)' % (e, E, e)
1756 t = '%d,%3d,%3d' % t
1757 printf('# %s = %s = %s %s', f, e, t, x)
1759 # __doc__ of this file, force all into registery
1760 def _RFs():
1761 yield NN
1762 for t in RefFrames.toRepr(all=True).split(_NL_):
1763 t = t.strip(_COMMA_)
1764 n = t.split(_COLONSPACE_)[0].split(_DOT_)[1]
1765 r = RefFrames.get(n)
1766 x = len(r.Xforms()), -len(r.Xforms(inverse=True))
1767 yield '%s .Xforms=%s' % (t, x)
1769 printf(_NLATvar_.join(sorted(_RFs())), nt=1)
1771 X, t = (), 0 # all form
1772 for r in RefFrames.values():
1773 X += tuple(r._Xto.values())
1774 for X in sorted(X):
1775 t += 1
1776 printf('#%4d %-24s xform=%r', t, X.name, X.xform)
1777 printf('#%29s rates=%r', _SPACE_, X.rates)
1779 t = _args_kwds_names(Transform.__init__)
1780 for n in TRFXform7Tuple._Names_:
1781 if n not in t:
1782 raise AssertionError(_SPACE_(n, _vs_, t))
1784 _main()
1785# del _main
1787# **) MIT License
1788#
1789# Copyright (C) 2016-2025 -- mrJean1 at Gmail -- All Rights Reserved.
1790#
1791# Permission is hereby granted, free of charge, to any person obtaining a
1792# copy of this software and associated documentation files (the "Software"),
1793# to deal in the Software without restriction, including without limitation
1794# the rights to use, copy, modify, merge, publish, distribute, sublicense,
1795# and/or sell copies of the Software, and to permit persons to whom the
1796# Software is furnished to do so, subject to the following conditions:
1797#
1798# The above copyright notice and this permission notice shall be included
1799# in all copies or substantial portions of the Software.
1800#
1801# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1802# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1803# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1804# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
1805# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1806# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
1807# OTHER DEALINGS IN THE SOFTWARE.
1809# % python -m pygeodesy.trf
1810#
1811# date2epoch(2024, 1, 1) = 2024.003, epoch2date(2024.003) = 2024, 1, 1
1812# date2epoch(2024, 1, 15) = 2024.041, epoch2date(2024.041) = 2024, 1, 15
1813# date2epoch(2024, 1, 30) = 2024.082, epoch2date(2024.082) = 2024, 1, 30
1814# date2epoch(2024, 1, 31) = 2024.085, epoch2date(2024.085) = 2024, 1, 31
1815# date2epoch(2024, 2, 1) = 2024.087, epoch2date(2024.087) = 2024, 2, 2 *
1816# date2epoch(2024, 2, 15) = 2024.126, epoch2date(2024.126) = 2024, 2, 16 *
1817# date2epoch(2024, 2, 28) = 2024.161, epoch2date(2024.161) = 2024, 2, 28
1818# date2epoch(2024, 2, 29) = 2024.164, epoch2date(2024.164) = 2024, 3, 1 *
1819# date2epoch(2024, 3, 1) = 2024.167, epoch2date(2024.167) = 2024, 3, 2 *
1820# date2epoch(2024, 3, 15) = 2024.205, epoch2date(2024.205) = 2024, 3, 16 *
1821# date2epoch(2024, 3, 30) = 2024.246, epoch2date(2024.246) = 2024, 3, 31 *
1822# date2epoch(2024, 3, 31) = 2024.249, epoch2date(2024.249) = 2024, 4, 1 *
1823# date2epoch(2024, 4, 1) = 2024.251, epoch2date(2024.251) = 2024, 4, 1
1824# date2epoch(2024, 4, 15) = 2024.290, epoch2date(2024.290) = 2024, 4, 15
1825# date2epoch(2024, 4, 29) = 2024.328, epoch2date(2024.328) = 2024, 4, 29
1826# date2epoch(2024, 4, 30) = 2024.331, epoch2date(2024.331) = 2024, 4, 30
1827# date2epoch(2024, 5, 1) = 2024.333, epoch2date(2024.333) = 2024, 5, 1
1828# date2epoch(2024, 5, 15) = 2024.372, epoch2date(2024.372) = 2024, 5, 15
1829# date2epoch(2024, 5, 30) = 2024.413, epoch2date(2024.413) = 2024, 5, 30
1830# date2epoch(2024, 5, 31) = 2024.415, epoch2date(2024.415) = 2024, 6, 1 *
1831# date2epoch(2024, 6, 1) = 2024.418, epoch2date(2024.418) = 2024, 6, 2 *
1832# date2epoch(2024, 6, 15) = 2024.456, epoch2date(2024.456) = 2024, 6, 16 *
1833# date2epoch(2024, 6, 29) = 2024.495, epoch2date(2024.495) = 2024, 6, 30 *
1834# date2epoch(2024, 6, 30) = 2024.497, epoch2date(2024.497) = 2024, 7, 1 *
1835# date2epoch(2024, 7, 1) = 2024.500, epoch2date(2024.500) = 2024, 7, 1
1836# date2epoch(2024, 7, 15) = 2024.538, epoch2date(2024.538) = 2024, 7, 16 *
1837# date2epoch(2024, 7, 30) = 2024.579, epoch2date(2024.579) = 2024, 7, 30
1838# date2epoch(2024, 7, 31) = 2024.582, epoch2date(2024.582) = 2024, 7, 31
1839# date2epoch(2024, 8, 1) = 2024.585, epoch2date(2024.585) = 2024, 8, 1
1840# date2epoch(2024, 8, 15) = 2024.623, epoch2date(2024.623) = 2024, 8, 15
1841# date2epoch(2024, 8, 30) = 2024.664, epoch2date(2024.664) = 2024, 8, 31 *
1842# date2epoch(2024, 8, 31) = 2024.667, epoch2date(2024.667) = 2024, 9, 1 *
1843# date2epoch(2024, 9, 1) = 2024.669, epoch2date(2024.669) = 2024, 9, 2 *
1844# date2epoch(2024, 9, 15) = 2024.708, epoch2date(2024.708) = 2024, 9, 16 *
1845# date2epoch(2024, 9, 29) = 2024.746, epoch2date(2024.746) = 2024, 9, 30 *
1846# date2epoch(2024, 9, 30) = 2024.749, epoch2date(2024.749) = 2024, 10, 1 *
1847# date2epoch(2024, 10, 1) = 2024.751, epoch2date(2024.751) = 2024, 10, 1
1848# date2epoch(2024, 10, 15) = 2024.790, epoch2date(2024.790) = 2024, 10, 15
1849# date2epoch(2024, 10, 30) = 2024.831, epoch2date(2024.831) = 2024, 10, 30
1850# date2epoch(2024, 10, 31) = 2024.833, epoch2date(2024.833) = 2024, 10, 31
1851# date2epoch(2024, 11, 1) = 2024.836, epoch2date(2024.836) = 2024, 11, 1
1852# date2epoch(2024, 11, 15) = 2024.874, epoch2date(2024.874) = 2024, 11, 15
1853# date2epoch(2024, 11, 29) = 2024.913, epoch2date(2024.913) = 2024, 11, 29
1854# date2epoch(2024, 11, 30) = 2024.915, epoch2date(2024.915) = 2024, 12, 1 *
1855# date2epoch(2024, 12, 1) = 2024.918, epoch2date(2024.918) = 2024, 12, 2 *
1856# date2epoch(2024, 12, 15) = 2024.956, epoch2date(2024.956) = 2024, 12, 16 *
1857# date2epoch(2024, 12, 30) = 2024.997, epoch2date(2024.997) = 2024, 12, 31 *
1858# date2epoch(2024, 12, 31) = 2025.000, epoch2date(2025.000) = 2025, 1, 1 *
1860# 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)
1861# rates=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0)
1862# 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)
1863# rates=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0)
1864# 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)
1865# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1866# 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)
1867# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1868# 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)
1869# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1870# 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)
1871# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1872# 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)
1873# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.11, sy=0.57, sz=-0.71)
1874# 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)
1875# rates=unity(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0)
1876# 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)
1877# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1878# 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)
1879# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.11, sy=0.57, sz=-0.71)
1880# 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)
1881# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=-0.053, sy=0.742, sz=0.032)
1882# 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)
1883# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1884# 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)
1885# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.21, sy=0.52, sz=-0.68)
1886# 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)
1887# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1888# 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)
1889# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1890# 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)
1891# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1892# 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)
1893# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.21, sy=0.52, sz=-0.68)
1894# 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)
1895# rates=rates(tx=2.9, ty=0.2, tz=0.6, s=-0.01, sx=0.191, sy=0.68, sz=-0.862)
1896# 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)
1897# rates=rates(tx=2.8, ty=0.1, tz=2.5, s=-0.12, sx=0.195, sy=0.721, sz=-0.84)
1898# 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)
1899# rates=rates(tx=-2.8, ty=0.0, tz=-2.7, s=0.12, sx=-0.024, sy=0.329, sz=-0.683)
1900# 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)
1901# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.32, sy=0.78, sz=-0.67)
1902# 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)
1903# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1904# 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)
1905# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1906# 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)
1907# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1908# 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)
1909# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.2, sy=0.5, sz=-0.65)
1910# 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)
1911# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.2, sy=0.5, sz=-0.65)
1912# 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)
1913# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.2, sy=0.5, sz=-0.65)
1914# 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)
1915# rates=rates(tx=-4.66, ty=3.55, tz=11.24, s=0.249, sx=1.7454, sy=1.4868, sz=1.224)
1916# 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)
1917# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.081, sy=0.49, sz=-0.792)
1918# 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)
1919# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1920# 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)
1921# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1922# 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)
1923# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1924# 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)
1925# rates=rates(tx=0.0, ty=0.6, tz=1.4, s=-0.01, sx=0.081, sy=0.49, sz=-0.812)
1926# 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)
1927# rates=rates(tx=-0.1, ty=-0.1, tz=1.9, s=-0.11, sx=0.085, sy=0.531, sz=-0.77)
1928# 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)
1929# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1930# 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)
1931# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1932# 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)
1933# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1934# 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)
1935# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1936# 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)
1937# rates=rates(tx=-0.1, ty=0.5, tz=3.3, s=-0.12, sx=0.085, sy=0.531, sz=-0.79)
1938# 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)
1939# rates=rates(tx=0.1, ty=0.2, tz=-2.1, s=0.11, sx=0.086, sy=0.519, sz=-0.753)
1940# 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)
1941# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1942# 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)
1943# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1944# 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)
1945# rates=rates(tx=0.1, ty=-0.4, tz=-3.5, s=0.12, sx=0.086, sy=0.519, sz=-0.733)
1946# 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)
1947# rates=rates(tx=-4.66, ty=3.55, tz=11.24, s=0.249, sx=1.7454, sy=1.4868, sz=1.224)
1948# 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)
1949# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02)
1950# 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)
1951# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02)
1952# 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)
1953# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02)
1954# 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)
1955# rates=rates(tx=0.0, ty=-0.6, tz=-1.4, s=0.01, sx=0.0, sy=0.0, sz=0.02)
1956# 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)
1957# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02)
1958# 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)
1959# rates=rates(tx=-2.9, ty=-0.2, tz=-0.6, s=0.01, sx=-0.11, sy=-0.19, sz=0.07)
1960# 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)
1961# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02)
1962# 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)
1963# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=0.02)
1964# 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)
1965# rates=rates(tx=0.69, ty=-0.1, tz=1.86, s=-0.19201, sx=0.01347, sy=-0.01514, sz=0.00027)
1966# 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)
1967# rates=rates(tx=0.0, ty=-0.06, tz=-0.14, s=0.01, sx=0.0, sy=0.0, sz=-0.02)
1968# 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)
1969# rates=rates(tx=0.7, ty=-0.7, tz=0.5, s=-0.182, sx=-0.06667, sy=0.75744, sz=0.05133)
1970# 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)
1971# rates=rates(tx=-0.2, ty=0.1, tz=-1.8, s=0.08, sx=0.081, sy=0.49, sz=-0.792)
1972# 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)
1973# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.054, sy=0.518, sz=-0.781)
1974# 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)
1975# rates=rates(tx=2.25, ty=-0.62, tz=-0.56, s=0.294, sx=-1.4707, sy=-1.1443, sz=-1.1701)
1976# 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)
1977# rates=rates(tx=0.5, ty=-0.6, tz=-1.3, s=-0.10201, sx=-0.06667, sy=0.75744, sz=0.05133)
1978# 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)
1979# rates=rates(tx=-0.3, ty=0.0, tz=0.1, s=-0.03, sx=0.085, sy=0.531, sz=-0.77)
1980# 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)
1981# rates=rates(tx=0.3, ty=0.1, tz=-0.3, s=0.03, sx=0.086, sy=0.519, sz=-0.753)
1982# 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)
1983# rates=rates(tx=2.25, ty=-0.62, tz=-0.56, s=0.294, sx=-1.4707, sy=-1.1443, sz=-1.1701)
1984# 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)
1985# rates=rates(tx=-0.2, ty=0.1, tz=-1.8, s=0.08, sx=0.0, sy=0.0, sz=0.0)
1986# 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)
1987# rates=rates(tx=1.42, ty=1.34, tz=0.9, s=0.109, sx=1.5461, sy=1.182, sz=1.1551)
1988# 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)
1989# rates=rates(tx=0.79, ty=-0.6, tz=-1.34, s=-0.10201, sx=-0.06667, sy=0.75744, sz=0.05133)
1990# 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)
1991# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.0532, sy=-0.7423, sz=-0.0316)
1992# 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)
1993# rates=rates(tx=0.1, ty=0.1, tz=-1.8, s=0.08, sx=0.081, sy=0.49, sz=-0.792)
1994# 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)
1995# rates=rates(tx=0.0, ty=0.0, tz=0.1, s=-0.03, sx=0.085, sy=0.531, sz=-0.77)
1996# 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)
1997# rates=rates(tx=0.0, ty=0.1, tz=-0.3, s=0.03, sx=0.086, sy=0.519, sz=-0.753)
1998# 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)
1999# rates=rates(tx=1.42, ty=1.34, tz=0.9, s=0.109, sx=1.5461, sy=1.182, sz=1.1551)
2000# 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)
2001# rates=rates(tx=0.1, ty=0.1, tz=-1.8, s=0.08, sx=0.0, sy=0.0, sz=0.0)
2002# 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)
2003# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2004# 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)
2005# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2006# 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)
2007# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2008# 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)
2009# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2010# 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)
2011# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2012# 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)
2013# rates=rates(tx=-2.8, ty=-0.1, tz=-2.4, s=0.09, sx=-0.11, sy=-0.19, sz=0.07)
2014# 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)
2015# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2016# 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)
2017# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2018# 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)
2019# rates=rates(tx=0.1, ty=-0.5, tz=-3.2, s=0.09, sx=0.0, sy=0.0, sz=0.02)
2020# 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)
2021# rates=rates(tx=0.3, ty=0.0, tz=0.0, s=0.0, sx=0.0, sy=0.0, sz=0.0)
2022# 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)
2023# rates=rates(tx=0.1, ty=0.1, tz=-1.9, s=0.11, sx=0.081, sy=0.49, sz=-0.792)
2024# 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)
2025# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.085, sy=0.531, sz=-0.77)
2026# 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)
2027# rates=rates(tx=0.0, ty=0.1, tz=-0.2, s=0.0, sx=0.086, sy=0.519, sz=-0.753)
2028# 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)
2029# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=1.50379, sy=1.18346, sz=1.20716)
2030# 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)
2031# rates=rates(tx=0.1, ty=0.1, tz=-1.9, s=0.11, sx=0.0, sy=0.0, sz=0.0)
2032# 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)
2033# rates=rates(tx=0.3, ty=0.0, tz=-0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0)
2034# 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)
2035# rates=rates(tx=0.0, ty=0.0, tz=-0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0)
2036# 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)
2037# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2038# 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)
2039# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2040# 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)
2041# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2042# 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)
2043# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2044# 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)
2045# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2046# 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)
2047# rates=rates(tx=-2.8, ty=-0.1, tz=-2.5, s=0.12, sx=-0.11, sy=-0.19, sz=0.07)
2048# 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)
2049# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2050# 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)
2051# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2052# 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)
2053# rates=rates(tx=0.1, ty=-0.5, tz=-3.3, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2054# 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)
2055# rates=rates(tx=0.1, ty=0.0, tz=-1.7, s=0.11, sx=0.081, sy=0.49, sz=-0.792)
2056# 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)
2057# rates=rates(tx=0.0, ty=-0.1, tz=0.2, s=0.0, sx=0.085, sy=0.531, sz=-0.77)
2058# 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)
2059# rates=rates(tx=0.0, ty=0.0, tz=0.0, s=0.0, sx=0.086, sy=0.519, sz=-0.753)
2060# 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)
2061# rates=rates(tx=0.1, ty=0.0, tz=-1.7, s=0.11, sx=0.0, sy=0.0, sz=0.0)
2062# 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)
2063# rates=rates(tx=0.3, ty=-0.1, tz=0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0)
2064# 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)
2065# rates=rates(tx=0.0, ty=-0.1, tz=0.1, s=0.03, sx=0.0, sy=0.0, sz=0.0)
2066# 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)
2067# rates=rates(tx=0.0, ty=-0.1, tz=0.2, s=0.0, sx=0.0, sy=0.0, sz=0.0)
2068# 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)
2069# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2070# 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)
2071# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2072# 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)
2073# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2074# 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)
2075# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2076# 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)
2077# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2078# 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)
2079# rates=rates(tx=-2.8, ty=-0.2, tz=-2.3, s=0.12, sx=-0.11, sy=-0.19, sz=0.07)
2080# 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)
2081# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2082# 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)
2083# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)
2084# 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)
2085# rates=rates(tx=0.1, ty=-0.6, tz=-3.1, s=0.12, sx=0.0, sy=0.0, sz=0.02)