caelus 0.16.0 → 0.17.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.
@@ -25,3 +25,31 @@ export interface Paran {
25
25
  * @returns The co-angular pairs as {@link Paran} objects.
26
26
  */
27
27
  export declare function parans(engine: Engine, jd: number, lat: number, bodies?: string[], toleranceMin?: number): Paran[];
28
+ /**
29
+ * The four angle crossings of a fixed `star` over the day from `jd` at latitude
30
+ * `lat`: the meridian transits always occur; `rise`/`set` are absent when the
31
+ * star is circumpolar or never rises.
32
+ */
33
+ export declare function starAngleTimes(engine: Engine, star: string, jd: number, lat: number): Record<string, number>;
34
+ /** One star-to-body paran: a fixed star and a body on angles at ~the same time. */
35
+ export interface StarParan {
36
+ star: string;
37
+ star_angle: string;
38
+ body: string;
39
+ body_angle: string;
40
+ jd: number;
41
+ gap_min: number;
42
+ }
43
+ /**
44
+ * Star-to-body parans over the day from `jd` (UT) at latitude `lat`: a fixed
45
+ * star and a moving body simultaneously on angles within `toleranceMin`
46
+ * minutes — Brady's fixed-star parans. Ordered by (star, body, jd).
47
+ *
48
+ * @param engine An engine whose data pack includes the fixed-star catalog.
49
+ * @param jd Julian Day in UT (the 24-hour window starts here).
50
+ * @param lat Geographic latitude in degrees, north positive.
51
+ * @param stars Catalog star names to test (see {@link Engine.starNames}).
52
+ * @param bodies Bodies to consider; defaults to the seven classical planets.
53
+ * @param toleranceMin The paran window in minutes (default 30).
54
+ */
55
+ export declare function starParans(engine: Engine, jd: number, lat: number, stars: string[], bodies?: string[], toleranceMin?: number): StarParan[];
@@ -13,8 +13,15 @@
13
13
  * `parans-golden`.
14
14
  */
15
15
  import { riseSet } from "./events.js";
16
+ import { gast } from "./houses.js";
17
+ import { DEG, mod } from "./core.js";
16
18
  export const PARAN_ANGLES = ["rise", "mtransit", "set", "itransit"];
17
19
  export const DEFAULT_PARAN_BODIES = ["sun", "moon", "mercury", "venus", "mars", "jupiter", "saturn"];
20
+ const TWO_PI = 2 * Math.PI;
21
+ // Local sidereal time advances one turn per sidereal day.
22
+ const SID_RATE = 360.98564736629 * DEG;
23
+ // Standard rise/set: the geometric horizon lifted by ~34' of refraction.
24
+ const RISE_ALT = -0.5667 * DEG;
18
25
  /**
19
26
  * Co-angular pairs over the 24 hours from `jd` (UT) at latitude `lat`: every
20
27
  * pair of different bodies whose angle crossings fall within `toleranceMin`
@@ -57,3 +64,80 @@ export function parans(engine, jd, lat, bodies = DEFAULT_PARAN_BODIES, tolerance
57
64
  out.sort((x, y) => (x.a < y.a ? -1 : x.a > y.a ? 1 : x.b < y.b ? -1 : x.b > y.b ? 1 : x.jd - y.jd));
58
65
  return out;
59
66
  }
67
+ /** The UT instant in `[jd, jd+1)` when apparent sidereal time = `target` (rad). */
68
+ function timeAtLst(engine, jd, target) {
69
+ const dlst = mod(target - gast(engine.data, jd), TWO_PI);
70
+ let t = jd + dlst / SID_RATE;
71
+ for (let i = 0; i < 2; i++) {
72
+ const err = mod(gast(engine.data, t) - target + Math.PI, TWO_PI) - Math.PI;
73
+ t -= err / SID_RATE;
74
+ }
75
+ return t;
76
+ }
77
+ /**
78
+ * The four angle crossings of a fixed `star` over the day from `jd` at latitude
79
+ * `lat`: the meridian transits always occur; `rise`/`set` are absent when the
80
+ * star is circumpolar or never rises.
81
+ */
82
+ export function starAngleTimes(engine, star, jd, lat) {
83
+ const fs = engine.fixedStar(star, jd);
84
+ const alpha = mod(fs.ra * DEG, TWO_PI);
85
+ const delta = fs.dec * DEG;
86
+ const phi = lat * DEG;
87
+ const out = {
88
+ mtransit: timeAtLst(engine, jd, alpha),
89
+ itransit: timeAtLst(engine, jd, mod(alpha + Math.PI, TWO_PI)),
90
+ };
91
+ const denom = Math.cos(phi) * Math.cos(delta);
92
+ if (denom !== 0) {
93
+ const cosH0 = (Math.sin(RISE_ALT) - Math.sin(phi) * Math.sin(delta)) / denom;
94
+ if (cosH0 >= -1 && cosH0 <= 1) {
95
+ const h0 = Math.acos(cosH0);
96
+ out.rise = timeAtLst(engine, jd, mod(alpha - h0, TWO_PI));
97
+ out.set = timeAtLst(engine, jd, mod(alpha + h0, TWO_PI));
98
+ }
99
+ }
100
+ return out;
101
+ }
102
+ /**
103
+ * Star-to-body parans over the day from `jd` (UT) at latitude `lat`: a fixed
104
+ * star and a moving body simultaneously on angles within `toleranceMin`
105
+ * minutes — Brady's fixed-star parans. Ordered by (star, body, jd).
106
+ *
107
+ * @param engine An engine whose data pack includes the fixed-star catalog.
108
+ * @param jd Julian Day in UT (the 24-hour window starts here).
109
+ * @param lat Geographic latitude in degrees, north positive.
110
+ * @param stars Catalog star names to test (see {@link Engine.starNames}).
111
+ * @param bodies Bodies to consider; defaults to the seven classical planets.
112
+ * @param toleranceMin The paran window in minutes (default 30).
113
+ */
114
+ export function starParans(engine, jd, lat, stars, bodies = DEFAULT_PARAN_BODIES, toleranceMin = 30) {
115
+ const bodyEvents = [];
116
+ for (const b of bodies) {
117
+ for (const kind of PARAN_ANGLES) {
118
+ const t = riseSet(engine, b, jd, lat, 0, kind);
119
+ if (t !== null && t < jd + 1)
120
+ bodyEvents.push([b, kind, t]);
121
+ }
122
+ }
123
+ const out = [];
124
+ for (const s of stars) {
125
+ const at = starAngleTimes(engine, s, jd, lat);
126
+ for (const [sa, ts] of Object.entries(at)) {
127
+ if (!(ts >= jd && ts < jd + 1))
128
+ continue;
129
+ for (const [b, ba, tb] of bodyEvents) {
130
+ const gap = Math.abs(ts - tb) * 1440;
131
+ if (gap <= toleranceMin) {
132
+ out.push({
133
+ star: s, star_angle: sa, body: b, body_angle: ba,
134
+ jd: Math.round(((ts + tb) / 2) * 1e6) / 1e6,
135
+ gap_min: Math.round(gap * 1e4) / 1e4,
136
+ });
137
+ }
138
+ }
139
+ }
140
+ }
141
+ out.sort((x, y) => (x.star < y.star ? -1 : x.star > y.star ? 1 : x.body < y.body ? -1 : x.body > y.body ? 1 : x.jd - y.jd));
142
+ return out;
143
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "caelus",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "Astrological ephemeris engine. MIT, no AGPL, no ephemeris files. Checked against Swiss Ephemeris.",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",