siderust-js 0.1.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/.github/workflows/ci.yml +166 -0
- package/.gitmodules +9 -0
- package/CHANGELOG.md +26 -0
- package/LICENSE +661 -0
- package/README.md +138 -0
- package/package.json +12 -0
- package/qtty-js/.github/workflows/ci.yml +151 -0
- package/qtty-js/.gitmodules +3 -0
- package/qtty-js/CHANGELOG.md +31 -0
- package/qtty-js/LICENSE +661 -0
- package/qtty-js/README.md +132 -0
- package/qtty-js/package.json +20 -0
- package/qtty-js/qtty/.github/workflows/ci.yml +155 -0
- package/qtty-js/qtty/CHANGELOG.md +120 -0
- package/qtty-js/qtty/Cargo.lock +1462 -0
- package/qtty-js/qtty/Cargo.toml +12 -0
- package/qtty-js/qtty/LICENSE +661 -0
- package/qtty-js/qtty/README.md +9 -0
- package/qtty-js/qtty/qtty/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty/README.md +8 -0
- package/qtty-js/qtty/qtty/examples/angles.rs +14 -0
- package/qtty-js/qtty/qtty/examples/astronomy.rs +17 -0
- package/qtty-js/qtty/qtty/examples/dimensional_arithmetic.rs +83 -0
- package/qtty-js/qtty/qtty/examples/python_integration.rs +61 -0
- package/qtty-js/qtty/qtty/examples/quickstart.rs +15 -0
- package/qtty-js/qtty/qtty/examples/ratios.rs +12 -0
- package/qtty-js/qtty/qtty/examples/serde_with_unit.rs +234 -0
- package/qtty-js/qtty/qtty/examples/serialization.rs +141 -0
- package/qtty-js/qtty/qtty/examples/serialization_advanced.rs +155 -0
- package/qtty-js/qtty/qtty/src/f32.rs +108 -0
- package/qtty-js/qtty/qtty/src/f64.rs +30 -0
- package/qtty-js/qtty/qtty/src/i128.rs +111 -0
- package/qtty-js/qtty/qtty/src/i16.rs +111 -0
- package/qtty-js/qtty/qtty/src/i32.rs +111 -0
- package/qtty-js/qtty/qtty/src/i64.rs +111 -0
- package/qtty-js/qtty/qtty/src/i8.rs +111 -0
- package/qtty-js/qtty/qtty/src/lib.rs +238 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-no-std-alloc/src/lib.rs +7 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.lock +83 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/Cargo.toml +10 -0
- package/qtty-js/qtty/qtty/tests/fixtures/qtty-vec-std/src/lib.rs +5 -0
- package/qtty-js/qtty/qtty/tests/integration_tests.rs +529 -0
- package/qtty-js/qtty/qtty/tests/qtty_vec_feature_matrix.rs +58 -0
- package/qtty-js/qtty/qtty-core/Cargo.toml +41 -0
- package/qtty-js/qtty/qtty-core/README.md +8 -0
- package/qtty-js/qtty/qtty-core/examples/diesel_integration.rs +145 -0
- package/qtty-js/qtty/qtty-core/examples/quantity_db_serde.rs +215 -0
- package/qtty-js/qtty/qtty-core/src/dimension.rs +249 -0
- package/qtty-js/qtty/qtty-core/src/feature_diesel.rs +318 -0
- package/qtty-js/qtty/qtty-core/src/feature_pyo3.rs +27 -0
- package/qtty-js/qtty/qtty-core/src/feature_serde.rs +203 -0
- package/qtty-js/qtty/qtty-core/src/feature_tiberius.rs +28 -0
- package/qtty-js/qtty/qtty-core/src/lib.rs +744 -0
- package/qtty-js/qtty/qtty-core/src/macros.rs +93 -0
- package/qtty-js/qtty/qtty-core/src/quantity.rs +810 -0
- package/qtty-js/qtty/qtty-core/src/scalar.rs +1742 -0
- package/qtty-js/qtty/qtty-core/src/unit.rs +332 -0
- package/qtty-js/qtty/qtty-core/src/units/angular.rs +1228 -0
- package/qtty-js/qtty/qtty-core/src/units/area.rs +243 -0
- package/qtty-js/qtty/qtty-core/src/units/frequency.rs +179 -0
- package/qtty-js/qtty/qtty-core/src/units/length.rs +1270 -0
- package/qtty-js/qtty/qtty-core/src/units/mass.rs +488 -0
- package/qtty-js/qtty/qtty-core/src/units/mod.rs +26 -0
- package/qtty-js/qtty/qtty-core/src/units/power.rs +324 -0
- package/qtty-js/qtty/qtty-core/src/units/time.rs +667 -0
- package/qtty-js/qtty/qtty-core/src/units/unitless.rs +212 -0
- package/qtty-js/qtty/qtty-core/src/units/velocity.rs +210 -0
- package/qtty-js/qtty/qtty-core/src/units/volume.rs +269 -0
- package/qtty-js/qtty/qtty-core/tests/core.rs +628 -0
- package/qtty-js/qtty/qtty-core/tests/diesel.rs +461 -0
- package/qtty-js/qtty/qtty-core/tests/integers.rs +632 -0
- package/qtty-js/qtty/qtty-core/tests/no_cross_unit_ops.rs +35 -0
- package/qtty-js/qtty/qtty-core/tests/pyo3.rs +334 -0
- package/qtty-js/qtty/qtty-core/tests/quantity_f32.rs +276 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_decimal.rs +258 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f32.rs +286 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_f64_real.rs +287 -0
- package/qtty-js/qtty/qtty-core/tests/scalar_rational.rs +260 -0
- package/qtty-js/qtty/qtty-core/tests/serde.rs +256 -0
- package/qtty-js/qtty/qtty-core/tests/tiberius.rs +208 -0
- package/qtty-js/qtty/qtty-derive/Cargo.toml +23 -0
- package/qtty-js/qtty/qtty-derive/README.md +8 -0
- package/qtty-js/qtty/qtty-derive/src/lib.rs +340 -0
- package/qtty-js/qtty/qtty-ffi/ARCHITECTURE.md +3 -0
- package/qtty-js/qtty/qtty-ffi/Cargo.toml +31 -0
- package/qtty-js/qtty/qtty-ffi/README.md +9 -0
- package/qtty-js/qtty/qtty-ffi/build.rs +326 -0
- package/qtty-js/qtty/qtty-ffi/cbindgen.toml +105 -0
- package/qtty-js/qtty/qtty-ffi/include/qtty_ffi.h +1126 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi.rs +1251 -0
- package/qtty-js/qtty/qtty-ffi/src/ffi_serde.rs +294 -0
- package/qtty-js/qtty/qtty-ffi/src/helpers.rs +310 -0
- package/qtty-js/qtty/qtty-ffi/src/lib.rs +229 -0
- package/qtty-js/qtty/qtty-ffi/src/macros.rs +121 -0
- package/qtty-js/qtty/qtty-ffi/src/registry.rs +274 -0
- package/qtty-js/qtty/qtty-ffi/src/types.rs +620 -0
- package/qtty-js/qtty/qtty-ffi/tests/integration_tests.rs +842 -0
- package/qtty-js/qtty/qtty-ffi/units.csv +156 -0
- package/qtty-js/qtty/qtty-ffi/units.csv.md +3 -0
- package/qtty-js/qtty-node/.prettierignore +6 -0
- package/qtty-js/qtty-node/.prettierrc.json +6 -0
- package/qtty-js/qtty-node/README.md +250 -0
- package/qtty-js/qtty-node/c8.config.json +11 -0
- package/qtty-js/qtty-node/eslint.config.js +31 -0
- package/qtty-js/qtty-node/examples/arithmetic.mjs +64 -0
- package/qtty-js/qtty-node/examples/astronomy.mjs +90 -0
- package/qtty-js/qtty-node/examples/quickstart.mjs +36 -0
- package/qtty-js/qtty-node/examples/serialization.mjs +125 -0
- package/qtty-js/qtty-node/examples/unit_factories.mjs +74 -0
- package/qtty-js/qtty-node/index.d.ts +219 -0
- package/qtty-js/qtty-node/index.js +323 -0
- package/qtty-js/qtty-node/lib/DerivedQuantity.js +122 -0
- package/qtty-js/qtty-node/lib/Quantity.js +151 -0
- package/qtty-js/qtty-node/lib/backend.js +25 -0
- package/qtty-js/qtty-node/native.cjs +306 -0
- package/qtty-js/qtty-node/package-lock.json +3223 -0
- package/qtty-js/qtty-node/package.json +70 -0
- package/qtty-js/qtty-node/units.d.ts +299 -0
- package/qtty-js/qtty-node/units.js +210 -0
- package/qtty-js/qtty-web/Cargo.lock +767 -0
- package/qtty-js/qtty-web/Cargo.toml +21 -0
- package/qtty-js/qtty-web/index.d.ts +140 -0
- package/qtty-js/qtty-web/index.js +20 -0
- package/qtty-js/qtty-web/lib/DerivedQuantity.js +58 -0
- package/qtty-js/qtty-web/lib/Quantity.js +75 -0
- package/qtty-js/qtty-web/lib/backend.js +80 -0
- package/qtty-js/qtty-web/package.json +45 -0
- package/qtty-js/qtty-web/src/lib.rs +111 -0
- package/qtty-js/scripts/ci.sh +73 -0
- package/scripts/ci.sh +123 -0
- package/siderust-core/Cargo.lock +787 -0
- package/siderust-core/Cargo.toml +18 -0
- package/siderust-core/DEDUPLICATION.md +124 -0
- package/siderust-core/src/body.rs +120 -0
- package/siderust-core/src/events.rs +184 -0
- package/siderust-core/src/lib.rs +20 -0
- package/siderust-core/src/observer.rs +55 -0
- package/siderust-core/src/position.rs +213 -0
- package/siderust-node/.prettierignore +7 -0
- package/siderust-node/.prettierrc.json +6 -0
- package/siderust-node/Cargo.lock +906 -0
- package/siderust-node/Cargo.toml +29 -0
- package/siderust-node/README.md +109 -0
- package/siderust-node/__test__/index.test.mjs +248 -0
- package/siderust-node/build.rs +5 -0
- package/siderust-node/c8.config.json +3 -0
- package/siderust-node/eslint.config.js +31 -0
- package/siderust-node/examples/01_basic_coordinates.mjs +24 -0
- package/siderust-node/examples/02_coordinate_transformations.mjs +25 -0
- package/siderust-node/examples/03_all_frames_conversions.mjs +26 -0
- package/siderust-node/examples/04_all_center_conversions.mjs +24 -0
- package/siderust-node/examples/05_target_tracking.mjs +22 -0
- package/siderust-node/examples/06_night_events.mjs +18 -0
- package/siderust-node/examples/07_moon_properties.mjs +21 -0
- package/siderust-node/examples/08_solar_system.mjs +19 -0
- package/siderust-node/examples/09_star_observability.mjs +22 -0
- package/siderust-node/examples/10_time_periods.mjs +9 -0
- package/siderust-node/examples/11_serialization.mjs +31 -0
- package/siderust-node/examples/12_runtime_ephemeris.mjs +27 -0
- package/siderust-node/examples/13_coordinate_operations.mjs +20 -0
- package/siderust-node/index.d.ts +623 -0
- package/siderust-node/index.js +79 -0
- package/siderust-node/lib/Observer.js +112 -0
- package/siderust-node/lib/Star.js +118 -0
- package/siderust-node/lib/backend.js +63 -0
- package/siderust-node/lib/wrappers.js +566 -0
- package/siderust-node/main.js +20 -0
- package/siderust-node/native.cjs +360 -0
- package/siderust-node/package-lock.json +3261 -0
- package/siderust-node/package.json +71 -0
- package/siderust-node/src/body.rs +74 -0
- package/siderust-node/src/coordinates.rs +372 -0
- package/siderust-node/src/ephemeris.rs +462 -0
- package/siderust-node/src/events.rs +577 -0
- package/siderust-node/src/lib.rs +43 -0
- package/siderust-node/src/observer.rs +132 -0
- package/siderust-node/src/phase.rs +218 -0
- package/siderust-node/src/position.rs +292 -0
- package/siderust-node/src/star.rs +200 -0
- package/siderust-web/Cargo.lock +855 -0
- package/siderust-web/Cargo.toml +34 -0
- package/siderust-web/README.md +100 -0
- package/siderust-web/__test__/index.test.mjs +118 -0
- package/siderust-web/examples/github-pages/README.md +31 -0
- package/siderust-web/examples/github-pages/index.html +135 -0
- package/siderust-web/index.d.ts +311 -0
- package/siderust-web/index.js +66 -0
- package/siderust-web/lib/Observer.js +103 -0
- package/siderust-web/lib/Star.js +116 -0
- package/siderust-web/lib/backend.js +400 -0
- package/siderust-web/lib/wrappers.js +512 -0
- package/siderust-web/package.json +55 -0
- package/siderust-web/src/body.rs +69 -0
- package/siderust-web/src/coordinates.rs +302 -0
- package/siderust-web/src/ephemeris.rs +456 -0
- package/siderust-web/src/events.rs +520 -0
- package/siderust-web/src/lib.rs +51 -0
- package/siderust-web/src/observer.rs +117 -0
- package/siderust-web/src/phase.rs +190 -0
- package/siderust-web/src/position.rs +291 -0
- package/siderust-web/src/star.rs +178 -0
- package/tempoch-js/.github/workflows/ci.yml +142 -0
- package/tempoch-js/.gitmodules +3 -0
- package/tempoch-js/CHANGELOG.md +25 -0
- package/tempoch-js/LICENSE +661 -0
- package/tempoch-js/README.md +126 -0
- package/tempoch-js/package.json +20 -0
- package/tempoch-js/scripts/ci.sh +73 -0
- package/tempoch-js/tempoch/.github/workflows/ci.yml +113 -0
- package/tempoch-js/tempoch/CHANGELOG.md +82 -0
- package/tempoch-js/tempoch/Cargo.lock +947 -0
- package/tempoch-js/tempoch/Cargo.toml +3 -0
- package/tempoch-js/tempoch/LICENSE +661 -0
- package/tempoch-js/tempoch/README.md +76 -0
- package/tempoch-js/tempoch/tempoch/Cargo.toml +27 -0
- package/tempoch-js/tempoch/tempoch/examples/periods.rs +45 -0
- package/tempoch-js/tempoch/tempoch/examples/quickstart.rs +13 -0
- package/tempoch-js/tempoch/tempoch/src/lib.rs +49 -0
- package/tempoch-js/tempoch/tempoch/tests/integration.rs +57 -0
- package/tempoch-js/tempoch/tempoch-core/Cargo.toml +24 -0
- package/tempoch-js/tempoch/tempoch-core/src/delta_t.rs +345 -0
- package/tempoch-js/tempoch/tempoch-core/src/instant.rs +811 -0
- package/tempoch-js/tempoch/tempoch-core/src/julian_date_ext.rs +142 -0
- package/tempoch-js/tempoch/tempoch-core/src/lib.rs +81 -0
- package/tempoch-js/tempoch/tempoch-core/src/period.rs +1168 -0
- package/tempoch-js/tempoch/tempoch-core/src/scales.rs +779 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.lock +889 -0
- package/tempoch-js/tempoch/tempoch-ffi/Cargo.toml +26 -0
- package/tempoch-js/tempoch/tempoch-ffi/build.rs +24 -0
- package/tempoch-js/tempoch/tempoch-ffi/cbindgen.toml +30 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/error.rs +19 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/lib.rs +82 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/period.rs +101 -0
- package/tempoch-js/tempoch/tempoch-ffi/src/time.rs +711 -0
- package/tempoch-js/tempoch/tempoch-ffi/tests/ffi.rs +265 -0
- package/tempoch-js/tempoch-node/.prettierignore +6 -0
- package/tempoch-js/tempoch-node/.prettierrc.json +6 -0
- package/tempoch-js/tempoch-node/Cargo.lock +496 -0
- package/tempoch-js/tempoch-node/Cargo.toml +29 -0
- package/tempoch-js/tempoch-node/README.md +265 -0
- package/tempoch-js/tempoch-node/__test__/index.test.mjs +598 -0
- package/tempoch-js/tempoch-node/build.rs +5 -0
- package/tempoch-js/tempoch-node/c8.config.json +3 -0
- package/tempoch-js/tempoch-node/eslint.config.js +31 -0
- package/tempoch-js/tempoch-node/examples/periods.mjs +79 -0
- package/tempoch-js/tempoch-node/examples/quickstart.mjs +71 -0
- package/tempoch-js/tempoch-node/examples/timescales.mjs +92 -0
- package/tempoch-js/tempoch-node/index.d.ts +280 -0
- package/tempoch-js/tempoch-node/index.js +32 -0
- package/tempoch-js/tempoch-node/lib/JulianDate.js +176 -0
- package/tempoch-js/tempoch-node/lib/ModifiedJulianDate.js +156 -0
- package/tempoch-js/tempoch-node/lib/Period.js +133 -0
- package/tempoch-js/tempoch-node/lib/backend.js +38 -0
- package/tempoch-js/tempoch-node/lib/qttyCompat.js +92 -0
- package/tempoch-js/tempoch-node/native.cjs +317 -0
- package/tempoch-js/tempoch-node/package-lock.json +3223 -0
- package/tempoch-js/tempoch-node/package.json +56 -0
- package/tempoch-js/tempoch-node/src/lib.rs +573 -0
- package/tempoch-js/tempoch-web/Cargo.toml +23 -0
- package/tempoch-js/tempoch-web/index.d.ts +95 -0
- package/tempoch-js/tempoch-web/index.js +27 -0
- package/tempoch-js/tempoch-web/lib/JulianDate.js +170 -0
- package/tempoch-js/tempoch-web/lib/ModifiedJulianDate.js +145 -0
- package/tempoch-js/tempoch-web/lib/Period.js +121 -0
- package/tempoch-js/tempoch-web/lib/backend.js +118 -0
- package/tempoch-js/tempoch-web/package.json +46 -0
- package/tempoch-js/tempoch-web/src/lib.rs +184 -0
|
@@ -0,0 +1,577 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Vallés Puig, Ramon
|
|
3
|
+
|
|
4
|
+
//! Altitude and azimuth event queries — the core observation-planning API.
|
|
5
|
+
//!
|
|
6
|
+
//! All functions accept an `Observer`, a body name (or `Star` handle), and
|
|
7
|
+
//! a time window, returning arrays of events or periods in a single call.
|
|
8
|
+
|
|
9
|
+
use napi_derive::napi;
|
|
10
|
+
|
|
11
|
+
use crate::body::{dispatch_body, parse_body};
|
|
12
|
+
use crate::observer::JsObserver;
|
|
13
|
+
use crate::star::JsStar;
|
|
14
|
+
|
|
15
|
+
use qtty::*;
|
|
16
|
+
use siderust::calculus::altitude::{self, SearchOpts};
|
|
17
|
+
use siderust::calculus::azimuth;
|
|
18
|
+
use siderust::AltitudePeriodsProvider;
|
|
19
|
+
use siderust::AzimuthProvider;
|
|
20
|
+
use tempoch::{ModifiedJulianDate, Period, MJD};
|
|
21
|
+
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
23
|
+
// Result types (plain objects)
|
|
24
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
25
|
+
|
|
26
|
+
/// A threshold-crossing event (rise or set).
|
|
27
|
+
#[napi(object)]
|
|
28
|
+
pub struct CrossingEvent {
|
|
29
|
+
/// Time of the crossing (Modified Julian Date).
|
|
30
|
+
pub mjd: f64,
|
|
31
|
+
/// Direction: `"rising"` or `"setting"`.
|
|
32
|
+
pub direction: String,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/// A culmination event (local altitude extremum).
|
|
36
|
+
#[napi(object)]
|
|
37
|
+
pub struct CulminationEvent {
|
|
38
|
+
/// Time of the culmination (Modified Julian Date).
|
|
39
|
+
pub mjd: f64,
|
|
40
|
+
/// Altitude at the extremum in degrees.
|
|
41
|
+
pub altitude_deg: f64,
|
|
42
|
+
/// Kind: `"max"` (upper culmination) or `"min"` (lower culmination).
|
|
43
|
+
pub kind: String,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/// A time period (MJD interval).
|
|
47
|
+
#[napi(object)]
|
|
48
|
+
pub struct MjdPeriod {
|
|
49
|
+
/// Start of the period (Modified Julian Date).
|
|
50
|
+
pub start_mjd: f64,
|
|
51
|
+
/// End of the period (Modified Julian Date).
|
|
52
|
+
pub end_mjd: f64,
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/// An azimuth-crossing event.
|
|
56
|
+
#[napi(object)]
|
|
57
|
+
pub struct AzimuthCrossingEvent {
|
|
58
|
+
/// Time of the event (Modified Julian Date).
|
|
59
|
+
pub mjd: f64,
|
|
60
|
+
/// Crossing direction: `"rising"` or `"setting"`.
|
|
61
|
+
pub direction: String,
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/// An azimuth extremum (local max or min bearing).
|
|
65
|
+
#[napi(object)]
|
|
66
|
+
pub struct AzimuthExtremum {
|
|
67
|
+
/// Time of the extremum (Modified Julian Date).
|
|
68
|
+
pub mjd: f64,
|
|
69
|
+
/// Azimuth at the extremum in degrees.
|
|
70
|
+
pub azimuth_deg: f64,
|
|
71
|
+
/// Kind: `"max"` or `"min"`.
|
|
72
|
+
pub kind: String,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
76
|
+
// Helpers
|
|
77
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
78
|
+
|
|
79
|
+
pub(crate) fn make_window(start_mjd: f64, end_mjd: f64) -> napi::Result<Period<MJD>> {
|
|
80
|
+
if !start_mjd.is_finite() || !end_mjd.is_finite() {
|
|
81
|
+
return Err(napi::Error::from_reason(
|
|
82
|
+
"Window bounds (startMjd, endMjd) must be finite",
|
|
83
|
+
));
|
|
84
|
+
}
|
|
85
|
+
if start_mjd >= end_mjd {
|
|
86
|
+
return Err(napi::Error::from_reason(
|
|
87
|
+
"Window start must be before end (startMjd < endMjd)",
|
|
88
|
+
));
|
|
89
|
+
}
|
|
90
|
+
Ok(Period::new(
|
|
91
|
+
ModifiedJulianDate::new(start_mjd),
|
|
92
|
+
ModifiedJulianDate::new(end_mjd),
|
|
93
|
+
))
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn convert_crossings(events: Vec<altitude::CrossingEvent>) -> Vec<CrossingEvent> {
|
|
97
|
+
events
|
|
98
|
+
.into_iter()
|
|
99
|
+
.map(|e| CrossingEvent {
|
|
100
|
+
mjd: e.mjd.value(),
|
|
101
|
+
direction: match e.direction {
|
|
102
|
+
altitude::CrossingDirection::Rising => "rising".to_string(),
|
|
103
|
+
altitude::CrossingDirection::Setting => "setting".to_string(),
|
|
104
|
+
},
|
|
105
|
+
})
|
|
106
|
+
.collect()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
fn convert_culminations(events: Vec<altitude::CulminationEvent>) -> Vec<CulminationEvent> {
|
|
110
|
+
events
|
|
111
|
+
.into_iter()
|
|
112
|
+
.map(|e| CulminationEvent {
|
|
113
|
+
mjd: e.mjd.value(),
|
|
114
|
+
altitude_deg: e.altitude.value(),
|
|
115
|
+
kind: match e.kind {
|
|
116
|
+
altitude::CulminationKind::Max => "max".to_string(),
|
|
117
|
+
altitude::CulminationKind::Min => "min".to_string(),
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
.collect()
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
fn convert_periods(periods: Vec<Period<MJD>>) -> Vec<MjdPeriod> {
|
|
124
|
+
periods
|
|
125
|
+
.into_iter()
|
|
126
|
+
.map(|p| MjdPeriod {
|
|
127
|
+
start_mjd: p.start.value(),
|
|
128
|
+
end_mjd: p.end.value(),
|
|
129
|
+
})
|
|
130
|
+
.collect()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
fn convert_az_crossings(
|
|
134
|
+
events: Vec<siderust::AzimuthCrossingEvent>,
|
|
135
|
+
) -> Vec<AzimuthCrossingEvent> {
|
|
136
|
+
events
|
|
137
|
+
.into_iter()
|
|
138
|
+
.map(|e| AzimuthCrossingEvent {
|
|
139
|
+
mjd: e.mjd.value(),
|
|
140
|
+
direction: match e.direction {
|
|
141
|
+
siderust::AzimuthCrossingDirection::Rising => "rising".to_string(),
|
|
142
|
+
siderust::AzimuthCrossingDirection::Setting => "setting".to_string(),
|
|
143
|
+
},
|
|
144
|
+
})
|
|
145
|
+
.collect()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
fn convert_az_extrema(events: Vec<siderust::AzimuthExtremum>) -> Vec<AzimuthExtremum> {
|
|
149
|
+
events
|
|
150
|
+
.into_iter()
|
|
151
|
+
.map(|e| AzimuthExtremum {
|
|
152
|
+
mjd: e.mjd.value(),
|
|
153
|
+
azimuth_deg: e.azimuth.value(),
|
|
154
|
+
kind: match e.kind {
|
|
155
|
+
siderust::AzimuthExtremumKind::Max => "max".to_string(),
|
|
156
|
+
siderust::AzimuthExtremumKind::Min => "min".to_string(),
|
|
157
|
+
},
|
|
158
|
+
})
|
|
159
|
+
.collect()
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
163
|
+
// Body altitude — instantaneous
|
|
164
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
165
|
+
|
|
166
|
+
/// Compute the altitude of a solar-system body at a single instant.
|
|
167
|
+
///
|
|
168
|
+
/// @param body — Body name (e.g. `"Sun"`, `"Moon"`, `"Mars"`).
|
|
169
|
+
/// @param observer — Observer location.
|
|
170
|
+
/// @param mjd — Modified Julian Date of the instant.
|
|
171
|
+
/// @returns Altitude in degrees.
|
|
172
|
+
///
|
|
173
|
+
/// ```js
|
|
174
|
+
/// const { Observer, bodyAltitudeAt } = require('@siderust/siderust');
|
|
175
|
+
/// const obs = Observer.roqueDeLasMuchachos();
|
|
176
|
+
/// const alt = bodyAltitudeAt('Sun', obs, 60000.0);
|
|
177
|
+
/// ```
|
|
178
|
+
#[napi(js_name = "bodyAltitudeAt")]
|
|
179
|
+
pub fn body_altitude_at(body: String, observer: &JsObserver, mjd: f64) -> napi::Result<f64> {
|
|
180
|
+
if !mjd.is_finite() {
|
|
181
|
+
return Err(napi::Error::from_reason("mjd must be finite"));
|
|
182
|
+
}
|
|
183
|
+
let kind = parse_body(&body)?;
|
|
184
|
+
let m = ModifiedJulianDate::new(mjd);
|
|
185
|
+
let result: f64 = dispatch_body!(kind, |b| {
|
|
186
|
+
b.altitude_at(&observer.inner, m).to::<Degree>().value()
|
|
187
|
+
});
|
|
188
|
+
Ok(result)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/// Compute the azimuth of a solar-system body at a single instant.
|
|
192
|
+
///
|
|
193
|
+
/// @returns Azimuth in degrees (north = 0°, east = 90°).
|
|
194
|
+
#[napi(js_name = "bodyAzimuthAt")]
|
|
195
|
+
pub fn body_azimuth_at(body: String, observer: &JsObserver, mjd: f64) -> napi::Result<f64> {
|
|
196
|
+
if !mjd.is_finite() {
|
|
197
|
+
return Err(napi::Error::from_reason("mjd must be finite"));
|
|
198
|
+
}
|
|
199
|
+
let kind = parse_body(&body)?;
|
|
200
|
+
let m = ModifiedJulianDate::new(mjd);
|
|
201
|
+
let result: f64 = dispatch_body!(kind, |b| {
|
|
202
|
+
b.azimuth_at(&observer.inner, m).to::<Degree>().value()
|
|
203
|
+
});
|
|
204
|
+
Ok(result)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
208
|
+
// Body altitude — batch events
|
|
209
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
210
|
+
|
|
211
|
+
/// Find threshold-crossing events (rise/set) for a solar-system body.
|
|
212
|
+
///
|
|
213
|
+
/// @param body — Body name.
|
|
214
|
+
/// @param observer — Observer location.
|
|
215
|
+
/// @param startMjd — Window start (MJD).
|
|
216
|
+
/// @param endMjd — Window end (MJD).
|
|
217
|
+
/// @param thresholdDeg — Altitude threshold in degrees (e.g. 0 for horizon).
|
|
218
|
+
/// @returns Array of crossing events `{ mjd, direction }`.
|
|
219
|
+
#[napi(js_name = "bodyCrossings")]
|
|
220
|
+
pub fn body_crossings(
|
|
221
|
+
body: String,
|
|
222
|
+
observer: &JsObserver,
|
|
223
|
+
start_mjd: f64,
|
|
224
|
+
end_mjd: f64,
|
|
225
|
+
threshold_deg: f64,
|
|
226
|
+
) -> napi::Result<Vec<CrossingEvent>> {
|
|
227
|
+
let kind = parse_body(&body)?;
|
|
228
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
229
|
+
let thr = Degrees::new(threshold_deg);
|
|
230
|
+
let opts = SearchOpts::default();
|
|
231
|
+
let result = dispatch_body!(kind, |b| {
|
|
232
|
+
convert_crossings(altitude::crossings(&b, &observer.inner, window, thr, opts))
|
|
233
|
+
});
|
|
234
|
+
Ok(result)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/// Find culmination events (altitude local extrema) for a solar-system body.
|
|
238
|
+
///
|
|
239
|
+
/// @returns Array of culmination events `{ mjd, altitudeDeg, kind }`.
|
|
240
|
+
#[napi(js_name = "bodyCulminations")]
|
|
241
|
+
pub fn body_culminations(
|
|
242
|
+
body: String,
|
|
243
|
+
observer: &JsObserver,
|
|
244
|
+
start_mjd: f64,
|
|
245
|
+
end_mjd: f64,
|
|
246
|
+
) -> napi::Result<Vec<CulminationEvent>> {
|
|
247
|
+
let kind = parse_body(&body)?;
|
|
248
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
249
|
+
let opts = SearchOpts::default();
|
|
250
|
+
let result = dispatch_body!(kind, |b| {
|
|
251
|
+
convert_culminations(altitude::culminations(&b, &observer.inner, window, opts))
|
|
252
|
+
});
|
|
253
|
+
Ok(result)
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/// Find periods where a body's altitude is above a threshold.
|
|
257
|
+
///
|
|
258
|
+
/// @returns Array of MJD periods `{ startMjd, endMjd }`.
|
|
259
|
+
#[napi(js_name = "bodyAboveThreshold")]
|
|
260
|
+
pub fn body_above_threshold(
|
|
261
|
+
body: String,
|
|
262
|
+
observer: &JsObserver,
|
|
263
|
+
start_mjd: f64,
|
|
264
|
+
end_mjd: f64,
|
|
265
|
+
threshold_deg: f64,
|
|
266
|
+
) -> napi::Result<Vec<MjdPeriod>> {
|
|
267
|
+
let kind = parse_body(&body)?;
|
|
268
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
269
|
+
let thr = Degrees::new(threshold_deg);
|
|
270
|
+
let opts = SearchOpts::default();
|
|
271
|
+
let result = dispatch_body!(kind, |b| {
|
|
272
|
+
convert_periods(altitude::above_threshold(
|
|
273
|
+
&b,
|
|
274
|
+
&observer.inner,
|
|
275
|
+
window,
|
|
276
|
+
thr,
|
|
277
|
+
opts,
|
|
278
|
+
))
|
|
279
|
+
});
|
|
280
|
+
Ok(result)
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/// Find periods where a body's altitude is below a threshold.
|
|
284
|
+
///
|
|
285
|
+
/// @returns Array of MJD periods `{ startMjd, endMjd }`.
|
|
286
|
+
#[napi(js_name = "bodyBelowThreshold")]
|
|
287
|
+
pub fn body_below_threshold(
|
|
288
|
+
body: String,
|
|
289
|
+
observer: &JsObserver,
|
|
290
|
+
start_mjd: f64,
|
|
291
|
+
end_mjd: f64,
|
|
292
|
+
threshold_deg: f64,
|
|
293
|
+
) -> napi::Result<Vec<MjdPeriod>> {
|
|
294
|
+
let kind = parse_body(&body)?;
|
|
295
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
296
|
+
let thr = Degrees::new(threshold_deg);
|
|
297
|
+
let opts = SearchOpts::default();
|
|
298
|
+
let result = dispatch_body!(kind, |b| {
|
|
299
|
+
convert_periods(altitude::below_threshold(
|
|
300
|
+
&b,
|
|
301
|
+
&observer.inner,
|
|
302
|
+
window,
|
|
303
|
+
thr,
|
|
304
|
+
opts,
|
|
305
|
+
))
|
|
306
|
+
});
|
|
307
|
+
Ok(result)
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/// Find azimuth-crossing events for a body.
|
|
311
|
+
///
|
|
312
|
+
/// @param bearingDeg — Target azimuth bearing in degrees.
|
|
313
|
+
/// @returns Array of azimuth crossing events `{ mjd, direction }`.
|
|
314
|
+
#[napi(js_name = "bodyAzimuthCrossings")]
|
|
315
|
+
pub fn body_azimuth_crossings(
|
|
316
|
+
body: String,
|
|
317
|
+
observer: &JsObserver,
|
|
318
|
+
start_mjd: f64,
|
|
319
|
+
end_mjd: f64,
|
|
320
|
+
bearing_deg: f64,
|
|
321
|
+
) -> napi::Result<Vec<AzimuthCrossingEvent>> {
|
|
322
|
+
let kind = parse_body(&body)?;
|
|
323
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
324
|
+
let bearing = Degrees::new(bearing_deg);
|
|
325
|
+
let opts = SearchOpts::default();
|
|
326
|
+
let result = dispatch_body!(kind, |b| {
|
|
327
|
+
convert_az_crossings(azimuth::azimuth_crossings(
|
|
328
|
+
&b,
|
|
329
|
+
&observer.inner,
|
|
330
|
+
window,
|
|
331
|
+
bearing,
|
|
332
|
+
opts,
|
|
333
|
+
))
|
|
334
|
+
});
|
|
335
|
+
Ok(result)
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/// Find azimuth extrema (max/min bearing) for a body.
|
|
339
|
+
///
|
|
340
|
+
/// @returns Array of azimuth extrema `{ mjd, azimuthDeg, kind }`.
|
|
341
|
+
#[napi(js_name = "bodyAzimuthExtrema")]
|
|
342
|
+
pub fn body_azimuth_extrema(
|
|
343
|
+
body: String,
|
|
344
|
+
observer: &JsObserver,
|
|
345
|
+
start_mjd: f64,
|
|
346
|
+
end_mjd: f64,
|
|
347
|
+
) -> napi::Result<Vec<AzimuthExtremum>> {
|
|
348
|
+
let kind = parse_body(&body)?;
|
|
349
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
350
|
+
let opts = SearchOpts::default();
|
|
351
|
+
let result = dispatch_body!(kind, |b| {
|
|
352
|
+
convert_az_extrema(azimuth::azimuth_extrema(
|
|
353
|
+
&b,
|
|
354
|
+
&observer.inner,
|
|
355
|
+
window,
|
|
356
|
+
opts,
|
|
357
|
+
))
|
|
358
|
+
});
|
|
359
|
+
Ok(result)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
363
|
+
// Star altitude — instantaneous
|
|
364
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
365
|
+
|
|
366
|
+
/// Compute the altitude of a catalog or custom star at a single instant.
|
|
367
|
+
///
|
|
368
|
+
/// @returns Altitude in degrees.
|
|
369
|
+
#[napi(js_name = "starAltitudeAt")]
|
|
370
|
+
pub fn star_altitude_at(star: &JsStar, observer: &JsObserver, mjd: f64) -> napi::Result<f64> {
|
|
371
|
+
if !mjd.is_finite() {
|
|
372
|
+
return Err(napi::Error::from_reason("mjd must be finite"));
|
|
373
|
+
}
|
|
374
|
+
let m = ModifiedJulianDate::new(mjd);
|
|
375
|
+
Ok(star
|
|
376
|
+
.inner
|
|
377
|
+
.altitude_at(&observer.inner, m)
|
|
378
|
+
.to::<Degree>()
|
|
379
|
+
.value())
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/// Compute the azimuth of a star at a single instant.
|
|
383
|
+
///
|
|
384
|
+
/// @returns Azimuth in degrees.
|
|
385
|
+
#[napi(js_name = "starAzimuthAt")]
|
|
386
|
+
pub fn star_azimuth_at(star: &JsStar, observer: &JsObserver, mjd: f64) -> napi::Result<f64> {
|
|
387
|
+
if !mjd.is_finite() {
|
|
388
|
+
return Err(napi::Error::from_reason("mjd must be finite"));
|
|
389
|
+
}
|
|
390
|
+
let m = ModifiedJulianDate::new(mjd);
|
|
391
|
+
Ok(star
|
|
392
|
+
.inner
|
|
393
|
+
.azimuth_at(&observer.inner, m)
|
|
394
|
+
.to::<Degree>()
|
|
395
|
+
.value())
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
399
|
+
// Star altitude — batch events
|
|
400
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
401
|
+
|
|
402
|
+
/// Find threshold-crossing events for a star.
|
|
403
|
+
#[napi(js_name = "starCrossings")]
|
|
404
|
+
pub fn star_crossings(
|
|
405
|
+
star: &JsStar,
|
|
406
|
+
observer: &JsObserver,
|
|
407
|
+
start_mjd: f64,
|
|
408
|
+
end_mjd: f64,
|
|
409
|
+
threshold_deg: f64,
|
|
410
|
+
) -> napi::Result<Vec<CrossingEvent>> {
|
|
411
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
412
|
+
let thr = Degrees::new(threshold_deg);
|
|
413
|
+
let opts = SearchOpts::default();
|
|
414
|
+
Ok(convert_crossings(altitude::crossings(
|
|
415
|
+
&star.inner,
|
|
416
|
+
&observer.inner,
|
|
417
|
+
window,
|
|
418
|
+
thr,
|
|
419
|
+
opts,
|
|
420
|
+
)))
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/// Find culmination events for a star.
|
|
424
|
+
#[napi(js_name = "starCulminations")]
|
|
425
|
+
pub fn star_culminations(
|
|
426
|
+
star: &JsStar,
|
|
427
|
+
observer: &JsObserver,
|
|
428
|
+
start_mjd: f64,
|
|
429
|
+
end_mjd: f64,
|
|
430
|
+
) -> napi::Result<Vec<CulminationEvent>> {
|
|
431
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
432
|
+
let opts = SearchOpts::default();
|
|
433
|
+
Ok(convert_culminations(altitude::culminations(
|
|
434
|
+
&star.inner,
|
|
435
|
+
&observer.inner,
|
|
436
|
+
window,
|
|
437
|
+
opts,
|
|
438
|
+
)))
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/// Find periods where a star's altitude is above a threshold.
|
|
442
|
+
#[napi(js_name = "starAboveThreshold")]
|
|
443
|
+
pub fn star_above_threshold(
|
|
444
|
+
star: &JsStar,
|
|
445
|
+
observer: &JsObserver,
|
|
446
|
+
start_mjd: f64,
|
|
447
|
+
end_mjd: f64,
|
|
448
|
+
threshold_deg: f64,
|
|
449
|
+
) -> napi::Result<Vec<MjdPeriod>> {
|
|
450
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
451
|
+
let thr = Degrees::new(threshold_deg);
|
|
452
|
+
let opts = SearchOpts::default();
|
|
453
|
+
Ok(convert_periods(altitude::above_threshold(
|
|
454
|
+
&star.inner,
|
|
455
|
+
&observer.inner,
|
|
456
|
+
window,
|
|
457
|
+
thr,
|
|
458
|
+
opts,
|
|
459
|
+
)))
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
/// Find periods where a star's altitude is below a threshold.
|
|
463
|
+
#[napi(js_name = "starBelowThreshold")]
|
|
464
|
+
pub fn star_below_threshold(
|
|
465
|
+
star: &JsStar,
|
|
466
|
+
observer: &JsObserver,
|
|
467
|
+
start_mjd: f64,
|
|
468
|
+
end_mjd: f64,
|
|
469
|
+
threshold_deg: f64,
|
|
470
|
+
) -> napi::Result<Vec<MjdPeriod>> {
|
|
471
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
472
|
+
let thr = Degrees::new(threshold_deg);
|
|
473
|
+
let opts = SearchOpts::default();
|
|
474
|
+
Ok(convert_periods(altitude::below_threshold(
|
|
475
|
+
&star.inner,
|
|
476
|
+
&observer.inner,
|
|
477
|
+
window,
|
|
478
|
+
thr,
|
|
479
|
+
opts,
|
|
480
|
+
)))
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
484
|
+
// Star azimuth — batch events
|
|
485
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
486
|
+
|
|
487
|
+
/// Find azimuth-crossing events for a star.
|
|
488
|
+
///
|
|
489
|
+
/// @param bearingDeg — Target azimuth bearing in degrees.
|
|
490
|
+
/// @returns Array of azimuth crossing events `{ mjd, direction }`.
|
|
491
|
+
#[napi(js_name = "starAzimuthCrossings")]
|
|
492
|
+
pub fn star_azimuth_crossings(
|
|
493
|
+
star: &JsStar,
|
|
494
|
+
observer: &JsObserver,
|
|
495
|
+
start_mjd: f64,
|
|
496
|
+
end_mjd: f64,
|
|
497
|
+
bearing_deg: f64,
|
|
498
|
+
) -> napi::Result<Vec<AzimuthCrossingEvent>> {
|
|
499
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
500
|
+
let bearing = Degrees::new(bearing_deg);
|
|
501
|
+
let opts = SearchOpts::default();
|
|
502
|
+
Ok(convert_az_crossings(azimuth::azimuth_crossings(
|
|
503
|
+
&star.inner,
|
|
504
|
+
&observer.inner,
|
|
505
|
+
window,
|
|
506
|
+
bearing,
|
|
507
|
+
opts,
|
|
508
|
+
)))
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/// Find azimuth extrema (max/min bearing) for a star.
|
|
512
|
+
///
|
|
513
|
+
/// @returns Array of azimuth extrema `{ mjd, azimuthDeg, kind }`.
|
|
514
|
+
#[napi(js_name = "starAzimuthExtrema")]
|
|
515
|
+
pub fn star_azimuth_extrema(
|
|
516
|
+
star: &JsStar,
|
|
517
|
+
observer: &JsObserver,
|
|
518
|
+
start_mjd: f64,
|
|
519
|
+
end_mjd: f64,
|
|
520
|
+
) -> napi::Result<Vec<AzimuthExtremum>> {
|
|
521
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
522
|
+
let opts = SearchOpts::default();
|
|
523
|
+
Ok(convert_az_extrema(azimuth::azimuth_extrema(
|
|
524
|
+
&star.inner,
|
|
525
|
+
&observer.inner,
|
|
526
|
+
window,
|
|
527
|
+
opts,
|
|
528
|
+
)))
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
532
|
+
// Period utilities
|
|
533
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
534
|
+
|
|
535
|
+
/// Intersect two lists of MJD periods, returning only overlapping intervals.
|
|
536
|
+
///
|
|
537
|
+
/// This is useful for combining altitude and azimuth constraints, or
|
|
538
|
+
/// combining target visibility with astronomical night periods.
|
|
539
|
+
///
|
|
540
|
+
/// @param periods1 — First list of MJD periods.
|
|
541
|
+
/// @param periods2 — Second list of MJD periods.
|
|
542
|
+
/// @returns Array of MJD periods representing the intersection.
|
|
543
|
+
///
|
|
544
|
+
/// ```js
|
|
545
|
+
/// const altPeriods = starAboveThreshold(star, obs, mjd0, mjd1, 25);
|
|
546
|
+
/// const azPeriods = bodyAboveThreshold('Sun', obs, mjd0, mjd1, -18); // dark sky
|
|
547
|
+
/// const observable = intersectPeriods(altPeriods, azPeriods);
|
|
548
|
+
/// ```
|
|
549
|
+
#[napi(js_name = "intersectPeriods")]
|
|
550
|
+
pub fn intersect_periods_js(
|
|
551
|
+
periods1: Vec<MjdPeriod>,
|
|
552
|
+
periods2: Vec<MjdPeriod>,
|
|
553
|
+
) -> Vec<MjdPeriod> {
|
|
554
|
+
let p1: Vec<Period<MJD>> = periods1
|
|
555
|
+
.iter()
|
|
556
|
+
.map(|p| Period::new(
|
|
557
|
+
ModifiedJulianDate::new(p.start_mjd),
|
|
558
|
+
ModifiedJulianDate::new(p.end_mjd),
|
|
559
|
+
))
|
|
560
|
+
.collect();
|
|
561
|
+
let p2: Vec<Period<MJD>> = periods2
|
|
562
|
+
.iter()
|
|
563
|
+
.map(|p| Period::new(
|
|
564
|
+
ModifiedJulianDate::new(p.start_mjd),
|
|
565
|
+
ModifiedJulianDate::new(p.end_mjd),
|
|
566
|
+
))
|
|
567
|
+
.collect();
|
|
568
|
+
|
|
569
|
+
let result = tempoch::intersect_periods(&p1, &p2);
|
|
570
|
+
result
|
|
571
|
+
.into_iter()
|
|
572
|
+
.map(|p| MjdPeriod {
|
|
573
|
+
start_mjd: p.start.value(),
|
|
574
|
+
end_mjd: p.end.value(),
|
|
575
|
+
})
|
|
576
|
+
.collect()
|
|
577
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Vallés Puig, Ramon
|
|
3
|
+
|
|
4
|
+
//! Node.js native bindings for **siderust** — high-precision astronomy.
|
|
5
|
+
//!
|
|
6
|
+
//! This crate uses `napi-rs` to expose siderust's core workflows as a
|
|
7
|
+
//! JavaScript/TypeScript-friendly API. All numerical computation stays in
|
|
8
|
+
//! Rust; the JS layer only sees high-level domain objects.
|
|
9
|
+
//!
|
|
10
|
+
//! ## Design principles
|
|
11
|
+
//!
|
|
12
|
+
//! * **Batch over chatty** — altitude/azimuth queries return arrays of events
|
|
13
|
+
//! in a single crossing, avoiding per-value FFI overhead.
|
|
14
|
+
//! * **Domain objects** — `Observer`, `Star`, `Body`, `CartesianPosition`, etc.
|
|
15
|
+
//! rather than raw numeric tuples.
|
|
16
|
+
//! * **Reuse conventions** — camelCase naming, `napi::Error` for exceptions,
|
|
17
|
+
//! MJD/JD as `f64` — consistent with `@siderust/tempoch` and `@siderust/qtty`.
|
|
18
|
+
|
|
19
|
+
#![deny(clippy::all)]
|
|
20
|
+
|
|
21
|
+
mod body;
|
|
22
|
+
mod coordinates;
|
|
23
|
+
mod ephemeris;
|
|
24
|
+
mod events;
|
|
25
|
+
mod observer;
|
|
26
|
+
mod phase;
|
|
27
|
+
mod position;
|
|
28
|
+
mod star;
|
|
29
|
+
|
|
30
|
+
pub use body::*;
|
|
31
|
+
pub use coordinates::*;
|
|
32
|
+
pub use ephemeris::*;
|
|
33
|
+
pub use events::*;
|
|
34
|
+
pub use observer::*;
|
|
35
|
+
pub use phase::*;
|
|
36
|
+
pub use position::*;
|
|
37
|
+
pub use star::*;
|
|
38
|
+
|
|
39
|
+
/// Return the siderust-node version string.
|
|
40
|
+
#[napi_derive::napi(js_name = "version")]
|
|
41
|
+
pub fn version() -> String {
|
|
42
|
+
env!("CARGO_PKG_VERSION").to_string()
|
|
43
|
+
}
|