@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,408 @@
|
|
|
1
|
+
# Azimuth and Altitude
|
|
2
|
+
|
|
3
|
+
**Azimuth** and **altitude** form the **horizontal coordinate system**, which describes where an object appears in the sky as seen from a specific location on Earth at a specific time. Unlike ecliptic or equatorial coordinates (which are fixed to the celestial sphere), horizontal coordinates change constantly as the Earth rotates.
|
|
4
|
+
|
|
5
|
+
- **Altitude** (also called elevation): The angle above the horizon, in degrees. 0 degrees = on the horizon, 90 degrees = directly overhead (the zenith), negative values = below the horizon.
|
|
6
|
+
- **Azimuth**: The compass direction along the horizon, measured in degrees.
|
|
7
|
+
|
|
8
|
+
This coordinate system is immediately practical: it tells you exactly where to point a telescope, where to look in the sky, or whether an object is above the horizon at all. It is used in telescope pointing systems, satellite tracking, architectural sun studies, and any situation where you need to know the physical direction of a celestial body from your location.
|
|
9
|
+
|
|
10
|
+
**IMPORTANT: Swiss Ephemeris azimuth convention** -- The Swiss Ephemeris measures azimuth starting from **South**, going clockwise through **West**:
|
|
11
|
+
- 0 degrees = **South**
|
|
12
|
+
- 90 degrees = **West**
|
|
13
|
+
- 180 degrees = **North**
|
|
14
|
+
- 270 degrees = **East**
|
|
15
|
+
|
|
16
|
+
This is **different from the common navigation/compass convention** where 0 degrees = North, 90 degrees = East, 180 degrees = South, 270 degrees = West. If you need compass bearings, add 180 degrees and normalize to [0, 360):
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
const compassAzimuth = (sweAzimuth + 180) % 360;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Quick Example
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { SwissEph } from '../index';
|
|
28
|
+
import { SE_SUN } from '../../constants';
|
|
29
|
+
|
|
30
|
+
const swe = new SwissEph();
|
|
31
|
+
|
|
32
|
+
// Where is the Sun in the sky from New York at 3 PM UT on June 21, 2024?
|
|
33
|
+
const jd = SwissEph.julianDay(2024, 6, 21, 15);
|
|
34
|
+
const nyc = { longitude: -74.006, latitude: 40.713 };
|
|
35
|
+
|
|
36
|
+
// First get the Sun's ecliptic position
|
|
37
|
+
const sun = swe.calc(jd, SE_SUN);
|
|
38
|
+
|
|
39
|
+
// Convert to horizontal coordinates
|
|
40
|
+
const hor = swe.azalt(jd, nyc, sun.longitude, sun.latitude, sun.distance);
|
|
41
|
+
|
|
42
|
+
console.log(`Sun azimuth (SE convention): ${hor.azimuth.toFixed(2)} deg`);
|
|
43
|
+
console.log(`Sun true altitude: ${hor.trueAltitude.toFixed(2)} deg`);
|
|
44
|
+
console.log(`Sun apparent altitude: ${hor.apparentAltitude.toFixed(2)} deg`);
|
|
45
|
+
|
|
46
|
+
// Convert to compass bearing
|
|
47
|
+
const compass = (hor.azimuth + 180) % 360;
|
|
48
|
+
console.log(`Sun compass bearing: ${compass.toFixed(2)} deg`);
|
|
49
|
+
|
|
50
|
+
swe.close();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Detailed Examples
|
|
56
|
+
|
|
57
|
+
### Sun position throughout the day
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import { SwissEph } from '../index';
|
|
61
|
+
import { SE_SUN } from '../../constants';
|
|
62
|
+
|
|
63
|
+
const swe = new SwissEph();
|
|
64
|
+
|
|
65
|
+
const london = { longitude: -0.128, latitude: 51.507 };
|
|
66
|
+
|
|
67
|
+
console.log('Sun position from London, June 21, 2024:');
|
|
68
|
+
console.log('Hour(UT) Altitude Azimuth(SE) Compass');
|
|
69
|
+
|
|
70
|
+
for (let hour = 4; hour <= 21; hour++) {
|
|
71
|
+
const jd = SwissEph.julianDay(2024, 6, 21, hour);
|
|
72
|
+
const sun = swe.calc(jd, SE_SUN);
|
|
73
|
+
const hor = swe.azalt(jd, london, sun.longitude, sun.latitude, sun.distance);
|
|
74
|
+
|
|
75
|
+
const compass = (hor.azimuth + 180) % 360;
|
|
76
|
+
const compassDir = compassDirection(compass);
|
|
77
|
+
|
|
78
|
+
if (hor.apparentAltitude > -2) { // Show when Sun is near or above horizon
|
|
79
|
+
console.log(
|
|
80
|
+
` ${String(hour).padStart(2)}:00 ` +
|
|
81
|
+
`${hor.apparentAltitude.toFixed(1).padStart(6)} deg ` +
|
|
82
|
+
`${hor.azimuth.toFixed(1).padStart(7)} deg ` +
|
|
83
|
+
`${compass.toFixed(1).padStart(6)} deg ${compassDir}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function compassDirection(deg: number): string {
|
|
89
|
+
const dirs = ['N','NNE','NE','ENE','E','ESE','SE','SSE','S','SSW','SW','WSW','W','WNW','NW','NNW'];
|
|
90
|
+
const index = Math.round(deg / 22.5) % 16;
|
|
91
|
+
return dirs[index];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
swe.close();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### True altitude vs apparent altitude
|
|
98
|
+
|
|
99
|
+
The `azalt` function returns both the **true** (geometric) altitude and the **apparent** altitude (after atmospheric refraction). Refraction makes objects appear slightly higher than they actually are, especially near the horizon.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { SwissEph } from '../index';
|
|
103
|
+
import { SE_SUN } from '../../constants';
|
|
104
|
+
|
|
105
|
+
const swe = new SwissEph();
|
|
106
|
+
|
|
107
|
+
const geo = { longitude: 0, latitude: 51.5 };
|
|
108
|
+
|
|
109
|
+
// Check the Sun near sunset when refraction is strongest
|
|
110
|
+
const jd = SwissEph.julianDay(2024, 3, 20, 18); // Near sunset at equinox
|
|
111
|
+
const sun = swe.calc(jd, SE_SUN);
|
|
112
|
+
const hor = swe.azalt(jd, geo, sun.longitude, sun.latitude, sun.distance);
|
|
113
|
+
|
|
114
|
+
console.log(`True (geometric) altitude: ${hor.trueAltitude.toFixed(4)} deg`);
|
|
115
|
+
console.log(`Apparent altitude: ${hor.apparentAltitude.toFixed(4)} deg`);
|
|
116
|
+
console.log(`Refraction effect: ${(hor.apparentAltitude - hor.trueAltitude).toFixed(4)} deg`);
|
|
117
|
+
// Near the horizon, refraction lifts the apparent position by about 0.5 degrees
|
|
118
|
+
// At higher altitudes the effect diminishes rapidly
|
|
119
|
+
|
|
120
|
+
swe.close();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Custom atmospheric conditions
|
|
124
|
+
|
|
125
|
+
Refraction depends on pressure and temperature. You can specify these for your location.
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
import { SwissEph } from '../index';
|
|
129
|
+
import { SE_SUN } from '../../constants';
|
|
130
|
+
|
|
131
|
+
const swe = new SwissEph();
|
|
132
|
+
|
|
133
|
+
const geo = { longitude: 0, latitude: 51.5 };
|
|
134
|
+
const jd = SwissEph.julianDay(2024, 3, 20, 18);
|
|
135
|
+
const sun = swe.calc(jd, SE_SUN);
|
|
136
|
+
|
|
137
|
+
// Standard atmosphere (default)
|
|
138
|
+
const standard = swe.azalt(jd, geo, sun.longitude, sun.latitude, sun.distance);
|
|
139
|
+
console.log(`Standard (1013.25 mbar, 15C): apparent alt = ${standard.apparentAltitude.toFixed(4)} deg`);
|
|
140
|
+
|
|
141
|
+
// High altitude, cold conditions
|
|
142
|
+
const highAlt = swe.azalt(jd, geo, sun.longitude, sun.latitude, sun.distance,
|
|
143
|
+
0, // calcFlag: SE_ECL2HOR (default)
|
|
144
|
+
700, // pressure in mbar (at ~3000m elevation)
|
|
145
|
+
-10 // temperature in Celsius
|
|
146
|
+
);
|
|
147
|
+
console.log(`High altitude (700 mbar, -10C): apparent alt = ${highAlt.apparentAltitude.toFixed(4)} deg`);
|
|
148
|
+
|
|
149
|
+
// No refraction (pressure = 0)
|
|
150
|
+
const noRefr = swe.azalt(jd, geo, sun.longitude, sun.latitude, sun.distance,
|
|
151
|
+
0, 0, 0);
|
|
152
|
+
console.log(`No refraction (0 mbar): apparent alt = ${noRefr.apparentAltitude.toFixed(4)} deg`);
|
|
153
|
+
|
|
154
|
+
swe.close();
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Using equatorial input (SE_EQU2HOR)
|
|
158
|
+
|
|
159
|
+
If you already have equatorial coordinates (Right Ascension and Declination) instead of ecliptic coordinates, use `SE_EQU2HOR` as the calculation flag.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
import { SwissEph } from '../index';
|
|
163
|
+
import { SE_SUN, SEFLG_EQUATORIAL, SE_EQU2HOR } from '../../constants';
|
|
164
|
+
|
|
165
|
+
const swe = new SwissEph();
|
|
166
|
+
|
|
167
|
+
const jd = SwissEph.julianDay(2024, 6, 21, 15);
|
|
168
|
+
const geo = { longitude: -74.006, latitude: 40.713 };
|
|
169
|
+
|
|
170
|
+
// Get Sun in equatorial coordinates
|
|
171
|
+
const sun = swe.calc(jd, SE_SUN, SEFLG_EQUATORIAL);
|
|
172
|
+
const ra = sun.longitude; // Right Ascension in degrees
|
|
173
|
+
const dec = sun.latitude; // Declination in degrees
|
|
174
|
+
|
|
175
|
+
// Convert from equatorial to horizontal
|
|
176
|
+
// When using SE_EQU2HOR, pass RA as "lon" and Dec as "lat"
|
|
177
|
+
const hor = swe.azalt(jd, geo, ra, dec, 1, SE_EQU2HOR);
|
|
178
|
+
|
|
179
|
+
console.log(`From equatorial (RA=${ra.toFixed(2)}, Dec=${dec.toFixed(2)}):`);
|
|
180
|
+
console.log(` Azimuth: ${hor.azimuth.toFixed(2)} deg (SE convention)`);
|
|
181
|
+
console.log(` True altitude: ${hor.trueAltitude.toFixed(2)} deg`);
|
|
182
|
+
console.log(` Apparent altitude: ${hor.apparentAltitude.toFixed(2)} deg`);
|
|
183
|
+
|
|
184
|
+
swe.close();
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Reverse conversion: azimuth/altitude to ecliptic
|
|
188
|
+
|
|
189
|
+
Given a direction in the sky (azimuth and apparent altitude), you can find what ecliptic longitude and latitude that direction corresponds to.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { SwissEph } from '../index';
|
|
193
|
+
import { SE_ECL2HOR, SE_EQU2HOR } from '../../constants';
|
|
194
|
+
|
|
195
|
+
const swe = new SwissEph();
|
|
196
|
+
|
|
197
|
+
const jd = SwissEph.julianDay(2024, 6, 21, 15);
|
|
198
|
+
const geo = { longitude: -74.006, latitude: 40.713 };
|
|
199
|
+
|
|
200
|
+
// I see something at azimuth 90 deg (West in SE convention) and altitude 45 deg
|
|
201
|
+
// What ecliptic coordinates does that correspond to?
|
|
202
|
+
const result = swe.azaltReverse(jd, geo, 90, 45, SE_ECL2HOR);
|
|
203
|
+
console.log(`Ecliptic longitude: ${result.azimuth.toFixed(2)} deg`);
|
|
204
|
+
console.log(`Ecliptic latitude: ${result.altitude.toFixed(2)} deg`);
|
|
205
|
+
|
|
206
|
+
// Or get equatorial coordinates back:
|
|
207
|
+
const resultEqu = swe.azaltReverse(jd, geo, 90, 45, SE_EQU2HOR);
|
|
208
|
+
console.log(`\nRight Ascension: ${resultEqu.azimuth.toFixed(2)} deg`);
|
|
209
|
+
console.log(`Declination: ${resultEqu.altitude.toFixed(2)} deg`);
|
|
210
|
+
|
|
211
|
+
swe.close();
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Checking if a planet is visible (above the horizon)
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { SwissEph } from '../index';
|
|
218
|
+
import {
|
|
219
|
+
SE_SUN, SE_MOON, SE_VENUS, SE_MARS, SE_JUPITER, SE_SATURN,
|
|
220
|
+
} from '../../constants';
|
|
221
|
+
|
|
222
|
+
const swe = new SwissEph();
|
|
223
|
+
|
|
224
|
+
const jd = SwissEph.julianDay(2024, 4, 15, 20); // 8 PM UT
|
|
225
|
+
const paris = { longitude: 2.352, latitude: 48.857 };
|
|
226
|
+
|
|
227
|
+
const bodies = [
|
|
228
|
+
{ id: SE_SUN, name: 'Sun' },
|
|
229
|
+
{ id: SE_MOON, name: 'Moon' },
|
|
230
|
+
{ id: SE_VENUS, name: 'Venus' },
|
|
231
|
+
{ id: SE_MARS, name: 'Mars' },
|
|
232
|
+
{ id: SE_JUPITER, name: 'Jupiter' },
|
|
233
|
+
{ id: SE_SATURN, name: 'Saturn' },
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
console.log('Visibility from Paris at 20:00 UT, April 15, 2024:');
|
|
237
|
+
for (const b of bodies) {
|
|
238
|
+
const pos = swe.calc(jd, b.id);
|
|
239
|
+
const hor = swe.azalt(jd, paris, pos.longitude, pos.latitude, pos.distance);
|
|
240
|
+
const compass = (hor.azimuth + 180) % 360;
|
|
241
|
+
const visible = hor.apparentAltitude > 0 ? 'VISIBLE' : 'below horizon';
|
|
242
|
+
console.log(
|
|
243
|
+
` ${b.name.padEnd(8)} alt: ${hor.apparentAltitude.toFixed(1).padStart(6)} deg` +
|
|
244
|
+
` compass: ${compass.toFixed(0).padStart(3)} deg` +
|
|
245
|
+
` ${visible}`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
swe.close();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Sky map: plotting planet positions in horizontal coordinates
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
import { SwissEph } from '../index';
|
|
256
|
+
import {
|
|
257
|
+
SE_MOON, SE_MERCURY, SE_VENUS, SE_MARS, SE_JUPITER, SE_SATURN,
|
|
258
|
+
} from '../../constants';
|
|
259
|
+
|
|
260
|
+
const swe = new SwissEph();
|
|
261
|
+
|
|
262
|
+
const jd = SwissEph.julianDay(2024, 8, 15, 22); // 10 PM UT
|
|
263
|
+
const geo = { longitude: 13.405, latitude: 52.520 }; // Berlin
|
|
264
|
+
|
|
265
|
+
const planets = [
|
|
266
|
+
{ id: SE_MOON, name: 'Moon', symbol: 'D' },
|
|
267
|
+
{ id: SE_MERCURY, name: 'Mercury', symbol: 'Me' },
|
|
268
|
+
{ id: SE_VENUS, name: 'Venus', symbol: 'Ve' },
|
|
269
|
+
{ id: SE_MARS, name: 'Mars', symbol: 'Ma' },
|
|
270
|
+
{ id: SE_JUPITER, name: 'Jupiter', symbol: 'Ju' },
|
|
271
|
+
{ id: SE_SATURN, name: 'Saturn', symbol: 'Sa' },
|
|
272
|
+
];
|
|
273
|
+
|
|
274
|
+
console.log('Sky positions from Berlin at 22:00 UT, Aug 15, 2024:');
|
|
275
|
+
console.log('Planet Compass Altitude');
|
|
276
|
+
|
|
277
|
+
for (const p of planets) {
|
|
278
|
+
const pos = swe.calc(jd, p.id);
|
|
279
|
+
const hor = swe.azalt(jd, geo, pos.longitude, pos.latitude, pos.distance);
|
|
280
|
+
|
|
281
|
+
if (hor.apparentAltitude > 0) {
|
|
282
|
+
const compass = (hor.azimuth + 180) % 360;
|
|
283
|
+
console.log(
|
|
284
|
+
` ${p.name.padEnd(9)} ${compass.toFixed(1).padStart(6)} deg ` +
|
|
285
|
+
`${hor.apparentAltitude.toFixed(1).padStart(5)} deg`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
swe.close();
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Deep Explanation
|
|
296
|
+
|
|
297
|
+
### The azimuth convention in detail
|
|
298
|
+
|
|
299
|
+
**This is one of the most common sources of confusion when using the Swiss Ephemeris.**
|
|
300
|
+
|
|
301
|
+
The Swiss Ephemeris follows the astronomical convention where azimuth is measured from **South** and increases clockwise (through West):
|
|
302
|
+
|
|
303
|
+
| SE Azimuth | Direction |
|
|
304
|
+
|------------|-----------|
|
|
305
|
+
| 0 degrees | South |
|
|
306
|
+
| 90 degrees | West |
|
|
307
|
+
| 180 degrees | North |
|
|
308
|
+
| 270 degrees | East |
|
|
309
|
+
|
|
310
|
+
The common **navigation/compass convention** (used in GPS, maps, and daily life) measures from **North** and increases clockwise (through East):
|
|
311
|
+
|
|
312
|
+
| Compass Azimuth | Direction |
|
|
313
|
+
|-----------------|-----------|
|
|
314
|
+
| 0 degrees | North |
|
|
315
|
+
| 90 degrees | East |
|
|
316
|
+
| 180 degrees | South |
|
|
317
|
+
| 270 degrees | West |
|
|
318
|
+
|
|
319
|
+
To convert between them:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
// Swiss Ephemeris to compass
|
|
323
|
+
const compassAzimuth = (sweAzimuth + 180) % 360;
|
|
324
|
+
|
|
325
|
+
// Compass to Swiss Ephemeris
|
|
326
|
+
const sweAzimuth = (compassAzimuth + 180) % 360;
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
The formula is the same in both directions because 180 degrees is exactly half a circle.
|
|
330
|
+
|
|
331
|
+
The astronomical convention originated because in the Northern Hemisphere, celestial objects transit (cross the meridian) in the South, so it was natural for astronomers to make South the reference direction. Many classical astronomical instruments (transit telescopes, meridian circles) point South by default.
|
|
332
|
+
|
|
333
|
+
### Altitude explained
|
|
334
|
+
|
|
335
|
+
| Altitude | Meaning |
|
|
336
|
+
|----------|---------|
|
|
337
|
+
| +90 degrees | Zenith (directly overhead) |
|
|
338
|
+
| +45 degrees | Halfway between horizon and zenith |
|
|
339
|
+
| 0 degrees | On the geometric horizon |
|
|
340
|
+
| -0.57 degrees | Approximate apparent altitude of a rising/setting star (refraction lifts it from ~-0.57 to 0) |
|
|
341
|
+
| -0.83 degrees | Approximate true altitude of the Sun's center at sunrise/sunset |
|
|
342
|
+
| -6 degrees | End of civil twilight |
|
|
343
|
+
| -12 degrees | End of nautical twilight |
|
|
344
|
+
| -18 degrees | End of astronomical twilight |
|
|
345
|
+
| -90 degrees | Nadir (directly below) |
|
|
346
|
+
|
|
347
|
+
### Atmospheric refraction
|
|
348
|
+
|
|
349
|
+
Atmospheric refraction causes celestial objects to appear higher in the sky than they geometrically are. The effect is strongest at the horizon and negligible at the zenith:
|
|
350
|
+
|
|
351
|
+
| True altitude | Refraction amount |
|
|
352
|
+
|--------------|-------------------|
|
|
353
|
+
| 0 degrees (horizon) | ~34 arc-minutes (~0.57 degrees) |
|
|
354
|
+
| 5 degrees | ~10 arc-minutes |
|
|
355
|
+
| 10 degrees | ~5 arc-minutes |
|
|
356
|
+
| 20 degrees | ~2.5 arc-minutes |
|
|
357
|
+
| 45 degrees | ~1 arc-minute |
|
|
358
|
+
| 90 degrees (zenith) | 0 |
|
|
359
|
+
|
|
360
|
+
The `azalt` function returns both `trueAltitude` (geometric, no refraction) and `apparentAltitude` (with refraction). The difference between them is the refraction correction.
|
|
361
|
+
|
|
362
|
+
Refraction depends on atmospheric conditions:
|
|
363
|
+
- **Higher pressure** = more refraction (denser air bends light more)
|
|
364
|
+
- **Lower temperature** = more refraction (colder air is denser)
|
|
365
|
+
- Default values: 1013.25 mbar, 15 degrees C
|
|
366
|
+
|
|
367
|
+
Setting pressure to 0 effectively disables the refraction calculation (apparent altitude = true altitude).
|
|
368
|
+
|
|
369
|
+
### SE_ECL2HOR vs SE_EQU2HOR
|
|
370
|
+
|
|
371
|
+
The `calcFlag` parameter determines what kind of input coordinates you are providing:
|
|
372
|
+
|
|
373
|
+
| Flag | Value | Input meaning |
|
|
374
|
+
|------|-------|--------------|
|
|
375
|
+
| `SE_ECL2HOR` | 0 | `lon` = ecliptic longitude, `lat` = ecliptic latitude. The function internally converts to equatorial then to horizontal. |
|
|
376
|
+
| `SE_EQU2HOR` | 1 | `lon` = Right Ascension (in degrees, not hours), `lat` = Declination. The function converts directly to horizontal. |
|
|
377
|
+
|
|
378
|
+
Both produce the same output (azimuth, true altitude, apparent altitude). Use whichever matches the coordinates you already have. If you have computed a planet position with `swe.calc()` (which returns ecliptic coordinates by default), use `SE_ECL2HOR`. If you used `SEFLG_EQUATORIAL` in the calc, use `SE_EQU2HOR`.
|
|
379
|
+
|
|
380
|
+
### The `azaltReverse` function
|
|
381
|
+
|
|
382
|
+
This reverses the conversion: given an azimuth and apparent altitude (what you see in the sky), it returns the ecliptic (or equatorial) coordinates that correspond to that direction.
|
|
383
|
+
|
|
384
|
+
The return value uses the same `AzaltRevResult` type with fields named `azimuth` and `altitude`, but these actually contain the ecliptic longitude/latitude (or RA/Dec) depending on the `calcFlag`:
|
|
385
|
+
|
|
386
|
+
| calcFlag | `azimuth` field | `altitude` field |
|
|
387
|
+
|----------|----------------|-----------------|
|
|
388
|
+
| `SE_ECL2HOR` (0) | Ecliptic longitude | Ecliptic latitude |
|
|
389
|
+
| `SE_EQU2HOR` (1) | Right Ascension (degrees) | Declination |
|
|
390
|
+
|
|
391
|
+
### The `dist` parameter
|
|
392
|
+
|
|
393
|
+
The `dist` parameter in `azalt()` is the distance of the object in AU. For most purposes, this has negligible effect and can be left at the default (1). It matters only for very close objects (like the Moon, which shows measurable parallax) -- but if you are getting the position from `swe.calc()`, you already have the correct distance in the result.
|
|
394
|
+
|
|
395
|
+
### Practical uses
|
|
396
|
+
|
|
397
|
+
- **Telescope pointing**: Convert a planet's ephemeris position to azimuth/altitude for alt-azimuth telescope mounts. Remember to convert the SE azimuth to compass azimuth if your mount uses the navigation convention.
|
|
398
|
+
- **Visibility checking**: If a planet's apparent altitude is negative, it is below the horizon and not observable.
|
|
399
|
+
- **Shadow calculation**: The Sun's altitude determines shadow length. At altitude *h*, a vertical stick of height *H* casts a shadow of length *H / tan(h)*.
|
|
400
|
+
- **Solar energy**: The Sun's altitude and azimuth determine the angle of incidence on solar panels, which affects energy generation.
|
|
401
|
+
- **Photography**: The Sun's position determines lighting direction and quality. Low altitude produces warm, long-shadow light (golden hour); high altitude produces harsh, overhead light.
|
|
402
|
+
|
|
403
|
+
### Tips
|
|
404
|
+
|
|
405
|
+
- Always remember the azimuth convention (0 = South in Swiss Ephemeris). Converting to compass bearing is simple: `(azimuth + 180) % 360`.
|
|
406
|
+
- The `apparentAltitude` is what you actually see; `trueAltitude` is the geometric reality. For observational purposes (is this object visible?), use `apparentAltitude`.
|
|
407
|
+
- At very low altitudes (near the horizon), refraction can be anomalous due to temperature inversions, mirages, and other atmospheric effects. The standard refraction formula is an average approximation.
|
|
408
|
+
- Setting `pressure` to 0 disables refraction, which is equivalent to what `SE_BIT_NO_REFRACTION` does for rise/set calculations.
|