以2000年天球坐标系,计算日月五行在坐标系上的坐标。
黄道面和赤道面约23.433°的夹角,这里经度计算粗略按两面重合计算。这里天体运行轨道按正圆计算,由于行星、卫星运行轨道都是椭圆,都有一定的偏心率,计算结果会有一些误差。计算结果仅作示意。
太阳和月亮相对地球来说是绕地球作圆周运动,行星则根据轨道在地球内测还是外侧分为内行星和外行星两大类分别计算。

太阳坐标经度计算

太阳每365.2422日(1回归年,每年回归间隔不是恒定的,取近百年左右的平均值)运行360°。因为岁差春分点每年西移,每年西移值不确定,约50.26角秒,以2000年天球坐标系,每回归年运行角度约为 360°—50.260角秒。

1
2
3
4
5
6
7
8
/**
* 计算指定日期太阳所在的天球经度
*/
public static double getLongitudeOfSun(Date date) {
long time = date.getTime() - SolarSystem.SPRING_EQUINOX; //SPRING_EQUINOX为春分点的时间戳(以2000年为基点)
double degree = time / SolarSystem.TROPICAL_YEAR / 86400000d * SolarSystem.TROPICAL_YEAR_DEGREE; //TROPICAL_YEAR即回归年365.2422日,TROPICAL_YEAR_DEGREE即(360°—50.260角秒)
return (degree % 360 + 360) % 360; //范围取到[0°,360°]
}

月亮坐标经度计算

月亮绕地球近似正圆运动,知道某个合日时间点,根据太阳在这个时间点的坐标经度就知道月亮在这个时间点的坐标经度,月亮绕地运行周期是27.32天,即可推算出月亮的坐标经度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* 获取绕地天体的当前经度
*
* @param solar 绕地运动的星体(月、轨道半径相对于地球非常大的外行星也可用此方法近似计算)
* @param baseDate 基准校对日期(合日点:在地球上看天体和太阳重合的时间点)
*/
private static double getCircularMotionLong(Solar solar, Date baseDate, Date date) {
long interval = date.getTime() - baseDate.getTime();
long period = (long) (solar.getSurroundPeriod() * 24 * 3600000); //SurroundPeriod:月亮是绕地周期27.32天,行星是相对地球绕行的周期(1/(1/T地-1/T星))
long time = (interval % period + period) % period; //变成非负数
double angle = 360d * time / period;
if (solar.getType() == 1) {
//行星对地球是相对太阳的period,所以要算上太阳的运动角度(以地球为基准外行星相当于太阳是反方向绕行的)
double longitudeSunNow = StarCoordsUtil.getLongitudeOfSun(date);
return (longitudeSunNow - angle + 360) % 360;
} else {
//月球绕地球正圆运动,直接在基点基础上增加角度
double longitudeSun = StarCoordsUtil.getLongitudeOfSun(baseDate);
return (longitudeSun + angle + 360) % 360;
}
}

行星坐标经度计算

pic
如图,内行星运行角速度大于地球,外行星运行角速度小于地球。
从行星合日点算起,假设地日连线恒定为X轴,单位时间内,内行星正行了θ1,外行星逆行了θ2。其中:
θ1=ω内-ω地;
θ2=ω地-ω外;
求出行星与地球的连线与X轴的夹角,即在地球上看行星与太阳的夹角,已知太阳的经度,即可估算出行星的经度。
内行星的经度计算(baseDate为上合日时间点):

1
2
3
4
5
6
7
8
9
10
11
12
13
private static double getInnerPlanetLong(Solar solar, Date baseDate, Date date) {
long interval = date.getTime() - baseDate.getTime(); //秒
double p1 = solar.getRevolutionPeriod(); //公转周期,天
double p0 = Solar.Earth.getRevolutionPeriod(); //公转周期,天
double angle1 = 360d * interval / p1 / 24 / 3600000;
double angle0 = 360d * interval / p0 / 24 / 3600000;
double anglex = angle1 - angle0; //相差角度
//用勾股定理求出夹角,OrbitRadius为轨道半径(地日距的多少倍)
double angle = Math.atan((solar.getOrbitRadius() * Math.sin(anglex * Math.PI / 180)) /
(1 + solar.getOrbitRadius() * Math.cos(anglex * Math.PI / 180))) * 180 / Math.PI; //星地日夹角(范围-90~90°)
double longitudeSunNow = StarCoordsUtil.getLongitudeOfSun(date);
return (longitudeSunNow + angle + 360) % 360;
}

外行星的经度计算(baseDate为合日时间点):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
private static double getOuterPlanetLong(Solar solar, Date baseDate, Date date) {
long interval = date.getTime() - baseDate.getTime(); //秒
double p1 = solar.getRevolutionPeriod(); //公转周期,天
double p0 = Solar.Earth.getRevolutionPeriod(); //公转周期,天
double angle1 = 360d * interval / p1 / 24 / 3600000;
double angle0 = 360d * interval / p0 / 24 / 3600000;
double anglex = angle1 - angle0; //相差角度
//用勾股定理求出夹角,OrbitRadius为轨道半径(地日距的多少倍)
double fy = (solar.getOrbitRadius() * Math.sin(anglex * Math.PI / 180));
double fx = (1 + solar.getOrbitRadius() * Math.cos(anglex * Math.PI / 180));
double angle;
//计算日星夹角(范围-90~270°)
if (fx == 0) {
angle = fy > 0 ? 90 : -90;
} else {
double angley = Math.atan(fy / fx) * 180 / Math.PI; //星地日夹角(范围-90~90°)
angle = fx > 0 ? angley : (angley + 180);
}
double longitudeSunNow = StarCoordsUtil.getLongitudeOfSun(date);
return (longitudeSunNow + angle + 360) % 360;
}

坐标纬度计算

黄道面和赤道面约23.433°(23°26′)的夹角,黄道在天球坐标系的位置:0°和180°时黄赤相交,经度0-180°时在北纬,180-360°时在南纬。
已知黄道上天体的经度,即可估算出天体的纬度:

1
2
3
public static double getEclipticLatitude(double longitude) {
return Math.sin(longitude * Math.PI / 180) * 23.433;
}

源码请参考:

https://github.com/guangGG/AndroidStarrySky