@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.
- package/README.md +422 -0
- package/ephe/semo_18.se1 +0 -0
- package/ephe/sepl_18.se1 +0 -0
- package/originalCode/.eslintrc.json +124 -0
- package/originalCode/.gitattributes +2 -0
- package/originalCode/.github/FUNDING.yml +5 -0
- package/originalCode/.github/workflows/test.yml +35 -0
- package/originalCode/LICENSE +840 -0
- package/originalCode/README.md +91 -0
- package/originalCode/binding.gyp +41 -0
- package/originalCode/constants.js +366 -0
- package/originalCode/docs.gif +0 -0
- package/originalCode/index.d.ts +5115 -0
- package/originalCode/index.js +7 -0
- package/originalCode/index.mjs +109 -0
- package/originalCode/package.json +55 -0
- package/originalCode/src/functions/azalt.cpp +39 -0
- package/originalCode/src/functions/azalt_rev.cpp +35 -0
- package/originalCode/src/functions/calc.cpp +29 -0
- package/originalCode/src/functions/calc_pctr.cpp +31 -0
- package/originalCode/src/functions/calc_ut.cpp +29 -0
- package/originalCode/src/functions/close.cpp +6 -0
- package/originalCode/src/functions/cotrans.cpp +26 -0
- package/originalCode/src/functions/cotrans_sp.cpp +26 -0
- package/originalCode/src/functions/cs2degstr.cpp +19 -0
- package/originalCode/src/functions/cs2lonlatstr.cpp +23 -0
- package/originalCode/src/functions/cs2timestr.cpp +23 -0
- package/originalCode/src/functions/csnorm.cpp +15 -0
- package/originalCode/src/functions/csroundsec.cpp +15 -0
- package/originalCode/src/functions/d2l.cpp +15 -0
- package/originalCode/src/functions/date_conversion.cpp +30 -0
- package/originalCode/src/functions/day_of_week.cpp +15 -0
- package/originalCode/src/functions/degnorm.cpp +15 -0
- package/originalCode/src/functions/deltat.cpp +15 -0
- package/originalCode/src/functions/deltat_ex.cpp +24 -0
- package/originalCode/src/functions/difcs2n.cpp +19 -0
- package/originalCode/src/functions/difcsn.cpp +19 -0
- package/originalCode/src/functions/difdeg2n.cpp +19 -0
- package/originalCode/src/functions/difdegn.cpp +19 -0
- package/originalCode/src/functions/fixstar.cpp +32 -0
- package/originalCode/src/functions/fixstar2.cpp +32 -0
- package/originalCode/src/functions/fixstar2_mag.cpp +28 -0
- package/originalCode/src/functions/fixstar2_ut.cpp +32 -0
- package/originalCode/src/functions/fixstar_mag.cpp +28 -0
- package/originalCode/src/functions/fixstar_ut.cpp +32 -0
- package/originalCode/src/functions/gauquelin_sector.cpp +44 -0
- package/originalCode/src/functions/get_ayanamsa.cpp +15 -0
- package/originalCode/src/functions/get_ayanamsa_ex.cpp +27 -0
- package/originalCode/src/functions/get_ayanamsa_ex_ut.cpp +27 -0
- package/originalCode/src/functions/get_ayanamsa_name.cpp +19 -0
- package/originalCode/src/functions/get_ayanamsa_ut.cpp +15 -0
- package/originalCode/src/functions/get_current_file_data.cpp +28 -0
- package/originalCode/src/functions/get_library_path.cpp +8 -0
- package/originalCode/src/functions/get_orbital_elements.cpp +29 -0
- package/originalCode/src/functions/get_planet_name.cpp +19 -0
- package/originalCode/src/functions/get_tid_acc.cpp +7 -0
- package/originalCode/src/functions/heliacal_pheno_ut.cpp +52 -0
- package/originalCode/src/functions/heliacal_ut.cpp +52 -0
- package/originalCode/src/functions/helio_cross.cpp +33 -0
- package/originalCode/src/functions/helio_cross_ut.cpp +33 -0
- package/originalCode/src/functions/house_name.cpp +20 -0
- package/originalCode/src/functions/house_pos.cpp +36 -0
- package/originalCode/src/functions/houses.cpp +35 -0
- package/originalCode/src/functions/houses_armc.cpp +38 -0
- package/originalCode/src/functions/houses_armc_ex2.cpp +47 -0
- package/originalCode/src/functions/houses_ex.cpp +37 -0
- package/originalCode/src/functions/houses_ex2.cpp +46 -0
- package/originalCode/src/functions/jdet_to_utc.cpp +38 -0
- package/originalCode/src/functions/jdut1_to_utc.cpp +38 -0
- package/originalCode/src/functions/julday.cpp +25 -0
- package/originalCode/src/functions/lat_to_lmt.cpp +27 -0
- package/originalCode/src/functions/lmt_to_lat.cpp +27 -0
- package/originalCode/src/functions/lun_eclipse_how.cpp +34 -0
- package/originalCode/src/functions/lun_eclipse_when.cpp +31 -0
- package/originalCode/src/functions/lun_eclipse_when_loc.cpp +39 -0
- package/originalCode/src/functions/lun_occult_when_glob.cpp +35 -0
- package/originalCode/src/functions/lun_occult_when_loc.cpp +43 -0
- package/originalCode/src/functions/lun_occult_where.cpp +34 -0
- package/originalCode/src/functions/mooncross.cpp +26 -0
- package/originalCode/src/functions/mooncross_node.cpp +30 -0
- package/originalCode/src/functions/mooncross_node_ut.cpp +30 -0
- package/originalCode/src/functions/mooncross_ut.cpp +26 -0
- package/originalCode/src/functions/nod_aps.cpp +42 -0
- package/originalCode/src/functions/nod_aps_ut.cpp +42 -0
- package/originalCode/src/functions/orbit_max_min_true_distance.cpp +37 -0
- package/originalCode/src/functions/pheno.cpp +29 -0
- package/originalCode/src/functions/pheno_ut.cpp +29 -0
- package/originalCode/src/functions/radnorm.cpp +15 -0
- package/originalCode/src/functions/refrac.cpp +23 -0
- package/originalCode/src/functions/refrac_extended.cpp +32 -0
- package/originalCode/src/functions/revjul.cpp +33 -0
- package/originalCode/src/functions/rise_trans.cpp +44 -0
- package/originalCode/src/functions/rise_trans_true_hor.cpp +46 -0
- package/originalCode/src/functions/set_delta_t_userdef.cpp +14 -0
- package/originalCode/src/functions/set_ephe_path.cpp +14 -0
- package/originalCode/src/functions/set_jpl_file.cpp +14 -0
- package/originalCode/src/functions/set_sid_mode.cpp +20 -0
- package/originalCode/src/functions/set_tid_acc.cpp +14 -0
- package/originalCode/src/functions/set_topo.cpp +20 -0
- package/originalCode/src/functions/sidtime.cpp +15 -0
- package/originalCode/src/functions/sidtime0.cpp +21 -0
- package/originalCode/src/functions/sol_eclipse_how.cpp +34 -0
- package/originalCode/src/functions/sol_eclipse_when_glob.cpp +31 -0
- package/originalCode/src/functions/sol_eclipse_when_loc.cpp +39 -0
- package/originalCode/src/functions/sol_eclipse_where.cpp +30 -0
- package/originalCode/src/functions/solcross.cpp +26 -0
- package/originalCode/src/functions/solcross_ut.cpp +26 -0
- package/originalCode/src/functions/split_deg.cpp +35 -0
- package/originalCode/src/functions/time_equ.cpp +25 -0
- package/originalCode/src/functions/utc_time_zone.cpp +48 -0
- package/originalCode/src/functions/utc_to_jd.cpp +37 -0
- package/originalCode/src/functions/version.cpp +8 -0
- package/originalCode/src/functions/vis_limit_mag.cpp +50 -0
- package/originalCode/src/sweph.cpp +150 -0
- package/originalCode/src/sweph.h +119 -0
- package/originalCode/swisseph/swecl.c +6428 -0
- package/originalCode/swisseph/swedate.c +588 -0
- package/originalCode/swisseph/swedate.h +81 -0
- package/originalCode/swisseph/swehel.c +3511 -0
- package/originalCode/swisseph/swehouse.c +3143 -0
- package/originalCode/swisseph/swehouse.h +98 -0
- package/originalCode/swisseph/swejpl.c +958 -0
- package/originalCode/swisseph/swejpl.h +103 -0
- package/originalCode/swisseph/swemmoon.c +1930 -0
- package/originalCode/swisseph/swemplan.c +967 -0
- package/originalCode/swisseph/swemptab.h +10640 -0
- package/originalCode/swisseph/swenut2000a.h +2819 -0
- package/originalCode/swisseph/sweodef.h +326 -0
- package/originalCode/swisseph/sweph.c +8614 -0
- package/originalCode/swisseph/sweph.h +849 -0
- package/originalCode/swisseph/swephexp.h +1020 -0
- package/originalCode/swisseph/swephlib.c +4634 -0
- package/originalCode/swisseph/swephlib.h +189 -0
- package/package.json +28 -0
- package/scripts/gen-swemptab.js +177 -0
- package/scripts/gen-swenut2000a.js +106 -0
- package/src/SwissEph/README.md +268 -0
- package/src/SwissEph/UseCases/Ayanamsa.md +363 -0
- package/src/SwissEph/UseCases/AzimuthAltitude.md +408 -0
- package/src/SwissEph/UseCases/CoordinateSystems.md +337 -0
- package/src/SwissEph/UseCases/DateAndTime.md +368 -0
- package/src/SwissEph/UseCases/DeltaT.md +258 -0
- package/src/SwissEph/UseCases/EphemerisFiles.md +338 -0
- package/src/SwissEph/UseCases/FixedStars.md +300 -0
- package/src/SwissEph/UseCases/GauquelinSectors.md +304 -0
- package/src/SwissEph/UseCases/HeliacalEvents.md +396 -0
- package/src/SwissEph/UseCases/HelioCrossings.md +325 -0
- package/src/SwissEph/UseCases/HousePosition.md +254 -0
- package/src/SwissEph/UseCases/HouseSystems.md +279 -0
- package/src/SwissEph/UseCases/LunarEclipse.md +326 -0
- package/src/SwissEph/UseCases/MeridianTransit.md +279 -0
- package/src/SwissEph/UseCases/MoonCrossings.md +373 -0
- package/src/SwissEph/UseCases/NodesAndApsides.md +307 -0
- package/src/SwissEph/UseCases/Occultation.md +352 -0
- package/src/SwissEph/UseCases/OrbitalElements.md +469 -0
- package/src/SwissEph/UseCases/Phenomena.md +328 -0
- package/src/SwissEph/UseCases/PlanetPositions.md +366 -0
- package/src/SwissEph/UseCases/Planetocentric.md +278 -0
- package/src/SwissEph/UseCases/Refraction.md +314 -0
- package/src/SwissEph/UseCases/RiseAndSet.md +433 -0
- package/src/SwissEph/UseCases/SiderealTime.md +302 -0
- package/src/SwissEph/UseCases/SolarEclipse.md +379 -0
- package/src/SwissEph/UseCases/SunCrossings.md +275 -0
- package/src/SwissEph/UseCases/TopocentricCorrection.md +335 -0
- package/src/SwissEph/errors.ts +10 -0
- package/src/SwissEph/index.ts +823 -0
- package/src/SwissEph/types.ts +291 -0
- package/src/constants.ts +762 -0
- package/src/file-reader.ts +147 -0
- package/src/index.ts +10 -0
- package/src/swecl.ts +4526 -0
- package/src/swedate.ts +376 -0
- package/src/swehel.ts +1939 -0
- package/src/swehouse.ts +2167 -0
- package/src/swejpl.ts +470 -0
- package/src/swemmoon.ts +1318 -0
- package/src/swemplan.ts +585 -0
- package/src/swemptab.ts +4448 -0
- package/src/swenut2000a.ts +2763 -0
- package/src/sweph.ts +3993 -0
- package/src/swephlib.ts +2720 -0
- package/src/types.ts +490 -0
- package/tests/c-style/ayanamsa.test.ts +63 -0
- package/tests/c-style/config.test.ts +96 -0
- package/tests/c-style/crossings.test.ts +81 -0
- package/tests/c-style/date-time.test.ts +114 -0
- package/tests/c-style/eclipses.test.ts +84 -0
- package/tests/c-style/fixed-stars.test.ts +66 -0
- package/tests/c-style/heliacal.test.ts +34 -0
- package/tests/c-style/houses.test.ts +135 -0
- package/tests/c-style/math-utils.test.ts +160 -0
- package/tests/c-style/orbital.test.ts +78 -0
- package/tests/c-style/phenomena.test.ts +42 -0
- package/tests/c-style/planetocentric.test.ts +26 -0
- package/tests/c-style/planets.test.ts +117 -0
- package/tests/c-style/rise-set.test.ts +71 -0
- package/tests/helpers.ts +21 -0
- package/tests/modern/ayanamsa.test.ts +47 -0
- package/tests/modern/calc.test.ts +113 -0
- package/tests/modern/config.test.ts +46 -0
- package/tests/modern/crossings.test.ts +45 -0
- package/tests/modern/eclipses.test.ts +81 -0
- package/tests/modern/errors.test.ts +71 -0
- package/tests/modern/heliacal.test.ts +30 -0
- package/tests/modern/houses.test.ts +87 -0
- package/tests/modern/orbital.test.ts +79 -0
- package/tests/modern/phenomena.test.ts +41 -0
- package/tests/modern/rise-set.test.ts +60 -0
- package/tests/modern/statics.test.ts +99 -0
- package/tests/modern/utilities.test.ts +70 -0
- 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 ☊ and the descending node by ☋. 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.
|