@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,275 @@
|
|
|
1
|
+
# Sun Crossings (Solar Ingresses)
|
|
2
|
+
|
|
3
|
+
A **Sun crossing** (or **solar ingress**) is the precise moment when the Sun reaches a specific ecliptic longitude. Since the Sun moves along the ecliptic at roughly 1 degree per day, it crosses each degree of the zodiac once per year. The most important crossings are the **solstices** and **equinoxes** -- the four cardinal points that define the astronomical seasons.
|
|
4
|
+
|
|
5
|
+
The `sunCrossing()` method finds the next Julian Day when the Sun reaches a given ecliptic longitude, searching forward from a starting date.
|
|
6
|
+
|
|
7
|
+
This is essential for:
|
|
8
|
+
- Determining the exact start of astronomical seasons
|
|
9
|
+
- Finding zodiac sign ingresses (when the Sun enters each sign)
|
|
10
|
+
- Computing the tropical year length
|
|
11
|
+
- Casting ingress charts in mundane astrology (political/world event astrology)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Quick Example
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { SwissEph } from '../index';
|
|
19
|
+
|
|
20
|
+
const swe = new SwissEph();
|
|
21
|
+
|
|
22
|
+
// Find the next vernal equinox (Sun at 0° Aries) after Jan 1, 2025
|
|
23
|
+
const startJd = SwissEph.julianDay(2025, 1, 1, 0);
|
|
24
|
+
const result = swe.sunCrossing(0, startJd);
|
|
25
|
+
|
|
26
|
+
const d = SwissEph.fromJulianDay(result.jd);
|
|
27
|
+
console.log(`Vernal Equinox 2025: ${d.year}-${d.month}-${d.day.toFixed(6)}`);
|
|
28
|
+
// The Sun crosses 0° longitude around March 20, 2025
|
|
29
|
+
|
|
30
|
+
swe.close();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Detailed Examples
|
|
36
|
+
|
|
37
|
+
### Finding all four cardinal points (seasons) in a year
|
|
38
|
+
|
|
39
|
+
The four cardinal longitudes are:
|
|
40
|
+
- **0 degrees** -- Vernal Equinox (start of spring, Northern Hemisphere)
|
|
41
|
+
- **90 degrees** -- Summer Solstice (longest day)
|
|
42
|
+
- **180 degrees** -- Autumnal Equinox (start of autumn)
|
|
43
|
+
- **270 degrees** -- Winter Solstice (shortest day)
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { SwissEph } from '../index';
|
|
47
|
+
|
|
48
|
+
const swe = new SwissEph();
|
|
49
|
+
|
|
50
|
+
const year = 2025;
|
|
51
|
+
const startJd = SwissEph.julianDay(year, 1, 1, 0);
|
|
52
|
+
|
|
53
|
+
const cardinals = [
|
|
54
|
+
{ lon: 0, name: 'Vernal Equinox (Spring)' },
|
|
55
|
+
{ lon: 90, name: 'Summer Solstice' },
|
|
56
|
+
{ lon: 180, name: 'Autumnal Equinox (Fall)' },
|
|
57
|
+
{ lon: 270, name: 'Winter Solstice' },
|
|
58
|
+
];
|
|
59
|
+
|
|
60
|
+
for (const c of cardinals) {
|
|
61
|
+
const result = swe.sunCrossing(c.lon, startJd);
|
|
62
|
+
const d = SwissEph.fromJulianDay(result.jd);
|
|
63
|
+
const hours = (d.day % 1) * 24;
|
|
64
|
+
const h = Math.floor(hours);
|
|
65
|
+
const m = Math.floor((hours - h) * 60);
|
|
66
|
+
console.log(
|
|
67
|
+
`${c.name.padEnd(30)} ` +
|
|
68
|
+
`${d.year}-${String(d.month).padStart(2,'0')}-${String(Math.floor(d.day)).padStart(2,'0')} ` +
|
|
69
|
+
`${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')} UT`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
swe.close();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Finding all 12 zodiac sign ingresses
|
|
77
|
+
|
|
78
|
+
When the Sun enters each zodiac sign, it crosses the sign boundary at a specific longitude. Each sign spans 30 degrees:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { SwissEph } from '../index';
|
|
82
|
+
|
|
83
|
+
const swe = new SwissEph();
|
|
84
|
+
|
|
85
|
+
const year = 2025;
|
|
86
|
+
const startJd = SwissEph.julianDay(year, 1, 1, 0);
|
|
87
|
+
|
|
88
|
+
const signs = [
|
|
89
|
+
'Aries', 'Taurus', 'Gemini', 'Cancer',
|
|
90
|
+
'Leo', 'Virgo', 'Libra', 'Scorpio',
|
|
91
|
+
'Sagittarius', 'Capricorn', 'Aquarius', 'Pisces',
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
for (let i = 0; i < 12; i++) {
|
|
95
|
+
const longitude = i * 30;
|
|
96
|
+
// Search from start of year; for signs Sun has already passed,
|
|
97
|
+
// the search will find next year's ingress if needed
|
|
98
|
+
const result = swe.sunCrossing(longitude, startJd);
|
|
99
|
+
const d = SwissEph.fromJulianDay(result.jd);
|
|
100
|
+
|
|
101
|
+
const hours = (d.day % 1) * 24;
|
|
102
|
+
const h = Math.floor(hours);
|
|
103
|
+
const m = Math.floor((hours - h) * 60);
|
|
104
|
+
|
|
105
|
+
console.log(
|
|
106
|
+
`Sun enters ${signs[i].padEnd(12)} (${String(longitude).padStart(3)}°): ` +
|
|
107
|
+
`${d.year}-${String(d.month).padStart(2,'0')}-${String(Math.floor(d.day)).padStart(2,'0')} ` +
|
|
108
|
+
`${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')} UT`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
swe.close();
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Measuring the length of the tropical year
|
|
116
|
+
|
|
117
|
+
The tropical year is the time between two successive vernal equinoxes. It is approximately 365.2422 days, but varies slightly from year to year.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import { SwissEph } from '../index';
|
|
121
|
+
|
|
122
|
+
const swe = new SwissEph();
|
|
123
|
+
|
|
124
|
+
// Find vernal equinoxes for several consecutive years
|
|
125
|
+
const years: number[] = [];
|
|
126
|
+
const equinoxJds: number[] = [];
|
|
127
|
+
|
|
128
|
+
for (let year = 2020; year <= 2030; year++) {
|
|
129
|
+
const startJd = SwissEph.julianDay(year, 1, 1, 0);
|
|
130
|
+
const result = swe.sunCrossing(0, startJd);
|
|
131
|
+
years.push(year);
|
|
132
|
+
equinoxJds.push(result.jd);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Compute tropical year lengths
|
|
136
|
+
for (let i = 1; i < years.length; i++) {
|
|
137
|
+
const length = equinoxJds[i] - equinoxJds[i - 1];
|
|
138
|
+
const d = SwissEph.fromJulianDay(equinoxJds[i]);
|
|
139
|
+
const hours = (d.day % 1) * 24;
|
|
140
|
+
console.log(
|
|
141
|
+
`${years[i]} Equinox: ` +
|
|
142
|
+
`${d.year}-${String(d.month).padStart(2,'0')}-${String(Math.floor(d.day)).padStart(2,'0')} ` +
|
|
143
|
+
`${Math.floor(hours).toString().padStart(2,'0')}:${Math.floor((hours % 1) * 60).toString().padStart(2,'0')} UT ` +
|
|
144
|
+
` year length: ${length.toFixed(6)} days`
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
swe.close();
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Finding when the Sun reaches a specific degree (e.g., 15 degrees Taurus)
|
|
152
|
+
|
|
153
|
+
In astrology, you might want to know when the Sun reaches an exact degree -- for example, to find when the Sun hits 15 degrees Taurus (45 degrees ecliptic longitude), perhaps for a transit to a natal planet.
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { SwissEph } from '../index';
|
|
157
|
+
|
|
158
|
+
const swe = new SwissEph();
|
|
159
|
+
|
|
160
|
+
// 15° Taurus = 30° (Aries) + 15° = 45° ecliptic longitude
|
|
161
|
+
const targetLon = 45;
|
|
162
|
+
const startJd = SwissEph.julianDay(2025, 1, 1, 0);
|
|
163
|
+
const result = swe.sunCrossing(targetLon, startJd);
|
|
164
|
+
|
|
165
|
+
const d = SwissEph.fromJulianDay(result.jd);
|
|
166
|
+
const hours = (d.day % 1) * 24;
|
|
167
|
+
const h = Math.floor(hours);
|
|
168
|
+
const m = Math.floor((hours - h) * 60);
|
|
169
|
+
|
|
170
|
+
console.log(
|
|
171
|
+
`Sun reaches 15° Taurus: ` +
|
|
172
|
+
`${d.year}-${String(d.month).padStart(2,'0')}-${String(Math.floor(d.day)).padStart(2,'0')} ` +
|
|
173
|
+
`${String(h).padStart(2,'0')}:${String(m).padStart(2,'0')} UT`
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// Verify by computing the Sun's position at that moment
|
|
177
|
+
const sun = swe.calc(result.jd, 0); // SE_SUN = 0
|
|
178
|
+
console.log(`Sun longitude at that moment: ${sun.longitude.toFixed(6)}°`);
|
|
179
|
+
// Should be very close to 45.000000°
|
|
180
|
+
|
|
181
|
+
swe.close();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Deep Explanation
|
|
187
|
+
|
|
188
|
+
### The Ecliptic and Solar Longitude
|
|
189
|
+
|
|
190
|
+
The **ecliptic** is the apparent path of the Sun across the sky over the course of a year. It is the plane of Earth's orbit projected onto the celestial sphere. Solar longitude measures the Sun's position along this path:
|
|
191
|
+
|
|
192
|
+
- **0 degrees**: The Vernal Equinox point (also called the First Point of Aries), where the Sun crosses the celestial equator going northward
|
|
193
|
+
- **90 degrees**: The Sun is at its northernmost point (Summer Solstice)
|
|
194
|
+
- **180 degrees**: The Sun crosses the celestial equator going southward (Autumnal Equinox)
|
|
195
|
+
- **270 degrees**: The Sun is at its southernmost point (Winter Solstice)
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
90° (Summer Solstice, ~Jun 21)
|
|
199
|
+
|
|
|
200
|
+
|
|
|
201
|
+
180° ---------+--------- 0°/360° (Vernal Equinox, ~Mar 20)
|
|
202
|
+
(Autumnal |
|
|
203
|
+
Equinox, |
|
|
204
|
+
~Sep 23) |
|
|
205
|
+
270° (Winter Solstice, ~Dec 21)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### Equinoxes and Solstices
|
|
209
|
+
|
|
210
|
+
The **equinoxes** are the two moments when the Sun crosses the celestial equator. At these times, day and night are approximately equal in length everywhere on Earth ("equinox" comes from Latin "equal night").
|
|
211
|
+
|
|
212
|
+
The **solstices** are the two moments when the Sun reaches its maximum northern or southern declination. The Summer Solstice is the longest day in the Northern Hemisphere (shortest in the Southern), and vice versa for the Winter Solstice.
|
|
213
|
+
|
|
214
|
+
These four points divide the year into the four astronomical seasons. The exact dates shift slightly from year to year because the tropical year (365.2422 days) does not divide evenly into calendar days.
|
|
215
|
+
|
|
216
|
+
### Precession and the Tropical Zodiac
|
|
217
|
+
|
|
218
|
+
The Vernal Equinox point (0 degrees Aries) is not fixed among the stars. Due to **precession** -- the slow wobble of Earth's axis over a ~26,000-year cycle -- the equinox point drifts westward through the constellations at about 1 degree every 72 years.
|
|
219
|
+
|
|
220
|
+
This is the difference between the **tropical zodiac** (based on the equinox, used in Western astrology) and the **sidereal zodiac** (based on the fixed stars, used in Vedic astrology). The `sunCrossing()` method uses the tropical zodiac by default -- 0 degrees always means the Vernal Equinox point.
|
|
221
|
+
|
|
222
|
+
If you need sidereal crossings, apply an ayanamsa offset to the longitude:
|
|
223
|
+
```typescript
|
|
224
|
+
const ayanamsa = swe.getAyanamsa(jd); // e.g., 24.2° for Lahiri
|
|
225
|
+
const siderealTarget = 0; // 0° sidereal Aries
|
|
226
|
+
const tropicalTarget = siderealTarget + ayanamsa;
|
|
227
|
+
const result = swe.sunCrossing(tropicalTarget, jd);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### The Tropical Year
|
|
231
|
+
|
|
232
|
+
The tropical year -- the time from one Vernal Equinox to the next -- is the basis of our calendar. Its current mean length is approximately:
|
|
233
|
+
|
|
234
|
+
**365.24219 days = 365 days, 5 hours, 48 minutes, 45 seconds**
|
|
235
|
+
|
|
236
|
+
This is not exactly 365.25 days (the Julian calendar's approximation), which is why the Gregorian calendar has its leap year rules (divisible by 4, except centuries unless divisible by 400).
|
|
237
|
+
|
|
238
|
+
The tropical year length varies slightly from year to year (by up to about 20 minutes) due to gravitational perturbations from the Moon and other planets.
|
|
239
|
+
|
|
240
|
+
### Ingress Charts in Mundane Astrology
|
|
241
|
+
|
|
242
|
+
In **mundane astrology** (the astrology of nations and world events), an **ingress chart** is the horoscope cast for the exact moment the Sun enters a cardinal sign (0 degrees of Aries, Cancer, Libra, or Capricorn) for a given location (usually a national capital).
|
|
243
|
+
|
|
244
|
+
The **Aries ingress** chart (Vernal Equinox) is considered the most important, as it is said to set the tone for the entire year. Astrologers examine the positions of planets, the Ascendant, and house placements in this chart to make predictions about the coming season or year.
|
|
245
|
+
|
|
246
|
+
### Sun's Speed Variation
|
|
247
|
+
|
|
248
|
+
The Sun's apparent speed along the ecliptic is not constant. Due to Earth's elliptical orbit:
|
|
249
|
+
- The Sun moves fastest around **perihelion** (early January): ~1.019 degrees/day
|
|
250
|
+
- The Sun moves slowest around **aphelion** (early July): ~0.953 degrees/day
|
|
251
|
+
- Average speed: ~0.9856 degrees/day
|
|
252
|
+
|
|
253
|
+
This means the Sun spends more time in the signs it transits during Northern Hemisphere summer (Cancer through Sagittarius) than in the winter signs. The `sunCrossing()` function accounts for this automatically.
|
|
254
|
+
|
|
255
|
+
### API Details
|
|
256
|
+
|
|
257
|
+
```typescript
|
|
258
|
+
swe.sunCrossing(longitude: number, jd: number, flags?: number): CrossingResult
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**Parameters:**
|
|
262
|
+
- `longitude`: The target ecliptic longitude in degrees (0-360). The function normalizes values outside this range.
|
|
263
|
+
- `jd`: The starting Julian Day to search from. The function finds the **next** crossing after this date.
|
|
264
|
+
- `flags` (optional): Calculation flags. Normally omitted (defaults are appropriate for most uses).
|
|
265
|
+
|
|
266
|
+
**Returns:**
|
|
267
|
+
```typescript
|
|
268
|
+
interface CrossingResult {
|
|
269
|
+
jd: number; // Julian Day of the crossing
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The returned Julian Day is precise to sub-second accuracy. Convert to a calendar date with `SwissEph.fromJulianDay(result.jd)`.
|
|
274
|
+
|
|
275
|
+
**Error handling:** The method throws a `SwissEphError` if the crossing cannot be found (which should not happen for the Sun under normal circumstances, since the Sun completes a full cycle every year).
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# Topocentric Correction
|
|
2
|
+
|
|
3
|
+
**Geocentric** positions are calculated from the center of the Earth. **Topocentric** positions are calculated from a specific point on the Earth's surface -- your actual physical location. The difference between these two is called **diurnal parallax**, and it matters most for nearby objects.
|
|
4
|
+
|
|
5
|
+
Why does this distinction exist? Imagine two people on opposite sides of the Earth looking at the Moon at the same instant. They see it in slightly different positions against the background stars, because they are separated by about 12,700 km (the Earth's diameter). This shift in apparent position is parallax. For the Moon, which is only about 384,000 km away, this parallax can reach nearly **1 degree** -- that is twice the Moon's apparent diameter. For the Sun (150 million km away), it is about 9 arc-seconds. For Jupiter and beyond, it is negligible.
|
|
6
|
+
|
|
7
|
+
Most astrological software uses geocentric positions (from Earth's center) because the differences are small for most planets. But for precise work involving the Moon, solar eclipses, occultations, or near-Earth asteroids, topocentric correction is essential.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Quick Example
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { SwissEph } from '../index';
|
|
15
|
+
import { SE_MOON, SEFLG_TOPOCTR } from '../../constants';
|
|
16
|
+
|
|
17
|
+
// Set up the observer's location in the constructor
|
|
18
|
+
const swe = new SwissEph({
|
|
19
|
+
topo: { longitude: 2.35, latitude: 48.86, altitude: 35 }, // Paris
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const jd = SwissEph.julianDay(2025, 6, 15, 22);
|
|
23
|
+
|
|
24
|
+
// Topocentric Moon -- must pass SEFLG_TOPOCTR flag
|
|
25
|
+
const moonTopo = swe.calc(jd, SE_MOON, SEFLG_TOPOCTR);
|
|
26
|
+
console.log(`Moon (topocentric from Paris): ${moonTopo.longitude.toFixed(4)} deg`);
|
|
27
|
+
|
|
28
|
+
swe.close();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Detailed Examples
|
|
34
|
+
|
|
35
|
+
### Comparing geocentric vs topocentric Moon
|
|
36
|
+
|
|
37
|
+
This example shows the parallax effect directly by computing the Moon's position both ways.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { SwissEph } from '../index';
|
|
41
|
+
import { SE_MOON, SEFLG_TOPOCTR } from '../../constants';
|
|
42
|
+
|
|
43
|
+
// Create two instances: one with topo, one without
|
|
44
|
+
const sweTopo = new SwissEph({
|
|
45
|
+
topo: { longitude: -73.98, latitude: 40.75, altitude: 10 }, // New York
|
|
46
|
+
});
|
|
47
|
+
const sweGeo = new SwissEph();
|
|
48
|
+
|
|
49
|
+
const jd = SwissEph.julianDay(2025, 3, 20, 3); // Moon near meridian transit
|
|
50
|
+
|
|
51
|
+
const moonGeo = sweGeo.calc(jd, SE_MOON);
|
|
52
|
+
const moonTopo = sweTopo.calc(jd, SE_MOON, SEFLG_TOPOCTR);
|
|
53
|
+
|
|
54
|
+
console.log(`Moon geocentric longitude: ${moonGeo.longitude.toFixed(4)} deg`);
|
|
55
|
+
console.log(`Moon topocentric longitude: ${moonTopo.longitude.toFixed(4)} deg`);
|
|
56
|
+
console.log(`Longitude difference: ${(moonTopo.longitude - moonGeo.longitude).toFixed(4)} deg`);
|
|
57
|
+
|
|
58
|
+
console.log(`\nMoon geocentric latitude: ${moonGeo.latitude.toFixed(4)} deg`);
|
|
59
|
+
console.log(`Moon topocentric latitude: ${moonTopo.latitude.toFixed(4)} deg`);
|
|
60
|
+
console.log(`Latitude difference: ${(moonTopo.latitude - moonGeo.latitude).toFixed(4)} deg`);
|
|
61
|
+
|
|
62
|
+
console.log(`\nMoon geocentric distance: ${moonGeo.distance.toFixed(6)} AU`);
|
|
63
|
+
console.log(`Moon topocentric distance: ${moonTopo.distance.toFixed(6)} AU`);
|
|
64
|
+
|
|
65
|
+
sweGeo.close();
|
|
66
|
+
sweTopo.close();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Using setTopo() to change location
|
|
70
|
+
|
|
71
|
+
Instead of setting the topocentric position in the constructor, you can use `setTopo()` to change it at any time. This is useful when computing positions for multiple observers.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { SwissEph } from '../index';
|
|
75
|
+
import { SE_MOON, SEFLG_TOPOCTR } from '../../constants';
|
|
76
|
+
|
|
77
|
+
const swe = new SwissEph();
|
|
78
|
+
const jd = SwissEph.julianDay(2025, 1, 15, 0);
|
|
79
|
+
|
|
80
|
+
const locations = [
|
|
81
|
+
{ name: 'North Pole', geo: { longitude: 0, latitude: 90, altitude: 0 } },
|
|
82
|
+
{ name: 'Quito', geo: { longitude: -78.47, latitude: -0.18, altitude: 2850 } },
|
|
83
|
+
{ name: 'London', geo: { longitude: -0.13, latitude: 51.51, altitude: 11 } },
|
|
84
|
+
{ name: 'Sydney', geo: { longitude: 151.21, latitude: -33.87, altitude: 58 } },
|
|
85
|
+
{ name: 'South Pole', geo: { longitude: 0, latitude: -90, altitude: 2835 } },
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
const moonGeo = swe.calc(jd, SE_MOON);
|
|
89
|
+
console.log(`Moon geocentric: ${moonGeo.longitude.toFixed(4)} deg lon, ${moonGeo.latitude.toFixed(4)} deg lat\n`);
|
|
90
|
+
|
|
91
|
+
console.log('Topocentric Moon from different locations:');
|
|
92
|
+
for (const loc of locations) {
|
|
93
|
+
swe.setTopo(loc.geo);
|
|
94
|
+
const moon = swe.calc(jd, SE_MOON, SEFLG_TOPOCTR);
|
|
95
|
+
const dLon = moon.longitude - moonGeo.longitude;
|
|
96
|
+
const dLat = moon.latitude - moonGeo.latitude;
|
|
97
|
+
console.log(
|
|
98
|
+
` ${loc.name.padEnd(12)} ` +
|
|
99
|
+
`lon=${moon.longitude.toFixed(4)} lat=${moon.latitude.toFixed(4)} ` +
|
|
100
|
+
`(dLon=${dLon.toFixed(4)}, dLat=${dLat.toFixed(4)})`
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
swe.close();
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Effect on the Sun and planets
|
|
108
|
+
|
|
109
|
+
The topocentric correction is much smaller for the Sun and planets than for the Moon. This example quantifies the difference for each body.
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { SwissEph } from '../index';
|
|
113
|
+
import {
|
|
114
|
+
SE_SUN, SE_MOON, SE_MERCURY, SE_VENUS, SE_MARS,
|
|
115
|
+
SE_JUPITER, SE_SATURN, SEFLG_TOPOCTR,
|
|
116
|
+
} from '../../constants';
|
|
117
|
+
|
|
118
|
+
const swe = new SwissEph({
|
|
119
|
+
topo: { longitude: -73.98, latitude: 40.75, altitude: 10 }, // New York
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const jd = SwissEph.julianDay(2025, 6, 15, 0);
|
|
123
|
+
|
|
124
|
+
const bodies = [
|
|
125
|
+
{ id: SE_SUN, name: 'Sun' },
|
|
126
|
+
{ id: SE_MOON, name: 'Moon' },
|
|
127
|
+
{ id: SE_MERCURY, name: 'Mercury' },
|
|
128
|
+
{ id: SE_VENUS, name: 'Venus' },
|
|
129
|
+
{ id: SE_MARS, name: 'Mars' },
|
|
130
|
+
{ id: SE_JUPITER, name: 'Jupiter' },
|
|
131
|
+
{ id: SE_SATURN, name: 'Saturn' },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
console.log('Topocentric parallax from New York:');
|
|
135
|
+
console.log('Body Geo lon Topo lon Difference (arcsec)');
|
|
136
|
+
console.log('-'.repeat(60));
|
|
137
|
+
|
|
138
|
+
for (const b of bodies) {
|
|
139
|
+
const geo = swe.calc(jd, b.id);
|
|
140
|
+
const topo = swe.calc(jd, b.id, SEFLG_TOPOCTR);
|
|
141
|
+
const diffArcsec = (topo.longitude - geo.longitude) * 3600;
|
|
142
|
+
console.log(
|
|
143
|
+
`${b.name.padEnd(9)} ` +
|
|
144
|
+
`${geo.longitude.toFixed(4).padStart(10)} ` +
|
|
145
|
+
`${topo.longitude.toFixed(4).padStart(10)} ` +
|
|
146
|
+
`${diffArcsec.toFixed(2).padStart(10)}`
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
// Moon: up to ~3600 arcsec (1 degree)
|
|
150
|
+
// Sun: ~9 arcsec
|
|
151
|
+
// Planets: < 1 arcsec typically
|
|
152
|
+
|
|
153
|
+
swe.close();
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Topocentric Moon for eclipse timing
|
|
157
|
+
|
|
158
|
+
When computing the exact timing of a lunar occultation or the moment of eclipse contact for your location, topocentric positions give you the precision you need.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { SwissEph } from '../index';
|
|
162
|
+
import { SE_SUN, SE_MOON, SEFLG_TOPOCTR } from '../../constants';
|
|
163
|
+
|
|
164
|
+
// Austin, Texas -- in the path of the 2024 April 8 total solar eclipse
|
|
165
|
+
const swe = new SwissEph({
|
|
166
|
+
topo: { longitude: -97.74, latitude: 30.27, altitude: 150 },
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// Near the time of eclipse maximum
|
|
170
|
+
const jd = SwissEph.julianDay(2024, 4, 8, 18.3); // ~18:18 UT
|
|
171
|
+
|
|
172
|
+
const sunGeo = swe.calc(jd, SE_SUN);
|
|
173
|
+
const moonGeo = swe.calc(jd, SE_MOON);
|
|
174
|
+
const sunTopo = swe.calc(jd, SE_SUN, SEFLG_TOPOCTR);
|
|
175
|
+
const moonTopo = swe.calc(jd, SE_MOON, SEFLG_TOPOCTR);
|
|
176
|
+
|
|
177
|
+
console.log('Geocentric Sun-Moon separation:');
|
|
178
|
+
const sepGeo = moonGeo.longitude - sunGeo.longitude;
|
|
179
|
+
console.log(` ${sepGeo.toFixed(4)} deg`);
|
|
180
|
+
|
|
181
|
+
console.log('Topocentric Sun-Moon separation (from Austin):');
|
|
182
|
+
const sepTopo = moonTopo.longitude - sunTopo.longitude;
|
|
183
|
+
console.log(` ${sepTopo.toFixed(4)} deg`);
|
|
184
|
+
|
|
185
|
+
console.log(`\nDifference: ${((sepTopo - sepGeo) * 3600).toFixed(1)} arcsec`);
|
|
186
|
+
// This difference determines whether you see totality or a near miss!
|
|
187
|
+
|
|
188
|
+
swe.close();
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Combining topocentric with sidereal
|
|
192
|
+
|
|
193
|
+
Topocentric correction can be combined with other flags like `SEFLG_SIDEREAL` or `SEFLG_EQUATORIAL`.
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { SwissEph } from '../index';
|
|
197
|
+
import {
|
|
198
|
+
SE_MOON, SE_SIDM_LAHIRI,
|
|
199
|
+
SEFLG_TOPOCTR, SEFLG_SIDEREAL, SEFLG_EQUATORIAL,
|
|
200
|
+
} from '../../constants';
|
|
201
|
+
|
|
202
|
+
const swe = new SwissEph({
|
|
203
|
+
siderealMode: SE_SIDM_LAHIRI,
|
|
204
|
+
topo: { longitude: 77.59, latitude: 12.97, altitude: 920 }, // Bangalore
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
const jd = SwissEph.julianDay(2025, 1, 15, 18);
|
|
208
|
+
|
|
209
|
+
// Sidereal topocentric Moon
|
|
210
|
+
const moonSidTopo = swe.calc(jd, SE_MOON, SEFLG_SIDEREAL | SEFLG_TOPOCTR);
|
|
211
|
+
console.log(`Moon sidereal topocentric: ${moonSidTopo.longitude.toFixed(4)} deg (Lahiri)`);
|
|
212
|
+
|
|
213
|
+
// Equatorial topocentric Moon (RA/Dec from observer's location)
|
|
214
|
+
const moonEqTopo = swe.calc(jd, SE_MOON, SEFLG_EQUATORIAL | SEFLG_TOPOCTR);
|
|
215
|
+
console.log(`Moon RA (topocentric): ${moonEqTopo.longitude.toFixed(4)} deg`);
|
|
216
|
+
console.log(`Moon Dec (topocentric): ${moonEqTopo.latitude.toFixed(4)} deg`);
|
|
217
|
+
|
|
218
|
+
swe.close();
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Deep Explanation
|
|
224
|
+
|
|
225
|
+
### What is diurnal parallax?
|
|
226
|
+
|
|
227
|
+
**Diurnal parallax** (from Greek "parallaxis" = alteration) is the apparent shift in position of a celestial body caused by the observer being displaced from Earth's center. It is called "diurnal" because as the Earth rotates over 24 hours, the observer sweeps through different positions, and the parallax shifts accordingly.
|
|
228
|
+
|
|
229
|
+
The maximum possible parallax for any object is called the **horizontal parallax** -- it occurs when the object is on the observer's horizon (the maximum displacement from Earth's center in the direction of the object). For the Moon, the horizontal parallax is about:
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
HP_Moon = arctan(R_Earth / d_Moon)
|
|
233
|
+
= arctan(6371 km / 384400 km)
|
|
234
|
+
= 0.95 degrees
|
|
235
|
+
= 57 arc-minutes
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
This is nearly a full degree. The actual parallax at any given moment depends on the Moon's altitude above the horizon and the observer's latitude.
|
|
239
|
+
|
|
240
|
+
For comparison:
|
|
241
|
+
- Sun: ~9 arc-seconds (0.0025 degrees)
|
|
242
|
+
- Mars at closest approach: ~23 arc-seconds
|
|
243
|
+
- Jupiter: ~2 arc-seconds
|
|
244
|
+
- Saturn: ~1 arc-second
|
|
245
|
+
|
|
246
|
+
### How topocentric correction works
|
|
247
|
+
|
|
248
|
+
The Swiss Ephemeris computes topocentric positions by:
|
|
249
|
+
|
|
250
|
+
1. Computing the geocentric position of the body normally
|
|
251
|
+
2. Computing the observer's position on the Earth's surface in the same coordinate system (using the geodetic latitude, longitude, and altitude)
|
|
252
|
+
3. Subtracting the observer's position vector from the body's geocentric position vector
|
|
253
|
+
4. Converting the result back to ecliptic (or equatorial) coordinates
|
|
254
|
+
|
|
255
|
+
The observer's position on Earth's surface depends on:
|
|
256
|
+
- **Geodetic latitude**: the latitude you read from a map or GPS. This differs from geocentric latitude because the Earth is not a perfect sphere -- it is an oblate spheroid (wider at the equator). At 45 degrees latitude, the difference is about 11 arc-minutes.
|
|
257
|
+
- **Longitude**: determines the observer's east-west position as Earth rotates.
|
|
258
|
+
- **Altitude above sea level**: a higher altitude increases the observer's distance from Earth's center, slightly increasing the parallax.
|
|
259
|
+
|
|
260
|
+
### When topocentric matters
|
|
261
|
+
|
|
262
|
+
| Scenario | Importance |
|
|
263
|
+
|----------|-----------|
|
|
264
|
+
| Moon position for astrology | Moderate. Up to ~1 deg difference. Some precise astrologers prefer topocentric charts. |
|
|
265
|
+
| Eclipse contact times | Critical. A fraction of a degree in the Moon's position determines whether totality occurs at your location. |
|
|
266
|
+
| Occultation predictions | Critical. Whether a star is hidden by the Moon depends on the exact topocentric Moon position. |
|
|
267
|
+
| Moon rise/set times | Important. The Swiss Ephemeris rise/set functions handle topocentric correction internally. |
|
|
268
|
+
| Sun position for precise sundials | Moderate. ~9 arcsec matters for precision sundial calibration. |
|
|
269
|
+
| Planet positions for astrology | Negligible. Less than 1 arcsec for all planets beyond Mars. |
|
|
270
|
+
| Fixed star positions | Zero effect. Stars are infinitely far away; parallax from Earth's surface is unmeasurable. |
|
|
271
|
+
|
|
272
|
+
### Geocentric vs geodetic latitude
|
|
273
|
+
|
|
274
|
+
An important subtlety: the latitude you get from a GPS or a map is **geodetic latitude** -- the angle between the local surface normal and the equatorial plane. Because the Earth is flattened at the poles, this differs from **geocentric latitude** -- the angle between the line to the Earth's center and the equatorial plane. The Swiss Ephemeris handles this conversion internally when you provide geodetic coordinates (which is what you should always provide).
|
|
275
|
+
|
|
276
|
+
The difference between geodetic and geocentric latitude can be up to about 11.5 arc-minutes (0.19 degrees) at 45 degrees latitude. At the equator and poles, they are identical.
|
|
277
|
+
|
|
278
|
+
### Altitude effect
|
|
279
|
+
|
|
280
|
+
Observer altitude above sea level has a small but measurable effect. A person on a 3,000-meter mountain is about 3 km farther from Earth's center than someone at sea level, which increases the parallax slightly. The effect is most pronounced for the Moon (a few arc-seconds) and negligible for everything else.
|
|
281
|
+
|
|
282
|
+
For very precise work (eclipse timing, occultation predictions), always include the observer's altitude.
|
|
283
|
+
|
|
284
|
+
### The constructor option vs setTopo()
|
|
285
|
+
|
|
286
|
+
There are two ways to set the topocentric position:
|
|
287
|
+
|
|
288
|
+
**Constructor option** (set once at creation time):
|
|
289
|
+
```typescript
|
|
290
|
+
const swe = new SwissEph({
|
|
291
|
+
topo: { longitude: -0.13, latitude: 51.51, altitude: 11 }
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
**setTopo() method** (can be changed at any time):
|
|
296
|
+
```typescript
|
|
297
|
+
const swe = new SwissEph();
|
|
298
|
+
swe.setTopo({ longitude: -0.13, latitude: 51.51, altitude: 11 });
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Both produce the same result. The `setTopo()` method is useful when you need to compute positions for multiple observers with the same instance.
|
|
302
|
+
|
|
303
|
+
### The SEFLG_TOPOCTR flag
|
|
304
|
+
|
|
305
|
+
Setting up the topocentric position (via constructor or `setTopo()`) only configures **where** the observer is. You must also pass `SEFLG_TOPOCTR` in the `flags` parameter of `calc()` to actually enable the topocentric correction. Without this flag, the position will still be geocentric even if `topo` is configured.
|
|
306
|
+
|
|
307
|
+
This two-step design (configure location, then opt-in per calculation) allows you to easily compare geocentric and topocentric results without creating separate instances.
|
|
308
|
+
|
|
309
|
+
### Combining with other flags
|
|
310
|
+
|
|
311
|
+
`SEFLG_TOPOCTR` can be combined with other flags using bitwise OR:
|
|
312
|
+
|
|
313
|
+
| Combination | Effect |
|
|
314
|
+
|------------|--------|
|
|
315
|
+
| `SEFLG_TOPOCTR` | Topocentric ecliptic coordinates |
|
|
316
|
+
| `SEFLG_TOPOCTR \| SEFLG_EQUATORIAL` | Topocentric equatorial (RA/Dec from observer) |
|
|
317
|
+
| `SEFLG_TOPOCTR \| SEFLG_SIDEREAL` | Topocentric sidereal ecliptic |
|
|
318
|
+
| `SEFLG_TOPOCTR \| SEFLG_EQUATORIAL \| SEFLG_SIDEREAL` | Topocentric sidereal equatorial |
|
|
319
|
+
|
|
320
|
+
`SEFLG_TOPOCTR` cannot be combined with `SEFLG_HELCTR` or `SEFLG_BARYCTR` (those place the observer at the Sun or solar system barycenter, which contradicts the idea of being on Earth's surface).
|
|
321
|
+
|
|
322
|
+
### The GeoPosition type
|
|
323
|
+
|
|
324
|
+
```typescript
|
|
325
|
+
interface GeoPosition {
|
|
326
|
+
longitude: number; // Geographic longitude in degrees. East = positive, West = negative.
|
|
327
|
+
latitude: number; // Geographic (geodetic) latitude in degrees. North = positive, South = negative.
|
|
328
|
+
altitude?: number; // Altitude above sea level in meters. Defaults to 0.
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Examples:
|
|
333
|
+
- New York: `{ longitude: -73.98, latitude: 40.75, altitude: 10 }`
|
|
334
|
+
- Tokyo: `{ longitude: 139.69, latitude: 35.69, altitude: 40 }`
|
|
335
|
+
- South Pole: `{ longitude: 0, latitude: -90, altitude: 2835 }`
|