@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,469 @@
1
+ # Orbital Elements
2
+
3
+ **Keplerian orbital elements** are the six numbers that completely define the shape, orientation, and timing of an orbit. They are the language of celestial mechanics -- given these six values, you can reconstruct the exact path of a planet around the Sun and predict where it will be at any moment.
4
+
5
+ This library provides three related methods:
6
+ - **`orbitalElements(jd, planet)`** -- returns the six classical elements plus derived quantities like period and daily motion
7
+ - **`orbitDistances(jd, planet)`** -- returns the maximum, minimum, and current distance of the planet
8
+ - **`nodesApsides(jd, planet)`** -- returns the positions of the orbital nodes and apsides (perihelion/aphelion) as full position objects
9
+
10
+ These are useful for:
11
+ - Understanding the physical structure of planetary orbits
12
+ - Computing orbital periods (how long a "year" is on each planet)
13
+ - Finding closest/farthest approaches
14
+ - Understanding why planets speed up and slow down
15
+ - Astronomical education and visualization
16
+
17
+ ---
18
+
19
+ ## Quick Example
20
+
21
+ ```typescript
22
+ import { SwissEph } from '../index';
23
+ import { SE_MARS } from '../../constants';
24
+
25
+ const swe = new SwissEph();
26
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
27
+
28
+ const elem = swe.orbitalElements(jd, SE_MARS);
29
+
30
+ console.log(`Mars orbital elements at J2025.0:`);
31
+ console.log(` Semi-major axis: ${elem.semiAxis.toFixed(4)} AU`);
32
+ console.log(` Eccentricity: ${elem.eccentricity.toFixed(6)}`);
33
+ console.log(` Inclination: ${elem.inclination.toFixed(4)}°`);
34
+ console.log(` Ascending node: ${elem.ascNode.toFixed(4)}°`);
35
+ console.log(` Arg of perihelion: ${elem.argPerihelion.toFixed(4)}°`);
36
+ console.log(` Mean anomaly: ${elem.meanAnomaly.toFixed(4)}°`);
37
+ console.log(` Tropical period: ${elem.tropicalPeriod.toFixed(4)} years`);
38
+ console.log(` Synodic period: ${elem.synodicPeriod.toFixed(1)} days`);
39
+
40
+ swe.close();
41
+ ```
42
+
43
+ ---
44
+
45
+ ## Detailed Examples
46
+
47
+ ### Orbital elements for all planets
48
+
49
+ ```typescript
50
+ import { SwissEph } from '../index';
51
+ import {
52
+ SE_MERCURY, SE_VENUS, SE_EARTH, SE_MARS,
53
+ SE_JUPITER, SE_SATURN, SE_URANUS, SE_NEPTUNE, SE_PLUTO,
54
+ } from '../../constants';
55
+
56
+ const swe = new SwissEph();
57
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
58
+
59
+ const planets = [
60
+ { id: SE_MERCURY, name: 'Mercury' },
61
+ { id: SE_VENUS, name: 'Venus' },
62
+ { id: SE_EARTH, name: 'Earth' },
63
+ { id: SE_MARS, name: 'Mars' },
64
+ { id: SE_JUPITER, name: 'Jupiter' },
65
+ { id: SE_SATURN, name: 'Saturn' },
66
+ { id: SE_URANUS, name: 'Uranus' },
67
+ { id: SE_NEPTUNE, name: 'Neptune' },
68
+ { id: SE_PLUTO, name: 'Pluto' },
69
+ ];
70
+
71
+ console.log('Planet a (AU) e i (°) Period (yr)');
72
+ console.log('---------- ------- ------- ------- -----------');
73
+
74
+ for (const pl of planets) {
75
+ const elem = swe.orbitalElements(jd, pl.id);
76
+ console.log(
77
+ `${pl.name.padEnd(10)} ` +
78
+ `${elem.semiAxis.toFixed(4).padStart(7)} ` +
79
+ `${elem.eccentricity.toFixed(5).padStart(7)} ` +
80
+ `${elem.inclination.toFixed(3).padStart(7)} ` +
81
+ `${elem.tropicalPeriod.toFixed(3).padStart(11)}`
82
+ );
83
+ }
84
+
85
+ swe.close();
86
+ ```
87
+
88
+ ### Getting orbital distances
89
+
90
+ The `orbitDistances()` method gives you the maximum, minimum, and current (true) distance from the Sun (for heliocentric) or from Earth (for geocentric, the default):
91
+
92
+ ```typescript
93
+ import { SwissEph } from '../index';
94
+ import {
95
+ SE_MARS, SE_JUPITER, SE_SATURN, SE_VENUS,
96
+ } from '../../constants';
97
+
98
+ const swe = new SwissEph();
99
+ const jd = SwissEph.julianDay(2025, 6, 15, 0);
100
+
101
+ const planets = [
102
+ { id: SE_VENUS, name: 'Venus' },
103
+ { id: SE_MARS, name: 'Mars' },
104
+ { id: SE_JUPITER, name: 'Jupiter' },
105
+ { id: SE_SATURN, name: 'Saturn' },
106
+ ];
107
+
108
+ console.log('Planet Current (AU) Min (AU) Max (AU)');
109
+ console.log('--------- ----------- -------- --------');
110
+
111
+ for (const pl of planets) {
112
+ const dist = swe.orbitDistances(jd, pl.id);
113
+ console.log(
114
+ `${pl.name.padEnd(9)} ` +
115
+ `${dist.true.toFixed(4).padStart(11)} ` +
116
+ `${dist.min.toFixed(4).padStart(8)} ` +
117
+ `${dist.max.toFixed(4).padStart(8)}`
118
+ );
119
+ }
120
+
121
+ swe.close();
122
+ ```
123
+
124
+ ### Nodes and apsides with different methods
125
+
126
+ The `nodesApsides()` method returns the positions of a planet's orbital nodes (where its orbit crosses the ecliptic) and apsides (perihelion and aphelion). There are several computation methods:
127
+
128
+ ```typescript
129
+ import { SwissEph } from '../index';
130
+ import {
131
+ SE_MARS,
132
+ SE_NODBIT_MEAN, SE_NODBIT_OSCU, SE_NODBIT_OSCU_BAR, SE_NODBIT_FOPOINT,
133
+ } from '../../constants';
134
+
135
+ const swe = new SwissEph();
136
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
137
+
138
+ // Method 1: Mean nodes/apsides (long-term average, smoothly moving)
139
+ const mean = swe.nodesApsides(jd, SE_MARS, SE_NODBIT_MEAN);
140
+ console.log('Mean nodes/apsides:');
141
+ console.log(` Ascending node: ${mean.ascendingNode.longitude.toFixed(4)}°`);
142
+ console.log(` Descending node: ${mean.descendingNode.longitude.toFixed(4)}°`);
143
+ console.log(` Perihelion: ${mean.perihelion.longitude.toFixed(4)}° (dist: ${mean.perihelion.distance.toFixed(4)} AU)`);
144
+ console.log(` Aphelion: ${mean.aphelion.longitude.toFixed(4)}° (dist: ${mean.aphelion.distance.toFixed(4)} AU)`);
145
+
146
+ // Method 2: Osculating nodes/apsides (instantaneous, includes perturbations)
147
+ const oscu = swe.nodesApsides(jd, SE_MARS, SE_NODBIT_OSCU);
148
+ console.log('\nOsculating nodes/apsides:');
149
+ console.log(` Ascending node: ${oscu.ascendingNode.longitude.toFixed(4)}°`);
150
+ console.log(` Descending node: ${oscu.descendingNode.longitude.toFixed(4)}°`);
151
+ console.log(` Perihelion: ${oscu.perihelion.longitude.toFixed(4)}°`);
152
+ console.log(` Aphelion: ${oscu.aphelion.longitude.toFixed(4)}°`);
153
+
154
+ // Method 3: Osculating with barycentric computation (more accurate for outer planets)
155
+ const bar = swe.nodesApsides(jd, SE_MARS, SE_NODBIT_OSCU_BAR);
156
+ console.log('\nOsculating (barycentric):');
157
+ console.log(` Ascending node: ${bar.ascendingNode.longitude.toFixed(4)}°`);
158
+ console.log(` Perihelion: ${bar.perihelion.longitude.toFixed(4)}°`);
159
+
160
+ swe.close();
161
+ ```
162
+
163
+ ### Comparing perihelion distance to orbit eccentricity
164
+
165
+ The perihelion and aphelion distances are directly related to the semi-major axis and eccentricity:
166
+ - Perihelion distance = a * (1 - e)
167
+ - Aphelion distance = a * (1 + e)
168
+
169
+ ```typescript
170
+ import { SwissEph } from '../index';
171
+ import { SE_MARS, SE_NODBIT_MEAN } from '../../constants';
172
+
173
+ const swe = new SwissEph();
174
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
175
+
176
+ const elem = swe.orbitalElements(jd, SE_MARS);
177
+ const nodes = swe.nodesApsides(jd, SE_MARS, SE_NODBIT_MEAN);
178
+
179
+ console.log('Mars orbit verification:');
180
+ console.log(` Semi-major axis a = ${elem.semiAxis.toFixed(6)} AU`);
181
+ console.log(` Eccentricity e = ${elem.eccentricity.toFixed(6)}`);
182
+ console.log();
183
+
184
+ const computedPeri = elem.semiAxis * (1 - elem.eccentricity);
185
+ const computedAph = elem.semiAxis * (1 + elem.eccentricity);
186
+
187
+ console.log(` Perihelion (computed a*(1-e)): ${computedPeri.toFixed(6)} AU`);
188
+ console.log(` Perihelion (from nodesApsides): ${nodes.perihelion.distance.toFixed(6)} AU`);
189
+ console.log();
190
+ console.log(` Aphelion (computed a*(1+e)): ${computedAph.toFixed(6)} AU`);
191
+ console.log(` Aphelion (from nodesApsides): ${nodes.aphelion.distance.toFixed(6)} AU`);
192
+
193
+ swe.close();
194
+ ```
195
+
196
+ ### Using the focal point (SE_NODBIT_FOPOINT)
197
+
198
+ The `SE_NODBIT_FOPOINT` flag replaces the aphelion with the **second focus** of the elliptical orbit. An ellipse has two foci; the Sun is at one focus, and the second focus is the empty point on the opposite side. Combined with `SE_NODBIT_OSCU`, this gives you the osculating second focus:
199
+
200
+ ```typescript
201
+ import { SwissEph } from '../index';
202
+ import { SE_MARS, SE_NODBIT_OSCU, SE_NODBIT_FOPOINT } from '../../constants';
203
+
204
+ const swe = new SwissEph();
205
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
206
+
207
+ // Combine flags with bitwise OR
208
+ const method = SE_NODBIT_OSCU | SE_NODBIT_FOPOINT;
209
+ const result = swe.nodesApsides(jd, SE_MARS, method);
210
+
211
+ console.log('Mars osculating orbit:');
212
+ console.log(` Ascending node: ${result.ascendingNode.longitude.toFixed(4)}°`);
213
+ console.log(` Descending node: ${result.descendingNode.longitude.toFixed(4)}°`);
214
+ console.log(` Perihelion: ${result.perihelion.longitude.toFixed(4)}° at ${result.perihelion.distance.toFixed(4)} AU`);
215
+ console.log(` Second focus: ${result.aphelion.longitude.toFixed(4)}° at ${result.aphelion.distance.toFixed(4)} AU`);
216
+ // Note: when FOPOINT is set, the "aphelion" field contains the second focus instead
217
+
218
+ swe.close();
219
+ ```
220
+
221
+ ### Daily motion and orbital speed
222
+
223
+ The `dailyMotion` and `meanDailyMotion` fields tell you how fast the planet moves along its orbit:
224
+
225
+ ```typescript
226
+ import { SwissEph } from '../index';
227
+ import {
228
+ SE_MERCURY, SE_VENUS, SE_EARTH, SE_MARS,
229
+ SE_JUPITER, SE_SATURN, SE_URANUS, SE_NEPTUNE, SE_PLUTO,
230
+ } from '../../constants';
231
+
232
+ const swe = new SwissEph();
233
+ const jd = SwissEph.julianDay(2025, 1, 1, 0);
234
+
235
+ const planets = [
236
+ { id: SE_MERCURY, name: 'Mercury' },
237
+ { id: SE_VENUS, name: 'Venus' },
238
+ { id: SE_EARTH, name: 'Earth' },
239
+ { id: SE_MARS, name: 'Mars' },
240
+ { id: SE_JUPITER, name: 'Jupiter' },
241
+ { id: SE_SATURN, name: 'Saturn' },
242
+ { id: SE_URANUS, name: 'Uranus' },
243
+ { id: SE_NEPTUNE, name: 'Neptune' },
244
+ { id: SE_PLUTO, name: 'Pluto' },
245
+ ];
246
+
247
+ console.log('Planet Daily Motion Mean Daily Period (yr)');
248
+ console.log('--------- ----------- ---------- -----------');
249
+
250
+ for (const pl of planets) {
251
+ const elem = swe.orbitalElements(jd, pl.id);
252
+ console.log(
253
+ `${pl.name.padEnd(9)} ` +
254
+ `${elem.dailyMotion.toFixed(6).padStart(10)}° ` +
255
+ `${elem.meanDailyMotion.toFixed(6).padStart(10)}° ` +
256
+ `${elem.tropicalPeriod.toFixed(3).padStart(11)}`
257
+ );
258
+ }
259
+
260
+ swe.close();
261
+ ```
262
+
263
+ ---
264
+
265
+ ## Deep Explanation
266
+
267
+ ### The Six Classical Orbital Elements
268
+
269
+ Every orbit in the solar system can be described by six numbers. Three define the shape and size of the orbit; three define its orientation in space.
270
+
271
+ #### Shape and Size
272
+
273
+ **1. Semi-major axis (a)** -- measured in AU (Astronomical Units, where 1 AU = Earth-Sun distance)
274
+
275
+ The semi-major axis is half the longest diameter of the elliptical orbit. It determines the size of the orbit and, by Kepler's Third Law, the orbital period.
276
+
277
+ ```
278
+ Semi-major axis (a)
279
+ |<-------------------------->|
280
+
281
+ Aphelion --- Center --- Perihelion
282
+ |
283
+ Sun (at one focus)
284
+ ```
285
+
286
+ Typical values:
287
+ | Planet | a (AU) |
288
+ |--------|--------|
289
+ | Mercury | 0.387 |
290
+ | Venus | 0.723 |
291
+ | Earth | 1.000 |
292
+ | Mars | 1.524 |
293
+ | Jupiter | 5.203 |
294
+ | Saturn | 9.537 |
295
+ | Uranus | 19.19 |
296
+ | Neptune | 30.07 |
297
+ | Pluto | 39.48 |
298
+
299
+ **2. Eccentricity (e)** -- dimensionless, range 0 to 1
300
+
301
+ The eccentricity measures how elongated the ellipse is:
302
+ - **e = 0**: Perfect circle
303
+ - **e = 0.5**: Moderately elliptical
304
+ - **e = 1**: Parabola (escape trajectory)
305
+ - **e > 1**: Hyperbola (unbound orbit)
306
+
307
+ Most planets have nearly circular orbits (e < 0.1). Notable exceptions:
308
+ | Planet | e | Description |
309
+ |--------|------|-----------|
310
+ | Venus | 0.007 | Nearly circular |
311
+ | Earth | 0.017 | Very slightly elliptical |
312
+ | Mars | 0.093 | Noticeably elliptical |
313
+ | Pluto | 0.249 | Highly elliptical |
314
+ | Mercury | 0.206 | Quite elliptical |
315
+
316
+ Mars's eccentricity of ~0.093 causes its brightness at opposition to vary dramatically: a close opposition (perihelion side) makes Mars much brighter than a distant one.
317
+
318
+ **3. Inclination (i)** -- measured in degrees
319
+
320
+ The angle between the planet's orbital plane and the ecliptic (Earth's orbital plane). Most planets have very low inclinations:
321
+ | Planet | i |
322
+ |--------|------|
323
+ | Mercury | 7.0° |
324
+ | Venus | 3.4° |
325
+ | Mars | 1.9° |
326
+ | Jupiter | 1.3° |
327
+ | Pluto | 17.1° |
328
+
329
+ #### Orientation
330
+
331
+ **4. Longitude of the Ascending Node (Omega)** -- measured in degrees
332
+
333
+ The angle (measured along the ecliptic) from the Vernal Equinox to the point where the planet's orbit crosses the ecliptic going northward. This orients the orbital plane's "tilt axis" relative to the reference direction.
334
+
335
+ ```
336
+ Ecliptic plane
337
+ Vernal Equinox ----Omega---- Ascending Node
338
+ /
339
+ Planet's orbit
340
+ (tilted)
341
+ ```
342
+
343
+ **5. Argument of Perihelion (omega)** -- measured in degrees
344
+
345
+ The angle (measured within the orbital plane) from the ascending node to the perihelion point. This tells you where in the orbit the closest approach to the Sun occurs.
346
+
347
+ **6. Mean Anomaly (M)** -- measured in degrees
348
+
349
+ The position of the planet along its orbit at the given epoch. Mean anomaly increases uniformly with time (unlike the true anomaly, which speeds up near perihelion). M = 0 at perihelion.
350
+
351
+ ### Kepler's Three Laws
352
+
353
+ These orbital elements are grounded in Kepler's laws of planetary motion:
354
+
355
+ **First Law (1609)**: Planets move in ellipses with the Sun at one focus.
356
+ - This is why we need `a` (size) and `e` (shape) to describe the orbit.
357
+
358
+ **Second Law (1609)**: A line from the Sun to a planet sweeps out equal areas in equal times.
359
+ - This means planets move faster at perihelion and slower at aphelion. It is why `dailyMotion` (actual current speed) differs from `meanDailyMotion` (average speed).
360
+
361
+ **Third Law (1619)**: The square of the orbital period is proportional to the cube of the semi-major axis.
362
+ - P^2 = a^3 (when P is in years and a is in AU)
363
+ - This connects `semiAxis` to `tropicalPeriod`
364
+
365
+ ### Osculating Elements
366
+
367
+ The elements returned by `orbitalElements()` are **osculating elements** -- they describe the orbit the planet would follow if all gravitational perturbations suddenly stopped at the given moment. They are an instantaneous snapshot.
368
+
369
+ In reality, the gravitational pull of other planets causes orbital elements to change slowly over time. For example:
370
+ - Mercury's argument of perihelion advances by about 574 arcseconds per century (43 of which are due to general relativity -- the famous anomalous precession that Einstein explained)
371
+ - Earth's eccentricity oscillates between about 0.005 and 0.058 over a ~100,000-year cycle (affecting ice ages)
372
+
373
+ This is why the function requires a Julian Day -- the elements are specific to that moment.
374
+
375
+ ### Derived Quantities
376
+
377
+ Beyond the six classical elements, `orbitalElements()` returns several useful derived quantities:
378
+
379
+ **Tropical Period** (`tropicalPeriod`): The time for the planet to complete one orbit relative to the Vernal Equinox (in years). Due to precession, this differs very slightly from the sidereal period.
380
+
381
+ **Synodic Period** (`synodicPeriod`): The time between successive conjunctions of the planet with the Sun as seen from Earth (in days). This is the cycle of visibility -- from one opposition to the next for outer planets, or from one inferior conjunction to the next for inner planets.
382
+
383
+ **Daily Motion** (`dailyMotion`): The planet's current angular velocity along its orbit (degrees per day). Varies due to Kepler's Second Law -- faster at perihelion, slower at aphelion.
384
+
385
+ **Mean Daily Motion** (`meanDailyMotion`): The average angular velocity (degrees per day), which is constant: 360 / (period in days).
386
+
387
+ **Mean Longitude** (`meanLongitude`): The sum of the ascending node, argument of perihelion, and mean anomaly. A single number that increases uniformly and wraps around every orbit.
388
+
389
+ ### The Nodes and Apsides Methods
390
+
391
+ The `nodesApsides()` method returns the positions of four special points:
392
+
393
+ **Ascending Node**: Where the planet's orbit crosses the ecliptic going northward. Important in astrology (the "North Node" of the planet).
394
+
395
+ **Descending Node**: Where the orbit crosses the ecliptic going southward.
396
+
397
+ **Perihelion**: The point of closest approach to the Sun. The planet moves fastest here (Kepler's Second Law).
398
+
399
+ **Aphelion**: The point farthest from the Sun. The planet moves slowest here.
400
+
401
+ Each of these is returned as a full `PlanetPosition` object with longitude, latitude, distance, and speeds.
402
+
403
+ ### Method Constants for nodesApsides
404
+
405
+ | Constant | Value | Description |
406
+ |----------|-------|-------------|
407
+ | `SE_NODBIT_MEAN` | 1 | Mean nodes/apsides -- smooth, long-term averages. These change slowly and predictably. Best for general astrological use. |
408
+ | `SE_NODBIT_OSCU` | 2 | Osculating nodes/apsides -- instantaneous values based on the current orbit. These can jump around due to perturbations. |
409
+ | `SE_NODBIT_OSCU_BAR` | 4 | Osculating, computed from barycentric positions. More accurate for outer planets where the Sun's wobble due to Jupiter matters. |
410
+ | `SE_NODBIT_FOPOINT` | 256 | Replace aphelion with the second focus of the ellipse. Can be combined with other flags using bitwise OR. |
411
+
412
+ ### The Astronomical Unit (AU)
413
+
414
+ The AU is the standard unit for measuring distances within the solar system. Historically defined as the mean Earth-Sun distance, it is now precisely defined as:
415
+
416
+ **1 AU = 149,597,870.7 km**
417
+
418
+ All distances in `orbitalElements()` and `orbitDistances()` are given in AU. To convert to kilometers, multiply by 149,597,870.7. To convert to light-minutes, multiply by 8.317 (light takes about 8.3 minutes to travel 1 AU).
419
+
420
+ ### Return Types
421
+
422
+ ```typescript
423
+ interface OrbitalElements {
424
+ semiAxis: number; // a -- semi-major axis in AU
425
+ eccentricity: number; // e -- eccentricity (0-1)
426
+ inclination: number; // i -- inclination in degrees
427
+ ascNode: number; // Longitude of ascending node in degrees
428
+ argPerihelion: number; // Argument of perihelion in degrees
429
+ longPerihelion: number; // Longitude of perihelion in degrees (= ascNode + argPerihelion)
430
+ meanAnomaly: number; // Mean anomaly in degrees
431
+ meanLongitude: number; // Mean longitude in degrees (= longPerihelion + meanAnomaly)
432
+ dailyMotion: number; // Current daily motion in degrees/day
433
+ tropicalPeriod: number; // Tropical period in years
434
+ synodicPeriod: number; // Synodic period in days
435
+ meanDailyMotion: number; // Mean daily motion in degrees/day
436
+ meanLongJ2000: number; // Mean longitude referred to J2000 equinox
437
+ meanLongOfDate: number; // Mean longitude of date
438
+ meanLongSpeed: number; // Speed of mean longitude
439
+ nodeJ2000: number; // Ascending node referred to J2000
440
+ nodeOfDate: number; // Ascending node of date
441
+ nodeSpeed: number; // Speed of ascending node
442
+ perihelionJ2000: number; // Longitude of perihelion referred to J2000
443
+ perihelionOfDate: number; // Longitude of perihelion of date
444
+ perihelionSpeed: number; // Speed of longitude of perihelion
445
+ }
446
+
447
+ interface OrbitDistances {
448
+ max: number; // Maximum distance (aphelion for heliocentric) in AU
449
+ min: number; // Minimum distance (perihelion for heliocentric) in AU
450
+ true: number; // Current true distance in AU
451
+ }
452
+
453
+ interface NodesApsides {
454
+ ascendingNode: PlanetPosition; // Full position at ascending node
455
+ descendingNode: PlanetPosition; // Full position at descending node
456
+ perihelion: PlanetPosition; // Full position at perihelion
457
+ aphelion: PlanetPosition; // Full position at aphelion (or second focus if FOPOINT)
458
+ }
459
+ ```
460
+
461
+ ### Why Elements Change Over Time (Perturbations)
462
+
463
+ If the Sun and a single planet were the only objects in the universe, the orbital elements would be constant forever (a perfect Keplerian orbit). In reality, the gravitational pulls of other planets cause the elements to drift:
464
+
465
+ - **Precession of perihelion**: The orientation of the orbit slowly rotates. Mercury's perihelion advances 574"/century.
466
+ - **Nodal regression**: The orbital plane slowly wobbles, causing the ascending node to drift.
467
+ - **Eccentricity oscillation**: The shape of the orbit changes over very long timescales.
468
+
469
+ These changes are tiny from year to year but accumulate over millennia. This is why astronomers use osculating elements (valid for a specific instant) rather than fixed mean elements when precision matters.