@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,307 @@
1
+ # Nodes and Apsides
2
+
3
+ **Planetary nodes** and **apsides** describe key geometric features of a planet's orbit.
4
+
5
+ **Nodes** are the two points where a planet's orbit crosses the ecliptic plane (the plane of Earth's orbit around the Sun). Every planet orbits the Sun on a slightly tilted plane, and these planes intersect the ecliptic at two points:
6
+ - The **ascending node** is where the planet crosses the ecliptic going northward (from below to above the plane).
7
+ - The **descending node** is where it crosses going southward.
8
+
9
+ The most well-known nodes are the **lunar nodes**. In Vedic astrology, the ascending node is called **Rahu** and the descending node is **Ketu**. In Western astrology, they are known as the **North Node** and **South Node**. But every planet has its own pair of nodes -- they are simply less commonly used.
10
+
11
+ **Apsides** are the points where a planet is closest to and farthest from the body it orbits:
12
+ - **Perihelion**: the point of closest approach to the Sun (for the Moon: **perigee**, closest to Earth).
13
+ - **Aphelion**: the point of greatest distance from the Sun (for the Moon: **apogee**, farthest from Earth).
14
+
15
+ The Moon's apogee has special significance in astrology as **Black Moon Lilith** (the mean apogee) or **Osculating Lilith** (the true, instantaneous apogee).
16
+
17
+ ---
18
+
19
+ ## Quick Example
20
+
21
+ ```typescript
22
+ import { SwissEph } from '../index';
23
+ import { SE_MOON, SE_NODBIT_MEAN } from '../../constants';
24
+
25
+ const swe = new SwissEph();
26
+ const jd = SwissEph.julianDay(2025, 1, 1, 12);
27
+
28
+ const result = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_MEAN);
29
+
30
+ console.log(`Moon ascending node: ${result.ascendingNode.longitude.toFixed(4)} deg`);
31
+ console.log(`Moon descending node: ${result.descendingNode.longitude.toFixed(4)} deg`);
32
+ console.log(`Moon perigee: ${result.perihelion.longitude.toFixed(4)} deg`);
33
+ console.log(`Moon apogee: ${result.aphelion.longitude.toFixed(4)} deg`);
34
+
35
+ swe.close();
36
+ ```
37
+
38
+ ---
39
+
40
+ ## Detailed Examples
41
+
42
+ ### Moon's nodes: mean vs osculating
43
+
44
+ The **mean node** moves smoothly backward through the zodiac at about 19.3 degrees per year. The **osculating (true) node** wobbles around the mean with perturbations of up to ~1.5 degrees. Most Western astrologers use the mean node; Vedic astrology traditionally uses the true node.
45
+
46
+ ```typescript
47
+ import { SwissEph } from '../index';
48
+ import { SE_MOON, SE_NODBIT_MEAN, SE_NODBIT_OSCU } from '../../constants';
49
+
50
+ const swe = new SwissEph();
51
+ const jd = SwissEph.julianDay(2025, 6, 15, 12);
52
+
53
+ const mean = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_MEAN);
54
+ const oscu = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_OSCU);
55
+
56
+ console.log(`Mean ascending node: ${mean.ascendingNode.longitude.toFixed(4)} deg`);
57
+ console.log(`Osculating ascending node: ${oscu.ascendingNode.longitude.toFixed(4)} deg`);
58
+ console.log(`Difference: ${(oscu.ascendingNode.longitude - mean.ascendingNode.longitude).toFixed(4)} deg`);
59
+
60
+ // The descending node is always roughly 180 degrees from the ascending node
61
+ console.log(`\nMean descending node: ${mean.descendingNode.longitude.toFixed(4)} deg`);
62
+
63
+ // Speed of the mean node (retrograde, so negative)
64
+ console.log(`Mean node speed: ${mean.ascendingNode.longitudeSpeed.toFixed(6)} deg/day`);
65
+
66
+ swe.close();
67
+ ```
68
+
69
+ ### Tracking the Moon's nodal cycle
70
+
71
+ The Moon's nodes complete a full retrograde circuit of the zodiac in approximately 18.6 years (6,798 days). This is the famous **nodal cycle** (or **Metonic-adjacent cycle**) that governs the timing of eclipses.
72
+
73
+ ```typescript
74
+ import { SwissEph } from '../index';
75
+ import { SE_MOON, SE_NODBIT_MEAN } from '../../constants';
76
+
77
+ const swe = new SwissEph();
78
+ const signs = ['Ari','Tau','Gem','Can','Leo','Vir','Lib','Sco','Sag','Cap','Aqu','Pis'];
79
+
80
+ // Track the North Node's position at the start of each year
81
+ console.log('North Node position by year:');
82
+ for (let year = 2020; year <= 2038; year++) {
83
+ const jd = SwissEph.julianDay(year, 1, 1, 0);
84
+ const result = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_MEAN);
85
+ const lon = result.ascendingNode.longitude;
86
+ const signIdx = Math.floor(lon / 30);
87
+ const degInSign = lon - signIdx * 30;
88
+ console.log(` ${year} ${degInSign.toFixed(1).padStart(5)} deg ${signs[signIdx]} (${lon.toFixed(2)} deg)`);
89
+ }
90
+ // After ~18.6 years, the node returns to the same position
91
+
92
+ swe.close();
93
+ ```
94
+
95
+ ### Planetary nodes (Mars, Jupiter, Saturn)
96
+
97
+ Every planet has its own pair of orbital nodes. These move much more slowly than the Moon's nodes.
98
+
99
+ ```typescript
100
+ import { SwissEph } from '../index';
101
+ import {
102
+ SE_MARS, SE_JUPITER, SE_SATURN,
103
+ SE_NODBIT_MEAN, SE_NODBIT_OSCU,
104
+ } from '../../constants';
105
+
106
+ const swe = new SwissEph();
107
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
108
+
109
+ const planets = [
110
+ { id: SE_MARS, name: 'Mars' },
111
+ { id: SE_JUPITER, name: 'Jupiter' },
112
+ { id: SE_SATURN, name: 'Saturn' },
113
+ ];
114
+
115
+ for (const p of planets) {
116
+ const mean = swe.nodesApsides(jd, p.id, SE_NODBIT_MEAN);
117
+ const oscu = swe.nodesApsides(jd, p.id, SE_NODBIT_OSCU);
118
+
119
+ console.log(`${p.name}:`);
120
+ console.log(` Mean asc. node: ${mean.ascendingNode.longitude.toFixed(4)} deg`);
121
+ console.log(` Oscu asc. node: ${oscu.ascendingNode.longitude.toFixed(4)} deg`);
122
+ console.log(` Mean perihelion: ${mean.perihelion.longitude.toFixed(4)} deg`);
123
+ console.log(` Mean aphelion: ${mean.aphelion.longitude.toFixed(4)} deg`);
124
+ console.log();
125
+ }
126
+
127
+ swe.close();
128
+ ```
129
+
130
+ ### Mars apsides: perihelion and aphelion
131
+
132
+ Mars has a notably eccentric orbit (e ~= 0.093). Its perihelion and aphelion distances differ by about 0.28 AU.
133
+
134
+ ```typescript
135
+ import { SwissEph } from '../index';
136
+ import { SE_MARS, SE_NODBIT_MEAN } from '../../constants';
137
+
138
+ const swe = new SwissEph();
139
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
140
+
141
+ const result = swe.nodesApsides(jd, SE_MARS, SE_NODBIT_MEAN);
142
+
143
+ console.log(`Mars perihelion longitude: ${result.perihelion.longitude.toFixed(4)} deg`);
144
+ console.log(`Mars perihelion distance: ${result.perihelion.distance.toFixed(6)} AU`);
145
+ console.log(`Mars aphelion longitude: ${result.aphelion.longitude.toFixed(4)} deg`);
146
+ console.log(`Mars aphelion distance: ${result.aphelion.distance.toFixed(6)} AU`);
147
+
148
+ // Speed of perihelion precession (very slow)
149
+ console.log(`Perihelion speed: ${result.perihelion.longitudeSpeed.toFixed(8)} deg/day`);
150
+
151
+ swe.close();
152
+ ```
153
+
154
+ ### Black Moon Lilith: mean vs osculating apogee
155
+
156
+ In astrology, "Black Moon Lilith" usually refers to the mean lunar apogee. The osculating (true) Lilith is the instantaneous apogee, which can differ significantly.
157
+
158
+ ```typescript
159
+ import { SwissEph } from '../index';
160
+ import { SE_MOON, SE_NODBIT_MEAN, SE_NODBIT_OSCU } from '../../constants';
161
+
162
+ const swe = new SwissEph();
163
+ const jd = SwissEph.julianDay(2025, 3, 20, 12);
164
+
165
+ const mean = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_MEAN);
166
+ const oscu = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_OSCU);
167
+
168
+ console.log(`Mean Lilith (apogee): ${mean.aphelion.longitude.toFixed(4)} deg`);
169
+ console.log(`Osculating Lilith (apogee): ${oscu.aphelion.longitude.toFixed(4)} deg`);
170
+ console.log(`Difference: ${(oscu.aphelion.longitude - mean.aphelion.longitude).toFixed(4)} deg`);
171
+
172
+ // Mean Lilith moves about 40.7 deg/year (direct motion, unlike the nodes)
173
+ console.log(`Mean Lilith speed: ${mean.aphelion.longitudeSpeed.toFixed(6)} deg/day`);
174
+
175
+ swe.close();
176
+ ```
177
+
178
+ ### The focal point (SE_NODBIT_FOPOINT)
179
+
180
+ An elliptical orbit has two focal points. The Sun (or Earth, for the Moon) sits at one focus. The `SE_NODBIT_FOPOINT` flag returns the **second (empty) focus** of the orbital ellipse instead of the aphelion. This is sometimes used in esoteric astrology as an alternative to Lilith.
181
+
182
+ ```typescript
183
+ import { SwissEph } from '../index';
184
+ import { SE_MOON, SE_NODBIT_OSCU, SE_NODBIT_FOPOINT } from '../../constants';
185
+
186
+ const swe = new SwissEph();
187
+ const jd = SwissEph.julianDay(2025, 1, 1, 12);
188
+
189
+ // Osculating aphelion (normal)
190
+ const oscu = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_OSCU);
191
+ console.log(`Osculating apogee (Lilith): ${oscu.aphelion.longitude.toFixed(4)} deg`);
192
+
193
+ // Focal point: use SE_NODBIT_OSCU | SE_NODBIT_FOPOINT
194
+ const focal = swe.nodesApsides(jd, SE_MOON, SE_NODBIT_OSCU | SE_NODBIT_FOPOINT);
195
+ console.log(`Second focal point: ${focal.aphelion.longitude.toFixed(4)} deg`);
196
+
197
+ // The focal point and apogee are close but not identical because the orbit is not
198
+ // a perfect ellipse — perturbations shift the apsidal line.
199
+
200
+ swe.close();
201
+ ```
202
+
203
+ ### Barycentric osculating nodes
204
+
205
+ The `SE_NODBIT_OSCU_BAR` method computes osculating elements relative to the **solar system barycenter** rather than the Sun. This matters for precise orbital mechanics because the Sun itself wobbles due to Jupiter and other giant planets.
206
+
207
+ ```typescript
208
+ import { SwissEph } from '../index';
209
+ import { SE_JUPITER, SE_NODBIT_OSCU, SE_NODBIT_OSCU_BAR } from '../../constants';
210
+
211
+ const swe = new SwissEph();
212
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
213
+
214
+ const helio = swe.nodesApsides(jd, SE_JUPITER, SE_NODBIT_OSCU);
215
+ const bary = swe.nodesApsides(jd, SE_JUPITER, SE_NODBIT_OSCU_BAR);
216
+
217
+ console.log('Jupiter ascending node:');
218
+ console.log(` Heliocentric osculating: ${helio.ascendingNode.longitude.toFixed(4)} deg`);
219
+ console.log(` Barycentric osculating: ${bary.ascendingNode.longitude.toFixed(4)} deg`);
220
+
221
+ console.log('Jupiter perihelion:');
222
+ console.log(` Heliocentric: ${helio.perihelion.longitude.toFixed(4)} deg`);
223
+ console.log(` Barycentric: ${bary.perihelion.longitude.toFixed(4)} deg`);
224
+
225
+ swe.close();
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Deep Explanation
231
+
232
+ ### What are orbital nodes?
233
+
234
+ Every planet orbits the Sun in a plane that is slightly tilted relative to the ecliptic. The **inclination** measures this tilt (e.g., Mercury ~7 degrees, Mars ~1.85 degrees, Pluto ~17 degrees). The line where the planet's orbital plane intersects the ecliptic plane is called the **line of nodes**. The two endpoints of this line (projected onto the ecliptic) are the ascending and descending nodes.
235
+
236
+ The ascending node is conventionally denoted by the symbol &#9738; and the descending node by &#9739;. The **longitude of the ascending node** (often written as capital omega) is one of the six classical Keplerian orbital elements.
237
+
238
+ ### Mean vs osculating elements
239
+
240
+ This is one of the most important distinctions in orbital mechanics:
241
+
242
+ - **Mean elements** are averaged values that describe the smoothly varying, long-term behavior of an orbit. They filter out short-period perturbations from other planets. The mean node of the Moon, for example, regresses steadily at about 19.3 degrees per year with no wobbles.
243
+
244
+ - **Osculating elements** describe the instantaneous orbit -- the ellipse that the body would follow if all perturbations were suddenly turned off at that moment. They capture the real-time wobbles caused by gravitational tugs from other bodies.
245
+
246
+ For the Moon, the osculating node can differ from the mean node by up to about 1.5 degrees due to solar perturbations. For astrology, the mean node is more commonly used in Western traditions because it produces smoother transits. Vedic astrology, however, traditionally uses the true (osculating) node.
247
+
248
+ ### The method parameter
249
+
250
+ | Constant | Value | Description |
251
+ |----------|-------|-------------|
252
+ | `SE_NODBIT_MEAN` | 1 | Mean elements. Smooth, averaged motion. Only available for Moon and planets with defined mean element models. |
253
+ | `SE_NODBIT_OSCU` | 2 | Osculating (heliocentric) elements. Instantaneous orbit at the given moment. Available for all bodies. |
254
+ | `SE_NODBIT_OSCU_BAR` | 4 | Osculating elements relative to the solar system barycenter instead of the Sun. More physically meaningful for precise work. |
255
+ | `SE_NODBIT_FOPOINT` | 256 | Instead of returning the aphelion position, returns the **second focal point** of the orbital ellipse. Can be combined with `SE_NODBIT_OSCU` or `SE_NODBIT_OSCU_BAR` using bitwise OR. |
256
+
257
+ Methods can be combined: `SE_NODBIT_OSCU | SE_NODBIT_FOPOINT` gives the osculating second focal point.
258
+
259
+ ### The return object
260
+
261
+ The `nodesApsides()` method returns four `PlanetPosition` objects:
262
+
263
+ | Field | Description |
264
+ |-------|-------------|
265
+ | `ascendingNode` | Position of the ascending node (longitude, latitude, distance, speeds) |
266
+ | `descendingNode` | Position of the descending node |
267
+ | `perihelion` | Position of the point of closest approach to the Sun (or Earth for Moon) |
268
+ | `aphelion` | Position of the point of greatest distance (or the second focal point if `SE_NODBIT_FOPOINT` is set) |
269
+
270
+ Each position includes:
271
+ - `longitude`: ecliptic longitude in degrees (0-360)
272
+ - `latitude`: ecliptic latitude in degrees (usually near 0 for nodes, can be nonzero for apsides)
273
+ - `distance`: heliocentric distance in AU at that orbital point
274
+ - `longitudeSpeed`, `latitudeSpeed`, `distanceSpeed`: daily rates of change
275
+
276
+ ### The 18.6-year nodal cycle of the Moon
277
+
278
+ The Moon's nodes regress (move backward through the zodiac) with a period of about 18.6 years (6,798.4 days). This cycle is fundamental to eclipse prediction: eclipses can only occur when the Sun is near one of the Moon's nodes. Because the nodes regress, eclipse "seasons" shift earlier each year by about 19 days.
279
+
280
+ The 18.6-year cycle also causes the **nutation** of Earth's axis -- a small wobble of ~9 arc-seconds superimposed on the 26,000-year precession cycle. This is why nutation and lunar nodes are so closely connected in the Swiss Ephemeris internals.
281
+
282
+ ### Perihelion precession
283
+
284
+ The apsidal line (the line connecting perihelion and aphelion) slowly rotates forward through the zodiac. For Mercury, this precession is about 574 arc-seconds per century -- and it was the famous anomalous 43 arc-seconds per century of Mercury's perihelion precession that provided one of the first confirmations of Einstein's general relativity.
285
+
286
+ For the Moon, the apsidal line (perigee/apogee) advances at about 40.7 degrees per year, completing a full cycle in about 8.85 years.
287
+
288
+ ### Black Moon Lilith in detail
289
+
290
+ "Black Moon Lilith" in astrology refers to the lunar apogee, but there are several variants:
291
+
292
+ | Variant | Source | Description |
293
+ |---------|--------|-------------|
294
+ | **Mean Lilith** | `SE_MEAN_APOG` (12) via `calc()`, or `nodesApsides()` with `SE_NODBIT_MEAN` | Smooth mean apogee. Moves steadily at ~40.7 deg/year. Most commonly used in astrology. |
295
+ | **Osculating Lilith** | `SE_OSCU_APOG` (13) via `calc()`, or `nodesApsides()` with `SE_NODBIT_OSCU` | True instantaneous apogee. Wobbles significantly -- can differ from mean by 30 degrees or more. |
296
+ | **Interpolated Lilith** | Some Swiss Ephemeris versions | An interpolation that smooths out extreme wobbles of the osculating Lilith. |
297
+ | **Second focal point** | `nodesApsides()` with `SE_NODBIT_OSCU | SE_NODBIT_FOPOINT` | The empty focus of the Moon's orbital ellipse. Very close to osculating Lilith for nearly circular orbits, but differs for eccentric orbits. |
298
+
299
+ The `calc()` method with `SE_MEAN_APOG` or `SE_OSCU_APOG` is typically the simplest way to get Lilith's position. The `nodesApsides()` method gives you additional control over the calculation method.
300
+
301
+ ### Practical considerations
302
+
303
+ - **For astrology**: Mean nodes are standard in most traditions. Use `SE_NODBIT_MEAN` for charts.
304
+ - **For astronomy**: Osculating elements are physically meaningful. Use `SE_NODBIT_OSCU` or `SE_NODBIT_OSCU_BAR`.
305
+ - **For eclipses**: The true (osculating) node determines the actual geometry, but the mean node gives a better sense of the long-term pattern.
306
+ - **SE_NODBIT_MEAN** is only available for the Moon and planets. For asteroids and other minor bodies, you must use `SE_NODBIT_OSCU`.
307
+ - Nodal and apsidal positions are given in ecliptic coordinates. The `distance` field for a node represents the heliocentric distance of the planet when it crosses the ecliptic, which is useful for understanding the orbital geometry.
@@ -0,0 +1,352 @@
1
+ # Occultations
2
+
3
+ A **lunar occultation** occurs when the Moon passes directly in front of another celestial body -- a planet, star, or asteroid -- temporarily hiding it from view. The word "occultation" comes from the Latin *occultare*, meaning "to conceal." While solar eclipses are technically a special case of occultation (the Moon occulting the Sun), the term "occultation" in astronomy usually refers to the Moon hiding other objects.
4
+
5
+ Occultations are significant to astronomers for several reasons:
6
+
7
+ - **Precise timing**: Because the Moon has no atmosphere, a star disappears and reappears almost instantaneously (within milliseconds). Timing these events precisely allows measurement of the Moon's position to very high accuracy, which has historically helped refine our knowledge of the lunar orbit and Earth's rotation.
8
+ - **Binary star discovery**: If a star winks out in two steps instead of one, it reveals an unsuspected close binary pair too tight to resolve with telescopes. Many binary stars were first discovered this way.
9
+ - **Stellar diameters**: A star does not vanish truly instantaneously -- the light diffracts around the Moon's edge, producing a brief Fresnel diffraction pattern. By analyzing this pattern with high-speed photometry, astronomers can measure the angular diameter of the star.
10
+ - **Asteroid occultations**: When an asteroid passes in front of a star, the shadow cast on Earth reveals the asteroid's precise size and shape. Citizen scientists across the predicted shadow path record the timing, and combining their observations produces a silhouette profile of the asteroid.
11
+ - **Historical importance**: Before modern techniques like radar ranging and space missions, lunar occultations were one of the primary methods for determining precise positions of celestial objects, especially radio sources in the early days of radio astronomy.
12
+
13
+ The Swiss Ephemeris can predict occultations of planets and fixed stars by the Moon -- finding when they happen globally, where they are visible, and how they appear from a specific location.
14
+
15
+ ---
16
+
17
+ ## Quick Example
18
+
19
+ ```typescript
20
+ import { SwissEph } from '../index';
21
+ import { SE_JUPITER } from '../../constants';
22
+
23
+ const swe = new SwissEph();
24
+
25
+ // Find the next occultation of Jupiter by the Moon after 2024-01-01
26
+ const jd = SwissEph.julianDay(2024, 1, 1, 0);
27
+ const occ = swe.occultationGlobal(jd, SE_JUPITER);
28
+
29
+ const date = SwissEph.fromJulianDay(occ.maximum);
30
+ console.log(`Next Jupiter occultation: ${date.year}-${date.month}-${date.day}`);
31
+
32
+ swe.close();
33
+ ```
34
+
35
+ ---
36
+
37
+ ## Detailed Examples
38
+
39
+ ### Finding the next occultation of a planet
40
+
41
+ ```typescript
42
+ import { SwissEph } from '../index';
43
+ import {
44
+ SE_VENUS, SE_MARS, SE_JUPITER, SE_SATURN,
45
+ } from '../../constants';
46
+
47
+ const swe = new SwissEph();
48
+ const jd = SwissEph.julianDay(2024, 1, 1, 0);
49
+
50
+ const fmt = (jd: number) => {
51
+ const d = SwissEph.fromJulianDay(jd);
52
+ return `${d.year}-${String(d.month).padStart(2,'0')}-${String(d.day).padStart(2,'0')}`;
53
+ };
54
+
55
+ const planets = [
56
+ { id: SE_VENUS, name: 'Venus' },
57
+ { id: SE_MARS, name: 'Mars' },
58
+ { id: SE_JUPITER, name: 'Jupiter' },
59
+ { id: SE_SATURN, name: 'Saturn' },
60
+ ];
61
+
62
+ for (const p of planets) {
63
+ const occ = swe.occultationGlobal(jd, p.id);
64
+ console.log(`Next occultation of ${p.name}: ${fmt(occ.maximum)}`);
65
+ }
66
+
67
+ swe.close();
68
+ ```
69
+
70
+ ### Occultation of a fixed star
71
+
72
+ You can search for the Moon occulting a fixed star by passing the star name and using planet = 0.
73
+
74
+ ```typescript
75
+ import { SwissEph } from '../index';
76
+
77
+ const swe = new SwissEph();
78
+ const jd = SwissEph.julianDay(2024, 1, 1, 0);
79
+
80
+ // Find the next occultation of Regulus (Alpha Leonis) by the Moon
81
+ // Planet parameter should be 0 when using a star name
82
+ const occ = swe.occultationGlobal(jd, 0, 'Regulus');
83
+
84
+ const date = SwissEph.fromJulianDay(occ.maximum);
85
+ console.log(`Next Regulus occultation: ${date.year}-${date.month}-${date.day}`);
86
+
87
+ // Contact times
88
+ const fmt = (jd: number) => {
89
+ if (jd === 0) return '(n/a)';
90
+ const d = SwissEph.fromJulianDay(jd);
91
+ const h = Math.floor(d.hour);
92
+ const m = Math.floor((d.hour - h) * 60);
93
+ return `${h}:${String(m).padStart(2,'0')} UT`;
94
+ };
95
+
96
+ console.log(` First contact: ${fmt(occ.first)}`);
97
+ console.log(` Maximum: ${fmt(occ.maximum)}`);
98
+ console.log(` Fourth contact: ${fmt(occ.fourth)}`);
99
+
100
+ swe.close();
101
+ ```
102
+
103
+ ### Where is the occultation visible?
104
+
105
+ Use `occultationWhere` to find the geographic coordinates where the occultation is visible at a given moment.
106
+
107
+ ```typescript
108
+ import { SwissEph } from '../index';
109
+ import { SE_JUPITER } from '../../constants';
110
+
111
+ const swe = new SwissEph();
112
+ const jd = SwissEph.julianDay(2024, 1, 1, 0);
113
+
114
+ // Find the next Jupiter occultation
115
+ const occ = swe.occultationGlobal(jd, SE_JUPITER);
116
+
117
+ // Where is it visible at maximum?
118
+ const where = swe.occultationWhere(occ.maximum, SE_JUPITER);
119
+
120
+ console.log(`Occultation visible from:`);
121
+ console.log(` Longitude: ${where.geopos.longitude.toFixed(2)} deg`);
122
+ console.log(` Latitude: ${where.geopos.latitude.toFixed(2)} deg`);
123
+ console.log(` Type flags: ${where.type}`);
124
+
125
+ swe.close();
126
+ ```
127
+
128
+ ### Local occultation: is it visible from my city?
129
+
130
+ Use `occultationLocal` to find when the next occultation of a given body is visible from a specific location.
131
+
132
+ ```typescript
133
+ import { SwissEph } from '../index';
134
+ import { SE_JUPITER } from '../../constants';
135
+
136
+ const swe = new SwissEph();
137
+ const jd = SwissEph.julianDay(2024, 1, 1, 0);
138
+
139
+ const london = { longitude: -0.128, latitude: 51.507 };
140
+
141
+ // Find the next Jupiter occultation visible from London
142
+ const local = swe.occultationLocal(jd, SE_JUPITER, london);
143
+
144
+ const fmt = (jd: number) => {
145
+ if (jd === 0) return '(n/a)';
146
+ const d = SwissEph.fromJulianDay(jd);
147
+ const h = Math.floor(d.hour);
148
+ const m = Math.floor((d.hour - h) * 60);
149
+ const s = Math.round(((d.hour - h) * 60 - m) * 60);
150
+ return `${d.year}-${String(d.month).padStart(2,'0')}-${String(d.day).padStart(2,'0')} ${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')} UT`;
151
+ };
152
+
153
+ console.log(`Jupiter occultation visible from London:`);
154
+ console.log(` Disappearance (1st contact): ${fmt(local.firstContact)}`);
155
+ console.log(` Maximum: ${fmt(local.maximum)}`);
156
+ console.log(` Reappearance (4th contact): ${fmt(local.fourthContact)}`);
157
+
158
+ // Attributes
159
+ console.log(` Magnitude: ${local.attributes.magnitude.toFixed(4)}`);
160
+
161
+ swe.close();
162
+ ```
163
+
164
+ ### Occultation of a fixed star from a specific location
165
+
166
+ ```typescript
167
+ import { SwissEph } from '../index';
168
+
169
+ const swe = new SwissEph();
170
+ const jd = SwissEph.julianDay(2024, 1, 1, 0);
171
+
172
+ const tokyo = { longitude: 139.692, latitude: 35.690 };
173
+
174
+ // Find the next occultation of Aldebaran visible from Tokyo
175
+ const local = swe.occultationLocal(jd, 0, tokyo, 'Aldebaran');
176
+
177
+ const date = SwissEph.fromJulianDay(local.maximum);
178
+ console.log(`Aldebaran occultation from Tokyo: ${date.year}-${date.month}-${date.day}`);
179
+
180
+ const fmt = (jd: number) => {
181
+ if (jd === 0) return '(n/a)';
182
+ const d = SwissEph.fromJulianDay(jd);
183
+ const h = Math.floor(d.hour);
184
+ const m = Math.floor((d.hour - h) * 60);
185
+ const s = Math.round(((d.hour - h) * 60 - m) * 60);
186
+ return `${h}:${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')} UT`;
187
+ };
188
+
189
+ console.log(` Star disappears: ${fmt(local.firstContact)}`);
190
+ console.log(` Star reappears: ${fmt(local.fourthContact)}`);
191
+
192
+ swe.close();
193
+ ```
194
+
195
+ ### Filtering by occultation type
196
+
197
+ Like solar eclipses, occultations can be total (the planet/star is completely hidden), annular (for large planets where the Moon does not completely cover them -- rare), or partial.
198
+
199
+ ```typescript
200
+ import { SwissEph } from '../index';
201
+ import { SE_JUPITER, SE_ECL_TOTAL } from '../../constants';
202
+
203
+ const swe = new SwissEph();
204
+ const jd = SwissEph.julianDay(2024, 1, 1, 0);
205
+
206
+ // Find only total occultations of Jupiter
207
+ const occ = swe.occultationGlobal(jd, SE_JUPITER, null, SE_ECL_TOTAL);
208
+
209
+ const date = SwissEph.fromJulianDay(occ.maximum);
210
+ console.log(`Next total Jupiter occultation: ${date.year}-${date.month}-${date.day}`);
211
+
212
+ swe.close();
213
+ ```
214
+
215
+ ### Listing occultations over a period
216
+
217
+ ```typescript
218
+ import { SwissEph } from '../index';
219
+ import { SE_VENUS } from '../../constants';
220
+
221
+ const swe = new SwissEph();
222
+
223
+ let jd = SwissEph.julianDay(2024, 1, 1, 0);
224
+ const endJd = SwissEph.julianDay(2030, 1, 1, 0);
225
+
226
+ console.log('Venus occultations by the Moon, 2024-2029:');
227
+ while (jd < endJd) {
228
+ const occ = swe.occultationGlobal(jd, SE_VENUS);
229
+ if (occ.maximum > endJd) break;
230
+
231
+ const date = SwissEph.fromJulianDay(occ.maximum);
232
+ const where = swe.occultationWhere(occ.maximum, SE_VENUS);
233
+ console.log(
234
+ ` ${date.year}-${String(date.month).padStart(2,'0')}-${String(date.day).padStart(2,'0')}` +
235
+ ` lon=${where.geopos.longitude.toFixed(1)}, lat=${where.geopos.latitude.toFixed(1)}`
236
+ );
237
+
238
+ jd = occ.maximum + 1;
239
+ }
240
+
241
+ swe.close();
242
+ ```
243
+
244
+ ### Searching backward
245
+
246
+ ```typescript
247
+ import { SwissEph } from '../index';
248
+ import { SE_SATURN } from '../../constants';
249
+
250
+ const swe = new SwissEph();
251
+
252
+ // Find the most recent Saturn occultation before 2025-01-01
253
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
254
+ const occ = swe.occultationGlobal(jd, SE_SATURN, null, 0, true);
255
+
256
+ const date = SwissEph.fromJulianDay(occ.maximum);
257
+ console.log(`Most recent Saturn occultation: ${date.year}-${date.month}-${date.day}`);
258
+
259
+ swe.close();
260
+ ```
261
+
262
+ ---
263
+
264
+ ## Deep Explanation
265
+
266
+ ### How occultations differ from eclipses
267
+
268
+ Although the Swiss Ephemeris uses similar functions and type constants for both, occultations and eclipses are conceptually different:
269
+
270
+ | Aspect | Solar Eclipse | Occultation |
271
+ |--------|--------------|-------------|
272
+ | **Occulting body** | Moon | Moon |
273
+ | **Occulted body** | Sun | Planet or star |
274
+ | **Apparent size of occulted body** | ~0.5 degrees (large) | Tiny (stars are points; planets are a few arc-seconds to ~1 arc-minute) |
275
+ | **Duration** | Minutes to hours | Seconds (stars) to ~1 hour (planets) |
276
+ | **Visibility path** | Narrow, ~100-200 km | Can be wider or narrower depending on geometry |
277
+
278
+ ### Disappearance and reappearance
279
+
280
+ When the Moon occults a star, two dramatic events occur:
281
+
282
+ 1. **Disappearance** (immersion, first contact): The star vanishes almost instantaneously as the Moon's leading edge passes over it. For a bright star, this is a striking sight -- one moment the star is shining, the next instant it is gone. Because the Moon has no atmosphere, there is no gradual fading.
283
+
284
+ 2. **Reappearance** (emersion, fourth contact): The star suddenly reappears from behind the Moon's trailing edge. If the Moon is a waxing crescent, the reappearance happens on the Moon's dark limb, making it particularly dramatic as the star seems to pop out of darkness.
285
+
286
+ For planets, which have a measurable angular diameter, the disappearance and reappearance are not instantaneous but take several seconds as the Moon gradually covers and then uncovers the planetary disc.
287
+
288
+ ### Grazing occultations
289
+
290
+ A **grazing occultation** occurs when the star passes very close to the Moon's edge (the limb). Because the Moon's limb is not perfectly smooth -- it has mountains, craters, and valleys -- the star may blink on and off multiple times as it passes behind mountain peaks and reappears in valleys. These events are scientifically valuable because they map the Moon's limb profile with high precision.
291
+
292
+ ### The contact points
293
+
294
+ The result structure for occultations is the same as for solar eclipses:
295
+
296
+ | Field | Description |
297
+ |-------|-------------|
298
+ | `first` / `firstContact` | Occultation begins (star/planet starts to disappear) |
299
+ | `second` / `secondContact` | Complete disappearance (total occultation begins) |
300
+ | `maximum` | Mid-occultation |
301
+ | `third` / `thirdContact` | Reappearance begins (total occultation ends) |
302
+ | `fourth` / `fourthContact` | Occultation fully ends (star/planet fully visible again) |
303
+
304
+ For a star (which is a point source), second and third contacts coincide with first and fourth contacts respectively -- the star is either visible or it is not. The second/third contacts are more meaningful for planets with measurable apparent diameters.
305
+
306
+ ### The type bitmask
307
+
308
+ Occultation results use the same type constants as solar eclipses:
309
+
310
+ | Constant | Value | Meaning |
311
+ |----------|-------|---------|
312
+ | `SE_ECL_TOTAL` | 4 | The body is completely hidden by the Moon |
313
+ | `SE_ECL_ANNULAR` | 8 | The Moon is smaller than the body (theoretically possible for very nearby planets, but extremely rare in practice) |
314
+ | `SE_ECL_PARTIAL` | 16 | Only part of the body is covered |
315
+ | `SE_ECL_CENTRAL` | 1 | The occultation has a central line across Earth |
316
+ | `SE_ECL_NONCENTRAL` | 2 | No central line |
317
+
318
+ ### The `starname` parameter
319
+
320
+ When searching for occultations of fixed stars:
321
+ - Pass the star name as a string (e.g., `'Regulus'`, `'Aldebaran'`, `'Spica'`, `'Antares'`)
322
+ - Set the `planet` parameter to `0`
323
+ - The star name follows the same conventions as `swe.fixedStar()` -- you can use the traditional name, the Bayer designation, or a catalog number
324
+
325
+ When searching for occultations of planets:
326
+ - Pass the planet constant (e.g., `SE_JUPITER`, `SE_VENUS`)
327
+ - Set `starname` to `null` (or omit it)
328
+
329
+ ### Attributes
330
+
331
+ The occultation attributes are the same type as solar eclipse attributes (`EclipseAttributes`). The most relevant fields for occultations are:
332
+
333
+ - `fraction`: How much of the occulted body's area is covered (1.0 for a total occultation of a star)
334
+ - `magnitude`: How much of the occulted body's diameter is covered
335
+ - `sarosCycle` / `sarosMember`: Saros series information (occultations also follow Saros-like cycles)
336
+
337
+ ### Historical importance of occultations
338
+
339
+ Lunar occultations have played a crucial role in the history of astronomy:
340
+
341
+ - **Navigation**: Before GPS and accurate clocks, sailors could determine their longitude by timing lunar occultations and comparing with predicted times in almanacs.
342
+ - **Radio astronomy**: In the 1960s, lunar occultations of radio sources were one of the few ways to determine precise positions of radio-emitting objects. The occultation of the radio source 3C 273 in 1962 led to the identification of quasars.
343
+ - **Lunar topography**: Grazing occultation observations contributed significantly to mapping the Moon's limb profile before space missions provided direct measurements.
344
+ - **Stellar astronomy**: Thousands of close binary stars and stellar diameters have been measured through occultation timing, providing data that would be difficult or impossible to obtain by other means.
345
+
346
+ ### Tips
347
+
348
+ - Occultation searches can be slower than eclipse searches because the Moon must be checked against specific planet/star positions rather than the Sun's predictable path.
349
+ - When iterating through occultations, advance `jd` by at least 1 day past the previous result.
350
+ - Not all global occultations are visible from any given location. Use `occultationLocal` to find events visible from your specific location.
351
+ - The brightest stars that are regularly occulted by the Moon lie near the ecliptic: Aldebaran, Regulus, Spica, and Antares. These are the most commonly observed occultations.
352
+ - Planetary occultations are rarer but more spectacular to observe, especially for bright planets like Venus and Jupiter.