@openwaters/almanac 0.6.0 → 0.8.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 +83 -7
- package/dist/eclipse.d.ts +1 -1
- package/dist/eclipse.js +6 -5
- package/dist/events.d.ts +44 -4
- package/dist/events.js +84 -16
- package/dist/horizon.d.ts +3 -0
- package/dist/horizon.js +24 -0
- package/dist/illumination.d.ts +22 -0
- package/dist/illumination.js +33 -3
- package/dist/index.d.ts +8 -5
- package/dist/index.js +4 -2
- package/dist/planetModels.d.ts +5 -0
- package/dist/planetModels.js +1261 -0
- package/dist/planets.d.ts +32 -0
- package/dist/planets.js +111 -0
- package/dist/solar.d.ts +3 -3
- package/dist/solar.js +17 -16
- package/dist/sun.d.ts +4 -0
- package/dist/sun.js +2 -2
- package/dist/transforms.d.ts +7 -3
- package/dist/transforms.js +2 -2
- package/dist/types.d.ts +3 -0
- package/dist/types.js +5 -0
- package/package.json +4 -3
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { type Planet, type Observer } from './types.js';
|
|
2
|
+
import { type AltAz } from './transforms.js';
|
|
3
|
+
/** Geometric Sun-centered AU vector in the fixed J2000 mean equatorial frame. */
|
|
4
|
+
export interface HeliocentricPosition {
|
|
5
|
+
xAu: number;
|
|
6
|
+
yAu: number;
|
|
7
|
+
zAu: number;
|
|
8
|
+
}
|
|
9
|
+
/** Apparent geocentric position on the true equator and equinox of date. */
|
|
10
|
+
export interface PlanetPosition {
|
|
11
|
+
raDeg: number;
|
|
12
|
+
decDeg: number;
|
|
13
|
+
distanceAu: number;
|
|
14
|
+
}
|
|
15
|
+
/** Geometric phase and approximate airless visual magnitude, plus apparent solar separation. */
|
|
16
|
+
export interface PlanetIllumination {
|
|
17
|
+
fraction: number;
|
|
18
|
+
phaseAngleDeg: number;
|
|
19
|
+
magnitude: number;
|
|
20
|
+
elongationDeg: number;
|
|
21
|
+
}
|
|
22
|
+
export declare function planetIlluminationAtTT(planet: Planet, tt: number): PlanetIllumination;
|
|
23
|
+
/** Approximate airless magnitude includes Saturn's rings; elongation is apparent separation from the Sun. */
|
|
24
|
+
export declare function planetIllumination(planet: Planet, time: Date): PlanetIllumination;
|
|
25
|
+
/** INTERNAL: TT-labeled evidence bypasses the civil-time Delta-T conversion. */
|
|
26
|
+
export declare function planetApparentAtTT(planet: Planet, tt: number): PlanetPosition;
|
|
27
|
+
/** Geometric position at the requested instant; accepts Earth. */
|
|
28
|
+
export declare function planetHeliocentricPosition(planet: Planet, time: Date): HeliocentricPosition;
|
|
29
|
+
/** Apparent geocentric position with light-time, aberration, precession, and nutation. */
|
|
30
|
+
export declare function planetPosition(planet: Planet, time: Date): PlanetPosition;
|
|
31
|
+
/** Refracted topocentric position; altitude remains relative to the horizontal plane. */
|
|
32
|
+
export declare function planetAltAz(planet: Planet, time: Date, observer: Observer): AltAz;
|
package/dist/planets.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { assertPlanet, assertSupported, assertObserver } from './types.js';
|
|
2
|
+
import { ttDays, ttDaysFromUt, utDays } from './time.js';
|
|
3
|
+
import { gyration, PrecessDirection, equatorialFromVector, DEG2RAD, RAD2DEG, earthTilt, eclipticToEquatorial } from './nutation.js';
|
|
4
|
+
import { planetHelioVector, planetGeoVectorEqj } from './planetModels.js';
|
|
5
|
+
import { topoAltAzUnrefracted, refract } from './transforms.js';
|
|
6
|
+
import { angleBetweenDeg } from './illumination.js';
|
|
7
|
+
import { earthHelioVector, sunGeoVectorEqj } from './sun.js';
|
|
8
|
+
// VisualMagnitude: https://github.com/cosinekitty/astronomy/blob/865d3da7d8112bbc7911238052c6af4aaf877181/source/js/astronomy.ts#L4901.
|
|
9
|
+
function visualMagnitude(planet, phase, helioDist, geoDist) {
|
|
10
|
+
let c0, c1 = 0, c2 = 0, c3 = 0;
|
|
11
|
+
switch (planet) {
|
|
12
|
+
case 'mercury':
|
|
13
|
+
c0 = -0.60;
|
|
14
|
+
c1 = 4.98;
|
|
15
|
+
c2 = -4.88;
|
|
16
|
+
c3 = 3.02;
|
|
17
|
+
break;
|
|
18
|
+
case 'venus':
|
|
19
|
+
if (phase < 163.6) {
|
|
20
|
+
c0 = -4.47;
|
|
21
|
+
c1 = 1.03;
|
|
22
|
+
c2 = 0.57;
|
|
23
|
+
c3 = 0.13;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
c0 = 0.98;
|
|
27
|
+
c1 = -1.02;
|
|
28
|
+
}
|
|
29
|
+
break;
|
|
30
|
+
case 'mars':
|
|
31
|
+
c0 = -1.52;
|
|
32
|
+
c1 = 1.60;
|
|
33
|
+
break;
|
|
34
|
+
case 'jupiter':
|
|
35
|
+
c0 = -9.40;
|
|
36
|
+
c1 = 0.50;
|
|
37
|
+
break;
|
|
38
|
+
case 'uranus':
|
|
39
|
+
c0 = -7.19;
|
|
40
|
+
c1 = 0.25;
|
|
41
|
+
break;
|
|
42
|
+
case 'neptune':
|
|
43
|
+
c0 = -6.87;
|
|
44
|
+
break;
|
|
45
|
+
default: throw new Error('unsupported planet in visualMagnitude');
|
|
46
|
+
}
|
|
47
|
+
const x = phase / 100;
|
|
48
|
+
let mag = c0 + x * (c1 + x * (c2 + x * c3));
|
|
49
|
+
mag += 5 * Math.log10(helioDist * geoDist);
|
|
50
|
+
return mag;
|
|
51
|
+
}
|
|
52
|
+
// SaturnMagnitude: pinned astronomy.ts#L4927; Ecliptic: #L3013.
|
|
53
|
+
function saturnMagnitude(phase, helioDist, geoDist, gc, tt) {
|
|
54
|
+
const ecl = eclipticToEquatorial(-earthTilt(tt).tobl, gyration(gc, tt, PrecessDirection.From2000));
|
|
55
|
+
const lat = RAD2DEG * Math.atan2(ecl.z, Math.hypot(ecl.x, ecl.y));
|
|
56
|
+
let lon = RAD2DEG * Math.atan2(ecl.y, ecl.x);
|
|
57
|
+
if (lon < 0)
|
|
58
|
+
lon += 360;
|
|
59
|
+
const ir = DEG2RAD * 28.06, nr = DEG2RAD * (169.51 + (3.82e-5 * tt));
|
|
60
|
+
const tilt = Math.asin(Math.sin(DEG2RAD * lat) * Math.cos(ir) - Math.cos(DEG2RAD * lat) * Math.sin(ir) * Math.sin(DEG2RAD * lon - nr));
|
|
61
|
+
const sinTilt = Math.sin(Math.abs(tilt));
|
|
62
|
+
let mag = -9 + 0.044 * phase;
|
|
63
|
+
mag += sinTilt * (-2.6 + 1.2 * sinTilt);
|
|
64
|
+
mag += 5 * Math.log10(helioDist * geoDist);
|
|
65
|
+
return mag;
|
|
66
|
+
}
|
|
67
|
+
// Illumination: pinned astronomy.ts#L5066; AngleFromSun: #L4869.
|
|
68
|
+
export function planetIlluminationAtTT(planet, tt) {
|
|
69
|
+
const earth = earthHelioVector(tt), hc = planetHelioVector(planet, tt);
|
|
70
|
+
const gc = { x: hc.x - earth.x, y: hc.y - earth.y, z: hc.z - earth.z };
|
|
71
|
+
const phaseAngleDeg = angleBetweenDeg(gc, hc);
|
|
72
|
+
const helioDist = Math.sqrt(hc.x * hc.x + hc.y * hc.y + hc.z * hc.z);
|
|
73
|
+
const geoDist = Math.sqrt(gc.x * gc.x + gc.y * gc.y + gc.z * gc.z);
|
|
74
|
+
const magnitude = planet === 'saturn' ? saturnMagnitude(phaseAngleDeg, helioDist, geoDist, gc, tt) : visualMagnitude(planet, phaseAngleDeg, helioDist, geoDist);
|
|
75
|
+
return { fraction: (1 + Math.cos(DEG2RAD * phaseAngleDeg)) / 2, phaseAngleDeg, magnitude,
|
|
76
|
+
elongationDeg: angleBetweenDeg(sunGeoVectorEqj(tt), planetGeoVectorEqj(planet, tt)) };
|
|
77
|
+
}
|
|
78
|
+
/** Approximate airless magnitude includes Saturn's rings; elongation is apparent separation from the Sun. */
|
|
79
|
+
export function planetIllumination(planet, time) {
|
|
80
|
+
assertPlanet(planet);
|
|
81
|
+
assertSupported(time);
|
|
82
|
+
return planetIlluminationAtTT(planet, ttDays(time));
|
|
83
|
+
}
|
|
84
|
+
/** INTERNAL: TT-labeled evidence bypasses the civil-time Delta-T conversion. */
|
|
85
|
+
export function planetApparentAtTT(planet, tt) {
|
|
86
|
+
const direction = equatorialFromVector(gyration(planetGeoVectorEqj(planet, tt), tt, PrecessDirection.From2000));
|
|
87
|
+
// Aberration changes direction, not physical range; keep Earth at reception for distance.
|
|
88
|
+
const range = planetGeoVectorEqj(planet, tt, false);
|
|
89
|
+
return { raDeg: direction.raDeg, decDeg: direction.decDeg, distanceAu: Math.hypot(range.x, range.y, range.z) };
|
|
90
|
+
}
|
|
91
|
+
/** Geometric position at the requested instant; accepts Earth. */
|
|
92
|
+
export function planetHeliocentricPosition(planet, time) {
|
|
93
|
+
assertPlanet(planet, true);
|
|
94
|
+
assertSupported(time);
|
|
95
|
+
const p = planetHelioVector(planet, ttDays(time));
|
|
96
|
+
return { xAu: p.x, yAu: p.y, zAu: p.z };
|
|
97
|
+
}
|
|
98
|
+
/** Apparent geocentric position with light-time, aberration, precession, and nutation. */
|
|
99
|
+
export function planetPosition(planet, time) {
|
|
100
|
+
assertPlanet(planet);
|
|
101
|
+
assertSupported(time);
|
|
102
|
+
return planetApparentAtTT(planet, ttDays(time));
|
|
103
|
+
}
|
|
104
|
+
/** Refracted topocentric position; altitude remains relative to the horizontal plane. */
|
|
105
|
+
export function planetAltAz(planet, time, observer) {
|
|
106
|
+
assertPlanet(planet);
|
|
107
|
+
assertSupported(time);
|
|
108
|
+
assertObserver(observer);
|
|
109
|
+
const ut = utDays(time);
|
|
110
|
+
return refract(topoAltAzUnrefracted(planetGeoVectorEqj(planet, ttDaysFromUt(ut)), ut, observer));
|
|
111
|
+
}
|
package/dist/solar.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export declare function eclipseKindFromUmbra(k: number): 'total' | 'annular';
|
|
|
67
67
|
* interval, or if no visible eclipse remains before the end of it.
|
|
68
68
|
* @throws {RangeError} if `after` is invalid or `observer` is out of range.
|
|
69
69
|
*/
|
|
70
|
-
export declare function nextSolarEclipse(after: Date, observer: Observer): SolarEclipse;
|
|
70
|
+
export declare function nextSolarEclipse(after: Date, observer: Observer, heightAboveGroundM?: number): SolarEclipse;
|
|
71
71
|
/**
|
|
72
72
|
* The last solar eclipse `observer` can see whose peak falls strictly before
|
|
73
73
|
* `before`, skipping peaks within 100 ms of it, just as `nextSolarEclipse`
|
|
@@ -77,6 +77,6 @@ export declare function nextSolarEclipse(after: Date, observer: Observer): Solar
|
|
|
77
77
|
* interval, or if no visible eclipse remains after the start of it.
|
|
78
78
|
* @throws {RangeError} if `before` is invalid or `observer` is out of range.
|
|
79
79
|
*/
|
|
80
|
-
export declare function previousSolarEclipse(before: Date, observer: Observer): SolarEclipse;
|
|
80
|
+
export declare function previousSolarEclipse(before: Date, observer: Observer, heightAboveGroundM?: number): SolarEclipse;
|
|
81
81
|
/** Solar eclipses `observer` can see with peaks in `[startUtc, endUtc)`, sorted ascending. Contacts may fall outside the window. */
|
|
82
|
-
export declare function solarEclipses(startUtc: Date, endUtc: Date, observer: Observer): SolarEclipse[];
|
|
82
|
+
export declare function solarEclipses(startUtc: Date, endUtc: Date, observer: Observer, heightAboveGroundM?: number): SolarEclipse[];
|
package/dist/solar.js
CHANGED
|
@@ -34,6 +34,7 @@ import { moonGeoVectorEqj } from './moon.js';
|
|
|
34
34
|
import { sunGeoVectorEqj } from './sun.js';
|
|
35
35
|
import { observerGeoVectorEqj, refractionDeg, topoAltAzUnrefracted } from './transforms.js';
|
|
36
36
|
import { MOON_MEAN_RADIUS_KM, SUN_RADIUS_KM, search, searchMoonPhase } from './events.js';
|
|
37
|
+
import { horizonDip } from './horizon.js';
|
|
37
38
|
import { calcShadow, moonEclipticLatitudeDeg, PRUNE_LATITUDE_DEG, SAME_ECLIPSE_MS, SHADOW_TOL_SECONDS, SHADOW_ITER_CAP } from './eclipse.js';
|
|
38
39
|
/** UPSTREAM: `SUN_RADIUS_AU` and `MOON_POLAR_RADIUS_AU`, astronomy.ts 135 and 149-150.
|
|
39
40
|
* INTERNAL: `MOON_POLAR_RADIUS_KM` is shared with globalSolar.ts. */
|
|
@@ -66,7 +67,7 @@ function localMoonShadow(ut, observer) {
|
|
|
66
67
|
return calcShadow(MOON_MEAN_RADIUS_KM, ut, o, hm);
|
|
67
68
|
}
|
|
68
69
|
/** UPSTREAM: `AngleBetween`, astronomy.ts ~256 — degrees. */
|
|
69
|
-
function
|
|
70
|
+
function solarAngleBetweenDeg(a, b) {
|
|
70
71
|
const aa = (a.x * a.x + a.y * a.y + a.z * a.z);
|
|
71
72
|
if (Math.abs(aa) < 1.0e-8)
|
|
72
73
|
throw new Error('almanac internal: AngleBetween first vector is too short');
|
|
@@ -131,7 +132,7 @@ function discObscuration(hm, lo) {
|
|
|
131
132
|
// Calculate the apparent angular radius of the Moon for the observer.
|
|
132
133
|
const moonRadius = Math.asin(MOON_POLAR_RADIUS_AU / Math.hypot(lo.x, lo.y, lo.z));
|
|
133
134
|
// Calculate the apparent angular separation between the Sun's center and the Moon's center.
|
|
134
|
-
const sunMoonSeparation =
|
|
135
|
+
const sunMoonSeparation = solarAngleBetweenDeg(lo, ho);
|
|
135
136
|
// Find the fraction of the Sun's apparent disc area that is covered by the Moon.
|
|
136
137
|
return discOverlap(sunRadius, moonRadius, sunMoonSeparation * DEG2RAD);
|
|
137
138
|
}
|
|
@@ -254,8 +255,8 @@ function buildSolarEclipse(shadow, observer) {
|
|
|
254
255
|
* ponytail: three samples, not a sunrise search — a day that starts after C1
|
|
255
256
|
* and ends before the peak still drops. Upgrade path: sunEvents over [c1, c4].
|
|
256
257
|
*/
|
|
257
|
-
function seesAnyOfIt(e) {
|
|
258
|
-
return e.sunAltDeg.c1 >
|
|
258
|
+
function seesAnyOfIt(e, dip) {
|
|
259
|
+
return e.sunAltDeg.c1 > dip || e.sunAltDeg.peak > dip || e.sunAltDeg.c4 > dip;
|
|
259
260
|
}
|
|
260
261
|
/**
|
|
261
262
|
* The first solar eclipse `observer` can see whose peak falls strictly after
|
|
@@ -270,8 +271,8 @@ function seesAnyOfIt(e) {
|
|
|
270
271
|
* interval, or if no visible eclipse remains before the end of it.
|
|
271
272
|
* @throws {RangeError} if `after` is invalid or `observer` is out of range.
|
|
272
273
|
*/
|
|
273
|
-
export function nextSolarEclipse(after, observer) {
|
|
274
|
-
return nearestSolarEclipse(after, 1, observer);
|
|
274
|
+
export function nextSolarEclipse(after, observer, heightAboveGroundM = 0) {
|
|
275
|
+
return nearestSolarEclipse(after, 1, observer, heightAboveGroundM);
|
|
275
276
|
}
|
|
276
277
|
/**
|
|
277
278
|
* The last solar eclipse `observer` can see whose peak falls strictly before
|
|
@@ -282,30 +283,30 @@ export function nextSolarEclipse(after, observer) {
|
|
|
282
283
|
* interval, or if no visible eclipse remains after the start of it.
|
|
283
284
|
* @throws {RangeError} if `before` is invalid or `observer` is out of range.
|
|
284
285
|
*/
|
|
285
|
-
export function previousSolarEclipse(before, observer) {
|
|
286
|
-
return nearestSolarEclipse(before, -1, observer);
|
|
286
|
+
export function previousSolarEclipse(before, observer, heightAboveGroundM = 0) {
|
|
287
|
+
return nearestSolarEclipse(before, -1, observer, heightAboveGroundM);
|
|
287
288
|
}
|
|
288
289
|
/** Solar eclipses `observer` can see with peaks in `[startUtc, endUtc)`, sorted ascending. Contacts may fall outside the window. */
|
|
289
|
-
export function solarEclipses(startUtc, endUtc, observer) {
|
|
290
|
+
export function solarEclipses(startUtc, endUtc, observer, heightAboveGroundM = 0) {
|
|
290
291
|
assertSupported(startUtc);
|
|
291
292
|
assertSupportedWindowEnd(endUtc);
|
|
292
|
-
|
|
293
|
-
return scanSolarEclipses(startUtc.getTime(), endUtc.getTime(), 1, false, observer);
|
|
293
|
+
const dip = horizonDip(observer, heightAboveGroundM);
|
|
294
|
+
return scanSolarEclipses(startUtc.getTime(), endUtc.getTime(), 1, false, observer, dip);
|
|
294
295
|
}
|
|
295
|
-
function nearestSolarEclipse(anchor, direction, observer) {
|
|
296
|
+
function nearestSolarEclipse(anchor, direction, observer, heightAboveGroundM) {
|
|
296
297
|
assertSupported(anchor);
|
|
297
|
-
|
|
298
|
+
const dip = horizonDip(observer, heightAboveGroundM);
|
|
298
299
|
const ms = anchor.getTime();
|
|
299
300
|
// No scan limit: walk to the supported boundary. A place can go years
|
|
300
301
|
// without a visible solar eclipse, and a pruned new moon is cheap.
|
|
301
302
|
const startMs = direction > 0 ? ms + SAME_ECLIPSE_MS + 1 : SUPPORTED_MIN;
|
|
302
303
|
const endMs = direction > 0 ? SUPPORTED_MAX : ms - SAME_ECLIPSE_MS;
|
|
303
|
-
const found = scanSolarEclipses(startMs, endMs, direction, true, observer);
|
|
304
|
+
const found = scanSolarEclipses(startMs, endMs, direction, true, observer, dip);
|
|
304
305
|
if (found.length)
|
|
305
306
|
return found[0];
|
|
306
307
|
throw new AlmanacOutOfRangeError();
|
|
307
308
|
}
|
|
308
|
-
function scanSolarEclipses(startMs, endMs, direction, firstOnly, observer) {
|
|
309
|
+
function scanSolarEclipses(startMs, endMs, direction, firstOnly, observer, dip) {
|
|
309
310
|
const found = [];
|
|
310
311
|
if (startMs >= endMs)
|
|
311
312
|
return found;
|
|
@@ -337,7 +338,7 @@ function scanSolarEclipses(startMs, endMs, direction, firstOnly, observer) {
|
|
|
337
338
|
// This is at least a partial solar eclipse for the observer.
|
|
338
339
|
const eclipse = buildSolarEclipse(shadow, observer);
|
|
339
340
|
// Ignore any eclipse that happens completely at night.
|
|
340
|
-
if (!seesAnyOfIt(eclipse))
|
|
341
|
+
if (!seesAnyOfIt(eclipse, dip))
|
|
341
342
|
continue;
|
|
342
343
|
found.push(eclipse);
|
|
343
344
|
if (firstOnly)
|
package/dist/sun.d.ts
CHANGED
|
@@ -7,6 +7,10 @@ type VsopModel = [VsopFormula, VsopFormula, VsopFormula];
|
|
|
7
7
|
* below are checked against; exported for that test only.
|
|
8
8
|
*/
|
|
9
9
|
export declare const vsopEarth: VsopModel;
|
|
10
|
+
/** UPSTREAM: `VsopRotate`, astronomy.ts lines 3234-3241 — VSOP ecliptic to J2000 equatorial. */
|
|
11
|
+
export declare function vsopRotate(eclip: Vec3): Vec3;
|
|
12
|
+
/** UPSTREAM: `VsopSphereToRect`, astronomy.ts lines 3243-3253. */
|
|
13
|
+
export declare function vsopSphereToRect(lon: number, lat: number, radius: number): Vec3;
|
|
10
14
|
/**
|
|
11
15
|
* UPSTREAM: `CalcVsop`, astronomy.ts lines 3255-3262, specialised to
|
|
12
16
|
* `vsop.Earth` — i.e. `HelioVector(Body.Earth, time)`. J2000 mean equator (EQJ).
|
package/dist/sun.js
CHANGED
|
@@ -204,7 +204,7 @@ function earthRad(t) {
|
|
|
204
204
|
return coord;
|
|
205
205
|
}
|
|
206
206
|
/** UPSTREAM: `VsopRotate`, astronomy.ts lines 3234-3241 — VSOP ecliptic to J2000 equatorial. */
|
|
207
|
-
function vsopRotate(eclip) {
|
|
207
|
+
export function vsopRotate(eclip) {
|
|
208
208
|
return {
|
|
209
209
|
x: eclip.x + 0.000000440360 * eclip.y - 0.000000190919 * eclip.z,
|
|
210
210
|
y: -0.000000479966 * eclip.x + 0.917482137087 * eclip.y - 0.397776982902 * eclip.z,
|
|
@@ -212,7 +212,7 @@ function vsopRotate(eclip) {
|
|
|
212
212
|
};
|
|
213
213
|
}
|
|
214
214
|
/** UPSTREAM: `VsopSphereToRect`, astronomy.ts lines 3243-3253. */
|
|
215
|
-
function vsopSphereToRect(lon, lat, radius) {
|
|
215
|
+
export function vsopSphereToRect(lon, lat, radius) {
|
|
216
216
|
// Convert spherical coordinates to ecliptic cartesian coordinates.
|
|
217
217
|
const r_coslat = radius * Math.cos(lat);
|
|
218
218
|
const coslon = Math.cos(lon);
|
package/dist/transforms.d.ts
CHANGED
|
@@ -7,13 +7,16 @@ export interface AltAz {
|
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* INTERNAL: what {@link topoAltAzUnrefracted} already computes on the way to
|
|
10
|
-
* az/alt. The L3 event layer needs
|
|
11
|
-
* local hour angle brackets each daily cycle's altitude extrema,
|
|
12
|
-
* topocentric distance sets the Moon's semidiameter, hence its rise/set target
|
|
10
|
+
* az/alt. The L3 event layer needs these from a single evaluation — the
|
|
11
|
+
* local hour angle brackets each daily cycle's altitude extrema, the
|
|
12
|
+
* topocentric distance sets the Moon's semidiameter, hence its rise/set target,
|
|
13
|
+
* and the topocentric RA/Dec orient the Moon's disc.
|
|
13
14
|
*/
|
|
14
15
|
export interface TopoUnrefracted extends AltAz {
|
|
15
16
|
hourAngleDeg: number;
|
|
16
17
|
distanceAu: number;
|
|
18
|
+
raDeg: number;
|
|
19
|
+
decDeg: number;
|
|
17
20
|
}
|
|
18
21
|
/**
|
|
19
22
|
* UPSTREAM: `sidereal_time`, astronomy.ts ~2031 — Greenwich Apparent Sidereal
|
|
@@ -56,6 +59,7 @@ export declare function topoAltAzUnrefracted(bodyEqj: Vec3, ut: number, observer
|
|
|
56
59
|
* altitude never drops below -90.
|
|
57
60
|
*/
|
|
58
61
|
export declare function refractionDeg(altitudeDeg: number): number;
|
|
62
|
+
export declare function refract(unrefracted: AltAz): AltAz;
|
|
59
63
|
/**
|
|
60
64
|
* Topocentric azimuth/altitude of the Sun — parallax (via the observer's
|
|
61
65
|
* geocentric position, WGS-84 flattening, elevation) and atmospheric
|
package/dist/transforms.js
CHANGED
|
@@ -160,7 +160,7 @@ export function topoAltAzUnrefracted(bodyEqj, ut, observer) {
|
|
|
160
160
|
let hourAngleDeg = (gast + observer.longitudeDeg - raDeg) % 360;
|
|
161
161
|
if (hourAngleDeg < 0)
|
|
162
162
|
hourAngleDeg += 360;
|
|
163
|
-
return { azDeg: az, altDeg: 90 - zd, hourAngleDeg, distanceAu };
|
|
163
|
+
return { azDeg: az, altDeg: 90 - zd, hourAngleDeg, distanceAu, raDeg, decDeg };
|
|
164
164
|
}
|
|
165
165
|
/**
|
|
166
166
|
* UPSTREAM: `Refraction('normal', altitude)`, astronomy.ts ~7176 — the
|
|
@@ -182,7 +182,7 @@ export function refractionDeg(altitudeDeg) {
|
|
|
182
182
|
}
|
|
183
183
|
return refr;
|
|
184
184
|
}
|
|
185
|
-
function refract(unrefracted) {
|
|
185
|
+
export function refract(unrefracted) {
|
|
186
186
|
return { azDeg: unrefracted.azDeg, altDeg: unrefracted.altDeg + refractionDeg(unrefracted.altDeg) };
|
|
187
187
|
}
|
|
188
188
|
/**
|
package/dist/types.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ export interface Observer {
|
|
|
3
3
|
longitudeDeg: number;
|
|
4
4
|
elevationM?: number;
|
|
5
5
|
}
|
|
6
|
+
export type Planet = 'mercury' | 'venus' | 'earth' | 'mars' | 'jupiter' | 'saturn' | 'uranus' | 'neptune';
|
|
7
|
+
/** INTERNAL: Earth has no planetary direction from an Earth-based observer. */
|
|
8
|
+
export declare function assertPlanet(planet: Planet, earthAllowed?: boolean): void;
|
|
6
9
|
export declare class AlmanacOutOfRangeError extends RangeError {
|
|
7
10
|
constructor(msg?: string);
|
|
8
11
|
}
|
package/dist/types.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/** INTERNAL: Earth has no planetary direction from an Earth-based observer. */
|
|
2
|
+
export function assertPlanet(planet, earthAllowed = false) {
|
|
3
|
+
if (!['mercury', 'venus', 'earth', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune'].includes(planet) || (!earthAllowed && planet === 'earth'))
|
|
4
|
+
throw new RangeError(`invalid planet: ${planet}`);
|
|
5
|
+
}
|
|
1
6
|
export class AlmanacOutOfRangeError extends RangeError {
|
|
2
7
|
constructor(msg = 'time outside supported interval 1950-01-01T00:00Z ≤ t < 2101-01-01T00:00Z') { super(msg); this.name = 'AlmanacOutOfRangeError'; }
|
|
3
8
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwaters/almanac",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Offline
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"description": "Offline astronomy: Sun, Moon and planet positions, apparent horizon, rise/set, phases and eclipses.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -18,7 +18,8 @@
|
|
|
18
18
|
"ephemeris",
|
|
19
19
|
"lunar-eclipse",
|
|
20
20
|
"solar-eclipse",
|
|
21
|
-
"marine"
|
|
21
|
+
"marine",
|
|
22
|
+
"suncalc"
|
|
22
23
|
],
|
|
23
24
|
"publishConfig": {
|
|
24
25
|
"access": "public"
|