1273 lines
38 KiB
Go
1273 lines
38 KiB
Go
// Copyright 2022 HE Boliang
|
|
// All rights reserved.
|
|
|
|
package gofa
|
|
|
|
// Coord
|
|
|
|
// Galactic Coordinates
|
|
|
|
/*
|
|
Icrs2g Transformation from ICRS to Galactic Coordinates.
|
|
|
|
Given:
|
|
dr float64 ICRS right ascension (radians)
|
|
dd float64 ICRS declination (radians)
|
|
|
|
Returned:
|
|
dl float64 galactic longitude (radians)
|
|
db float64 galactic latitude (radians)
|
|
|
|
Notes:
|
|
|
|
1) The IAU 1958 system of Galactic coordinates was defined with
|
|
respect to the now obsolete reference system FK4 B1950.0. When
|
|
interpreting the system in a modern context, several factors have
|
|
to be taken into account:
|
|
|
|
. The inclusion in FK4 positions of the E-terms of aberration.
|
|
. The distortion of the FK4 proper motion system by differential
|
|
Galactic rotation.
|
|
. The use of the B1950.0 equinox rather than the now-standard
|
|
J2000.0.
|
|
. The frame bias between ICRS and the J2000.0 mean place system.
|
|
|
|
The Hipparcos Catalogue (Perryman & ESA 1997) provides a rotation
|
|
matrix that transforms directly between ICRS and Galactic
|
|
coordinates with the above factors taken into account. The
|
|
matrix is derived from three angles, namely the ICRS coordinates
|
|
of the Galactic pole and the longitude of the ascending node of
|
|
the galactic equator on the ICRS equator. They are given in
|
|
degrees to five decimal places and for canonical purposes are
|
|
regarded as exact. In the Hipparcos Catalogue the matrix
|
|
elements are given to 10 decimal places (about 20 microarcsec).
|
|
In the present SOFA function the matrix elements have been
|
|
recomputed from the canonical three angles and are given to 30
|
|
decimal places.
|
|
|
|
2) The inverse transformation is performed by the function G2icrs.
|
|
|
|
Called:
|
|
Anp normalize angle into range 0 to 2pi
|
|
Anpm normalize angle into range +/- pi
|
|
S2c spherical coordinates to unit vector
|
|
Rxp product of r-matrix and p-vector
|
|
C2s p-vector to spherical
|
|
|
|
Reference:
|
|
Perryman M.A.C. & ESA, 1997, ESA SP-1200, The Hipparcos and Tycho
|
|
catalogues. Astrometric and photometric star catalogues
|
|
derived from the ESA Hipparcos Space Astrometry Mission. ESA
|
|
Publications Division, Noordwijk, Netherlands.
|
|
*/
|
|
func Icrs2g(dr, dd float64, dl, db *float64) {
|
|
var v1, v2 [3]float64
|
|
|
|
/*
|
|
L2,B2 system of galactic coordinates in the form presented in the
|
|
Hipparcos Catalogue. In degrees:
|
|
|
|
P = 192.85948 right ascension of the Galactic north pole in ICRS
|
|
Q = 27.12825 declination of the Galactic north pole in ICRS
|
|
R = 32.93192 Galactic longitude of the ascending node of
|
|
the Galactic equator on the ICRS equator
|
|
|
|
ICRS to galactic rotation matrix, obtained by computing
|
|
R_3(-R) R_1(pi/2-Q) R_3(pi/2+P) to the full precision shown:
|
|
*/
|
|
r := [3][3]float64{
|
|
{-0.054875560416215368492398900454, -0.873437090234885048760383168409, -0.483835015548713226831774175116},
|
|
{+0.494109427875583673525222371358, -0.444829629960011178146614061616, +0.746982244497218890527388004556},
|
|
{-0.867666149019004701181616534570, -0.198076373431201528180486091412, +0.455983776175066922272100478348},
|
|
}
|
|
|
|
/* Spherical to Cartesian. */
|
|
S2c(dr, dd, &v1)
|
|
|
|
/* ICRS to Galactic. */
|
|
Rxp(r, v1, &v2)
|
|
|
|
/* Cartesian to spherical. */
|
|
C2s(v2, dl, db)
|
|
|
|
/* Express in conventional ranges. */
|
|
*dl = Anp(*dl)
|
|
*db = Anpm(*db)
|
|
}
|
|
|
|
/*
|
|
G2icrsTransformation from Galactic Coordinates to ICRS.
|
|
|
|
Given:
|
|
dl float64 galactic longitude (radians)
|
|
db float64 galactic latitude (radians)
|
|
|
|
Returned:
|
|
dr float64 ICRS right ascension (radians)
|
|
dd float64 ICRS declination (radians)
|
|
|
|
Notes:
|
|
|
|
1) The IAU 1958 system of Galactic coordinates was defined with
|
|
respect to the now obsolete reference system FK4 B1950.0. When
|
|
interpreting the system in a modern context, several factors have
|
|
to be taken into account:
|
|
|
|
. The inclusion in FK4 positions of the E-terms of aberration.
|
|
. The distortion of the FK4 proper motion system by differential
|
|
Galactic rotation.
|
|
. The use of the B1950.0 equinox rather than the now-standard
|
|
J2000.0.
|
|
. The frame bias between ICRS and the J2000.0 mean place system.
|
|
|
|
The Hipparcos Catalogue (Perryman & ESA 1997) provides a rotation
|
|
matrix that transforms directly between ICRS and Galactic
|
|
coordinates with the above factors taken into account. The
|
|
matrix is derived from three angles, namely the ICRS coordinates
|
|
of the Galactic pole and the longitude of the ascending node of
|
|
the galactic equator on the ICRS equator. They are given in
|
|
degrees to five decimal places and for canonical purposes are
|
|
regarded as exact. In the Hipparcos Catalogue the matrix
|
|
elements are given to 10 decimal places (about 20 microarcsec).
|
|
In the present SOFA function the matrix elements have been
|
|
recomputed from the canonical three angles and are given to 30
|
|
decimal places.
|
|
|
|
2) The inverse transformation is performed by the function Icrs2g.
|
|
|
|
Called:
|
|
Anp normalize angle into range 0 to 2pi
|
|
Anpm normalize angle into range +/- pi
|
|
S2c spherical coordinates to unit vector
|
|
Trxp product of transpose of r-matrix and p-vector
|
|
C2s p-vector to spherical
|
|
|
|
Reference:
|
|
Perryman M.A.C. & ESA, 1997, ESA SP-1200, The Hipparcos and Tycho
|
|
catalogues. Astrometric and photometric star catalogues
|
|
derived from the ESA Hipparcos Space Astrometry Mission. ESA
|
|
Publications Division, Noordwijk, Netherlands.
|
|
*/
|
|
func G2icrs(dl, db float64, dr, dd *float64) {
|
|
var v1, v2 [3]float64
|
|
|
|
/*
|
|
L2,B2 system of galactic coordinates in the form presented in the
|
|
Hipparcos Catalogue. In degrees:
|
|
|
|
P = 192.85948 right ascension of the Galactic north pole in ICRS
|
|
Q = 27.12825 declination of the Galactic north pole in ICRS
|
|
R = 32.93192 Galactic longitude of the ascending node of
|
|
the Galactic equator on the ICRS equator
|
|
|
|
ICRS to galactic rotation matrix, obtained by computing
|
|
R_3(-R) R_1(pi/2-Q) R_3(pi/2+P) to the full precision shown:
|
|
*/
|
|
r := [3][3]float64{
|
|
{-0.054875560416215368492398900454, -0.873437090234885048760383168409, -0.483835015548713226831774175116},
|
|
{+0.494109427875583673525222371358, -0.444829629960011178146614061616, +0.746982244497218890527388004556},
|
|
{-0.867666149019004701181616534570, -0.198076373431201528180486091412, +0.455983776175066922272100478348},
|
|
}
|
|
|
|
/* Spherical to Cartesian. */
|
|
S2c(dl, db, &v1)
|
|
|
|
/* Galactic to ICRS. */
|
|
Trxp(r, v1, &v2)
|
|
|
|
/* Cartesian to spherical. */
|
|
C2s(v2, dr, dd)
|
|
|
|
/* Express in conventional ranges. */
|
|
*dr = Anp(*dr)
|
|
*dd = Anpm(*dd)
|
|
}
|
|
|
|
/*
|
|
Ae2hd Horizon to equatorial coordinates, transform azimuth and altitude to hour angle and declination.
|
|
|
|
Given:
|
|
az float64 azimuth
|
|
el float64 altitude (informally, elevation)
|
|
phi float64 site latitude
|
|
|
|
Returned:
|
|
ha float64 hour angle (local)
|
|
dec float64 declination
|
|
|
|
Notes:
|
|
|
|
1) All the arguments are angles in radians.
|
|
|
|
2) The sign convention for azimuth is north zero, east +pi/2.
|
|
|
|
3) HA is returned in the range +/-pi. Declination is returned in
|
|
the range +/-pi/2.
|
|
|
|
4) The latitude phi is pi/2 minus the angle between the Earth's
|
|
rotation axis and the adopted zenith. In many applications it
|
|
will be sufficient to use the published geodetic latitude of the
|
|
site. In very precise (sub-arcsecond) applications, phi can be
|
|
corrected for polar motion.
|
|
|
|
5) The azimuth az must be with respect to the rotational north pole,
|
|
as opposed to the ITRS pole, and an azimuth with respect to north
|
|
on a map of the Earth's surface will need to be adjusted for
|
|
polar motion if sub-arcsecond accuracy is required.
|
|
|
|
6) Should the user wish to work with respect to the astronomical
|
|
zenith rather than the geodetic zenith, phi will need to be
|
|
adjusted for deflection of the vertical (often tens of
|
|
arcseconds), and the zero point of ha will also be affected.
|
|
|
|
7) The transformation is the same as Ve = Ry(phi-pi/2)*Rz(pi)*Vh,
|
|
where Ve and Vh are lefthanded unit vectors in the (ha,dec) and
|
|
(az,el) systems respectively and Rz and Ry are rotations about
|
|
first the z-axis and then the y-axis. (n.b. Rz(pi) simply
|
|
reverses the signs of the x and y components.) For efficiency,
|
|
the algorithm is written out rather than calling other utility
|
|
functions. For applications that require even greater
|
|
efficiency, additional savings are possible if constant terms
|
|
such as functions of latitude are computed once and for all.
|
|
|
|
8) Again for efficiency, no range checking of arguments is carried
|
|
out.
|
|
*/
|
|
func Ae2hd(az, el, phi float64, ha, dec *float64) {
|
|
var sa, ca, se, ce, sp, cp, x, y, z, r float64
|
|
|
|
/* Useful trig functions. */
|
|
sa = sin(az)
|
|
ca = cos(az)
|
|
se = sin(el)
|
|
ce = cos(el)
|
|
sp = sin(phi)
|
|
cp = cos(phi)
|
|
|
|
/* HA,Dec unit vector. */
|
|
x = -ca*ce*sp + se*cp
|
|
y = -sa * ce
|
|
z = ca*ce*cp + se*sp
|
|
|
|
/* To spherical. */
|
|
r = sqrt(x*x + y*y)
|
|
if r != 0.0 {
|
|
*ha = atan2(y, x)
|
|
} else {
|
|
*ha = 0.0
|
|
}
|
|
*dec = atan2(z, r)
|
|
}
|
|
|
|
/*
|
|
Hd2ae Equatorial to horizon coordinates: transform hour angle and declination to azimuth and altitude.
|
|
|
|
Given:
|
|
ha float64 hour angle (local)
|
|
dec float64 declination
|
|
phi float64 site latitude
|
|
|
|
Returned:
|
|
az float64 azimuth
|
|
el float64 altitude (informally, elevation)
|
|
|
|
Notes:
|
|
|
|
1) All the arguments are angles in radians.
|
|
|
|
2) Azimuth is returned in the range 0-2pi; north is zero, and east
|
|
is +pi/2. Altitude is returned in the range +/- pi/2.
|
|
|
|
3) The latitude phi is pi/2 minus the angle between the Earth's
|
|
rotation axis and the adopted zenith. In many applications it
|
|
will be sufficient to use the published geodetic latitude of the
|
|
site. In very precise (sub-arcsecond) applications, phi can be
|
|
corrected for polar motion.
|
|
|
|
4) The returned azimuth az is with respect to the rotational north
|
|
pole, as opposed to the ITRS pole, and for sub-arcsecond
|
|
accuracy will need to be adjusted for polar motion if it is to
|
|
be with respect to north on a map of the Earth's surface.
|
|
|
|
5) Should the user wish to work with respect to the astronomical
|
|
zenith rather than the geodetic zenith, phi will need to be
|
|
adjusted for deflection of the vertical (often tens of
|
|
arcseconds), and the zero point of the hour angle ha will also
|
|
be affected.
|
|
|
|
6) The transformation is the same as Vh = Rz(pi)*Ry(pi/2-phi)*Ve,
|
|
where Vh and Ve are lefthanded unit vectors in the (az,el) and
|
|
(ha,dec) systems respectively and Ry and Rz are rotations about
|
|
first the y-axis and then the z-axis. (n.b. Rz(pi) simply
|
|
reverses the signs of the x and y components.) For efficiency,
|
|
the algorithm is written out rather than calling other utility
|
|
functions. For applications that require even greater
|
|
efficiency, additional savings are possible if constant terms
|
|
such as functions of latitude are computed once and for all.
|
|
|
|
7) Again for efficiency, no range checking of arguments is carried
|
|
out.
|
|
*/
|
|
func Hd2ae(ha, dec, phi float64, az, el *float64) {
|
|
var sh, ch, sd, cd, sp, cp, x, y, z, r, a float64
|
|
|
|
/* Useful trig functions. */
|
|
sh = sin(ha)
|
|
ch = cos(ha)
|
|
sd = sin(dec)
|
|
cd = cos(dec)
|
|
sp = sin(phi)
|
|
cp = cos(phi)
|
|
|
|
/* Az,Alt unit vector. */
|
|
x = -ch*cd*sp + sd*cp
|
|
y = -sh * cd
|
|
z = ch*cd*cp + sd*sp
|
|
|
|
/* To spherical. */
|
|
r = sqrt(x*x + y*y)
|
|
if r != 0.0 {
|
|
a = atan2(y, x)
|
|
} else {
|
|
a = 0.0
|
|
}
|
|
if a < 0.0 {
|
|
*az = a + D2PI
|
|
} else {
|
|
*az = a
|
|
}
|
|
|
|
*el = atan2(z, r)
|
|
}
|
|
|
|
/*
|
|
Hd2pa Parallactic angle for a given hour angle and declination.
|
|
|
|
Given:
|
|
ha float64 hour angle
|
|
dec float64 declination
|
|
phi float64 site latitude
|
|
|
|
Returned (function value):
|
|
float64 parallactic angle
|
|
|
|
Notes:
|
|
|
|
1) All the arguments are angles in radians.
|
|
|
|
2) The parallactic angle at a point in the sky is the position
|
|
angle of the vertical, i.e. the angle between the directions to
|
|
the north celestial pole and to the zenith respectively.
|
|
|
|
3) The result is returned in the range -pi to +pi.
|
|
|
|
4) At the pole itself a zero result is returned.
|
|
|
|
5) The latitude phi is pi/2 minus the angle between the Earth's
|
|
rotation axis and the adopted zenith. In many applications it
|
|
will be sufficient to use the published geodetic latitude of the
|
|
site. In very precise (sub-arcsecond) applications, phi can be
|
|
corrected for polar motion.
|
|
|
|
6) Should the user wish to work with respect to the astronomical
|
|
zenith rather than the geodetic zenith, phi will need to be
|
|
adjusted for deflection of the vertical (often tens of
|
|
arcseconds), and the zero point of the hour angle ha will also
|
|
be affected.
|
|
|
|
Reference:
|
|
Smart, W.M., "Spherical Astronomy", Cambridge University Press,
|
|
6th edition (Green, 1977), p49.
|
|
*/
|
|
func Hd2pa(ha, dec, phi float64) float64 {
|
|
var cp, cqsz, sqsz float64
|
|
|
|
cp = cos(phi)
|
|
sqsz = cp * sin(ha)
|
|
cqsz = sin(phi)*cos(dec) - cp*sin(dec)*cos(ha)
|
|
if sqsz != 0.0 || cqsz != 0.0 {
|
|
return atan2(sqsz, cqsz)
|
|
}
|
|
return 0.0
|
|
}
|
|
|
|
/*
|
|
Ecm06 ICRS equatorial to ecliptic rotation matrix, IAU 2006.
|
|
|
|
Given:
|
|
date1,date2 float64 TT as a 2-part Julian date (Note 1)
|
|
|
|
Returned:
|
|
rm [3][3]float64 ICRS to ecliptic rotation matrix
|
|
|
|
Notes:
|
|
|
|
1) The TT date date1+date2 is a Julian Date, apportioned in any
|
|
convenient way between the two arguments. For example,
|
|
JD(TT)=2450123.7 could be expressed in any of these ways,
|
|
among others:
|
|
|
|
date1 date2
|
|
|
|
2450123.7 0.0 (JD method)
|
|
2451545.0 -1421.3 (J2000 method)
|
|
2400000.5 50123.2 (MJD method)
|
|
2450123.5 0.2 (date & time method)
|
|
|
|
The JD method is the most natural and convenient to use in
|
|
cases where the loss of several decimal digits of resolution
|
|
is acceptable. The J2000 method is best matched to the way
|
|
the argument is handled internally and will deliver the
|
|
optimum resolution. The MJD method and the date & time methods
|
|
are both good compromises between resolution and convenience.
|
|
|
|
2) The matrix is in the sense
|
|
|
|
E_ep = rm x P_ICRS,
|
|
|
|
where P_ICRS is a vector with respect to ICRS right ascension
|
|
and declination axes and E_ep is the same vector with respect to
|
|
the (inertial) ecliptic and equinox of date.
|
|
|
|
3) P_ICRS is a free vector, merely a direction, typically of unit
|
|
magnitude, and not bound to any particular spatial origin, such
|
|
as the Earth, Sun or SSB. No assumptions are made about whether
|
|
it represents starlight and embodies astrometric effects such as
|
|
parallax or aberration. The transformation is approximately that
|
|
between mean J2000.0 right ascension and declination and ecliptic
|
|
longitude and latitude, with only frame bias (always less than
|
|
25 mas) to disturb this classical picture.
|
|
|
|
Called:
|
|
Obl06 mean obliquity, IAU 2006
|
|
Pmat06 PB matrix, IAU 2006
|
|
Ir initialize r-matrix to identity
|
|
Rx rotate around X-axis
|
|
Rxr product of two r-matrices
|
|
*/
|
|
func Ecm06(date1, date2 float64, rm *[3][3]float64) {
|
|
var ob float64
|
|
var bp, e [3][3]float64
|
|
|
|
/* Obliquity, IAU 2006. */
|
|
ob = Obl06(date1, date2)
|
|
|
|
/* Precession-bias matrix, IAU 2006. */
|
|
Pmat06(date1, date2, &bp)
|
|
|
|
/* Equatorial of date to ecliptic matrix. */
|
|
Ir(&e)
|
|
Rx(ob, &e)
|
|
|
|
/* ICRS to ecliptic coordinates rotation matrix, IAU 2006. */
|
|
Rxr(e, bp, rm)
|
|
|
|
}
|
|
|
|
/*
|
|
Eqec06 Transformation from ICRS equatorial coordinates to ecliptic coordinates
|
|
(mean equinox and ecliptic of date) using IAU 2006 precession model.
|
|
|
|
Given:
|
|
date1,date2 float64 TT as a 2-part Julian date (Note 1)
|
|
dr,dd float64 ICRS right ascension and declination (radians)
|
|
|
|
Returned:
|
|
dl,db float64 ecliptic longitude and latitude (radians)
|
|
|
|
Notes:
|
|
|
|
1) The TT date date1+date2 is a Julian Date, apportioned in any
|
|
convenient way between the two arguments. For example,
|
|
JD(TT)=2450123.7 could be expressed in any of these ways,
|
|
among others:
|
|
|
|
date1 date2
|
|
|
|
2450123.7 0.0 (JD method)
|
|
2451545.0 -1421.3 (J2000 method)
|
|
2400000.5 50123.2 (MJD method)
|
|
2450123.5 0.2 (date & time method)
|
|
|
|
The JD method is the most natural and convenient to use in
|
|
cases where the loss of several decimal digits of resolution
|
|
is acceptable. The J2000 method is best matched to the way
|
|
the argument is handled internally and will deliver the
|
|
optimum resolution. The MJD method and the date & time methods
|
|
are both good compromises between resolution and convenience.
|
|
|
|
2) No assumptions are made about whether the coordinates represent
|
|
starlight and embody astrometric effects such as parallax or
|
|
aberration.
|
|
|
|
3) The transformation is approximately that from mean J2000.0 right
|
|
ascension and declination to ecliptic longitude and latitude
|
|
(mean equinox and ecliptic of date), with only frame bias (always
|
|
less than 25 mas) to disturb this classical picture.
|
|
|
|
Called:
|
|
S2c spherical coordinates to unit vector
|
|
Ecm06 J2000.0 to ecliptic rotation matrix, IAU 2006
|
|
Rxp product of r-matrix and p-vector
|
|
C2s unit vector to spherical coordinates
|
|
Anp normalize angle into range 0 to 2pi
|
|
Anpm normalize angle into range +/- pi
|
|
*/
|
|
func Eqec06(date1, date2 float64, dr, dd float64, dl, db *float64) {
|
|
var rm [3][3]float64
|
|
var v1, v2 [3]float64
|
|
var a, b float64
|
|
|
|
/* Spherical to Cartesian. */
|
|
S2c(dr, dd, &v1)
|
|
|
|
/* Rotation matrix, ICRS equatorial to ecliptic. */
|
|
Ecm06(date1, date2, &rm)
|
|
|
|
/* The transformation from ICRS to ecliptic. */
|
|
Rxp(rm, v1, &v2)
|
|
|
|
/* Cartesian to spherical. */
|
|
C2s(v2, &a, &b)
|
|
|
|
/* Express in conventional ranges. */
|
|
*dl = Anp(a)
|
|
*db = Anpm(b)
|
|
}
|
|
|
|
/*
|
|
Eceq06 Transformation from ecliptic coordinates (mean equinox and ecliptic
|
|
of date) to ICRS RA,Dec, using the IAU 2006 precession model.
|
|
|
|
Given:
|
|
date1,date2 float64 TT as a 2-part Julian date (Note 1)
|
|
dl,db float64 ecliptic longitude and latitude (radians)
|
|
|
|
Returned:
|
|
dr,dd float64 ICRS right ascension and declination (radians)
|
|
|
|
Notes:
|
|
1) The TT date date1+date2 is a Julian Date, apportioned in any
|
|
convenient way between the two arguments. For example,
|
|
JD(TT)=2450123.7 could be expressed in any of these ways,
|
|
among others:
|
|
|
|
date1 date2
|
|
|
|
2450123.7 0.0 (JD method)
|
|
2451545.0 -1421.3 (J2000 method)
|
|
2400000.5 50123.2 (MJD method)
|
|
2450123.5 0.2 (date & time method)
|
|
|
|
The JD method is the most natural and convenient to use in
|
|
cases where the loss of several decimal digits of resolution
|
|
is acceptable. The J2000 method is best matched to the way
|
|
the argument is handled internally and will deliver the
|
|
optimum resolution. The MJD method and the date & time methods
|
|
are both good compromises between resolution and convenience.
|
|
|
|
2) No assumptions are made about whether the coordinates represent
|
|
starlight and embody astrometric effects such as parallax or
|
|
aberration.
|
|
|
|
3) The transformation is approximately that from ecliptic longitude
|
|
and latitude (mean equinox and ecliptic of date) to mean J2000.0
|
|
right ascension and declination, with only frame bias (always
|
|
less than 25 mas) to disturb this classical picture.
|
|
|
|
Called:
|
|
S2c spherical coordinates to unit vector
|
|
Ecm06 J2000.0 to ecliptic rotation matrix, IAU 2006
|
|
Trxp product of transpose of r-matrix and p-vector
|
|
C2s unit vector to spherical coordinates
|
|
Anp normalize angle into range 0 to 2pi
|
|
Anpm normalize angle into range +/- pi
|
|
*/
|
|
func Eceq06(date1, date2 float64, dl, db float64, dr, dd *float64) {
|
|
var rm [3][3]float64
|
|
var v1, v2 [3]float64
|
|
var a, b float64
|
|
|
|
/* Spherical to Cartesian. */
|
|
S2c(dl, db, &v1)
|
|
|
|
/* Rotation matrix, ICRS equatorial to ecliptic. */
|
|
Ecm06(date1, date2, &rm)
|
|
|
|
/* The transformation from ecliptic to ICRS. */
|
|
Trxp(rm, v1, &v2)
|
|
|
|
/* Cartesian to spherical. */
|
|
C2s(v2, &a, &b)
|
|
|
|
/* Express in conventional ranges. */
|
|
*dr = Anp(a)
|
|
*dd = Anpm(b)
|
|
}
|
|
|
|
/*
|
|
Ltecm ICRS equatorial to ecliptic rotation matrix, long-term.
|
|
|
|
Given:
|
|
epj float64 Julian epoch (TT)
|
|
|
|
Returned:
|
|
rm [3][3]float64 ICRS to ecliptic rotation matrix
|
|
|
|
Notes:
|
|
|
|
1) The matrix is in the sense
|
|
|
|
E_ep = rm x P_ICRS,
|
|
|
|
where P_ICRS is a vector with respect to ICRS right ascension
|
|
and declination axes and E_ep is the same vector with respect to
|
|
the (inertial) ecliptic and equinox of epoch epj.
|
|
|
|
2) P_ICRS is a free vector, merely a direction, typically of unit
|
|
magnitude, and not bound to any particular spatial origin, such
|
|
as the Earth, Sun or SSB. No assumptions are made about whether
|
|
it represents starlight and embodies astrometric effects such as
|
|
parallax or aberration. The transformation is approximately that
|
|
between mean J2000.0 right ascension and declination and ecliptic
|
|
longitude and latitude, with only frame bias (always less than
|
|
25 mas) to disturb this classical picture.
|
|
|
|
3) The Vondrak et al. (2011, 2012) 400 millennia precession model
|
|
agrees with the IAU 2006 precession at J2000.0 and stays within
|
|
100 microarcseconds during the 20th and 21st centuries. It is
|
|
accurate to a few arcseconds throughout the historical period,
|
|
worsening to a few tenths of a degree at the end of the
|
|
+/- 200,000 year time span.
|
|
|
|
Called:
|
|
Ltpequ equator pole, long term
|
|
Ltpecl ecliptic pole, long term
|
|
Pxp vector product
|
|
Pn normalize vector
|
|
|
|
References:
|
|
|
|
Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession
|
|
expressions, valid for long time intervals, Astron.Astrophys. 534,
|
|
A22
|
|
|
|
Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession
|
|
expressions, valid for long time intervals (Corrigendum),
|
|
Astron.Astrophys. 541, C1
|
|
*/
|
|
func Ltecm(epj float64, rm *[3][3]float64) {
|
|
/* Frame bias (IERS Conventions 2010, Eqs. 5.21 and 5.33) */
|
|
dx := -0.016617 * DAS2R
|
|
de := -0.0068192 * DAS2R
|
|
dr := -0.0146 * DAS2R
|
|
|
|
var p, z, w, x, y [3]float64
|
|
var s float64
|
|
|
|
/* Equator pole. */
|
|
Ltpequ(epj, &p)
|
|
|
|
/* Ecliptic pole (bottom row of equatorial to ecliptic matrix). */
|
|
Ltpecl(epj, &z)
|
|
|
|
/* Equinox (top row of matrix). */
|
|
Pxp(p, z, &w)
|
|
Pn(w, &s, &x)
|
|
|
|
/* Middle row of matrix. */
|
|
Pxp(z, x, &y)
|
|
|
|
/* Combine with frame bias. */
|
|
rm[0][0] = x[0] - x[1]*dr + x[2]*dx
|
|
rm[0][1] = x[0]*dr + x[1] + x[2]*de
|
|
rm[0][2] = -x[0]*dx - x[1]*de + x[2]
|
|
rm[1][0] = y[0] - y[1]*dr + y[2]*dx
|
|
rm[1][1] = y[0]*dr + y[1] + y[2]*de
|
|
rm[1][2] = -y[0]*dx - y[1]*de + y[2]
|
|
rm[2][0] = z[0] - z[1]*dr + z[2]*dx
|
|
rm[2][1] = z[0]*dr + z[1] + z[2]*de
|
|
rm[2][2] = -z[0]*dx - z[1]*de + z[2]
|
|
}
|
|
|
|
/*
|
|
Lteqec Transformation from ICRS equatorial coordinates to ecliptic coordinates
|
|
(mean equinox and ecliptic of date) using a long-term precession model.
|
|
|
|
Given:
|
|
epj float64 Julian epoch (TT)
|
|
dr,dd float64 ICRS right ascension and declination (radians)
|
|
|
|
Returned:
|
|
dl,db float64 ecliptic longitude and latitude (radians)
|
|
|
|
Notes:
|
|
1) No assumptions are made about whether the coordinates represent
|
|
starlight and embody astrometric effects such as parallax or
|
|
aberration.
|
|
|
|
2) The transformation is approximately that from mean J2000.0 right
|
|
ascension and declination to ecliptic longitude and latitude
|
|
(mean equinox and ecliptic of date), with only frame bias (always
|
|
less than 25 mas) to disturb this classical picture.
|
|
|
|
3) The Vondrak et al. (2011, 2012) 400 millennia precession model
|
|
agrees with the IAU 2006 precession at J2000.0 and stays within
|
|
100 microarcseconds during the 20th and 21st centuries. It is
|
|
accurate to a few arcseconds throughout the historical period,
|
|
worsening to a few tenths of a degree at the end of the
|
|
+/- 200,000 year time span.
|
|
|
|
Called:
|
|
S2c spherical coordinates to unit vector
|
|
Ltecm J2000.0 to ecliptic rotation matrix, long term
|
|
Rxp product of r-matrix and p-vector
|
|
C2s unit vector to spherical coordinates
|
|
Anp normalize angle into range 0 to 2pi
|
|
Anpm normalize angle into range +/- pi
|
|
|
|
References:
|
|
|
|
Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession
|
|
expressions, valid for long time intervals, Astron.Astrophys. 534,
|
|
A22
|
|
|
|
Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession
|
|
expressions, valid for long time intervals (Corrigendum),
|
|
Astron.Astrophys. 541, C1
|
|
*/
|
|
func Lteqec(epj float64, dr, dd float64, dl, db *float64) {
|
|
var rm [3][3]float64
|
|
var v1, v2 [3]float64
|
|
var a, b float64
|
|
|
|
/* Spherical to Cartesian. */
|
|
S2c(dr, dd, &v1)
|
|
|
|
/* Rotation matrix, ICRS equatorial to ecliptic. */
|
|
Ltecm(epj, &rm)
|
|
|
|
/* The transformation from ICRS to ecliptic. */
|
|
Rxp(rm, v1, &v2)
|
|
|
|
/* Cartesian to spherical. */
|
|
C2s(v2, &a, &b)
|
|
|
|
/* Express in conventional ranges. */
|
|
*dl = Anp(a)
|
|
*db = Anpm(b)
|
|
}
|
|
|
|
/*
|
|
Lteceq Transformation from ecliptic coordinates (mean equinox and ecliptic
|
|
of date) to ICRS RA,Dec, using a long-term precession model.
|
|
|
|
Given:
|
|
epj float64 Julian epoch (TT)
|
|
dl,db float64 ecliptic longitude and latitude (radians)
|
|
|
|
Returned:
|
|
dr,dd float64 ICRS right ascension and declination (radians)
|
|
|
|
Notes:
|
|
1) No assumptions are made about whether the coordinates represent
|
|
starlight and embody astrometric effects such as parallax or
|
|
aberration.
|
|
|
|
2) The transformation is approximately that from ecliptic longitude
|
|
and latitude (mean equinox and ecliptic of date) to mean J2000.0
|
|
right ascension and declination, with only frame bias (always
|
|
less than 25 mas) to disturb this classical picture.
|
|
|
|
3) The Vondrak et al. (2011, 2012) 400 millennia precession model
|
|
agrees with the IAU 2006 precession at J2000.0 and stays within
|
|
100 microarcseconds during the 20th and 21st centuries. It is
|
|
accurate to a few arcseconds throughout the historical period,
|
|
worsening to a few tenths of a degree at the end of the
|
|
+/- 200,000 year time span.
|
|
|
|
Called:
|
|
S2c spherical coordinates to unit vector
|
|
Ltecm J2000.0 to ecliptic rotation matrix, long term
|
|
Trxp product of transpose of r-matrix and p-vector
|
|
C2s unit vector to spherical coordinates
|
|
Anp normalize angle into range 0 to 2pi
|
|
Anpm normalize angle into range +/- pi
|
|
|
|
References:
|
|
|
|
Vondrak, J., Capitaine, N. and Wallace, P., 2011, New precession
|
|
expressions, valid for long time intervals, Astron.Astrophys. 534,
|
|
A22
|
|
|
|
Vondrak, J., Capitaine, N. and Wallace, P., 2012, New precession
|
|
expressions, valid for long time intervals (Corrigendum),
|
|
Astron.Astrophys. 541, C1
|
|
*/
|
|
func Lteceq(epj float64, dl, db float64, dr, dd *float64) {
|
|
var rm [3][3]float64
|
|
var v1, v2 [3]float64
|
|
var a, b float64
|
|
|
|
/* Spherical to Cartesian. */
|
|
S2c(dl, db, &v1)
|
|
|
|
/* Rotation matrix, ICRS equatorial to ecliptic. */
|
|
Ltecm(epj, &rm)
|
|
|
|
/* The transformation from ecliptic to ICRS. */
|
|
Trxp(rm, v1, &v2)
|
|
|
|
/* Cartesian to spherical. */
|
|
C2s(v2, &a, &b)
|
|
|
|
/* Express in conventional ranges. */
|
|
*dr = Anp(a)
|
|
*dd = Anpm(b)
|
|
}
|
|
|
|
/*
|
|
Eform a,f for a nominated Earth reference ellipsoid
|
|
|
|
Given:
|
|
n int ellipsoid identifier (Note 1)
|
|
|
|
Returned:
|
|
a float64 equatorial radius (meters, Note 2)
|
|
f float64 flattening (Note 2)
|
|
|
|
Returned (function value):
|
|
int status: 0 = OK
|
|
-1 = illegal identifier (Note 3)
|
|
|
|
Notes:
|
|
|
|
1) The identifier n is a number that specifies the choice of
|
|
reference ellipsoid. The following are supported:
|
|
|
|
n ellipsoid
|
|
|
|
1 WGS84
|
|
2 GRS80
|
|
3 WGS72
|
|
|
|
The n value has no significance outside the SOFA software. For
|
|
convenience, symbols WGS84 etc. are defined in sofam.h.
|
|
|
|
2) The ellipsoid parameters are returned in the form of equatorial
|
|
radius in meters (a) and flattening (f). The latter is a number
|
|
around 0.00335, i.e. around 1/298.
|
|
|
|
3) For the case where an unsupported n value is supplied, zero a and
|
|
f are returned, as well as error status.
|
|
|
|
References:
|
|
|
|
Department of Defense World Geodetic System 1984, National
|
|
Imagery and Mapping Agency Technical Report 8350.2, Third
|
|
Edition, p3-2.
|
|
|
|
Moritz, H., Bull. Geodesique 66-2, 187 (1992).
|
|
|
|
The Department of Defense World Geodetic System 1972, World
|
|
Geodetic System Committee, May 1974.
|
|
|
|
Explanatory Supplement to the Astronomical Almanac,
|
|
P. Kenneth Seidelmann (ed), University Science Books (1992),
|
|
p220.
|
|
*/
|
|
func Eform(n int, a, f *float64) int {
|
|
/* Look up a and f for the specified reference ellipsoid. */
|
|
switch n {
|
|
|
|
case WGS84:
|
|
*a = 6378137.0
|
|
*f = 1.0 / 298.257223563
|
|
break
|
|
|
|
case GRS80:
|
|
*a = 6378137.0
|
|
*f = 1.0 / 298.257222101
|
|
break
|
|
|
|
case WGS72:
|
|
*a = 6378135.0
|
|
*f = 1.0 / 298.26
|
|
break
|
|
|
|
default:
|
|
|
|
/* Invalid identifier. */
|
|
*a = 0.0
|
|
*f = 0.0
|
|
return -1
|
|
|
|
}
|
|
|
|
/* OK status. */
|
|
return 0
|
|
}
|
|
|
|
/*
|
|
Gc2gd Transform geocentric coordinates to geodetic using the specified
|
|
reference ellipsoid.
|
|
|
|
Given:
|
|
n int ellipsoid identifier (Note 1)
|
|
xyz [3]float64 geocentric vector (Note 2)
|
|
|
|
Returned:
|
|
elong float64 longitude (radians, east +ve, Note 3)
|
|
phi float64 latitude (geodetic, radians, Note 3)
|
|
height float64 height above ellipsoid (geodetic, Notes 2,3)
|
|
|
|
Returned (function value):
|
|
int status: 0 = OK
|
|
-1 = illegal identifier (Note 3)
|
|
-2 = internal error (Note 3)
|
|
|
|
Notes:
|
|
|
|
1) The identifier n is a number that specifies the choice of
|
|
reference ellipsoid. The following are supported:
|
|
|
|
n ellipsoid
|
|
|
|
1 WGS84
|
|
2 GRS80
|
|
3 WGS72
|
|
|
|
The n value has no significance outside the SOFA software. For
|
|
convenience, symbols WGS84 etc. are defined in sofam.h.
|
|
|
|
2) The geocentric vector (xyz, given) and height (height, returned)
|
|
are in meters.
|
|
|
|
3) An error status -1 means that the identifier n is illegal. An
|
|
error status -2 is theoretically impossible. In all error cases,
|
|
all three results are set to -1e9.
|
|
|
|
4) The inverse transformation is performed in the function iauGd2gc.
|
|
|
|
Called:
|
|
Eform Earth reference ellipsoids
|
|
Gc2gde geocentric to geodetic transformation, general
|
|
*/
|
|
func Gc2gd(n int, xyz [3]float64, elong, phi, height *float64) int {
|
|
var j int
|
|
var a, f float64
|
|
|
|
/* Obtain reference ellipsoid parameters. */
|
|
j = Eform(n, &a, &f)
|
|
|
|
/* If OK, transform x,y,z to longitude, geodetic latitude, height. */
|
|
if j == 0 {
|
|
j = Gc2gde(a, f, xyz, elong, phi, height)
|
|
if j < 0 {
|
|
j = -2
|
|
}
|
|
}
|
|
|
|
/* Deal with any errors. */
|
|
if j < 0 {
|
|
*elong = -1e9
|
|
*phi = -1e9
|
|
*height = -1e9
|
|
}
|
|
|
|
/* Return the status. */
|
|
return j
|
|
}
|
|
|
|
/*
|
|
Gc2gde Transform geocentric coordinates to geodetic for a reference
|
|
ellipsoid of specified form.
|
|
|
|
Given:
|
|
a float64 equatorial radius (Notes 2,4)
|
|
f float64 flattening (Note 3)
|
|
xyz [3]float64 geocentric vector (Note 4)
|
|
|
|
Returned:
|
|
elong float64 longitude (radians, east +ve)
|
|
phi float64 latitude (geodetic, radians)
|
|
height float64 height above ellipsoid (geodetic, Note 4)
|
|
|
|
Returned (function value):
|
|
int status: 0 = OK
|
|
-1 = illegal f
|
|
-2 = illegal a
|
|
|
|
Notes:
|
|
|
|
1) This function is based on the GCONV2H Fortran subroutine by
|
|
Toshio Fukushima (see reference).
|
|
|
|
2) The equatorial radius, a, can be in any units, but meters is
|
|
the conventional choice.
|
|
|
|
3) The flattening, f, is (for the Earth) a value around 0.00335,
|
|
i.e. around 1/298.
|
|
|
|
4) The equatorial radius, a, and the geocentric vector, xyz,
|
|
must be given in the same units, and determine the units of
|
|
the returned height, height.
|
|
|
|
5) If an error occurs (status < 0), elong, phi and height are
|
|
unchanged.
|
|
|
|
6) The inverse transformation is performed in the function
|
|
iauGd2gce.
|
|
|
|
7) The transformation for a standard ellipsoid (such as WGS84) can
|
|
more conveniently be performed by calling iauGc2gd, which uses a
|
|
numerical code to identify the required A and F values.
|
|
|
|
Reference:
|
|
|
|
Fukushima, T., "Transformation from Cartesian to geodetic
|
|
coordinates accelerated by Halley's method", J.Geodesy (2006)
|
|
79: 689-693
|
|
*/
|
|
func Gc2gde(a, f float64, xyz [3]float64, elong, phi, height *float64) int {
|
|
var aeps2, e2, e4t, ec2, ec, b, x, y, z, p2, absz, p, s0, pn, zc,
|
|
c0, c02, c03, s02, s03, a02, a0, a03, d0, f0, b0, s1,
|
|
cc, s12, cc2 float64
|
|
|
|
/* ------------- */
|
|
/* Preliminaries */
|
|
/* ------------- */
|
|
|
|
/* Validate ellipsoid parameters. */
|
|
if f < 0.0 || f >= 1.0 {
|
|
return -1
|
|
}
|
|
if a <= 0.0 {
|
|
return -2
|
|
}
|
|
|
|
/* Functions of ellipsoid parameters (with further validation of f). */
|
|
aeps2 = a * a * 1e-32
|
|
e2 = (2.0 - f) * f
|
|
e4t = e2 * e2 * 1.5
|
|
ec2 = 1.0 - e2
|
|
if ec2 <= 0.0 {
|
|
return -1
|
|
}
|
|
ec = sqrt(ec2)
|
|
b = a * ec
|
|
|
|
/* Cartesian components. */
|
|
x = xyz[0]
|
|
y = xyz[1]
|
|
z = xyz[2]
|
|
|
|
/* Distance from polar axis squared. */
|
|
p2 = x*x + y*y
|
|
|
|
/* Longitude. */
|
|
// *elong = p2 > 0.0 ? atan2(y, x) : 0.0;
|
|
if p2 > 0.0 {
|
|
*elong = atan2(y, x)
|
|
} else {
|
|
*elong = 0.0
|
|
}
|
|
|
|
/* Unsigned z-coordinate. */
|
|
absz = fabs(z)
|
|
|
|
/* Proceed unless polar case. */
|
|
if p2 > aeps2 {
|
|
|
|
/* Distance from polar axis. */
|
|
p = sqrt(p2)
|
|
|
|
/* Normalization. */
|
|
s0 = absz / a
|
|
pn = p / a
|
|
zc = ec * s0
|
|
|
|
/* Prepare Newton correction factors. */
|
|
c0 = ec * pn
|
|
c02 = c0 * c0
|
|
c03 = c02 * c0
|
|
s02 = s0 * s0
|
|
s03 = s02 * s0
|
|
a02 = c02 + s02
|
|
a0 = sqrt(a02)
|
|
a03 = a02 * a0
|
|
d0 = zc*a03 + e2*s03
|
|
f0 = pn*a03 - e2*c03
|
|
|
|
/* Prepare Halley correction factor. */
|
|
b0 = e4t * s02 * c02 * pn * (a0 - ec)
|
|
s1 = d0*f0 - b0*s0
|
|
cc = ec * (f0*f0 - b0*c0)
|
|
|
|
/* Evaluate latitude and height. */
|
|
*phi = atan(s1 / cc)
|
|
s12 = s1 * s1
|
|
cc2 = cc * cc
|
|
*height = (p*cc + absz*s1 - a*sqrt(ec2*s12+cc2)) / sqrt(s12+cc2)
|
|
} else {
|
|
|
|
/* Exception: pole. */
|
|
*phi = DPI / 2.0
|
|
*height = absz - b
|
|
}
|
|
|
|
/* Restore sign of latitude. */
|
|
if z < 0 {
|
|
*phi = -*phi
|
|
}
|
|
|
|
/* OK status. */
|
|
return 0
|
|
}
|
|
|
|
/*
|
|
Gd2gc Transform geodetic coordinates to geocentric using the specified
|
|
reference ellipsoid.
|
|
|
|
Given:
|
|
n int ellipsoid identifier (Note 1)
|
|
elong float64 longitude (radians, east +ve)
|
|
phi float64 latitude (geodetic, radians, Note 3)
|
|
height float64 height above ellipsoid (geodetic, Notes 2,3)
|
|
|
|
Returned:
|
|
xyz [3]float64 geocentric vector (Note 2)
|
|
|
|
Returned (function value):
|
|
int status: 0 = OK
|
|
-1 = illegal identifier (Note 3)
|
|
-2 = illegal case (Note 3)
|
|
|
|
Notes:
|
|
|
|
1) The identifier n is a number that specifies the choice of
|
|
reference ellipsoid. The following are supported:
|
|
|
|
n ellipsoid
|
|
|
|
1 WGS84
|
|
2 GRS80
|
|
3 WGS72
|
|
|
|
The n value has no significance outside the SOFA software. For
|
|
convenience, symbols WGS84 etc. are defined in sofam.h.
|
|
|
|
2) The height (height, given) and the geocentric vector (xyz,
|
|
returned) are in meters.
|
|
|
|
3) No validation is performed on the arguments elong, phi and
|
|
height. An error status -1 means that the identifier n is
|
|
illegal. An error status -2 protects against cases that would
|
|
lead to arithmetic exceptions. In all error cases, xyz is set
|
|
to zeros.
|
|
|
|
4) The inverse transformation is performed in the function iauGc2gd.
|
|
|
|
Called:
|
|
Eform Earth reference ellipsoids
|
|
Gd2gce geodetic to geocentric transformation, general
|
|
Zp zero p-vector
|
|
*/
|
|
func Gd2gc(n int, elong, phi, height float64, xyz *[3]float64) int {
|
|
var j int
|
|
var a, f float64
|
|
|
|
/* Obtain reference ellipsoid parameters. */
|
|
j = Eform(n, &a, &f)
|
|
|
|
/* If OK, transform longitude, geodetic latitude, height to x,y,z. */
|
|
if j == 0 {
|
|
j = Gd2gce(a, f, elong, phi, height, xyz)
|
|
if j != 0 {
|
|
j = -2
|
|
}
|
|
}
|
|
|
|
/* Deal with any errors. */
|
|
if j != 0 {
|
|
Zp(xyz)
|
|
}
|
|
|
|
/* Return the status. */
|
|
return j
|
|
}
|
|
|
|
/*
|
|
Gd2gce Transform geodetic coordinates to geocentric for a reference
|
|
ellipsoid of specified form.
|
|
|
|
Given:
|
|
a float64 equatorial radius (Notes 1,4)
|
|
f float64 flattening (Notes 2,4)
|
|
elong float64 longitude (radians, east +ve)
|
|
phi float64 latitude (geodetic, radians, Note 4)
|
|
height float64 height above ellipsoid (geodetic, Notes 3,4)
|
|
|
|
Returned:
|
|
xyz [3]float64 geocentric vector (Note 3)
|
|
|
|
Returned (function value):
|
|
int status: 0 = OK
|
|
-1 = illegal case (Note 4)
|
|
Notes:
|
|
|
|
1) The equatorial radius, a, can be in any units, but meters is
|
|
the conventional choice.
|
|
|
|
2) The flattening, f, is (for the Earth) a value around 0.00335,
|
|
i.e. around 1/298.
|
|
|
|
3) The equatorial radius, a, and the height, height, must be
|
|
given in the same units, and determine the units of the
|
|
returned geocentric vector, xyz.
|
|
|
|
4) No validation is performed on individual arguments. The error
|
|
status -1 protects against (unrealistic) cases that would lead
|
|
to arithmetic exceptions. If an error occurs, xyz is unchanged.
|
|
|
|
5) The inverse transformation is performed in the function
|
|
iauGc2gde.
|
|
|
|
6) The transformation for a standard ellipsoid (such as WGS84) can
|
|
more conveniently be performed by calling iauGd2gc, which uses a
|
|
numerical code to identify the required a and f values.
|
|
|
|
References:
|
|
|
|
Green, R.M., Spherical Astronomy, Cambridge University Press,
|
|
(1985) Section 4.5, p96.
|
|
|
|
Explanatory Supplement to the Astronomical Almanac,
|
|
P. Kenneth Seidelmann (ed), University Science Books (1992),
|
|
Section 4.22, p202.
|
|
*/
|
|
func Gd2gce(a, f float64, elong, phi, height float64, xyz *[3]float64) int {
|
|
var sp, cp, w, d, ac, as, r float64
|
|
|
|
/* Functions of geodetic latitude. */
|
|
sp = sin(phi)
|
|
cp = cos(phi)
|
|
w = 1.0 - f
|
|
w = w * w
|
|
d = cp*cp + w*sp*sp
|
|
if d <= 0.0 {
|
|
return -1
|
|
}
|
|
ac = a / sqrt(d)
|
|
as = w * ac
|
|
|
|
/* Geocentric vector. */
|
|
r = (ac + height) * cp
|
|
xyz[0] = r * cos(elong)
|
|
xyz[1] = r * sin(elong)
|
|
xyz[2] = (as + height) * sp
|
|
|
|
/* Success. */
|
|
return 0
|
|
}
|