caelus 0.10.0 → 0.12.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/dist/src/chart.d.ts +193 -13
- package/dist/src/chart.js +163 -13
- package/dist/src/compiler.d.ts +79 -0
- package/dist/src/compiler.js +152 -0
- package/dist/src/core.d.ts +33 -2
- package/dist/src/core.js +33 -2
- package/dist/src/derived.d.ts +91 -2
- package/dist/src/derived.js +91 -2
- package/dist/src/eclipses.d.ts +17 -1
- package/dist/src/eclipses.js +17 -1
- package/dist/src/events.d.ts +53 -7
- package/dist/src/events.js +53 -7
- package/dist/src/features.d.ts +88 -0
- package/dist/src/features.js +119 -0
- package/dist/src/houses.d.ts +13 -4
- package/dist/src/houses.js +13 -4
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/pheno.d.ts +16 -2
- package/dist/src/pheno.js +16 -2
- package/dist/src/query.d.ts +47 -6
- package/dist/src/query.js +47 -6
- package/dist/src/turbo.d.ts +35 -1
- package/dist/src/turbo.js +35 -1
- package/package.json +1 -1
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine compiler -- synthesize a chart form from geometric constraints.
|
|
3
|
+
*
|
|
4
|
+
* The inverse of (time, place) -> chart: given weighted geometric constraints
|
|
5
|
+
* (aspects between bodies, sign or degree placements), find the body longitudes
|
|
6
|
+
* that best satisfy them, and report how well they can be. If the best fit is
|
|
7
|
+
* still poor, the form is geometrically impossible -- a valid result.
|
|
8
|
+
*
|
|
9
|
+
* The loss / constraint math is pure and mirrors the Python reference
|
|
10
|
+
* (astroengine/compiler.py), pinned by the golden. The optimizer is a
|
|
11
|
+
* deterministic coordinate descent with fixed low-discrepancy restarts.
|
|
12
|
+
*/
|
|
13
|
+
const PHI = 0.6180339887498949;
|
|
14
|
+
function angDist(a, b) {
|
|
15
|
+
return Math.abs(((a - b + 180.0) % 360.0) - 180.0);
|
|
16
|
+
}
|
|
17
|
+
function signLoss(lon, sign) {
|
|
18
|
+
const lo = (((sign % 12) + 12) % 12) * 30.0;
|
|
19
|
+
const d = (((lon - lo) % 360.0) + 360.0) % 360.0;
|
|
20
|
+
if (d < 30.0)
|
|
21
|
+
return 0.0;
|
|
22
|
+
return Math.min(d - 30.0, 360.0 - d);
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Degrees by which a single {@link Constraint} is unmet for a set of body
|
|
26
|
+
* longitudes — `0` when satisfied. The pure building block of {@link formLoss}
|
|
27
|
+
* and {@link compileForm}.
|
|
28
|
+
*
|
|
29
|
+
* @param lons Body longitudes in degrees, keyed by body id.
|
|
30
|
+
* @param c The constraint to score.
|
|
31
|
+
* @returns The unmet amount in degrees (`0` = satisfied).
|
|
32
|
+
*/
|
|
33
|
+
export function constraintLoss(lons, c) {
|
|
34
|
+
if (c.kind === "aspect")
|
|
35
|
+
return Math.abs(angDist(lons[c.a], lons[c.b]) - c.angle);
|
|
36
|
+
if (c.kind === "sign")
|
|
37
|
+
return signLoss(lons[c.body], c.sign);
|
|
38
|
+
return angDist(lons[c.body], c.degree);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Total weighted loss for a set of body longitudes — the sum of each
|
|
42
|
+
* constraint's {@link constraintLoss} times its weight. The objective
|
|
43
|
+
* {@link compileForm} minimizes.
|
|
44
|
+
*
|
|
45
|
+
* @param lons Body longitudes in degrees, keyed by body id.
|
|
46
|
+
* @param constraints The constraints to score.
|
|
47
|
+
* @returns The total weighted loss in degrees (`0` = all satisfied).
|
|
48
|
+
*/
|
|
49
|
+
export function formLoss(lons, constraints) {
|
|
50
|
+
let total = 0;
|
|
51
|
+
for (const c of constraints)
|
|
52
|
+
total += (c.weight ?? 1.0) * constraintLoss(lons, c);
|
|
53
|
+
return total;
|
|
54
|
+
}
|
|
55
|
+
function bodiesOf(constraints) {
|
|
56
|
+
const s = new Set();
|
|
57
|
+
for (const c of constraints) {
|
|
58
|
+
if (c.kind === "aspect") {
|
|
59
|
+
s.add(c.a);
|
|
60
|
+
s.add(c.b);
|
|
61
|
+
}
|
|
62
|
+
else
|
|
63
|
+
s.add(c.body);
|
|
64
|
+
}
|
|
65
|
+
return [...s].sort();
|
|
66
|
+
}
|
|
67
|
+
function involves(c, body) {
|
|
68
|
+
return c.kind === "aspect" ? (c.a === body || c.b === body) : c.body === body;
|
|
69
|
+
}
|
|
70
|
+
function bodyLoss(lons, body, constraints) {
|
|
71
|
+
let total = 0;
|
|
72
|
+
for (const c of constraints)
|
|
73
|
+
if (involves(c, body))
|
|
74
|
+
total += (c.weight ?? 1.0) * constraintLoss(lons, c);
|
|
75
|
+
return total;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Synthesize a chart form from geometric constraints — the inverse of
|
|
79
|
+
* (time, place) → chart. Given weighted {@link Constraint}s (aspects between
|
|
80
|
+
* bodies, sign placements, exact degrees), find the body longitudes that best
|
|
81
|
+
* satisfy them via deterministic coordinate descent, and report how well they
|
|
82
|
+
* can be met. When even the best fit is poor, the form is flagged `impossible`
|
|
83
|
+
* — a valid, informative result.
|
|
84
|
+
*
|
|
85
|
+
* @param constraints The geometric constraints to satisfy; each may carry a
|
|
86
|
+
* `weight` (default `1`).
|
|
87
|
+
* @param opts `restarts` and `iters` tune the optimizer (more = slower, more
|
|
88
|
+
* thorough); `impossibleDeg` is the worst-constraint threshold in degrees
|
|
89
|
+
* above which the form is impossible. Defaults: `12`, `8`, `5`.
|
|
90
|
+
* @returns A {@link CompiledForm}: solved `longitudes`, total `residual`,
|
|
91
|
+
* `maxConstraintLoss`, the `impossible` flag, and each constraint annotated
|
|
92
|
+
* with its `loss`.
|
|
93
|
+
* @example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const form = compileForm([
|
|
96
|
+
* { kind: "aspect", a: "sun", b: "moon", angle: 120 }, // trine
|
|
97
|
+
* { kind: "sign", body: "sun", sign: 0 }, // Aries
|
|
98
|
+
* ]);
|
|
99
|
+
* form.impossible; // false
|
|
100
|
+
* form.longitudes.sun; // a degree within Aries
|
|
101
|
+
* ```
|
|
102
|
+
*/
|
|
103
|
+
export function compileForm(constraints, opts = {}) {
|
|
104
|
+
const restarts = opts.restarts ?? 12;
|
|
105
|
+
const iters = opts.iters ?? 8;
|
|
106
|
+
const impossibleDeg = opts.impossibleDeg ?? 5.0;
|
|
107
|
+
const bodies = bodiesOf(constraints);
|
|
108
|
+
const n = Math.max(bodies.length, 1);
|
|
109
|
+
let best = null;
|
|
110
|
+
for (let r = 0; r < restarts; r++) {
|
|
111
|
+
const lons = {};
|
|
112
|
+
bodies.forEach((b, i) => { lons[b] = (((r * n + i + 1) * PHI) % 1.0) * 360.0; });
|
|
113
|
+
for (let it = 0; it < iters; it++) {
|
|
114
|
+
for (const b of bodies) {
|
|
115
|
+
let bestL = lons[b];
|
|
116
|
+
let bestE = bodyLoss(lons, b, constraints);
|
|
117
|
+
for (let i = 0; i < 360; i++) {
|
|
118
|
+
lons[b] = i;
|
|
119
|
+
const e = bodyLoss(lons, b, constraints);
|
|
120
|
+
if (e < bestE) {
|
|
121
|
+
bestE = e;
|
|
122
|
+
bestL = i;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
for (let k = -20; k <= 20; k++) {
|
|
126
|
+
const cand = (((bestL + k * 0.05) % 360.0) + 360.0) % 360.0;
|
|
127
|
+
lons[b] = cand;
|
|
128
|
+
const e = bodyLoss(lons, b, constraints);
|
|
129
|
+
if (e < bestE) {
|
|
130
|
+
bestE = e;
|
|
131
|
+
bestL = cand;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
lons[b] = bestL;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const e = formLoss(lons, constraints);
|
|
138
|
+
if (best === null || e < best.e)
|
|
139
|
+
best = { e, lons: { ...lons } };
|
|
140
|
+
}
|
|
141
|
+
const lons = best.lons;
|
|
142
|
+
let maxLoss = 0;
|
|
143
|
+
for (const c of constraints)
|
|
144
|
+
maxLoss = Math.max(maxLoss, constraintLoss(lons, c));
|
|
145
|
+
return {
|
|
146
|
+
longitudes: lons,
|
|
147
|
+
residual: best.e,
|
|
148
|
+
maxConstraintLoss: maxLoss,
|
|
149
|
+
impossible: maxLoss > impossibleDeg,
|
|
150
|
+
constraints: constraints.map((c) => ({ ...c, loss: constraintLoss(lons, c) })),
|
|
151
|
+
};
|
|
152
|
+
}
|
package/dist/src/core.d.ts
CHANGED
|
@@ -59,9 +59,40 @@ export interface EngineData {
|
|
|
59
59
|
/** Fixed-star catalog (HYG-derived; ICRS J2000 + proper motions). */
|
|
60
60
|
fixedStars?: import("./stars.js").StarPack;
|
|
61
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Convert a UT calendar date and time to a Julian Day (UT) — the time
|
|
64
|
+
* coordinate the engine consumes. Pass the result to {@link Engine.position},
|
|
65
|
+
* {@link Engine.longitude}, {@link Engine.chartAt}, and the event/derived
|
|
66
|
+
* functions; {@link Engine.chart} takes the calendar fields directly instead.
|
|
67
|
+
*
|
|
68
|
+
* Arguments are **UT**, not local civil time — convert a local time to UT
|
|
69
|
+
* first (see the `caelus-birth` package). Uses the proleptic Gregorian
|
|
70
|
+
* calendar.
|
|
71
|
+
*
|
|
72
|
+
* @param y Year in UT, e.g. `1990`.
|
|
73
|
+
* @param mo Month, `1`–`12`.
|
|
74
|
+
* @param d Day of month, `1`–`31`.
|
|
75
|
+
* @param h Hour, `0`–`23`. Defaults to `0`.
|
|
76
|
+
* @param mi Minute, `0`–`59`. Defaults to `0`.
|
|
77
|
+
* @param s Second, `0`–`59`. Defaults to `0`.
|
|
78
|
+
* @returns The Julian Day in UT (a fractional day count).
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const jd = julianDay(2025, 6, 1, 12, 0, 0); // 2025-06-01 12:00 UT
|
|
82
|
+
* engine.longitude("sun", jd);
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
62
85
|
export declare function julianDay(y: number, mo: number, d: number, h?: number, mi?: number, s?: number): number;
|
|
63
|
-
/**
|
|
64
|
-
*
|
|
86
|
+
/**
|
|
87
|
+
* ΔT (TT − UT1) in seconds at a given instant — the gap between Terrestrial
|
|
88
|
+
* Time and universal time. Observed IERS values 1955–2025, Espenak–Meeus
|
|
89
|
+
* polynomials before, and a gentle extrapolation after (Earth's rotation sped
|
|
90
|
+
* up post-2016). The engine applies this for you; call it directly only for
|
|
91
|
+
* timescale work.
|
|
92
|
+
*
|
|
93
|
+
* @param jdUt Julian Day (UT).
|
|
94
|
+
* @returns ΔT in seconds.
|
|
95
|
+
*/
|
|
65
96
|
export declare function deltaT(jdUt: number): number;
|
|
66
97
|
export declare function jdTT(jdUt: number): number;
|
|
67
98
|
export declare function vsopHeliocentric(series: VsopSeries, jde: number): [number, number, number];
|
package/dist/src/core.js
CHANGED
|
@@ -17,6 +17,29 @@ export function mod(a, b) {
|
|
|
17
17
|
return r !== 0 && (r < 0) !== (b < 0) ? r + b : r;
|
|
18
18
|
}
|
|
19
19
|
// ---------------------------------------------------------------- timescale
|
|
20
|
+
/**
|
|
21
|
+
* Convert a UT calendar date and time to a Julian Day (UT) — the time
|
|
22
|
+
* coordinate the engine consumes. Pass the result to {@link Engine.position},
|
|
23
|
+
* {@link Engine.longitude}, {@link Engine.chartAt}, and the event/derived
|
|
24
|
+
* functions; {@link Engine.chart} takes the calendar fields directly instead.
|
|
25
|
+
*
|
|
26
|
+
* Arguments are **UT**, not local civil time — convert a local time to UT
|
|
27
|
+
* first (see the `caelus-birth` package). Uses the proleptic Gregorian
|
|
28
|
+
* calendar.
|
|
29
|
+
*
|
|
30
|
+
* @param y Year in UT, e.g. `1990`.
|
|
31
|
+
* @param mo Month, `1`–`12`.
|
|
32
|
+
* @param d Day of month, `1`–`31`.
|
|
33
|
+
* @param h Hour, `0`–`23`. Defaults to `0`.
|
|
34
|
+
* @param mi Minute, `0`–`59`. Defaults to `0`.
|
|
35
|
+
* @param s Second, `0`–`59`. Defaults to `0`.
|
|
36
|
+
* @returns The Julian Day in UT (a fractional day count).
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* const jd = julianDay(2025, 6, 1, 12, 0, 0); // 2025-06-01 12:00 UT
|
|
40
|
+
* engine.longitude("sun", jd);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
20
43
|
export function julianDay(y, mo, d, h = 0, mi = 0, s = 0) {
|
|
21
44
|
const frac = (h + mi / 60.0 + s / 3600.0) / 24.0;
|
|
22
45
|
if (mo <= 2) {
|
|
@@ -33,8 +56,16 @@ const DT_OBS = [
|
|
|
33
56
|
[1980, 50.5], [1985, 54.3], [1990, 56.9], [1995, 60.8], [2000, 63.8],
|
|
34
57
|
[2005, 64.7], [2010, 66.1], [2015, 67.6], [2020, 69.4], [2025, 69.2],
|
|
35
58
|
];
|
|
36
|
-
/**
|
|
37
|
-
*
|
|
59
|
+
/**
|
|
60
|
+
* ΔT (TT − UT1) in seconds at a given instant — the gap between Terrestrial
|
|
61
|
+
* Time and universal time. Observed IERS values 1955–2025, Espenak–Meeus
|
|
62
|
+
* polynomials before, and a gentle extrapolation after (Earth's rotation sped
|
|
63
|
+
* up post-2016). The engine applies this for you; call it directly only for
|
|
64
|
+
* timescale work.
|
|
65
|
+
*
|
|
66
|
+
* @param jdUt Julian Day (UT).
|
|
67
|
+
* @returns ΔT in seconds.
|
|
68
|
+
*/
|
|
38
69
|
export function deltaT(jdUt) {
|
|
39
70
|
const y = 2000.0 + (jdUt - J2000) / 365.25;
|
|
40
71
|
if (y >= 1955 && y <= 2025) {
|
package/dist/src/derived.d.ts
CHANGED
|
@@ -5,11 +5,50 @@ export declare function midpointLon(a: number, b: number): number;
|
|
|
5
5
|
/** UT JDs in [jdStart, jdEnd] when `body` returns to its natal longitude.
|
|
6
6
|
* Outer-planet returns can show three crossings around a retrograde loop. */
|
|
7
7
|
export declare function returns(engine: Engine, body: BodyId, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac, maxHits?: number): number[];
|
|
8
|
+
/**
|
|
9
|
+
* Solar-return instants in `[jdStart, jdEnd]`: the times the Sun returns to its
|
|
10
|
+
* natal longitude (about once a year). Build a chart at each with
|
|
11
|
+
* {@link Engine.chartAt} for the solar-return chart.
|
|
12
|
+
*
|
|
13
|
+
* @param engine The engine used to evaluate positions.
|
|
14
|
+
* @param natalJd Natal Julian Day (UT) — defines the target Sun longitude.
|
|
15
|
+
* @param jdStart Start of the search window, Julian Day (UT).
|
|
16
|
+
* @param jdEnd End of the search window, Julian Day (UT).
|
|
17
|
+
* @param zodiac Zodiac for the longitude match. Defaults to tropical.
|
|
18
|
+
* @returns Return instants as Julian Days (UT), sorted.
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const natal = julianDay(1990, 6, 10, 14, 30);
|
|
22
|
+
* const [thisYear] = solarReturn(engine, natal, julianDay(2025, 1, 1), julianDay(2026, 1, 1));
|
|
23
|
+
* const returnChart = engine.chartAt(thisYear, 27.95, -82.46);
|
|
24
|
+
* ```
|
|
25
|
+
* @see {@link lunarReturn} for the monthly Moon return.
|
|
26
|
+
*/
|
|
8
27
|
export declare function solarReturn(engine: Engine, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac): number[];
|
|
9
28
|
export declare function lunarReturn(engine: Engine, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac): number[];
|
|
10
29
|
/** The JD whose real positions are the secondary-progressed positions for the
|
|
11
30
|
* age (targetJd - natalJd): one day of motion per year of life. */
|
|
12
31
|
export declare function progressedJd(natalJd: number, targetJd: number, yearLength?: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Secondary-progressed longitude of a body for a given target date: the
|
|
34
|
+
* "day-for-a-year" method, where one day of real motion after birth maps to one
|
|
35
|
+
* year of life. Equivalent to taking the body's longitude at
|
|
36
|
+
* {@link progressedJd}.
|
|
37
|
+
*
|
|
38
|
+
* @param engine The engine used to evaluate positions.
|
|
39
|
+
* @param body A body id from {@link Engine.bodies}.
|
|
40
|
+
* @param natalJd Natal Julian Day (UT).
|
|
41
|
+
* @param targetJd The date to progress to, Julian Day (UT).
|
|
42
|
+
* @param yearLength Days per year of life. Defaults to the tropical year.
|
|
43
|
+
* @param zodiac Zodiac for the result. Defaults to tropical.
|
|
44
|
+
* @returns The progressed ecliptic longitude in degrees, `[0, 360)`.
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const natal = julianDay(1990, 6, 10, 14, 30);
|
|
48
|
+
* progressedLongitude(engine, "moon", natal, julianDay(2025, 6, 10));
|
|
49
|
+
* ```
|
|
50
|
+
* @see {@link solarArc} and {@link directedLongitude} for solar-arc directions.
|
|
51
|
+
*/
|
|
13
52
|
export declare function progressedLongitude(engine: Engine, body: BodyId, natalJd: number, targetJd: number, yearLength?: number, zodiac?: Zodiac): number;
|
|
14
53
|
/** Solar-arc direction angle (degrees, forward): how far the secondary-
|
|
15
54
|
* progressed Sun has moved from the natal Sun. Add it to any natal longitude. */
|
|
@@ -24,6 +63,22 @@ export declare function compositeLongitudes(engine: Engine, jdA: number, jdB: nu
|
|
|
24
63
|
export declare function davisonParams(jdA: number, jdB: number, latA: number, lonEastA: number, latB: number, lonEastB: number): [number, number, number];
|
|
25
64
|
/** The nth-harmonic longitude of a point: lon * n, wrapped to 360. */
|
|
26
65
|
export declare function harmonicLongitude(lon: number, n: number): number;
|
|
66
|
+
/**
|
|
67
|
+
* The nth-harmonic chart: each body's longitude multiplied by `n` and wrapped
|
|
68
|
+
* to `[0, 360)`. The 5th harmonic surfaces quintiles, the 9th the navamsa, and
|
|
69
|
+
* so on.
|
|
70
|
+
*
|
|
71
|
+
* @param engine The engine used to evaluate positions.
|
|
72
|
+
* @param jd Julian Day (UT).
|
|
73
|
+
* @param bodies The bodies to include.
|
|
74
|
+
* @param n The harmonic number, e.g. `5` or `9`.
|
|
75
|
+
* @param zodiac Zodiac for the base longitudes. Defaults to tropical.
|
|
76
|
+
* @returns Harmonic longitudes in degrees, keyed by body id.
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* harmonicChart(engine, jd, ["sun", "moon", "venus"], 5); // quintile harmonic
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
27
82
|
export declare function harmonicChart(engine: Engine, jd: number, bodies: BodyId[], n: number, zodiac?: Zodiac): Record<string, number>;
|
|
28
83
|
/** Reflection across the solstice (Cancer-Capricorn) axis. */
|
|
29
84
|
export declare function antiscion(lon: number): number;
|
|
@@ -37,15 +92,49 @@ export interface DeclinationPair {
|
|
|
37
92
|
b: string;
|
|
38
93
|
kind: DeclinationKind;
|
|
39
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Parallels and contraparallels among a set of bodies at an instant: pairs
|
|
97
|
+
* whose declinations are equal (parallel) or equal and opposite
|
|
98
|
+
* (contraparallel) within `orb` — the declination analogue of conjunction and
|
|
99
|
+
* opposition.
|
|
100
|
+
*
|
|
101
|
+
* @param engine The engine used to evaluate positions.
|
|
102
|
+
* @param bodies The bodies to compare.
|
|
103
|
+
* @param jd Julian Day (UT).
|
|
104
|
+
* @param orb Declination orb in degrees. Defaults to `1.0`.
|
|
105
|
+
* @returns {@link DeclinationPair}s `{ a, b, kind }`, where `kind` is
|
|
106
|
+
* `"parallel"` or `"contraparallel"`.
|
|
107
|
+
*/
|
|
40
108
|
export declare function declinationAspects(engine: Engine, bodies: BodyId[], jd: number, orb?: number): DeclinationPair[];
|
|
41
109
|
/** |declination| minus the mean obliquity, degrees. Positive = out of bounds. */
|
|
42
110
|
export declare function outOfBoundsMargin(engine: Engine, body: BodyId, jd: number): number;
|
|
43
111
|
export declare function outOfBounds(engine: Engine, body: BodyId, jd: number): boolean;
|
|
44
|
-
/**
|
|
45
|
-
*
|
|
112
|
+
/**
|
|
113
|
+
* Essential dignities a body holds in a sign: any of `"domicile"`,
|
|
114
|
+
* `"exaltation"`, `"detriment"`, `"fall"` (the last two are the signs opposite
|
|
115
|
+
* domicile and exaltation). Empty when the body is peregrine there.
|
|
116
|
+
*
|
|
117
|
+
* @param body Body id, e.g. `"mars"`.
|
|
118
|
+
* @param sign A sign index `0`–`11` (Aries = 0) or its name, e.g. `"Aries"`.
|
|
119
|
+
* @returns The dignities held, in the order above; empty if none.
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* dignities("mars", "Aries"); // ["domicile"]
|
|
123
|
+
* dignities("sun", "Libra"); // ["fall"]
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
46
126
|
export declare function dignities(body: string, sign: number | string): string[];
|
|
47
127
|
export declare function dignityOf(engine: Engine, body: BodyId, jd: number, zodiac?: Zodiac): string[];
|
|
48
128
|
/** Diurnal when the Sun is above the horizon at the given place. */
|
|
49
129
|
export declare function isDayChart(engine: Engine, jd: number, lat: number, lonEast: number): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* The sect a body belongs to: `"diurnal"` (Sun, Jupiter, Saturn),
|
|
132
|
+
* `"nocturnal"` (Moon, Venus, Mars), or `null` for Mercury and bodies without a
|
|
133
|
+
* fixed sect. Whether a chart is itself day or night — the Sun above or below
|
|
134
|
+
* the horizon — is a separate question.
|
|
135
|
+
*
|
|
136
|
+
* @param body Body id.
|
|
137
|
+
* @returns `"diurnal"`, `"nocturnal"`, or `null`.
|
|
138
|
+
*/
|
|
50
139
|
export declare function planetarySect(body: string): "diurnal" | "nocturnal" | null;
|
|
51
140
|
export declare function inSect(body: string, dayChart: boolean): boolean | null;
|
package/dist/src/derived.js
CHANGED
|
@@ -25,6 +25,25 @@ export function returns(engine, body, natalJd, jdStart, jdEnd, zodiac = "tropica
|
|
|
25
25
|
const natalLon = engine.longitude(body, natalJd, { zodiac });
|
|
26
26
|
return crossings(engine, body, natalLon, jdStart, jdEnd, zodiac, maxHits);
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Solar-return instants in `[jdStart, jdEnd]`: the times the Sun returns to its
|
|
30
|
+
* natal longitude (about once a year). Build a chart at each with
|
|
31
|
+
* {@link Engine.chartAt} for the solar-return chart.
|
|
32
|
+
*
|
|
33
|
+
* @param engine The engine used to evaluate positions.
|
|
34
|
+
* @param natalJd Natal Julian Day (UT) — defines the target Sun longitude.
|
|
35
|
+
* @param jdStart Start of the search window, Julian Day (UT).
|
|
36
|
+
* @param jdEnd End of the search window, Julian Day (UT).
|
|
37
|
+
* @param zodiac Zodiac for the longitude match. Defaults to tropical.
|
|
38
|
+
* @returns Return instants as Julian Days (UT), sorted.
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const natal = julianDay(1990, 6, 10, 14, 30);
|
|
42
|
+
* const [thisYear] = solarReturn(engine, natal, julianDay(2025, 1, 1), julianDay(2026, 1, 1));
|
|
43
|
+
* const returnChart = engine.chartAt(thisYear, 27.95, -82.46);
|
|
44
|
+
* ```
|
|
45
|
+
* @see {@link lunarReturn} for the monthly Moon return.
|
|
46
|
+
*/
|
|
28
47
|
export function solarReturn(engine, natalJd, jdStart, jdEnd, zodiac = "tropical") {
|
|
29
48
|
return returns(engine, "sun", natalJd, jdStart, jdEnd, zodiac);
|
|
30
49
|
}
|
|
@@ -37,6 +56,26 @@ export function lunarReturn(engine, natalJd, jdStart, jdEnd, zodiac = "tropical"
|
|
|
37
56
|
export function progressedJd(natalJd, targetJd, yearLength = TROPICAL_YEAR) {
|
|
38
57
|
return natalJd + (targetJd - natalJd) / yearLength;
|
|
39
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Secondary-progressed longitude of a body for a given target date: the
|
|
61
|
+
* "day-for-a-year" method, where one day of real motion after birth maps to one
|
|
62
|
+
* year of life. Equivalent to taking the body's longitude at
|
|
63
|
+
* {@link progressedJd}.
|
|
64
|
+
*
|
|
65
|
+
* @param engine The engine used to evaluate positions.
|
|
66
|
+
* @param body A body id from {@link Engine.bodies}.
|
|
67
|
+
* @param natalJd Natal Julian Day (UT).
|
|
68
|
+
* @param targetJd The date to progress to, Julian Day (UT).
|
|
69
|
+
* @param yearLength Days per year of life. Defaults to the tropical year.
|
|
70
|
+
* @param zodiac Zodiac for the result. Defaults to tropical.
|
|
71
|
+
* @returns The progressed ecliptic longitude in degrees, `[0, 360)`.
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const natal = julianDay(1990, 6, 10, 14, 30);
|
|
75
|
+
* progressedLongitude(engine, "moon", natal, julianDay(2025, 6, 10));
|
|
76
|
+
* ```
|
|
77
|
+
* @see {@link solarArc} and {@link directedLongitude} for solar-arc directions.
|
|
78
|
+
*/
|
|
40
79
|
export function progressedLongitude(engine, body, natalJd, targetJd, yearLength = TROPICAL_YEAR, zodiac = "tropical") {
|
|
41
80
|
return engine.longitude(body, progressedJd(natalJd, targetJd, yearLength), { zodiac });
|
|
42
81
|
}
|
|
@@ -82,6 +121,22 @@ export function davisonParams(jdA, jdB, latA, lonEastA, latB, lonEastB) {
|
|
|
82
121
|
export function harmonicLongitude(lon, n) {
|
|
83
122
|
return mod(lon * n, 360);
|
|
84
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* The nth-harmonic chart: each body's longitude multiplied by `n` and wrapped
|
|
126
|
+
* to `[0, 360)`. The 5th harmonic surfaces quintiles, the 9th the navamsa, and
|
|
127
|
+
* so on.
|
|
128
|
+
*
|
|
129
|
+
* @param engine The engine used to evaluate positions.
|
|
130
|
+
* @param jd Julian Day (UT).
|
|
131
|
+
* @param bodies The bodies to include.
|
|
132
|
+
* @param n The harmonic number, e.g. `5` or `9`.
|
|
133
|
+
* @param zodiac Zodiac for the base longitudes. Defaults to tropical.
|
|
134
|
+
* @returns Harmonic longitudes in degrees, keyed by body id.
|
|
135
|
+
* @example
|
|
136
|
+
* ```ts
|
|
137
|
+
* harmonicChart(engine, jd, ["sun", "moon", "venus"], 5); // quintile harmonic
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
85
140
|
export function harmonicChart(engine, jd, bodies, n, zodiac = "tropical") {
|
|
86
141
|
const out = {};
|
|
87
142
|
for (const b of bodies)
|
|
@@ -105,6 +160,19 @@ export function declinationAspect(decA, decB, orb = 1.0) {
|
|
|
105
160
|
return "contraparallel";
|
|
106
161
|
return null;
|
|
107
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Parallels and contraparallels among a set of bodies at an instant: pairs
|
|
165
|
+
* whose declinations are equal (parallel) or equal and opposite
|
|
166
|
+
* (contraparallel) within `orb` — the declination analogue of conjunction and
|
|
167
|
+
* opposition.
|
|
168
|
+
*
|
|
169
|
+
* @param engine The engine used to evaluate positions.
|
|
170
|
+
* @param bodies The bodies to compare.
|
|
171
|
+
* @param jd Julian Day (UT).
|
|
172
|
+
* @param orb Declination orb in degrees. Defaults to `1.0`.
|
|
173
|
+
* @returns {@link DeclinationPair}s `{ a, b, kind }`, where `kind` is
|
|
174
|
+
* `"parallel"` or `"contraparallel"`.
|
|
175
|
+
*/
|
|
108
176
|
export function declinationAspects(engine, bodies, jd, orb = 1.0) {
|
|
109
177
|
const decs = {};
|
|
110
178
|
for (const b of bodies)
|
|
@@ -140,8 +208,20 @@ const EXALTATION = {
|
|
|
140
208
|
function signIndex(sign) {
|
|
141
209
|
return typeof sign === "number" ? sign : SIGNS.indexOf(sign);
|
|
142
210
|
}
|
|
143
|
-
/**
|
|
144
|
-
*
|
|
211
|
+
/**
|
|
212
|
+
* Essential dignities a body holds in a sign: any of `"domicile"`,
|
|
213
|
+
* `"exaltation"`, `"detriment"`, `"fall"` (the last two are the signs opposite
|
|
214
|
+
* domicile and exaltation). Empty when the body is peregrine there.
|
|
215
|
+
*
|
|
216
|
+
* @param body Body id, e.g. `"mars"`.
|
|
217
|
+
* @param sign A sign index `0`–`11` (Aries = 0) or its name, e.g. `"Aries"`.
|
|
218
|
+
* @returns The dignities held, in the order above; empty if none.
|
|
219
|
+
* @example
|
|
220
|
+
* ```ts
|
|
221
|
+
* dignities("mars", "Aries"); // ["domicile"]
|
|
222
|
+
* dignities("sun", "Libra"); // ["fall"]
|
|
223
|
+
* ```
|
|
224
|
+
*/
|
|
145
225
|
export function dignities(body, sign) {
|
|
146
226
|
const idx = signIndex(sign);
|
|
147
227
|
const dom = DOMICILE[body] ?? [];
|
|
@@ -169,6 +249,15 @@ export function isDayChart(engine, jd, lat, lonEast) {
|
|
|
169
249
|
const [, alt] = azAlt(engine.data, sun.lon, sun.lat, jd, lat, lonEast);
|
|
170
250
|
return alt > 0;
|
|
171
251
|
}
|
|
252
|
+
/**
|
|
253
|
+
* The sect a body belongs to: `"diurnal"` (Sun, Jupiter, Saturn),
|
|
254
|
+
* `"nocturnal"` (Moon, Venus, Mars), or `null` for Mercury and bodies without a
|
|
255
|
+
* fixed sect. Whether a chart is itself day or night — the Sun above or below
|
|
256
|
+
* the horizon — is a separate question.
|
|
257
|
+
*
|
|
258
|
+
* @param body Body id.
|
|
259
|
+
* @returns `"diurnal"`, `"nocturnal"`, or `null`.
|
|
260
|
+
*/
|
|
172
261
|
export function planetarySect(body) {
|
|
173
262
|
if (DIURNAL.has(body))
|
|
174
263
|
return "diurnal";
|
package/dist/src/eclipses.d.ts
CHANGED
|
@@ -20,5 +20,21 @@ export interface SolarEclipse {
|
|
|
20
20
|
}
|
|
21
21
|
/** Lunar eclipses in [jdStart, jdEnd] (UT JDs). */
|
|
22
22
|
export declare function lunarEclipses(engine: Engine, jdStart: number, jdEnd: number): LunarEclipse[];
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Solar eclipses in `[jdStart, jdEnd]`, with global circumstances (not
|
|
25
|
+
* local visibility). Each new Moon in the window is tested for an eclipse and,
|
|
26
|
+
* when found, classified by the Moon's shadow geometry.
|
|
27
|
+
*
|
|
28
|
+
* @param engine The engine used to evaluate positions.
|
|
29
|
+
* @param jdStart Start of the window, Julian Day (UT).
|
|
30
|
+
* @param jdEnd End of the window, Julian Day (UT).
|
|
31
|
+
* @returns {@link SolarEclipse} records: `tMax` (greatest eclipse, JD UT),
|
|
32
|
+
* `type` (`"total"`/`"annular"`/`"hybrid"`/`"partial"`), `gamma` (minimum
|
|
33
|
+
* shadow-axis distance in Earth radii), and the `begin`/`end` JDs.
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const eclipses = solarEclipses(engine, julianDay(2025, 1, 1), julianDay(2030, 1, 1));
|
|
37
|
+
* eclipses[0].type; // e.g. "partial"
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
24
40
|
export declare function solarEclipses(engine: Engine, jdStart: number, jdEnd: number): SolarEclipse[];
|
package/dist/src/eclipses.js
CHANGED
|
@@ -131,7 +131,23 @@ export function lunarEclipses(engine, jdStart, jdEnd) {
|
|
|
131
131
|
}
|
|
132
132
|
return out;
|
|
133
133
|
}
|
|
134
|
-
/**
|
|
134
|
+
/**
|
|
135
|
+
* Solar eclipses in `[jdStart, jdEnd]`, with global circumstances (not
|
|
136
|
+
* local visibility). Each new Moon in the window is tested for an eclipse and,
|
|
137
|
+
* when found, classified by the Moon's shadow geometry.
|
|
138
|
+
*
|
|
139
|
+
* @param engine The engine used to evaluate positions.
|
|
140
|
+
* @param jdStart Start of the window, Julian Day (UT).
|
|
141
|
+
* @param jdEnd End of the window, Julian Day (UT).
|
|
142
|
+
* @returns {@link SolarEclipse} records: `tMax` (greatest eclipse, JD UT),
|
|
143
|
+
* `type` (`"total"`/`"annular"`/`"hybrid"`/`"partial"`), `gamma` (minimum
|
|
144
|
+
* shadow-axis distance in Earth radii), and the `begin`/`end` JDs.
|
|
145
|
+
* @example
|
|
146
|
+
* ```ts
|
|
147
|
+
* const eclipses = solarEclipses(engine, julianDay(2025, 1, 1), julianDay(2030, 1, 1));
|
|
148
|
+
* eclipses[0].type; // e.g. "partial"
|
|
149
|
+
* ```
|
|
150
|
+
*/
|
|
135
151
|
export function solarEclipses(engine, jdStart, jdEnd) {
|
|
136
152
|
const out = [];
|
|
137
153
|
for (const tNew of syzygies(engine, jdStart - 1, jdEnd + 1, 0.0)) {
|
package/dist/src/events.d.ts
CHANGED
|
@@ -8,22 +8,68 @@ export interface RiseSetOptions {
|
|
|
8
8
|
/** Rise/set of the disc center instead of the upper limb. */
|
|
9
9
|
discCenter?: boolean;
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
*
|
|
11
|
+
/**
|
|
12
|
+
* The next rise, set, or meridian transit of a body after `jdStart`, as a
|
|
13
|
+
* Julian Day (UT). Accounts for the body's apparent radius, atmospheric
|
|
14
|
+
* refraction, and observer altitude.
|
|
15
|
+
*
|
|
16
|
+
* @param engine The engine used to evaluate positions.
|
|
17
|
+
* @param body A body id from {@link Engine.bodies}.
|
|
18
|
+
* @param jdStart Search start, Julian Day (UT). The result is the first event
|
|
19
|
+
* strictly after this instant.
|
|
20
|
+
* @param latDeg Observer latitude in degrees, north positive.
|
|
21
|
+
* @param lonDeg Observer longitude in degrees, east positive.
|
|
22
|
+
* @param kind `"rise"`, `"set"`, `"mtransit"` (upper/meridian transit), or
|
|
23
|
+
* `"itransit"` (lower transit). Defaults to `"rise"`.
|
|
24
|
+
* @param opts `altM` (observer altitude, m), `pressure` (hPa), `tempC`, and
|
|
25
|
+
* `searchDays` (how far ahead to look; defaults to 2).
|
|
26
|
+
* @returns The event time as a Julian Day (UT), or `null` when it does not
|
|
27
|
+
* occur in the window (e.g. polar day or night).
|
|
28
|
+
* @example
|
|
29
|
+
* ```ts
|
|
30
|
+
* // Next sunrise over London after 2025-06-01
|
|
31
|
+
* const jd = riseSet(engine, "sun", julianDay(2025, 6, 1), 51.5, -0.13, "rise");
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
13
34
|
export declare function riseSet(engine: Engine, body: BodyId, jdStart: number, latDeg: number, lonDeg: number, kind?: RiseKind, opts?: RiseSetOptions): number | null;
|
|
14
35
|
/** UT JDs where the body's apparent longitude crosses targetLon (degrees)
|
|
15
36
|
* in [jdStart, jdEnd]. Retrograde bodies can cross a degree three times;
|
|
16
37
|
* every crossing is returned in time order. */
|
|
17
38
|
export declare function crossings(engine: Engine, body: BodyId, targetLon: number, jdStart: number, jdEnd: number, zodiac?: Zodiac, maxHits?: number): number[];
|
|
18
39
|
export type PhaseName = "new" | "first_quarter" | "full" | "last_quarter";
|
|
19
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Every principal lunar phase (new, first quarter, full, last quarter) within
|
|
42
|
+
* `[jdStart, jdEnd]`, sorted by time. Found from the Sun–Moon elongation
|
|
43
|
+
* crossing 0°/90°/180°/270°.
|
|
44
|
+
*
|
|
45
|
+
* @param engine The engine used to evaluate positions.
|
|
46
|
+
* @param jdStart Start of the window, Julian Day (UT).
|
|
47
|
+
* @param jdEnd End of the window, Julian Day (UT).
|
|
48
|
+
* @param maxHits Cap on the number of phases returned. Defaults to 60.
|
|
49
|
+
* @returns Sorted `[jdUt, phase]` pairs, where `phase` is one of
|
|
50
|
+
* {@link PhaseName}.
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const phases = lunarPhases(engine, julianDay(2025, 1, 1), julianDay(2025, 2, 1));
|
|
54
|
+
* // [[jd, "new"], [jd, "first_quarter"], ...]
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
20
57
|
export declare function lunarPhases(engine: Engine, jdStart: number, jdEnd: number, maxHits?: number): Array<[number, PhaseName]>;
|
|
21
58
|
/** Times the body stations (speed crosses zero): [jdUt, direction the body
|
|
22
59
|
* turns]. Sun and Moon never station. Station timing is ill-conditioned:
|
|
23
60
|
* expect minute-level differences between ephemerides. */
|
|
24
61
|
export declare function stations(engine: Engine, body: BodyId, jdStart: number, jdEnd: number, maxHits?: number): Array<[number, "retrograde" | "direct"]>;
|
|
25
|
-
/**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
62
|
+
/**
|
|
63
|
+
* The Gauquelin sector of a body (1–36, fractional) from the rise/set times of
|
|
64
|
+
* the disc centre with refraction (Swiss Ephemeris method 3). Sectors run from
|
|
65
|
+
* rise: 1–18 above the horizon, 19–36 below.
|
|
66
|
+
*
|
|
67
|
+
* @param engine The engine used to evaluate positions.
|
|
68
|
+
* @param body A body id from {@link Engine.bodies}.
|
|
69
|
+
* @param jdUt Julian Day (UT).
|
|
70
|
+
* @param latDeg Observer latitude in degrees, north positive.
|
|
71
|
+
* @param lonDeg Observer longitude in degrees, east positive.
|
|
72
|
+
* @returns The sector in `[1, 37)`, or `null` in polar no-rise/no-set
|
|
73
|
+
* conditions.
|
|
74
|
+
*/
|
|
29
75
|
export declare function gauquelinSector(engine: Engine, body: BodyId, jdUt: number, latDeg: number, lonDeg: number): number | null;
|