image-20221210165212635

很奇怪j2000不是一个固定的值吗(其实自己也不是很清楚

但Stellarium软件的J2000值在变

问了天文同学也不太清楚, 直接在Stellarium的github 讨论区问作者。

作者回答

Please do not use Stellarium as source or reference for own work. It has its own errors.

That said, to compare, set Stellarium to J1991.25 (to set proper motion自行), and observe the J2000 1月1日12时 儒略日 coordinates. At least disable aberration and probably even nutation章动. Or observe from the center of the Sun.

当我从设置观测点为太阳时,设置儒略日 完美对上!

image-20221206205114703

得到的J2000

https://github.com/gmiller123456/hip2000

项目中 使用NOVAS(Naval Observatory Vector Astrometry Subroutines)库的transform_hip功能

image-20221206205154919

一致


hipparcos源文件中的北落师门 hip = 113368

ra = 6.011119421 rad

ra = 344.411772972423023020 度

ra = 22.960784864828202245 h

ra = h: 22 m: 57 s: 38.825513381528082846

dec = -29.621836820143990110

dec = h: -29 m: 37 s: 18.612552518364395837

#include <bits/stdc++.h>
using namespace std;
#define PI acos(-1);

int main()
{
double ra = 6.011119421;
double dec = -0.516998583;
double decd = dec * 180 / PI;
double rad = ra * 180 / PI;
double rah = rad / 15;
cout << fixed << setprecision(18) << rad << endl;
cout << rah << endl;
cout << " h: " << (int)rah << " m: " << int((rah - int(rah)) * 60) << " s: " << 60 * ((rah - int(rah)) * 60 - int((rah - int(rah)) * 60)) << endl;

cout << decd << endl;
cout << " h: " << (int)decd << " m: " << abs(int((decd - int(decd)) * 60)) << " s: " << abs(60 * ((decd - int(decd)) * 60 - int((decd - int(decd)) * 60))) << endl;
system("pause");
return 0;
}

研究一下novas库如何实现将j1991.25到J2000的

https://github.com/brandon-rhodes/python-novas

看说明先装novas库,可惜不能支持windows

image-20221206215016569

这是已易于使用的Hipparcos目录的更改版本。原始目录具有1991.25的Equinox的RA/DEC坐标。在这里,我使用NOVA函数“ transform_hip”将坐标转换为J2000。


在海军天文台novas.c中有一个函数transform_hip,作用是将 依巴谷原始星表中的J1991.25纪元的数据转换为FK5形式的数据,专用于依巴谷星表,

/********transform_hip */

void transform_hip (cat_entry *hipparcos, cat_entry *fk5)
/*
------------------------------------------------------------------------

PURPOSE:
To convert Hipparcos data at epoch J1991.25 to epoch J2000.0 and
FK5-style units. To be used only for Hipparcos or Tycho stars
with linear space motion.

INPUT
ARGUMENTS:
*hipparcos (struct cat_entry)
An entry from the Hipparcos catalog, at epoch J1991.25, with
all members having Hipparcos catalog units. See Note 1
below (struct defined in novas.h).

OUTPUT
ARGUMENTS:
*fk5 (struct cat_entry)
The transformed input entry, at epoch J2000.0, with all
members having FK5 catalog units. See Note 2 below (struct
defined in novas.h).



NOTES:
1. Hipparcos epoch and units:
Epoch: J1991.25
Right ascension (RA): degrees
Declination (Dec): degrees
Proper motion in RA * cos (Dec): milliarcseconds per year
Proper motion in Dec: milliarcseconds per year
Parallax: milliarcseconds
Radial velocity: kilometers per second (not in catalog)
2. FK5 epoch and units:
Epoch: J2000.0
Right ascension: hours
Declination: degrees
Proper motion in RA: seconds of time per Julian century
Proper motion in Dec: arcseconds per Julian century
Parallax: arcseconds
Radial velocity: kilometers per second
3. This function based on subroutine 'gethip' from NOVAS Fortran.

------------------------------------------------------------------------
*/
{
double epoch_hip = 2448349.0625;
double epoch_fk5 = 2451545.0000;

cat_entry scratch;

/*
The "scratch" catalog entry contains data with FK5-like units at
epoch J1991.25. Copy the catalog entry quantities that don't
change from the Hipparcos catalog entry to the "scratch" entry.
*/

strcpy (scratch.starname, hipparcos->starname);
scratch.starnumber = hipparcos->starnumber;
scratch.dec = hipparcos->dec;
scratch.radialvelocity = hipparcos->radialvelocity;

strcpy (scratch.catalog, "SCR");

/*
Convert Hipparcos units to FK5-like units; insert transformed
quantities into the "scratch" catalog entry.
*/

scratch.ra = hipparcos->ra / 15.0;
scratch.promora = hipparcos->promora / (150.0 *
cos (hipparcos->dec * DEG2RAD));
scratch.promodec = hipparcos->promodec / 10.0;
scratch.parallax = hipparcos->parallax / 1000.0;

/*
Change the epoch of the Hipparcos data from J1991.25 to J2000.0.
*/

transform_cat (1,epoch_hip,&scratch,epoch_fk5,"FK5", fk5);

return;
}

user guide中写道:Radial velocity (hipparcos->radialvelocity) is not given in the Hipparcos catalog. If a value is not known, set hipparcos->radialvelocity = 0.0. The radial velocity is important for only a small number of nearby, high proper motion stars.

image-20221207150407348

#include <bits/stdc++.h>
using namespace std;
const double TWOPI = 6.28318530717958647692;
const double DEG2RAD = 0.017453292519943296;
const double RAD2DEG = 57.295779513082321;
const double RAD2SEC = 206264.806247096355;
const double epoch_hip = 2448349.0625; // J1991.25
const double epoch_fk5 = 2451545.0000;

/*
ARGUMENTS:
in :
hip_ra (rad)
hip_dec (rad)
hip_promora (mas/yr)
hip_promodec (mas/yr)
hip_parallax (mas)
out :
fk5_ra(h)
fk5_dec(degree)
*/
void convert(double hip_ra, double hip_dec, double hip_promora, double hip_promodec, double hip_parallax, double &fk5_ra, double &fk5_dec)
{
hip_ra = hip_ra * RAD2DEG / 15.0;
hip_promora = hip_promora / (150.0 * cos(hip_dec));
hip_dec *= RAD2DEG;
hip_promodec /= 10.0;
hip_parallax /= 1000.0;
if (hip_parallax <= 0.0)
hip_parallax = 1.0e-7;
double dist = RAD2SEC / hip_parallax;
double r = hip_ra * 54000.0 / RAD2SEC;
double d = hip_dec * 3600.0 / RAD2SEC;
double cra, sra, cdc, sdc, pos1[3], term1, pmr, pmd, vel1[3], pos2[3], xyproj;
cra = cos(r);
sra = sin(r);
cdc = cos(d);
sdc = sin(d);
pos1[0] = dist * cdc * cra;
pos1[1] = dist * cdc * sra;
pos1[2] = dist * sdc;
term1 = hip_parallax * 36525.0;
pmr = hip_promora * 15.0 * cdc / term1;
pmd = hip_promodec / term1;
vel1[0] = -pmr * sra - pmd * sdc * cra;
vel1[1] = pmr * cra - pmd * sdc * sra;
vel1[2] = pmd * cdc;
for (int j = 0; j < 3; j++)
{
pos2[j] = pos1[j] + vel1[j] * (epoch_fk5 - epoch_hip);
}
xyproj = sqrt(pos2[0] * pos2[0] + pos2[1] * pos2[1]);
r = atan2(pos2[1], pos2[0]);
d = atan2(pos2[2], xyproj);
fk5_ra = r * RAD2SEC / 54000.0;
fk5_dec = d * RAD2SEC / 3600.0;
if (fk5_ra < 0.0)
fk5_ra += 24.0;
}

int main()
{
double hip_ra = 6.011119421;
double hip_dec = -0.516998583;
double hip_promora = 328.95;
double hip_promodec = -164.67;
double hip_parallax = 129.81;
double fk5_ra, fk5_dec;

convert(hip_ra, hip_dec, hip_promora, hip_promodec, hip_parallax, fk5_ra, fk5_dec);

double rah = fk5_ra;
cout << " ra: " << fk5_ra;

cout << " rah: " << int(rah) << " ram: " << int((rah - int(rah)) * 60) << " ras: " << 60 * ((rah - int(rah)) * 60 - int((rah - int(rah)) * 60)) << endl;
cout << fk5_dec << endl;
double dech = fk5_dec;
cout << " dech " << int(dech) << " ram: " << int((dech - int(dech)) * 60) << " ras: " << 60 * ((dech - int(dech)) * 60 - int((dech - int(dech)) * 60)) << endl;
system("pause");
return 0;
}

研究一下j2000转 视赤道坐标 的转换

short int app_star (double tjd, body *earth, cat_entry *star, double *ra, double *dec)
/* PURPOSE:
Computes the apparent place of a star at date 'tjd', given its mean place, proper motion, parallax, and radial velocity for J2000.0.
short int get_earth (double tjd, body *earth,
double *tdb,
double *bary_earthp, double *bary_earthv,
double *helio_earthp, double *helio_earthv)
// Obtains the barycentric & heliocentric positions and velocities of the Earth from the solar system ephemeris. 从太阳系星历表中获取地球的重心和日心位置和速度。

在novas第一个函数中

TDB:质心力学时 和 tjd:在novas中就是儒略日;

TT:Terrestrial Time (TT) 地球时

TDT:Terrestrial Dynamical Time

UTC:协调世界时

image-20221207192519170

Barycentric动力学时间(TDB,来自法国温度动态Barycentrique)是一个相对论坐标时间尺度,旨在在计算轨道,小型小行星,彗星和彗星和彗星和彗星和彗星,彗星和彗星,彗星和彗星,彗星和彗星,彗星和彗星,彗星和天文学的轨道和天文学时,供天文使用作为时间标准[1]太阳系中的星际航天器。


c++时间转换

得到UTC时间 https://www.runoob.com/cplusplus/cpp-date-time.html

time_t now = time(0);
tm *utc = gmtime(&now);

cout << fixed << setprecision(10) << julian_date(1900 + utc->tm_year, 1 + utc->tm_mon, utc->tm_mday, utc->tm_hour + utc->tm_min / 60.0 + utc->tm_sec / 3600.0) << endl;

计算儒略日

double julian_date(short int year, short int month, short int day, double hour)
{
long int jd12h = (long)day - 32075L + 1461L * ((long)year + 4800L + ((long)month - 14L) / 12L) / 4L + 367L * ((long)month - 2L - ((long)month - 14L) / 12L * 12L) / 12L - 3L * (((long)year + 4900L + ((long)month - 14L) / 12L) / 100L) / 4L;
double tjd = (double)jd12h - 0.5 + hour / 24.0;

return (tjd);
}

https://en.wikipedia.org/wiki/%CE%94T_(timekeeping)

为了求 The difference between terrestrial dynamical time system 1 time, and universal time.

image-20221208114456687

设置为deltat = 67.

但事实上该值设置完之后反而和软件中的值不一致,因此设为0;

image-20221208202842675

方位角和两个软件误差2’’和0.2’’,高度角相差7’’和0.8’’ ,非常准,验证成功!

关键函数讲解

void equ2hor(double tjd, double deltat, double x, double y, site_info *location, double ra, double dec, short int ref_option, double *zd, double *az, double *rar, double *decr)
// tjd 为儒略日
// deltat应该为 TT (or TDT)-UT1 大约70 但设置了值之后反而和软件中的值不一样 故设为0
// x y 设为0
// site_info loc = {32.08, 118.8, 10, 10, 1013}; 温度和高度都设为10,压强毫巴和百帕一致
// ref_option设为0 no refraction 不考虑蒙气差
//

现在研究一下从hipparcos星表 根据星等 处理为J1991.25

import numpy as np
import pandas as pd
import math

user_cols = ['hip', 'a2', 'a3', 'a4', 'ra', 'dec', 'plx', 'pmra', 'pmdec', 'era',
'ede', 'eplx', 'epmra', 'epmde', 'ntr', 'f2', 'f1', 'var', 'ic', 'hpmag']
mag = [2, 3, 4, 5, 6, 6.5]
for m in mag:
df = pd.read_table("hip2.dat", sep='\s+', header=None,
engine='python', index_col=0, usecols=list(range(20)), names=user_cols)

df1 = df[df['hpmag'] <= m]

tmp = df1['ra'] * 180 / math.pi
df1.insert(df1.shape[1], 'ra_d', tmp)

tmp = df1['dec'] * 180 / math.pi
df1.insert(df1.shape[1], 'dec_d', tmp)
newdf = df1[['ra_d', 'dec_d', 'pmra', 'pmdec', 'plx', 'hpmag']]
newdf.to_csv('J1991_25_'+str(m)+'.csv')

image-20221209181128304

单位分别为:hip、度、度、mas/year、mas/year、mas、星等

image-20221209181146712

hip_main.dat文件中有118322个星

有两种星表

image-20221209162226229

import numpy as np
import pandas as pd
import math
user_cols = ['hip', 'a2', 'a3', 'a4', 'a5', 'ra', 'a6']
df = pd.read_table("hip_main.dat", delimiter='|', header=None,usecols=list(range(7)),names=user_cols)

df["ra"] = [float(str(i).replace(" ", "0")) for i in df["ra"]]
df['ra'].astype(float)

df1 = df[df['ra'] <= 6.5]

针对的是Magnitude in Johnson V 而hip2只有Hpmag Hipparcos magnitude

前为hip1 后为hip2

<= 6.5 有8875个星 7982

< 6.5 8790个星 7982

<= 6.0 5045个星 4559

< 6.0 4996个星 4559

<= 5.0 1628个星 1471

< 5.0 1609个星 1471

<= 4.0 520个星 480

< 4.0 517个星 480

<= 3.0 178个星 165

< 3.0 173个星 165

<= 2.0 50个星 46

< 2.0 50个星 46

<= 1.0 16个星 15

< 1.0 16个星 15

一是 https://heasarc.gsfc.nasa.gov/W3Browse/all/hipparcos.html

image-20221209162308287

二是 http://vizier.cds.unistra.fr/viz-bin/VizieR-3?-source=I/311/hip2

image-20221209162337713

2007年发布了由Hipparcos任务产生的天文数据的新降低,声称几乎全明星的精度比HP = 8的幅度更明亮,要比原始目录中的幅度更好,最高为4。该目录被称为Hipparcos-2目录。


J1991.25 转 J2000

image-20221210161025540

image-20221210161117925

经过验证 没问题,

除了6种星等 只需要0.2s

#include <bits/stdc++.h>

using namespace std;

#define BARYC 0
#define HELIOC 1

const double KMAU = 1.49597870e+8;
const double TWOPI = 6.28318530717958647692;
const double RAD2SEC = 206264.806247096355;
const double DEG2RAD = 0.017453292519943296;
const double epoch_hip = 2448349.0625;
const double epoch_fk5 = 2451545.0000;

typedef struct
{
long int starnumber;
double ra;
double dec;
double promora;
double promodec;
double parallax;
double radialvelocity = 0;
} cat_entry;

void transform_cat(cat_entry *incat, cat_entry *newcat)
{
double paralx, dist, r, d, cra, sra, cdc, sdc, pos1[3], term1, pmr, pmd, rvl, vel1[3], pos2[3], vel2[3], xyproj;

paralx = incat->parallax;
if (paralx <= 0.0)
paralx = 1.0e-7;

dist = RAD2SEC / paralx;
r = incat->ra * 54000.0 / RAD2SEC;
d = incat->dec * 3600.0 / RAD2SEC;
cra = cos(r);
sra = sin(r);
cdc = cos(d);
sdc = sin(d);
pos1[0] = dist * cdc * cra;
pos1[1] = dist * cdc * sra;
pos1[2] = dist * sdc;

term1 = paralx * 36525.0;
pmr = incat->promora * 15.0 * cdc / term1;
pmd = incat->promodec / term1;

vel1[0] = -pmr * sra - pmd * sdc * cra;
vel1[1] = pmr * cra - pmd * sdc * sra;
vel1[2] = pmd * cdc;

for (short j = 0; j < 3; j++)
{
pos2[j] = pos1[j] + vel1[j] * (epoch_fk5 - epoch_hip);
vel2[j] = vel1[j];
}

xyproj = sqrt(pos2[0] * pos2[0] + pos2[1] * pos2[1]);
r = atan2(pos2[1], pos2[0]);
d = atan2(pos2[2], xyproj);
newcat->ra = r * RAD2SEC / 54000.0;
newcat->dec = d * RAD2SEC / 3600.0;
if (newcat->ra < 0.0)
newcat->ra += 24.0;

dist = sqrt(pos2[0] * pos2[0] + pos2[1] * pos2[1] +
pos2[2] * pos2[2]);
paralx = RAD2SEC / dist;
newcat->parallax = paralx;

cra = cos(r);
sra = sin(r);
cdc = cos(d);
sdc = sin(d);
pmr = -vel2[0] * sra + vel2[1] * cra;
pmd = -vel2[0] * cra * sdc - vel2[1] * sra * sdc + vel2[2] * cdc;
rvl = vel2[0] * cra * cdc + vel2[1] * sra * cdc + vel2[2] * sdc;

newcat->promora = pmr * paralx * 36525.0 / (15.0 * cdc);
newcat->promodec = pmd * paralx * 36525.0;
newcat->radialvelocity = rvl * KMAU / 86400.0;

if (newcat->parallax <= 1.01e-7)
{
newcat->parallax = 0.0;
newcat->radialvelocity = incat->radialvelocity;
}

newcat->starnumber = incat->starnumber;

return;
}

void transform_hip(cat_entry *hipparcos, cat_entry *fk5)
{
cat_entry scratch;
scratch.starnumber = hipparcos->starnumber;
scratch.dec = hipparcos->dec;
scratch.radialvelocity = hipparcos->radialvelocity;

scratch.ra = hipparcos->ra / 15.0;
scratch.promora = hipparcos->promora / (150.0 *
cos(hipparcos->dec * DEG2RAD));
scratch.promodec = hipparcos->promodec / 10.0;
scratch.parallax = hipparcos->parallax / 1000.0;

transform_cat(&scratch, fk5);

return;
}

int main()
{
clock_t start, end; // 定义clock_t变量

start = clock(); // 开始时间

cat_entry hip, fk5;
vector<string> files = {"2", "3", "4", "5", "6", "6.5"};
for (int i = 0; i < files.size(); i++)
{
ifstream inFile("C:\\Users\\hp\\Downloads\\hip2.dat\\J1991_25_" + files[i] + ".csv");
ofstream outFile("C:\\Users\\hp\\Downloads\\hip2.dat\\J2000_" + files[i] + ".csv");
string lineStr;
double hgmag;
getline(inFile, lineStr); // 跳过列名,第一行不做处理

while (getline(inFile, lineStr))
{
// cout << lineStr << endl;
// 存成二维表结构
stringstream ss(lineStr);
string str;
// 按照逗号分隔
getline(ss, str, ',');
hip.starnumber = stod(str);
getline(ss, str, ',');
hip.ra = stod(str);
getline(ss, str, ',');
hip.dec = stod(str);
getline(ss, str, ',');
hip.promora = stod(str);
getline(ss, str, ',');
hip.promodec = stod(str);
getline(ss, str, ',');
hip.parallax = stod(str);
getline(ss, str, ',');
hgmag = stod(str);

transform_hip(&hip, &fk5);

// cout << " hip " << hip.starnumber << " ra " << hip.ra << " dec " << hip.dec << " promora: " << hip.promora << " promodec: " << hip.promodec << " para " << hip.parallax << endl;
outFile << fk5.starnumber << "," << fk5.ra << "," << fk5.dec << "," << fk5.promora << "," << fk5.promodec << "," << fk5.parallax << "," << hgmag << "\n";
}
}

end = clock(); // 结束时间
cout << "time = " << double(end - start) / CLOCKS_PER_SEC << "s" << endl; // 输出时间(单位:s)
system("pause");
return 0;
}

最终代码(novas有阉割)为

#include <bits/stdc++.h>
using namespace std;

#define BARYC 0
#define HELIOC 1

const double T0 = 2451545.00000000;
const double KMAU = 1.49597870e+8;
const double MAU = 1.49597870e+11;
const double C = 173.14463348;
const double GS = 1.32712438e+20;
const double TWOPI = 6.28318530717958647692;
const double RAD2SEC = 206264.806247096355;
const double DEG2RAD = 0.017453292519943296;
const double RAD2DEG = 57.295779513082321;
const double epoch_hip = 2448349.0625;
const double epoch_fk5 = 2451545.0000;
static double PSI_COR = 0.0;
static double EPS_COR = 0.0;
const short int FN0 = 0;

typedef struct
{
long int starnumber;
double ra;
double dec;
double promora;
double promodec;
double parallax;
double radialvelocity;
} cat_entry;

typedef struct
{
double latitude;
double longitude;
} site_info;

short int vector2radec(double *pos, double *ra, double *dec)
{
double xyproj;

xyproj = sqrt(pow(pos[0], 2.0) + pow(pos[1], 2.0));
if ((xyproj == 0.0) && (pos[2] == 0))
{
*ra = 0.0;
*dec = 0.0;
return 1;
}
else if (xyproj == 0.0)
{
*ra = 0.0;
if (pos[2] < 0.0)
*dec = -90.0;
else
*dec = 90.0;
return 2;
}
else
{
*ra = atan2(pos[1], pos[0]) * RAD2SEC / 54000.0;
*dec = atan2(pos[2], xyproj) * RAD2SEC / 3600.0;

if (*ra < 0.0)
*ra += 24.0;
}
return 0;
}

void fund_args(double t, double a[5])
{
short int i;

a[0] = 2.3555483935439407 + t * (8328.691422883896 + t * (1.517951635553957e-4 + 3.1028075591010306e-7 * t));
a[1] = 6.240035939326023 + t * (628.3019560241842 + t * (-2.7973749400020225e-6 - 5.817764173314431e-8 * t));
a[2] = 1.6279019339719611 + t * (8433.466158318453 + t * (-6.427174970469119e-5 + 5.332950492204896e-8 * t));
a[3] = 5.198469513579922 + t * (7771.377146170642 + t * (-3.340851076525812e-5 + 9.211459941081184e-8 * t));
a[4] = 2.1824386243609943 + t * (-33.75704593375351 + t * (3.614285992671591e-5 + 3.878509448876288e-8 * t));

for (i = 0; i < 5; i++)
{
a[i] = fmod(a[i], TWOPI);
if (a[i] < 0.0)
a[i] += TWOPI;
}

return;
}

short int nutation_angles(double t, double *longnutation, double *obliqnutation)
{
double clng[106] = {1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0,
-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0,
-1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0,
1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 2.0,
2.0, 2.0, 2.0, 2.0, -2.0, 2.0, 2.0,
2.0, 3.0, -3.0, -3.0, 3.0, -3.0, 3.0,
-3.0, 3.0, 4.0, 4.0, -4.0, -4.0, 4.0,
-4.0, 5.0, 5.0, 5.0, -5.0, 6.0, 6.0,
6.0, -6.0, 6.0, -7.0, 7.0, 7.0, -7.0,
-8.0, 10.0, 11.0, 12.0, -13.0, -15.0, -16.0,
-16.0, 17.0, -21.0, -22.0, 26.0, 29.0, 29.0,
-31.0, -38.0, -46.0, 48.0, -51.0, 58.0, 59.0,
63.0, 63.0, -123.0, 129.0, -158.0, -217.0, -301.0,
-386.0, -517.0, 712.0, 1426.0, 2062.0, -2274.0,
-13187.0, -171996.0},
clngx[14] = {0.1, -0.1, 0.1, 0.1, 0.1, 0.1, 0.2, -0.2, -0.4, 0.5, 1.2,
-1.6, -3.4, -174.2},
cobl[64] = {1.0, 1.0, 1.0, -1.0, -1.0, -1.0,
1.0, 1.0, 1.0, 1.0, 1.0, -1.0,
1.0, -1.0, 1.0, -1.0, -1.0, -1.0,
1.0, -1.0, 1.0, 1.0, -1.0, -2.0,
-2.0, -2.0, 3.0, 3.0, -3.0, 3.0,
3.0, -3.0, 3.0, 3.0, -3.0, 3.0,
3.0, 5.0, 6.0, 7.0, -7.0, 7.0,
-8.0, 9.0, -10.0, -12.0, 13.0, 16.0,
-24.0, 26.0, 27.0, 32.0, -33.0, -53.0,
54.0, -70.0, -95.0, 129.0, 200.0, 224.0,
-895.0, 977.0, 5736.0, 92025.0},
coblx[8] = {-0.1, -0.1, 0.3, 0.5, -0.5, -0.6, -3.1, 8.9};

short int i, ii, i1, i2, iop;
short int nav1[10] = {0, 0, 1, 0, 2, 1, 3, 0, 4, 0},
nav2[10] = {0, 0, 0, 5, 1, 1, 3, 3, 4, 4},
nav[183] = {2, 0, 1, 1, 5, 2, 2, 0, 2, 1, 0, 3, 2, 5, 8, 1, 17, 8,
1, 18, 0, 2, 0, 8, 0, 1, 3, 2, 1, 8, 0, 17, 1, 1, 15, 1,
2, 21, 1, 1, 2, 8, 2, 0, 29, 1, 21, 2, 2, 1, 29, 2, 0, 9,
2, 5, 4, 2, 0, 4, 0, 1, 9, 2, 1, 4, 0, 2, 9, 2, 2, 4,
1, 14, 44, 2, 0, 45, 2, 5, 44, 2, 50, 0, 1, 36, 2, 2, 5, 45,
1, 37, 2, 2, 1, 45, 2, 1, 44, 2, 53, 1, 2, 8, 4, 1, 40, 3,
2, 17, 4, 2, 0, 64, 1, 39, 8, 2, 27, 4, 1, 50, 18, 1, 21, 47,
2, 44, 3, 2, 44, 8, 2, 45, 8, 1, 46, 8, 0, 67, 2, 1, 5, 74,
1, 0, 74, 2, 50, 8, 1, 5, 78, 2, 17, 53, 2, 53, 8, 2, 0, 80,
2, 0, 81, 0, 7, 79, 1, 7, 81, 2, 1, 81, 2, 24, 44, 1, 1, 79,
2, 27, 44},
llng[106] = {57, 25, 82, 34, 41, 66, 33, 36, 19, 88, 18, 104, 93,
84, 47, 28, 83, 86, 69, 75, 89, 30, 58, 73, 46, 77,
23, 32, 59, 72, 31, 16, 74, 22, 98, 38, 62, 96, 37,
35, 6, 76, 85, 51, 26, 10, 13, 63, 105, 52, 102, 67,
99, 15, 24, 14, 3, 100, 65, 11, 55, 68, 20, 87, 64,
95, 27, 60, 61, 80, 91, 94, 12, 43, 71, 42, 97, 70,
7, 49, 29, 2, 5, 92, 50, 78, 56, 17, 48, 40, 90,
8, 39, 54, 81, 21, 103, 53, 45, 101, 0, 1, 9, 44,
79, 4},
llngx[14] = {81, 7, 97, 0, 39, 40, 9, 44, 45, 103, 101, 79, 1, 4},
lobl[64] = {51, 98, 17, 21, 5, 2, 63, 105, 38, 52, 102, 62, 96,
37, 35, 76, 36, 88, 85, 104, 93, 84, 83, 67, 99, 8,
68, 100, 60, 61, 91, 87, 64, 80, 95, 65, 55, 94, 43,
97, 0, 71, 70, 42, 49, 92, 50, 78, 56, 90, 48, 40,
39, 54, 1, 81, 103, 53, 45, 101, 9, 44, 79, 4},
loblx[8] = {53, 1, 103, 9, 44, 101, 79, 4};

double a[5], angle, cc, ss1, cs, sc, c[106], s[106], lng, lngx, obl,
oblx;

fund_args(t, a);

i = 0;
for (ii = 0; ii < 10; ii += 2)
{
angle = a[nav1[ii]] * (double)(nav1[1 + ii] + 1);
c[i] = cos(angle);
s[i] = sin(angle);
i += 1;
}

i = 5;
for (ii = 0; ii < 10; ii += 2)
{
i1 = nav2[ii];
i2 = nav2[1 + ii];

c[i] = c[i1] * c[i2] - s[i1] * s[i2];
s[i] = s[i1] * c[i2] + c[i1] * s[i2];
i += 1;
}

i = 10;
for (ii = 0; ii < 183; ii += 3)
{
iop = nav[ii];
i1 = nav[1 + ii];
i2 = nav[2 + ii];
switch (iop)
{
case 0:
c[i] = c[i1] * c[i2] - s[i1] * s[i2];
s[i] = s[i1] * c[i2] + c[i1] * s[i2];
i += 1;
break;
case 1:
c[i] = c[i1] * c[i2] + s[i1] * s[i2];
s[i] = s[i1] * c[i2] - c[i1] * s[i2];
i += 1;
break;
case 2:
cc = c[i1] * c[i2];
ss1 = s[i1] * s[i2];
sc = s[i1] * c[i2];
cs = c[i1] * s[i2];
c[i] = cc - ss1;
s[i] = sc + cs;
i += 1;
c[i] = cc + ss1;
s[i] = sc - cs;
i += 1;
break;
}
if (iop == 3)
break;
}

lng = 0.0;
for (i = 0; i < 106; i++)
lng += clng[i] * s[llng[i]];

lngx = 0.0;
for (i = 0; i < 14; i++)
lngx += clngx[i] * s[llngx[i]];

obl = 0.0;
for (i = 0; i < 64; i++)
obl += cobl[i] * c[lobl[i]];

oblx = 0.0;
for (i = 0; i < 8; i++)
oblx += coblx[i] * c[loblx[i]];

*longnutation = (lng + t * lngx) / 10000.0;
*obliqnutation = (obl + t * oblx) / 10000.0;

return 0;
}

void earthtilt(double tjd, double *mobl, double *tobl, double *eq, double *dpsi, double *deps)
{
static double tjd_last = 0.0;
static double t, dp, de;
double mean_obliq, true_obliq, eq_eq, args[5];

t = (tjd - T0) / 36525.0;

if (fabs(tjd - tjd_last) > 1.0e-6)
nutation_angles(t, &dp, &de);

mean_obliq = 84381.4480 - 46.8150 * t - 0.00059 * pow(t, 2.0) + 0.001813 * pow(t, 3.0);

true_obliq = mean_obliq + de;

mean_obliq /= 3600.0;
true_obliq /= 3600.0;

fund_args(t, args);

eq_eq = dp * cos(mean_obliq * DEG2RAD) +
(0.00264 * sin(args[4]) + 0.000063 * sin(2.0 * args[4]));

eq_eq /= 15.0;

*dpsi = dp;
*deps = de;
*eq = eq_eq;
*mobl = mean_obliq;
*tobl = true_obliq;

return;
}

void starvectors(cat_entry *star, double *pos, double *vel)
{
double paralx, dist, r, d, cra, sra, cdc, sdc, pmr, pmd, rvl;

paralx = star->parallax;

if (star->parallax <= 0.0)
paralx = 1.0e-7;

dist = RAD2SEC / paralx;
r = (star->ra) * 15.0 * DEG2RAD;
d = (star->dec) * DEG2RAD;
cra = cos(r);
sra = sin(r);
cdc = cos(d);
sdc = sin(d);

pos[0] = dist * cdc * cra;
pos[1] = dist * cdc * sra;
pos[2] = dist * sdc;

pmr = star->promora * 15.0 * cdc / (paralx * 36525.0);
pmd = star->promodec / (paralx * 36525.0);
rvl = star->radialvelocity * 86400.0 / KMAU;
vel[0] = -pmr * sra - pmd * sdc * cra + rvl * cdc * cra;
vel[1] = pmr * cra - pmd * sdc * sra + rvl * cdc * sra;
vel[2] = pmd * cdc + rvl * sdc;

return;
}

void tdb2tdt(double tdb, double *tdtjd, double *secdiff)
{
double ecc = 0.01671022;
double rev = 1296000.0;
double tdays, m, l, lj, e;

tdays = tdb - T0;
m = (357.51716 + 0.985599987 * tdays) * 3600.0;
l = (280.46435 + 0.985609100 * tdays) * 3600.0;
lj = (34.40438 + 0.083086762 * tdays) * 3600.0;
m = fmod(m, rev) / RAD2SEC;
l = fmod(l, rev) / RAD2SEC;
lj = fmod(lj, rev) / RAD2SEC;
e = m + ecc * sin(m) + 0.5 * ecc * ecc * sin(2.0 * m);
*secdiff = 1.658e-3 * sin(e) + 20.73e-6 * sin(l - lj);
*tdtjd = tdb - *secdiff / 86400.0;

return;
}

void precession(double tjd1, double *pos, double tjd2, double *pos2);

void transform_cat(cat_entry *incat, cat_entry *newcat)
{
short int j;

double paralx, dist, r, d, cra, sra, cdc, sdc, pos1[3], term1, pmr, pmd, rvl, vel1[3], pos2[3], vel2[3], xyproj;

paralx = incat->parallax;
if (paralx <= 0.0)
paralx = 1.0e-7;

dist = RAD2SEC / paralx;
r = incat->ra * 54000.0 / RAD2SEC;
d = incat->dec * 3600.0 / RAD2SEC;
cra = cos(r);
sra = sin(r);
cdc = cos(d);
sdc = sin(d);
pos1[0] = dist * cdc * cra;
pos1[1] = dist * cdc * sra;
pos1[2] = dist * sdc;

term1 = paralx * 36525.0;
pmr = incat->promora * 15.0 * cdc / term1;
pmd = incat->promodec / term1;

vel1[0] = -pmr * sra - pmd * sdc * cra;
vel1[1] = pmr * cra - pmd * sdc * sra;
vel1[2] = pmd * cdc;

for (j = 0; j < 3; j++)
{
pos2[j] = pos1[j] + vel1[j] * (epoch_fk5 - epoch_hip);
vel2[j] = vel1[j];
}

xyproj = sqrt(pos2[0] * pos2[0] + pos2[1] * pos2[1]);
r = atan2(pos2[1], pos2[0]);
d = atan2(pos2[2], xyproj);
newcat->ra = r * RAD2SEC / 54000.0;
newcat->dec = d * RAD2SEC / 3600.0;
if (newcat->ra < 0.0)
newcat->ra += 24.0;

dist = sqrt(pos2[0] * pos2[0] + pos2[1] * pos2[1] +
pos2[2] * pos2[2]);
paralx = RAD2SEC / dist;
newcat->parallax = paralx;

cra = cos(r);
sra = sin(r);
cdc = cos(d);
sdc = sin(d);
pmr = -vel2[0] * sra + vel2[1] * cra;
pmd = -vel2[0] * cra * sdc - vel2[1] * sra * sdc + vel2[2] * cdc;
rvl = vel2[0] * cra * cdc + vel2[1] * sra * cdc + vel2[2] * sdc;

newcat->promora = pmr * paralx * 36525.0 / (15.0 * cdc);
newcat->promodec = pmd * paralx * 36525.0;
newcat->radialvelocity = rvl * KMAU / 86400.0;

if (newcat->parallax <= 1.01e-7)
{
newcat->parallax = 0.0;
newcat->radialvelocity = incat->radialvelocity;
}

newcat->starnumber = incat->starnumber;

return;
}

void transform_hip(cat_entry *hipparcos, cat_entry *fk5)
{
cat_entry scratch;
scratch.starnumber = hipparcos->starnumber;
scratch.dec = hipparcos->dec;
scratch.radialvelocity = hipparcos->radialvelocity;

scratch.ra = hipparcos->ra / 15.0;
scratch.promora = hipparcos->promora / (150.0 *
cos(hipparcos->dec * DEG2RAD));
scratch.promodec = hipparcos->promodec / 10.0;
scratch.parallax = hipparcos->parallax / 1000.0;

transform_cat(&scratch, fk5);

return;
}

void sun_eph(double jd, double *ra, double *dec, double *dis)
{
short int i;

double sum_lon = 0.0;
double sum_r = 0.0;
const double factor = 1.0e-07;
double u, arg, lon, lat, t, t2, emean, sin_lon;

struct sun_con
{
double l;
double r;
double alpha;
double nu;
};

static const struct sun_con con[50] =
{{403406.0, 0.0, 4.721964, 1.621043},
{195207.0, -97597.0, 5.937458, 62830.348067},
{119433.0, -59715.0, 1.115589, 62830.821524},
{112392.0, -56188.0, 5.781616, 62829.634302},
{3891.0, -1556.0, 5.5474, 125660.5691},
{2819.0, -1126.0, 1.5120, 125660.9845},
{1721.0, -861.0, 4.1897, 62832.4766},
{0.0, 941.0, 1.163, 0.813},
{660.0, -264.0, 5.415, 125659.310},
{350.0, -163.0, 4.315, 57533.850},
{334.0, 0.0, 4.553, -33.931},
{314.0, 309.0, 5.198, 777137.715},
{268.0, -158.0, 5.989, 78604.191},
{242.0, 0.0, 2.911, 5.412},
{234.0, -54.0, 1.423, 39302.098},
{158.0, 0.0, 0.061, -34.861},
{132.0, -93.0, 2.317, 115067.698},
{129.0, -20.0, 3.193, 15774.337},
{114.0, 0.0, 2.828, 5296.670},
{99.0, -47.0, 0.52, 58849.27},
{93.0, 0.0, 4.65, 5296.11},
{86.0, 0.0, 4.35, -3980.70},
{78.0, -33.0, 2.75, 52237.69},
{72.0, -32.0, 4.50, 55076.47},
{68.0, 0.0, 3.23, 261.08},
{64.0, -10.0, 1.22, 15773.85},
{46.0, -16.0, 0.14, 188491.03},
{38.0, 0.0, 3.44, -7756.55},
{37.0, 0.0, 4.37, 264.89},
{32.0, -24.0, 1.14, 117906.27},
{29.0, -13.0, 2.84, 55075.75},
{28.0, 0.0, 5.96, -7961.39},
{27.0, -9.0, 5.09, 188489.81},
{27.0, 0.0, 1.72, 2132.19},
{25.0, -17.0, 2.56, 109771.03},
{24.0, -11.0, 1.92, 54868.56},
{21.0, 0.0, 0.09, 25443.93},
{21.0, 31.0, 5.98, -55731.43},
{20.0, -10.0, 4.03, 60697.74},
{18.0, 0.0, 4.27, 2132.79},
{17.0, -12.0, 0.79, 109771.63},
{14.0, 0.0, 4.24, -7752.82},
{13.0, -5.0, 2.01, 188491.91},
{13.0, 0.0, 2.65, 207.81},
{13.0, 0.0, 4.98, 29424.63},
{12.0, 0.0, 0.93, -7.99},
{10.0, 0.0, 2.21, 46941.14},
{10.0, 0.0, 3.59, -68.29},
{10.0, 0.0, 1.50, 21463.25},
{10.0, -9.0, 2.55, 157208.40}};

u = (jd - T0) / 3652500.0;

for (i = 0; i < 50; i++)
{
arg = con[i].alpha + con[i].nu * u;
sum_lon += con[i].l * sin(arg);
sum_r += con[i].r * cos(arg);
}

lon = 4.9353929 + 62833.1961680 * u + factor * sum_lon;

lon = fmod(lon, TWOPI);
if (lon < 0.0)
lon += TWOPI;

lat = 0.0;

*dis = 1.0001026 + factor * sum_r;

t = u * 100.0;
t2 = t * t;
emean = (0.001813 * t2 * t - 0.00059 * t2 - 46.8150 * t + 84381.448) / RAD2SEC;

sin_lon = sin(lon);
*ra = atan2((cos(emean) * sin_lon), cos(lon)) * RAD2DEG;
*ra = fmod(*ra, 360.0);
if (*ra < 0.0)
*ra += 360.0;
*ra = *ra / 15.0;

*dec = asin(sin(emean) * sin_lon) * RAD2DEG;

return;
}

void precession(double tjd1, double *pos, double tjd2, double *pos2)
{
double xx, yx, zx, xy, yy, zy, xz, yz, zz, t, t1, t02, t2, t3, zeta0, zee, theta;

t = (tjd1 - T0) / 36525.0;
t1 = (tjd2 - tjd1) / 36525.0;
t02 = t * t;
t2 = t1 * t1;
t3 = t2 * t1;
zeta0 = (2306.2181 + 1.39656 * t - 0.000139 * t02) * t1 + (0.30188 - 0.000344 * t) * t2 + 0.017998 * t3;

zee = (2306.2181 + 1.39656 * t - 0.000139 * t02) * t1 + (1.09468 + 0.000066 * t) * t2 + 0.018203 * t3;

theta = (2004.3109 - 0.85330 * t - 0.000217 * t02) * t1 + (-0.42665 - 0.000217 * t) * t2 - 0.041833 * t3;

zeta0 /= RAD2SEC;
zee /= RAD2SEC;
theta /= RAD2SEC;
xx = cos(zeta0) * cos(theta) * cos(zee) - sin(zeta0) * sin(zee);
yx = -sin(zeta0) * cos(theta) * cos(zee) - cos(zeta0) *
sin(zee);
zx = -sin(theta) * cos(zee);
xy = cos(zeta0) * cos(theta) * sin(zee) + sin(zeta0) * cos(zee);
yy = -sin(zeta0) * cos(theta) * sin(zee) + cos(zeta0) *
cos(zee);
zy = -sin(theta) * sin(zee);
xz = cos(zeta0) * sin(theta);
yz = -sin(zeta0) * sin(theta);
zz = cos(theta);
pos2[0] = xx * pos[0] + yx * pos[1] + zx * pos[2];
pos2[1] = xy * pos[0] + yy * pos[1] + zy * pos[2];
pos2[2] = xz * pos[0] + yz * pos[1] + zz * pos[2];

return;
}

void radec2vector(double ra, double dec, double dist, double *vector)
{
vector[0] = dist * cos(DEG2RAD * dec) * cos(DEG2RAD * 15.0 * ra);
vector[1] = dist * cos(DEG2RAD * dec) * sin(DEG2RAD * 15.0 * ra);
vector[2] = dist * sin(DEG2RAD * dec);
return;
}
short int solarsystem(double tjd, short int origin, double *pos, double *vel)
{
short int ierr = 0;
short int i;
const double pm[4] = {1047.349, 3497.898, 22903.0, 19412.2};
const double pa[4] = {5.203363, 9.537070, 19.191264, 30.068963};
const double pl[4] = {0.600470, 0.871693, 5.466933, 5.321160};
const double pn[4] = {1.450138e-3, 5.841727e-4, 2.047497e-4, 1.043891e-4};
const double obl = 23.43929111;

static double tlast = 0.0;
static double sine, cose, tmass, pbary[3], vbary[3];

double oblr, qjd, ras, decs, diss, pos1[3], p[3][3], dlon, sinl, cosl, x, y, z, xdot, ydot, zdot, f;

if (tlast == 0.0)
{
oblr = obl * TWOPI / 360.0;
sine = sin(oblr);
cose = cos(oblr);
tmass = 1.0;
for (i = 0; i < 4; i++)
tmass += 1.0 / pm[i];
tlast = 1.0;
}

if ((tjd < 2340000.5) || (tjd > 2560000.5))
return (ierr = 1);

for (i = 0; i < 3; i++)
{
qjd = tjd + (double)(i - 1) * 0.1;
sun_eph(qjd, &ras, &decs, &diss);
radec2vector(ras, decs, diss, pos1);
precession(qjd, pos1, T0, pos);
p[i][0] = -pos[0];
p[i][1] = -pos[1];
p[i][2] = -pos[2];
}
for (i = 0; i < 3; i++)
{
pos[i] = p[1][i];
vel[i] = (p[2][i] - p[0][i]) / 0.2;
}

if (origin == 0)
{
if (fabs(tjd - tlast) >= 1.0e-06)
{
for (i = 0; i < 3; i++)
pbary[i] = vbary[i] = 0.0;

for (i = 0; i < 4; i++)
{
dlon = pl[i] + pn[i] * (tjd - T0);
dlon = fmod(dlon, TWOPI);
sinl = sin(dlon);
cosl = cos(dlon);

x = pa[i] * cosl;
y = pa[i] * sinl * cose;
z = pa[i] * sinl * sine;
xdot = -pa[i] * pn[i] * sinl;
ydot = pa[i] * pn[i] * cosl * cose;
zdot = pa[i] * pn[i] * cosl * sine;

f = 1.0 / (pm[i] * tmass);

pbary[0] += x * f;
pbary[1] += y * f;
pbary[2] += z * f;
vbary[0] += xdot * f;
vbary[1] += ydot * f;
vbary[2] += zdot * f;
}

tlast = tjd;
}

for (i = 0; i < 3; i++)
{
pos[i] -= pbary[i];
vel[i] -= vbary[i];
}
}

return (ierr);
}

void proper_motion(double tjd1, double *pos, double *vel, double tjd2, double *pos2)
{
short int j;

for (j = 0; j < 3; j++)
pos2[j] = pos[j] + (vel[j] * (tjd2 - tjd1));

return;
}

short int get_earth(double tjd, double *tdb, double *bary_earthp, double *bary_earthv, double *helio_earthp, double *helio_earthv)
{
short int error = 0;

static double tjd_last = 0.0;
static double time1, peb[3], veb[3], pes[3], ves[3];
double dummy, secdiff;

if (fabs(tjd - tjd_last) > 1.0e-6)
{
tdb2tdt(tjd, &dummy, &secdiff);
time1 = tjd + secdiff / 86400.0;

if (error = solarsystem(time1, BARYC, peb, veb))
{
tjd_last = 0.0;
return error;
}

if (error = solarsystem(time1, HELIOC, pes, ves))
{
tjd_last = 0.0;
return error;
}
tjd_last = tjd;
}

*tdb = time1;
for (short int i = 0; i < 3; i++)
{
bary_earthp[i] = peb[i];
bary_earthv[i] = veb[i];
helio_earthp[i] = pes[i];
helio_earthv[i] = ves[i];
}

return error;
}
void bary_to_geo(double *pos, double *earthvector, double *pos2, double *lighttime)

{
short int j;

double sum_of_squares;

for (j = 0; j < 3; j++)
pos2[j] = pos[j] - earthvector[j];

sum_of_squares = pow(pos2[0], 2.0) + pow(pos2[1], 2.0) + pow(pos2[2], 2.0);

*lighttime = sqrt(sum_of_squares) / C;

return;
}

short int sun_field(double *pos, double *earthvector, double *pos2)

{
short int j;

double f = 0.0;
double p1mag, pemag, cosd, sind, b, bm, pqmag, zfinl, zinit,
xifinl, xiinit, delphi, delphp, delp, p1hat[3], pehat[3];

double c = (C * MAU) / 86400.0;

p1mag = sqrt(pow(pos[0], 2.0) + pow(pos[1], 2.0) + pow(pos[2], 2.0));
pemag = sqrt(pow(earthvector[0], 2.0) + pow(earthvector[1], 2.0) + pow(earthvector[2], 2.0));

for (j = 0; j < 3; j++)
{
p1hat[j] = pos[j] / p1mag;
pehat[j] = earthvector[j] / pemag;
}

cosd = -pehat[0] * p1hat[0] - pehat[1] * p1hat[1] - pehat[2] * p1hat[2];

if (fabs(cosd) > 0.9999999999)
{
for (j = 0; j < 3; j++)
pos2[j] = pos[j];
}
else
{
sind = sqrt(1.0 - pow(cosd, 2.0));

b = pemag * sind;
bm = b * MAU;

pqmag = sqrt(pow(p1mag, 2.0) + pow(pemag, 2.0) - 2.0 * p1mag * pemag * cosd);

zfinl = pemag * cosd;
zinit = -p1mag + zfinl;
xifinl = zfinl / b;
xiinit = zinit / b;

delphi = 2.0 * GS / (bm * c * c) * (xifinl / sqrt(1.0 + pow(xifinl, 2.0)) - xiinit / sqrt(1.0 + pow(xiinit, 2.0)));

delphp = delphi / (1.0 + (pemag / pqmag));

f = delphp * p1mag / sind;

for (j = 0; j < 3; j++)
{
delp = f * (cosd * p1hat[j] + pehat[j]);
pos2[j] = pos[j] + delp;
}
}

return 0;
}

short int aberration(double *pos, double *ve, double lighttime, double *pos2)
{
double p1mag, vemag, beta, dot, cosd, gammai, p, q, r;

if (lighttime == 0.0)
{
p1mag = sqrt(pow(pos[0], 2.0) + pow(pos[1], 2.0) + pow(pos[2], 2.0));
lighttime = p1mag / C;
}
else
p1mag = lighttime * C;

vemag = sqrt(pow(ve[0], 2.0) + pow(ve[1], 2.0) + pow(ve[2], 2.0));
beta = vemag / C;
dot = pos[0] * ve[0] + pos[1] * ve[1] + pos[2] * ve[2];

cosd = dot / (p1mag * vemag);
gammai = sqrt(1.0 - pow(beta, 2.0));
p = beta * cosd;
q = (1.0 + p / (1.0 + gammai)) * lighttime;
r = 1.0 + p;

for (short int j = 0; j < 3; j++)
pos2[j] = (gammai * pos[j] + q * ve[j]) / r;

return 0;
}

short int nutate(double tjd, short int fn, double *pos, double *pos2)
{
double cobm, sobm, cobt, sobt, cpsi, spsi, xx, yx, zx, xy, yy, zy, xz, yz, zz, oblm, oblt, eqeq, psi, eps;

earthtilt(tjd, &oblm, &oblt, &eqeq, &psi, &eps);

cobm = cos(oblm * DEG2RAD);
sobm = sin(oblm * DEG2RAD);
cobt = cos(oblt * DEG2RAD);
sobt = sin(oblt * DEG2RAD);
cpsi = cos(psi / RAD2SEC);
spsi = sin(psi / RAD2SEC);

xx = cpsi;
yx = -spsi * cobm;
zx = -spsi * sobm;
xy = spsi * cobt;
yy = cpsi * cobm * cobt + sobm * sobt;
zy = cpsi * sobm * cobt - cobm * sobt;
xz = spsi * sobt;
yz = cpsi * cobm * sobt - sobm * cobt;
zz = cpsi * sobm * sobt + cobm * cobt;

if (!fn)
{

pos2[0] = xx * pos[0] + yx * pos[1] + zx * pos[2];
pos2[1] = xy * pos[0] + yy * pos[1] + zy * pos[2];
pos2[2] = xz * pos[0] + yz * pos[1] + zz * pos[2];
}
else
{

pos2[0] = xx * pos[0] + xy * pos[1] + xz * pos[2];
pos2[1] = yx * pos[0] + yy * pos[1] + yz * pos[2];
pos2[2] = zx * pos[0] + zy * pos[1] + zz * pos[2];
}
return 0;
}

short int app_star(double tjd, cat_entry *star, double *ra, double *dec)
{
short int error = 0;

double tdb, time2, peb[3], veb[3], pes[3], ves[3], pos1[3], pos2[3],
pos3[3], pos4[3], pos5[3], pos6[3], pos7[3], vel1[3];

if (error = get_earth(tjd, &tdb, peb, veb, pes, ves))
{
*ra = 0.0;
*dec = 0.0;
return error;
}
starvectors(star, pos1, vel1);
proper_motion(T0, pos1, vel1, tdb, pos2);

bary_to_geo(pos2, peb, pos3, &time2);
sun_field(pos3, pes, pos4);
aberration(pos4, veb, time2, pos5);
precession(T0, pos5, tdb, pos6);
nutate(tdb, FN0, pos6, pos7);

vector2radec(pos7, ra, dec);

return 0;
}

void spin(double st, double *pos1, double *pos2)
{
double str, cosst, sinst, xx, yx, xy, yy;

str = st * 15.0 * DEG2RAD;
cosst = cos(str);
sinst = sin(str);

xx = cosst;
yx = -sinst;
xy = sinst;
yy = cosst;

pos2[0] = xx * pos1[0] + yx * pos1[1];
pos2[1] = xy * pos1[0] + yy * pos1[1];
pos2[2] = pos1[2];

return;
}
void pnsw(double gast, double *vece, double *vecs)
{
double dummy, v1[3], v2[3], v3[3];

short int j;

for (j = 0; j < 3; j++)
v1[j] = vece[j];

if (gast == 0.0)
{
for (j = 0; j < 3; j++)
v2[j] = v1[j];
}
else
spin(gast, v1, v2);

for (j = 0; j < 3; j++)
vecs[j] = v2[j];

return;
}

void sidereal_time(double jd_high, double ee, double *gst)
{
double t_hi, t_lo, t, t2, t3, st;

t_hi = (jd_high - T0) / 36525.0;
t_lo = 0;
t = t_hi;
t2 = t * t;
t3 = t2 * t;

st = ee - 6.2e-6 * t3 + 0.093104 * t2 + 67310.54841 + 8640184.812866 * t_lo + 3155760000.0 * t_lo + 8640184.812866 * t_hi + 3155760000.0 * t_hi;

*gst = fmod((st / 3600.0), 24.0);

if (*gst < 0.0)
*gst += 24.0;

return;
}

void equ2hor(double tjd, site_info *location, double ra, double dec, double *zd, double *az, double *rar, double *decr)
{
short int j;

double ujd, dummy, secdiff, tdb, mobl, tobl, ee, dpsi, deps, gast,
sinlat, coslat, sinlon, coslon, sindc, cosdc, sinra, cosra,
uze[3], une[3], uwe[3], uz[3], un[3], uw[3], p[3], pz, pn, pw,
proj, zd0, zd1, refr, cosr, prlen, rlen, pr[3];

ujd = tjd;

tdb2tdt(tjd, &dummy, &secdiff);
tdb = tjd + secdiff / 86400.0;

earthtilt(tdb, &mobl, &tobl, &ee, &dpsi, &deps);

sidereal_time(ujd, ee, &gast);
*rar = ra;
*decr = dec;

sinlat = sin(location->latitude * DEG2RAD);
coslat = cos(location->latitude * DEG2RAD);
sinlon = sin(location->longitude * DEG2RAD);
coslon = cos(location->longitude * DEG2RAD);
sindc = sin(dec * DEG2RAD);
cosdc = cos(dec * DEG2RAD);
sinra = sin(ra * 15.0 * DEG2RAD);
cosra = cos(ra * 15.0 * DEG2RAD);

uze[0] = coslat * coslon;
uze[1] = coslat * sinlon;
uze[2] = sinlat;
une[0] = -sinlat * coslon;
une[1] = -sinlat * sinlon;
une[2] = coslat;

uwe[0] = sinlon;
uwe[1] = -coslon;
uwe[2] = 0.0;

pnsw(gast, uze, uz);
pnsw(gast, une, un);
pnsw(gast, uwe, uw);

p[0] = cosdc * cosra;
p[1] = cosdc * sinra;
p[2] = sindc;

pz = p[0] * uz[0] + p[1] * uz[1] + p[2] * uz[2];
pn = p[0] * un[0] + p[1] * un[1] + p[2] * un[2];
pw = p[0] * uw[0] + p[1] * uw[1] + p[2] * uw[2];

proj = sqrt(pn * pn + pw * pw);

if (proj > 0.0)
*az = -atan2(pw, pn) * RAD2DEG;

if (*az < 0.0)
*az += 360.0;

if (*az >= 360.0)
*az -= 360.0;

*zd = atan2(proj, pz) * RAD2DEG;
return;
}

double julian_date(short int year, short int month, short int day, double hour)
{
long int jd12h = (long)day - 32075L + 1461L * ((long)year + 4800L + ((long)month - 14L) / 12L) / 4L + 367L * ((long)month - 2L - ((long)month - 14L) / 12L * 12L) / 12L - 3L * (((long)year + 4900L + ((long)month - 14L) / 12L) / 100L) / 4L;
double tjd = (double)jd12h - 0.5 + hour / 24.0;

return (tjd);
}

int main()
{

// convert(hip_ra, hip_dec, hip_promora, hip_promodec, hip_parallax, fk5_ra, fk5_dec);
cat_entry hip = {113368, 6.011119421 / TWOPI * 360, -0.516998583 / TWOPI * 360, 328.95, -164.67, 129.81, 0}; // "hi", "beiluoshimen"
// cat_entry hip = {"ho", "niulang", 97649, 5.195749333 / TWOPI * 360, 0.15476506 / TWOPI * 360, 536.23, 385.29, 194.95, 0};
// cat_entry hip = {"hi", "tianhezuo", 109268, 5.79550224 / TWOPI * 360, -0.819617367 / TWOPI * 360, 126.69, -147.47, 32.29, 0};
cat_entry fk5;
site_info loc = {32.08, 118.8}; // 温度10摄氏度 高度10米 大气压1013毫巴=1013百帕
transform_hip(&hip, &fk5);
cout << fk5.ra << endl;
cout << fk5.dec << endl;

time_t now;
tm *utc;
double tjd, ra, dec, zd, az, rar, decr, rah;

while (1)
{
now = time(0);
utc = gmtime(&now);
tjd = julian_date(1900 + utc->tm_year, 1 + utc->tm_mon, utc->tm_mday, utc->tm_hour + utc->tm_min / 60.0 + utc->tm_sec / 3600.0);
cout << fixed << setprecision(10) << tjd << endl;
// double tjd = 2459921.90082;
cout << " tjd " << fixed << setprecision(10) << tjd << endl;

app_star(tjd, &fk5, &ra, &dec);
cout << ra << endl
<< dec << endl;
equ2hor(tjd, &loc, ra, dec, &zd, &az, &rar, &decr);
cout << 90 - zd << endl
<< az << endl;
cout << " zd 高度 : " << int(90 - zd) << " ram: " << int((90 - zd - int(90 - zd)) * 60) << " ras: " << 60 * ((90 - zd - int(90 - zd)) * 60 - int((90 - zd - int(90 - zd)) * 60)) << endl;
cout << " az 方位 : " << int(az) << " ram: " << int((az - int(az)) * 60) << " ras: " << 60 * ((az - int(az)) * 60 - int((az - int(az)) * 60)) << endl;
}
// double tdb,
// time2, peb[3], veb[3], pes[3], ves[3], pos1[3], pos2[3], pos3[3], pos4[3], pos5[3], pos6[3], pos7[3], vel1[3];

rah = ra;
// cout << " ra: " << fk5_ra;

cout << " rah: " << int(rah) << " ram: " << int((rah - int(rah)) * 60) << " ras: " << 60 * ((rah - int(rah)) * 60 - int((rah - int(rah)) * 60)) << endl;
// cout << fk5_dec << endl;
double dech = dec;
cout << " dech: " << (dech < 0 ? "-" : "") << abs(int(dech)) << " ram: " << abs(int((dech - int(dech)) * 60)) << " ras: " << abs(60 * ((dech - int(dech)) * 60 - int((dech - int(dech)) * 60))) << endl;

system("pause");
return 0;
}