- 新增日食、月食、本地可见性、中心线、半影区域、SVG 图示与沙罗周期信息 - 新增行星冲合、留、方照、物理星历、视直径、相位、亮肢角、轨道节点等计算 - 新增木星伽利略卫星位置、现象与接触事件计算 - 新增恒星星表、星座判定、自行修正与观测辅助能力 - 新增 coord、formula、orbit、sundial、lite/sun、lite/moon 等扩展包 - 完善农历年号、月相英文别名、视差角、大气质量、折射、日晷与双星计算 - 增加 NASA、JPL Horizons、IMCCE 等回归测试数据与基线测试 - 重构基础算法文件组织,补充大量公开 API 注释和语义回归测试 - 更新中文和英文 README,补充示例、精度说明、SVG 配图
221 lines
8.0 KiB
Go
221 lines
8.0 KiB
Go
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],
|
||
}
|
||
}
|