@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,823 @@
1
+ /* ================================================================
2
+ * SwissEph — Modern TypeScript wrapper for Swiss Ephemeris
3
+ *
4
+ * Hides C-style patterns (SweData threading, Float64Array returns,
5
+ * mutable output arrays, error codes) behind a clean class API
6
+ * with named return types, automatic UT/ET routing, and exceptions.
7
+ * ================================================================ */
8
+
9
+ import type { SweData } from '../types';
10
+ import { createDefaultSweData } from '../types';
11
+
12
+ import {
13
+ sweCalc, sweCalcUt, sweCalcPctr,
14
+ sweFixstar, sweFixstarUt, sweFixstarMag,
15
+ sweFixstar2, sweFixstar2Ut, sweFixstar2Mag,
16
+ sweSetSidMode, sweGetAyanamsaEx, sweGetAyanamsaExUt, sweGetAyanamsaName,
17
+ sweSetTopo, sweSetEphePath, sweSetEphemerisFile, sweLoadJplFile,
18
+ sweGetPlanetName, sweVersion, sweClose, sweTimeEqu,
19
+ sweSolcross, sweSolcrossUt, sweMooncross, sweMooncrossUt,
20
+ sweMooncrossNode, sweMooncrossNodeUt, sweHelioCross, sweHelioCrossUt,
21
+ sweDifdeg2n,
22
+ } from '../sweph';
23
+
24
+ import {
25
+ sweDeltatEx, sweSidtime, sweDegnorm, sweRadnorm,
26
+ sweDegMidp, sweRadMidp, sweCotrans, sweSplitDeg,
27
+ } from '../swephlib';
28
+
29
+ import {
30
+ sweHousesEx2, sweHousesArmcEx2, sweHousePos, sweHouseName,
31
+ } from '../swehouse';
32
+
33
+ import {
34
+ sweNodAps, sweNodApsUt,
35
+ sweGetOrbitalElements, sweOrbitMaxMinTrueDistance,
36
+ sweSolEclipseWhenGlob, sweSolEclipseWhere, sweSolEclipseHow, sweSolEclipseWhenLoc,
37
+ sweLunEclipseWhen, sweLunEclipseHow, sweLunEclipseWhenLoc,
38
+ sweLunOccultWhenGlob, sweLunOccultWhere, sweLunOccultWhenLoc,
39
+ sweRiseTrans, sweAzalt, sweAzaltRev,
40
+ swePheno, swePhenoUt,
41
+ sweGauquelinSector, sweRefrac,
42
+ } from '../swecl';
43
+
44
+ import {
45
+ sweHeliacalUt, sweHeliacalPhenoUt, sweVisLimitMag,
46
+ } from '../swehel';
47
+
48
+ import {
49
+ julDay, revJul, utcToJd, jdetToUtc, jdut1ToUtc, dayOfWeek,
50
+ } from '../swedate';
51
+
52
+ import {
53
+ SEFLG_MOSEPH, SEFLG_SWIEPH, SEFLG_JPLEPH, SEFLG_SPEED,
54
+ SEFLG_SIDEREAL, SEFLG_TOPOCTR,
55
+ SE_CALC_RISE, SE_CALC_SET, SE_CALC_MTRANSIT, SE_CALC_ITRANSIT,
56
+ SE_ECL2HOR, ERR, SE_GREG_CAL,
57
+ } from '../constants';
58
+
59
+ import { SwissEphError } from './errors';
60
+
61
+ import type {
62
+ GeoPosition, SwissEphOptions, RiseSetOptions, HeliacalOptions,
63
+ PlanetPosition, StarPosition, NodesApsides, OrbitalElements, OrbitDistances,
64
+ SolarEclipseGlobal, SolarEclipseLocal, SolarEclipseWhere, SolarEclipseHow,
65
+ LunarEclipseGlobal, LunarEclipseLocal, LunarEclipseHow,
66
+ OccultationGlobal, OccultationLocal, OccultationWhere,
67
+ EclipseAttributes,
68
+ RiseSetResult, PhenoResult,
69
+ AzaltResult, AzaltRevResult,
70
+ CrossingResult, MoonNodeCrossingResult,
71
+ HeliacalResult, HeliacalPhenoResult, VisualLimitResult,
72
+ GauquelinResult, HouseResult, SplitDegResult,
73
+ DateResult, UtcToJdResult, JdToUtcResult,
74
+ } from './types';
75
+
76
+ export { SwissEphError } from './errors';
77
+ export type * from './types';
78
+
79
+ /* ================================================================
80
+ * Helpers
81
+ * ================================================================ */
82
+
83
+ function posFromXx(flags: number, xx: Float64Array): PlanetPosition {
84
+ return {
85
+ longitude: xx[0], latitude: xx[1], distance: xx[2],
86
+ longitudeSpeed: xx[3], latitudeSpeed: xx[4], distanceSpeed: xx[5],
87
+ flags,
88
+ };
89
+ }
90
+
91
+ function posFrom6(arr: number[]): PlanetPosition {
92
+ return {
93
+ longitude: arr[0], latitude: arr[1], distance: arr[2],
94
+ longitudeSpeed: arr[3], latitudeSpeed: arr[4], distanceSpeed: arr[5],
95
+ flags: 0,
96
+ };
97
+ }
98
+
99
+ function geoArr(geo: GeoPosition): number[] {
100
+ return [geo.longitude, geo.latitude, geo.altitude ?? 0];
101
+ }
102
+
103
+ function mapEclAttr(attr: number[]): EclipseAttributes {
104
+ return {
105
+ fraction: attr[0], ratio: attr[1], magnitude: attr[2],
106
+ sarosCycle: attr[3], sarosMember: attr[4],
107
+ solarDiameter: attr[5], lunarDiameter: attr[6],
108
+ sarosRepetition: attr[7], eclipseLongitude: attr[8],
109
+ eclipseLatitude: attr[9], eclipseMagnitude: attr[10],
110
+ sunAltitude: attr[11],
111
+ };
112
+ }
113
+
114
+ /* ================================================================
115
+ * SwissEph class
116
+ * ================================================================ */
117
+
118
+ export class SwissEph {
119
+ /** Internal engine state — exposed for advanced / escape-hatch use */
120
+ readonly swed: SweData;
121
+ private timeMode: 'ut' | 'et';
122
+ private ephemerisFlag: number;
123
+
124
+ constructor(options?: SwissEphOptions) {
125
+ this.swed = createDefaultSweData();
126
+ this.timeMode = options?.timeMode ?? 'ut';
127
+
128
+ switch (options?.ephemeris) {
129
+ case 'swisseph': this.ephemerisFlag = SEFLG_SWIEPH; break;
130
+ case 'jpl': this.ephemerisFlag = SEFLG_JPLEPH; break;
131
+ default: this.ephemerisFlag = SEFLG_MOSEPH; break;
132
+ }
133
+
134
+ if (options?.siderealMode != null) {
135
+ sweSetSidMode(this.swed, options.siderealMode,
136
+ options.siderealT0 ?? 0, options.siderealAyanT0 ?? 0);
137
+ }
138
+ if (options?.topo) {
139
+ sweSetTopo(this.swed,
140
+ options.topo.longitude, options.topo.latitude, options.topo.altitude ?? 0);
141
+ }
142
+ }
143
+
144
+ /** Release internal resources. The instance should not be used after this. */
145
+ close(): void {
146
+ sweClose(this.swed);
147
+ }
148
+
149
+ /* ---------- flag helpers ---------- */
150
+
151
+ private flags(extra: number = 0): number {
152
+ return this.ephemerisFlag | SEFLG_SPEED | extra;
153
+ }
154
+
155
+ private get isUt(): boolean { return this.timeMode === 'ut'; }
156
+
157
+ /* ==============================================================
158
+ * Core Calculation
159
+ * ============================================================== */
160
+
161
+ /** Calculate position of a planet / object. */
162
+ calc(jd: number, planet: number, flags: number = 0): PlanetPosition {
163
+ const f = this.flags(flags);
164
+ const r = this.isUt
165
+ ? sweCalcUt(this.swed, jd, planet, f)
166
+ : sweCalc(this.swed, jd, planet, f);
167
+ if (r.flags === ERR) throw new SwissEphError(r.serr || 'calc failed');
168
+ return posFromXx(r.flags, r.xx);
169
+ }
170
+
171
+ /** Calculate position of a planet as seen from another planet (planetocentric). */
172
+ calcPlanetocentric(jd: number, planet: number, center: number, flags: number = 0): PlanetPosition {
173
+ const f = this.flags(flags);
174
+ const r = sweCalcPctr(this.swed, jd, planet, center, f);
175
+ if (r.flags === ERR) throw new SwissEphError(r.serr || 'calcPctr failed');
176
+ return posFromXx(r.flags, r.xx);
177
+ }
178
+
179
+ /** Calculate position of a fixed star. */
180
+ fixedStar(star: string, jd: number, flags: number = 0): StarPosition {
181
+ const f = this.flags(flags);
182
+ const r = this.isUt
183
+ ? sweFixstarUt(this.swed, star, jd, f)
184
+ : sweFixstar(this.swed, star, jd, f);
185
+ if (r.flags === ERR) throw new SwissEphError(r.serr || 'fixedStar failed');
186
+ return { ...posFromXx(r.flags, r.xx), starName: r.starOut };
187
+ }
188
+
189
+ /** Calculate position of a fixed star (using fixstar2 variant). */
190
+ fixedStar2(star: string, jd: number, flags: number = 0): StarPosition {
191
+ const f = this.flags(flags);
192
+ const r = this.isUt
193
+ ? sweFixstar2Ut(this.swed, star, jd, f)
194
+ : sweFixstar2(this.swed, star, jd, f);
195
+ if (r.flags === ERR) throw new SwissEphError(r.serr || 'fixedStar2 failed');
196
+ return { ...posFromXx(r.flags, r.xx), starName: r.starOut };
197
+ }
198
+
199
+ /** Get the magnitude of a fixed star. */
200
+ fixedStarMagnitude(star: string): number {
201
+ const r = sweFixstarMag(this.swed, star);
202
+ if (r.serr) throw new SwissEphError(r.serr);
203
+ return r.mag;
204
+ }
205
+
206
+ /** Calculate planetary nodes and apsides (perihelion/aphelion). */
207
+ nodesApsides(jd: number, planet: number, method: number = 0, flags: number = 0): NodesApsides {
208
+ const f = this.flags(flags);
209
+ const r = this.isUt
210
+ ? sweNodApsUt(this.swed, jd, planet, f, method)
211
+ : sweNodAps(this.swed, jd, planet, f, method);
212
+ if (r.retval === ERR) throw new SwissEphError(r.serr || 'nodesApsides failed');
213
+ return {
214
+ ascendingNode: posFrom6(r.xnasc),
215
+ descendingNode: posFrom6(r.xndsc),
216
+ perihelion: posFrom6(r.xperi),
217
+ aphelion: posFrom6(r.xaphe),
218
+ };
219
+ }
220
+
221
+ /** Get orbital elements for a planet. */
222
+ orbitalElements(jd: number, planet: number, flags: number = 0): OrbitalElements {
223
+ const f = this.flags(flags);
224
+ const r = sweGetOrbitalElements(this.swed, jd, planet, f);
225
+ if (r.retval === ERR) throw new SwissEphError(r.serr || 'orbitalElements failed');
226
+ const d = r.dret;
227
+ return {
228
+ semiAxis: d[0], eccentricity: d[1], inclination: d[2],
229
+ ascNode: d[3], argPerihelion: d[4], longPerihelion: d[5],
230
+ meanAnomaly: d[6], meanLongitude: d[7], dailyMotion: d[8],
231
+ tropicalPeriod: d[9], synodicPeriod: d[10],
232
+ meanDailyMotion: d[11], meanLongJ2000: d[12], meanLongOfDate: d[13],
233
+ meanLongSpeed: d[14], nodeJ2000: d[15], nodeOfDate: d[16],
234
+ nodeSpeed: d[17], perihelionJ2000: d[18], perihelionOfDate: d[19],
235
+ perihelionSpeed: d[20],
236
+ };
237
+ }
238
+
239
+ /** Get maximum, minimum, and true distance of an orbit. */
240
+ orbitDistances(jd: number, planet: number, flags: number = 0): OrbitDistances {
241
+ const f = this.flags(flags);
242
+ const r = sweOrbitMaxMinTrueDistance(this.swed, jd, planet, f);
243
+ if (r.retval === ERR) throw new SwissEphError(r.serr || 'orbitDistances failed');
244
+ return { max: r.dmax, min: r.dmin, true: r.dtrue };
245
+ }
246
+
247
+ /* ==============================================================
248
+ * Ayanamsa
249
+ * ============================================================== */
250
+
251
+ /** Get ayanamsa value for a given Julian day. */
252
+ getAyanamsa(jd: number, flags: number = 0): number {
253
+ const f = this.ephemerisFlag | flags;
254
+ const r = this.isUt
255
+ ? sweGetAyanamsaExUt(this.swed, jd, f)
256
+ : sweGetAyanamsaEx(this.swed, jd, f);
257
+ if (r.retc === ERR) throw new SwissEphError(r.serr || 'getAyanamsa failed');
258
+ return r.daya;
259
+ }
260
+
261
+ /** Set sidereal mode (ayanamsa system). */
262
+ setSiderealMode(mode: number, t0: number = 0, ayanT0: number = 0): void {
263
+ sweSetSidMode(this.swed, mode, t0, ayanT0);
264
+ }
265
+
266
+ /** Get the name of a sidereal mode. */
267
+ getAyanamsaName(mode: number): string {
268
+ return sweGetAyanamsaName(mode);
269
+ }
270
+
271
+ /* ==============================================================
272
+ * Houses
273
+ * ============================================================== */
274
+
275
+ /** Calculate house cusps and angles. */
276
+ houses(jd: number, geo: GeoPosition, system: string = 'P', flags: number = 0): HouseResult {
277
+ const f = this.ephemerisFlag | flags;
278
+ const cusp: number[] = new Array(37).fill(0);
279
+ const ascmc: number[] = new Array(10).fill(0);
280
+ const cuspSpeed: number[] = new Array(37).fill(0);
281
+ const ascmcSpeed: number[] = new Array(10).fill(0);
282
+ const serr = { value: '' };
283
+ sweHousesEx2(this.swed, jd, f, geo.latitude, geo.longitude, system,
284
+ cusp, ascmc, cuspSpeed, ascmcSpeed, serr);
285
+ return {
286
+ cusps: cusp,
287
+ ascendant: ascmc[0],
288
+ mc: ascmc[1],
289
+ armc: ascmc[2],
290
+ vertex: ascmc[3],
291
+ equatorialAscendant: ascmc[4],
292
+ coAscendantKoch: ascmc[5],
293
+ coAscendantMunkasey: ascmc[6],
294
+ polarAscendant: ascmc[7],
295
+ };
296
+ }
297
+
298
+ /** Calculate houses from ARMC (sidereal time in degrees). */
299
+ housesFromArmc(armc: number, lat: number, eps: number, system: string = 'P'): HouseResult {
300
+ const cusp: number[] = new Array(37).fill(0);
301
+ const ascmc: number[] = new Array(10).fill(0);
302
+ const serr = { value: '' };
303
+ sweHousesArmcEx2(armc, lat, eps, system, cusp, ascmc, null, null, serr);
304
+ return {
305
+ cusps: cusp,
306
+ ascendant: ascmc[0],
307
+ mc: ascmc[1],
308
+ armc: ascmc[2],
309
+ vertex: ascmc[3],
310
+ equatorialAscendant: ascmc[4],
311
+ coAscendantKoch: ascmc[5],
312
+ coAscendantMunkasey: ascmc[6],
313
+ polarAscendant: ascmc[7],
314
+ };
315
+ }
316
+
317
+ /** Get the house position (1.0–12.999…) of a body. */
318
+ housePosition(armc: number, lat: number, eps: number, system: string,
319
+ eclLon: number, eclLat: number): number {
320
+ const serr = { value: '' };
321
+ const pos = sweHousePos(armc, lat, eps, system, [eclLon, eclLat], serr);
322
+ if (pos === 0 && serr.value) throw new SwissEphError(serr.value);
323
+ return pos;
324
+ }
325
+
326
+ /** Get the name of a house system. */
327
+ houseName(system: string): string {
328
+ return sweHouseName(system);
329
+ }
330
+
331
+ /* ==============================================================
332
+ * Solar Eclipses
333
+ * ============================================================== */
334
+
335
+ /** Find the next global solar eclipse after jd. */
336
+ solarEclipseGlobal(jd: number, type: number = 0, backward: boolean = false): SolarEclipseGlobal {
337
+ const r = sweSolEclipseWhenGlob(this.swed, jd, this.ephemerisFlag, type, backward ? 1 : 0);
338
+ if (r.retval === ERR) throw new SwissEphError('solarEclipseGlobal failed');
339
+ return {
340
+ type: r.retval,
341
+ maximum: r.tret[0], first: r.tret[1], second: r.tret[2],
342
+ third: r.tret[3], fourth: r.tret[4],
343
+ sunrise: r.tret[5], sunset: r.tret[6],
344
+ };
345
+ }
346
+
347
+ /** Find the next local solar eclipse after jd. */
348
+ solarEclipseLocal(jd: number, geo: GeoPosition, backward: boolean = false): SolarEclipseLocal {
349
+ const r = sweSolEclipseWhenLoc(this.swed, jd, this.ephemerisFlag, geoArr(geo), backward ? 1 : 0);
350
+ if (r.retval === ERR) throw new SwissEphError('solarEclipseLocal failed');
351
+ return {
352
+ type: r.retval,
353
+ maximum: r.tret[0], firstContact: r.tret[1], secondContact: r.tret[2],
354
+ thirdContact: r.tret[3], fourthContact: r.tret[4],
355
+ attributes: mapEclAttr(r.attr),
356
+ };
357
+ }
358
+
359
+ /** Calculate geographic coordinates of central line for a solar eclipse at jd. */
360
+ solarEclipseWhere(jd: number): SolarEclipseWhere {
361
+ const r = sweSolEclipseWhere(this.swed, jd, this.ephemerisFlag);
362
+ if (r.retval === ERR) throw new SwissEphError('solarEclipseWhere failed');
363
+ return {
364
+ type: r.retval,
365
+ geopos: { longitude: r.geopos[0], latitude: r.geopos[1] },
366
+ attributes: mapEclAttr(r.attr),
367
+ };
368
+ }
369
+
370
+ /** Calculate attributes of a solar eclipse for a geographic position. */
371
+ solarEclipseHow(jd: number, geo: GeoPosition): SolarEclipseHow {
372
+ const r = sweSolEclipseHow(this.swed, jd, this.ephemerisFlag, geoArr(geo));
373
+ if (r.retval === ERR) throw new SwissEphError('solarEclipseHow failed');
374
+ return { type: r.retval, attributes: mapEclAttr(r.attr) };
375
+ }
376
+
377
+ /* ==============================================================
378
+ * Lunar Eclipses
379
+ * ============================================================== */
380
+
381
+ /** Find the next global lunar eclipse after jd. */
382
+ lunarEclipseGlobal(jd: number, type: number = 0, backward: boolean = false): LunarEclipseGlobal {
383
+ const r = sweLunEclipseWhen(this.swed, jd, this.ephemerisFlag, type, backward ? 1 : 0);
384
+ if (r.retval === ERR) throw new SwissEphError('lunarEclipseGlobal failed');
385
+ return {
386
+ type: r.retval,
387
+ maximum: r.tret[0],
388
+ partialBegin: r.tret[2], partialEnd: r.tret[3],
389
+ totalBegin: r.tret[4], totalEnd: r.tret[5],
390
+ penumbralBegin: r.tret[6], penumbralEnd: r.tret[7],
391
+ };
392
+ }
393
+
394
+ /** Calculate attributes of a lunar eclipse at jd. */
395
+ lunarEclipseHow(jd: number, geo?: GeoPosition): LunarEclipseHow {
396
+ const r = sweLunEclipseHow(this.swed, jd, this.ephemerisFlag, geo ? geoArr(geo) : null);
397
+ if (r.retval === ERR) throw new SwissEphError('lunarEclipseHow failed');
398
+ return {
399
+ type: r.retval,
400
+ umbraMagnitude: r.attr[0], penumbraMagnitude: r.attr[1],
401
+ moonDiameter: r.attr[5], umbraDiameter: r.attr[6],
402
+ penumbraDiameter: r.attr[7], sunDistanceFromNode: r.attr[8],
403
+ };
404
+ }
405
+
406
+ /** Find the next local lunar eclipse after jd. */
407
+ lunarEclipseLocal(jd: number, geo: GeoPosition, backward: boolean = false): LunarEclipseLocal {
408
+ const r = sweLunEclipseWhenLoc(this.swed, jd, this.ephemerisFlag, geoArr(geo), backward ? 1 : 0);
409
+ if (r.retval === ERR) throw new SwissEphError('lunarEclipseLocal failed');
410
+ const how = sweLunEclipseHow(this.swed, r.tret[0], this.ephemerisFlag, geoArr(geo));
411
+ return {
412
+ type: r.retval,
413
+ maximum: r.tret[0],
414
+ partialBegin: r.tret[2], partialEnd: r.tret[3],
415
+ totalBegin: r.tret[4], totalEnd: r.tret[5],
416
+ penumbralBegin: r.tret[6], penumbralEnd: r.tret[7],
417
+ moonRise: r.tret[8], moonSet: r.tret[9],
418
+ attributes: {
419
+ type: how.retval,
420
+ umbraMagnitude: how.attr[0], penumbraMagnitude: how.attr[1],
421
+ moonDiameter: how.attr[5], umbraDiameter: how.attr[6],
422
+ penumbraDiameter: how.attr[7], sunDistanceFromNode: how.attr[8],
423
+ },
424
+ };
425
+ }
426
+
427
+ /* ==============================================================
428
+ * Occultations
429
+ * ============================================================== */
430
+
431
+ /** Find the next global occultation of a planet/star by the Moon. */
432
+ occultationGlobal(jd: number, planet: number, starname: string | null = null,
433
+ type: number = 0, backward: boolean = false): OccultationGlobal {
434
+ const r = sweLunOccultWhenGlob(this.swed, jd, planet, starname,
435
+ this.ephemerisFlag, type, backward ? 1 : 0);
436
+ if (r.retval === ERR) throw new SwissEphError('occultationGlobal failed');
437
+ return {
438
+ type: r.retval,
439
+ maximum: r.tret[0], first: r.tret[1], second: r.tret[2],
440
+ third: r.tret[3], fourth: r.tret[4],
441
+ sunrise: r.tret[5], sunset: r.tret[6],
442
+ };
443
+ }
444
+
445
+ /** Find the next local occultation at a geographic position. */
446
+ occultationLocal(jd: number, planet: number, geo: GeoPosition,
447
+ starname: string | null = null, backward: boolean = false): OccultationLocal {
448
+ const r = sweLunOccultWhenLoc(this.swed, jd, planet, starname,
449
+ this.ephemerisFlag, geoArr(geo), backward ? 1 : 0);
450
+ if (r.retval === ERR) throw new SwissEphError('occultationLocal failed');
451
+ return {
452
+ type: r.retval,
453
+ maximum: r.tret[0], firstContact: r.tret[1], secondContact: r.tret[2],
454
+ thirdContact: r.tret[3], fourthContact: r.tret[4],
455
+ attributes: mapEclAttr(r.attr),
456
+ };
457
+ }
458
+
459
+ /** Calculate geographic coordinates of an occultation at jd. */
460
+ occultationWhere(jd: number, planet: number, starname: string | null = null): OccultationWhere {
461
+ const r = sweLunOccultWhere(this.swed, jd, planet, starname, this.ephemerisFlag);
462
+ if (r.retval === ERR) throw new SwissEphError('occultationWhere failed');
463
+ return {
464
+ type: r.retval,
465
+ geopos: { longitude: r.geopos[0], latitude: r.geopos[1] },
466
+ attributes: mapEclAttr(r.attr),
467
+ };
468
+ }
469
+
470
+ /* ==============================================================
471
+ * Rise / Set / Transit
472
+ * ============================================================== */
473
+
474
+ /** Find the next rise of a planet after jd. */
475
+ rise(jd: number, planet: number, geo: GeoPosition, options?: RiseSetOptions): RiseSetResult {
476
+ return this.riseSetTransit(jd, planet, geo, SE_CALC_RISE, options);
477
+ }
478
+
479
+ /** Find the next set of a planet after jd. */
480
+ set(jd: number, planet: number, geo: GeoPosition, options?: RiseSetOptions): RiseSetResult {
481
+ return this.riseSetTransit(jd, planet, geo, SE_CALC_SET, options);
482
+ }
483
+
484
+ /** Find the next upper meridian transit of a planet after jd. */
485
+ transit(jd: number, planet: number, geo: GeoPosition, options?: RiseSetOptions): RiseSetResult {
486
+ return this.riseSetTransit(jd, planet, geo, SE_CALC_MTRANSIT, options);
487
+ }
488
+
489
+ /** Find the next lower meridian transit of a planet after jd. */
490
+ antiTransit(jd: number, planet: number, geo: GeoPosition, options?: RiseSetOptions): RiseSetResult {
491
+ return this.riseSetTransit(jd, planet, geo, SE_CALC_ITRANSIT, options);
492
+ }
493
+
494
+ private riseSetTransit(jd: number, planet: number, geo: GeoPosition,
495
+ rsmi: number, options?: RiseSetOptions): RiseSetResult {
496
+ const serr = { value: '' };
497
+ const r = sweRiseTrans(this.swed, jd, planet, null, this.ephemerisFlag,
498
+ rsmi | (options?.flags ?? 0),
499
+ geoArr(geo), options?.pressure ?? 1013.25, options?.temperature ?? 15, serr);
500
+ if (r.retval === ERR) throw new SwissEphError(serr.value || 'rise/set/transit failed');
501
+ return { jd: r.tret };
502
+ }
503
+
504
+ /* ==============================================================
505
+ * Horizon Coordinates
506
+ * ============================================================== */
507
+
508
+ /** Convert ecliptic/equatorial coordinates to azimuth/altitude. */
509
+ azalt(jd: number, geo: GeoPosition, lon: number, lat: number, dist: number = 1,
510
+ calcFlag: number = SE_ECL2HOR, pressure: number = 1013.25, temperature: number = 15): AzaltResult {
511
+ const xaz: number[] = [0, 0, 0];
512
+ sweAzalt(this.swed, jd, calcFlag, geoArr(geo), pressure, temperature,
513
+ [lon, lat, dist], xaz);
514
+ return { azimuth: xaz[0], trueAltitude: xaz[1], apparentAltitude: xaz[2] };
515
+ }
516
+
517
+ /** Convert azimuth/altitude back to ecliptic/equatorial. */
518
+ azaltReverse(jd: number, geo: GeoPosition, azimuth: number, altitude: number,
519
+ calcFlag: number = SE_ECL2HOR): AzaltRevResult {
520
+ const xout: number[] = [0, 0];
521
+ sweAzaltRev(this.swed, jd, calcFlag, geoArr(geo), [azimuth, altitude], xout);
522
+ return { azimuth: xout[0], altitude: xout[1] };
523
+ }
524
+
525
+ /* ==============================================================
526
+ * Phenomena
527
+ * ============================================================== */
528
+
529
+ /** Calculate planetary phenomena (phase angle, elongation, etc.). */
530
+ phenomena(jd: number, planet: number, flags: number = 0): PhenoResult {
531
+ const f = this.ephemerisFlag | flags;
532
+ const serr = { value: '' };
533
+ const r = this.isUt
534
+ ? swePhenoUt(this.swed, jd, planet, f, serr)
535
+ : swePheno(this.swed, jd, planet, f, serr);
536
+ if (r.retval === ERR) throw new SwissEphError(serr.value || 'phenomena failed');
537
+ return {
538
+ phaseAngle: r.attr[0], phase: r.attr[1], elongation: r.attr[2],
539
+ apparentDiameter: r.attr[3], apparentMagnitude: r.attr[4],
540
+ };
541
+ }
542
+
543
+ /** Calculate Gauquelin sector position of a planet. */
544
+ gauquelinSector(jd: number, planet: number, geo: GeoPosition,
545
+ method: number = 0, pressure: number = 1013.25, temperature: number = 15): GauquelinResult {
546
+ const serr = { value: '' };
547
+ const r = sweGauquelinSector(this.swed, jd, planet, null, this.ephemerisFlag,
548
+ method, geoArr(geo), pressure, temperature, serr);
549
+ if (r.retval === ERR) throw new SwissEphError(serr.value || 'gauquelinSector failed');
550
+ return { sector: r.dgsect };
551
+ }
552
+
553
+ /* ==============================================================
554
+ * Crossings
555
+ * ============================================================== */
556
+
557
+ /** Find the next time the Sun crosses a given ecliptic longitude. */
558
+ sunCrossing(longitude: number, jd: number, flags: number = 0): CrossingResult {
559
+ const f = this.flags(flags);
560
+ const r = this.isUt
561
+ ? sweSolcrossUt(this.swed, longitude, jd, f)
562
+ : sweSolcross(this.swed, longitude, jd, f);
563
+ if (r.jd < jd - 0.5) throw new SwissEphError(r.serr || 'sunCrossing failed');
564
+ return { jd: r.jd };
565
+ }
566
+
567
+ /** Find the next time the Moon crosses a given ecliptic longitude. */
568
+ moonCrossing(longitude: number, jd: number, flags: number = 0): CrossingResult {
569
+ const f = this.flags(flags);
570
+ const r = this.isUt
571
+ ? sweMooncrossUt(this.swed, longitude, jd, f)
572
+ : sweMooncross(this.swed, longitude, jd, f);
573
+ if (r.jd < jd - 0.5) throw new SwissEphError(r.serr || 'moonCrossing failed');
574
+ return { jd: r.jd };
575
+ }
576
+
577
+ /** Find the next time the Moon crosses the ecliptic (node crossing). */
578
+ moonNodeCrossing(jd: number, flags: number = 0): MoonNodeCrossingResult {
579
+ const f = this.flags(flags);
580
+ const r = this.isUt
581
+ ? sweMooncrossNodeUt(this.swed, jd, f)
582
+ : sweMooncrossNode(this.swed, jd, f);
583
+ if (r.jd < jd - 0.5) throw new SwissEphError(r.serr || 'moonNodeCrossing failed');
584
+ return { jd: r.jd, longitude: r.xlon, latitude: r.xlat };
585
+ }
586
+
587
+ /** Find the next time a planet crosses a heliocentric longitude. */
588
+ helioCrossing(planet: number, longitude: number, jd: number, flags: number = 0, dir: number = 0): CrossingResult {
589
+ const f = this.flags(flags);
590
+ const r = this.isUt
591
+ ? sweHelioCrossUt(this.swed, planet, longitude, jd, f, dir)
592
+ : sweHelioCross(this.swed, planet, longitude, jd, f, dir);
593
+ if (r.jdCross < jd - 0.5) throw new SwissEphError(r.serr || 'helioCrossing failed');
594
+ return { jd: r.jdCross };
595
+ }
596
+
597
+ /* ==============================================================
598
+ * Heliacal Events
599
+ * ============================================================== */
600
+
601
+ /** Find the next heliacal rising/setting event. */
602
+ heliacalEvent(jd: number, geo: GeoPosition, object: string,
603
+ eventType: number, options?: HeliacalOptions): HeliacalResult {
604
+ const { datm, dobs, helflag } = this.heliacalParams(options);
605
+ const r = sweHeliacalUt(this.swed, jd, geoArr(geo), datm, dobs,
606
+ object, eventType, helflag);
607
+ if (r.retval === ERR) throw new SwissEphError(r.serr || 'heliacalEvent failed');
608
+ return {
609
+ startVisible: r.dret[0], bestVisible: r.dret[1], endVisible: r.dret[2],
610
+ };
611
+ }
612
+
613
+ /** Calculate heliacal phenomena (detailed arc of vision etc.). */
614
+ heliacalPhenomena(jd: number, geo: GeoPosition, object: string,
615
+ eventType: number, options?: HeliacalOptions): HeliacalPhenoResult {
616
+ const { datm, dobs, helflag } = this.heliacalParams(options);
617
+ const r = sweHeliacalPhenoUt(this.swed, jd, geoArr(geo), datm, dobs,
618
+ object, eventType, helflag);
619
+ if (r.retval === ERR) throw new SwissEphError(r.serr || 'heliacalPhenomena failed');
620
+ const d = r.darr;
621
+ return {
622
+ raw: d,
623
+ tcrescent: d[0], tcrescentBest: d[1], tcrescent3: d[2],
624
+ elong: d[3], elongBest: d[4], eDistArcVis: d[5],
625
+ altObj: d[6], azObj: d[7], altSun: d[8], azSun: d[9],
626
+ altMoon: d[10], azMoon: d[11], elongMoon: d[12],
627
+ };
628
+ }
629
+
630
+ /** Calculate the visual limiting magnitude at a given time/place. */
631
+ visualLimitMagnitude(jd: number, geo: GeoPosition, object: string,
632
+ options?: HeliacalOptions): VisualLimitResult {
633
+ const { datm, dobs, helflag } = this.heliacalParams(options);
634
+ const r = sweVisLimitMag(this.swed, jd, geoArr(geo), datm, dobs, object, helflag);
635
+ if (r.retval === ERR) throw new SwissEphError(r.serr || 'visualLimitMag failed');
636
+ return {
637
+ limitingMagnitude: r.dret[0],
638
+ altObject: r.dret[1], azObject: r.dret[2],
639
+ altSun: r.dret[3], azSun: r.dret[4],
640
+ altMoon: r.dret[5], azMoon: r.dret[6],
641
+ elongMoon: r.dret[7],
642
+ };
643
+ }
644
+
645
+ private heliacalParams(options?: HeliacalOptions) {
646
+ const datm = [
647
+ options?.pressure ?? 1013.25,
648
+ options?.temperature ?? 15,
649
+ options?.humidity ?? 40,
650
+ options?.extinction ?? 0.25,
651
+ ];
652
+ const dobs = [
653
+ options?.acuity ?? 1,
654
+ options?.acuity ?? 1,
655
+ options?.observerAge ?? 36,
656
+ 0, 0, 0,
657
+ ];
658
+ const helflag = this.ephemerisFlag | (options?.flags ?? 0);
659
+ return { datm, dobs, helflag };
660
+ }
661
+
662
+ /* ==============================================================
663
+ * Configuration
664
+ * ============================================================== */
665
+
666
+ /** Set topocentric observer position. */
667
+ setTopo(geo: GeoPosition): void {
668
+ sweSetTopo(this.swed, geo.longitude, geo.latitude, geo.altitude ?? 0);
669
+ }
670
+
671
+ /** Set the ephemeris file search path. */
672
+ setEphePath(path: string): void {
673
+ sweSetEphePath(this.swed, path);
674
+ }
675
+
676
+ /** Load an SE1 binary ephemeris file from an ArrayBuffer. */
677
+ loadEphemerisFile(data: ArrayBuffer, name: string): void {
678
+ sweSetEphemerisFile(name, data, this.swed);
679
+ }
680
+
681
+ /** Load a JPL binary ephemeris file from an ArrayBuffer. */
682
+ loadJplFile(data: ArrayBuffer, name?: string): void {
683
+ const r = sweLoadJplFile(this.swed, data, name);
684
+ if (r.retc === ERR) throw new SwissEphError(r.serr || 'loadJplFile failed');
685
+ }
686
+
687
+ /** Set tidal acceleration value. */
688
+ setTidalAcceleration(value: number): void {
689
+ (this.swed as SweData).tidAcc = value;
690
+ (this.swed as SweData).isTidAccManual = true;
691
+ }
692
+
693
+ /** Set a user-defined delta-T value. */
694
+ setDeltaTUserDefined(value: number): void {
695
+ (this.swed as SweData).deltaTUserdefIsSet = true;
696
+ (this.swed as SweData).deltaTUserdef = value;
697
+ }
698
+
699
+ /** Set nutation interpolation on or off. */
700
+ setInterpolateNutation(enable: boolean): void {
701
+ (this.swed as SweData).doInterpolateNut = enable;
702
+ }
703
+
704
+ /* ==============================================================
705
+ * Utility (instance)
706
+ * ============================================================== */
707
+
708
+ /** Get the name of a planet/object by its number. */
709
+ getPlanetName(planet: number): string {
710
+ return sweGetPlanetName(planet, this.swed);
711
+ }
712
+
713
+ /** Get delta-T for a Julian day. */
714
+ deltaT(jd: number, flags: number = -1): number {
715
+ return sweDeltatEx(jd, flags, this.swed);
716
+ }
717
+
718
+ /** Get sidereal time for a Julian day (UT). Returns hours. */
719
+ siderealTime(jd: number): number {
720
+ return sweSidtime(this.swed, jd);
721
+ }
722
+
723
+ /** Get the equation of time (difference between apparent and mean solar time). */
724
+ timeEquation(jd: number): number {
725
+ const r = sweTimeEqu(this.swed, jd);
726
+ if (r.retc === ERR) throw new SwissEphError(r.serr || 'timeEquation failed');
727
+ return r.e;
728
+ }
729
+
730
+ /** Calculate atmospheric refraction. */
731
+ refraction(altitude: number, pressure: number, temperature: number, flag: number): number {
732
+ return sweRefrac(altitude, pressure, temperature, flag);
733
+ }
734
+
735
+ /** Split a degree value into degrees, minutes, seconds, sign. */
736
+ splitDegrees(value: number, flags: number): SplitDegResult {
737
+ return sweSplitDeg(value, flags);
738
+ }
739
+
740
+ /** Normalize a degree difference to [-180, 180). */
741
+ difDeg2n(p1: number, p2: number): number {
742
+ return sweDifdeg2n(p1, p2);
743
+ }
744
+
745
+ /* ==============================================================
746
+ * Date/Time (static)
747
+ * ============================================================== */
748
+
749
+ /** Convert a calendar date to Julian Day number. */
750
+ static julianDay(y: number, m: number, d: number, h: number = 0,
751
+ gregflag: number = SE_GREG_CAL): number {
752
+ return julDay(y, m, d, h, gregflag);
753
+ }
754
+
755
+ /** Convert a Julian Day number to calendar date components. */
756
+ static fromJulianDay(jd: number, gregflag: number = SE_GREG_CAL): DateResult {
757
+ return revJul(jd, gregflag);
758
+ }
759
+
760
+ /** Convert UTC date/time components to Julian Day numbers (ET and UT). */
761
+ static utcToJd(y: number, m: number, d: number, h: number, min: number, sec: number,
762
+ gregflag: number = SE_GREG_CAL): UtcToJdResult {
763
+ // utcToJd needs a deltatEx callback — create a temporary SweData for it
764
+ const tmpSwed = createDefaultSweData();
765
+ return utcToJd(y, m, d, h, min, sec, gregflag,
766
+ (tjd, iflag) => sweDeltatEx(tjd, iflag, tmpSwed));
767
+ }
768
+
769
+ /** Convert Julian Day (ET) to UTC date/time components. */
770
+ static jdToUtc(jdEt: number, gregflag: number = SE_GREG_CAL): JdToUtcResult {
771
+ const tmpSwed = createDefaultSweData();
772
+ return jdetToUtc(jdEt, gregflag,
773
+ (tjd, iflag) => sweDeltatEx(tjd, iflag, tmpSwed));
774
+ }
775
+
776
+ /** Convert Julian Day (UT) to UTC date/time components. */
777
+ static jdUtToUtc(jdUt: number, gregflag: number = SE_GREG_CAL): JdToUtcResult {
778
+ const tmpSwed = createDefaultSweData();
779
+ return jdut1ToUtc(jdUt, gregflag,
780
+ (tjd, iflag) => sweDeltatEx(tjd, iflag, tmpSwed));
781
+ }
782
+
783
+ /** Get the day of week (0 = Monday, 6 = Sunday). */
784
+ static dayOfWeek(jd: number): number {
785
+ return dayOfWeek(jd);
786
+ }
787
+
788
+ /* ==============================================================
789
+ * Math Utilities (static)
790
+ * ============================================================== */
791
+
792
+ /** Get the Swiss Ephemeris version string. */
793
+ static version(): string {
794
+ return sweVersion();
795
+ }
796
+
797
+ /** Normalize degrees to [0, 360). */
798
+ static normalizeDegrees(x: number): number {
799
+ return sweDegnorm(x);
800
+ }
801
+
802
+ /** Normalize radians to [0, 2π). */
803
+ static normalizeRadians(x: number): number {
804
+ return sweRadnorm(x);
805
+ }
806
+
807
+ /** Midpoint between two degree values on the circle. */
808
+ static degreeMidpoint(a: number, b: number): number {
809
+ return sweDegMidp(a, b);
810
+ }
811
+
812
+ /** Midpoint between two radian values on the circle. */
813
+ static radianMidpoint(a: number, b: number): number {
814
+ return sweRadMidp(a, b);
815
+ }
816
+
817
+ /** Transform coordinates by obliquity (ecliptic ↔ equatorial). */
818
+ static coordinateTransform(coords: number[], eps: number): number[] {
819
+ const out = [0, 0, 0, 0, 0, 0];
820
+ sweCotrans(coords, out, eps);
821
+ return out;
822
+ }
823
+ }