@typescriptify/sweph 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/README.md +422 -0
  2. package/ephe/semo_18.se1 +0 -0
  3. package/ephe/sepl_18.se1 +0 -0
  4. package/originalCode/.eslintrc.json +124 -0
  5. package/originalCode/.gitattributes +2 -0
  6. package/originalCode/.github/FUNDING.yml +5 -0
  7. package/originalCode/.github/workflows/test.yml +35 -0
  8. package/originalCode/LICENSE +840 -0
  9. package/originalCode/README.md +91 -0
  10. package/originalCode/binding.gyp +41 -0
  11. package/originalCode/constants.js +366 -0
  12. package/originalCode/docs.gif +0 -0
  13. package/originalCode/index.d.ts +5115 -0
  14. package/originalCode/index.js +7 -0
  15. package/originalCode/index.mjs +109 -0
  16. package/originalCode/package.json +55 -0
  17. package/originalCode/src/functions/azalt.cpp +39 -0
  18. package/originalCode/src/functions/azalt_rev.cpp +35 -0
  19. package/originalCode/src/functions/calc.cpp +29 -0
  20. package/originalCode/src/functions/calc_pctr.cpp +31 -0
  21. package/originalCode/src/functions/calc_ut.cpp +29 -0
  22. package/originalCode/src/functions/close.cpp +6 -0
  23. package/originalCode/src/functions/cotrans.cpp +26 -0
  24. package/originalCode/src/functions/cotrans_sp.cpp +26 -0
  25. package/originalCode/src/functions/cs2degstr.cpp +19 -0
  26. package/originalCode/src/functions/cs2lonlatstr.cpp +23 -0
  27. package/originalCode/src/functions/cs2timestr.cpp +23 -0
  28. package/originalCode/src/functions/csnorm.cpp +15 -0
  29. package/originalCode/src/functions/csroundsec.cpp +15 -0
  30. package/originalCode/src/functions/d2l.cpp +15 -0
  31. package/originalCode/src/functions/date_conversion.cpp +30 -0
  32. package/originalCode/src/functions/day_of_week.cpp +15 -0
  33. package/originalCode/src/functions/degnorm.cpp +15 -0
  34. package/originalCode/src/functions/deltat.cpp +15 -0
  35. package/originalCode/src/functions/deltat_ex.cpp +24 -0
  36. package/originalCode/src/functions/difcs2n.cpp +19 -0
  37. package/originalCode/src/functions/difcsn.cpp +19 -0
  38. package/originalCode/src/functions/difdeg2n.cpp +19 -0
  39. package/originalCode/src/functions/difdegn.cpp +19 -0
  40. package/originalCode/src/functions/fixstar.cpp +32 -0
  41. package/originalCode/src/functions/fixstar2.cpp +32 -0
  42. package/originalCode/src/functions/fixstar2_mag.cpp +28 -0
  43. package/originalCode/src/functions/fixstar2_ut.cpp +32 -0
  44. package/originalCode/src/functions/fixstar_mag.cpp +28 -0
  45. package/originalCode/src/functions/fixstar_ut.cpp +32 -0
  46. package/originalCode/src/functions/gauquelin_sector.cpp +44 -0
  47. package/originalCode/src/functions/get_ayanamsa.cpp +15 -0
  48. package/originalCode/src/functions/get_ayanamsa_ex.cpp +27 -0
  49. package/originalCode/src/functions/get_ayanamsa_ex_ut.cpp +27 -0
  50. package/originalCode/src/functions/get_ayanamsa_name.cpp +19 -0
  51. package/originalCode/src/functions/get_ayanamsa_ut.cpp +15 -0
  52. package/originalCode/src/functions/get_current_file_data.cpp +28 -0
  53. package/originalCode/src/functions/get_library_path.cpp +8 -0
  54. package/originalCode/src/functions/get_orbital_elements.cpp +29 -0
  55. package/originalCode/src/functions/get_planet_name.cpp +19 -0
  56. package/originalCode/src/functions/get_tid_acc.cpp +7 -0
  57. package/originalCode/src/functions/heliacal_pheno_ut.cpp +52 -0
  58. package/originalCode/src/functions/heliacal_ut.cpp +52 -0
  59. package/originalCode/src/functions/helio_cross.cpp +33 -0
  60. package/originalCode/src/functions/helio_cross_ut.cpp +33 -0
  61. package/originalCode/src/functions/house_name.cpp +20 -0
  62. package/originalCode/src/functions/house_pos.cpp +36 -0
  63. package/originalCode/src/functions/houses.cpp +35 -0
  64. package/originalCode/src/functions/houses_armc.cpp +38 -0
  65. package/originalCode/src/functions/houses_armc_ex2.cpp +47 -0
  66. package/originalCode/src/functions/houses_ex.cpp +37 -0
  67. package/originalCode/src/functions/houses_ex2.cpp +46 -0
  68. package/originalCode/src/functions/jdet_to_utc.cpp +38 -0
  69. package/originalCode/src/functions/jdut1_to_utc.cpp +38 -0
  70. package/originalCode/src/functions/julday.cpp +25 -0
  71. package/originalCode/src/functions/lat_to_lmt.cpp +27 -0
  72. package/originalCode/src/functions/lmt_to_lat.cpp +27 -0
  73. package/originalCode/src/functions/lun_eclipse_how.cpp +34 -0
  74. package/originalCode/src/functions/lun_eclipse_when.cpp +31 -0
  75. package/originalCode/src/functions/lun_eclipse_when_loc.cpp +39 -0
  76. package/originalCode/src/functions/lun_occult_when_glob.cpp +35 -0
  77. package/originalCode/src/functions/lun_occult_when_loc.cpp +43 -0
  78. package/originalCode/src/functions/lun_occult_where.cpp +34 -0
  79. package/originalCode/src/functions/mooncross.cpp +26 -0
  80. package/originalCode/src/functions/mooncross_node.cpp +30 -0
  81. package/originalCode/src/functions/mooncross_node_ut.cpp +30 -0
  82. package/originalCode/src/functions/mooncross_ut.cpp +26 -0
  83. package/originalCode/src/functions/nod_aps.cpp +42 -0
  84. package/originalCode/src/functions/nod_aps_ut.cpp +42 -0
  85. package/originalCode/src/functions/orbit_max_min_true_distance.cpp +37 -0
  86. package/originalCode/src/functions/pheno.cpp +29 -0
  87. package/originalCode/src/functions/pheno_ut.cpp +29 -0
  88. package/originalCode/src/functions/radnorm.cpp +15 -0
  89. package/originalCode/src/functions/refrac.cpp +23 -0
  90. package/originalCode/src/functions/refrac_extended.cpp +32 -0
  91. package/originalCode/src/functions/revjul.cpp +33 -0
  92. package/originalCode/src/functions/rise_trans.cpp +44 -0
  93. package/originalCode/src/functions/rise_trans_true_hor.cpp +46 -0
  94. package/originalCode/src/functions/set_delta_t_userdef.cpp +14 -0
  95. package/originalCode/src/functions/set_ephe_path.cpp +14 -0
  96. package/originalCode/src/functions/set_jpl_file.cpp +14 -0
  97. package/originalCode/src/functions/set_sid_mode.cpp +20 -0
  98. package/originalCode/src/functions/set_tid_acc.cpp +14 -0
  99. package/originalCode/src/functions/set_topo.cpp +20 -0
  100. package/originalCode/src/functions/sidtime.cpp +15 -0
  101. package/originalCode/src/functions/sidtime0.cpp +21 -0
  102. package/originalCode/src/functions/sol_eclipse_how.cpp +34 -0
  103. package/originalCode/src/functions/sol_eclipse_when_glob.cpp +31 -0
  104. package/originalCode/src/functions/sol_eclipse_when_loc.cpp +39 -0
  105. package/originalCode/src/functions/sol_eclipse_where.cpp +30 -0
  106. package/originalCode/src/functions/solcross.cpp +26 -0
  107. package/originalCode/src/functions/solcross_ut.cpp +26 -0
  108. package/originalCode/src/functions/split_deg.cpp +35 -0
  109. package/originalCode/src/functions/time_equ.cpp +25 -0
  110. package/originalCode/src/functions/utc_time_zone.cpp +48 -0
  111. package/originalCode/src/functions/utc_to_jd.cpp +37 -0
  112. package/originalCode/src/functions/version.cpp +8 -0
  113. package/originalCode/src/functions/vis_limit_mag.cpp +50 -0
  114. package/originalCode/src/sweph.cpp +150 -0
  115. package/originalCode/src/sweph.h +119 -0
  116. package/originalCode/swisseph/swecl.c +6428 -0
  117. package/originalCode/swisseph/swedate.c +588 -0
  118. package/originalCode/swisseph/swedate.h +81 -0
  119. package/originalCode/swisseph/swehel.c +3511 -0
  120. package/originalCode/swisseph/swehouse.c +3143 -0
  121. package/originalCode/swisseph/swehouse.h +98 -0
  122. package/originalCode/swisseph/swejpl.c +958 -0
  123. package/originalCode/swisseph/swejpl.h +103 -0
  124. package/originalCode/swisseph/swemmoon.c +1930 -0
  125. package/originalCode/swisseph/swemplan.c +967 -0
  126. package/originalCode/swisseph/swemptab.h +10640 -0
  127. package/originalCode/swisseph/swenut2000a.h +2819 -0
  128. package/originalCode/swisseph/sweodef.h +326 -0
  129. package/originalCode/swisseph/sweph.c +8614 -0
  130. package/originalCode/swisseph/sweph.h +849 -0
  131. package/originalCode/swisseph/swephexp.h +1020 -0
  132. package/originalCode/swisseph/swephlib.c +4634 -0
  133. package/originalCode/swisseph/swephlib.h +189 -0
  134. package/package.json +28 -0
  135. package/scripts/gen-swemptab.js +177 -0
  136. package/scripts/gen-swenut2000a.js +106 -0
  137. package/src/SwissEph/README.md +268 -0
  138. package/src/SwissEph/UseCases/Ayanamsa.md +363 -0
  139. package/src/SwissEph/UseCases/AzimuthAltitude.md +408 -0
  140. package/src/SwissEph/UseCases/CoordinateSystems.md +337 -0
  141. package/src/SwissEph/UseCases/DateAndTime.md +368 -0
  142. package/src/SwissEph/UseCases/DeltaT.md +258 -0
  143. package/src/SwissEph/UseCases/EphemerisFiles.md +338 -0
  144. package/src/SwissEph/UseCases/FixedStars.md +300 -0
  145. package/src/SwissEph/UseCases/GauquelinSectors.md +304 -0
  146. package/src/SwissEph/UseCases/HeliacalEvents.md +396 -0
  147. package/src/SwissEph/UseCases/HelioCrossings.md +325 -0
  148. package/src/SwissEph/UseCases/HousePosition.md +254 -0
  149. package/src/SwissEph/UseCases/HouseSystems.md +279 -0
  150. package/src/SwissEph/UseCases/LunarEclipse.md +326 -0
  151. package/src/SwissEph/UseCases/MeridianTransit.md +279 -0
  152. package/src/SwissEph/UseCases/MoonCrossings.md +373 -0
  153. package/src/SwissEph/UseCases/NodesAndApsides.md +307 -0
  154. package/src/SwissEph/UseCases/Occultation.md +352 -0
  155. package/src/SwissEph/UseCases/OrbitalElements.md +469 -0
  156. package/src/SwissEph/UseCases/Phenomena.md +328 -0
  157. package/src/SwissEph/UseCases/PlanetPositions.md +366 -0
  158. package/src/SwissEph/UseCases/Planetocentric.md +278 -0
  159. package/src/SwissEph/UseCases/Refraction.md +314 -0
  160. package/src/SwissEph/UseCases/RiseAndSet.md +433 -0
  161. package/src/SwissEph/UseCases/SiderealTime.md +302 -0
  162. package/src/SwissEph/UseCases/SolarEclipse.md +379 -0
  163. package/src/SwissEph/UseCases/SunCrossings.md +275 -0
  164. package/src/SwissEph/UseCases/TopocentricCorrection.md +335 -0
  165. package/src/SwissEph/errors.ts +10 -0
  166. package/src/SwissEph/index.ts +823 -0
  167. package/src/SwissEph/types.ts +291 -0
  168. package/src/constants.ts +762 -0
  169. package/src/file-reader.ts +147 -0
  170. package/src/index.ts +10 -0
  171. package/src/swecl.ts +4526 -0
  172. package/src/swedate.ts +376 -0
  173. package/src/swehel.ts +1939 -0
  174. package/src/swehouse.ts +2167 -0
  175. package/src/swejpl.ts +470 -0
  176. package/src/swemmoon.ts +1318 -0
  177. package/src/swemplan.ts +585 -0
  178. package/src/swemptab.ts +4448 -0
  179. package/src/swenut2000a.ts +2763 -0
  180. package/src/sweph.ts +3993 -0
  181. package/src/swephlib.ts +2720 -0
  182. package/src/types.ts +490 -0
  183. package/tests/c-style/ayanamsa.test.ts +63 -0
  184. package/tests/c-style/config.test.ts +96 -0
  185. package/tests/c-style/crossings.test.ts +81 -0
  186. package/tests/c-style/date-time.test.ts +114 -0
  187. package/tests/c-style/eclipses.test.ts +84 -0
  188. package/tests/c-style/fixed-stars.test.ts +66 -0
  189. package/tests/c-style/heliacal.test.ts +34 -0
  190. package/tests/c-style/houses.test.ts +135 -0
  191. package/tests/c-style/math-utils.test.ts +160 -0
  192. package/tests/c-style/orbital.test.ts +78 -0
  193. package/tests/c-style/phenomena.test.ts +42 -0
  194. package/tests/c-style/planetocentric.test.ts +26 -0
  195. package/tests/c-style/planets.test.ts +117 -0
  196. package/tests/c-style/rise-set.test.ts +71 -0
  197. package/tests/helpers.ts +21 -0
  198. package/tests/modern/ayanamsa.test.ts +47 -0
  199. package/tests/modern/calc.test.ts +113 -0
  200. package/tests/modern/config.test.ts +46 -0
  201. package/tests/modern/crossings.test.ts +45 -0
  202. package/tests/modern/eclipses.test.ts +81 -0
  203. package/tests/modern/errors.test.ts +71 -0
  204. package/tests/modern/heliacal.test.ts +30 -0
  205. package/tests/modern/houses.test.ts +87 -0
  206. package/tests/modern/orbital.test.ts +79 -0
  207. package/tests/modern/phenomena.test.ts +41 -0
  208. package/tests/modern/rise-set.test.ts +60 -0
  209. package/tests/modern/statics.test.ts +99 -0
  210. package/tests/modern/utilities.test.ts +70 -0
  211. package/tsconfig.json +20 -0
@@ -0,0 +1,2720 @@
1
+ /*************************************************************
2
+ * swephlib.ts — Swiss Ephemeris library functions
3
+ * Translated from swephlib.c
4
+ *
5
+ * coordinate transformations, obliquity, nutation, precession,
6
+ * delta t, sidereal time, CRC, Chebyshev interpolation, etc.
7
+ *
8
+ * Copyright (C) 1997 - 2021 Astrodienst AG, Switzerland. (AGPL)
9
+ *************************************************************/
10
+
11
+ import {
12
+ PI, TWOPI, DEGTORAD, RADTODEG, J2000, B1950, J1900, B1850, STR,
13
+ SEFLG_JPLEPH, SEFLG_SWIEPH, SEFLG_MOSEPH, SEFLG_EPHMASK,
14
+ SEFLG_SPEED, SEFLG_BARYCTR, SEFLG_JPLHOR, SEFLG_JPLHOR_APPROX,
15
+ PREC_IAU_1976_CTIES, PREC_IAU_2000_CTIES, PREC_IAU_2006_CTIES,
16
+ SEMOD_PREC_IAU_1976, SEMOD_PREC_IAU_2000, SEMOD_PREC_IAU_2006,
17
+ SEMOD_PREC_BRETAGNON_2003, SEMOD_PREC_NEWCOMB, SEMOD_PREC_OWEN_1990,
18
+ SEMOD_PREC_SIMON_1994, SEMOD_PREC_WILLIAMS_1994, SEMOD_PREC_LASKAR_1986,
19
+ SEMOD_PREC_VONDRAK_2011, SEMOD_PREC_DEFAULT, SEMOD_PREC_DEFAULT_SHORT,
20
+ SEMOD_PREC_WILL_EPS_LASK,
21
+ SEMOD_NUT_IAU_1980, SEMOD_NUT_IAU_CORR_1987, SEMOD_NUT_IAU_2000A,
22
+ SEMOD_NUT_IAU_2000B, SEMOD_NUT_WOOLARD, SEMOD_NUT_DEFAULT,
23
+ SEMOD_SIDT_IAU_1976, SEMOD_SIDT_IAU_2006, SEMOD_SIDT_IERS_CONV_2010,
24
+ SEMOD_SIDT_LONGTERM, SEMOD_SIDT_DEFAULT,
25
+ SEMOD_BIAS_NONE, SEMOD_BIAS_IAU2000, SEMOD_BIAS_IAU2006,
26
+ SEMOD_BIAS_DEFAULT,
27
+ SEMOD_JPLHOR_LONG_AGREEMENT, SEMOD_JPLHORA_1, SEMOD_JPLHORA_2,
28
+ SEMOD_JPLHORA_3, SEMOD_JPLHORA_DEFAULT,
29
+ SEMOD_DELTAT_STEPHENSON_MORRISON_1984, SEMOD_DELTAT_STEPHENSON_1997,
30
+ SEMOD_DELTAT_STEPHENSON_MORRISON_2004, SEMOD_DELTAT_ESPENAK_MEEUS_2006,
31
+ SEMOD_DELTAT_STEPHENSON_ETC_2016, SEMOD_DELTAT_DEFAULT,
32
+ SEMOD_NPREC, SEMOD_NNUT, SEMOD_NSIDT, SEMOD_NBIAS,
33
+ SEMOD_NJPLHOR, SEMOD_NJPLHORA, SEMOD_NDELTAT,
34
+ SEI_NMODELS,
35
+ DPSI_DEPS_IAU1980_TJD0_HORIZONS, HORIZONS_TJD0_DPSI_DEPS_IAU1980,
36
+ DPSI_IAU1980_TJD0, DEPS_IAU1980_TJD0,
37
+ J2000_TO_J, J_TO_J2000,
38
+ NUT_SPEED_INTV, SE_TIDAL_DEFAULT, SE_TIDAL_26, SE_TIDAL_AUTOMATIC,
39
+ SE_TIDAL_DE200, SE_TIDAL_DE403, SE_TIDAL_DE404, SE_TIDAL_DE405,
40
+ SE_TIDAL_DE406, SE_TIDAL_DE421, SE_TIDAL_DE422, SE_TIDAL_DE430,
41
+ SE_TIDAL_DE431, SE_TIDAL_DE441, SE_TIDAL_STEPHENSON_2016,
42
+ SE_DELTAT_AUTOMATIC, SE_DE_NUMBER, SE_TIDAL_MOSEPH,
43
+ SEI_FILE_MOON,
44
+ SE_MODEL_PREC_LONGTERM, SE_MODEL_PREC_SHORTTERM, SE_MODEL_NUT,
45
+ SE_MODEL_SIDT, SE_MODEL_BIAS, SE_MODEL_JPLHOR_MODE, SE_MODEL_JPLHORA_MODE,
46
+ SE_MODEL_DELTAT,
47
+ AS_MAXCH, SWE_DATA_DPSI_DEPS,
48
+ SE_SPLIT_DEG_ROUND_DEG, SE_SPLIT_DEG_ROUND_MIN, SE_SPLIT_DEG_ROUND_SEC,
49
+ SE_SPLIT_DEG_KEEP_DEG, SE_SPLIT_DEG_KEEP_SIGN, SE_SPLIT_DEG_NAKSHATRA,
50
+ SE_SPLIT_DEG_ZODIACAL,
51
+ OK, ERR, ENDMARK,
52
+ AUNIT, CLIGHT, NCTIES,
53
+ SEI_MOON, SEI_EMB, SEI_MERCURY, SEI_VENUS, SEI_MARS,
54
+ SEI_JUPITER, SEI_SATURN, SEI_URANUS, SEI_NEPTUNE, SEI_PLUTO,
55
+ SEI_SUNBARY, SEI_CERES, SEI_PALLAS, SEI_JUNO, SEI_VESTA,
56
+ SEI_CHIRON, SEI_PHOLUS,
57
+ SE_PLMOON_OFFSET, SE_AST_OFFSET, SE_FILE_SUFFIX,
58
+ } from './constants';
59
+
60
+ import type { SweData, Epsilon, Nut, Interpol } from './types';
61
+
62
+ // IAU 2000A nutation data — placeholder imports (will be provided by swenut2000a.ts)
63
+ // For now we declare them; the actual file will export these arrays.
64
+ import {
65
+ O1MAS2DEG, NLS, NLS_2000B, NPL,
66
+ nls as nutLsArgMul, cls as nutLsCoef,
67
+ npl as nutPlArgMul, icpl as nutPlCoef,
68
+ } from './swenut2000a';
69
+
70
+ /* ================================================================
71
+ * Utility: square_sum (replaces C macro)
72
+ * ================================================================ */
73
+ export function squareSum(x: ArrayLike<number>, off = 0): number {
74
+ return x[off] * x[off] + x[off + 1] * x[off + 1] + x[off + 2] * x[off + 2];
75
+ }
76
+
77
+ /* ================================================================
78
+ * 1. Angle normalization
79
+ * ================================================================ */
80
+
81
+ /** Reduce x modulo 360 degrees → [0, 360) */
82
+ export function sweDegnorm(x: number): number {
83
+ let y = x % 360.0;
84
+ if (Math.abs(y) < 1e-13) y = 0;
85
+ if (y < 0.0) y += 360.0;
86
+ return y;
87
+ }
88
+
89
+ /** Reduce x modulo 2*PI → [0, 2π) */
90
+ export function sweRadnorm(x: number): number {
91
+ let y = x % TWOPI;
92
+ if (Math.abs(y) < 1e-13) y = 0;
93
+ if (y < 0.0) y += TWOPI;
94
+ return y;
95
+ }
96
+
97
+ /** Midpoint in degrees */
98
+ export function sweDegMidp(x1: number, x0: number): number {
99
+ const d = sweDifdeg2n(x1, x0);
100
+ return sweDegnorm(x0 + d / 2);
101
+ }
102
+
103
+ /** Midpoint in radians */
104
+ export function sweRadMidp(x1: number, x0: number): number {
105
+ return DEGTORAD * sweDegMidp(x1 * RADTODEG, x0 * RADTODEG);
106
+ }
107
+
108
+ /** Reduce x modulo 2*PI (no near-zero fix) */
109
+ export function swiMod2PI(x: number): number {
110
+ let y = x % TWOPI;
111
+ if (y < 0.0) y += TWOPI;
112
+ return y;
113
+ }
114
+
115
+ /** Quick angle normalization (assumes x is at most one period off) */
116
+ export function swiAngnorm(x: number): number {
117
+ if (x < 0.0) return x + TWOPI;
118
+ else if (x >= TWOPI) return x - TWOPI;
119
+ else return x;
120
+ }
121
+
122
+ /* ================================================================
123
+ * 2. Cross product
124
+ * ================================================================ */
125
+
126
+ export function swiCrossProd(
127
+ a: ArrayLike<number>, b: ArrayLike<number>, x: Float64Array, xOff = 0,
128
+ ): void {
129
+ x[xOff] = a[1] * b[2] - a[2] * b[1];
130
+ x[xOff + 1] = a[2] * b[0] - a[0] * b[2];
131
+ x[xOff + 2] = a[0] * b[1] - a[1] * b[0];
132
+ }
133
+
134
+ /* ================================================================
135
+ * 3. Chebyshev evaluation
136
+ * ================================================================ */
137
+
138
+ /**
139
+ * Evaluate Chebyshev series coef[0..ncf-1] at x in [-1, 1].
140
+ * ACM algorithm 446 by Broucke.
141
+ */
142
+ export function swiEcheb(x: number, coef: ArrayLike<number>, ncf: number): number {
143
+ const x2 = x * 2;
144
+ let br = 0, brp2 = 0, brpp = 0;
145
+ for (let j = ncf - 1; j >= 0; j--) {
146
+ brp2 = brpp;
147
+ brpp = br;
148
+ br = x2 * brpp - brp2 + coef[j];
149
+ }
150
+ return (br - brp2) * 0.5;
151
+ }
152
+
153
+ /** Evaluate derivative of Chebyshev series */
154
+ export function swiEdcheb(x: number, coef: ArrayLike<number>, ncf: number): number {
155
+ const x2 = x * 2;
156
+ let bf = 0, bj = 0;
157
+ let xjp2 = 0, xjpl = 0;
158
+ let bjp2 = 0, bjpl = 0;
159
+ for (let j = ncf - 1; j >= 1; j--) {
160
+ const dj = j + j;
161
+ const xj = coef[j] * dj + xjp2;
162
+ bj = x2 * bjpl - bjp2 + xj;
163
+ bf = bjp2;
164
+ bjp2 = bjpl;
165
+ bjpl = bj;
166
+ xjp2 = xjpl;
167
+ xjpl = xj;
168
+ }
169
+ return (bj - bf) * 0.5;
170
+ }
171
+
172
+ /* ================================================================
173
+ * 4. Coordinate transforms
174
+ * ================================================================ */
175
+
176
+ /**
177
+ * Ecliptical ↔ equatorial polar coordinate conversion (degrees).
178
+ * For ecl→equ: eps must be negative. For equ→ecl: eps must be positive.
179
+ * xpo, xpn are [lon, lat, dist] in degrees (dist passed through).
180
+ */
181
+ export function sweCotrans(xpo: number[], xpn: number[], eps: number): void {
182
+ const e = eps * DEGTORAD;
183
+ const x = new Float64Array(6);
184
+ x[0] = xpo[0] * DEGTORAD;
185
+ x[1] = xpo[1] * DEGTORAD;
186
+ x[2] = 1;
187
+ swiPolcart(x, x);
188
+ swiCoortrf(x, x, e);
189
+ swiCartpol(x, x);
190
+ xpn[0] = x[0] * RADTODEG;
191
+ xpn[1] = x[1] * RADTODEG;
192
+ xpn[2] = xpo[2];
193
+ }
194
+
195
+ /**
196
+ * Ecliptical ↔ equatorial polar with speed (degrees).
197
+ * For ecl→equ: eps must be negative. For equ→ecl: eps must be positive.
198
+ * xpo, xpn are [lon, lat, dist, lonSpd, latSpd, distSpd].
199
+ */
200
+ export function sweCotransSp(xpo: number[], xpn: number[], eps: number): void {
201
+ const e = eps * DEGTORAD;
202
+ const x = new Float64Array(6);
203
+ for (let i = 0; i <= 5; i++) x[i] = xpo[i];
204
+ x[0] *= DEGTORAD;
205
+ x[1] *= DEGTORAD;
206
+ x[2] = 1;
207
+ x[3] *= DEGTORAD;
208
+ x[4] *= DEGTORAD;
209
+ swiPolcartSp(x, x);
210
+ swiCoortrf(x, x, e);
211
+ swiCoortrfOff(x, 3, x, 3, e);
212
+ swiCartpolSp(x, xpn);
213
+ xpn[0] *= RADTODEG;
214
+ xpn[1] *= RADTODEG;
215
+ xpn[2] = xpo[2];
216
+ xpn[3] *= RADTODEG;
217
+ xpn[4] *= RADTODEG;
218
+ xpn[5] = xpo[5];
219
+ }
220
+
221
+ /**
222
+ * Ecliptical ↔ equatorial cartesian rotation.
223
+ * For ecl→equ: eps must be negative.
224
+ */
225
+ export function swiCoortrf(
226
+ xpo: ArrayLike<number>, xpn: Float64Array | number[], eps: number,
227
+ srcOff = 0, dstOff = 0,
228
+ ): void {
229
+ const sineps = Math.sin(eps);
230
+ const coseps = Math.cos(eps);
231
+ const x0 = xpo[srcOff];
232
+ const x1 = xpo[srcOff + 1] * coseps + xpo[srcOff + 2] * sineps;
233
+ const x2 = -xpo[srcOff + 1] * sineps + xpo[srcOff + 2] * coseps;
234
+ xpn[dstOff] = x0;
235
+ xpn[dstOff + 1] = x1;
236
+ xpn[dstOff + 2] = x2;
237
+ }
238
+
239
+ /** Offset variant for speed arrays (replaces C's `swi_coortrf(x+3, x+3, e)`) */
240
+ function swiCoortrfOff(
241
+ xpo: ArrayLike<number>, srcOff: number,
242
+ xpn: Float64Array | number[], dstOff: number,
243
+ eps: number,
244
+ ): void {
245
+ swiCoortrf(xpo, xpn, eps, srcOff, dstOff);
246
+ }
247
+
248
+ /**
249
+ * Ecliptical ↔ equatorial cartesian rotation with pre-computed sin/cos.
250
+ * For ecl→equ: sineps must be -sin(eps).
251
+ */
252
+ export function swiCoortrf2(
253
+ xpo: ArrayLike<number>, xpn: Float64Array | number[],
254
+ sineps: number, coseps: number,
255
+ srcOff = 0, dstOff = 0,
256
+ ): void {
257
+ const x0 = xpo[srcOff];
258
+ const x1 = xpo[srcOff + 1] * coseps + xpo[srcOff + 2] * sineps;
259
+ const x2 = -xpo[srcOff + 1] * sineps + xpo[srcOff + 2] * coseps;
260
+ xpn[dstOff] = x0;
261
+ xpn[dstOff + 1] = x1;
262
+ xpn[dstOff + 2] = x2;
263
+ }
264
+
265
+ /** Cartesian [x,y,z] → polar [lon, lat, rad] */
266
+ export function swiCartpol(x: ArrayLike<number>, l: Float64Array | number[], srcOff = 0, dstOff = 0): void {
267
+ const x0 = x[srcOff], x1 = x[srcOff + 1], x2 = x[srcOff + 2];
268
+ if (x0 === 0 && x1 === 0 && x2 === 0) {
269
+ l[dstOff] = l[dstOff + 1] = l[dstOff + 2] = 0;
270
+ return;
271
+ }
272
+ let rxy = x0 * x0 + x1 * x1;
273
+ const rad = Math.sqrt(rxy + x2 * x2);
274
+ rxy = Math.sqrt(rxy);
275
+ let lon = Math.atan2(x1, x0);
276
+ if (lon < 0.0) lon += TWOPI;
277
+ let lat: number;
278
+ if (rxy === 0) {
279
+ lat = x2 >= 0 ? PI / 2 : -(PI / 2);
280
+ } else {
281
+ lat = Math.atan(x2 / rxy);
282
+ }
283
+ l[dstOff] = lon;
284
+ l[dstOff + 1] = lat;
285
+ l[dstOff + 2] = rad;
286
+ }
287
+
288
+ /** Polar [lon, lat, rad] → cartesian [x, y, z] */
289
+ export function swiPolcart(l: ArrayLike<number>, x: Float64Array | number[], srcOff = 0, dstOff = 0): void {
290
+ const cosl1 = Math.cos(l[srcOff + 1]);
291
+ const xx0 = l[srcOff + 2] * cosl1 * Math.cos(l[srcOff]);
292
+ const xx1 = l[srcOff + 2] * cosl1 * Math.sin(l[srcOff]);
293
+ const xx2 = l[srcOff + 2] * Math.sin(l[srcOff + 1]);
294
+ x[dstOff] = xx0;
295
+ x[dstOff + 1] = xx1;
296
+ x[dstOff + 2] = xx2;
297
+ }
298
+
299
+ /** Cartesian position+speed → polar position+speed */
300
+ export function swiCartpolSp(x: ArrayLike<number>, l: Float64Array | number[]): void {
301
+ // zero position: direction of motion
302
+ if (x[0] === 0 && x[1] === 0 && x[2] === 0) {
303
+ const ll = new Float64Array(6);
304
+ ll[5] = Math.sqrt(squareSum(x, 3));
305
+ swiCartpol(x, ll, 3, 0);
306
+ ll[2] = 0;
307
+ ll[3] = 0; ll[4] = 0;
308
+ for (let i = 0; i <= 5; i++) l[i] = ll[i];
309
+ return;
310
+ }
311
+ // zero speed
312
+ if (x[3] === 0 && x[4] === 0 && x[5] === 0) {
313
+ l[3] = l[4] = l[5] = 0;
314
+ swiCartpol(x, l);
315
+ return;
316
+ }
317
+ // position
318
+ let rxy = x[0] * x[0] + x[1] * x[1];
319
+ const rad = Math.sqrt(rxy + x[2] * x[2]);
320
+ rxy = Math.sqrt(rxy);
321
+ const lon = Math.atan2(x[1], x[0]) < 0 ? Math.atan2(x[1], x[0]) + TWOPI : Math.atan2(x[1], x[0]);
322
+ const lat = Math.atan(x[2] / rxy);
323
+ // speed
324
+ const coslon = x[0] / rxy;
325
+ const sinlon = x[1] / rxy;
326
+ const coslat = rxy / rad;
327
+ const sinlat = x[2] / rad;
328
+ let xx3 = x[3] * coslon + x[4] * sinlon;
329
+ const xx4_lon = -x[3] * sinlon + x[4] * coslon;
330
+ l[3] = xx4_lon / rxy; // speed in longitude
331
+ const xx4 = -sinlat * xx3 + coslat * x[5];
332
+ const xx5 = coslat * xx3 + sinlat * x[5];
333
+ l[4] = xx4 / rad; // speed in latitude
334
+ l[5] = xx5; // speed in radius
335
+ l[0] = lon;
336
+ l[1] = lat;
337
+ l[2] = rad;
338
+ }
339
+
340
+ /** Polar position+speed → cartesian position+speed */
341
+ export function swiPolcartSp(l: ArrayLike<number>, x: Float64Array | number[]): void {
342
+ // zero speed
343
+ if (l[3] === 0 && l[4] === 0 && l[5] === 0) {
344
+ x[3] = x[4] = x[5] = 0;
345
+ swiPolcart(l, x);
346
+ return;
347
+ }
348
+ const coslon = Math.cos(l[0]);
349
+ const sinlon = Math.sin(l[0]);
350
+ const coslat = Math.cos(l[1]);
351
+ const sinlat = Math.sin(l[1]);
352
+ const xx0 = l[2] * coslat * coslon;
353
+ const xx1 = l[2] * coslat * sinlon;
354
+ const xx2 = l[2] * sinlat;
355
+ // speed
356
+ const rxyz = l[2];
357
+ const rxy = Math.sqrt(xx0 * xx0 + xx1 * xx1);
358
+ const xx5 = l[5];
359
+ const xx4 = l[4] * rxyz;
360
+ x[5] = sinlat * xx5 + coslat * xx4;
361
+ const xx3 = coslat * xx5 - sinlat * xx4;
362
+ const xx4b = l[3] * rxy;
363
+ x[3] = coslon * xx3 - sinlon * xx4b;
364
+ x[4] = sinlon * xx3 + coslon * xx4b;
365
+ x[0] = xx0;
366
+ x[1] = xx1;
367
+ x[2] = xx2;
368
+ }
369
+
370
+ /** Dot product of unit vectors → cosine of angle, clamped to [-1,1] */
371
+ export function swiDotProdUnit(x: ArrayLike<number>, y: ArrayLike<number>): number {
372
+ let dop = x[0] * y[0] + x[1] * y[1] + x[2] * y[2];
373
+ const e1 = Math.sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
374
+ const e2 = Math.sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
375
+ dop /= e1;
376
+ dop /= e2;
377
+ if (dop > 1) dop = 1;
378
+ if (dop < -1) dop = -1;
379
+ return dop;
380
+ }
381
+
382
+ /* ================================================================
383
+ * 5. Centisecond and degree utilities
384
+ * ================================================================ */
385
+
386
+ /** Normalize centiseconds to [0, DEG360) */
387
+ export function sweCsnorm(p: number): number {
388
+ let q = p;
389
+ while (q < 0) q += 360 * 360000;
390
+ while (q >= 360 * 360000) q -= 360 * 360000;
391
+ return q;
392
+ }
393
+
394
+ /** Difference in centiseconds, normalized to [-180°, 180°) */
395
+ export function sweDifcsn(p1: number, p2: number): number {
396
+ let diff = (p1 - p2) % (360 * 360000);
397
+ if (diff >= 180 * 360000) diff -= 360 * 360000;
398
+ if (diff < -180 * 360000) diff += 360 * 360000;
399
+ return diff;
400
+ }
401
+
402
+ /** Difference of two radian angles, normalized to [-PI, PI) */
403
+ export function sweDifrad2n(p1: number, p2: number): number {
404
+ let d = sweRadnorm(p1 - p2);
405
+ if (d >= PI) return d - TWOPI;
406
+ return d;
407
+ }
408
+
409
+ /** Difference in degrees, normalized to [-180, 180) */
410
+ export function sweDifdeg2n(p1: number, p2: number): number {
411
+ let d = p1 - p2;
412
+ d = d % 360.0;
413
+ if (Math.abs(d) < 1e-14) d = 0;
414
+ if (d >= 180.0) d -= 360.0;
415
+ if (d < -180.0) d += 360.0;
416
+ return d;
417
+ }
418
+
419
+ /** Double → int32 (C-style truncation + rounding to nearest) */
420
+ export function sweD2l(x: number): number {
421
+ if (x >= 0) return Math.floor(x + 0.5);
422
+ else return Math.ceil(x - 0.5);
423
+ }
424
+
425
+ /** Day of week: Monday = 0, ... Sunday = 6 */
426
+ export function sweDayOfWeek(jd: number): number {
427
+ return (Math.floor(jd - 2433282 - 1.5) % 7 + 7) % 7;
428
+ }
429
+
430
+ /* ================================================================
431
+ * 6. swe_split_deg
432
+ * ================================================================ */
433
+
434
+ export interface SplitDegResult {
435
+ deg: number;
436
+ min: number;
437
+ sec: number;
438
+ secFr: number;
439
+ sign: number;
440
+ }
441
+
442
+ function splitDegNakshatra(ddeg: number, roundflag: number): SplitDegResult {
443
+ let dateflag = false;
444
+ let deg: number, min: number, sec: number, secfr: number;
445
+
446
+ if ((roundflag & SE_SPLIT_DEG_ROUND_DEG) !== 0) {
447
+ ddeg = Math.round(ddeg);
448
+ ddeg = ddeg % 360;
449
+ const inak = Math.trunc(ddeg / (360 / 27));
450
+ deg = ddeg - inak * (360 / 27);
451
+ return { deg, min: 0, sec: 0, secFr: 0, sign: inak };
452
+ }
453
+ if ((roundflag & SE_SPLIT_DEG_ROUND_MIN) !== 0) dateflag = true;
454
+ if ((roundflag & SE_SPLIT_DEG_ROUND_SEC) !== 0) dateflag = true;
455
+
456
+ ddeg = ddeg % 360;
457
+ const inak = Math.trunc(ddeg / (360 / 27));
458
+ ddeg -= inak * (360 / 27);
459
+ deg = Math.trunc(ddeg);
460
+ let d = (ddeg - deg) * 60;
461
+ min = Math.trunc(d);
462
+ d = (d - min) * 60;
463
+ sec = Math.trunc(d);
464
+ secfr = d - sec;
465
+
466
+ if (dateflag) {
467
+ if ((roundflag & SE_SPLIT_DEG_ROUND_SEC) !== 0) {
468
+ if (secfr >= 0.5) sec++;
469
+ secfr = 0;
470
+ if (sec >= 60) { sec = 0; min++; }
471
+ if (min >= 60) { min = 0; deg++; }
472
+ }
473
+ if ((roundflag & SE_SPLIT_DEG_ROUND_MIN) !== 0) {
474
+ if (sec >= 30) min++;
475
+ sec = 0; secfr = 0;
476
+ if (min >= 60) { min = 0; deg++; }
477
+ }
478
+ }
479
+ return { deg, min, sec, secFr: secfr, sign: inak };
480
+ }
481
+
482
+ export function sweSplitDeg(
483
+ ddeg: number,
484
+ roundflag: number,
485
+ ): SplitDegResult {
486
+ if ((roundflag & SE_SPLIT_DEG_NAKSHATRA) !== 0) {
487
+ return splitDegNakshatra(ddeg, roundflag);
488
+ }
489
+
490
+ let dateflag = false;
491
+ let deg: number, min: number, sec: number, secfr: number, sgn: number;
492
+
493
+ if ((roundflag & SE_SPLIT_DEG_ROUND_DEG) !== 0) dateflag = true;
494
+ if ((roundflag & SE_SPLIT_DEG_ROUND_MIN) !== 0) dateflag = true;
495
+ if ((roundflag & SE_SPLIT_DEG_ROUND_SEC) !== 0) dateflag = true;
496
+
497
+ if ((roundflag & SE_SPLIT_DEG_KEEP_DEG) !== 0) {
498
+ if (ddeg < 0) {
499
+ sgn = -1;
500
+ ddeg = -ddeg;
501
+ } else {
502
+ sgn = 0;
503
+ }
504
+ if ((roundflag & SE_SPLIT_DEG_KEEP_SIGN) !== 0) {
505
+ // not applicable without zodiacal
506
+ }
507
+ } else if ((roundflag & SE_SPLIT_DEG_ZODIACAL) !== 0) {
508
+ sgn = 0;
509
+ ddeg = sweDegnorm(ddeg);
510
+ sgn = Math.trunc(ddeg / 30);
511
+ ddeg = ddeg % 30;
512
+ } else {
513
+ sgn = 0;
514
+ if (ddeg < 0) { sgn = -1; ddeg = -ddeg; }
515
+ }
516
+
517
+ deg = Math.trunc(ddeg);
518
+ let d = (ddeg - deg) * 60;
519
+ min = Math.trunc(d);
520
+ d = (d - min) * 60;
521
+ sec = Math.trunc(d);
522
+ secfr = d - sec;
523
+
524
+ if (dateflag) {
525
+ if ((roundflag & SE_SPLIT_DEG_ROUND_SEC) !== 0) {
526
+ if (secfr >= 0.5) sec++;
527
+ secfr = 0;
528
+ if (sec >= 60) { sec = 0; min++; }
529
+ if (min >= 60) { min = 0; deg++; }
530
+ }
531
+ if ((roundflag & SE_SPLIT_DEG_ROUND_MIN) !== 0) {
532
+ if (sec >= 30) min++;
533
+ sec = 0; secfr = 0;
534
+ if (min >= 60) { min = 0; deg++; }
535
+ }
536
+ if ((roundflag & SE_SPLIT_DEG_ROUND_DEG) !== 0) {
537
+ if (min >= 30) deg++;
538
+ min = 0; sec = 0; secfr = 0;
539
+ }
540
+ if ((roundflag & SE_SPLIT_DEG_ZODIACAL) !== 0) {
541
+ if (deg >= 30) {
542
+ deg = 0;
543
+ sgn++;
544
+ if (sgn >= 12) sgn = 0;
545
+ }
546
+ }
547
+ }
548
+
549
+ return { deg, min, sec, secFr: secfr, sign: sgn };
550
+ }
551
+
552
+ /* ================================================================
553
+ * 7. CRC32
554
+ * ================================================================ */
555
+
556
+ let crc32Table: Uint32Array | null = null;
557
+ const CRC32_POLY = 0x04c11db7; // AUTODIN II, Ethernet, FDDI — MSB-first
558
+
559
+ function initCrc32(): void {
560
+ if (crc32Table) return;
561
+ crc32Table = new Uint32Array(256);
562
+ for (let i = 0; i < 256; i++) {
563
+ let c = (i << 24) >>> 0;
564
+ for (let j = 8; j > 0; j--) {
565
+ c = c & 0x80000000 ? ((c << 1) ^ CRC32_POLY) >>> 0 : (c << 1) >>> 0;
566
+ }
567
+ crc32Table[i] = c >>> 0;
568
+ }
569
+ }
570
+
571
+ export function swiCrc32(buf: Uint8Array, len: number): number {
572
+ initCrc32();
573
+ let crc = 0xFFFFFFFF;
574
+ for (let i = 0; i < len; i++) {
575
+ crc = ((crc << 8) ^ crc32Table![((crc >>> 24) ^ buf[i]) & 0xFF]) >>> 0;
576
+ }
577
+ return (~crc) >>> 0;
578
+ }
579
+
580
+ /* ================================================================
581
+ * 8. Kepler equation solver
582
+ * ================================================================ */
583
+
584
+ export function swiKepler(E: number, M: number, ecce: number): number {
585
+ let dE = 1;
586
+ let E1 = E;
587
+ const maxIter = 200;
588
+ for (let i = 0; i < maxIter && Math.abs(dE) > 1e-12; i++) {
589
+ dE = (E1 - ecce * Math.sin(E1) - M) / (1 - ecce * Math.cos(E1));
590
+ E1 -= dE;
591
+ }
592
+ return E1;
593
+ }
594
+
595
+ /* ================================================================
596
+ * 9. FK4 ↔ FK5
597
+ * ================================================================ */
598
+
599
+ export function swiFK4_FK5(xp: Float64Array | number[], tjd: number): void {
600
+ // equinox and epoch J2000 to B1950
601
+ const cosRA = Math.cos(xp[0]);
602
+ const sinRA = Math.sin(xp[0]);
603
+ const cosDec = Math.cos(xp[1]);
604
+ const sinDec = Math.sin(xp[1]);
605
+ // E-terms removal
606
+ const a0 = -1.62557e-6;
607
+ const a1 = -0.31919e-6;
608
+ const a2 = -0.13843e-6;
609
+ const d0 = a0 * cosDec * cosRA + a1 * cosDec * sinRA + a2 * sinDec;
610
+ xp[0] += -a0 * sinRA + a1 * cosRA + (a0 * cosRA + a1 * sinRA) * sinDec / cosDec * d0;
611
+ xp[1] += d0 * (cosDec - sinDec * d0);
612
+ }
613
+
614
+ export function swiFK5_FK4(xp: Float64Array | number[], tjd: number): void {
615
+ // reverse: add E-terms
616
+ const cosRA = Math.cos(xp[0]);
617
+ const sinRA = Math.sin(xp[0]);
618
+ const cosDec = Math.cos(xp[1]);
619
+ const sinDec = Math.sin(xp[1]);
620
+ const a0 = -1.62557e-6;
621
+ const a1 = -0.31919e-6;
622
+ const a2 = -0.13843e-6;
623
+ const d0 = a0 * cosDec * cosRA + a1 * cosDec * sinRA + a2 * sinDec;
624
+ xp[0] -= -a0 * sinRA + a1 * cosRA + (a0 * cosRA + a1 * sinRA) * sinDec / cosDec * d0;
625
+ xp[1] -= d0 * (cosDec - sinDec * d0);
626
+ }
627
+
628
+ /* ================================================================
629
+ * 10. Astro-model helpers
630
+ * ================================================================ */
631
+
632
+ function getPrecModel(swed: SweData): number {
633
+ const m = swed.astroModels[SE_MODEL_PREC_LONGTERM];
634
+ return m !== 0 ? m : SEMOD_PREC_DEFAULT;
635
+ }
636
+
637
+ function getPrecModelShort(swed: SweData): number {
638
+ const m = swed.astroModels[SE_MODEL_PREC_SHORTTERM];
639
+ return m !== 0 ? m : SEMOD_PREC_DEFAULT;
640
+ }
641
+
642
+ function getNutModel(swed: SweData): number {
643
+ const m = swed.astroModels[SE_MODEL_NUT];
644
+ return m !== 0 ? m : SEMOD_NUT_DEFAULT;
645
+ }
646
+
647
+ function getSidtModel(swed: SweData): number {
648
+ const m = swed.astroModels[SE_MODEL_SIDT];
649
+ return m !== 0 ? m : SEMOD_SIDT_DEFAULT;
650
+ }
651
+
652
+ function getBiasModel(swed: SweData): number {
653
+ const m = swed.astroModels[SE_MODEL_BIAS];
654
+ return m !== 0 ? m : SEMOD_BIAS_DEFAULT;
655
+ }
656
+
657
+ function getJplHorModel(swed: SweData): number {
658
+ const m = swed.astroModels[SE_MODEL_JPLHOR_MODE];
659
+ return m !== 0 ? m : SEMOD_JPLHOR_LONG_AGREEMENT;
660
+ }
661
+
662
+ function getJplHoraModel(swed: SweData): number {
663
+ const m = swed.astroModels[SE_MODEL_JPLHORA_MODE];
664
+ return m !== 0 ? m : SEMOD_JPLHORA_DEFAULT;
665
+ }
666
+
667
+ function getDeltatModel(swed: SweData): number {
668
+ const m = swed.astroModels[SE_MODEL_DELTAT];
669
+ return m !== 0 ? m : SEMOD_DELTAT_DEFAULT;
670
+ }
671
+
672
+ export function sweSetAstroModels(swed: SweData, saession: string): void {
673
+ // parse comma-separated list of model numbers
674
+ const parts = saession.split(',');
675
+ for (let i = 0; i < parts.length && i < SEI_NMODELS; i++) {
676
+ const val = parseInt(parts[i].trim(), 10);
677
+ if (!isNaN(val)) {
678
+ swed.astroModels[i] = val;
679
+ }
680
+ }
681
+ }
682
+
683
+ export function sweGetAstroModels(swed: SweData): string {
684
+ const parts: string[] = [];
685
+ for (let i = 0; i < SEI_NMODELS; i++) {
686
+ parts.push(String(swed.astroModels[i]));
687
+ }
688
+ return parts.join(',');
689
+ }
690
+
691
+ /** Guess ephemeris flag from SweData */
692
+ export function swiGuessEpheFlag(swed: SweData): number {
693
+ if ((swed.lastEpheflag & SEFLG_JPLEPH) !== 0) return SEFLG_JPLEPH;
694
+ if ((swed.lastEpheflag & SEFLG_MOSEPH) !== 0) return SEFLG_MOSEPH;
695
+ return SEFLG_SWIEPH;
696
+ }
697
+
698
+ /* ================================================================
699
+ * 11. Vondrak 2011 precession tables and functions
700
+ * ================================================================ */
701
+
702
+ const AS2R = DEGTORAD / 3600.0;
703
+ const D2PI = TWOPI;
704
+ const EPS0 = 84381.406 * AS2R;
705
+
706
+ /* pepol[4][2], peper[5][10] — for swi_ldp_peps */
707
+ const pepol: readonly [number, number][] = [
708
+ [+8134.017132, +84028.206305],
709
+ [+5043.0520035, +0.3624445],
710
+ [-0.00710733, -0.00004039],
711
+ [+0.000000271, -0.000000110],
712
+ ];
713
+
714
+ const peper: readonly number[][] = [
715
+ [+409.90, +396.15, +537.22, +402.90, +417.15, +288.92, +4043.00, +306.00, +277.00, +203.00],
716
+ [-6908.287473, -3198.706291, +1453.674527, -857.748557, +1173.231614, -156.981465, +371.836550, -216.619040, +193.691479, +11.891524],
717
+ [+753.872780, -247.805823, +379.471484, -53.880558, -90.109153, -353.600190, -63.115353, -28.248187, +17.703387, +38.911307],
718
+ [-2845.175469, +449.844989, -1255.915323, +886.736783, +418.887514, +997.912441, -240.979710, +76.541307, -36.788069, -170.964086],
719
+ [-1704.720302, -862.308358, +447.832178, -889.571909, +190.402846, -56.564991, -296.222622, -75.859952, +67.473503, +3.014055],
720
+ ];
721
+
722
+ /* pqpol[4][2], pqper[5][8] — for pre_pecl */
723
+ const pqpol: readonly [number, number][] = [
724
+ [+5851.607687, -1600.886300],
725
+ [-0.1189000, +1.1689818],
726
+ [-0.00028913, -0.00000020],
727
+ [+0.000000101, -0.000000437],
728
+ ];
729
+
730
+ const pqper: readonly number[][] = [
731
+ [708.15, 2309, 1620, 492.2, 1183, 622, 882, 547],
732
+ [-5486.751211, -17.127623, -617.517403, 413.44294, 78.614193, -180.732815, -87.676083, 46.140315],
733
+ [-684.66156, 2446.28388, 399.671049, -356.652376, -186.387003, -316.80007, 198.296701, 101.135679],
734
+ [667.66673, -2354.886252, -428.152441, 376.202861, 184.778874, 335.321713, -185.138669, -120.97283],
735
+ [-5523.863691, -549.74745, -310.998056, 421.535876, -36.776172, -145.278396, -34.74445, 22.885731],
736
+ ];
737
+
738
+ /* xypol[4][2], xyper[5][14] — for pre_pequ */
739
+ const xypol: readonly [number, number][] = [
740
+ [+5453.282155, -73750.930350],
741
+ [+0.4252841, -0.7675452],
742
+ [-0.00037173, -0.00018725],
743
+ [-0.000000152, +0.000000231],
744
+ ];
745
+
746
+ const xyper: readonly number[][] = [
747
+ [256.75, 708.15, 274.2, 241.45, 2309, 492.2, 396.1, 288.9, 231.1, 1610, 620, 157.87, 220.3, 1200],
748
+ [-819.940624, -8444.676815, 2600.009459, 2755.17563, -167.659835, 871.855056, 44.769698, -512.313065, -819.415595, -538.071099, -189.793622, -402.922932, 179.516345, -9.814756],
749
+ [75004.344875, 624.033993, 1251.136893, -1102.212834, -2660.66498, 699.291817, 153.16722, -950.865637, 499.754645, -145.18821, 558.116553, -23.923029, -165.405086, 9.344131],
750
+ [81491.287984, 787.163481, 1251.296102, -1257.950837, -2966.79973, 639.744522, 131.600209, -445.040117, 584.522874, -89.756563, 524.42963, -13.549067, -210.157124, -44.919798],
751
+ [1558.515853, 7774.939698, -2219.534038, -2523.969396, 247.850422, -846.485643, -1393.124055, 368.526116, 749.045012, 444.704518, 235.934465, 374.049623, -171.33018, -22.899655],
752
+ ];
753
+
754
+ /** General precession in longitude and obliquity (Vondrak 2011) */
755
+ export function swiLdpPeps(tjd: number): { dpre: number; deps: number } {
756
+ const NPOL = 4, NPER = 10;
757
+ const t = (tjd - J2000) / 36525.0;
758
+ let p = 0, q = 0;
759
+ // periodic terms
760
+ for (let i = 0; i < NPER; i++) {
761
+ const w = D2PI * t;
762
+ const a = w / peper[0][i];
763
+ const s = Math.sin(a);
764
+ const c = Math.cos(a);
765
+ p += c * peper[1][i] + s * peper[3][i];
766
+ q += c * peper[2][i] + s * peper[4][i];
767
+ }
768
+ // polynomial terms
769
+ let w = 1;
770
+ for (let i = 0; i < NPOL; i++) {
771
+ p += pepol[i][0] * w;
772
+ q += pepol[i][1] * w;
773
+ w *= t;
774
+ }
775
+ return { dpre: p * AS2R, deps: q * AS2R };
776
+ }
777
+
778
+ /** Precession of the ecliptic (Vondrak 2011) */
779
+ function prePecl(tjd: number, vec: number[]): void {
780
+ const NPOL = 4, NPER = 8;
781
+ const t = (tjd - J2000) / 36525.0;
782
+ let p = 0, q = 0;
783
+ for (let i = 0; i < NPER; i++) {
784
+ const w = D2PI * t;
785
+ const a = w / pqper[0][i];
786
+ const s = Math.sin(a);
787
+ const c = Math.cos(a);
788
+ p += c * pqper[1][i] + s * pqper[3][i];
789
+ q += c * pqper[2][i] + s * pqper[4][i];
790
+ }
791
+ let w = 1;
792
+ for (let i = 0; i < NPOL; i++) {
793
+ p += pqpol[i][0] * w;
794
+ q += pqpol[i][1] * w;
795
+ w *= t;
796
+ }
797
+ p *= AS2R;
798
+ q *= AS2R;
799
+ let z = 1 - p * p - q * q;
800
+ z = z < 0 ? 0 : Math.sqrt(z);
801
+ const s = Math.sin(EPS0);
802
+ const c = Math.cos(EPS0);
803
+ vec[0] = p;
804
+ vec[1] = -q * c - z * s;
805
+ vec[2] = -q * s + z * c;
806
+ }
807
+
808
+ /** Precession of the equator (Vondrak 2011) */
809
+ function prePequ(tjd: number, veq: number[]): void {
810
+ const NPOL = 4, NPER = 14;
811
+ const t = (tjd - J2000) / 36525.0;
812
+ let x = 0, y = 0;
813
+ for (let i = 0; i < NPER; i++) {
814
+ const w = D2PI * t;
815
+ const a = w / xyper[0][i];
816
+ const s = Math.sin(a);
817
+ const c = Math.cos(a);
818
+ x += c * xyper[1][i] + s * xyper[3][i];
819
+ y += c * xyper[2][i] + s * xyper[4][i];
820
+ }
821
+ let w = 1;
822
+ for (let i = 0; i < NPOL; i++) {
823
+ x += xypol[i][0] * w;
824
+ y += xypol[i][1] * w;
825
+ w *= t;
826
+ }
827
+ x *= AS2R;
828
+ y *= AS2R;
829
+ veq[0] = x;
830
+ veq[1] = y;
831
+ const ww = x * x + y * y;
832
+ veq[2] = ww < 1 ? Math.sqrt(1 - ww) : 0;
833
+ }
834
+
835
+ /** Precession matrix from Vondrak 2011 */
836
+ function prePmat(tjd: number, rp: number[]): void {
837
+ const peqr = [0, 0, 0], pecl = [0, 0, 0];
838
+ const v = new Float64Array(3);
839
+ prePequ(tjd, peqr);
840
+ prePecl(tjd, pecl);
841
+ // equinox = cross(peqr, pecl)
842
+ swiCrossProd(peqr, pecl, v);
843
+ const w = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
844
+ const eqx = [v[0] / w, v[1] / w, v[2] / w];
845
+ // v2 = cross(peqr, eqx)
846
+ swiCrossProd(peqr, eqx, v);
847
+ rp[0] = eqx[0]; rp[1] = eqx[1]; rp[2] = eqx[2];
848
+ rp[3] = v[0]; rp[4] = v[1]; rp[5] = v[2];
849
+ rp[6] = peqr[0]; rp[7] = peqr[1]; rp[8] = peqr[2];
850
+ }
851
+
852
+ /* ================================================================
853
+ * 12. Owen 1990 precession
854
+ * ================================================================ */
855
+
856
+ const owenEps0Coef: readonly number[][] = [
857
+ [23.699391439256386, 5.2330816033981775e-1, -5.6259493384864815e-2, -8.2033318431602032e-3, 6.6774163554156385e-4, 2.4931584012812606e-5, -3.1313623302407878e-6, 2.0343814827951515e-7, 2.9182026615852936e-8, -4.1118760893281951e-9],
858
+ [24.124759551704588, -1.2094875596566286e-1, -8.3914869653015218e-2, 3.5357075322387405e-3, 6.4557467824807032e-4, -2.5092064378707704e-5, -1.7631607274450848e-6, 1.3363622791424094e-7, 1.5577817511054047e-8, -2.4613907093017122e-9],
859
+ [23.439103144206208, -4.9386077073143590e-1, -2.3965445283267805e-4, 8.6637485629656489e-3, -5.2828151901367600e-5, -4.3951004595359217e-5, -1.1058785949914705e-6, 6.2431490022621172e-8, 3.4725376218710764e-8, 1.3658853127005757e-9],
860
+ [22.724671295125046, -1.6041813558650337e-1, 7.0646783888132504e-2, 1.4967806745062837e-3, -6.6857270989190734e-4, 5.7578378071604775e-6, 3.3738508454638728e-6, -2.2917813537654764e-7, -2.1019907929218137e-8, 4.3139832091694682e-9],
861
+ [22.914636050333696, 3.2123508304962416e-1, 3.6633220173792710e-2, -5.9228324767696043e-3, -1.882379107379328e-4, 3.2274552870236244e-5, 4.9052463646336507e-7, -5.9064298731578425e-8, -2.0485712675098837e-8, -6.2163304813908160e-10],
862
+ ];
863
+
864
+ const owenPsiaCoef: readonly number[][] = [
865
+ [-218.57864954903122, 51.752257487741612, 1.3304715765661958e-1, 9.2048123521890745e-2, -6.0877528127241278e-3, -7.0013893644531700e-5, -4.9217728385458495e-5, -1.8578234189053723e-6, 7.4396426162029877e-7, -5.9157528981843864e-9],
866
+ [-111.94350527506128, 55.175558131675861, 4.7366115762797613e-1, -4.7701750975398538e-2, -9.2445765329325809e-3, 7.0962838707454917e-4, 1.5140455277814658e-4, -7.7813159018954928e-7, -2.4729402281953378e-6, -1.0898887008726418e-7],
867
+ [-2.041452011529441e-1, 55.969995858494106, -1.9295093699770936e-1, -5.6819574830421158e-3, 1.1073687302518981e-2, -9.0868489896815619e-5, -1.1999773777895820e-4, 9.9748697306154409e-6, 5.7911493603430550e-7, -2.3647526839778175e-7],
868
+ [111.61366860604471, 56.404525305162447, 4.4403302410703782e-1, 7.1490030578883907e-2, -4.9184559079790816e-3, -1.3912698949042046e-3, -6.8490613661884005e-5, 1.2394328562905297e-6, 1.7719847841480384e-6, 2.4889095220628068e-7],
869
+ [228.40683531269390, 60.056143904919826, 2.9583200718478960e-2, -1.5710838319490748e-1, -7.0017356811600801e-3, 3.3009615142224537e-3, 2.0318123852537664e-4, -6.5840216067828310e-5, -5.9077673352976155e-6, 1.3983942185303064e-6],
870
+ ];
871
+
872
+ const owenOmaCoef: readonly number[][] = [
873
+ [25.541291140949806, 2.377889511272162e-1, -3.7337334723142133e-1, 2.4579295485161534e-2, 4.3840999514263623e-3, -3.1126873333599556e-4, -9.8443045771748915e-6, -7.9403103080496923e-7, 1.0840116743893556e-9, 9.2865105216887919e-9],
874
+ [24.429357654237926, -9.5205745947740161e-1, 8.6738296270534816e-2, 3.0061543426062955e-2, -4.1532480523019988e-3, -3.7920928393860939e-4, 3.5117012399609737e-5, 4.6811877283079217e-6, -8.1836046585546861e-8, -6.1803706664211173e-8],
875
+ [23.450465062489337, -9.7259278279739817e-2, 1.1082286925130981e-2, -3.1469883339372219e-2, -1.0041906996819648e-4, 5.6455168475133958e-4, -8.4403910211030209e-6, -3.8269157371098435e-6, 3.1422585261198437e-7, 9.3481729116773404e-9],
876
+ [22.581778052947806, -8.7069701538602037e-1, -9.8140710050197307e-2, 2.6025931340678079e-2, 4.8165322168786755e-3, -1.906558772193363e-4, -4.6838759635421777e-5, -1.6608525315998471e-6, -3.2347811293516124e-8, 2.8104728109642000e-9],
877
+ [21.518861835737142, 2.0494789509441385e-1, 3.5193604846503161e-1, 1.5305977982348925e-2, -7.5015367726336455e-3, -4.0322553186065610e-4, 1.0655320434844041e-4, 7.1792339586935752e-6, -1.603874697543020e-6, -1.613563462813512e-7],
878
+ ];
879
+
880
+ const owenChiaCoef: readonly number[][] = [
881
+ [8.2378850337329404e-1, -3.7443109739678667, 4.0143936898854026e-1, 8.1822830214590811e-2, -8.5978790792656293e-3, -2.8350488448426132e-5, -4.2474671728156727e-5, -1.6214840884656678e-6, 7.8560442001953050e-7, -1.032016641696707e-8],
882
+ [-2.1726062070318606, 7.8470515033132925e-1, 4.4044931004195718e-1, -8.0671247169971653e-2, -8.9672662444325007e-3, 9.2248978383109719e-4, 1.5143472266372874e-4, -1.6387009056475679e-6, -2.4405558979328144e-6, -1.0148113464009015e-7],
883
+ [-4.8518673570735556e-1, 1.0016737299946743e-1, -4.7074888613099918e-1, -5.8604054305076092e-3, 1.4300208240553435e-2, -6.7127991650300028e-5, -1.3703764889645475e-4, 9.0505213684444634e-6, 6.0368690647808607e-7, -2.2135404747652171e-7],
884
+ [-2.0950740076326087, -9.4447359463206877e-1, 4.0940512860493755e-1, 1.0261699700263508e-1, -5.3133241571955160e-3, -1.6634631550720911e-3, -5.9477519536647907e-5, 2.9651387319208926e-6, 1.6434499452070584e-6, 2.3720647656961084e-7],
885
+ [6.3315163285678715e-1, 3.5241082918420464, 2.1223076605364606e-1, -1.5648122502767368e-1, -9.1964075390801980e-3, 3.3896161239812411e-3, 2.1485178626085787e-4, -6.6261759864793735e-5, -5.9257969712852667e-6, 1.3918759086160525e-6],
886
+ ];
887
+
888
+ function getOwenT0Icof(tjd: number): { t0: number; icof: number } {
889
+ const t0s = [-3392455.5, -470455.5, 2451544.5, 5373544.5, 8295544.5];
890
+ let t0 = t0s[0];
891
+ let j = 0;
892
+ for (let i = 1; i < 5; i++) {
893
+ if (tjd >= (t0s[i - 1] + t0s[i]) / 2) {
894
+ t0 = t0s[i];
895
+ j++;
896
+ }
897
+ }
898
+ return { t0, icof: j };
899
+ }
900
+
901
+ function owenChebyshevBasis(tjd: number, t0: number): { k: number[]; tau: number[] } {
902
+ const tau = new Array<number>(10);
903
+ tau[0] = 0;
904
+ tau[1] = (tjd - t0) / 36525.0 / 40.0;
905
+ for (let i = 2; i <= 9; i++) tau[i] = tau[1] * tau[i - 1];
906
+ const k = new Array<number>(10);
907
+ k[0] = 1;
908
+ k[1] = tau[1];
909
+ k[2] = 2 * tau[2] - 1;
910
+ k[3] = 4 * tau[3] - 3 * tau[1];
911
+ k[4] = 8 * tau[4] - 8 * tau[2] + 1;
912
+ k[5] = 16 * tau[5] - 20 * tau[3] + 5 * tau[1];
913
+ k[6] = 32 * tau[6] - 48 * tau[4] + 18 * tau[2] - 1;
914
+ k[7] = 64 * tau[7] - 112 * tau[5] + 56 * tau[3] - 7 * tau[1];
915
+ k[8] = 128 * tau[8] - 256 * tau[6] + 160 * tau[4] - 32 * tau[2] + 1;
916
+ k[9] = 256 * tau[9] - 576 * tau[7] + 432 * tau[5] - 120 * tau[3] + 9 * tau[1];
917
+ return { k, tau };
918
+ }
919
+
920
+ function owenPreMatrix(tjd: number, rp: number[], iflag: number): void {
921
+ const { t0, icof } = getOwenT0Icof(tjd);
922
+ const { k } = owenChebyshevBasis(tjd, t0);
923
+ let psia = 0, oma = 0, chia = 0;
924
+ for (let i = 0; i < 10; i++) {
925
+ psia += k[i] * owenPsiaCoef[icof][i];
926
+ oma += k[i] * owenOmaCoef[icof][i];
927
+ chia += k[i] * owenChiaCoef[icof][i];
928
+ }
929
+ if (iflag & (SEFLG_JPLHOR | SEFLG_JPLHOR_APPROX)) {
930
+ psia += -0.000018560;
931
+ }
932
+ const eps0 = 84381.448 / 3600.0 * DEGTORAD;
933
+ const psiaR = psia * DEGTORAD;
934
+ const chiaR = chia * DEGTORAD;
935
+ const omaR = oma * DEGTORAD;
936
+ const coseps0 = Math.cos(eps0), sineps0 = Math.sin(eps0);
937
+ const coschia = Math.cos(chiaR), sinchia = Math.sin(chiaR);
938
+ const cospsia = Math.cos(psiaR), sinpsia = Math.sin(psiaR);
939
+ const cosoma = Math.cos(omaR), sinoma = Math.sin(omaR);
940
+ rp[0] = coschia * cospsia + sinchia * cosoma * sinpsia;
941
+ rp[1] = (-coschia * sinpsia + sinchia * cosoma * cospsia) * coseps0 + sinchia * sinoma * sineps0;
942
+ rp[2] = (-coschia * sinpsia + sinchia * cosoma * cospsia) * sineps0 - sinchia * sinoma * coseps0;
943
+ rp[3] = -sinchia * cospsia + coschia * cosoma * sinpsia;
944
+ rp[4] = (sinchia * sinpsia + coschia * cosoma * cospsia) * coseps0 + coschia * sinoma * sineps0;
945
+ rp[5] = (sinchia * sinpsia + coschia * cosoma * cospsia) * sineps0 - coschia * sinoma * coseps0;
946
+ rp[6] = sinoma * sinpsia;
947
+ rp[7] = sinoma * cospsia * coseps0 - cosoma * sineps0;
948
+ rp[8] = sinoma * cospsia * sineps0 + cosoma * coseps0;
949
+ }
950
+
951
+ function epsilnOwen1986(tjd: number): number {
952
+ const { t0, icof } = getOwenT0Icof(tjd);
953
+ const { k } = owenChebyshevBasis(tjd, t0);
954
+ let eps = 0;
955
+ for (let i = 0; i < 10; i++) {
956
+ eps += k[i] * owenEps0Coef[icof][i];
957
+ }
958
+ return eps;
959
+ }
960
+
961
+ /* ================================================================
962
+ * 13. Obliquity of the ecliptic
963
+ * ================================================================ */
964
+
965
+ const OFFSET_EPS_JPLHORIZONS = 35.95;
966
+ const DCOR_EPS_JPL_TJD0 = 2437846.5;
967
+ const NDCOR_EPS_JPL = 51;
968
+
969
+ const dcorEpsJpl = [
970
+ 36.726, 36.627, 36.595, 36.578, 36.640, 36.659, 36.731, 36.765,
971
+ 36.662, 36.555, 36.335, 36.321, 36.354, 36.227, 36.289, 36.348, 36.257, 36.163,
972
+ 35.979, 35.896, 35.842, 35.825, 35.912, 35.950, 36.093, 36.191, 36.009, 35.943,
973
+ 35.875, 35.771, 35.788, 35.753, 35.822, 35.866, 35.771, 35.732, 35.543, 35.498,
974
+ 35.449, 35.409, 35.497, 35.556, 35.672, 35.760, 35.596, 35.565, 35.510, 35.394,
975
+ 35.385, 35.375, 35.415,
976
+ ];
977
+
978
+ export function swiEpsiln(J: number, iflag: number, swed: SweData): number {
979
+ const T = (J - J2000) / 36525.0;
980
+ const precModel = getPrecModel(swed);
981
+ const precModelShort = getPrecModelShort(swed);
982
+ const jplhoraModel = getJplHoraModel(swed);
983
+ let isJplhor = false;
984
+ if (iflag & SEFLG_JPLHOR) isJplhor = true;
985
+ if ((iflag & SEFLG_JPLHOR_APPROX)
986
+ && jplhoraModel === SEMOD_JPLHORA_3
987
+ && J <= HORIZONS_TJD0_DPSI_DEPS_IAU1980)
988
+ isJplhor = true;
989
+
990
+ let eps: number;
991
+ if (isJplhor) {
992
+ if (J > 2378131.5 && J < 2525323.5) {
993
+ eps = (((1.813e-3 * T - 5.9e-4) * T - 46.8150) * T + 84381.448) * DEGTORAD / 3600;
994
+ } else {
995
+ eps = epsilnOwen1986(J) * DEGTORAD;
996
+ }
997
+ } else if ((iflag & SEFLG_JPLHOR_APPROX) && jplhoraModel === SEMOD_JPLHORA_2) {
998
+ eps = (((1.813e-3 * T - 5.9e-4) * T - 46.8150) * T + 84381.448) * DEGTORAD / 3600;
999
+ } else if (precModelShort === SEMOD_PREC_IAU_1976 && Math.abs(T) <= PREC_IAU_1976_CTIES) {
1000
+ eps = (((1.813e-3 * T - 5.9e-4) * T - 46.8150) * T + 84381.448) * DEGTORAD / 3600;
1001
+ } else if (precModel === SEMOD_PREC_IAU_1976) {
1002
+ eps = (((1.813e-3 * T - 5.9e-4) * T - 46.8150) * T + 84381.448) * DEGTORAD / 3600;
1003
+ } else if (precModelShort === SEMOD_PREC_IAU_2000 && Math.abs(T) <= PREC_IAU_2000_CTIES) {
1004
+ eps = (((1.813e-3 * T - 5.9e-4) * T - 46.84024) * T + 84381.406) * DEGTORAD / 3600;
1005
+ } else if (precModel === SEMOD_PREC_IAU_2000) {
1006
+ eps = (((1.813e-3 * T - 5.9e-4) * T - 46.84024) * T + 84381.406) * DEGTORAD / 3600;
1007
+ } else if (precModelShort === SEMOD_PREC_IAU_2006 && Math.abs(T) <= PREC_IAU_2006_CTIES) {
1008
+ eps = (((((-4.34e-8 * T - 5.76e-7) * T + 2.0034e-3) * T - 1.831e-4) * T - 46.836769) * T + 84381.406) * DEGTORAD / 3600.0;
1009
+ } else if (precModel === SEMOD_PREC_NEWCOMB) {
1010
+ const Tn = (J - 2396758.0) / 36525.0;
1011
+ eps = (0.0017 * Tn * Tn * Tn - 0.0085 * Tn * Tn - 46.837 * Tn + 84451.68) * DEGTORAD / 3600.0;
1012
+ } else if (precModel === SEMOD_PREC_IAU_2006) {
1013
+ eps = (((((-4.34e-8 * T - 5.76e-7) * T + 2.0034e-3) * T - 1.831e-4) * T - 46.836769) * T + 84381.406) * DEGTORAD / 3600.0;
1014
+ } else if (precModel === SEMOD_PREC_BRETAGNON_2003) {
1015
+ eps = ((((((- 3e-11 * T - 2.48e-8) * T - 5.23e-7) * T + 1.99911e-3) * T - 1.667e-4) * T - 46.836051) * T + 84381.40880) * DEGTORAD / 3600.0;
1016
+ } else if (precModel === SEMOD_PREC_SIMON_1994) {
1017
+ eps = (((((2.5e-8 * T - 5.1e-7) * T + 1.9989e-3) * T - 1.52e-4) * T - 46.80927) * T + 84381.412) * DEGTORAD / 3600.0;
1018
+ } else if (precModel === SEMOD_PREC_WILLIAMS_1994) {
1019
+ eps = ((((-1.0e-6 * T + 2.0e-3) * T - 1.74e-4) * T - 46.833960) * T + 84381.409) * DEGTORAD / 3600.0;
1020
+ } else if (precModel === SEMOD_PREC_LASKAR_1986 || precModel === SEMOD_PREC_WILL_EPS_LASK) {
1021
+ let T10 = T / 10.0;
1022
+ eps = ((((((((( 2.45e-10 * T10 + 5.79e-9) * T10 + 2.787e-7) * T10
1023
+ + 7.12e-7) * T10 - 3.905e-5) * T10 - 2.4967e-3) * T10
1024
+ - 5.138e-3) * T10 + 1.99925) * T10 - 0.0155) * T10 - 468.093) * T10
1025
+ + 84381.448;
1026
+ eps *= DEGTORAD / 3600.0;
1027
+ } else if (precModel === SEMOD_PREC_OWEN_1990) {
1028
+ eps = epsilnOwen1986(J) * DEGTORAD;
1029
+ } else {
1030
+ // SEMOD_PREC_VONDRAK_2011
1031
+ const { deps } = swiLdpPeps(J);
1032
+ eps = deps;
1033
+ if ((iflag & SEFLG_JPLHOR_APPROX) && jplhoraModel !== SEMOD_JPLHORA_2) {
1034
+ let tofs = (J - DCOR_EPS_JPL_TJD0) / 365.25;
1035
+ let dofs = OFFSET_EPS_JPLHORIZONS;
1036
+ if (tofs < 0) {
1037
+ tofs = 0;
1038
+ dofs = dcorEpsJpl[0];
1039
+ } else if (tofs >= NDCOR_EPS_JPL - 1) {
1040
+ tofs = NDCOR_EPS_JPL;
1041
+ dofs = dcorEpsJpl[NDCOR_EPS_JPL - 1];
1042
+ } else {
1043
+ const t0 = Math.trunc(tofs);
1044
+ dofs = (tofs - t0) * (dcorEpsJpl[t0] - dcorEpsJpl[t0 + 1]) + dcorEpsJpl[t0];
1045
+ }
1046
+ dofs /= (1000.0 * 3600.0);
1047
+ eps += dofs * DEGTORAD;
1048
+ }
1049
+ }
1050
+ return eps;
1051
+ }
1052
+
1053
+ /* ================================================================
1054
+ * 14. Precession methods 1, 2, 3 and swi_precess dispatcher
1055
+ * ================================================================ */
1056
+
1057
+ function precess1(R: Float64Array | number[], J: number, direction: number, precMethod: number): number {
1058
+ if (J === J2000) return 0;
1059
+ const T = (J - J2000) / 36525.0;
1060
+ let Z = 0, z = 0, TH = 0;
1061
+ if (precMethod === SEMOD_PREC_IAU_1976) {
1062
+ Z = ((0.017998 * T + 0.30188) * T + 2306.2181) * T * DEGTORAD / 3600;
1063
+ z = ((0.018203 * T + 1.09468) * T + 2306.2181) * T * DEGTORAD / 3600;
1064
+ TH = ((-0.041833 * T - 0.42665) * T + 2004.3109) * T * DEGTORAD / 3600;
1065
+ } else if (precMethod === SEMOD_PREC_IAU_2000) {
1066
+ Z = (((((-0.0000002 * T - 0.0000327) * T + 0.0179663) * T + 0.3019015) * T + 2306.0809506) * T + 2.5976176) * DEGTORAD / 3600;
1067
+ z = (((((-0.0000003 * T - 0.000047) * T + 0.0182237) * T + 1.0947790) * T + 2306.0803226) * T - 2.5976176) * DEGTORAD / 3600;
1068
+ TH = ((((-0.0000001 * T - 0.0000601) * T - 0.0418251) * T - 0.4269353) * T + 2004.1917476) * T * DEGTORAD / 3600;
1069
+ } else if (precMethod === SEMOD_PREC_IAU_2006) {
1070
+ Z = (((((-0.0000003173 * T - 0.000005971) * T + 0.01801828) * T + 0.2988499) * T + 2306.083227) * T + 2.650545) * DEGTORAD / 3600;
1071
+ z = (((((-0.0000002904 * T - 0.000028596) * T + 0.01826837) * T + 1.0927348) * T + 2306.077181) * T - 2.650545) * DEGTORAD / 3600;
1072
+ TH = ((((-0.00000011274 * T - 0.000007089) * T - 0.04182264) * T - 0.4294934) * T + 2004.191903) * T * DEGTORAD / 3600;
1073
+ } else if (precMethod === SEMOD_PREC_BRETAGNON_2003) {
1074
+ Z = ((((((-0.00000000013 * T - 0.0000003040) * T - 0.000005708) * T + 0.01801752) * T + 0.3023262) * T + 2306.080472) * T + 2.72767) * DEGTORAD / 3600;
1075
+ z = ((((((-0.00000000005 * T - 0.0000002486) * T - 0.000028276) * T + 0.01826676) * T + 1.0956768) * T + 2306.076070) * T - 2.72767) * DEGTORAD / 3600;
1076
+ TH = ((((((0.000000000009 * T + 0.00000000036) * T - 0.0000001127) * T - 0.000007291) * T - 0.04182364) * T - 0.4266980) * T + 2004.190936) * T * DEGTORAD / 3600;
1077
+ } else if (precMethod === SEMOD_PREC_NEWCOMB) {
1078
+ const mills = 365242.198782;
1079
+ const t1 = (J2000 - B1850) / mills;
1080
+ const t2 = (J - B1850) / mills;
1081
+ const Tn = t2 - t1;
1082
+ const T2 = Tn * Tn, T3 = T2 * Tn;
1083
+ const Z1 = 23035.5548 + 139.720 * t1 + 0.069 * t1 * t1;
1084
+ Z = (Z1 * Tn + (30.242 - 0.269 * t1) * T2 + 17.996 * T3) * DEGTORAD / 3600.0;
1085
+ z = (Z1 * Tn + (109.478 - 0.387 * t1) * T2 + 18.324 * T3) * DEGTORAD / 3600.0;
1086
+ TH = ((20051.125 - 85.294 * t1 - 0.365 * t1 * t1) * Tn + (-42.647 - 0.365 * t1) * T2 - 41.802 * T3) * DEGTORAD / 3600.0;
1087
+ } else {
1088
+ return 0;
1089
+ }
1090
+ const sinth = Math.sin(TH), costh = Math.cos(TH);
1091
+ const sinZ = Math.sin(Z), cosZ = Math.cos(Z);
1092
+ const sinz = Math.sin(z), cosz = Math.cos(z);
1093
+ const A = cosZ * costh;
1094
+ const B = sinZ * costh;
1095
+ const x = [0, 0, 0];
1096
+ if (direction < 0) {
1097
+ // From J2000.0 to J
1098
+ x[0] = (A * cosz - sinZ * sinz) * R[0] - (B * cosz + cosZ * sinz) * R[1] - sinth * cosz * R[2];
1099
+ x[1] = (A * sinz + sinZ * cosz) * R[0] - (B * sinz - cosZ * cosz) * R[1] - sinth * sinz * R[2];
1100
+ x[2] = cosZ * sinth * R[0] - sinZ * sinth * R[1] + costh * R[2];
1101
+ } else {
1102
+ // From J to J2000.0
1103
+ x[0] = (A * cosz - sinZ * sinz) * R[0] + (A * sinz + sinZ * cosz) * R[1] + cosZ * sinth * R[2];
1104
+ x[1] = -(B * cosz + cosZ * sinz) * R[0] - (B * sinz - cosZ * cosz) * R[1] - sinZ * sinth * R[2];
1105
+ x[2] = -sinth * cosz * R[0] - sinth * sinz * R[1] + costh * R[2];
1106
+ }
1107
+ R[0] = x[0]; R[1] = x[1]; R[2] = x[2];
1108
+ return 0;
1109
+ }
1110
+
1111
+ /* Laskar/Simon/Williams precession coefficient tables */
1112
+ const pAcofWilliams = [-8.66e-10, -4.759e-8, 2.424e-7, 1.3095e-5, 1.7451e-4, -1.8055e-3, -0.235316, 0.076, 110.5407, 50287.70000];
1113
+ const nodecofWilliams = [6.6402e-16, -2.69151e-15, -1.547021e-12, 7.521313e-12, 1.9e-10, -3.54e-9, -1.8103e-7, 1.26e-7, 7.436169e-5, -0.04207794833, 3.052115282424];
1114
+ const inclcofWilliams = [1.2147e-16, 7.3759e-17, -8.26287e-14, 2.503410e-13, 2.4650839e-11, -5.4000441e-11, 1.32115526e-9, -6.012e-7, -1.62442e-5, 0.00227850649, 0.0];
1115
+
1116
+ const pAcofSimon = [-8.66e-10, -4.759e-8, 2.424e-7, 1.3095e-5, 1.7451e-4, -1.8055e-3, -0.235316, 0.07732, 111.2022, 50288.200];
1117
+ const nodecofSimon = [6.6402e-16, -2.69151e-15, -1.547021e-12, 7.521313e-12, 1.9e-10, -3.54e-9, -1.8103e-7, 2.579e-8, 7.4379679e-5, -0.0420782900, 3.0521126906];
1118
+ const inclcofSimon = [1.2147e-16, 7.3759e-17, -8.26287e-14, 2.503410e-13, 2.4650839e-11, -5.4000441e-11, 1.32115526e-9, -5.99908e-7, -1.624383e-5, 0.002278492868, 0.0];
1119
+
1120
+ const pAcofLaskar = [-8.66e-10, -4.759e-8, 2.424e-7, 1.3095e-5, 1.7451e-4, -1.8055e-3, -0.235316, 0.07732, 111.1971, 50290.966];
1121
+ const nodecofLaskar = [6.6402e-16, -2.69151e-15, -1.547021e-12, 7.521313e-12, 6.3190131e-10, -3.48388152e-9, -1.813065896e-7, 2.75036225e-8, 7.4394531426e-5, -0.042078604317, 3.052112654975];
1122
+ const inclcofLaskar = [1.2147e-16, 7.3759e-17, -8.26287e-14, 2.503410e-13, 2.4650839e-11, -5.4000441e-11, 1.32115526e-9, -5.998737027e-7, -1.6242797091e-5, 0.002278495537, 0.0];
1123
+
1124
+ function precess2(R: Float64Array | number[], J: number, iflag: number, direction: number, precMethod: number, swed: SweData): number {
1125
+ if (J === J2000) return 0;
1126
+ let pAcof: number[], nodecof: number[], inclcof: number[];
1127
+ if (precMethod === SEMOD_PREC_SIMON_1994) {
1128
+ pAcof = pAcofSimon as unknown as number[];
1129
+ nodecof = nodecofSimon as unknown as number[];
1130
+ inclcof = inclcofSimon as unknown as number[];
1131
+ } else if (precMethod === SEMOD_PREC_WILLIAMS_1994) {
1132
+ pAcof = pAcofWilliams as unknown as number[];
1133
+ nodecof = nodecofWilliams as unknown as number[];
1134
+ inclcof = inclcofWilliams as unknown as number[];
1135
+ } else {
1136
+ pAcof = pAcofLaskar as unknown as number[];
1137
+ nodecof = nodecofLaskar as unknown as number[];
1138
+ inclcof = inclcofLaskar as unknown as number[];
1139
+ }
1140
+ let T = (J - J2000) / 36525.0;
1141
+ // rotate from equator to ecliptic
1142
+ let eps: number;
1143
+ if (direction === 1) eps = swiEpsiln(J, iflag, swed);
1144
+ else eps = swiEpsiln(J2000, iflag, swed);
1145
+ let sineps = Math.sin(eps), coseps = Math.cos(eps);
1146
+ const x = [R[0], coseps * R[1] + sineps * R[2], -sineps * R[1] + coseps * R[2]];
1147
+
1148
+ T /= 10.0; // thousands of years
1149
+ let pA = pAcof[0];
1150
+ for (let i = 1; i <= 9; i++) pA = pA * T + pAcof[i];
1151
+ pA *= DEGTORAD / 3600 * T;
1152
+
1153
+ let W = nodecof[0];
1154
+ for (let i = 1; i <= 10; i++) W = W * T + nodecof[i];
1155
+
1156
+ // rotate to node
1157
+ let zz = direction === 1 ? W + pA : W;
1158
+ let B = Math.cos(zz), A = Math.sin(zz);
1159
+ let tmp = B * x[0] + A * x[1];
1160
+ x[1] = -A * x[0] + B * x[1];
1161
+ x[0] = tmp;
1162
+
1163
+ // rotate by inclination
1164
+ let incl = inclcof[0];
1165
+ for (let i = 1; i <= 10; i++) incl = incl * T + inclcof[i];
1166
+ if (direction === 1) incl = -incl;
1167
+ B = Math.cos(incl); A = Math.sin(incl);
1168
+ tmp = B * x[1] + A * x[2];
1169
+ x[2] = -A * x[1] + B * x[2];
1170
+ x[1] = tmp;
1171
+
1172
+ // rotate back from node
1173
+ zz = direction === 1 ? -W : -W - pA;
1174
+ B = Math.cos(zz); A = Math.sin(zz);
1175
+ tmp = B * x[0] + A * x[1];
1176
+ x[1] = -A * x[0] + B * x[1];
1177
+ x[0] = tmp;
1178
+
1179
+ // rotate to final equator
1180
+ if (direction === 1) eps = swiEpsiln(J2000, iflag, swed);
1181
+ else eps = swiEpsiln(J, iflag, swed);
1182
+ sineps = Math.sin(eps); coseps = Math.cos(eps);
1183
+ tmp = coseps * x[1] - sineps * x[2];
1184
+ x[2] = sineps * x[1] + coseps * x[2];
1185
+ x[1] = tmp;
1186
+ R[0] = x[0]; R[1] = x[1]; R[2] = x[2];
1187
+ return 0;
1188
+ }
1189
+
1190
+ function precess3(R: Float64Array | number[], J: number, direction: number, iflag: number, precMeth: number): number {
1191
+ if (J === J2000) return 0;
1192
+ const pmat = [0, 0, 0, 0, 0, 0, 0, 0, 0];
1193
+ if (precMeth === SEMOD_PREC_OWEN_1990) {
1194
+ owenPreMatrix(J, pmat, iflag);
1195
+ } else {
1196
+ prePmat(J, pmat);
1197
+ }
1198
+ const x = [0, 0, 0];
1199
+ if (direction === -1) {
1200
+ for (let i = 0; i <= 2; i++) {
1201
+ const j = i * 3;
1202
+ x[i] = R[0] * pmat[j] + R[1] * pmat[j + 1] + R[2] * pmat[j + 2];
1203
+ }
1204
+ } else {
1205
+ for (let i = 0; i <= 2; i++) {
1206
+ x[i] = R[0] * pmat[i] + R[1] * pmat[i + 3] + R[2] * pmat[i + 6];
1207
+ }
1208
+ }
1209
+ R[0] = x[0]; R[1] = x[1]; R[2] = x[2];
1210
+ return 0;
1211
+ }
1212
+
1213
+ /** Precess equatorial coordinates between J and J2000 */
1214
+ export function swiPrecess(R: Float64Array | number[], J: number, iflag: number, direction: number, swed: SweData): number {
1215
+ const T = (J - J2000) / 36525.0;
1216
+ const precModel = getPrecModel(swed);
1217
+ const precModelShort = getPrecModelShort(swed);
1218
+ const jplhoraModel = getJplHoraModel(swed);
1219
+ let isJplhor = false;
1220
+ if (iflag & SEFLG_JPLHOR) isJplhor = true;
1221
+ if ((iflag & SEFLG_JPLHOR_APPROX)
1222
+ && jplhoraModel === SEMOD_JPLHORA_3
1223
+ && J <= HORIZONS_TJD0_DPSI_DEPS_IAU1980) isJplhor = true;
1224
+
1225
+ if (isJplhor) {
1226
+ if (J > 2378131.5 && J < 2525323.5) {
1227
+ return precess1(R, J, direction, SEMOD_PREC_IAU_1976);
1228
+ } else {
1229
+ return precess3(R, J, direction, iflag, SEMOD_PREC_OWEN_1990);
1230
+ }
1231
+ } else if (precModelShort === SEMOD_PREC_IAU_1976 && Math.abs(T) <= PREC_IAU_1976_CTIES) {
1232
+ return precess1(R, J, direction, SEMOD_PREC_IAU_1976);
1233
+ } else if (precModel === SEMOD_PREC_IAU_1976) {
1234
+ return precess1(R, J, direction, SEMOD_PREC_IAU_1976);
1235
+ } else if (precModelShort === SEMOD_PREC_IAU_2000 && Math.abs(T) <= PREC_IAU_2000_CTIES) {
1236
+ return precess1(R, J, direction, SEMOD_PREC_IAU_2000);
1237
+ } else if (precModel === SEMOD_PREC_IAU_2000) {
1238
+ return precess1(R, J, direction, SEMOD_PREC_IAU_2000);
1239
+ } else if (precModelShort === SEMOD_PREC_IAU_2006 && Math.abs(T) <= PREC_IAU_2006_CTIES) {
1240
+ return precess1(R, J, direction, SEMOD_PREC_IAU_2006);
1241
+ } else if (precModel === SEMOD_PREC_IAU_2006) {
1242
+ return precess1(R, J, direction, SEMOD_PREC_IAU_2006);
1243
+ } else if (precModel === SEMOD_PREC_BRETAGNON_2003) {
1244
+ return precess1(R, J, direction, SEMOD_PREC_BRETAGNON_2003);
1245
+ } else if (precModel === SEMOD_PREC_NEWCOMB) {
1246
+ return precess1(R, J, direction, SEMOD_PREC_NEWCOMB);
1247
+ } else if (precModel === SEMOD_PREC_LASKAR_1986) {
1248
+ return precess2(R, J, iflag, direction, SEMOD_PREC_LASKAR_1986, swed);
1249
+ } else if (precModel === SEMOD_PREC_SIMON_1994) {
1250
+ return precess2(R, J, iflag, direction, SEMOD_PREC_SIMON_1994, swed);
1251
+ } else if (precModel === SEMOD_PREC_WILLIAMS_1994 || precModel === SEMOD_PREC_WILL_EPS_LASK) {
1252
+ return precess2(R, J, iflag, direction, SEMOD_PREC_WILLIAMS_1994, swed);
1253
+ } else if (precModel === SEMOD_PREC_OWEN_1990) {
1254
+ return precess3(R, J, direction, iflag, SEMOD_PREC_OWEN_1990);
1255
+ } else {
1256
+ // SEMOD_PREC_VONDRAK_2011
1257
+ return precess3(R, J, direction, iflag, SEMOD_PREC_VONDRAK_2011);
1258
+ }
1259
+ }
1260
+
1261
+ /* ================================================================
1262
+ * 15. Nutation — IAU 1980
1263
+ * ================================================================ */
1264
+
1265
+ // prettier-ignore
1266
+ const nt = [
1267
+ /* MM,MS,FF,DD,OM, LS, LS2,OC, OC2 */
1268
+ 0, 0, 0, 0, 2, 2062, 2, -895, 5,
1269
+ -2, 0, 2, 0, 1, 46, 0, -24, 0,
1270
+ 2, 0,-2, 0, 0, 11, 0, 0, 0,
1271
+ -2, 0, 2, 0, 2, -3, 0, 1, 0,
1272
+ 1,-1, 0,-1, 0, -3, 0, 0, 0,
1273
+ 0,-2, 2,-2, 1, -2, 0, 1, 0,
1274
+ 2, 0,-2, 0, 1, 1, 0, 0, 0,
1275
+ 0, 0, 2,-2, 2,-13187,-16, 5736,-31,
1276
+ 0, 1, 0, 0, 0, 1426,-34, 54, -1,
1277
+ 0, 1, 2,-2, 2, -517, 12, 224, -6,
1278
+ 0,-1, 2,-2, 2, 217, -5, -95, 3,
1279
+ 0, 0, 2,-2, 1, 129, 1, -70, 0,
1280
+ 2, 0, 0,-2, 0, 48, 0, 1, 0,
1281
+ 0, 0, 2,-2, 0, -22, 0, 0, 0,
1282
+ 0, 2, 0, 0, 0, 17, -1, 0, 0,
1283
+ 0, 1, 0, 0, 1, -15, 0, 9, 0,
1284
+ 0, 2, 2,-2, 2, -16, 1, 7, 0,
1285
+ 0,-1, 0, 0, 1, -12, 0, 6, 0,
1286
+ -2, 0, 0, 2, 1, -6, 0, 3, 0,
1287
+ 0,-1, 2,-2, 1, -5, 0, 3, 0,
1288
+ 2, 0, 0,-2, 1, 4, 0, -2, 0,
1289
+ 0, 1, 2,-2, 1, 4, 0, -2, 0,
1290
+ 1, 0, 0,-1, 0, -4, 0, 0, 0,
1291
+ 2, 1, 0,-2, 0, 1, 0, 0, 0,
1292
+ 0, 0,-2, 2, 1, 1, 0, 0, 0,
1293
+ 0, 1,-2, 2, 0, -1, 0, 0, 0,
1294
+ 0, 1, 0, 0, 2, 1, 0, 0, 0,
1295
+ -1, 0, 0, 1, 1, 1, 0, 0, 0,
1296
+ 0, 1, 2,-2, 0, -1, 0, 0, 0,
1297
+ 0, 0, 2, 0, 2, -2274, -2, 977, -5,
1298
+ 1, 0, 0, 0, 0, 712, 1, -7, 0,
1299
+ 0, 0, 2, 0, 1, -386, -4, 200, 0,
1300
+ 1, 0, 2, 0, 2, -301, 0, 129, -1,
1301
+ 1, 0, 0,-2, 0, -158, 0, -1, 0,
1302
+ -1, 0, 2, 0, 2, 123, 0, -53, 0,
1303
+ 0, 0, 0, 2, 0, 63, 0, -2, 0,
1304
+ 1, 0, 0, 0, 1, 63, 1, -33, 0,
1305
+ -1, 0, 0, 0, 1, -58, -1, 32, 0,
1306
+ -1, 0, 2, 2, 2, -59, 0, 26, 0,
1307
+ 1, 0, 2, 0, 1, -51, 0, 27, 0,
1308
+ 0, 0, 2, 2, 2, -38, 0, 16, 0,
1309
+ 2, 0, 0, 0, 0, 29, 0, -1, 0,
1310
+ 1, 0, 2,-2, 2, 29, 0, -12, 0,
1311
+ 2, 0, 2, 0, 2, -31, 0, 13, 0,
1312
+ 0, 0, 2, 0, 0, 26, 0, -1, 0,
1313
+ -1, 0, 2, 0, 1, 21, 0, -10, 0,
1314
+ -1, 0, 0, 2, 1, 16, 0, -8, 0,
1315
+ 1, 0, 0,-2, 1, -13, 0, 7, 0,
1316
+ -1, 0, 2, 2, 1, -10, 0, 5, 0,
1317
+ 1, 1, 0,-2, 0, -7, 0, 0, 0,
1318
+ 0, 1, 2, 0, 2, 7, 0, -3, 0,
1319
+ 0,-1, 2, 0, 2, -7, 0, 3, 0,
1320
+ 1, 0, 2, 2, 2, -8, 0, 3, 0,
1321
+ 1, 0, 0, 2, 0, 6, 0, 0, 0,
1322
+ 2, 0, 2,-2, 2, 6, 0, -3, 0,
1323
+ 0, 0, 0, 2, 1, -6, 0, 3, 0,
1324
+ 0, 0, 2, 2, 1, -7, 0, 3, 0,
1325
+ 1, 0, 2,-2, 1, 6, 0, -3, 0,
1326
+ 0, 0, 0,-2, 1, -5, 0, 3, 0,
1327
+ 1,-1, 0, 0, 0, 5, 0, 0, 0,
1328
+ 2, 0, 2, 0, 1, -5, 0, 3, 0,
1329
+ 0, 1, 0,-2, 0, -4, 0, 0, 0,
1330
+ 1, 0,-2, 0, 0, 4, 0, 0, 0,
1331
+ 0, 0, 0, 1, 0, -4, 0, 0, 0,
1332
+ 1, 1, 0, 0, 0, -3, 0, 0, 0,
1333
+ 1, 0, 2, 0, 0, 3, 0, 0, 0,
1334
+ 1,-1, 2, 0, 2, -3, 0, 1, 0,
1335
+ -1,-1, 2, 2, 2, -3, 0, 1, 0,
1336
+ -2, 0, 0, 0, 1, -2, 0, 1, 0,
1337
+ 3, 0, 2, 0, 2, -3, 0, 1, 0,
1338
+ 0,-1, 2, 2, 2, -3, 0, 1, 0,
1339
+ 1, 1, 2, 0, 2, 2, 0, -1, 0,
1340
+ -1, 0, 2,-2, 1, -2, 0, 1, 0,
1341
+ 2, 0, 0, 0, 1, 2, 0, -1, 0,
1342
+ 1, 0, 0, 0, 2, -2, 0, 1, 0,
1343
+ 3, 0, 0, 0, 0, 2, 0, 0, 0,
1344
+ 0, 0, 2, 1, 2, 2, 0, -1, 0,
1345
+ -1, 0, 0, 0, 2, 1, 0, -1, 0,
1346
+ 1, 0, 0,-4, 0, -1, 0, 0, 0,
1347
+ -2, 0, 2, 2, 2, 1, 0, -1, 0,
1348
+ -1, 0, 2, 4, 2, -2, 0, 1, 0,
1349
+ 2, 0, 0,-4, 0, -1, 0, 0, 0,
1350
+ 1, 1, 2,-2, 2, 1, 0, -1, 0,
1351
+ 1, 0, 2, 2, 1, -1, 0, 1, 0,
1352
+ -2, 0, 2, 4, 2, -1, 0, 1, 0,
1353
+ -1, 0, 4, 0, 2, 1, 0, 0, 0,
1354
+ 1,-1, 0,-2, 0, 1, 0, 0, 0,
1355
+ 2, 0, 2,-2, 1, 1, 0, -1, 0,
1356
+ 2, 0, 2, 2, 2, -1, 0, 0, 0,
1357
+ 1, 0, 0, 2, 1, -1, 0, 0, 0,
1358
+ 0, 0, 4,-2, 2, 1, 0, 0, 0,
1359
+ 3, 0, 2,-2, 2, 1, 0, 0, 0,
1360
+ 1, 0, 2,-2, 0, -1, 0, 0, 0,
1361
+ 0, 1, 2, 0, 1, 1, 0, 0, 0,
1362
+ -1,-1, 0, 2, 1, 1, 0, 0, 0,
1363
+ 0, 0,-2, 0, 1, -1, 0, 0, 0,
1364
+ 0, 0, 2,-1, 2, -1, 0, 0, 0,
1365
+ 0, 1, 0, 2, 0, -1, 0, 0, 0,
1366
+ 1, 0,-2,-2, 0, -1, 0, 0, 0,
1367
+ 0,-1, 2, 0, 1, -1, 0, 0, 0,
1368
+ 1, 1, 0,-2, 1, -1, 0, 0, 0,
1369
+ 1, 0,-2, 2, 0, -1, 0, 0, 0,
1370
+ 2, 0, 0, 2, 0, 1, 0, 0, 0,
1371
+ 0, 0, 2, 4, 2, -1, 0, 0, 0,
1372
+ 0, 1, 0, 1, 0, 1, 0, 0, 0,
1373
+ // corrections to IAU 1980 nutation series by Herring 1987 (in 0.00001")
1374
+ 101, 0, 0, 0, 1,-725, 0, 213, 0,
1375
+ 101, 1, 0, 0, 0, 523, 0, 208, 0,
1376
+ 101, 0, 2,-2, 2, 102, 0, -41, 0,
1377
+ 101, 0, 2, 0, 2, -81, 0, 32, 0,
1378
+ // cos for nutl and sin for nuto
1379
+ 102, 0, 0, 0, 1, 417, 0, 224, 0,
1380
+ 102, 1, 0, 0, 0, 61, 0, -24, 0,
1381
+ 102, 0, 2,-2, 2,-118, 0, -47, 0,
1382
+ ENDMARK,
1383
+ ];
1384
+
1385
+ function calcNutationIau1980(J: number, nutlo: number[], swed: SweData): number {
1386
+ const nutModel = getNutModel(swed);
1387
+ const T = (J - J2000) / 36525.0;
1388
+ const T2 = T * T;
1389
+ // Fundamental arguments
1390
+ let OM = -6962890.539 * T + 450160.280 + (0.008 * T + 7.455) * T2;
1391
+ OM = sweDegnorm(OM / 3600) * DEGTORAD;
1392
+ let MS = 129596581.224 * T + 1287099.804 - (0.012 * T + 0.577) * T2;
1393
+ MS = sweDegnorm(MS / 3600) * DEGTORAD;
1394
+ let MM = 1717915922.633 * T + 485866.733 + (0.064 * T + 31.310) * T2;
1395
+ MM = sweDegnorm(MM / 3600) * DEGTORAD;
1396
+ let FF = 1739527263.137 * T + 335778.877 + (0.011 * T - 13.257) * T2;
1397
+ FF = sweDegnorm(FF / 3600) * DEGTORAD;
1398
+ let DD = 1602961601.328 * T + 1072261.307 + (0.019 * T - 6.891) * T2;
1399
+ DD = sweDegnorm(DD / 3600) * DEGTORAD;
1400
+ const args = [MM, MS, FF, DD, OM];
1401
+ const ns = [3, 2, 4, 4, 2];
1402
+ // Precompute sin/cos of multiple angles
1403
+ const ss: number[][] = [[], [], [], [], []];
1404
+ const cc: number[][] = [[], [], [], [], []];
1405
+ for (let k = 0; k <= 4; k++) {
1406
+ const arg = args[k];
1407
+ const n = ns[k];
1408
+ let su = Math.sin(arg), cu = Math.cos(arg);
1409
+ ss[k][0] = su; cc[k][0] = cu;
1410
+ let sv = 2.0 * su * cu, cv = cu * cu - su * su;
1411
+ ss[k][1] = sv; cc[k][1] = cv;
1412
+ for (let i = 2; i < n; i++) {
1413
+ const s = su * cv + cu * sv;
1414
+ cv = cu * cv - su * sv;
1415
+ sv = s;
1416
+ ss[k][i] = sv; cc[k][i] = cv;
1417
+ }
1418
+ }
1419
+ // first terms (not in table)
1420
+ let C = (-0.01742 * T - 17.1996) * ss[4][0];
1421
+ let D = (0.00089 * T + 9.2025) * cc[4][0];
1422
+ for (let pi = 0; nt[pi] !== ENDMARK; pi += 9) {
1423
+ if (nutModel !== SEMOD_NUT_IAU_CORR_1987 && (nt[pi] === 101 || nt[pi] === 102))
1424
+ continue;
1425
+ let k1 = 0, cv = 0, sv = 0;
1426
+ for (let m = 0; m < 5; m++) {
1427
+ let j = nt[pi + m];
1428
+ if (j > 100) j = 0;
1429
+ if (j !== 0) {
1430
+ let k = j < 0 ? -j : j;
1431
+ let su = ss[m][k - 1];
1432
+ if (j < 0) su = -su;
1433
+ const cu = cc[m][k - 1];
1434
+ if (k1 === 0) {
1435
+ sv = su; cv = cu; k1 = 1;
1436
+ } else {
1437
+ const sw = su * cv + cu * sv;
1438
+ cv = cu * cv - su * sv;
1439
+ sv = sw;
1440
+ }
1441
+ }
1442
+ }
1443
+ let f = nt[pi + 5] * 0.0001;
1444
+ if (nt[pi + 6] !== 0) f += 0.00001 * T * nt[pi + 6];
1445
+ let g = nt[pi + 7] * 0.0001;
1446
+ if (nt[pi + 8] !== 0) g += 0.00001 * T * nt[pi + 8];
1447
+ if (nt[pi] >= 100) { f *= 0.1; g *= 0.1; }
1448
+ if (nt[pi] !== 102) {
1449
+ C += f * sv;
1450
+ D += g * cv;
1451
+ } else {
1452
+ C += f * cv;
1453
+ D += g * sv;
1454
+ }
1455
+ }
1456
+ nutlo[0] = DEGTORAD * C / 3600.0;
1457
+ nutlo[1] = DEGTORAD * D / 3600.0;
1458
+ return 0;
1459
+ }
1460
+
1461
+ /* ================================================================
1462
+ * 16. Nutation — IAU 2000A/B
1463
+ * ================================================================ */
1464
+
1465
+ function calcNutationIau2000ab(J: number, nutlo: number[], swed: SweData): number {
1466
+ const nutModel = getNutModel(swed);
1467
+ const T = (J - J2000) / 36525.0;
1468
+ // Fundamental arguments (Simon et al. 1994)
1469
+ const M = sweDegnorm((485868.249036 + T * (1717915923.2178 + T * (31.8792 + T * (0.051635 + T * (-0.00024470))))) / 3600.0) * DEGTORAD;
1470
+ const SM = sweDegnorm((1287104.79305 + T * (129596581.0481 + T * (-0.5532 + T * (0.000136 + T * (-0.00001149))))) / 3600.0) * DEGTORAD;
1471
+ const F = sweDegnorm((335779.526232 + T * (1739527262.8478 + T * (-12.7512 + T * (-0.001037 + T * 0.00000417)))) / 3600.0) * DEGTORAD;
1472
+ const D = sweDegnorm((1072260.70369 + T * (1602961601.2090 + T * (-6.3706 + T * (0.006593 + T * (-0.00003169))))) / 3600.0) * DEGTORAD;
1473
+ const OM = sweDegnorm((450160.398036 + T * (-6962890.5431 + T * (7.4722 + T * (0.007702 + T * (-0.00005939))))) / 3600.0) * DEGTORAD;
1474
+
1475
+ // luni-solar nutation
1476
+ const inls = nutModel === SEMOD_NUT_IAU_2000B ? NLS_2000B : NLS;
1477
+ let dpsi = 0, deps = 0;
1478
+ for (let i = inls - 1; i >= 0; i--) {
1479
+ const j = i * 5;
1480
+ const darg = sweRadnorm(
1481
+ nutLsArgMul[j] * M + nutLsArgMul[j + 1] * SM +
1482
+ nutLsArgMul[j + 2] * F + nutLsArgMul[j + 3] * D +
1483
+ nutLsArgMul[j + 4] * OM
1484
+ );
1485
+ const sinarg = Math.sin(darg);
1486
+ const cosarg = Math.cos(darg);
1487
+ const k = i * 6;
1488
+ dpsi += (nutLsCoef[k] + nutLsCoef[k + 1] * T) * sinarg + nutLsCoef[k + 2] * cosarg;
1489
+ deps += (nutLsCoef[k + 3] + nutLsCoef[k + 4] * T) * cosarg + nutLsCoef[k + 5] * sinarg;
1490
+ }
1491
+ nutlo[0] = dpsi * O1MAS2DEG;
1492
+ nutlo[1] = deps * O1MAS2DEG;
1493
+
1494
+ if (nutModel === SEMOD_NUT_IAU_2000A) {
1495
+ // planetary nutation
1496
+ const AL = sweRadnorm(2.35555598 + 8328.6914269554 * T);
1497
+ const ALSU = sweRadnorm(6.24006013 + 628.301955 * T);
1498
+ const AF = sweRadnorm(1.627905234 + 8433.466158131 * T);
1499
+ const AD = sweRadnorm(5.198466741 + 7771.3771468121 * T);
1500
+ const AOM = sweRadnorm(2.18243920 - 33.757045 * T);
1501
+ const ALME = sweRadnorm(4.402608842 + 2608.7903141574 * T);
1502
+ const ALVE = sweRadnorm(3.176146697 + 1021.3285546211 * T);
1503
+ const ALEA = sweRadnorm(1.753470314 + 628.3075849991 * T);
1504
+ const ALMA = sweRadnorm(6.203480913 + 334.0612426700 * T);
1505
+ const ALJU = sweRadnorm(0.599546497 + 52.9690962641 * T);
1506
+ const ALSA = sweRadnorm(0.874016757 + 21.3299104960 * T);
1507
+ const ALUR = sweRadnorm(5.481293871 + 7.4781598567 * T);
1508
+ const ALNE = sweRadnorm(5.321159000 + 3.8127774000 * T);
1509
+ const APA = (0.02438175 + 0.00000538691 * T) * T;
1510
+ const plArgs = [AL, ALSU, AF, AD, AOM, ALME, ALVE, ALEA, ALMA, ALJU, ALSA, ALUR, ALNE, APA];
1511
+
1512
+ dpsi = 0; deps = 0;
1513
+ for (let i = NPL - 1; i >= 0; i--) {
1514
+ const j = i * 14;
1515
+ let darg = 0;
1516
+ for (let m = 0; m < 14; m++) darg += nutPlArgMul[j + m] * plArgs[m];
1517
+ darg = sweRadnorm(darg);
1518
+ const sinarg = Math.sin(darg);
1519
+ const cosarg = Math.cos(darg);
1520
+ const k = i * 4;
1521
+ dpsi += nutPlCoef[k] * sinarg + nutPlCoef[k + 1] * cosarg;
1522
+ deps += nutPlCoef[k + 2] * sinarg + nutPlCoef[k + 3] * cosarg;
1523
+ }
1524
+ nutlo[0] += dpsi * O1MAS2DEG;
1525
+ nutlo[1] += deps * O1MAS2DEG;
1526
+
1527
+ // P03 precession corrections (Capitaine et al. 2005 = IAU 2006)
1528
+ dpsi = -8.1 * Math.sin(OM) - 0.6 * Math.sin(2 * F - 2 * D + 2 * OM);
1529
+ dpsi += T * (47.8 * Math.sin(OM) + 3.7 * Math.sin(2 * F - 2 * D + 2 * OM) + 0.6 * Math.sin(2 * F + 2 * OM) - 0.6 * Math.sin(2 * OM));
1530
+ deps = T * (-25.6 * Math.cos(OM) - 1.6 * Math.cos(2 * F - 2 * D + 2 * OM));
1531
+ nutlo[0] += dpsi / (3600.0 * 1000000.0);
1532
+ nutlo[1] += deps / (3600.0 * 1000000.0);
1533
+ }
1534
+ nutlo[0] *= DEGTORAD;
1535
+ nutlo[1] *= DEGTORAD;
1536
+ return 0;
1537
+ }
1538
+
1539
+ /* ================================================================
1540
+ * 17. Nutation — Woolard 1953
1541
+ * ================================================================ */
1542
+
1543
+ function calcNutationWoolard(J: number, nutlo: number[]): number {
1544
+ const mjd = J - J1900;
1545
+ const t = mjd / 36525.0;
1546
+ const t2 = t * t;
1547
+ let a: number, b: number;
1548
+ a = 100.0021358 * t; b = 360.0 * (a - Math.trunc(a));
1549
+ const ls = 279.697 + 0.000303 * t2 + b;
1550
+ a = 1336.855231 * t; b = 360.0 * (a - Math.trunc(a));
1551
+ const ld = 270.434 - 0.001133 * t2 + b;
1552
+ a = 99.99736056000026 * t; b = 360.0 * (a - Math.trunc(a));
1553
+ const ms = (358.476 - 0.00015 * t2 + b) * DEGTORAD;
1554
+ a = 13255523.59 * t; b = 360.0 * (a - Math.trunc(a));
1555
+ const md = (296.105 + 0.009192 * t2 + b) * DEGTORAD;
1556
+ a = 5.372616667 * t; b = 360.0 * (a - Math.trunc(a));
1557
+ const nm = (259.183 + 0.002078 * t2 - b) * DEGTORAD;
1558
+ const tls = 2 * ls * DEGTORAD;
1559
+ const tnm = 2 * nm;
1560
+ const tld = 2 * ld * DEGTORAD;
1561
+
1562
+ const dpsi = (-17.2327 - 0.01737 * t) * Math.sin(nm) + (-1.2729 - 0.00013 * t) * Math.sin(tls)
1563
+ + 0.2088 * Math.sin(tnm) - 0.2037 * Math.sin(tld) + (0.1261 - 0.00031 * t) * Math.sin(ms)
1564
+ + 0.0675 * Math.sin(md) - (0.0497 - 0.00012 * t) * Math.sin(tls + ms)
1565
+ - 0.0342 * Math.sin(tld - nm) - 0.0261 * Math.sin(tld + md) + 0.0214 * Math.sin(tls - ms)
1566
+ - 0.0149 * Math.sin(tls - tld + md) + 0.0124 * Math.sin(tls - nm) + 0.0114 * Math.sin(tld - md);
1567
+ const deps = (9.21 + 0.00091 * t) * Math.cos(nm) + (0.5522 - 0.00029 * t) * Math.cos(tls)
1568
+ - 0.0904 * Math.cos(tnm) + 0.0884 * Math.cos(tld) + 0.0216 * Math.cos(tls + ms)
1569
+ + 0.0183 * Math.cos(tld - nm) + 0.0113 * Math.cos(tld + md) - 0.0093 * Math.cos(tls - ms)
1570
+ - 0.0066 * Math.cos(tls - nm);
1571
+ nutlo[0] = dpsi / 3600.0 * DEGTORAD;
1572
+ nutlo[1] = deps / 3600.0 * DEGTORAD;
1573
+ return OK;
1574
+ }
1575
+
1576
+ /* ================================================================
1577
+ * 18. Bessel interpolation and nutation dispatcher
1578
+ * ================================================================ */
1579
+
1580
+ function bessel(v: Float64Array | null, n: number, t: number): number {
1581
+ if (!v) return 0;
1582
+ if (t <= 0) return v[0];
1583
+ if (t >= n - 1) return v[n - 1];
1584
+ const p0 = Math.floor(t);
1585
+ const iy = Math.trunc(t);
1586
+ let ans = v[iy];
1587
+ const k0 = iy + 1;
1588
+ if (k0 >= n) return ans;
1589
+ const p = t - p0;
1590
+ ans += p * (v[k0] - v[iy]);
1591
+ if (iy - 1 < 0 || iy + 2 >= n) return ans;
1592
+ // first differences
1593
+ const d = [0, 0, 0, 0, 0, 0];
1594
+ let k = iy - 2;
1595
+ for (let i = 0; i < 5; i++) {
1596
+ d[i] = (k < 0 || k + 1 >= n) ? 0 : v[k + 1] - v[k];
1597
+ k++;
1598
+ }
1599
+ // second differences
1600
+ for (let i = 0; i < 4; i++) d[i] = d[i + 1] - d[i];
1601
+ let B = 0.25 * p * (p - 1.0);
1602
+ ans += B * (d[1] + d[2]);
1603
+ if (iy + 2 >= n) return ans;
1604
+ // third differences
1605
+ for (let i = 0; i < 3; i++) d[i] = d[i + 1] - d[i];
1606
+ B = 2.0 * B / 3.0;
1607
+ ans += (p - 0.5) * B * d[1];
1608
+ if (iy - 2 < 0 || iy + 3 > n) return ans;
1609
+ // fourth differences
1610
+ for (let i = 0; i < 2; i++) d[i] = d[i + 1] - d[i];
1611
+ B = 0.125 * B * (p + 1.0) * (p - 2.0);
1612
+ ans += B * (d[0] + d[1]);
1613
+ return ans;
1614
+ }
1615
+
1616
+ function calcNutation(J: number, iflag: number, nutlo: number[], swed: SweData): number {
1617
+ const nutModel = getNutModel(swed);
1618
+ const jplhoraModel = getJplHoraModel(swed);
1619
+ let isJplhor = false;
1620
+ if (iflag & SEFLG_JPLHOR) isJplhor = true;
1621
+ if ((iflag & SEFLG_JPLHOR_APPROX)
1622
+ && jplhoraModel === SEMOD_JPLHORA_3
1623
+ && J <= HORIZONS_TJD0_DPSI_DEPS_IAU1980) isJplhor = true;
1624
+
1625
+ if (isJplhor) {
1626
+ calcNutationIau1980(J, nutlo, swed);
1627
+ if (iflag & SEFLG_JPLHOR) {
1628
+ const n = Math.trunc(swed.eopTjdEnd - swed.eopTjdBeg + 0.000001);
1629
+ let J2 = J;
1630
+ if (J < swed.eopTjdBegHorizons) J2 = swed.eopTjdBegHorizons;
1631
+ const dpsi = bessel(swed.dpsi, n + 1, J2 - swed.eopTjdBeg);
1632
+ const deps = bessel(swed.deps, n + 1, J2 - swed.eopTjdBeg);
1633
+ nutlo[0] += dpsi / 3600.0 * DEGTORAD;
1634
+ nutlo[1] += deps / 3600.0 * DEGTORAD;
1635
+ } else {
1636
+ nutlo[0] += DPSI_IAU1980_TJD0 / 3600.0 * DEGTORAD;
1637
+ nutlo[1] += DEPS_IAU1980_TJD0 / 3600.0 * DEGTORAD;
1638
+ }
1639
+ } else if (nutModel === SEMOD_NUT_IAU_1980 || nutModel === SEMOD_NUT_IAU_CORR_1987) {
1640
+ calcNutationIau1980(J, nutlo, swed);
1641
+ } else if (nutModel === SEMOD_NUT_IAU_2000A || nutModel === SEMOD_NUT_IAU_2000B) {
1642
+ calcNutationIau2000ab(J, nutlo, swed);
1643
+ if ((iflag & SEFLG_JPLHOR_APPROX) && jplhoraModel === SEMOD_JPLHORA_2) {
1644
+ nutlo[0] += -41.7750 / 3600.0 / 1000.0 * DEGTORAD;
1645
+ nutlo[1] += -6.8192 / 3600.0 / 1000.0 * DEGTORAD;
1646
+ }
1647
+ } else if (nutModel === SEMOD_NUT_WOOLARD) {
1648
+ calcNutationWoolard(J, nutlo);
1649
+ }
1650
+ return OK;
1651
+ }
1652
+
1653
+ function quadraticIntp(ym: number, y0: number, yp: number, x: number): number {
1654
+ const c = y0;
1655
+ const b = (yp - ym) / 2.0;
1656
+ const a = (yp + ym) / 2.0 - c;
1657
+ return a * x * x + b * x + c;
1658
+ }
1659
+
1660
+ export function swiNutation(tjd: number, iflag: number, nutlo: number[], swed: SweData): number {
1661
+ let retc = OK;
1662
+ if (!swed.doInterpolateNut) {
1663
+ retc = calcNutation(tjd, iflag, nutlo, swed);
1664
+ } else {
1665
+ if (tjd < swed.interpol.tjdNut2 && tjd > swed.interpol.tjdNut0) {
1666
+ const dx = (tjd - swed.interpol.tjdNut0) - 1.0;
1667
+ nutlo[0] = quadraticIntp(swed.interpol.nutDpsi0, swed.interpol.nutDpsi1, swed.interpol.nutDpsi2, dx);
1668
+ nutlo[1] = quadraticIntp(swed.interpol.nutDeps0, swed.interpol.nutDeps1, swed.interpol.nutDeps2, dx);
1669
+ } else {
1670
+ swed.interpol.tjdNut0 = tjd - 1.0;
1671
+ swed.interpol.tjdNut2 = tjd + 1.0;
1672
+ const dnut = [0, 0];
1673
+ retc = calcNutation(swed.interpol.tjdNut0, iflag, dnut, swed);
1674
+ if (retc === ERR) return ERR;
1675
+ swed.interpol.nutDpsi0 = dnut[0];
1676
+ swed.interpol.nutDeps0 = dnut[1];
1677
+ retc = calcNutation(swed.interpol.tjdNut2, iflag, dnut, swed);
1678
+ if (retc === ERR) return ERR;
1679
+ swed.interpol.nutDpsi2 = dnut[0];
1680
+ swed.interpol.nutDeps2 = dnut[1];
1681
+ retc = calcNutation(tjd, iflag, nutlo, swed);
1682
+ if (retc === ERR) return ERR;
1683
+ swed.interpol.nutDpsi1 = nutlo[0];
1684
+ swed.interpol.nutDeps1 = nutlo[1];
1685
+ }
1686
+ }
1687
+ return retc;
1688
+ }
1689
+
1690
+ /** Set nutation interpolation mode */
1691
+ export function sweSetInterpolateNut(swed: SweData, doInterpolate: boolean): void {
1692
+ swed.doInterpolateNut = doInterpolate;
1693
+ swed.interpol.tjdNut0 = 0;
1694
+ swed.interpol.tjdNut2 = 0;
1695
+ }
1696
+
1697
+ /* ================================================================
1698
+ * 19. Frame bias (GCRS ↔ J2000) and ICRS ↔ FK5
1699
+ * ================================================================ */
1700
+
1701
+ const OFFSET_JPLHORIZONS = -52.3;
1702
+ const DCOR_RA_JPL_TJD0 = 2437846.5;
1703
+ const NDCOR_RA_JPL = 51;
1704
+
1705
+ const dcorRaJpl = [
1706
+ -51.257, -51.103, -51.065, -51.503, -51.224, -50.796, -51.161, -51.181,
1707
+ -50.932, -51.064, -51.182, -51.386, -51.416, -51.428, -51.586, -51.766, -52.038, -52.370,
1708
+ -52.553, -52.397, -52.340, -52.676, -52.348, -51.964, -52.444, -52.364, -51.988, -52.212,
1709
+ -52.370, -52.523, -52.541, -52.496, -52.590, -52.629, -52.788, -53.014, -53.053, -52.902,
1710
+ -52.850, -53.087, -52.635, -52.185, -52.588, -52.292, -51.796, -51.961, -52.055, -52.134,
1711
+ -52.165, -52.141, -52.255,
1712
+ ];
1713
+
1714
+ function swiApproxJplhor(x: Float64Array | number[], tjd: number, iflag: number, backward: boolean, swed: SweData): void {
1715
+ const jplhoraModel = getJplHoraModel(swed);
1716
+ if (!(iflag & SEFLG_JPLHOR_APPROX)) return;
1717
+ if (jplhoraModel === SEMOD_JPLHORA_2) return;
1718
+ let t = (tjd - DCOR_RA_JPL_TJD0) / 365.25;
1719
+ let dofs = OFFSET_JPLHORIZONS;
1720
+ if (t < 0) {
1721
+ t = 0;
1722
+ dofs = dcorRaJpl[0];
1723
+ } else if (t >= NDCOR_RA_JPL - 1) {
1724
+ t = NDCOR_RA_JPL;
1725
+ dofs = dcorRaJpl[NDCOR_RA_JPL - 1];
1726
+ } else {
1727
+ const t0 = Math.trunc(t);
1728
+ dofs = (t - t0) * (dcorRaJpl[t0] - dcorRaJpl[t0 + 1]) + dcorRaJpl[t0];
1729
+ }
1730
+ dofs /= (1000.0 * 3600.0);
1731
+ swiCartpol(x, x);
1732
+ if (backward) x[0] -= dofs * DEGTORAD;
1733
+ else x[0] += dofs * DEGTORAD;
1734
+ swiPolcart(x, x);
1735
+ }
1736
+
1737
+ /** GCRS to J2000 frame bias */
1738
+ export function swiBias(x: Float64Array | number[], tjd: number, iflag: number, backward: boolean, swed: SweData): void {
1739
+ const biasModel = getBiasModel(swed);
1740
+ const jplhoraModel = getJplHoraModel(swed);
1741
+ if (biasModel === SEMOD_BIAS_NONE) return;
1742
+ if (iflag & SEFLG_JPLHOR_APPROX) {
1743
+ if (jplhoraModel === SEMOD_JPLHORA_2) return;
1744
+ if (jplhoraModel === SEMOD_JPLHORA_3 && tjd < DPSI_DEPS_IAU1980_TJD0_HORIZONS) return;
1745
+ }
1746
+ const rb = [
1747
+ [0, 0, 0],
1748
+ [0, 0, 0],
1749
+ [0, 0, 0],
1750
+ ];
1751
+ if (biasModel === SEMOD_BIAS_IAU2006) {
1752
+ rb[0][0] = +0.99999999999999412; rb[1][0] = -0.00000007078368961; rb[2][0] = +0.00000008056213978;
1753
+ rb[0][1] = +0.00000007078368695; rb[1][1] = +0.99999999999999700; rb[2][1] = +0.00000003306428553;
1754
+ rb[0][2] = -0.00000008056214212; rb[1][2] = -0.00000003306427981; rb[2][2] = +0.99999999999999634;
1755
+ } else {
1756
+ rb[0][0] = +0.9999999999999942; rb[1][0] = -0.0000000707827974; rb[2][0] = +0.0000000805621715;
1757
+ rb[0][1] = +0.0000000707827948; rb[1][1] = +0.9999999999999969; rb[2][1] = +0.0000000330604145;
1758
+ rb[0][2] = -0.0000000805621738; rb[1][2] = -0.0000000330604088; rb[2][2] = +0.9999999999999962;
1759
+ }
1760
+ const xx = [0, 0, 0, 0, 0, 0];
1761
+ if (backward) {
1762
+ swiApproxJplhor(x, tjd, iflag, true, swed);
1763
+ for (let i = 0; i <= 2; i++) {
1764
+ xx[i] = x[0] * rb[i][0] + x[1] * rb[i][1] + x[2] * rb[i][2];
1765
+ if (iflag & SEFLG_SPEED)
1766
+ xx[i + 3] = x[3] * rb[i][0] + x[4] * rb[i][1] + x[5] * rb[i][2];
1767
+ }
1768
+ } else {
1769
+ for (let i = 0; i <= 2; i++) {
1770
+ xx[i] = x[0] * rb[0][i] + x[1] * rb[1][i] + x[2] * rb[2][i];
1771
+ if (iflag & SEFLG_SPEED)
1772
+ xx[i + 3] = x[3] * rb[0][i] + x[4] * rb[1][i] + x[5] * rb[2][i];
1773
+ }
1774
+ swiApproxJplhor(xx, tjd, iflag, false, swed);
1775
+ }
1776
+ for (let i = 0; i <= 2; i++) x[i] = xx[i];
1777
+ if (iflag & SEFLG_SPEED)
1778
+ for (let i = 3; i <= 5; i++) x[i] = xx[i];
1779
+ }
1780
+
1781
+ /** GCRS to FK5 */
1782
+ export function swiIcrs2fk5(x: Float64Array | number[], iflag: number, backward: boolean): void {
1783
+ const rb = [
1784
+ [+0.9999999999999928, +0.0000001110223287, +0.0000000441180557],
1785
+ [-0.0000001110223330, +0.9999999999999891, +0.0000000964779176],
1786
+ [-0.0000000441180450, -0.0000000964779225, +0.9999999999999943],
1787
+ ];
1788
+ const xx = [0, 0, 0, 0, 0, 0];
1789
+ if (backward) {
1790
+ for (let i = 0; i <= 2; i++) {
1791
+ xx[i] = x[0] * rb[i][0] + x[1] * rb[i][1] + x[2] * rb[i][2];
1792
+ if (iflag & SEFLG_SPEED)
1793
+ xx[i + 3] = x[3] * rb[i][0] + x[4] * rb[i][1] + x[5] * rb[i][2];
1794
+ }
1795
+ } else {
1796
+ for (let i = 0; i <= 2; i++) {
1797
+ xx[i] = x[0] * rb[0][i] + x[1] * rb[1][i] + x[2] * rb[2][i];
1798
+ if (iflag & SEFLG_SPEED)
1799
+ xx[i + 3] = x[3] * rb[0][i] + x[4] * rb[1][i] + x[5] * rb[2][i];
1800
+ }
1801
+ }
1802
+ for (let i = 0; i <= 5; i++) x[i] = xx[i];
1803
+ }
1804
+
1805
+ /* ================================================================
1806
+ * 20. Delta T tables and functions
1807
+ * ================================================================ */
1808
+
1809
+ const TABSTART = 1620;
1810
+ const TABEND = 2028;
1811
+ const TABSIZ = TABEND - TABSTART + 1;
1812
+
1813
+ // prettier-ignore
1814
+ const dt = [
1815
+ /* 1620 - 1659 */
1816
+ 124.00, 119.00, 115.00, 110.00, 106.00, 102.00, 98.00, 95.00, 91.00, 88.00,
1817
+ 85.00, 82.00, 79.00, 77.00, 74.00, 72.00, 70.00, 67.00, 65.00, 63.00,
1818
+ 62.00, 60.00, 58.00, 57.00, 55.00, 54.00, 53.00, 51.00, 50.00, 49.00,
1819
+ 48.00, 47.00, 46.00, 45.00, 44.00, 43.00, 42.00, 41.00, 40.00, 38.00,
1820
+ /* 1660 - 1699 */
1821
+ 37.00, 36.00, 35.00, 34.00, 33.00, 32.00, 31.00, 30.00, 28.00, 27.00,
1822
+ 26.00, 25.00, 24.00, 23.00, 22.00, 21.00, 20.00, 19.00, 18.00, 17.00,
1823
+ 16.00, 15.00, 14.00, 14.00, 13.00, 12.00, 12.00, 11.00, 11.00, 10.00,
1824
+ 10.00, 10.00, 9.00, 9.00, 9.00, 9.00, 9.00, 9.00, 9.00, 9.00,
1825
+ /* 1700 - 1739 */
1826
+ 9.00, 9.00, 9.00, 9.00, 9.00, 9.00, 9.00, 9.00, 10.00, 10.00,
1827
+ 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 11.00, 11.00, 11.00,
1828
+ 11.00, 11.00, 11.00, 11.00, 11.00, 11.00, 11.00, 11.00, 11.00, 11.00,
1829
+ 11.00, 11.00, 11.00, 11.00, 12.00, 12.00, 12.00, 12.00, 12.00, 12.00,
1830
+ /* 1740 - 1779 */
1831
+ 12.00, 12.00, 12.00, 12.00, 13.00, 13.00, 13.00, 13.00, 13.00, 13.00,
1832
+ 13.00, 14.00, 14.00, 14.00, 14.00, 14.00, 14.00, 14.00, 15.00, 15.00,
1833
+ 15.00, 15.00, 15.00, 15.00, 15.00, 16.00, 16.00, 16.00, 16.00, 16.00,
1834
+ 16.00, 16.00, 16.00, 16.00, 16.00, 17.00, 17.00, 17.00, 17.00, 17.00,
1835
+ /* 1780 - 1799 */
1836
+ 17.00, 17.00, 17.00, 17.00, 17.00, 17.00, 17.00, 17.00, 17.00, 17.00,
1837
+ 17.00, 17.00, 16.00, 16.00, 16.00, 16.00, 15.00, 15.00, 14.00, 14.00,
1838
+ /* 1800 - 1819 */
1839
+ 13.70, 13.40, 13.10, 12.90, 12.70, 12.60, 12.50, 12.50, 12.50, 12.50,
1840
+ 12.50, 12.50, 12.50, 12.50, 12.50, 12.50, 12.50, 12.40, 12.30, 12.20,
1841
+ /* 1820 - 1859 */
1842
+ 12.00, 11.70, 11.40, 11.10, 10.60, 10.20, 9.60, 9.10, 8.60, 8.00,
1843
+ 7.50, 7.00, 6.60, 6.30, 6.00, 5.80, 5.70, 5.60, 5.60, 5.60,
1844
+ 5.70, 5.80, 5.90, 6.10, 6.20, 6.30, 6.50, 6.60, 6.80, 6.90,
1845
+ 7.10, 7.20, 7.30, 7.40, 7.50, 7.60, 7.70, 7.70, 7.80, 7.80,
1846
+ /* 1860 - 1899 */
1847
+ 7.88, 7.82, 7.54, 6.97, 6.40, 6.02, 5.41, 4.10, 2.92, 1.82,
1848
+ 1.61, .10, -1.02, -1.28, -2.69, -3.24, -3.64, -4.54, -4.71, -5.11,
1849
+ -5.40, -5.42, -5.20, -5.46, -5.46, -5.79, -5.63, -5.64, -5.80, -5.66,
1850
+ -5.87, -6.01, -6.19, -6.64, -6.44, -6.47, -6.09, -5.76, -4.66, -3.74,
1851
+ /* 1900 - 1939 */
1852
+ -2.72, -1.54, -.02, 1.24, 2.64, 3.86, 5.37, 6.14, 7.75, 9.13,
1853
+ 10.46, 11.53, 13.36, 14.65, 16.01, 17.20, 18.24, 19.06, 20.25, 20.95,
1854
+ 21.16, 22.25, 22.41, 23.03, 23.49, 23.62, 23.86, 24.49, 24.34, 24.08,
1855
+ 24.02, 24.00, 23.87, 23.95, 23.86, 23.93, 23.73, 23.92, 23.96, 24.02,
1856
+ /* 1940 - 1949 */
1857
+ 24.33, 24.83, 25.30, 25.70, 26.24, 26.77, 27.28, 27.78, 28.25, 28.71,
1858
+ /* 1950 - 1959 */
1859
+ 29.15, 29.57, 29.97, 30.36, 30.72, 31.07, 31.35, 31.68, 32.18, 32.68,
1860
+ /* 1960 - 1969 */
1861
+ 33.15, 33.59, 34.00, 34.47, 35.03, 35.73, 36.54, 37.43, 38.29, 39.20,
1862
+ /* 1970 - 1979 */
1863
+ 40.18, 41.17, 42.23, 43.37, 44.4841, 45.4761, 46.4567, 47.5214, 48.5344, 49.5862,
1864
+ /* 1980 - 1989 */
1865
+ 50.5387, 51.3808, 52.1668, 52.9565, 53.7882, 54.3427, 54.8713, 55.3222, 55.8197, 56.3000,
1866
+ /* 1990 - 1999 */
1867
+ 56.8553, 57.5653, 58.3092, 59.1218, 59.9845, 60.7854, 61.6287, 62.2951, 62.9659, 63.4673,
1868
+ /* 2000 - 2009 */
1869
+ 63.8285, 64.0908, 64.2998, 64.4734, 64.5736, 64.6876, 64.8452, 65.1464, 65.4574, 65.7768,
1870
+ /* 2010 - 2019 */
1871
+ 66.0699, 66.3246, 66.6030, 66.9069, 67.2810, 67.6439, 68.1024, 68.5927, 68.9676, 69.2202,
1872
+ /* 2020 - 2028 */
1873
+ 69.3612, 69.3593, 69.2945, 69.1833, 69.10, 69.00, 68.90, 68.80, 68.80,
1874
+ ];
1875
+
1876
+ const TAB2_SIZ = 27;
1877
+ const TAB2_START = -1000;
1878
+ const TAB2_END = 1600;
1879
+ const TAB2_STEP = 100;
1880
+ const LTERM_EQUATION_YSTART = 1820;
1881
+ const LTERM_EQUATION_COEFF = 32;
1882
+
1883
+ // prettier-ignore
1884
+ const dt2 = [
1885
+ 25400,23700,22000,21000,19040,17190,15530,14080,12790,11640,
1886
+ 10580, 9600, 8640, 7680, 6700, 5710, 4740, 3810, 2960, 2200,
1887
+ 1570, 1090, 740, 490, 320, 200, 120,
1888
+ ];
1889
+
1890
+ const TAB97_SIZ = 43;
1891
+ const TAB97_START = -500;
1892
+ const TAB97_END = 1600;
1893
+ const TAB97_STEP = 50;
1894
+
1895
+ // prettier-ignore
1896
+ const dt97 = [
1897
+ 16800,16000,15300,14600,14000,13400,12800,12200,11600,11100,
1898
+ 10600,10100, 9600, 9100, 8600, 8200, 7700, 7200, 6700, 6200,
1899
+ 5700, 5200, 4700, 4300, 3800, 3400, 3000, 2600, 2200, 1900,
1900
+ 1600, 1350, 1100, 900, 750, 600, 470, 380, 300, 230,
1901
+ 180, 140, 110,
1902
+ ];
1903
+
1904
+ function adjustForTidacc(ans: number, Y: number, tidAcc: number, tidAcc0: number, adjustAfter1955: boolean): number {
1905
+ if (Y < 1955.0 || adjustAfter1955) {
1906
+ const B = Y - 1955.0;
1907
+ return ans + (-0.000091 * (tidAcc - tidAcc0) * B * B);
1908
+ }
1909
+ return ans;
1910
+ }
1911
+
1912
+ function deltatLongtermMorrisonStephenson(tjd: number): number {
1913
+ const Ygreg = 2000.0 + (tjd - J2000) / 365.2425;
1914
+ const u = (Ygreg - 1820) / 100.0;
1915
+ return -20 + 32 * u * u;
1916
+ }
1917
+
1918
+ function deltatStephensonMorrison1997_1600(tjd: number, tidAcc: number): number {
1919
+ let ans = 0;
1920
+ const Y = 2000.0 + (tjd - J2000) / 365.25;
1921
+ if (Y < TAB97_START) {
1922
+ let B = (Y - 1735) * 0.01;
1923
+ ans = -20 + 35 * B * B;
1924
+ ans = adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false);
1925
+ if (Y >= TAB97_START - 100) {
1926
+ const ans2 = adjustForTidacc(dt97[0], TAB97_START, tidAcc, SE_TIDAL_26, false);
1927
+ B = (TAB97_START - 1735) * 0.01;
1928
+ let ans3 = -20 + 35 * B * B;
1929
+ ans3 = adjustForTidacc(ans3, Y, tidAcc, SE_TIDAL_26, false);
1930
+ const dd = ans3 - ans2;
1931
+ B = (Y - (TAB97_START - 100)) * 0.01;
1932
+ ans = ans - dd * B;
1933
+ }
1934
+ }
1935
+ if (Y >= TAB97_START && Y < TAB2_END) {
1936
+ const p = Math.floor(Y);
1937
+ const iy = Math.trunc((p - TAB97_START) / 50.0);
1938
+ const dd = (Y - (TAB97_START + 50 * iy)) / 50.0;
1939
+ ans = dt97[iy] + (dt97[iy + 1] - dt97[iy]) * dd;
1940
+ ans = adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false);
1941
+ }
1942
+ return ans / 86400.0;
1943
+ }
1944
+
1945
+ function deltatStephensonMorrison2004_1600(tjd: number, tidAcc: number): number {
1946
+ let ans = 0;
1947
+ const Y = 2000.0 + (tjd - J2000) / 365.2425;
1948
+ if (Y < TAB2_START) {
1949
+ ans = deltatLongtermMorrisonStephenson(tjd);
1950
+ ans = adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false);
1951
+ if (Y >= TAB2_START - 100) {
1952
+ const ans2 = adjustForTidacc(dt2[0], TAB2_START, tidAcc, SE_TIDAL_26, false);
1953
+ const tjd0 = (TAB2_START - 2000) * 365.2425 + J2000;
1954
+ let ans3 = deltatLongtermMorrisonStephenson(tjd0);
1955
+ ans3 = adjustForTidacc(ans3, Y, tidAcc, SE_TIDAL_26, false);
1956
+ const dd = ans3 - ans2;
1957
+ const B = (Y - (TAB2_START - 100)) * 0.01;
1958
+ ans = ans - dd * B;
1959
+ }
1960
+ }
1961
+ if (Y >= TAB2_START && Y < TAB2_END) {
1962
+ const Yjul = 2000 + (tjd - 2451557.5) / 365.25;
1963
+ const p = Math.floor(Yjul);
1964
+ const iy = Math.trunc((p - TAB2_START) / TAB2_STEP);
1965
+ const dd = (Yjul - (TAB2_START + TAB2_STEP * iy)) / TAB2_STEP;
1966
+ ans = dt2[iy] + (dt2[iy + 1] - dt2[iy]) * dd;
1967
+ ans = adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false);
1968
+ }
1969
+ return ans / 86400.0;
1970
+ }
1971
+
1972
+ const NDTCF16 = 54;
1973
+ // prettier-ignore
1974
+ const dtcf16 = [
1975
+ [1458085.5, 1867156.5, 20550.593,-21268.478, 11863.418, -4541.129],
1976
+ [1867156.5, 2086302.5, 6604.404, -5981.266, -505.093, 1349.609],
1977
+ [2086302.5, 2268923.5, 1467.654, -2452.187, 2460.927, -1183.759],
1978
+ [2268923.5, 2305447.5, 292.635, -216.322, -43.614, 56.681],
1979
+ [2305447.5, 2323710.5, 89.380, -66.754, 31.607, -10.497],
1980
+ [2323710.5, 2349276.5, 43.736, -49.043, 0.227, 15.811],
1981
+ [2349276.5, 2378496.5, 10.730, -1.321, 62.250, -52.946],
1982
+ [2378496.5, 2382148.5, 18.714, -4.457, -1.509, 2.507],
1983
+ [2382148.5, 2385800.5, 15.255, 0.046, 6.012, -4.634],
1984
+ [2385800.5, 2389453.5, 16.679, -1.831, -7.889, 3.799],
1985
+ [2389453.5, 2393105.5, 10.758, -6.211, 3.509, -0.388],
1986
+ [2393105.5, 2396758.5, 7.668, -0.357, 2.345, -0.338],
1987
+ [2396758.5, 2398584.5, 9.317, 1.659, 0.332, -0.932],
1988
+ [2398584.5, 2400410.5, 10.376, -0.472, -2.463, 1.596],
1989
+ [2400410.5, 2402237.5, 9.038, -0.610, 2.325, -2.497],
1990
+ [2402237.5, 2404063.5, 8.256, -3.450, -5.166, 2.729],
1991
+ [2404063.5, 2405889.5, 2.369, -5.596, 3.020, -0.919],
1992
+ [2405889.5, 2407715.5, -1.126, -2.312, 0.264, -0.037],
1993
+ [2407715.5, 2409542.5, -3.211, -1.894, 0.154, 0.562],
1994
+ [2409542.5, 2411368.5, -4.388, 0.101, 1.841, -1.438],
1995
+ [2411368.5, 2413194.5, -3.884, -0.531, -2.473, 1.870],
1996
+ [2413194.5, 2415020.5, -5.017, 0.134, 3.138, -0.232],
1997
+ [2415020.5, 2416846.5, -1.977, 5.715, 2.443, -1.257],
1998
+ [2416846.5, 2418672.5, 4.923, 6.828, -1.329, 0.720],
1999
+ [2418672.5, 2420498.5, 11.142, 6.330, 0.831, -0.825],
2000
+ [2420498.5, 2422324.5, 17.479, 5.518, -1.643, 0.262],
2001
+ [2422324.5, 2424151.5, 21.617, 3.020, -0.856, 0.008],
2002
+ [2424151.5, 2425977.5, 23.789, 1.333, -0.831, 0.127],
2003
+ [2425977.5, 2427803.5, 24.418, 0.052, -0.449, 0.142],
2004
+ [2427803.5, 2429629.5, 24.164, -0.419, -0.022, 0.702],
2005
+ [2429629.5, 2431456.5, 24.426, 1.645, 2.086, -1.106],
2006
+ [2431456.5, 2433282.5, 27.050, 2.499, -1.232, 0.614],
2007
+ [2433282.5, 2434378.5, 28.932, 1.127, 0.220, -0.277],
2008
+ [2434378.5, 2435473.5, 30.002, 0.737, -0.610, 0.631],
2009
+ [2435473.5, 2436569.5, 30.760, 1.409, 1.282, -0.799],
2010
+ [2436569.5, 2437665.5, 32.652, 1.577, -1.115, 0.507],
2011
+ [2437665.5, 2438761.5, 33.621, 0.868, 0.406, 0.199],
2012
+ [2438761.5, 2439856.5, 35.093, 2.275, 1.002, -0.414],
2013
+ [2439856.5, 2440952.5, 37.956, 3.035, -0.242, 0.202],
2014
+ [2440952.5, 2442048.5, 40.951, 3.157, 0.364, -0.229],
2015
+ [2442048.5, 2443144.5, 44.244, 3.198, -0.323, 0.172],
2016
+ [2443144.5, 2444239.5, 47.291, 3.069, 0.193, -0.192],
2017
+ [2444239.5, 2445335.5, 50.361, 2.878, -0.384, 0.081],
2018
+ [2445335.5, 2446431.5, 52.936, 2.354, -0.140, -0.166],
2019
+ [2446431.5, 2447527.5, 54.984, 1.577, -0.637, 0.448],
2020
+ [2447527.5, 2448622.5, 56.373, 1.649, 0.709, -0.277],
2021
+ [2448622.5, 2449718.5, 58.453, 2.235, -0.122, 0.111],
2022
+ [2449718.5, 2450814.5, 60.677, 2.324, 0.212, -0.315],
2023
+ [2450814.5, 2451910.5, 62.899, 1.804, -0.732, 0.112],
2024
+ [2451910.5, 2453005.5, 64.082, 0.675, -0.396, 0.193],
2025
+ [2453005.5, 2454101.5, 64.555, 0.463, 0.184, -0.008],
2026
+ [2454101.5, 2455197.5, 65.194, 0.809, 0.161, -0.101],
2027
+ [2455197.5, 2456293.5, 66.063, 0.828, -0.142, 0.168],
2028
+ [2456293.5, 2457388.5, 66.917, 1.046, 0.360, -0.282],
2029
+ ];
2030
+
2031
+ function deltatStephensonEtc2016(tjd: number, tidAcc: number): number {
2032
+ const Ygreg = 2000.0 + (tjd - J2000) / 365.2425;
2033
+ let dt2: number;
2034
+ let irec = -1;
2035
+ for (let i = 0; i < NDTCF16; i++) {
2036
+ if (tjd < dtcf16[i][0]) break;
2037
+ if (tjd < dtcf16[i][1]) { irec = i; break; }
2038
+ }
2039
+ if (irec >= 0) {
2040
+ const t = (tjd - dtcf16[irec][0]) / (dtcf16[irec][1] - dtcf16[irec][0]);
2041
+ dt2 = dtcf16[irec][2] + dtcf16[irec][3] * t + dtcf16[irec][4] * t * t + dtcf16[irec][5] * t * t * t;
2042
+ } else if (Ygreg < -720) {
2043
+ const t = (Ygreg - 1825) / 100.0;
2044
+ dt2 = -320 + 32.5 * t * t - 179.7337208;
2045
+ } else {
2046
+ const t = (Ygreg - 1825) / 100.0;
2047
+ dt2 = -320 + 32.5 * t * t + 269.4790417;
2048
+ }
2049
+ dt2 = adjustForTidacc(dt2, Ygreg, tidAcc, SE_TIDAL_STEPHENSON_2016, true);
2050
+ return dt2 / 86400.0;
2051
+ }
2052
+
2053
+ function deltatEspenakMeeus1620(tjd: number, tidAcc: number): number {
2054
+ let ans: number;
2055
+ const Ygreg = 2000.0 + (tjd - J2000) / 365.2425;
2056
+ if (Ygreg < -500) {
2057
+ ans = deltatLongtermMorrisonStephenson(tjd);
2058
+ } else if (Ygreg < 500) {
2059
+ const u = Ygreg / 100.0;
2060
+ ans = (((((0.0090316521 * u + 0.022174192) * u - 0.1798452) * u - 5.952053) * u + 33.78311) * u - 1014.41) * u + 10583.6;
2061
+ } else if (Ygreg < 1600) {
2062
+ const u = (Ygreg - 1000) / 100.0;
2063
+ ans = (((((0.0083572073 * u - 0.005050998) * u - 0.8503463) * u + 0.319781) * u + 71.23472) * u - 556.01) * u + 1574.2;
2064
+ } else if (Ygreg < 1700) {
2065
+ const u = Ygreg - 1600;
2066
+ ans = 120 - 0.9808 * u - 0.01532 * u * u + u * u * u / 7129.0;
2067
+ } else if (Ygreg < 1800) {
2068
+ const u = Ygreg - 1700;
2069
+ ans = (((-u / 1174000.0 + 0.00013336) * u - 0.0059285) * u + 0.1603) * u + 8.83;
2070
+ } else if (Ygreg < 1860) {
2071
+ const u = Ygreg - 1800;
2072
+ ans = ((((((0.000000000875 * u - 0.0000001699) * u + 0.0000121272) * u - 0.00037436) * u + 0.0041116) * u + 0.0068612) * u - 0.332447) * u + 13.72;
2073
+ } else if (Ygreg < 1900) {
2074
+ const u = Ygreg - 1860;
2075
+ ans = ((((u / 233174.0 - 0.0004473624) * u + 0.01680668) * u - 0.251754) * u + 0.5737) * u + 7.62;
2076
+ } else if (Ygreg < 1920) {
2077
+ const u = Ygreg - 1900;
2078
+ ans = (((-0.000197 * u + 0.0061966) * u - 0.0598939) * u + 1.494119) * u - 2.79;
2079
+ } else if (Ygreg < 1941) {
2080
+ const u = Ygreg - 1920;
2081
+ ans = 21.20 + 0.84493 * u - 0.076100 * u * u + 0.0020936 * u * u * u;
2082
+ } else if (Ygreg < 1961) {
2083
+ const u = Ygreg - 1950;
2084
+ ans = 29.07 + 0.407 * u - u * u / 233.0 + u * u * u / 2547.0;
2085
+ } else if (Ygreg < 1986) {
2086
+ const u = Ygreg - 1975;
2087
+ ans = 45.45 + 1.067 * u - u * u / 260.0 - u * u * u / 718.0;
2088
+ } else {
2089
+ const u = Ygreg - 2000;
2090
+ ans = ((((0.00002373599 * u + 0.000651814) * u + 0.0017275) * u - 0.060374) * u + 0.3345) * u + 63.86;
2091
+ }
2092
+ ans = adjustForTidacc(ans, Ygreg, tidAcc, SE_TIDAL_26, false);
2093
+ return ans / 86400.0;
2094
+ }
2095
+
2096
+ function deltatAa(tjd: number, tidAcc: number, swed: SweData): number {
2097
+ const tabsiz = TABSIZ;
2098
+ const tabend = TABSTART + tabsiz - 1;
2099
+ const deltatModel = getDeltatModel(swed);
2100
+ const Y = 2000.0 + (tjd - 2451544.5) / 365.25;
2101
+ if (Y <= tabend) {
2102
+ // Bessel interpolation from table
2103
+ const p0 = Math.floor(Y);
2104
+ const iy = Math.trunc(p0 - TABSTART);
2105
+ let ans = dt[iy];
2106
+ const k = iy + 1;
2107
+ if (k >= tabsiz) {
2108
+ return adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false) / 86400.0;
2109
+ }
2110
+ const p = Y - p0;
2111
+ ans += p * (dt[k] - dt[iy]);
2112
+ if (iy - 1 < 0 || iy + 2 >= tabsiz) {
2113
+ return adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false) / 86400.0;
2114
+ }
2115
+ const d = [0, 0, 0, 0, 0, 0];
2116
+ let kk = iy - 2;
2117
+ for (let i = 0; i < 5; i++) {
2118
+ d[i] = (kk < 0 || kk + 1 >= tabsiz) ? 0 : dt[kk + 1] - dt[kk];
2119
+ kk++;
2120
+ }
2121
+ for (let i = 0; i < 4; i++) d[i] = d[i + 1] - d[i];
2122
+ let B = 0.25 * p * (p - 1.0);
2123
+ ans += B * (d[1] + d[2]);
2124
+ if (iy + 2 >= tabsiz) {
2125
+ return adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false) / 86400.0;
2126
+ }
2127
+ for (let i = 0; i < 3; i++) d[i] = d[i + 1] - d[i];
2128
+ B = 2.0 * B / 3.0;
2129
+ ans += (p - 0.5) * B * d[1];
2130
+ if (iy - 2 < 0 || iy + 3 > tabsiz) {
2131
+ return adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false) / 86400.0;
2132
+ }
2133
+ for (let i = 0; i < 2; i++) d[i] = d[i + 1] - d[i];
2134
+ B = 0.125 * B * (p + 1.0) * (p - 2.0);
2135
+ ans += B * (d[0] + d[1]);
2136
+ return adjustForTidacc(ans, Y, tidAcc, SE_TIDAL_26, false) / 86400.0;
2137
+ }
2138
+ // future
2139
+ let ans: number, ans2: number;
2140
+ if (deltatModel === SEMOD_DELTAT_STEPHENSON_ETC_2016) {
2141
+ let B = Y - 2000;
2142
+ if (Y < 2500) {
2143
+ ans = B * B * B * 121.0 / 30000000.0 + B * B / 1250.0 + B * 521.0 / 3000.0 + 64.0;
2144
+ const B2 = tabend - 2000;
2145
+ ans2 = B2 * B2 * B2 * 121.0 / 30000000.0 + B2 * B2 / 1250.0 + B2 * 521.0 / 3000.0 + 64.0;
2146
+ } else {
2147
+ B = 0.01 * (Y - 2000);
2148
+ ans = B * B * 32.5 + 42.5;
2149
+ ans2 = 0; // won't be used
2150
+ }
2151
+ } else {
2152
+ const B = 0.01 * (Y - 1820);
2153
+ ans = -20 + 31 * B * B;
2154
+ const B2 = 0.01 * (tabend - 1820);
2155
+ ans2 = -20 + 31 * B2 * B2;
2156
+ }
2157
+ if (Y <= tabend + 100) {
2158
+ const ans3 = dt[tabsiz - 1];
2159
+ const dd = ans2 - ans3;
2160
+ ans += dd * (Y - (tabend + 100)) * 0.01;
2161
+ }
2162
+ return ans / 86400.0;
2163
+ }
2164
+
2165
+ function calcDeltat(tjd: number, iflag: number, swed: SweData): { deltat: number; retflag: number } {
2166
+ const deltatModel = getDeltatModel(swed);
2167
+ const tidAcc = swed.tidAcc || SE_TIDAL_DEFAULT;
2168
+ const Y = 2000.0 + (tjd - J2000) / 365.25;
2169
+ const Ygreg = 2000.0 + (tjd - J2000) / 365.2425;
2170
+
2171
+ if (deltatModel === SEMOD_DELTAT_STEPHENSON_ETC_2016 && tjd < 2435108.5) {
2172
+ let d = deltatStephensonEtc2016(tjd, tidAcc);
2173
+ if (tjd >= 2434108.5) {
2174
+ d += (1.0 - (2435108.5 - tjd) / 1000.0) * 0.6610218 / 86400.0;
2175
+ }
2176
+ return { deltat: d, retflag: iflag };
2177
+ }
2178
+ if (deltatModel === SEMOD_DELTAT_ESPENAK_MEEUS_2006 && tjd < 2317746.13090277789) {
2179
+ return { deltat: deltatEspenakMeeus1620(tjd, tidAcc), retflag: iflag };
2180
+ }
2181
+ if (deltatModel === SEMOD_DELTAT_STEPHENSON_MORRISON_2004 && Y < TABSTART) {
2182
+ if (Y < TAB2_END) {
2183
+ return { deltat: deltatStephensonMorrison2004_1600(tjd, tidAcc), retflag: iflag };
2184
+ } else {
2185
+ const B = TABSTART - TAB2_END;
2186
+ const iy = Math.trunc((TAB2_END - TAB2_START) / TAB2_STEP);
2187
+ const dd = (Y - TAB2_END) / B;
2188
+ let ans = dt2[iy] + dd * (dt[0] - dt2[iy]);
2189
+ ans = adjustForTidacc(ans, Ygreg, tidAcc, SE_TIDAL_26, false);
2190
+ return { deltat: ans / 86400.0, retflag: iflag };
2191
+ }
2192
+ }
2193
+ if (deltatModel === SEMOD_DELTAT_STEPHENSON_1997 && Y < TABSTART) {
2194
+ if (Y < TAB97_END) {
2195
+ return { deltat: deltatStephensonMorrison1997_1600(tjd, tidAcc), retflag: iflag };
2196
+ } else {
2197
+ const B = TABSTART - TAB97_END;
2198
+ const iy = Math.trunc((TAB97_END - TAB97_START) / TAB97_STEP);
2199
+ const dd = (Y - TAB97_END) / B;
2200
+ let ans = dt97[iy] + dd * (dt[0] - dt97[iy]);
2201
+ ans = adjustForTidacc(ans, Ygreg, tidAcc, SE_TIDAL_26, false);
2202
+ return { deltat: ans / 86400.0, retflag: iflag };
2203
+ }
2204
+ }
2205
+ if (deltatModel === SEMOD_DELTAT_STEPHENSON_MORRISON_1984 && Y < TABSTART) {
2206
+ let ans: number;
2207
+ if (Y >= 948.0) {
2208
+ const B = 0.01 * (Y - 2000.0);
2209
+ ans = (23.58 * B + 100.3) * B + 101.6;
2210
+ } else {
2211
+ const B = 0.01 * (Y - 2000.0) + 3.75;
2212
+ ans = 35.0 * B * B + 40.0;
2213
+ }
2214
+ return { deltat: ans / 86400.0, retflag: iflag };
2215
+ }
2216
+ if (Y >= TABSTART) {
2217
+ return { deltat: deltatAa(tjd, tidAcc, swed), retflag: iflag };
2218
+ }
2219
+ return { deltat: 0, retflag: iflag };
2220
+ }
2221
+
2222
+ /** Delta T with explicit ephemeris flag */
2223
+ export function sweDeltatEx(tjd: number, iflag: number, swed: SweData): number {
2224
+ if (swed.deltaTUserdefIsSet) return swed.deltaTUserdef;
2225
+ const { deltat } = calcDeltat(tjd, iflag, swed);
2226
+ return deltat;
2227
+ }
2228
+
2229
+ /** Delta T with default ephemeris */
2230
+ export function sweDeltat(tjd: number, swed: SweData): number {
2231
+ const iflag = swiGuessEpheFlag(swed);
2232
+ return sweDeltatEx(tjd, iflag, swed);
2233
+ }
2234
+
2235
+ /* ================================================================
2236
+ * 21. Tidal acceleration
2237
+ * ================================================================ */
2238
+
2239
+ export function sweGetTidAcc(swed: SweData): number {
2240
+ return swed.tidAcc;
2241
+ }
2242
+
2243
+ export function sweSetTidAcc(swed: SweData, tAcc: number): void {
2244
+ if (tAcc === SE_TIDAL_AUTOMATIC) {
2245
+ swed.tidAcc = SE_TIDAL_DEFAULT;
2246
+ swed.isTidAccManual = false;
2247
+ return;
2248
+ }
2249
+ swed.tidAcc = tAcc;
2250
+ swed.isTidAccManual = true;
2251
+ }
2252
+
2253
+ export function sweSetDeltaTUserdef(swed: SweData, dtt: number): void {
2254
+ if (dtt === SE_DELTAT_AUTOMATIC) {
2255
+ swed.deltaTUserdefIsSet = false;
2256
+ } else {
2257
+ swed.deltaTUserdefIsSet = true;
2258
+ swed.deltaTUserdef = dtt;
2259
+ }
2260
+ }
2261
+
2262
+ /* ================================================================
2263
+ * 22. Sidereal time
2264
+ * ================================================================ */
2265
+
2266
+ const SIDTNTERM = 33;
2267
+ const SIDTNARG = 14;
2268
+
2269
+ /** Sidereal time non-polynomial coefficients C'_{s,j}, C'_{c,j} */
2270
+ const stcf: readonly number[] = [
2271
+ 2640.96,-0.39,
2272
+ 63.52,-0.02,
2273
+ 11.75,0.01,
2274
+ 11.21,0.01,
2275
+ -4.55,0.00,
2276
+ 2.02,0.00,
2277
+ 1.98,0.00,
2278
+ -1.72,0.00,
2279
+ -1.41,-0.01,
2280
+ -1.26,-0.01,
2281
+ -0.63,0.00,
2282
+ -0.63,0.00,
2283
+ 0.46,0.00,
2284
+ 0.45,0.00,
2285
+ 0.36,0.00,
2286
+ -0.24,-0.12,
2287
+ 0.32,0.00,
2288
+ 0.28,0.00,
2289
+ 0.27,0.00,
2290
+ 0.26,0.00,
2291
+ -0.21,0.00,
2292
+ 0.19,0.00,
2293
+ 0.18,0.00,
2294
+ -0.10,0.05,
2295
+ 0.15,0.00,
2296
+ -0.14,0.00,
2297
+ 0.14,0.00,
2298
+ -0.14,0.00,
2299
+ 0.14,0.00,
2300
+ 0.13,0.00,
2301
+ -0.11,0.00,
2302
+ 0.11,0.00,
2303
+ 0.11,0.00,
2304
+ ];
2305
+
2306
+ /** Sidereal time argument multipliers:
2307
+ * l l' F D Om L_Me L_Ve L_E L_Ma L_J L_Sa L_U L_Ne p_A */
2308
+ const stfarg: readonly number[] = [
2309
+ 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2310
+ 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2311
+ 0, 0, 2, -2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2312
+ 0, 0, 2, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2313
+ 0, 0, 2, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2314
+ 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2315
+ 0, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2316
+ 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2317
+ 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2318
+ 0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2319
+ 1, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2320
+ 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2321
+ 0, 1, 2, -2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2322
+ 0, 1, 2, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2323
+ 0, 0, 4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2324
+ 0, 0, 1, -1, 1, 0, -8, 12, 0, 0, 0, 0, 0, 0,
2325
+ 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2326
+ 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2327
+ 1, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2328
+ 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2329
+ 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2330
+ 0, 1, -2, 2, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2331
+ 0, 1, -2, 2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2332
+ 0, 0, 0, 0, 0, 0, 8,-13, 0, 0, 0, 0, 0, -1,
2333
+ 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2334
+ 2, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2335
+ 1, 0, 0, -2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2336
+ 0, 1, 2, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2337
+ 1, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2338
+ 0, 0, 4, -2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2339
+ 0, 0, 2, -2, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2340
+ 1, 0, -2, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2341
+ 1, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2342
+ ];
2343
+
2344
+ /** Non-polynomial part of equation of the equinoxes (ERA-based) */
2345
+ function sidtimeNonPolynomialPart(tt: number): number {
2346
+ const delm = new Array<number>(SIDTNARG);
2347
+ /* L: mean anomaly of the Moon */
2348
+ delm[0] = sweRadnorm(2.35555598 + 8328.6914269554 * tt);
2349
+ /* L': mean anomaly of the Sun */
2350
+ delm[1] = sweRadnorm(6.24006013 + 628.301955 * tt);
2351
+ /* F: mean argument of latitude of the Moon */
2352
+ delm[2] = sweRadnorm(1.627905234 + 8433.466158131 * tt);
2353
+ /* D: mean elongation of the Moon from the Sun */
2354
+ delm[3] = sweRadnorm(5.198466741 + 7771.3771468121 * tt);
2355
+ /* Om: mean longitude of ascending node of the Moon */
2356
+ delm[4] = sweRadnorm(2.18243920 - 33.757045 * tt);
2357
+ /* Planetary longitudes, Mercury through Neptune (Souchay et al. 1999) */
2358
+ delm[5] = sweRadnorm(4.402608842 + 2608.7903141574 * tt);
2359
+ delm[6] = sweRadnorm(3.176146697 + 1021.3285546211 * tt);
2360
+ delm[7] = sweRadnorm(1.753470314 + 628.3075849991 * tt);
2361
+ delm[8] = sweRadnorm(6.203480913 + 334.0612426700 * tt);
2362
+ delm[9] = sweRadnorm(0.599546497 + 52.9690962641 * tt);
2363
+ delm[10] = sweRadnorm(0.874016757 + 21.3299104960 * tt);
2364
+ delm[11] = sweRadnorm(5.481293871 + 7.4781598567 * tt);
2365
+ delm[12] = sweRadnorm(5.321159000 + 3.8127774000 * tt);
2366
+ /* PA: general accumulated precession in longitude */
2367
+ delm[13] = (0.02438175 + 0.00000538691 * tt) * tt;
2368
+ let dadd = -0.87 * Math.sin(delm[4]) * tt;
2369
+ for (let i = 0; i < SIDTNTERM; i++) {
2370
+ let darg = 0;
2371
+ for (let j = 0; j < SIDTNARG; j++) {
2372
+ darg += stfarg[i * SIDTNARG + j] * delm[j];
2373
+ }
2374
+ dadd += stcf[i * 2] * Math.sin(darg) + stcf[i * 2 + 1] * Math.cos(darg);
2375
+ }
2376
+ dadd /= (3600.0 * 1000000.0);
2377
+ return dadd;
2378
+ }
2379
+
2380
+ /**
2381
+ * Long-term sidereal time based on Simon et al. mean earth longitude,
2382
+ * precessed to equinox of date. Gives exact agreement for epoch
2383
+ * 1 Jan 2003 with IERS 2010 definition.
2384
+ */
2385
+ function sidtimeLongTerm(swed: SweData, tjdUt: number, eps: number, nut: number): number {
2386
+ const dlt = AUNIT / CLIGHT / 86400.0;
2387
+ const tjdEt = tjdUt + sweDeltatEx(tjdUt, -1, swed);
2388
+ const t = (tjdEt - J2000) / 365250.0;
2389
+ const t2 = t * t;
2390
+ const t3 = t * t2;
2391
+ /* mean longitude of earth J2000 */
2392
+ let dlon = 100.46645683 + (1295977422.83429 * t - 2.04411 * t2 - 0.00523 * t3) / 3600.0;
2393
+ /* light time sun-earth */
2394
+ dlon = sweDegnorm(dlon - dlt * 360.0 / 365.2425);
2395
+ const xs = [dlon * DEGTORAD, 0, 1, 0, 0, 0];
2396
+ /* to mean equator J2000, cartesian */
2397
+ const xoblJ2000 = swiEpsiln(J2000 + sweDeltatEx(J2000, -1, swed), 0, swed) * RADTODEG;
2398
+ swiPolcart(xs, xs);
2399
+ swiCoortrf(xs, xs, -xoblJ2000 * DEGTORAD);
2400
+ /* precess to mean equinox of date */
2401
+ swiPrecess(xs, tjdEt, 0, J2000_TO_J, swed);
2402
+ /* to mean equinox of date */
2403
+ const xoblDate = swiEpsiln(tjdEt, 0, swed) * RADTODEG;
2404
+ const nutlo = [0, 0];
2405
+ swiNutation(tjdEt, 0, nutlo, swed);
2406
+ const xoblTrue = xoblDate + nutlo[1] * RADTODEG;
2407
+ const nutLon = nutlo[0] * RADTODEG;
2408
+ swiCoortrf(xs, xs, xoblDate * DEGTORAD);
2409
+ swiCartpol(xs, xs);
2410
+ xs[0] *= RADTODEG;
2411
+ const dhour = ((tjdUt - 0.5) % 1) * 360;
2412
+ /* mean to true (if nut != 0) */
2413
+ if (eps === 0) {
2414
+ xs[0] += nutLon * Math.cos(xoblTrue * DEGTORAD);
2415
+ } else {
2416
+ xs[0] += nut * Math.cos(eps * DEGTORAD);
2417
+ }
2418
+ /* add hour */
2419
+ xs[0] = sweDegnorm(xs[0] + dhour);
2420
+ return xs[0] / 15;
2421
+ }
2422
+
2423
+ /* sidtime_long_term is not used between these dates */
2424
+ const SIDT_LTERM_T0 = 2396758.5; /* 1 Jan 1850 */
2425
+ const SIDT_LTERM_T1 = 2469807.5; /* 1 Jan 2050 */
2426
+ const SIDT_LTERM_OFS0 = 0.000378172 / 15.0;
2427
+ const SIDT_LTERM_OFS1 = 0.001385646 / 15.0;
2428
+
2429
+ /**
2430
+ * Apparent Sidereal Time at Greenwich with equation of the equinoxes.
2431
+ * Returns sidereal time in hours.
2432
+ *
2433
+ * @param tjd Julian day UT
2434
+ * @param eps obliquity of ecliptic, degrees
2435
+ * @param nut nutation in longitude, degrees
2436
+ */
2437
+ export function sweSidtime0(swed: SweData, tjd: number, eps: number, nut: number): number {
2438
+ const precModelShort = swed.astroModels[SE_MODEL_PREC_SHORTTERM] || SEMOD_PREC_DEFAULT_SHORT;
2439
+ const sidtModel = swed.astroModels[SE_MODEL_SIDT] || SEMOD_SIDT_DEFAULT;
2440
+ let gmst: number;
2441
+ /* long-term sidereal time for dates outside 1850-2050 */
2442
+ if (sidtModel === SEMOD_SIDT_LONGTERM) {
2443
+ if (tjd <= SIDT_LTERM_T0 || tjd >= SIDT_LTERM_T1) {
2444
+ gmst = sidtimeLongTerm(swed, tjd, eps, nut);
2445
+ if (tjd <= SIDT_LTERM_T0) gmst -= SIDT_LTERM_OFS0;
2446
+ else if (tjd >= SIDT_LTERM_T1) gmst -= SIDT_LTERM_OFS1;
2447
+ if (gmst >= 24) gmst -= 24;
2448
+ if (gmst < 0) gmst += 24;
2449
+ return gmst;
2450
+ }
2451
+ }
2452
+ /* Julian day at given UT */
2453
+ let jd0 = Math.floor(tjd);
2454
+ let secs = tjd - jd0;
2455
+ if (secs < 0.5) {
2456
+ jd0 -= 0.5;
2457
+ secs += 0.5;
2458
+ } else {
2459
+ jd0 += 0.5;
2460
+ secs -= 0.5;
2461
+ }
2462
+ secs *= 86400.0;
2463
+ const tu = (jd0 - J2000) / 36525.0; /* UT1 in centuries after J2000 */
2464
+ if (sidtModel === SEMOD_SIDT_IERS_CONV_2010 || sidtModel === SEMOD_SIDT_LONGTERM) {
2465
+ /* ERA-based expression for GST based on IAU 2006 precession */
2466
+ const jdrel = tjd - J2000;
2467
+ const tt = (tjd + sweDeltatEx(tjd, -1, swed) - J2000) / 36525.0;
2468
+ gmst = sweDegnorm((0.7790572732640 + 1.00273781191135448 * jdrel) * 360);
2469
+ gmst += (0.014506 + tt * (4612.156534 + tt * (1.3915817 + tt * (-0.00000044 + tt * (-0.000029956 + tt * -0.0000000368))))) / 3600.0;
2470
+ const dadd = sidtimeNonPolynomialPart(tt);
2471
+ gmst = sweDegnorm(gmst + dadd);
2472
+ gmst = gmst / 15.0 * 3600.0;
2473
+ } else if (sidtModel === SEMOD_SIDT_IAU_2006) {
2474
+ /* Capitaine, Wallace & Chapront 2003 */
2475
+ const tt = (jd0 + sweDeltatEx(jd0, -1, swed) - J2000) / 36525.0;
2476
+ gmst = (((-0.000000002454 * tt - 0.00000199708) * tt - 0.0000002926) * tt + 0.092772110) * tt * tt
2477
+ + 307.4771013 * (tt - tu) + 8640184.79447825 * tu + 24110.5493771;
2478
+ const msday = 1 + ((((-0.000000012270 * tt - 0.00000798832) * tt - 0.0000008778) * tt + 0.185544220) * tt + 8640184.79447825) / (86400.0 * 36525.0);
2479
+ gmst += msday * secs;
2480
+ } else {
2481
+ /* IAU 1976 formula */
2482
+ gmst = ((-6.2e-6 * tu + 9.3104e-2) * tu + 8640184.812866) * tu + 24110.54841;
2483
+ const msday = 1.0 + ((-1.86e-5 * tu + 0.186208) * tu + 8640184.812866) / (86400.0 * 36525.0);
2484
+ gmst += msday * secs;
2485
+ }
2486
+ /* equation of the equinoxes */
2487
+ const eqeq = 240.0 * nut * Math.cos(eps * DEGTORAD);
2488
+ gmst = gmst + eqeq;
2489
+ /* modulo 1 sidereal day */
2490
+ gmst = gmst - 86400.0 * Math.floor(gmst / 86400.0);
2491
+ /* return in hours */
2492
+ gmst /= 3600;
2493
+ return gmst;
2494
+ }
2495
+
2496
+ /**
2497
+ * Sidereal time without explicit eps/nut parameters.
2498
+ * tjdUt must be UT!
2499
+ */
2500
+ export function sweSidtime(swed: SweData, tjdUt: number): number {
2501
+ const tjde = tjdUt + sweDeltatEx(tjdUt, -1, swed);
2502
+ const eps = swiEpsiln(tjde, 0, swed) * RADTODEG;
2503
+ const nutlo = [0, 0];
2504
+ swiNutation(tjde, 0, nutlo, swed);
2505
+ nutlo[0] *= RADTODEG;
2506
+ nutlo[1] *= RADTODEG;
2507
+ return sweSidtime0(swed, tjdUt, eps + nutlo[1], nutlo[0]);
2508
+ }
2509
+
2510
+ /* ================================================================
2511
+ * 23. Ephemeris filename generation
2512
+ * ================================================================ */
2513
+
2514
+ /**
2515
+ * Generate the name of a Swiss Ephemeris .se1 file for a given Julian day
2516
+ * and internal planet number.
2517
+ */
2518
+ export function swiGenFilename(tjd: number, ipli: number): string {
2519
+ let fname: string;
2520
+ switch (ipli) {
2521
+ case SEI_MOON:
2522
+ fname = 'semo';
2523
+ break;
2524
+ case SEI_EMB:
2525
+ case SEI_MERCURY:
2526
+ case SEI_VENUS:
2527
+ case SEI_MARS:
2528
+ case SEI_JUPITER:
2529
+ case SEI_SATURN:
2530
+ case SEI_URANUS:
2531
+ case SEI_NEPTUNE:
2532
+ case SEI_PLUTO:
2533
+ case SEI_SUNBARY:
2534
+ fname = 'sepl';
2535
+ break;
2536
+ case SEI_CERES:
2537
+ case SEI_PALLAS:
2538
+ case SEI_JUNO:
2539
+ case SEI_VESTA:
2540
+ case SEI_CHIRON:
2541
+ case SEI_PHOLUS:
2542
+ fname = 'seas';
2543
+ break;
2544
+ default:
2545
+ /* asteroid or planetary moon */
2546
+ if (ipli > SE_PLMOON_OFFSET && ipli < SE_AST_OFFSET) {
2547
+ return `sepm${ipli}.${SE_FILE_SUFFIX}`;
2548
+ } else {
2549
+ const astNum = ipli - SE_AST_OFFSET;
2550
+ const dir = Math.trunc(astNum / 1000);
2551
+ if (astNum > 99999) {
2552
+ return `ast${dir}/s${String(astNum).padStart(6, '0')}.${SE_FILE_SUFFIX}`;
2553
+ } else {
2554
+ return `ast${dir}/se${String(astNum).padStart(5, '0')}.${SE_FILE_SUFFIX}`;
2555
+ }
2556
+ }
2557
+ }
2558
+ /* century of tjd */
2559
+ const gregflag = tjd >= 2305447.5;
2560
+ const { year: jyear } = revJulInternal(tjd, gregflag);
2561
+ /* start century of file containing tjd */
2562
+ const sgn = jyear < 0 ? -1 : 1;
2563
+ let icty = Math.trunc(jyear / 100);
2564
+ if (sgn < 0 && jyear % 100 !== 0) icty -= 1;
2565
+ const ncties = Math.trunc(NCTIES);
2566
+ while (icty % ncties !== 0) icty--;
2567
+ /* B.C. or A.D. */
2568
+ fname += icty < 0 ? 'm' : '_';
2569
+ const ictyAbs = Math.abs(icty);
2570
+ fname += String(ictyAbs).padStart(2, '0') + '.' + SE_FILE_SUFFIX;
2571
+ return fname;
2572
+ }
2573
+
2574
+ /**
2575
+ * Internal revJul for filename generation (avoids circular dependency).
2576
+ * Returns year from Julian day number.
2577
+ */
2578
+ function revJulInternal(tjd: number, gregflag: boolean): { year: number; month: number; day: number } {
2579
+ let b: number, c: number, d: number, e: number;
2580
+ const jd0 = tjd + 0.5;
2581
+ const z = Math.trunc(jd0);
2582
+ if (gregflag) {
2583
+ const a = Math.trunc((z - 1867216.25) / 36524.25);
2584
+ const aa = Math.trunc(a / 4);
2585
+ b = z + 1 + a - aa;
2586
+ } else {
2587
+ b = z;
2588
+ }
2589
+ c = b + 1524;
2590
+ d = Math.trunc((c - 122.1) / 365.25);
2591
+ e = Math.trunc(365.25 * d);
2592
+ const g = Math.trunc((c - e) / 30.6001);
2593
+ const day = c - e - Math.trunc(30.6001 * g);
2594
+ const month = g < 14 ? g - 1 : g - 13;
2595
+ const year = month > 2 ? d - 4716 : d - 4715;
2596
+ return { year, month, day };
2597
+ }
2598
+
2599
+ /* ==================================================================
2600
+ * Additional formatting / centisecond utilities
2601
+ * C: swe_difdegn, swe_difcs2n, swe_csroundsec,
2602
+ * swe_cs2timestr, swe_cs2lonlatstr, swe_cs2degstr
2603
+ * ================================================================== */
2604
+
2605
+ /** Distance in degrees normalized to [0, 360°). C: swe_difdegn */
2606
+ export function sweDifdegn(p1: number, p2: number): number {
2607
+ return sweDegnorm(p1 - p2);
2608
+ }
2609
+
2610
+ /** Distance in centiseconds normalized to [-180°, 180°). C: swe_difcs2n */
2611
+ export function sweDifcs2n(p1: number, p2: number): number {
2612
+ const dif = sweCsnorm(p1 - p2);
2613
+ if (dif >= 180 * 360000) return dif - 360 * 360000;
2614
+ return dif;
2615
+ }
2616
+
2617
+ /** Round centiseconds to whole seconds, avoiding rounding up to next sign. C: swe_csroundsec */
2618
+ export function sweCsroundsec(x: number): number {
2619
+ x = Math.trunc(x);
2620
+ let t = Math.trunc((x + 50) / 100) * 100;
2621
+ if (t > x && t % (30 * 360000) === 0)
2622
+ t = Math.trunc(x / 100) * 100;
2623
+ return t;
2624
+ }
2625
+
2626
+ /**
2627
+ * Centiseconds to time string "HH:MM:SS".
2628
+ * C: swe_cs2timestr (swephlib.c:3864-3886)
2629
+ */
2630
+ export function sweCs2timestr(t: number, sep: string, suppressZero: boolean): string {
2631
+ t = Math.trunc((Math.trunc(t) + 50) / 100) % (24 * 3600);
2632
+ const s = t % 60;
2633
+ const m = Math.trunc(t / 60) % 60;
2634
+ const h = Math.trunc(t / 3600) % 100;
2635
+ const hStr = String(h).padStart(2, '0');
2636
+ const mStr = String(m).padStart(2, '0');
2637
+ if (s === 0 && suppressZero)
2638
+ return `${hStr}${sep}${mStr}`;
2639
+ const sStr = String(s).padStart(2, '0');
2640
+ return `${hStr}${sep}${mStr}${sep}${sStr}`;
2641
+ }
2642
+
2643
+ /**
2644
+ * Centiseconds to longitude/latitude string "ddd°mm'ss".
2645
+ * C: swe_cs2lonlatstr (swephlib.c:3888-3916)
2646
+ */
2647
+ export function sweCs2lonlatstr(t: number, pchar: string, mchar: string): string {
2648
+ const sign = t < 0 ? mchar : pchar;
2649
+ t = Math.trunc((Math.abs(Math.trunc(t)) + 50) / 100);
2650
+ const s = t % 60;
2651
+ const m = Math.trunc(t / 60) % 60;
2652
+ const h = Math.trunc(t / 3600) % 1000;
2653
+ let result = `${h}${sign}${String(m).padStart(2, '0')}'`;
2654
+ if (s !== 0)
2655
+ result += String(s).padStart(2, '0');
2656
+ return result;
2657
+ }
2658
+
2659
+ /**
2660
+ * Centiseconds to degree string "dd°mm'ss".
2661
+ * C: swe_cs2degstr (swephlib.c:3918-3929)
2662
+ */
2663
+ export function sweCs2degstr(t: number): string {
2664
+ t = Math.trunc(Math.trunc(t) / 100) % (30 * 3600);
2665
+ const s = t % 60;
2666
+ const m = Math.trunc(t / 60) % 60;
2667
+ const h = Math.trunc(t / 3600) % 100;
2668
+ return `${String(h).padStart(2, ' ')}°${String(m).padStart(2, '0')}'${String(s).padStart(2, '0')}`;
2669
+ }
2670
+
2671
+ /* ================================================================
2672
+ * String utilities (from swephlib.c)
2673
+ * ================================================================ */
2674
+
2675
+ /**
2676
+ * Cut string at any character in cutlist; return array of partial strings.
2677
+ * Multiple consecutive separators count as one.
2678
+ * Newline/CR treated as end of string.
2679
+ * C: swi_cutstr (swephlib.c:3693-3722)
2680
+ */
2681
+ export function swiCutstr(s: string, cutlist: string, nmax: number = Infinity): string[] {
2682
+ const end = s.search(/[\r\n]/);
2683
+ if (end >= 0) s = s.substring(0, end);
2684
+ const re = new RegExp(`[${cutlist.replace(/[-[\]{}()*+?.,\\^$|#]/g, '\\$&')}]+`);
2685
+ const parts = s.split(re);
2686
+ if (nmax !== Infinity && parts.length > nmax) {
2687
+ const head = parts.slice(0, nmax - 1);
2688
+ const rest = parts.slice(nmax - 1).join(cutlist[0]);
2689
+ head.push(rest);
2690
+ return head;
2691
+ }
2692
+ return parts;
2693
+ }
2694
+
2695
+ /**
2696
+ * Right-trim whitespace from string.
2697
+ * C: swi_right_trim (swephlib.c:3724-3731)
2698
+ */
2699
+ export function swiRightTrim(s: string): string {
2700
+ return s.trimEnd();
2701
+ }
2702
+
2703
+ /**
2704
+ * Safe string copy (handles overlapping source/dest in C).
2705
+ * In JS strings are immutable values, so this is identity.
2706
+ * C: swi_strcpy (swephlib.c:4539-4559)
2707
+ */
2708
+ export function swiStrcpy(from: string): string {
2709
+ return from;
2710
+ }
2711
+
2712
+ /**
2713
+ * Open trace files for debugging.
2714
+ * No-op in TypeScript (C uses #ifdef TRACE with file I/O).
2715
+ * C: swi_open_trace (swephlib.c:4562-4633)
2716
+ */
2717
+ export function swiOpenTrace(_serr?: string): void {
2718
+ // In the C library this opens trace log files when compiled with TRACE.
2719
+ // Not applicable in TypeScript — use console.log for debugging.
2720
+ }