caelus 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 +1 -1
- package/accuracy.json +9 -9
- package/dist/src/core.d.ts +5 -4
- package/dist/src/core.js +133 -43
- package/dist/src/derived.d.ts +51 -0
- package/dist/src/derived.js +184 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/query.d.ts +32 -0
- package/dist/src/query.js +161 -0
- package/dist/src/stars.d.ts +2 -3
- package/dist/src/stars.js +2 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ ephemeris files. 1:1 port of the Python reference, checked by golden fixtures.
|
|
|
11
11
|
(vs full DE431 files, 1850–2149), angles and Placidus cusps ≤ 3.2″ — all
|
|
12
12
|
invisible at the arcminute display precision chart software uses.
|
|
13
13
|
2. TypeScript port verified against Python golden fixtures: **3,218 checks,
|
|
14
|
-
0 failures, worst deviation
|
|
14
|
+
0 failures, worst deviation 0.41 nano-arcseconds.** The two implementations
|
|
15
15
|
are numerically identical.
|
|
16
16
|
|
|
17
17
|
Regenerate fixtures any time from the Python side; any future TS change must
|
package/accuracy.json
CHANGED
|
@@ -107,9 +107,9 @@
|
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
109
|
"name": "Sidereal longitudes",
|
|
110
|
-
"max": "
|
|
110
|
+
"max": "—",
|
|
111
111
|
"rms": "—",
|
|
112
|
-
"note": "ayanamsa model vs SE ≤0.
|
|
112
|
+
"note": "ayanamsa model vs SE ≤0.005″ (Vondrák 2011, same model both sides); sidereal longitudes inherit each body's tropical bound"
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "RA / Dec",
|
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
"name": "Topocentric Moon",
|
|
122
|
-
"max": "2.
|
|
122
|
+
"max": "2.5",
|
|
123
123
|
"rms": "—",
|
|
124
124
|
"note": "parallax model adds ≤0.1″ over the geocentric bound"
|
|
125
125
|
},
|
|
@@ -179,15 +179,15 @@
|
|
|
179
179
|
},
|
|
180
180
|
{
|
|
181
181
|
"name": "Fixed stars (318-star catalog)",
|
|
182
|
-
"max": "0.
|
|
182
|
+
"max": "0.3",
|
|
183
183
|
"rms": "—",
|
|
184
|
-
"note": "HYG-derived catalog (ICRS J2000 + proper motions, full 3D space motion); vs swe_fixstar fed the same rows
|
|
184
|
+
"note": "HYG-derived catalog (ICRS J2000 + proper motions, full 3D space motion, Vondrák 2011 precession); vs swe_fixstar fed the same rows"
|
|
185
185
|
},
|
|
186
186
|
{
|
|
187
187
|
"name": "Star-anchored ayanamsas",
|
|
188
|
-
"max": "0.
|
|
188
|
+
"max": "0.5",
|
|
189
189
|
"rms": "—",
|
|
190
|
-
"note": "galcent_0sag and true_citra computed from the apparent star
|
|
190
|
+
"note": "galcent_0sag and true_citra computed from the apparent star; bound tracks the fixed-star chain (≤0.3″) plus the body's tropical accuracy"
|
|
191
191
|
},
|
|
192
192
|
{
|
|
193
193
|
"name": "Gauquelin sectors",
|
|
@@ -257,11 +257,11 @@
|
|
|
257
257
|
},
|
|
258
258
|
{
|
|
259
259
|
"label": "Fixed stars",
|
|
260
|
-
"bound": "≤ 0.
|
|
260
|
+
"bound": "≤ 0.3″"
|
|
261
261
|
},
|
|
262
262
|
{
|
|
263
263
|
"label": "Sidereal (7 ayanamsas)",
|
|
264
|
-
"bound": "≤ 0.
|
|
264
|
+
"bound": "≤ 0.005″ added"
|
|
265
265
|
},
|
|
266
266
|
{
|
|
267
267
|
"label": "Eclipses",
|
package/dist/src/core.d.ts
CHANGED
|
@@ -69,7 +69,8 @@ export declare function vsopHeliocentric(series: VsopSeries, jde: number): [numb
|
|
|
69
69
|
export declare function nutation(data: EngineData, jde: number): [number, number];
|
|
70
70
|
export declare function meanObliquity(jde: number): number;
|
|
71
71
|
export declare function trueObliquity(data: EngineData, jde: number): number;
|
|
72
|
-
/** Precession of ecliptic coordinates (
|
|
72
|
+
/** Precession of ecliptic coordinates between epochs (Vondrak 2011):
|
|
73
|
+
* ecliptic-of-from -> J2000 equatorial -> ecliptic-of-to. */
|
|
73
74
|
export declare function precessEcliptic(lon: number, lat: number, jdeFrom: number, jdeTo: number): [number, number];
|
|
74
75
|
/** Apparent geocentric ecliptic lon/lat (true equinox of date), distance. */
|
|
75
76
|
export declare function planetApparent(data: EngineData, name: string, jde: number): [number, number, number];
|
|
@@ -96,9 +97,9 @@ export declare function trueNodeSeries(data: EngineData, jde: number): number;
|
|
|
96
97
|
/** Ecliptic lon/lat -> right ascension, declination (all radians). */
|
|
97
98
|
export declare function equatorial(lon: number, lat: number, eps: number): [number, number];
|
|
98
99
|
/** Mean ayanamsa at J2000.0 (degrees) per mode. Standard epoch anchors
|
|
99
|
-
* (matched to Swiss Ephemeris 2.10 to 1e-9 deg); propagation uses
|
|
100
|
-
* ecliptic precession
|
|
101
|
-
*
|
|
100
|
+
* (matched to Swiss Ephemeris 2.10 to 1e-9 deg); propagation uses Vondrak
|
|
101
|
+
* 2011 ecliptic precession, the same model Swiss Ephemeris uses:
|
|
102
|
+
* agreement over 1900-2099 is <=0.005 arcsec. */
|
|
102
103
|
export declare const AYANAMSA_J2000: Record<string, number>;
|
|
103
104
|
/** Mean ayanamsa in degrees. Sidereal longitude = (tropical true-equinox
|
|
104
105
|
* longitude - nutation in longitude) - ayanamsa: the sidereal zodiac is
|
package/dist/src/core.js
CHANGED
|
@@ -140,48 +140,138 @@ function fk5Correction(L, B, jde) {
|
|
|
140
140
|
const dB = 0.03916 * ARCSEC * (Math.cos(Lp) - Math.sin(Lp));
|
|
141
141
|
return [L + dL, B + dB];
|
|
142
142
|
}
|
|
143
|
-
|
|
143
|
+
// ------------------------------------------------- Vondrak 2011 precession
|
|
144
|
+
// Long-term precession of the ecliptic and equator (Vondrak, Capitaine &
|
|
145
|
+
// Wallace 2011, A&A 534 A22; coefficient tables as carried by ERFA under
|
|
146
|
+
// BSD-3). Replaces the IAU 1976 angles.
|
|
147
|
+
const PQ_POL = [
|
|
148
|
+
[5851.607687, -0.1189, -0.00028913, 0.000000101],
|
|
149
|
+
[-1600.8863, 1.1689818, -0.0000002, -0.000000437],
|
|
150
|
+
];
|
|
151
|
+
const PQ_PER = [
|
|
152
|
+
[708.15, -5486.751211, -684.66156, 667.66673, -5523.863691],
|
|
153
|
+
[2309.0, -17.127623, 2446.28388, -2354.886252, -549.74745],
|
|
154
|
+
[1620.0, -617.517403, 399.671049, -428.152441, -310.998056],
|
|
155
|
+
[492.2, 413.44294, -356.652376, 376.202861, 421.535876],
|
|
156
|
+
[1183.0, 78.614193, -186.387003, 184.778874, -36.776172],
|
|
157
|
+
[622.0, -180.732815, -316.80007, 335.321713, -145.278396],
|
|
158
|
+
[882.0, -87.676083, 198.296701, -185.138669, -34.74445],
|
|
159
|
+
[547.0, 46.140315, 101.135679, -120.97283, 22.885731],
|
|
160
|
+
];
|
|
161
|
+
const XY_POL = [
|
|
162
|
+
[5453.282155, 0.4252841, -0.00037173, -0.000000152],
|
|
163
|
+
[-73750.93035, -0.7675452, -0.00018725, 0.000000231],
|
|
164
|
+
];
|
|
165
|
+
const XY_PER = [
|
|
166
|
+
[256.75, -819.940624, 75004.344875, 81491.287984, 1558.515853],
|
|
167
|
+
[708.15, -8444.676815, 624.033993, 787.163481, 7774.939698],
|
|
168
|
+
[274.2, 2600.009459, 1251.136893, 1251.296102, -2219.534038],
|
|
169
|
+
[241.45, 2755.17563, -1102.212834, -1257.950837, -2523.969396],
|
|
170
|
+
[2309.0, -167.659835, -2660.66498, -2966.79973, 247.850422],
|
|
171
|
+
[492.2, 871.855056, 699.291817, 639.744522, -846.485643],
|
|
172
|
+
[396.1, 44.769698, 153.16722, 131.600209, -1393.124055],
|
|
173
|
+
[288.9, -512.313065, -950.865637, -445.040117, 368.526116],
|
|
174
|
+
[231.1, -819.415595, 499.754645, 584.522874, 749.045012],
|
|
175
|
+
[1610.0, -538.071099, -145.18821, -89.756563, 444.704518],
|
|
176
|
+
[620.0, -189.793622, 558.116553, 524.42963, 235.934465],
|
|
177
|
+
[157.87, -402.922932, -23.923029, -13.549067, 374.049623],
|
|
178
|
+
[220.3, 179.516345, -165.405086, -210.157124, -171.33018],
|
|
179
|
+
[1200.0, -9.814756, 9.344131, -44.919798, -22.899655],
|
|
180
|
+
];
|
|
181
|
+
const EPS0_V = 84381.406 * ARCSEC; // J2000 obliquity of the Vondrak model
|
|
182
|
+
const EPS0_FRAME = 84381.448 * ARCSEC; // obliquity defining our ecliptic-J2000 data
|
|
183
|
+
function ltpPecl(jde) {
|
|
184
|
+
const t = (jde - J2000) / 36525.0;
|
|
185
|
+
let p = 0.0;
|
|
186
|
+
let q = 0.0;
|
|
187
|
+
const w = 2.0 * Math.PI * t;
|
|
188
|
+
for (const [per, c1, c2, s1, s2] of PQ_PER) {
|
|
189
|
+
const a = w / per;
|
|
190
|
+
const ca = Math.cos(a);
|
|
191
|
+
const sa = Math.sin(a);
|
|
192
|
+
p += ca * c1 + sa * s1;
|
|
193
|
+
q += ca * c2 + sa * s2;
|
|
194
|
+
}
|
|
195
|
+
let tn = 1.0;
|
|
196
|
+
for (let i = 0; i < 4; i++) {
|
|
197
|
+
p += PQ_POL[0][i] * tn;
|
|
198
|
+
q += PQ_POL[1][i] * tn;
|
|
199
|
+
tn *= t;
|
|
200
|
+
}
|
|
201
|
+
p *= ARCSEC;
|
|
202
|
+
q *= ARCSEC;
|
|
203
|
+
const z = Math.sqrt(Math.max(1.0 - p * p - q * q, 0.0));
|
|
204
|
+
const s = Math.sin(EPS0_V);
|
|
205
|
+
const c = Math.cos(EPS0_V);
|
|
206
|
+
return [p, -q * c - z * s, -q * s + z * c];
|
|
207
|
+
}
|
|
208
|
+
function ltpPequ(jde) {
|
|
209
|
+
const t = (jde - J2000) / 36525.0;
|
|
210
|
+
let x = 0.0;
|
|
211
|
+
let y = 0.0;
|
|
212
|
+
const w = 2.0 * Math.PI * t;
|
|
213
|
+
for (const [per, c1, c2, s1, s2] of XY_PER) {
|
|
214
|
+
const a = w / per;
|
|
215
|
+
const ca = Math.cos(a);
|
|
216
|
+
const sa = Math.sin(a);
|
|
217
|
+
x += ca * c1 + sa * s1;
|
|
218
|
+
y += ca * c2 + sa * s2;
|
|
219
|
+
}
|
|
220
|
+
let tn = 1.0;
|
|
221
|
+
for (let i = 0; i < 4; i++) {
|
|
222
|
+
x += XY_POL[0][i] * tn;
|
|
223
|
+
y += XY_POL[1][i] * tn;
|
|
224
|
+
tn *= t;
|
|
225
|
+
}
|
|
226
|
+
x *= ARCSEC;
|
|
227
|
+
y *= ARCSEC;
|
|
228
|
+
return [x, y, Math.sqrt(Math.max(1.0 - x * x - y * y, 0.0))];
|
|
229
|
+
}
|
|
230
|
+
/** Rows of the rotation J2000-equatorial -> mean ecliptic/equinox of date
|
|
231
|
+
* (ERFA eraLtecm): x = equinox, z = ecliptic pole, y = z cross x. */
|
|
232
|
+
function ltpEclMatrix(jde) {
|
|
233
|
+
const p = ltpPequ(jde);
|
|
234
|
+
const z = ltpPecl(jde);
|
|
235
|
+
const wx = [
|
|
236
|
+
p[1] * z[2] - p[2] * z[1], p[2] * z[0] - p[0] * z[2], p[0] * z[1] - p[1] * z[0],
|
|
237
|
+
];
|
|
238
|
+
const n = Math.sqrt(wx[0] ** 2 + wx[1] ** 2 + wx[2] ** 2);
|
|
239
|
+
const x = [wx[0] / n, wx[1] / n, wx[2] / n];
|
|
240
|
+
const y = [
|
|
241
|
+
z[1] * x[2] - z[2] * x[1], z[2] * x[0] - z[0] * x[2], z[0] * x[1] - z[1] * x[0],
|
|
242
|
+
];
|
|
243
|
+
return [x, y, z];
|
|
244
|
+
}
|
|
245
|
+
/** Precession of ecliptic coordinates between epochs (Vondrak 2011):
|
|
246
|
+
* ecliptic-of-from -> J2000 equatorial -> ecliptic-of-to. */
|
|
144
247
|
export function precessEcliptic(lon, lat, jdeFrom, jdeTo) {
|
|
145
|
-
const
|
|
146
|
-
const
|
|
147
|
-
const
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
248
|
+
const cb = Math.cos(lat);
|
|
249
|
+
const v = [cb * Math.cos(lon), cb * Math.sin(lon), Math.sin(lat)];
|
|
250
|
+
const [xf, yf, zf] = ltpEclMatrix(jdeFrom);
|
|
251
|
+
const e = [0, 1, 2].map((i) => xf[i] * v[0] + yf[i] * v[1] + zf[i] * v[2]);
|
|
252
|
+
const [xt, yt, zt] = ltpEclMatrix(jdeTo);
|
|
253
|
+
const u = [
|
|
254
|
+
xt[0] * e[0] + xt[1] * e[1] + xt[2] * e[2],
|
|
255
|
+
yt[0] * e[0] + yt[1] * e[1] + yt[2] * e[2],
|
|
256
|
+
zt[0] * e[0] + zt[1] * e[1] + zt[2] * e[2],
|
|
257
|
+
];
|
|
258
|
+
return [mod(Math.atan2(u[1], u[0]), TWO_PI),
|
|
259
|
+
Math.asin(Math.max(-1, Math.min(1, u[2])))];
|
|
260
|
+
}
|
|
261
|
+
/** Rotate a vector from the ecliptic-J2000 data frame (obliquity 84381.448
|
|
262
|
+
* arcsec, as used by Horizons/Meeus) to the mean ecliptic of date
|
|
263
|
+
* (Vondrak 2011). */
|
|
161
264
|
function eclJ2000ToEclDate(v, jde) {
|
|
162
|
-
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
[x, y] = [c * x + s * y, -s * x + c * y];
|
|
173
|
-
};
|
|
174
|
-
const ry = (a) => {
|
|
175
|
-
const c = Math.cos(a);
|
|
176
|
-
const s = Math.sin(a);
|
|
177
|
-
[x, z] = [c * x - s * z, s * x + c * z];
|
|
178
|
-
};
|
|
179
|
-
rz(-zeta);
|
|
180
|
-
ry(th);
|
|
181
|
-
rz(-zz);
|
|
182
|
-
const e = meanObliquity(jde);
|
|
183
|
-
[y, z] = [y * Math.cos(e) + z * Math.sin(e), -y * Math.sin(e) + z * Math.cos(e)];
|
|
184
|
-
return [x, y, z];
|
|
265
|
+
const [x, y, z] = v;
|
|
266
|
+
const s = Math.sin(EPS0_FRAME);
|
|
267
|
+
const c = Math.cos(EPS0_FRAME);
|
|
268
|
+
const e = [x, y * c - z * s, y * s + z * c];
|
|
269
|
+
const [xt, yt, zt] = ltpEclMatrix(jde);
|
|
270
|
+
return [
|
|
271
|
+
xt[0] * e[0] + xt[1] * e[1] + xt[2] * e[2],
|
|
272
|
+
yt[0] * e[0] + yt[1] * e[1] + yt[2] * e[2],
|
|
273
|
+
zt[0] * e[0] + zt[1] * e[1] + zt[2] * e[2],
|
|
274
|
+
];
|
|
185
275
|
}
|
|
186
276
|
// ---------------------------------------------------------------- planets
|
|
187
277
|
function geoVector(data, name, jde) {
|
|
@@ -385,9 +475,9 @@ export function equatorial(lon, lat, eps) {
|
|
|
385
475
|
return [ra, dec];
|
|
386
476
|
}
|
|
387
477
|
/** Mean ayanamsa at J2000.0 (degrees) per mode. Standard epoch anchors
|
|
388
|
-
* (matched to Swiss Ephemeris 2.10 to 1e-9 deg); propagation uses
|
|
389
|
-
* ecliptic precession
|
|
390
|
-
*
|
|
478
|
+
* (matched to Swiss Ephemeris 2.10 to 1e-9 deg); propagation uses Vondrak
|
|
479
|
+
* 2011 ecliptic precession, the same model Swiss Ephemeris uses:
|
|
480
|
+
* agreement over 1900-2099 is <=0.005 arcsec. */
|
|
391
481
|
export const AYANAMSA_J2000 = {
|
|
392
482
|
lahiri: 23.857092325,
|
|
393
483
|
fagan_bradley: 24.740299966,
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Engine, BodyId, Zodiac } from "./chart.js";
|
|
2
|
+
export declare const TROPICAL_YEAR = 365.24219;
|
|
3
|
+
/** Shorter-arc midpoint of two longitudes (degrees). */
|
|
4
|
+
export declare function midpointLon(a: number, b: number): number;
|
|
5
|
+
/** UT JDs in [jdStart, jdEnd] when `body` returns to its natal longitude.
|
|
6
|
+
* Outer-planet returns can show three crossings around a retrograde loop. */
|
|
7
|
+
export declare function returns(engine: Engine, body: BodyId, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac, maxHits?: number): number[];
|
|
8
|
+
export declare function solarReturn(engine: Engine, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac): number[];
|
|
9
|
+
export declare function lunarReturn(engine: Engine, natalJd: number, jdStart: number, jdEnd: number, zodiac?: Zodiac): number[];
|
|
10
|
+
/** The JD whose real positions are the secondary-progressed positions for the
|
|
11
|
+
* age (targetJd - natalJd): one day of motion per year of life. */
|
|
12
|
+
export declare function progressedJd(natalJd: number, targetJd: number, yearLength?: number): number;
|
|
13
|
+
export declare function progressedLongitude(engine: Engine, body: BodyId, natalJd: number, targetJd: number, yearLength?: number, zodiac?: Zodiac): number;
|
|
14
|
+
/** Solar-arc direction angle (degrees, forward): how far the secondary-
|
|
15
|
+
* progressed Sun has moved from the natal Sun. Add it to any natal longitude. */
|
|
16
|
+
export declare function solarArc(engine: Engine, natalJd: number, targetJd: number, yearLength?: number, zodiac?: Zodiac): number;
|
|
17
|
+
export declare function directedLongitude(engine: Engine, body: BodyId, natalJd: number, targetJd: number, yearLength?: number, zodiac?: Zodiac): number;
|
|
18
|
+
/** Midpoint-method composite: the shorter-arc midpoint of each body's two
|
|
19
|
+
* longitudes. Angles compose the same way via midpointLon on the two ASC/MC. */
|
|
20
|
+
export declare function compositeLongitudes(engine: Engine, jdA: number, jdB: number, bodies: BodyId[], zodiac?: Zodiac): Record<string, number>;
|
|
21
|
+
/** Time and place for a Davison relationship chart: the temporal midpoint and
|
|
22
|
+
* the geographic midpoint (mean latitude, shorter-arc mean longitude). Compute
|
|
23
|
+
* a normal chart at these to get the Davison chart. Returns [jd, lat, lonEast]. */
|
|
24
|
+
export declare function davisonParams(jdA: number, jdB: number, latA: number, lonEastA: number, latB: number, lonEastB: number): [number, number, number];
|
|
25
|
+
/** The nth-harmonic longitude of a point: lon * n, wrapped to 360. */
|
|
26
|
+
export declare function harmonicLongitude(lon: number, n: number): number;
|
|
27
|
+
export declare function harmonicChart(engine: Engine, jd: number, bodies: BodyId[], n: number, zodiac?: Zodiac): Record<string, number>;
|
|
28
|
+
/** Reflection across the solstice (Cancer-Capricorn) axis. */
|
|
29
|
+
export declare function antiscion(lon: number): number;
|
|
30
|
+
/** Reflection across the equinox (Aries-Libra) axis. */
|
|
31
|
+
export declare function contraAntiscion(lon: number): number;
|
|
32
|
+
export type DeclinationKind = "parallel" | "contraparallel" | null;
|
|
33
|
+
/** Classify two declinations: parallel (same), contraparallel (opposite), null. */
|
|
34
|
+
export declare function declinationAspect(decA: number, decB: number, orb?: number): DeclinationKind;
|
|
35
|
+
export interface DeclinationPair {
|
|
36
|
+
a: string;
|
|
37
|
+
b: string;
|
|
38
|
+
kind: DeclinationKind;
|
|
39
|
+
}
|
|
40
|
+
export declare function declinationAspects(engine: Engine, bodies: BodyId[], jd: number, orb?: number): DeclinationPair[];
|
|
41
|
+
/** |declination| minus the mean obliquity, degrees. Positive = out of bounds. */
|
|
42
|
+
export declare function outOfBoundsMargin(engine: Engine, body: BodyId, jd: number): number;
|
|
43
|
+
export declare function outOfBounds(engine: Engine, body: BodyId, jd: number): boolean;
|
|
44
|
+
/** Essential dignities of `body` in `sign`: domicile, exaltation, detriment,
|
|
45
|
+
* fall (the last two are the signs opposite domicile and exaltation). */
|
|
46
|
+
export declare function dignities(body: string, sign: number | string): string[];
|
|
47
|
+
export declare function dignityOf(engine: Engine, body: BodyId, jd: number, zodiac?: Zodiac): string[];
|
|
48
|
+
/** Diurnal when the Sun is above the horizon at the given place. */
|
|
49
|
+
export declare function isDayChart(engine: Engine, jd: number, lat: number, lonEast: number): boolean;
|
|
50
|
+
export declare function planetarySect(body: string): "diurnal" | "nocturnal" | null;
|
|
51
|
+
export declare function inSect(body: string, dayChart: boolean): boolean | null;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine derived -- standard chart derivations built on the validated
|
|
3
|
+
* primitives: returns, secondary progressions, solar arc directions, composite
|
|
4
|
+
* charts, Davison charts.
|
|
5
|
+
*
|
|
6
|
+
* These are constructions on top of apparent positions (already checked against
|
|
7
|
+
* Swiss Ephemeris), so this layer is time-mapping and arithmetic, not new
|
|
8
|
+
* ephemeris. Mirrors the Python reference (astroengine/derived.py); the
|
|
9
|
+
* golden fixtures pin the two together.
|
|
10
|
+
*/
|
|
11
|
+
import { mod, meanObliquity, jdTT, DEG } from "./core.js";
|
|
12
|
+
import { SIGNS } from "./chart.js";
|
|
13
|
+
import { crossings } from "./events.js";
|
|
14
|
+
import { azAlt } from "./pheno.js";
|
|
15
|
+
export const TROPICAL_YEAR = 365.24219; // mean tropical year, days
|
|
16
|
+
/** Shorter-arc midpoint of two longitudes (degrees). */
|
|
17
|
+
export function midpointLon(a, b) {
|
|
18
|
+
const d = mod(b - a + 180, 360) - 180; // signed shortest a -> b
|
|
19
|
+
return mod(a + d / 2, 360);
|
|
20
|
+
}
|
|
21
|
+
// ---------------------------------------------------------------- returns
|
|
22
|
+
/** UT JDs in [jdStart, jdEnd] when `body` returns to its natal longitude.
|
|
23
|
+
* Outer-planet returns can show three crossings around a retrograde loop. */
|
|
24
|
+
export function returns(engine, body, natalJd, jdStart, jdEnd, zodiac = "tropical", maxHits = 60) {
|
|
25
|
+
const natalLon = engine.longitude(body, natalJd, { zodiac });
|
|
26
|
+
return crossings(engine, body, natalLon, jdStart, jdEnd, zodiac, maxHits);
|
|
27
|
+
}
|
|
28
|
+
export function solarReturn(engine, natalJd, jdStart, jdEnd, zodiac = "tropical") {
|
|
29
|
+
return returns(engine, "sun", natalJd, jdStart, jdEnd, zodiac);
|
|
30
|
+
}
|
|
31
|
+
export function lunarReturn(engine, natalJd, jdStart, jdEnd, zodiac = "tropical") {
|
|
32
|
+
return returns(engine, "moon", natalJd, jdStart, jdEnd, zodiac);
|
|
33
|
+
}
|
|
34
|
+
// ----------------------------------------------- secondary progressions
|
|
35
|
+
/** The JD whose real positions are the secondary-progressed positions for the
|
|
36
|
+
* age (targetJd - natalJd): one day of motion per year of life. */
|
|
37
|
+
export function progressedJd(natalJd, targetJd, yearLength = TROPICAL_YEAR) {
|
|
38
|
+
return natalJd + (targetJd - natalJd) / yearLength;
|
|
39
|
+
}
|
|
40
|
+
export function progressedLongitude(engine, body, natalJd, targetJd, yearLength = TROPICAL_YEAR, zodiac = "tropical") {
|
|
41
|
+
return engine.longitude(body, progressedJd(natalJd, targetJd, yearLength), { zodiac });
|
|
42
|
+
}
|
|
43
|
+
// ----------------------------------------------------------- solar arc
|
|
44
|
+
/** Solar-arc direction angle (degrees, forward): how far the secondary-
|
|
45
|
+
* progressed Sun has moved from the natal Sun. Add it to any natal longitude. */
|
|
46
|
+
export function solarArc(engine, natalJd, targetJd, yearLength = TROPICAL_YEAR, zodiac = "tropical") {
|
|
47
|
+
const pjd = progressedJd(natalJd, targetJd, yearLength);
|
|
48
|
+
const natalSun = engine.longitude("sun", natalJd, { zodiac });
|
|
49
|
+
const progSun = engine.longitude("sun", pjd, { zodiac });
|
|
50
|
+
return mod(progSun - natalSun, 360); // Sun only moves forward
|
|
51
|
+
}
|
|
52
|
+
export function directedLongitude(engine, body, natalJd, targetJd, yearLength = TROPICAL_YEAR, zodiac = "tropical") {
|
|
53
|
+
const arc = solarArc(engine, natalJd, targetJd, yearLength, zodiac);
|
|
54
|
+
return mod(engine.longitude(body, natalJd, { zodiac }) + arc, 360);
|
|
55
|
+
}
|
|
56
|
+
// ----------------------------------------------------------- composite
|
|
57
|
+
/** Midpoint-method composite: the shorter-arc midpoint of each body's two
|
|
58
|
+
* longitudes. Angles compose the same way via midpointLon on the two ASC/MC. */
|
|
59
|
+
export function compositeLongitudes(engine, jdA, jdB, bodies, zodiac = "tropical") {
|
|
60
|
+
const out = {};
|
|
61
|
+
for (const body of bodies) {
|
|
62
|
+
const la = engine.longitude(body, jdA, { zodiac });
|
|
63
|
+
const lb = engine.longitude(body, jdB, { zodiac });
|
|
64
|
+
out[body] = midpointLon(la, lb);
|
|
65
|
+
}
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
// ----------------------------------------------------------- davison
|
|
69
|
+
/** Time and place for a Davison relationship chart: the temporal midpoint and
|
|
70
|
+
* the geographic midpoint (mean latitude, shorter-arc mean longitude). Compute
|
|
71
|
+
* a normal chart at these to get the Davison chart. Returns [jd, lat, lonEast]. */
|
|
72
|
+
export function davisonParams(jdA, jdB, latA, lonEastA, latB, lonEastB) {
|
|
73
|
+
const midJd = 0.5 * (jdA + jdB);
|
|
74
|
+
const midLat = 0.5 * (latA + latB);
|
|
75
|
+
let midLon = midpointLon(mod(lonEastA, 360), mod(lonEastB, 360));
|
|
76
|
+
if (midLon > 180)
|
|
77
|
+
midLon -= 360; // back to (-180, 180] east-longitude
|
|
78
|
+
return [midJd, midLat, midLon];
|
|
79
|
+
}
|
|
80
|
+
// ----------------------------------------------------------- harmonics
|
|
81
|
+
/** The nth-harmonic longitude of a point: lon * n, wrapped to 360. */
|
|
82
|
+
export function harmonicLongitude(lon, n) {
|
|
83
|
+
return mod(lon * n, 360);
|
|
84
|
+
}
|
|
85
|
+
export function harmonicChart(engine, jd, bodies, n, zodiac = "tropical") {
|
|
86
|
+
const out = {};
|
|
87
|
+
for (const b of bodies)
|
|
88
|
+
out[b] = harmonicLongitude(engine.longitude(b, jd, { zodiac }), n);
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
// ----------------------------------------------------------- antiscia
|
|
92
|
+
/** Reflection across the solstice (Cancer-Capricorn) axis. */
|
|
93
|
+
export function antiscion(lon) {
|
|
94
|
+
return mod(180 - lon, 360);
|
|
95
|
+
}
|
|
96
|
+
/** Reflection across the equinox (Aries-Libra) axis. */
|
|
97
|
+
export function contraAntiscion(lon) {
|
|
98
|
+
return mod(-lon, 360);
|
|
99
|
+
}
|
|
100
|
+
/** Classify two declinations: parallel (same), contraparallel (opposite), null. */
|
|
101
|
+
export function declinationAspect(decA, decB, orb = 1.0) {
|
|
102
|
+
if (Math.abs(decA - decB) <= orb)
|
|
103
|
+
return "parallel";
|
|
104
|
+
if (Math.abs(decA + decB) <= orb)
|
|
105
|
+
return "contraparallel";
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
export function declinationAspects(engine, bodies, jd, orb = 1.0) {
|
|
109
|
+
const decs = {};
|
|
110
|
+
for (const b of bodies)
|
|
111
|
+
decs[b] = engine.position(b, jd).dec;
|
|
112
|
+
const out = [];
|
|
113
|
+
for (let i = 0; i < bodies.length; i++) {
|
|
114
|
+
for (let j = i + 1; j < bodies.length; j++) {
|
|
115
|
+
const kind = declinationAspect(decs[bodies[i]], decs[bodies[j]], orb);
|
|
116
|
+
if (kind)
|
|
117
|
+
out.push({ a: bodies[i], b: bodies[j], kind });
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
// ----------------------------------------------------------- out of bounds
|
|
123
|
+
/** |declination| minus the mean obliquity, degrees. Positive = out of bounds. */
|
|
124
|
+
export function outOfBoundsMargin(engine, body, jd) {
|
|
125
|
+
const dec = engine.position(body, jd).dec;
|
|
126
|
+
const eps = meanObliquity(jdTT(jd)) / DEG;
|
|
127
|
+
return Math.abs(dec) - eps;
|
|
128
|
+
}
|
|
129
|
+
export function outOfBounds(engine, body, jd) {
|
|
130
|
+
return outOfBoundsMargin(engine, body, jd) > 0;
|
|
131
|
+
}
|
|
132
|
+
// ----------------------------------------------------------- dignities
|
|
133
|
+
const DOMICILE = {
|
|
134
|
+
sun: [4], moon: [3], mercury: [2, 5], venus: [1, 6],
|
|
135
|
+
mars: [0, 7], jupiter: [8, 11], saturn: [9, 10],
|
|
136
|
+
};
|
|
137
|
+
const EXALTATION = {
|
|
138
|
+
sun: 0, moon: 1, mercury: 5, venus: 11, mars: 9, jupiter: 3, saturn: 6,
|
|
139
|
+
};
|
|
140
|
+
function signIndex(sign) {
|
|
141
|
+
return typeof sign === "number" ? sign : SIGNS.indexOf(sign);
|
|
142
|
+
}
|
|
143
|
+
/** Essential dignities of `body` in `sign`: domicile, exaltation, detriment,
|
|
144
|
+
* fall (the last two are the signs opposite domicile and exaltation). */
|
|
145
|
+
export function dignities(body, sign) {
|
|
146
|
+
const idx = signIndex(sign);
|
|
147
|
+
const dom = DOMICILE[body] ?? [];
|
|
148
|
+
const out = [];
|
|
149
|
+
if (dom.includes(idx))
|
|
150
|
+
out.push("domicile");
|
|
151
|
+
if (EXALTATION[body] === idx)
|
|
152
|
+
out.push("exaltation");
|
|
153
|
+
if (dom.map((d) => mod(d + 6, 12)).includes(idx))
|
|
154
|
+
out.push("detriment");
|
|
155
|
+
if (body in EXALTATION && mod(EXALTATION[body] + 6, 12) === idx)
|
|
156
|
+
out.push("fall");
|
|
157
|
+
return out;
|
|
158
|
+
}
|
|
159
|
+
export function dignityOf(engine, body, jd, zodiac = "tropical") {
|
|
160
|
+
const lon = engine.longitude(body, jd, { zodiac });
|
|
161
|
+
return dignities(body, mod(Math.floor(lon / 30), 12));
|
|
162
|
+
}
|
|
163
|
+
// ----------------------------------------------------------- sect
|
|
164
|
+
const DIURNAL = new Set(["sun", "jupiter", "saturn"]);
|
|
165
|
+
const NOCTURNAL = new Set(["moon", "venus", "mars"]);
|
|
166
|
+
/** Diurnal when the Sun is above the horizon at the given place. */
|
|
167
|
+
export function isDayChart(engine, jd, lat, lonEast) {
|
|
168
|
+
const sun = engine.position("sun", jd);
|
|
169
|
+
const [, alt] = azAlt(engine.data, sun.lon, sun.lat, jd, lat, lonEast);
|
|
170
|
+
return alt > 0;
|
|
171
|
+
}
|
|
172
|
+
export function planetarySect(body) {
|
|
173
|
+
if (DIURNAL.has(body))
|
|
174
|
+
return "diurnal";
|
|
175
|
+
if (NOCTURNAL.has(body))
|
|
176
|
+
return "nocturnal";
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
export function inSect(body, dayChart) {
|
|
180
|
+
const s = planetarySect(body);
|
|
181
|
+
if (s === null)
|
|
182
|
+
return null;
|
|
183
|
+
return (s === "diurnal") === Boolean(dayChart);
|
|
184
|
+
}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Engine, BodyId, Zodiac } from "./chart.js";
|
|
2
|
+
export declare const QUERY_ASPECTS: Record<string, number>;
|
|
3
|
+
export type Interval = [number, number];
|
|
4
|
+
/** Margin function (true where >= 0) carrying the bodies it depends on. */
|
|
5
|
+
export interface Predicate {
|
|
6
|
+
(engine: Engine, t: number): number;
|
|
7
|
+
bodies: Set<string>;
|
|
8
|
+
}
|
|
9
|
+
/** True while `body` is within `orb` deg of an exact `kind` aspect to
|
|
10
|
+
* `target` -- a fixed ecliptic longitude (deg) or another body name. */
|
|
11
|
+
export declare function aspect(body: BodyId, kind: string, target: number | BodyId, orb?: number, zodiac?: Zodiac): Predicate;
|
|
12
|
+
/** True while `body` is in `sign` (index 0=Aries..11=Pisces, or name). */
|
|
13
|
+
export declare function inSign(body: BodyId, sign: number | string, zodiac?: Zodiac): Predicate;
|
|
14
|
+
/** True while `body` is in apparent retrograde motion. */
|
|
15
|
+
export declare function retrograde(body: BodyId, zodiac?: Zodiac): Predicate;
|
|
16
|
+
/** True while `body` is direct or stationary. */
|
|
17
|
+
export declare function notRetrograde(body: BodyId, zodiac?: Zodiac): Predicate;
|
|
18
|
+
/** True where every predicate is true (interval intersection). */
|
|
19
|
+
export declare function allOf(...preds: Predicate[]): Predicate;
|
|
20
|
+
/** True where any predicate is true (interval union). */
|
|
21
|
+
export declare function anyOf(...preds: Predicate[]): Predicate;
|
|
22
|
+
/** True where `pred` is false (interval complement). */
|
|
23
|
+
export declare function notOf(pred: Predicate): Predicate;
|
|
24
|
+
export interface WhenOptions {
|
|
25
|
+
step?: number;
|
|
26
|
+
maxIntervals?: number;
|
|
27
|
+
}
|
|
28
|
+
/** Time intervals (jdStartUt, jdEndUt) in [jdStart, jdEnd] where `predicate`
|
|
29
|
+
* is true. Endpoints touching the range bounds are clamped. The scan step
|
|
30
|
+
* defaults to 0.125 d when a fast body (Moon, nodes, Lilith) is involved
|
|
31
|
+
* and 1 d otherwise. */
|
|
32
|
+
export declare function when(engine: Engine, predicate: Predicate, jdStart: number, jdEnd: number, opts?: WhenOptions): Interval[];
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine query -- declarative time queries ("when is ...?").
|
|
3
|
+
*
|
|
4
|
+
* The engine answers "where is the body?"; this answers "when is the
|
|
5
|
+
* configuration true?" over a time range. A predicate is a continuous
|
|
6
|
+
* "margin" function, true exactly where margin >= 0 (e.g. aspect-within-orb
|
|
7
|
+
* -> orb minus angular distance from exact). A boolean combination is then
|
|
8
|
+
* itself a margin -- AND = min of the parts, OR = max, NOT = negation -- so
|
|
9
|
+
* any query reduces to one continuous function and `when()` returns the
|
|
10
|
+
* intervals where it is true using the same coarse-scan-then-bisect root
|
|
11
|
+
* finder as events.crossings.
|
|
12
|
+
*
|
|
13
|
+
* when(engine, allOf(aspect("saturn", "square", natalMoon),
|
|
14
|
+
* notRetrograde("mercury"),
|
|
15
|
+
* inSign("venus", "Taurus")), jdStart, jdEnd)
|
|
16
|
+
*
|
|
17
|
+
* Mirrors the Python reference (astroengine/query.py); the golden fixtures
|
|
18
|
+
* pin the two implementations together.
|
|
19
|
+
*/
|
|
20
|
+
import { mod } from "./core.js";
|
|
21
|
+
import { SIGNS } from "./chart.js";
|
|
22
|
+
export const QUERY_ASPECTS = {
|
|
23
|
+
conjunction: 0, semisextile: 30, sextile: 60, square: 90,
|
|
24
|
+
trine: 120, quincunx: 150, opposition: 180,
|
|
25
|
+
};
|
|
26
|
+
const FAST = new Set([
|
|
27
|
+
"moon", "mean_node", "true_node", "mean_lilith", "true_lilith",
|
|
28
|
+
]);
|
|
29
|
+
function wrap180(d) {
|
|
30
|
+
return mod(d + 180, 360) - 180;
|
|
31
|
+
}
|
|
32
|
+
function mk(fn, bodies) {
|
|
33
|
+
const p = fn;
|
|
34
|
+
p.bodies = bodies;
|
|
35
|
+
return p;
|
|
36
|
+
}
|
|
37
|
+
// ---------------------------------------------------------------- predicates
|
|
38
|
+
/** True while `body` is within `orb` deg of an exact `kind` aspect to
|
|
39
|
+
* `target` -- a fixed ecliptic longitude (deg) or another body name. */
|
|
40
|
+
export function aspect(body, kind, target, orb = 1.0, zodiac = "tropical") {
|
|
41
|
+
const ang = QUERY_ASPECTS[kind];
|
|
42
|
+
if (ang === undefined)
|
|
43
|
+
throw new Error(`unknown aspect ${kind}`);
|
|
44
|
+
const isLon = typeof target === "number";
|
|
45
|
+
const bodies = new Set([body]);
|
|
46
|
+
if (!isLon)
|
|
47
|
+
bodies.add(target);
|
|
48
|
+
return mk((engine, t) => {
|
|
49
|
+
const lon = engine.longitude(body, t, { zodiac });
|
|
50
|
+
const tl = isLon
|
|
51
|
+
? target
|
|
52
|
+
: engine.longitude(target, t, { zodiac });
|
|
53
|
+
const sep = lon - tl;
|
|
54
|
+
return orb - Math.min(Math.abs(wrap180(sep - ang)), Math.abs(wrap180(sep + ang)));
|
|
55
|
+
}, bodies);
|
|
56
|
+
}
|
|
57
|
+
/** True while `body` is in `sign` (index 0=Aries..11=Pisces, or name). */
|
|
58
|
+
export function inSign(body, sign, zodiac = "tropical") {
|
|
59
|
+
const idx = typeof sign === "number" ? sign : SIGNS.indexOf(sign);
|
|
60
|
+
if (idx < 0)
|
|
61
|
+
throw new Error(`unknown sign ${sign}`);
|
|
62
|
+
const lo = idx * 30;
|
|
63
|
+
return mk((engine, t) => {
|
|
64
|
+
const d = mod(engine.longitude(body, t, { zodiac }) - lo, 360);
|
|
65
|
+
// signed distance to the nearest 30-deg band edge, positive inside
|
|
66
|
+
return d <= 30 ? Math.min(d, 30 - d) : -Math.min(d - 30, 360 - d);
|
|
67
|
+
}, new Set([body]));
|
|
68
|
+
}
|
|
69
|
+
/** True while `body` is in apparent retrograde motion. */
|
|
70
|
+
export function retrograde(body, zodiac = "tropical") {
|
|
71
|
+
const h = 0.25;
|
|
72
|
+
return mk((engine, t) => {
|
|
73
|
+
const l0 = engine.longitude(body, t - h, { zodiac });
|
|
74
|
+
const l1 = engine.longitude(body, t + h, { zodiac });
|
|
75
|
+
return -wrap180(l1 - l0) / (2 * h); // >= 0 when moving backwards
|
|
76
|
+
}, new Set([body]));
|
|
77
|
+
}
|
|
78
|
+
/** True while `body` is direct or stationary. */
|
|
79
|
+
export function notRetrograde(body, zodiac = "tropical") {
|
|
80
|
+
return notOf(retrograde(body, zodiac));
|
|
81
|
+
}
|
|
82
|
+
// --------------------------------------------------------------- combinators
|
|
83
|
+
function combine(op, preds) {
|
|
84
|
+
const bodies = new Set();
|
|
85
|
+
for (const p of preds)
|
|
86
|
+
for (const b of p.bodies)
|
|
87
|
+
bodies.add(b);
|
|
88
|
+
return mk((engine, t) => op(preds.map((p) => p(engine, t))), bodies);
|
|
89
|
+
}
|
|
90
|
+
/** True where every predicate is true (interval intersection). */
|
|
91
|
+
export function allOf(...preds) {
|
|
92
|
+
return combine((xs) => Math.min(...xs), preds);
|
|
93
|
+
}
|
|
94
|
+
/** True where any predicate is true (interval union). */
|
|
95
|
+
export function anyOf(...preds) {
|
|
96
|
+
return combine((xs) => Math.max(...xs), preds);
|
|
97
|
+
}
|
|
98
|
+
/** True where `pred` is false (interval complement). */
|
|
99
|
+
export function notOf(pred) {
|
|
100
|
+
return mk((engine, t) => -pred(engine, t), new Set(pred.bodies));
|
|
101
|
+
}
|
|
102
|
+
// --------------------------------------------------------------- solver
|
|
103
|
+
function bisect(f, a, b, tol = 1e-6) {
|
|
104
|
+
let fa = f(a);
|
|
105
|
+
for (let i = 0; i < 60; i++) {
|
|
106
|
+
const m = 0.5 * (a + b);
|
|
107
|
+
if (Math.abs(b - a) < tol)
|
|
108
|
+
return m;
|
|
109
|
+
const fm = f(m);
|
|
110
|
+
if ((fa < 0) !== (fm < 0)) {
|
|
111
|
+
b = m;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
a = m;
|
|
115
|
+
fa = fm;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return 0.5 * (a + b);
|
|
119
|
+
}
|
|
120
|
+
/** Time intervals (jdStartUt, jdEndUt) in [jdStart, jdEnd] where `predicate`
|
|
121
|
+
* is true. Endpoints touching the range bounds are clamped. The scan step
|
|
122
|
+
* defaults to 0.125 d when a fast body (Moon, nodes, Lilith) is involved
|
|
123
|
+
* and 1 d otherwise. */
|
|
124
|
+
export function when(engine, predicate, jdStart, jdEnd, opts = {}) {
|
|
125
|
+
let step = opts.step;
|
|
126
|
+
if (step === undefined) {
|
|
127
|
+
let fast = false;
|
|
128
|
+
for (const b of predicate.bodies)
|
|
129
|
+
if (FAST.has(b))
|
|
130
|
+
fast = true;
|
|
131
|
+
step = fast ? 0.125 : 1.0;
|
|
132
|
+
}
|
|
133
|
+
const maxIntervals = opts.maxIntervals ?? 500;
|
|
134
|
+
const f = (t) => predicate(engine, t);
|
|
135
|
+
const intervals = [];
|
|
136
|
+
let prev = f(jdStart);
|
|
137
|
+
let openStart = prev >= 0 ? jdStart : null;
|
|
138
|
+
let t = jdStart + step;
|
|
139
|
+
while (t <= jdEnd + 1e-9 && intervals.length < maxIntervals) {
|
|
140
|
+
if (t > jdEnd)
|
|
141
|
+
t = jdEnd;
|
|
142
|
+
const cur = f(t);
|
|
143
|
+
if ((prev < 0) !== (cur < 0)) {
|
|
144
|
+
const edge = bisect(f, t - step, t);
|
|
145
|
+
if (cur >= 0) {
|
|
146
|
+
openStart = edge;
|
|
147
|
+
}
|
|
148
|
+
else if (openStart !== null) {
|
|
149
|
+
intervals.push([openStart, edge]);
|
|
150
|
+
openStart = null;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
prev = cur;
|
|
154
|
+
if (t >= jdEnd)
|
|
155
|
+
break;
|
|
156
|
+
t += step;
|
|
157
|
+
}
|
|
158
|
+
if (openStart !== null)
|
|
159
|
+
intervals.push([openStart, jdEnd]);
|
|
160
|
+
return intervals;
|
|
161
|
+
}
|
package/dist/src/stars.d.ts
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
* catalog (data/fixed_stars.json; ICRS J2000 with proper motions).
|
|
4
4
|
*
|
|
5
5
|
* Chain: full 3D space motion (proper motion + radial velocity at the
|
|
6
|
-
* parallax distance) -> ICRS equatorial -> ecliptic J2000 ->
|
|
6
|
+
* parallax distance) -> ICRS equatorial -> ecliptic J2000 -> Vondrak 2011
|
|
7
7
|
* precession to date -> annual aberration (classic elliptic form, as for
|
|
8
8
|
* Pluto/Chiron) -> nutation. Validated against swe_fixstar fed the same
|
|
9
|
-
* catalog rows: <=0.
|
|
10
|
-
* Vondrak precession difference, shared with the rest of the engine).
|
|
9
|
+
* catalog rows: <=0.3 arcsec over 1900-2099.
|
|
11
10
|
*/
|
|
12
11
|
import { EngineData } from "./core.js";
|
|
13
12
|
export interface StarEntry {
|
package/dist/src/stars.js
CHANGED
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
* catalog (data/fixed_stars.json; ICRS J2000 with proper motions).
|
|
4
4
|
*
|
|
5
5
|
* Chain: full 3D space motion (proper motion + radial velocity at the
|
|
6
|
-
* parallax distance) -> ICRS equatorial -> ecliptic J2000 ->
|
|
6
|
+
* parallax distance) -> ICRS equatorial -> ecliptic J2000 -> Vondrak 2011
|
|
7
7
|
* precession to date -> annual aberration (classic elliptic form, as for
|
|
8
8
|
* Pluto/Chiron) -> nutation. Validated against swe_fixstar fed the same
|
|
9
|
-
* catalog rows: <=0.
|
|
10
|
-
* Vondrak precession difference, shared with the rest of the engine).
|
|
9
|
+
* catalog rows: <=0.3 arcsec over 1900-2099.
|
|
11
10
|
*/
|
|
12
11
|
import { DEG, ARCSEC, J2000, mod, nutation, precessEcliptic, vsopHeliocentric, } from "./core.js";
|
|
13
12
|
const TWO_PI = 2 * Math.PI;
|