@openwaters/almanac 0.5.0 → 0.7.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 +57 -8
- package/dist/eclipse.d.ts +1 -1
- package/dist/eclipse.js +6 -5
- package/dist/events.d.ts +12 -4
- package/dist/events.js +31 -12
- package/dist/globalSolar.d.ts +6 -0
- package/dist/globalSolar.js +55 -13
- package/dist/horizon.d.ts +3 -0
- package/dist/horizon.js +24 -0
- package/dist/illumination.d.ts +3 -0
- package/dist/illumination.js +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +3 -1
- package/dist/planetModels.d.ts +5 -0
- package/dist/planetModels.js +467 -0
- package/dist/planets.d.ts +32 -0
- package/dist/planets.js +104 -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 +1 -0
- package/dist/transforms.js +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/types.js +5 -0
- package/package.json +2 -2
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
|
@@ -56,6 +56,7 @@ export declare function topoAltAzUnrefracted(bodyEqj: Vec3, ut: number, observer
|
|
|
56
56
|
* altitude never drops below -90.
|
|
57
57
|
*/
|
|
58
58
|
export declare function refractionDeg(altitudeDeg: number): number;
|
|
59
|
+
export declare function refract(unrefracted: AltAz): AltAz;
|
|
59
60
|
/**
|
|
60
61
|
* Topocentric azimuth/altitude of the Sun — parallax (via the observer's
|
|
61
62
|
* geocentric position, WGS-84 flattening, elevation) and atmospheric
|
package/dist/transforms.js
CHANGED
|
@@ -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';
|
|
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'].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.7.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",
|