change delta T formula and add planet phenomena function

master
兔子 1 year ago
parent bb07e23238
commit 97c017be08
Signed by: b612
GPG Key ID: 481225A74DEB62A1

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 数据源本地存储已忽略文件
/../../../../../../:\gocode\src\b612.me\astro\.idea/dataSources/
/dataSources.local.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/astro.iml" filepath="$PROJECT_DIR$/.idea/astro.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

@ -104,8 +104,8 @@ func DeltaT(Date float64, IsJDE bool) (Result float64) { //传入年或儒略日
return
}
if Year < 2100 && Year >= 2010 {
//fmt.Println(Year)
Result = dt_cal(Year) //-3.2-(Year-2017)*0.029915;
var t = (Year - 2000.0)
Result = 62.92 + 0.32217*t + 0.005589*t*t
return
}
if Year >= 2100 && Year <= 2150 {

@ -9,8 +9,8 @@ import (
/*
*
*/
func LoToRa(lo, bo, jde float64) float64 {
ra := math.Atan2(Sin(lo)*Cos(Sita(jde)-Tan(bo)*Sin(Sita(jde))), Cos(lo))
func LoToRa(jde, lo, bo float64) float64 {
ra := math.Atan2(Sin(lo)*Cos(Sita(jde))-Tan(bo)*Sin(Sita(jde)), Cos(lo))
ra = ra * 180 / math.Pi
if ra < 0 {
ra += 360
@ -18,11 +18,48 @@ func LoToRa(lo, bo, jde float64) float64 {
return ra
}
func BoToDec(lo, bo, jde float64) float64 {
func BoToDec(jde, lo, bo float64) float64 {
dec := ArcSin(Sin(bo)*Cos(Sita(jde)) + Cos(bo)*Sin(Sita(jde))*Sin(lo))
return dec
}
func LoBoToRaDec(jde, lo, bo float64) (float64, float64) {
dec := ArcSin(Sin(bo)*Cos(Sita(jde)) + Cos(bo)*Sin(Sita(jde))*Sin(lo))
ra := math.Atan2(Sin(lo)*Cos(Sita(jde))-Tan(bo)*Sin(Sita(jde)), Cos(lo))
ra = ra * 180 / math.Pi
if ra < 0 {
ra += 360
}
return ra, dec
}
func RaDecToLoBo(jde, ra, dec float64) (float64, float64) {
//tan(λ) = (sin(α)*cos(ε) + tan(δ)*sin(ε)) / cos(α)
//sin(β)=sin(δ)*cos(ε)-cos(δ)*sin(ε)*sin(α)
sita := Sita(jde)
sinBo := Sin(dec)*Cos(sita) - Cos(dec)*Sin(sita)*Sin(ra)
lo := math.Atan2((Sin(ra)*Cos(sita) + Tan(dec)*Sin(sita)), Cos(ra))
lo = Limit360(lo * 180 / math.Pi)
return lo, ArcSin(sinBo)
}
func RaToLo(jde, ra, dec float64) float64 {
//tan(λ) = (sin(α)*cos(ε) + tan(δ)*sin(ε)) / cos(α)
//sin(β)=sin(δ)*cos(ε)-cos(δ)*sin(ε)*sin(α)
sita := Sita(jde)
lo := math.Atan2((Sin(ra)*Cos(sita) + Tan(dec)*Sin(sita)), Cos(ra))
lo = Limit360(lo * 180 / math.Pi)
return lo
}
func DecToBo(jde, ra, dec float64) float64 {
//tan(λ) = (sin(α)*cos(ε) + tan(δ)*sin(ε)) / cos(α)
//sin(β)=sin(δ)*cos(ε)-cos(δ)*sin(ε)*sin(α)
sita := Sita(jde)
sinBo := Sin(dec)*Cos(sita) - Cos(dec)*Sin(sita)*Sin(ra)
return ArcSin(sinBo)
}
/*
* st end JDE
*/
@ -98,7 +135,7 @@ func ZhanXinLo(lo, bo, lat, lon, jd, au, h float64) float64 { //jd为格林尼
C := pcosi(lat, h)
S := psini(lat, h)
sinpi := Sin(0.0024427777777) / au
ra := LoToRa(lo, bo, jd)
ra := LoToRa(jd, lo, bo)
tH := Limit360(TD2UT(ApparentSiderealTime(jd), false)*15 + lon - ra)
N := Cos(lo)*Cos(bo) - C*sinpi*Cos(tH)
nlo := math.Atan2(Sin(lo)*Cos(bo)-sinpi*(S*Sin(Sita(jd))+C*Cos(Sita(jd))*Sin(tH)), N) * 180 / math.Pi
@ -109,7 +146,7 @@ func ZhanXinBo(lo, bo, lat, lon, jd, au, h float64) float64 { //jd为格林尼
C := pcosi(lat, h)
S := psini(lat, h)
sinpi := Sin(0.0024427777777) / au
ra := LoToRa(lo, bo, jd)
ra := LoToRa(jd, lo, bo)
tH := Limit360(TD2UT(ApparentSiderealTime(jd), false)*15 + lon - ra)
N := Cos(lo)*Cos(bo) - C*sinpi*Cos(tH)
nlo := math.Atan2(Sin(lo)*Cos(bo)-sinpi*(S*Sin(Sita(jd))+C*Cos(Sita(jd))*Sin(tH)), N) * 180 / math.Pi
@ -117,25 +154,20 @@ func ZhanXinBo(lo, bo, lat, lon, jd, au, h float64) float64 { //jd为格林尼
return nbo
}
/*
func GXCLo(lo,bo,jd float64) float64{ //光行差修正
k:=20.49552;
sunlo:=SunTrueLo(jd);
e:=Earthe(jd);
epi=earth->EarthPI(jd);
tmp=(-k*this->CosR(sunlo-lo)+e*k*this->CosR(epi-lo))/this->CosR(bo);
return tmp;
}
public function GXCBo(lo,bo,jd)
{
earth=new Earth();
k=20.49552;
sunlo=earth->SunTrueLo(jd);
e=earth->Earthe(jd);
epi=earth->EarthPI(jd);
tmp=-k*this->SinR(bo)*(this->SinR(sunlo-lo)-e*this->SinR(epi-lo));
return tmp;
}
*/
func GXCLo(lo, bo, jd float64) float64 { //光行差修正
k := 20.49552
sunlo := SunTrueLo(jd)
e := Earthe(jd)
epi := EarthPI(jd)
tmp := (-k*Cos(sunlo-lo) + e*k*Cos(epi-lo)) / Cos(bo)
return tmp
}
func GXCBo(lo, bo, jd float64) float64 {
k := 20.49552
sunlo := SunTrueLo(jd)
e := Earthe(jd)
epi := EarthPI(jd)
tmp := -k * Sin(bo) * (Sin(sunlo-lo) - e*Sin(epi-lo))
return tmp
}

@ -8,3 +8,43 @@ import (
func Test_LoBo(t *testing.T) {
fmt.Printf("%.9f", dt_cal(2020.5))
}
func Test_LoBoRaDec(t *testing.T) {
jde := 2451545.0
lo, bo := RaDecToLoBo(jde, 10, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 40, 80)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 90, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 130, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 160, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 180, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 210, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 260, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 270, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 300, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 350, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
lo, bo = RaDecToLoBo(jde, 0, 50)
fmt.Println("LO,BO", lo, bo)
fmt.Println(LoBoToRaDec(jde, lo, bo))
}

@ -63,22 +63,22 @@ func AJupiterXYZ(JD float64) (float64, float64, float64) {
return x, y, z
}
func JupiterSeeRa(JD float64) float64 {
lo, bo := JupiterSeeLoBo(JD)
func JupiterApparentRa(JD float64) float64 {
lo, bo := JupiterApparentLoBo(JD)
sita := Sita(JD)
ra := math.Atan2((Sin(lo)*Cos(sita) - Tan(bo)*Sin(sita)), Cos(lo))
ra = ra * 180 / math.Pi
return Limit360(ra)
}
func JupiterSeeDec(JD float64) float64 {
lo, bo := JupiterSeeLoBo(JD)
func JupiterApparentDec(JD float64) float64 {
lo, bo := JupiterApparentLoBo(JD)
sita := Sita(JD)
dec := ArcSin(Sin(bo)*Cos(sita) + Cos(bo)*Sin(sita)*Sin(lo))
return dec
}
func JupiterSeeRaDec(JD float64) (float64, float64) {
lo, bo := JupiterSeeLoBo(JD)
func JupiterApparentRaDec(JD float64) (float64, float64) {
lo, bo := JupiterApparentLoBo(JD)
sita := Sita(JD)
ra := math.Atan2((Sin(lo)*Cos(sita) - Tan(bo)*Sin(sita)), Cos(lo))
ra = ra * 180 / math.Pi
@ -92,7 +92,7 @@ func EarthJupiterAway(JD float64) float64 {
return to
}
func JupiterSeeLo(JD float64) float64 {
func JupiterApparentLo(JD float64) float64 {
x, y, z := AJupiterXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AJupiterXYZ(JD - to)
@ -107,7 +107,7 @@ func JupiterSeeLo(JD float64) float64 {
return lo
}
func JupiterSeeBo(JD float64) float64 {
func JupiterApparentBo(JD float64) float64 {
x, y, z := AJupiterXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AJupiterXYZ(JD - to)
@ -121,7 +121,7 @@ func JupiterSeeBo(JD float64) float64 {
return bo
}
func JupiterSeeLoBo(JD float64) (float64, float64) {
func JupiterApparentLoBo(JD float64) (float64, float64) {
x, y, z := AJupiterXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AJupiterXYZ(JD - to)
@ -145,3 +145,293 @@ func JupiterMag(JD float64) float64 {
Mag := -9.40 + 5*math.Log10(AwaySun*AwayEarth) + 0.0005*i
return FloatRound(Mag, 2)
}
func JupiterHeight(jde, lon, lat, timezone float64) float64 {
// 转换为世界时
utcJde := jde - timezone/24.0
// 计算视恒星时
ra, dec := JupiterApparentRaDec(TD2UT(utcJde, true))
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
// 高度角、时角与天球座标三角转换公式
// sin(h)=sin(lat)*sin(dec)+cos(dec)*cos(lat)*cos(H)
sinHeight := Sin(lat)*Sin(dec) + Cos(dec)*Cos(lat)*Cos(H)
return ArcSin(sinHeight)
}
func JupiterAzimuth(jde, lon, lat, timezone float64) float64 {
// 转换为世界时
utcJde := jde - timezone/24.0
// 计算视恒星时
ra, dec := JupiterApparentRaDec(TD2UT(utcJde, true))
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
// 三角转换公式
tanAzimuth := Sin(H) / (Cos(H)*Sin(lat) - Tan(dec)*Cos(lat))
Azimuth := ArcTan(tanAzimuth)
if Azimuth < 0 {
if H/15 < 12 {
return Azimuth + 360
}
return Azimuth + 180
}
if H/15 < 12 {
return Azimuth + 180
}
return Azimuth
}
func JupiterHourAngle(JD, Lon, TZ float64) float64 {
startime := Limit360(ApparentSiderealTime(JD-TZ/24)*15 + Lon)
timeangle := startime - JupiterApparentRa(TD2UT(JD-TZ/24.0, true))
if timeangle < 0 {
timeangle += 360
}
return timeangle
}
func JupiterCulminationTime(jde, lon, timezone float64) float64 {
//jde 世界时,非力学时,当地时区 0时无需转换力学时
//ra,dec 瞬时天球座标非J2000等时间天球坐标
jde = math.Floor(jde) + 0.5
JD1 := jde + Limit360(360-JupiterHourAngle(jde, lon, timezone))/15.0/24.0*0.99726851851851851851
limitHA := func(jde, lon, timezone float64) float64 {
ha := JupiterHourAngle(jde, lon, timezone)
if ha < 180 {
ha += 360
}
return ha
}
for {
JD0 := JD1
stDegree := limitHA(JD0, lon, timezone) - 360
stDegreep := (limitHA(JD0+0.000005, lon, timezone) - limitHA(JD0-0.000005, lon, timezone)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return JD1
}
func JupiterRiseTime(JD, Lon, Lat, TZ, ZS, HEI float64) float64 {
return jupiterRiseDown(JD, Lon, Lat, TZ, ZS, HEI, true)
}
func JupiterDownTime(JD, Lon, Lat, TZ, ZS, HEI float64) float64 {
return jupiterRiseDown(JD, Lon, Lat, TZ, ZS, HEI, false)
}
func jupiterRiseDown(JD, Lon, Lat, TZ, ZS, HEI float64, isRise bool) float64 {
var An float64
JD = math.Floor(JD) + 0.5
ntz := math.Round(Lon / 15)
if ZS != 0 {
An = -0.8333
}
An = An - HeightDegreeByLat(HEI, Lat)
tztime := JupiterCulminationTime(JD, Lon, ntz)
if JupiterHeight(tztime, Lon, Lat, ntz) < An {
return -2 //极夜
}
if JupiterHeight(tztime-0.5, Lon, Lat, ntz) > An {
return -1 //极昼
}
dec := HSunApparentDec(TD2UT(tztime-ntz/24, true))
//(sin(ho)-sin(φ)*sin(δ2))/(cos(φ)*cos(δ2))
tmp := (Sin(An) - Sin(dec)*Sin(Lat)) / (Cos(dec) * Cos(Lat))
var rise float64
if math.Abs(tmp) <= 1 {
rzsc := ArcCos(tmp) / 15
if isRise {
rise = tztime - rzsc/24 - 25.0/24.0/60.0
} else {
rise = tztime + rzsc/24 - 25.0/24.0/60.0
}
} else {
rise = tztime
i := 0
//TODO:使用二分法计算
for JupiterHeight(rise, Lon, Lat, ntz) > An {
i++
if isRise {
rise -= 15.0 / 60.0 / 24.0
} else {
rise += 15.0 / 60.0 / 24.0
}
if i > 48 {
break
}
}
}
JD1 := rise
for {
JD0 := JD1
stDegree := JupiterHeight(JD0, Lon, Lat, ntz) - An
stDegreep := (JupiterHeight(JD0+0.000005, Lon, Lat, ntz) - JupiterHeight(JD0-0.000005, Lon, Lat, ntz)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return JD1 - ntz/24 + TZ/24
}
// Pos
const JUPITER_S_PERIOD = 1 / ((1 / 365.256363004) - (1 / 4332.59))
func jupiterConjunction(jde, degree float64, next uint8) float64 {
//0=last 1=next
decSub := func(jde float64, degree float64, filter bool) float64 {
sub := Limit360(Limit360(JupiterApparentLo(jde)-HSunApparentLo(jde)) - degree)
if filter {
if sub > 180 {
sub -= 360
}
if sub < -180 {
sub += 360
}
}
return sub
}
dayCost := JUPITER_S_PERIOD / 360
nowSub := decSub(jde, degree, false)
if next == 0 {
jde -= (360 - nowSub) * dayCost
} else {
jde += dayCost * nowSub
}
JD1 := jde
for {
JD0 := JD1
stDegree := decSub(JD0, degree, true)
stDegreep := (decSub(JD0+0.000005, degree, true) - decSub(JD0-0.000005, degree, true)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return TD2UT(JD1, false)
}
func LastJupiterConjunction(jde float64) float64 {
return jupiterConjunction(jde, 0, 0)
}
func NextJupiterConjunction(jde float64) float64 {
return jupiterConjunction(jde, 0, 1)
}
func LastJupiterOpposition(jde float64) float64 {
return jupiterConjunction(jde, 180, 0)
}
func NextJupiterOpposition(jde float64) float64 {
return jupiterConjunction(jde, 180, 1)
}
func NextJupiterEasternQuadrature(jde float64) float64 {
return jupiterConjunction(jde, 90, 1)
}
func LastJupiterEasternQuadrature(jde float64) float64 {
return jupiterConjunction(jde, 90, 0)
}
func NextJupiterWesternQuadrature(jde float64) float64 {
return jupiterConjunction(jde, 270, 1)
}
func LastJupiterWesternQuadrature(jde float64) float64 {
return jupiterConjunction(jde, 270, 0)
}
func jupiterRetrograde(jde float64, isLeft bool) float64 {
//0=last 1=next
decSub := func(jde float64, val float64) float64 {
sub := JupiterApparentRa(jde+val) - JupiterApparentRa(jde-val)
if sub > 180 {
sub -= 360
}
if sub < -180 {
sub += 360
}
return sub / (2 * val)
}
jde = NextJupiterOpposition(jde)
if isLeft {
jde -= 60
} else {
jde += 60
}
for {
nowSub := decSub(jde, 1.0/86400.0)
if math.Abs(nowSub) > 0.55 {
jde += 2
continue
}
break
}
JD1 := jde
for {
JD0 := JD1
stDegree := decSub(JD0, 2.0/86400.0)
stDegreep := (decSub(JD0+15.0/86400.0, 2.0/86400.0) - decSub(JD0-15.0/86400.0, 2.0/86400.0)) / (30.0 / 86400.0)
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 30.0/86400.0 {
break
}
}
JD1 = JD1 - 15.0/86400.0
min := JD1
minRa := 100.0
for i := 0.0; i < 60.0; i++ {
tmp := decSub(JD1+i*0.5/86400.0, 0.5/86400.0)
if math.Abs(tmp) < math.Abs(minRa) {
minRa = tmp
min = JD1 + i*0.5/86400.0
}
}
return TD2UT(min, false)
}
func NextJupiterRetrogradeToPrograde(jde float64) float64 {
date := jupiterRetrograde(jde, false)
if date < jde {
op := NextJupiterOpposition(jde)
return jupiterRetrograde(op+10, false)
}
return date
}
func LastJupiterRetrogradeToPrograde(jde float64) float64 {
jde = LastJupiterOpposition(jde) - 10
date := jupiterRetrograde(jde, false)
if date > jde {
op := LastJupiterOpposition(jde)
return jupiterRetrograde(op-10, false)
}
return date
}
func NextJupiterProgradeToRetrograde(jde float64) float64 {
date := jupiterRetrograde(jde, true)
if date < jde {
op := NextJupiterOpposition(jde)
return jupiterRetrograde(op+10, true)
}
return date
}
func LastJupiterProgradeToRetrograde(jde float64) float64 {
jde = LastJupiterOpposition(jde) - 10
date := jupiterRetrograde(jde, true)
if date > jde {
op := LastJupiterOpposition(jde)
return jupiterRetrograde(op-10, true)
}
return date
}

@ -0,0 +1,13 @@
package basic
import (
"fmt"
"testing"
)
func TestJupiter(t *testing.T) {
jde := GetNowJDE() - 6000
for i := 0.00; i < 20; i++ {
fmt.Println(jde+i*365, JDE2Date(jde+i*365), JDE2Date(NextJupiterRetrogradeToPrograde(jde+i*365)))
}
}

@ -63,22 +63,22 @@ func AMarsXYZ(JD float64) (float64, float64, float64) {
return x, y, z
}
func MarsSeeRa(JD float64) float64 {
lo, bo := MarsSeeLoBo(JD)
func MarsApparentRa(JD float64) float64 {
lo, bo := MarsApparentLoBo(JD)
sita := Sita(JD)
ra := math.Atan2((Sin(lo)*Cos(sita) - Tan(bo)*Sin(sita)), Cos(lo))
ra = ra * 180 / math.Pi
return Limit360(ra)
}
func MarsSeeDec(JD float64) float64 {
lo, bo := MarsSeeLoBo(JD)
func MarsApparentDec(JD float64) float64 {
lo, bo := MarsApparentLoBo(JD)
sita := Sita(JD)
dec := ArcSin(Sin(bo)*Cos(sita) + Cos(bo)*Sin(sita)*Sin(lo))
return dec
}
func MarsSeeRaDec(JD float64) (float64, float64) {
lo, bo := MarsSeeLoBo(JD)
func MarsApparentRaDec(JD float64) (float64, float64) {
lo, bo := MarsApparentLoBo(JD)
sita := Sita(JD)
ra := math.Atan2((Sin(lo)*Cos(sita) - Tan(bo)*Sin(sita)), Cos(lo))
ra = ra * 180 / math.Pi
@ -92,22 +92,21 @@ func EarthMarsAway(JD float64) float64 {
return to
}
func MarsSeeLo(JD float64) float64 {
func MarsApparentLo(JD float64) float64 {
x, y, z := AMarsXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AMarsXYZ(JD - to)
lo := math.Atan2(y, x)
bo := math.Atan2(z, math.Sqrt(x*x+y*y))
lo = lo * 180 / math.Pi
bo = bo * 180 / math.Pi
lo = Limit360(lo)
//bo := math.Atan2(z, math.Sqrt(x*x+y*y))
lo = lo * 180.0 / math.Pi
//bo = bo * 180 / math.Pi
lo = Limit360(lo) + HJZD(JD)
//lo-=GXCLo(lo,bo,JD)/3600;
//bo+=GXCBo(lo,bo,JD);
lo += HJZD(JD)
return lo
}
func MarsSeeBo(JD float64) float64 {
func MarsApparentBo(JD float64) float64 {
x, y, z := AMarsXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AMarsXYZ(JD - to)
@ -121,7 +120,7 @@ func MarsSeeBo(JD float64) float64 {
return bo
}
func MarsSeeLoBo(JD float64) (float64, float64) {
func MarsApparentLoBo(JD float64) (float64, float64) {
x, y, z := AMarsXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AMarsXYZ(JD - to)
@ -130,12 +129,32 @@ func MarsSeeLoBo(JD float64) (float64, float64) {
lo = lo * 180 / math.Pi
bo = bo * 180 / math.Pi
lo = Limit360(lo)
//lo-=GXCLo(lo,bo,JD)/3600;
//bo+=GXCBo(lo,bo,JD);
//lo -= GXCLo(lo, bo, JD) / 3600
//bo += GXCBo(lo, bo, JD)
lo += HJZD(JD)
return lo, bo
}
func MarsTrueLoBo(JD float64) (float64, float64) {
x, y, z := AMarsXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AMarsXYZ(JD - to)
lo := math.Atan2(y, x)
bo := math.Atan2(z, math.Sqrt(x*x+y*y))
lo = lo * 180 / math.Pi
bo = bo * 180 / math.Pi
lo = Limit360(lo)
return lo, bo
}
func MarsTrueLo(JD float64) float64 {
x, y, _ := AMarsXYZ(JD)
lo := math.Atan2(y, x)
lo = lo * 180 / math.Pi
lo = Limit360(lo)
return lo
}
func MarsMag(JD float64) float64 {
AwaySun := MarsR(JD)
AwayEarth := EarthMarsAway(JD)
@ -145,3 +164,293 @@ func MarsMag(JD float64) float64 {
Mag := -1.52 + 5*math.Log10(AwaySun*AwayEarth) + 0.016*i
return FloatRound(Mag, 2)
}
func MarsHeight(jde, lon, lat, timezone float64) float64 {
// 转换为世界时
utcJde := jde - timezone/24.0
// 计算视恒星时
ra, dec := MarsApparentRaDec(TD2UT(utcJde, true))
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
// 高度角、时角与天球座标三角转换公式
// sin(h)=sin(lat)*sin(dec)+cos(dec)*cos(lat)*cos(H)
sinHeight := Sin(lat)*Sin(dec) + Cos(dec)*Cos(lat)*Cos(H)
return ArcSin(sinHeight)
}
func MarsAzimuth(jde, lon, lat, timezone float64) float64 {
// 转换为世界时
utcJde := jde - timezone/24.0
// 计算视恒星时
ra, dec := MarsApparentRaDec(TD2UT(utcJde, true))
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
// 三角转换公式
tanAzimuth := Sin(H) / (Cos(H)*Sin(lat) - Tan(dec)*Cos(lat))
Azimuth := ArcTan(tanAzimuth)
if Azimuth < 0 {
if H/15 < 12 {
return Azimuth + 360
}
return Azimuth + 180
}
if H/15 < 12 {
return Azimuth + 180
}
return Azimuth
}
func MarsHourAngle(JD, Lon, TZ float64) float64 {
startime := Limit360(ApparentSiderealTime(JD-TZ/24)*15 + Lon)
timeangle := startime - MarsApparentRa(TD2UT(JD-TZ/24.0, true))
if timeangle < 0 {
timeangle += 360
}
return timeangle
}
func MarsCulminationTime(jde, lon, timezone float64) float64 {
//jde 世界时,非力学时,当地时区 0时无需转换力学时
//ra,dec 瞬时天球座标非J2000等时间天球坐标
jde = math.Floor(jde) + 0.5
JD1 := jde + Limit360(360-MarsHourAngle(jde, lon, timezone))/15.0/24.0*0.99726851851851851851
limitHA := func(jde, lon, timezone float64) float64 {
ha := MarsHourAngle(jde, lon, timezone)
if ha < 180 {
ha += 360
}
return ha
}
for {
JD0 := JD1
stDegree := limitHA(JD0, lon, timezone) - 360
stDegreep := (limitHA(JD0+0.000005, lon, timezone) - limitHA(JD0-0.000005, lon, timezone)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return JD1
}
func MarsRiseTime(JD, Lon, Lat, TZ, ZS, HEI float64) float64 {
return marsRiseDown(JD, Lon, Lat, TZ, ZS, HEI, true)
}
func MarsDownTime(JD, Lon, Lat, TZ, ZS, HEI float64) float64 {
return marsRiseDown(JD, Lon, Lat, TZ, ZS, HEI, false)
}
func marsRiseDown(JD, Lon, Lat, TZ, ZS, HEI float64, isRise bool) float64 {
var An float64
JD = math.Floor(JD) + 0.5
ntz := math.Round(Lon / 15)
if ZS != 0 {
An = -0.8333
}
An = An - HeightDegreeByLat(HEI, Lat)
tztime := MarsCulminationTime(JD, Lon, ntz)
if MarsHeight(tztime, Lon, Lat, ntz) < An {
return -2 //极夜
}
if MarsHeight(tztime-0.5, Lon, Lat, ntz) > An {
return -1 //极昼
}
dec := HSunApparentDec(TD2UT(tztime-ntz/24, true))
//(sin(ho)-sin(φ)*sin(δ2))/(cos(φ)*cos(δ2))
tmp := (Sin(An) - Sin(dec)*Sin(Lat)) / (Cos(dec) * Cos(Lat))
var rise float64
if math.Abs(tmp) <= 1 {
rzsc := ArcCos(tmp) / 15
if isRise {
rise = tztime - rzsc/24 - 25.0/24.0/60.0
} else {
rise = tztime + rzsc/24 - 25.0/24.0/60.0
}
} else {
rise = tztime
i := 0
//TODO:使用二分法计算
for MarsHeight(rise, Lon, Lat, ntz) > An {
i++
if isRise {
rise -= 15.0 / 60.0 / 24.0
} else {
rise += 15.0 / 60.0 / 24.0
}
if i > 48 {
break
}
}
}
JD1 := rise
for {
JD0 := JD1
stDegree := MarsHeight(JD0, Lon, Lat, ntz) - An
stDegreep := (MarsHeight(JD0+0.000005, Lon, Lat, ntz) - MarsHeight(JD0-0.000005, Lon, Lat, ntz)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return JD1 - ntz/24 + TZ/24
}
// Pos
const MARS_S_PERIOD = 1 / ((1 / 365.256363004) - (1 / 686.98))
func marsConjunction(jde, degree float64, next uint8) float64 {
//0=last 1=next
decSub := func(jde float64, degree float64, filter bool) float64 {
sub := Limit360(Limit360(MarsApparentLo(jde)-HSunApparentLo(jde)) - degree)
if filter {
if sub > 180 {
sub -= 360
}
if sub < -180 {
sub += 360
}
}
return sub
}
dayCost := MARS_S_PERIOD / 360
nowSub := decSub(jde, degree, false)
if next == 0 {
jde -= (360 - nowSub) * dayCost
} else {
jde += dayCost * nowSub
}
JD1 := jde
for {
JD0 := JD1
stDegree := decSub(JD0, degree, true)
stDegreep := (decSub(JD0+0.000005, degree, true) - decSub(JD0-0.000005, degree, true)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return TD2UT(JD1, false)
}
func LastMarsConjunction(jde float64) float64 {
return marsConjunction(jde, 0, 0)
}
func NextMarsConjunction(jde float64) float64 {
return marsConjunction(jde, 0, 1)
}
func LastMarsOpposition(jde float64) float64 {
return marsConjunction(jde, 180, 0)
}
func NextMarsOpposition(jde float64) float64 {
return marsConjunction(jde, 180, 1)
}
func NextMarsEasternQuadrature(jde float64) float64 {
return marsConjunction(jde, 90, 1)
}
func LastMarsEasternQuadrature(jde float64) float64 {
return marsConjunction(jde, 90, 0)
}
func NextMarsWesternQuadrature(jde float64) float64 {
return marsConjunction(jde, 270, 1)
}
func LastMarsWesternQuadrature(jde float64) float64 {
return marsConjunction(jde, 270, 0)
}
func marsRetrograde(jde float64, isLeft bool) float64 {
//0=last 1=next
decSub := func(jde float64, val float64) float64 {
sub := MarsApparentRa(jde+val) - MarsApparentRa(jde-val)
if sub > 180 {
sub -= 360
}
if sub < -180 {
sub += 360
}
return sub / (2 * val)
}
jde = NextMarsOpposition(jde)
if isLeft {
jde -= 60
} else {
jde += 60
}
for {
nowSub := decSub(jde, 1.0/86400.0)
if math.Abs(nowSub) > 0.55 {
jde += 2
continue
}
break
}
JD1 := jde
for {
JD0 := JD1
stDegree := decSub(JD0, 2.0/86400.0)
stDegreep := (decSub(JD0+15.0/86400.0, 2.0/86400.0) - decSub(JD0-15.0/86400.0, 2.0/86400.0)) / (30.0 / 86400.0)
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 30.0/86400.0 {
break
}
}
JD1 = JD1 - 15.0/86400.0
min := JD1
minRa := 100.0
for i := 0.0; i < 60.0; i++ {
tmp := decSub(JD1+i*0.5/86400.0, 0.5/86400.0)
if math.Abs(tmp) < math.Abs(minRa) {
minRa = tmp
min = JD1 + i*0.5/86400.0
}
}
return TD2UT(min, false)
}
func NextMarsRetrogradeToPrograde(jde float64) float64 {
date := marsRetrograde(jde, false)
if date < jde {
op := NextMarsOpposition(jde)
return marsRetrograde(op+10, false)
}
return date
}
func LastMarsRetrogradeToPrograde(jde float64) float64 {
jde = LastMarsOpposition(jde) - 10
date := marsRetrograde(jde, false)
if date > jde {
op := LastMarsOpposition(jde)
return marsRetrograde(op-10, false)
}
return date
}
func NextMarsProgradeToRetrograde(jde float64) float64 {
date := marsRetrograde(jde, true)
if date < jde {
op := NextMarsOpposition(jde)
return marsRetrograde(op+10, true)
}
return date
}
func LastMarsProgradeToRetrograde(jde float64) float64 {
jde = LastMarsOpposition(jde) - 10
date := marsRetrograde(jde, true)
if date > jde {
op := LastMarsOpposition(jde)
return marsRetrograde(op-10, true)
}
return date
}

@ -0,0 +1,21 @@
package basic
import (
"fmt"
"testing"
)
func TestMars(t *testing.T) {
jde := GetNowJDE() - 6000
/*
fmt.Println(JDE2Date(VenusCulminationTime(jde, 115, 8)))
fmt.Println(JDE2Date(VenusRiseTime(jde, 115, 23, 8, 0, 0)))
fmt.Println(JDE2Date(VenusDownTime(jde, 115, 23, 8, 0, 0)))
fmt.Println("----------------")
*/
//LastVenusConjunction(2.4596600340162036e+06)
//fmt.Println(2.4590359532407406e+06, JDE2Date(2.4590359532407406e+06), JDE2Date(NextVenusRetrograde(2.4590359532407406e+06)))
for i := 0.00; i < 1; i++ {
fmt.Println(jde+i*740, JDE2Date(jde+i*740), JDE2Date(LastMarsProgradeToRetrograde(jde+i*740)))
}
}

@ -63,27 +63,20 @@ func AMercuryXYZ(JD float64) (float64, float64, float64) {
return x, y, z
}
func MercurySeeRa(JD float64) float64 {
lo, bo := MercurySeeLoBo(JD)
sita := Sita(JD)
ra := math.Atan2((Sin(lo)*Cos(sita) - Tan(bo)*Sin(sita)), Cos(lo))
ra = ra * 180 / math.Pi
return Limit360(ra)
func MercuryApparentRa(JD float64) float64 {
lo, bo := MercuryApparentLoBo(JD)
return LoToRa(JD, lo, bo)
}
func MercurySeeDec(JD float64) float64 {
lo, bo := MercurySeeLoBo(JD)
func MercuryApparentDec(JD float64) float64 {
lo, bo := MercuryApparentLoBo(JD)
sita := Sita(JD)
dec := ArcSin(Sin(bo)*Cos(sita) + Cos(bo)*Sin(sita)*Sin(lo))
return dec
}
func MercurySeeRaDec(JD float64) (float64, float64) {
lo, bo := MercurySeeLoBo(JD)
sita := Sita(JD)
ra := math.Atan2((Sin(lo)*Cos(sita) - Tan(bo)*Sin(sita)), Cos(lo))
ra = ra * 180 / math.Pi
dec := ArcSin(Sin(bo)*Cos(sita) + Cos(bo)*Sin(sita)*Sin(lo))
return Limit360(ra), dec
func MercuryApparentRaDec(JD float64) (float64, float64) {
lo, bo := MercuryApparentLoBo(JD)
return LoBoToRaDec(JD, lo, bo)
}
func EarthMercuryAway(JD float64) float64 {
@ -92,7 +85,7 @@ func EarthMercuryAway(JD float64) float64 {
return to
}
func MercurySeeLo(JD float64) float64 {
func MercuryApparentLo(JD float64) float64 {
x, y, z := AMercuryXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AMercuryXYZ(JD - to)
@ -107,7 +100,7 @@ func MercurySeeLo(JD float64) float64 {
return lo
}
func MercurySeeBo(JD float64) float64 {
func MercuryApparentBo(JD float64) float64 {
x, y, z := AMercuryXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AMercuryXYZ(JD - to)
@ -121,7 +114,7 @@ func MercurySeeBo(JD float64) float64 {
return bo
}
func MercurySeeLoBo(JD float64) (float64, float64) {
func MercuryApparentLoBo(JD float64) (float64, float64) {
x, y, z := AMercuryXYZ(JD)
to := 0.0057755183 * math.Sqrt(x*x+y*y+z*z)
x, y, z = AMercuryXYZ(JD - to)
@ -129,10 +122,9 @@ func MercurySeeLoBo(JD float64) (float64, float64) {
bo := math.Atan2(z, math.Sqrt(x*x+y*y))
lo = lo * 180 / math.Pi
bo = bo * 180 / math.Pi
lo = Limit360(lo)
lo = Limit360(lo) + HJZD(JD)
//lo-=GXCLo(lo,bo,JD)/3600;
//bo+=GXCBo(lo,bo,JD);
lo += HJZD(JD)
return lo, bo
}
@ -145,3 +137,472 @@ func MercuryMag(JD float64) float64 {
Mag := -0.42 + 5*math.Log10(AwaySun*AwayEarth) + 0.0380*i - 0.000273*i*i + 0.000002*i*i*i
return FloatRound(Mag, 2)
}
func MercuryHeight(jde, lon, lat, timezone float64) float64 {
// 转换为世界时
utcJde := jde - timezone/24.0
// 计算视恒星时
ra, dec := MercuryApparentRaDec(TD2UT(utcJde, true))
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
// 高度角、时角与天球座标三角转换公式
// sin(h)=sin(lat)*sin(dec)+cos(dec)*cos(lat)*cos(H)
sinHeight := Sin(lat)*Sin(dec) + Cos(dec)*Cos(lat)*Cos(H)
return ArcSin(sinHeight)
}
func MercuryAzimuth(jde, lon, lat, timezone float64) float64 {
// 转换为世界时
utcJde := jde - timezone/24.0
// 计算视恒星时
ra, dec := MercuryApparentRaDec(TD2UT(utcJde, true))
st := Limit360(ApparentSiderealTime(utcJde)*15 + lon)
// 计算时角
H := Limit360(st - ra)
// 三角转换公式
tanAzimuth := Sin(H) / (Cos(H)*Sin(lat) - Tan(dec)*Cos(lat))
Azimuth := ArcTan(tanAzimuth)
if Azimuth < 0 {
if H/15 < 12 {
return Azimuth + 360
}
return Azimuth + 180
}
if H/15 < 12 {
return Azimuth + 180
}
return Azimuth
}
func MercuryHourAngle(JD, Lon, TZ float64) float64 {
startime := Limit360(ApparentSiderealTime(JD-TZ/24)*15 + Lon)
timeangle := startime - MercuryApparentRa(TD2UT(JD-TZ/24.0, true))
if timeangle < 0 {
timeangle += 360
}
return timeangle
}
func MercuryCulminationTime(jde, lon, timezone float64) float64 {
//jde 世界时,非力学时,当地时区 0时无需转换力学时
//ra,dec 瞬时天球座标非J2000等时间天球坐标
jde = math.Floor(jde) + 0.5
JD1 := jde + Limit360(360-MercuryHourAngle(jde, lon, timezone))/15.0/24.0*0.99726851851851851851
limitHA := func(jde, lon, timezone float64) float64 {
ha := MercuryHourAngle(jde, lon, timezone)
if ha < 180 {
ha += 360
}
return ha
}
for {
JD0 := JD1
stDegree := limitHA(JD0, lon, timezone) - 360
stDegreep := (limitHA(JD0+0.000005, lon, timezone) - limitHA(JD0-0.000005, lon, timezone)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return JD1
}
func MercuryRiseTime(JD, Lon, Lat, TZ, ZS, HEI float64) float64 {
return mercuryRiseDown(JD, Lon, Lat, TZ, ZS, HEI, true)
}
func MercuryDownTime(JD, Lon, Lat, TZ, ZS, HEI float64) float64 {
return mercuryRiseDown(JD, Lon, Lat, TZ, ZS, HEI, false)
}
func mercuryRiseDown(JD, Lon, Lat, TZ, ZS, HEI float64, isRise bool) float64 {
var An float64
JD = math.Floor(JD) + 0.5
ntz := math.Round(Lon / 15)
if ZS != 0 {
An = -0.8333
}
An = An - HeightDegreeByLat(HEI, Lat)
tztime := MercuryCulminationTime(JD, Lon, ntz)
if MercuryHeight(tztime, Lon, Lat, ntz) < An {
return -2 //极夜
}
if MercuryHeight(tztime-0.5, Lon, Lat, ntz) > An {
return -1 //极昼
}
dec := HSunApparentDec(TD2UT(tztime-ntz/24, true))
//(sin(ho)-sin(φ)*sin(δ2))/(cos(φ)*cos(δ2))
tmp := (Sin(An) - Sin(dec)*Sin(Lat)) / (Cos(dec) * Cos(Lat))
var rise float64
if math.Abs(tmp) <= 1 {
rzsc := ArcCos(tmp) / 15
if isRise {
rise = tztime - rzsc/24 - 25.0/24.0/60.0
} else {
rise = tztime + rzsc/24 - 25.0/24.0/60.0
}
} else {
rise = tztime
i := 0
//TODO:使用二分法计算
for MercuryHeight(rise, Lon, Lat, ntz) > An {
i++
if isRise {
rise -= 15.0 / 60.0 / 24.0
} else {
rise += 15.0 / 60.0 / 24.0
}
if i > 48 {
break
}
}
}
JD1 := rise
for {
JD0 := JD1
stDegree := MercuryHeight(JD0, Lon, Lat, ntz) - An
stDegreep := (MercuryHeight(JD0+0.000005, Lon, Lat, ntz) - MercuryHeight(JD0-0.000005, Lon, Lat, ntz)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return JD1 - ntz/24 + TZ/24
}
// Pos
const MERCURY_S_PERIOD = 1 / ((1 / 87.9691) - (1 / 365.256363004))
func mercuryConjunction(jde float64, next uint8) float64 {
//0=last 1=next
decSub := func(jde float64) float64 {
sub := Limit360(MercuryApparentLo(jde) - HSunApparentLo(jde))
if sub > 180 {
sub -= 360
}
if sub < -180 {
sub += 360
}
return sub
}
nowSub := decSub(jde)
// pos 大于0:远离太阳 小于0:靠近太阳
pos := math.Abs(decSub(jde+1/86400.0)) - math.Abs(nowSub)
if pos >= 0 && next == 1 && nowSub > 0 {
jde += MERCURY_S_PERIOD/8.0 + 2
}
if pos >= 0 && next == 1 && nowSub < 0 {
jde += MERCURY_S_PERIOD/6.0 + 2
}
if pos <= 0 && next == 0 && nowSub < 0 {
jde -= MERCURY_S_PERIOD/8.0 + 2
}
if pos <= 0 && next == 0 && nowSub > 0 {
jde -= MERCURY_S_PERIOD/6.0 + 2
}
for {
nowSub := decSub(jde)
pos := math.Abs(decSub(jde+1/86400.0)) - math.Abs(nowSub)
if math.Abs(nowSub) > 12 || (pos > 0 && next == 1) || (pos < 0 && next == 0) {
if next == 1 {
jde += 2
} else {
jde -= 2
}
continue
}
break
}
JD1 := jde
for {
JD0 := JD1
stDegree := decSub(JD0)
stDegreep := (decSub(JD0+0.000005) - decSub(JD0-0.000005)) / 0.00001
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 0.00001 {
break
}
}
return TD2UT(JD1, false)
}
func LastMercuryConjunction(jde float64) float64 {
return mercuryConjunction(jde, 0)
}
func NextMercuryConjunction(jde float64) float64 {
return mercuryConjunction(jde, 1)
}
func NextMercuryInferiorConjunction(jde float64) float64 {
date := NextMercuryConjunction(jde)
if EarthMercuryAway(date) > EarthAway(date) {
return NextMercuryConjunction(date + 2)
}
return date
}
func NextMercurySuperiorConjunction(jde float64) float64 {
date := NextMercuryConjunction(jde)
if EarthMercuryAway(date) < EarthAway(date) {
return NextMercuryConjunction(date + 2)
}
return date
}
func LastMercuryInferiorConjunction(jde float64) float64 {
date := LastMercuryConjunction(jde)
if EarthMercuryAway(date) > EarthAway(date) {
return LastMercuryConjunction(date - 2)
}
return date
}
func LastMercurySuperiorConjunction(jde float64) float64 {
date := LastMercuryConjunction(jde)
if EarthMercuryAway(date) < EarthAway(date) {
return LastMercuryConjunction(date - 2)
}
return date
}
func mercuryRetrograde(jde float64) float64 {
//0=last 1=next
decSunSub := func(jde float64) float64 {
sub := Limit360(MercuryApparentRa(jde) - SunApparentRa(jde))
if sub > 180 {
sub -= 360
}
if sub < -180 {
sub += 360
}
return sub
}
decSub := func(jde float64, val float64) float64 {
sub := MercuryApparentRa(jde+val) - MercuryApparentRa(jde-val)
if sub > 180 {
sub -= 360
}
if sub < -180 {
sub += 360
}
return sub / (2 * val)
}
lastHe := LastMercuryConjunction(jde)
nextHe := NextMercuryConjunction(jde)
nowSub := decSunSub(jde)
if nowSub > 0 {
jde = lastHe + ((nextHe - lastHe) / 5.0 * 3.5)
} else {
jde = lastHe + ((nextHe - lastHe) / 5.5)
}
for {
nowSub := decSub(jde, 1.0/86400.0)
if math.Abs(nowSub) > 0.55 {
jde += 2
continue
}
break
}
JD1 := jde
for {
JD0 := JD1
stDegree := decSub(JD0, 2.0/86400.0)
stDegreep := (decSub(JD0+15.0/86400.0, 2.0/86400.0) - decSub(JD0-15.0/86400.0, 2.0/86400.0)) / (30.0 / 86400.0)
JD1 = JD0 - stDegree/stDegreep
if math.Abs(JD1-JD0) <= 30.0/86400.0 {
break
}
}
JD1 = JD1 - 15.0/86400.0
min := JD1
minRa := 100.0
for i := 0.0; i < 60.0; i++ {
tmp := decSub(JD1+i*0.5/86400.0, 0.5/86400.0)
if math.Abs(tmp) < math.Abs(minRa) {
minRa = tmp
min = JD1 + i*0.5/86400.0
}
}
//fmt.Println((min - lastHe) / (nextHe - lastHe))
return TD2UT(min, false)
}
func NextMercuryRetrograde(jde float64) float64 {
date := mercuryRetrograde(jde)
if date < jde {
nextHe := NextMercuryConjunction(jde)
return mercuryRetrograde(nextHe + 2)
}
return date
}
func LastMercuryRetrograde(jde float64) float64 {
lastHe := LastMercuryConjunction(jde)
date := mercuryRetrograde(lastHe + 2)
if date > jde {
lastLastHe := LastMercuryConjunction(lastHe - 2)
return mercuryRetrograde(lastLastHe + 2)
}
return date
}
func NextMercuryProgradeToRetrograde(jde float64) float64 {
date := NextMercuryRetrograde(jde)
sub := Limit360(MercuryApparentRa(date) - SunApparentRa(date))
if sub > 180 {
return NextMercuryRetrograde(date + MERCURY_S_PERIOD/2)
}
return date
}
func NextMercuryRetrogradeToPrograde(jde float64) float64 {
date := NextMercuryRetrograde(jde)
sub := Limit360(MercuryApparentRa(date) - SunApparentRa(date))