klio 1.4.9 → 1.5.1

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.
@@ -0,0 +1,279 @@
1
+ const { loadSwephWasmModule } = require('./swephWasmLoader');
2
+
3
+ let nativeSwisseph = null;
4
+ try {
5
+ nativeSwisseph = require('swisseph');
6
+ } catch (error) {
7
+ nativeSwisseph = null;
8
+ }
9
+
10
+ const SE_GREG_CAL = nativeSwisseph ? nativeSwisseph.SE_GREG_CAL : 1;
11
+ const SEFLG_SWIEPH = nativeSwisseph ? nativeSwisseph.SEFLG_SWIEPH : 2;
12
+ const SEFLG_SPEED = nativeSwisseph ? nativeSwisseph.SEFLG_SPEED : 256;
13
+ const SEFLG_MOSEPH = nativeSwisseph ? nativeSwisseph.SEFLG_MOSEPH : 4;
14
+
15
+ let wasmModule = null;
16
+ let wasmGet = null;
17
+ let wasmReadyPromise = null;
18
+
19
+ const planetCache = new Map();
20
+ const houseCache = new Map();
21
+
22
+ function ensureReady() {
23
+ if (nativeSwisseph) {
24
+ return;
25
+ }
26
+ if (!wasmModule || !wasmGet) {
27
+ throw new Error('Sweph WASM is not initialized. Call initialize() before use.');
28
+ }
29
+ }
30
+
31
+ async function initialize() {
32
+ if (nativeSwisseph) {
33
+ return;
34
+ }
35
+ if (!wasmReadyPromise) {
36
+ wasmReadyPromise = loadSwephWasmModule().then((moduleInstance) => {
37
+ wasmModule = moduleInstance;
38
+ wasmGet = wasmModule.cwrap('get', 'string', [
39
+ 'number', 'number', 'number', 'number', 'number', 'number',
40
+ 'number', 'number', 'number', 'string',
41
+ 'number', 'number', 'number', 'string',
42
+ 'string'
43
+ ]);
44
+ return wasmModule;
45
+ });
46
+ }
47
+ await wasmReadyPromise;
48
+ }
49
+
50
+ function toDms(value) {
51
+ const absValue = Math.abs(value);
52
+ let degrees = Math.floor(absValue);
53
+ let minutesFloat = (absValue - degrees) * 60;
54
+ let minutes = Math.floor(minutesFloat);
55
+ let seconds = Math.round((minutesFloat - minutes) * 60);
56
+
57
+ if (seconds === 60) {
58
+ seconds = 0;
59
+ minutes += 1;
60
+ }
61
+ if (minutes === 60) {
62
+ minutes = 0;
63
+ degrees += 1;
64
+ }
65
+
66
+ return { degrees, minutes, seconds };
67
+ }
68
+
69
+ function toLonLatArgs(longitude, latitude) {
70
+ const lon = toDms(longitude);
71
+ const lat = toDms(latitude);
72
+
73
+ return {
74
+ lonG: lon.degrees,
75
+ lonM: lon.minutes,
76
+ lonS: lon.seconds,
77
+ lonEW: longitude < 0 ? 'W' : 'E',
78
+ latG: lat.degrees,
79
+ latM: lat.minutes,
80
+ latS: lat.seconds,
81
+ latNS: latitude < 0 ? 'S' : 'N'
82
+ };
83
+ }
84
+
85
+ function swe_julday(year, month, day, hour, gregflag) {
86
+ if (nativeSwisseph && nativeSwisseph.swe_julday) {
87
+ return nativeSwisseph.swe_julday(year, month, day, hour, gregflag);
88
+ }
89
+ const isGregorian = gregflag === SE_GREG_CAL;
90
+ let y = year;
91
+ let m = month;
92
+ if (m <= 2) {
93
+ y -= 1;
94
+ m += 12;
95
+ }
96
+ const a = Math.floor(y / 100);
97
+ const b = isGregorian ? 2 - a + Math.floor(a / 4) : 0;
98
+ const jd = Math.floor(365.25 * (y + 4716))
99
+ + Math.floor(30.6001 * (m + 1))
100
+ + day + b - 1524.5 + hour / 24;
101
+ return jd;
102
+ }
103
+
104
+ function swe_revjul(julianDay, gregflag) {
105
+ if (nativeSwisseph && nativeSwisseph.swe_revjul) {
106
+ return nativeSwisseph.swe_revjul(julianDay, gregflag);
107
+ }
108
+ const isGregorian = gregflag === SE_GREG_CAL;
109
+ const jd = julianDay + 0.5;
110
+ let z = Math.floor(jd);
111
+ const f = jd - z;
112
+ let a = z;
113
+
114
+ if (isGregorian) {
115
+ const alpha = Math.floor((z - 1867216.25) / 36524.25);
116
+ a = z + 1 + alpha - Math.floor(alpha / 4);
117
+ }
118
+
119
+ const b = a + 1524;
120
+ const c = Math.floor((b - 122.1) / 365.25);
121
+ const d = Math.floor(365.25 * c);
122
+ const e = Math.floor((b - d) / 30.6001);
123
+
124
+ const dayWithFraction = b - d - Math.floor(30.6001 * e) + f;
125
+ const day = Math.floor(dayWithFraction);
126
+ const dayFraction = dayWithFraction - day;
127
+
128
+ let month = e < 14 ? e - 1 : e - 13;
129
+ let year = month > 2 ? c - 4716 : c - 4715;
130
+
131
+ const hour = dayFraction * 24;
132
+
133
+ return { year, month, day, hour };
134
+ }
135
+
136
+ function parseWasmResponse(jsonText) {
137
+ try {
138
+ return JSON.parse(jsonText);
139
+ } catch (error) {
140
+ return null;
141
+ }
142
+ }
143
+
144
+ function getPlanetsForJulianDay(julianDay) {
145
+ const cacheKey = julianDay.toFixed(8);
146
+ if (planetCache.has(cacheKey)) {
147
+ return planetCache.get(cacheKey);
148
+ }
149
+
150
+ const { year, month, day, hour } = swe_revjul(julianDay, SE_GREG_CAL);
151
+ const hourInt = Math.floor(hour);
152
+ const minute = Math.floor((hour - hourInt) * 60);
153
+ const second = Math.round((((hour - hourInt) * 60) - minute) * 60);
154
+
155
+ const jsonText = wasmGet(
156
+ year, month, day, hourInt, minute, second,
157
+ 0, 0, 0, 'E',
158
+ 0, 0, 0, 'N',
159
+ 'K'
160
+ );
161
+
162
+ const parsed = parseWasmResponse(jsonText);
163
+ if (!parsed || !Array.isArray(parsed.planets)) {
164
+ return null;
165
+ }
166
+
167
+ planetCache.set(cacheKey, parsed.planets);
168
+ return parsed.planets;
169
+ }
170
+
171
+ function getHousesForJulianDay(julianDay, latitude, longitude, houseSystem) {
172
+ const cacheKey = `${julianDay.toFixed(8)}|${latitude.toFixed(4)}|${longitude.toFixed(4)}|${houseSystem}`;
173
+ if (houseCache.has(cacheKey)) {
174
+ return houseCache.get(cacheKey);
175
+ }
176
+
177
+ const { year, month, day, hour } = swe_revjul(julianDay, SE_GREG_CAL);
178
+ const hourInt = Math.floor(hour);
179
+ const minute = Math.floor((hour - hourInt) * 60);
180
+ const second = Math.round((((hour - hourInt) * 60) - minute) * 60);
181
+ const coords = toLonLatArgs(longitude, latitude);
182
+ const houseCode = (houseSystem && typeof houseSystem === 'string')
183
+ ? houseSystem.charAt(0).toUpperCase()
184
+ : 'K';
185
+
186
+ const jsonText = wasmGet(
187
+ year, month, day, hourInt, minute, second,
188
+ coords.lonG, coords.lonM, coords.lonS, coords.lonEW,
189
+ coords.latG, coords.latM, coords.latS, coords.latNS,
190
+ houseCode
191
+ );
192
+
193
+ const parsed = parseWasmResponse(jsonText);
194
+ if (!parsed) {
195
+ return null;
196
+ }
197
+
198
+ const houseArray = new Array(13).fill(0);
199
+ if (Array.isArray(parsed.house)) {
200
+ parsed.house.forEach((entry) => {
201
+ const index = parseInt(entry.name, 10);
202
+ if (!Number.isNaN(index) && index >= 1 && index <= 12) {
203
+ houseArray[index] = entry.long;
204
+ }
205
+ });
206
+ }
207
+
208
+ const ascmc = new Array(10).fill(0);
209
+ if (Array.isArray(parsed.ascmc)) {
210
+ parsed.ascmc.forEach((entry) => {
211
+ if (entry.name === 'Asc') {
212
+ ascmc[0] = entry.long;
213
+ } else if (entry.name === 'MC') {
214
+ ascmc[1] = entry.long;
215
+ }
216
+ });
217
+ }
218
+
219
+ const result = { house: houseArray, ascmc };
220
+ houseCache.set(cacheKey, result);
221
+ return result;
222
+ }
223
+
224
+ function swe_calc_ut(julianDay, planet, flag) {
225
+ if (nativeSwisseph) {
226
+ return nativeSwisseph.swe_calc_ut(julianDay, planet, flag);
227
+ }
228
+
229
+ ensureReady();
230
+ const planets = getPlanetsForJulianDay(julianDay);
231
+ if (!planets) {
232
+ return { error: 'Sweph WASM returned invalid data.' };
233
+ }
234
+
235
+ const match = planets.find((entry) => entry.index === planet);
236
+ if (!match) {
237
+ return { error: `Planet index ${planet} not found in Sweph WASM data.` };
238
+ }
239
+
240
+ return {
241
+ longitude: match.long,
242
+ latitude: match.lat,
243
+ distance: match.distance,
244
+ longitudeSpeed: match.speed
245
+ };
246
+ }
247
+
248
+ function swe_houses(julianDay, latitude, longitude, houseSystem, callback) {
249
+ if (nativeSwisseph) {
250
+ return nativeSwisseph.swe_houses(julianDay, latitude, longitude, houseSystem, callback);
251
+ }
252
+
253
+ ensureReady();
254
+ const result = getHousesForJulianDay(julianDay, latitude, longitude, houseSystem);
255
+ if (typeof callback === 'function') {
256
+ callback(result);
257
+ }
258
+ return result;
259
+ }
260
+
261
+ function swe_set_ephe_path() {
262
+ if (nativeSwisseph && nativeSwisseph.swe_set_ephe_path) {
263
+ return nativeSwisseph.swe_set_ephe_path.apply(nativeSwisseph, arguments);
264
+ }
265
+ return null;
266
+ }
267
+
268
+ module.exports = {
269
+ SE_GREG_CAL,
270
+ SEFLG_SWIEPH,
271
+ SEFLG_SPEED,
272
+ SEFLG_MOSEPH,
273
+ initialize,
274
+ swe_set_ephe_path,
275
+ swe_calc_ut,
276
+ swe_julday,
277
+ swe_revjul,
278
+ swe_houses
279
+ };