caelus 0.9.0 → 0.10.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/astrocartography.d.ts +16 -0
- package/dist/src/astrocartography.js +47 -0
- package/dist/src/ephemeris.d.ts +27 -0
- package/dist/src/ephemeris.js +30 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +3 -0
- package/dist/src/spherical.d.ts +8 -0
- package/dist/src/spherical.js +28 -0
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Engine, BodyId } from "./chart.js";
|
|
2
|
+
export interface AngleLines {
|
|
3
|
+
/** MC meridian longitude (culmination). */
|
|
4
|
+
mc: number;
|
|
5
|
+
/** IC meridian longitude (anti-culmination). */
|
|
6
|
+
ic: number;
|
|
7
|
+
/** Rising track, [lon, lat] points over the latitude band. */
|
|
8
|
+
asc: [number, number][];
|
|
9
|
+
/** Setting track, [lon, lat] points. */
|
|
10
|
+
dsc: [number, number][];
|
|
11
|
+
}
|
|
12
|
+
/** Angle lines for one body at right ascension/declination (degrees) and a
|
|
13
|
+
* Greenwich apparent sidereal time (degrees). */
|
|
14
|
+
export declare function planetLines(ra: number, dec: number, gastDeg: number, latMin?: number, latMax?: number, latStep?: number): AngleLines;
|
|
15
|
+
/** Angle lines for each body at jdUt: { body: AngleLines }. */
|
|
16
|
+
export declare function astrocartography(engine: Engine, jdUt: number, bodies: BodyId[], latMin?: number, latMax?: number, latStep?: number): Record<string, AngleLines>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine astrocartography -- planetary angle lines across the globe.
|
|
3
|
+
*
|
|
4
|
+
* For one moment, each planet is exactly on an angle along a curve on the
|
|
5
|
+
* Earth's surface: MC and IC are meridians (culmination / anti-culmination),
|
|
6
|
+
* ASC and DSC are the curved rising / setting tracks. Geometry from each body's
|
|
7
|
+
* right ascension and declination and the moment's Greenwich apparent sidereal
|
|
8
|
+
* time. Mirrors the Python reference (astroengine/astrocartography.py); the
|
|
9
|
+
* golden pins the two.
|
|
10
|
+
*/
|
|
11
|
+
import { DEG } from "./core.js";
|
|
12
|
+
import { gast } from "./houses.js";
|
|
13
|
+
/** Wrap a longitude to (-180, 180], east positive. */
|
|
14
|
+
function mapLon(deg) {
|
|
15
|
+
const d = ((deg % 360) + 360) % 360;
|
|
16
|
+
return d > 180 ? d - 360 : d;
|
|
17
|
+
}
|
|
18
|
+
/** Angle lines for one body at right ascension/declination (degrees) and a
|
|
19
|
+
* Greenwich apparent sidereal time (degrees). */
|
|
20
|
+
export function planetLines(ra, dec, gastDeg, latMin = -85.0, latMax = 85.0, latStep = 1.0) {
|
|
21
|
+
const mc = mapLon(ra - gastDeg);
|
|
22
|
+
const ic = mapLon(ra - gastDeg - 180.0);
|
|
23
|
+
const td = Math.tan(dec * DEG);
|
|
24
|
+
const asc = [];
|
|
25
|
+
const dsc = [];
|
|
26
|
+
const n = Math.floor((latMax - latMin) / latStep + 1e-9); // never exceed latMax
|
|
27
|
+
for (let i = 0; i <= n; i++) {
|
|
28
|
+
const phi = latMin + i * latStep;
|
|
29
|
+
const x = -Math.tan(phi * DEG) * td;
|
|
30
|
+
if (x >= -1.0 && x <= 1.0) {
|
|
31
|
+
const h0 = Math.acos(x) / DEG; // hour-angle half-width, degrees
|
|
32
|
+
asc.push([mapLon(ra - h0 - gastDeg), phi]); // eastern horizon
|
|
33
|
+
dsc.push([mapLon(ra + h0 - gastDeg), phi]); // western horizon
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { mc, ic, asc, dsc };
|
|
37
|
+
}
|
|
38
|
+
/** Angle lines for each body at jdUt: { body: AngleLines }. */
|
|
39
|
+
export function astrocartography(engine, jdUt, bodies, latMin = -85.0, latMax = 85.0, latStep = 1.0) {
|
|
40
|
+
const g = gast(engine.data, jdUt) / DEG; // Greenwich apparent sidereal time, deg
|
|
41
|
+
const out = {};
|
|
42
|
+
for (const b of bodies) {
|
|
43
|
+
const p = engine.position(b, jdUt);
|
|
44
|
+
out[b] = planetLines(p.ra, p.dec, g, latMin, latMax, latStep);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine ephemeris -- a time series of one value per body over a range, the
|
|
3
|
+
* data behind a graphic ephemeris. A thin collector over the validated
|
|
4
|
+
* positions (longitude, latitude, declination, right ascension, or speed), so
|
|
5
|
+
* there is no new math here; the underlying values are the ones the conformance
|
|
6
|
+
* suite already pins. Pair it with caelus-wheel's EphemerisGraph to draw it.
|
|
7
|
+
*/
|
|
8
|
+
import { Engine, BodyId, Zodiac } from "./chart.js";
|
|
9
|
+
export type EphemerisValue = "longitude" | "latitude" | "declination" | "rightAscension" | "speed";
|
|
10
|
+
export interface EphemerisOptions {
|
|
11
|
+
/** First instant, UT Julian Day (inclusive). */
|
|
12
|
+
start: number;
|
|
13
|
+
/** Last instant, UT Julian Day (inclusive). */
|
|
14
|
+
end: number;
|
|
15
|
+
/** Spacing between samples, days. Must be positive. */
|
|
16
|
+
step: number;
|
|
17
|
+
/** Which quantity to sample (default longitude). */
|
|
18
|
+
value?: EphemerisValue;
|
|
19
|
+
zodiac?: Zodiac;
|
|
20
|
+
}
|
|
21
|
+
export interface EphemerisPoint {
|
|
22
|
+
jd: number;
|
|
23
|
+
value: number;
|
|
24
|
+
}
|
|
25
|
+
/** Sample `value` for each body across [start, end], returning per-body series
|
|
26
|
+
* in time order. */
|
|
27
|
+
export declare function ephemeris(engine: Engine, bodies: BodyId[], opts: EphemerisOptions): Record<string, EphemerisPoint[]>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Sample `value` for each body across [start, end], returning per-body series
|
|
2
|
+
* in time order. */
|
|
3
|
+
export function ephemeris(engine, bodies, opts) {
|
|
4
|
+
if (opts.step <= 0)
|
|
5
|
+
throw new Error("ephemeris step must be positive");
|
|
6
|
+
const value = opts.value ?? "longitude";
|
|
7
|
+
const zodiac = opts.zodiac ?? "tropical";
|
|
8
|
+
const out = {};
|
|
9
|
+
for (const b of bodies)
|
|
10
|
+
out[b] = [];
|
|
11
|
+
const total = Math.floor((opts.end - opts.start) / opts.step + 1e-9) + 1;
|
|
12
|
+
for (let i = 0; i < total; i++) {
|
|
13
|
+
const jd = opts.start + i * opts.step;
|
|
14
|
+
for (const b of bodies) {
|
|
15
|
+
let v;
|
|
16
|
+
if (value === "longitude") {
|
|
17
|
+
v = engine.longitude(b, jd, { zodiac });
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
const p = engine.position(b, jd, { zodiac });
|
|
21
|
+
v = value === "latitude" ? p.lat
|
|
22
|
+
: value === "declination" ? p.dec
|
|
23
|
+
: value === "rightAscension" ? p.ra
|
|
24
|
+
: p.speed;
|
|
25
|
+
}
|
|
26
|
+
out[b].push({ jd, value: v });
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|
package/dist/src/index.d.ts
CHANGED
package/dist/src/index.js
CHANGED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type Vec3 = [number, number, number];
|
|
2
|
+
/** Unit vector on the sphere for an (ecliptic longitude, latitude) pair, in the
|
|
3
|
+
* ecliptic frame: x toward 0 Aries, z toward the north ecliptic pole. */
|
|
4
|
+
export declare function unitVector(lonDeg: number, latDeg: number): Vec3;
|
|
5
|
+
/** True great-circle angle (degrees) between two bodies from their ecliptic
|
|
6
|
+
* longitude and latitude. With both latitudes zero this is the unsigned
|
|
7
|
+
* longitude difference; latitude pulls the two apart in three dimensions. */
|
|
8
|
+
export declare function angularSeparation3d(lonA: number, latA: number, lonB: number, latB: number): number;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* astroengine spherical -- spherical-geometry primitives for 3D chart views.
|
|
3
|
+
*
|
|
4
|
+
* A body sits at a point on the celestial sphere, not just a zodiac longitude.
|
|
5
|
+
* `unitVector` gives the direction for an (ecliptic longitude, latitude) pair;
|
|
6
|
+
* `angularSeparation3d` gives the true great-circle angle between two bodies,
|
|
7
|
+
* which is the basis for 3D aspects (the separation in space, accounting for
|
|
8
|
+
* ecliptic latitude, rather than the 2D longitude difference). Mirrors the
|
|
9
|
+
* Python reference (astroengine/spherical.py); the golden pins the two.
|
|
10
|
+
*/
|
|
11
|
+
import { DEG } from "./core.js";
|
|
12
|
+
/** Unit vector on the sphere for an (ecliptic longitude, latitude) pair, in the
|
|
13
|
+
* ecliptic frame: x toward 0 Aries, z toward the north ecliptic pole. */
|
|
14
|
+
export function unitVector(lonDeg, latDeg) {
|
|
15
|
+
const lam = lonDeg * DEG;
|
|
16
|
+
const beta = latDeg * DEG;
|
|
17
|
+
const cb = Math.cos(beta);
|
|
18
|
+
return [cb * Math.cos(lam), cb * Math.sin(lam), Math.sin(beta)];
|
|
19
|
+
}
|
|
20
|
+
/** True great-circle angle (degrees) between two bodies from their ecliptic
|
|
21
|
+
* longitude and latitude. With both latitudes zero this is the unsigned
|
|
22
|
+
* longitude difference; latitude pulls the two apart in three dimensions. */
|
|
23
|
+
export function angularSeparation3d(lonA, latA, lonB, latB) {
|
|
24
|
+
const [ax, ay, az] = unitVector(lonA, latA);
|
|
25
|
+
const [bx, by, bz] = unitVector(lonB, latB);
|
|
26
|
+
const dot = Math.max(-1, Math.min(1, ax * bx + ay * by + az * bz));
|
|
27
|
+
return Math.acos(dot) / DEG;
|
|
28
|
+
}
|