feat: 扩展天文计算能力
- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息 - 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算 - 新增木星伽利略卫星位置、现象与接触事件计算 - 新增恒星星表、星座判定、自行修正与观测辅助能力 - 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包 - 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算 - 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试 - 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试 - 更新中文和英文 README,补充示例、精度说明、SVG 配图
This commit is contained in:
@@ -0,0 +1,220 @@
|
||||
package coord
|
||||
|
||||
import "math"
|
||||
|
||||
// Galactic 银道坐标 / galactic coordinates.
|
||||
type Galactic struct {
|
||||
Lon float64 // 银经,单位度 / galactic longitude in degrees.
|
||||
Lat float64 // 银纬,单位度 / galactic latitude in degrees.
|
||||
}
|
||||
|
||||
// SOFA ICRS2G/G2ICRS fixed rotation matrix.
|
||||
// Source: IAU SOFA 2023-10-11, iauIcrs2g/iauG2icrs.
|
||||
var icrsToGalacticMatrix = [3][3]float64{
|
||||
{-0.054875560416215368492398900454, -0.873437090234885048760383168409, -0.483835015548713226831774175116},
|
||||
{+0.494109427875583673525222371358, -0.444829629960011178146614061616, +0.746982244497218890527388004556},
|
||||
{-0.867666149019004701181616534570, -0.198076373431201528180486091412, +0.455983776175066922272100478348},
|
||||
}
|
||||
|
||||
// EclipticToEquatorialByObliquity 黄道转赤道坐标(指定黄赤交角) / ecliptic to equatorial by obliquity.
|
||||
//
|
||||
// lon: 黄经,单位度
|
||||
// lat: 黄纬,单位度
|
||||
// obliquity: 黄赤交角,单位度
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 赤经 RA,单位度;赤纬 Dec,单位度
|
||||
func EclipticToEquatorialByObliquity(lon, lat, obliquity float64) Equatorial {
|
||||
sinLon, cosLon := sinCosDeg(lon)
|
||||
sinLat, cosLat := sinCosDeg(lat)
|
||||
sinObliquity, cosObliquity := sinCosDeg(obliquity)
|
||||
|
||||
ra := normalize360(math.Atan2(sinLon*cosObliquity-math.Tan(lat*math.Pi/180)*sinObliquity, cosLon) * 180 / math.Pi)
|
||||
dec := math.Asin(clampUnit(sinLat*cosObliquity+cosLat*sinObliquity*sinLon)) * 180 / math.Pi
|
||||
return Equatorial{RA: ra, Dec: dec}
|
||||
}
|
||||
|
||||
// EquatorialToEclipticByObliquity 赤道转黄道坐标(指定黄赤交角) / equatorial to ecliptic by obliquity.
|
||||
//
|
||||
// ra: 赤经,单位度
|
||||
// dec: 赤纬,单位度
|
||||
// obliquity: 黄赤交角,单位度
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 黄经 Lon,单位度;黄纬 Lat,单位度
|
||||
func EquatorialToEclipticByObliquity(ra, dec, obliquity float64) Ecliptic {
|
||||
sinRA, cosRA := sinCosDeg(ra)
|
||||
sinDec, cosDec := sinCosDeg(dec)
|
||||
sinObliquity, cosObliquity := sinCosDeg(obliquity)
|
||||
|
||||
lon := normalize360(math.Atan2(sinRA*cosObliquity+math.Tan(dec*math.Pi/180)*sinObliquity, cosRA) * 180 / math.Pi)
|
||||
lat := math.Asin(clampUnit(sinDec*cosObliquity-cosDec*sinObliquity*sinRA)) * 180 / math.Pi
|
||||
return Ecliptic{Lon: lon, Lat: lat}
|
||||
}
|
||||
|
||||
// HourAngleDeclinationToHorizontal 时角赤纬转地平坐标 / horizontal coordinates from hour angle and declination.
|
||||
//
|
||||
// hourAngle: 时角,单位度
|
||||
// declination: 赤纬,单位度
|
||||
// latitude: 观测者地理纬度,单位度,北正南负
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 方位角 Azimuth(正北为0,顺时针增加)、高度角 Altitude、天顶距 Zenith,均为度
|
||||
func HourAngleDeclinationToHorizontal(hourAngle, declination, latitude float64) Horizontal {
|
||||
sinLatitude, cosLatitude := sinCosDeg(latitude)
|
||||
sinDeclination, cosDeclination := sinCosDeg(declination)
|
||||
sinHourAngle, cosHourAngle := sinCosDeg(hourAngle)
|
||||
|
||||
altitude := math.Asin(clampUnit(sinLatitude*sinDeclination+cosLatitude*cosDeclination*cosHourAngle)) * 180 / math.Pi
|
||||
azimuth := normalize360(math.Atan2(-cosDeclination*sinHourAngle, cosLatitude*sinDeclination-sinLatitude*cosDeclination*cosHourAngle) * 180 / math.Pi)
|
||||
return Horizontal{
|
||||
Azimuth: azimuth,
|
||||
Altitude: altitude,
|
||||
Zenith: 90 - altitude,
|
||||
HourAngle: normalize360(hourAngle),
|
||||
}
|
||||
}
|
||||
|
||||
// HorizontalToHourAngleDeclination 地平坐标转时角赤纬 / hour angle and declination from horizontal coordinates.
|
||||
//
|
||||
// azimuth: 方位角,单位度,正北为0,顺时针增加
|
||||
// altitude: 高度角,单位度
|
||||
// latitude: 观测者地理纬度,单位度,北正南负
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 时角 HourAngle,单位度;赤纬 Declination,单位度
|
||||
func HorizontalToHourAngleDeclination(azimuth, altitude, latitude float64) (hourAngle, declination float64) {
|
||||
sinLatitude, cosLatitude := sinCosDeg(latitude)
|
||||
sinAltitude, cosAltitude := sinCosDeg(altitude)
|
||||
sinAzimuth, cosAzimuth := sinCosDeg(azimuth)
|
||||
|
||||
declination = math.Asin(clampUnit(sinLatitude*sinAltitude+cosLatitude*cosAltitude*cosAzimuth)) * 180 / math.Pi
|
||||
sinHourAngle := -cosAltitude * sinAzimuth
|
||||
cosHourAngle := sinAltitude*cosLatitude - cosAltitude*sinLatitude*cosAzimuth
|
||||
hourAngle = normalize360(math.Atan2(sinHourAngle, cosHourAngle) * 180 / math.Pi)
|
||||
return hourAngle, declination
|
||||
}
|
||||
|
||||
// EquatorialToHorizontalByLocalSiderealTime 赤道转地平坐标(指定地方恒星时) / equatorial to horizontal by local sidereal time.
|
||||
//
|
||||
// localSiderealTimeHours: 站点本地恒星时,单位小时
|
||||
// ra: 赤经,单位度
|
||||
// dec: 赤纬,单位度
|
||||
// latitude: 观测者地理纬度,单位度,北正南负
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 方位角 Azimuth(正北为0,顺时针增加)、高度角 Altitude、天顶距 Zenith,均为度;
|
||||
// 附带返回对应的时角 HourAngle,单位度
|
||||
//
|
||||
// 例:
|
||||
//
|
||||
// hz := coord.EquatorialToHorizontalByLocalSiderealTime(10.5, 83.6331, 22.0145, 31.2)
|
||||
func EquatorialToHorizontalByLocalSiderealTime(localSiderealTimeHours, ra, dec, latitude float64) Horizontal {
|
||||
hourAngle := normalize360(localSiderealTimeHours*15 - ra)
|
||||
return HourAngleDeclinationToHorizontal(hourAngle, dec, latitude)
|
||||
}
|
||||
|
||||
// HorizontalToEquatorialByLocalSiderealTime 地平转赤道坐标(指定地方恒星时) / horizontal to equatorial by local sidereal time.
|
||||
//
|
||||
// localSiderealTimeHours: 站点本地恒星时,单位小时
|
||||
// azimuth: 方位角,单位度,正北为0,顺时针增加
|
||||
// altitude: 高度角,单位度
|
||||
// latitude: 观测者地理纬度,单位度,北正南负
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 赤经 RA,单位度;赤纬 Dec,单位度
|
||||
//
|
||||
// 例:
|
||||
//
|
||||
// eq := coord.HorizontalToEquatorialByLocalSiderealTime(10.5, 128.2, 37.6, 31.2)
|
||||
func HorizontalToEquatorialByLocalSiderealTime(localSiderealTimeHours, azimuth, altitude, latitude float64) Equatorial {
|
||||
hourAngle, declination := HorizontalToHourAngleDeclination(azimuth, altitude, latitude)
|
||||
ra := normalize360(localSiderealTimeHours*15 - hourAngle)
|
||||
return Equatorial{RA: ra, Dec: declination}
|
||||
}
|
||||
|
||||
// EquatorialToGalactic 赤道转银道坐标 / equatorial to galactic coordinates.
|
||||
//
|
||||
// ra: ICRS 赤经,单位度
|
||||
// dec: ICRS 赤纬,单位度
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// 银经 Lon,单位度;银纬 Lat,单位度
|
||||
func EquatorialToGalactic(ra, dec float64) Galactic {
|
||||
vector := sphericalToVector(ra, dec)
|
||||
rotated := matrixVectorMul(icrsToGalacticMatrix, vector)
|
||||
lon, lat := vectorToSpherical(rotated)
|
||||
return Galactic{Lon: lon, Lat: lat}
|
||||
}
|
||||
|
||||
// GalacticToEquatorial 银道转赤道坐标 / galactic to equatorial coordinates.
|
||||
//
|
||||
// lon: 银经,单位度
|
||||
// lat: 银纬,单位度
|
||||
//
|
||||
// 返回:
|
||||
//
|
||||
// ICRS 赤经 RA,单位度;ICRS 赤纬 Dec,单位度
|
||||
func GalacticToEquatorial(lon, lat float64) Equatorial {
|
||||
vector := sphericalToVector(lon, lat)
|
||||
rotated := matrixTransposeVectorMul(icrsToGalacticMatrix, vector)
|
||||
ra, dec := vectorToSpherical(rotated)
|
||||
return Equatorial{RA: ra, Dec: dec}
|
||||
}
|
||||
|
||||
func sinCosDeg(angle float64) (sinValue, cosValue float64) {
|
||||
return math.Sincos(angle * math.Pi / 180)
|
||||
}
|
||||
|
||||
func normalize360(angle float64) float64 {
|
||||
angle = math.Mod(angle, 360)
|
||||
if angle < 0 {
|
||||
angle += 360
|
||||
}
|
||||
return angle
|
||||
}
|
||||
|
||||
func clampUnit(value float64) float64 {
|
||||
if value > 1 {
|
||||
return 1
|
||||
}
|
||||
if value < -1 {
|
||||
return -1
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func sphericalToVector(lon, lat float64) [3]float64 {
|
||||
sinLon, cosLon := sinCosDeg(lon)
|
||||
sinLat, cosLat := sinCosDeg(lat)
|
||||
return [3]float64{cosLat * cosLon, cosLat * sinLon, sinLat}
|
||||
}
|
||||
|
||||
func vectorToSpherical(vector [3]float64) (lon, lat float64) {
|
||||
lon = normalize360(math.Atan2(vector[1], vector[0]) * 180 / math.Pi)
|
||||
lat = math.Asin(clampUnit(vector[2])) * 180 / math.Pi
|
||||
return lon, lat
|
||||
}
|
||||
|
||||
func matrixVectorMul(matrix [3][3]float64, vector [3]float64) [3]float64 {
|
||||
return [3]float64{
|
||||
matrix[0][0]*vector[0] + matrix[0][1]*vector[1] + matrix[0][2]*vector[2],
|
||||
matrix[1][0]*vector[0] + matrix[1][1]*vector[1] + matrix[1][2]*vector[2],
|
||||
matrix[2][0]*vector[0] + matrix[2][1]*vector[1] + matrix[2][2]*vector[2],
|
||||
}
|
||||
}
|
||||
|
||||
func matrixTransposeVectorMul(matrix [3][3]float64, vector [3]float64) [3]float64 {
|
||||
return [3]float64{
|
||||
matrix[0][0]*vector[0] + matrix[1][0]*vector[1] + matrix[2][0]*vector[2],
|
||||
matrix[0][1]*vector[0] + matrix[1][1]*vector[1] + matrix[2][1]*vector[2],
|
||||
matrix[0][2]*vector[0] + matrix[1][2]*vector[1] + matrix[2][2]*vector[2],
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user