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,190 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Vallés Puig, Ramon
|
|
3
|
+
|
|
4
|
+
//! Lunar phase queries — geometry, events, and illumination periods.
|
|
5
|
+
|
|
6
|
+
use serde::Serialize;
|
|
7
|
+
use wasm_bindgen::prelude::*;
|
|
8
|
+
|
|
9
|
+
use crate::body::to_js;
|
|
10
|
+
use crate::events::{make_window, MjdPeriod};
|
|
11
|
+
use crate::observer::Observer;
|
|
12
|
+
|
|
13
|
+
use qtty::*;
|
|
14
|
+
use siderust::calculus::ephemeris::Vsop87Ephemeris;
|
|
15
|
+
use siderust::calculus::lunar::phase::{
|
|
16
|
+
find_phase_events, illumination_above, illumination_below, illumination_range,
|
|
17
|
+
moon_phase_geocentric, moon_phase_topocentric, MoonPhaseLabel, PhaseSearchOpts,
|
|
18
|
+
};
|
|
19
|
+
use siderust::time::JulianDate;
|
|
20
|
+
|
|
21
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
22
|
+
// Result types
|
|
23
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
#[derive(Serialize)]
|
|
26
|
+
#[serde(rename_all = "camelCase")]
|
|
27
|
+
pub struct MoonPhase {
|
|
28
|
+
pub phase_angle_deg: f64,
|
|
29
|
+
pub illuminated_fraction: f64,
|
|
30
|
+
pub elongation_deg: f64,
|
|
31
|
+
pub waxing: bool,
|
|
32
|
+
pub label: String,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
#[derive(Serialize)]
|
|
36
|
+
#[serde(rename_all = "camelCase")]
|
|
37
|
+
pub struct PhaseEvent {
|
|
38
|
+
pub mjd: f64,
|
|
39
|
+
pub kind: String,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
// Phase geometry
|
|
44
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
/// Compute geocentric Moon phase geometry at a Julian Date.
|
|
47
|
+
#[wasm_bindgen(js_name = "moonPhase")]
|
|
48
|
+
pub fn moon_phase(jd: f64) -> Result<JsValue, JsError> {
|
|
49
|
+
if !jd.is_finite() {
|
|
50
|
+
return Err(JsError::new("jd must be finite"));
|
|
51
|
+
}
|
|
52
|
+
let geom = moon_phase_geocentric::<Vsop87Ephemeris>(JulianDate::new(jd));
|
|
53
|
+
let label = geom.label();
|
|
54
|
+
to_js(&MoonPhase {
|
|
55
|
+
phase_angle_deg: geom.phase_angle.to::<Degree>().value(),
|
|
56
|
+
illuminated_fraction: geom.illuminated_fraction,
|
|
57
|
+
elongation_deg: geom.elongation.to::<Degree>().value(),
|
|
58
|
+
waxing: geom.waxing,
|
|
59
|
+
label: label_to_string(label),
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Compute topocentric Moon phase geometry at a Julian Date for an observer.
|
|
64
|
+
#[wasm_bindgen(js_name = "moonPhaseTopocentric")]
|
|
65
|
+
pub fn moon_phase_topo(jd: f64, observer: &Observer) -> Result<JsValue, JsError> {
|
|
66
|
+
if !jd.is_finite() {
|
|
67
|
+
return Err(JsError::new("jd must be finite"));
|
|
68
|
+
}
|
|
69
|
+
let geom =
|
|
70
|
+
moon_phase_topocentric::<Vsop87Ephemeris>(JulianDate::new(jd), observer.inner.clone());
|
|
71
|
+
let label = geom.label();
|
|
72
|
+
to_js(&MoonPhase {
|
|
73
|
+
phase_angle_deg: geom.phase_angle.to::<Degree>().value(),
|
|
74
|
+
illuminated_fraction: geom.illuminated_fraction,
|
|
75
|
+
elongation_deg: geom.elongation.to::<Degree>().value(),
|
|
76
|
+
waxing: geom.waxing,
|
|
77
|
+
label: label_to_string(label),
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
82
|
+
// Phase event finding
|
|
83
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
84
|
+
|
|
85
|
+
/// Find all principal lunar phase events in a time window.
|
|
86
|
+
#[wasm_bindgen(js_name = "findPhaseEvents")]
|
|
87
|
+
pub fn find_phase_events_js(start_mjd: f64, end_mjd: f64) -> Result<JsValue, JsError> {
|
|
88
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
89
|
+
let events = find_phase_events::<Vsop87Ephemeris>(window, PhaseSearchOpts::default());
|
|
90
|
+
let out: Vec<PhaseEvent> = events
|
|
91
|
+
.into_iter()
|
|
92
|
+
.map(|e| PhaseEvent {
|
|
93
|
+
mjd: e.mjd.value(),
|
|
94
|
+
kind: phase_kind_to_string(e.kind),
|
|
95
|
+
})
|
|
96
|
+
.collect();
|
|
97
|
+
to_js(&out)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
101
|
+
// Illumination periods
|
|
102
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
/// Find periods where geocentric Moon illumination is above `kMin` ∈ [0, 1].
|
|
105
|
+
#[wasm_bindgen(js_name = "moonIlluminationAbove")]
|
|
106
|
+
pub fn moon_illumination_above(
|
|
107
|
+
start_mjd: f64,
|
|
108
|
+
end_mjd: f64,
|
|
109
|
+
k_min: f64,
|
|
110
|
+
) -> Result<JsValue, JsError> {
|
|
111
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
112
|
+
let periods = illumination_above::<Vsop87Ephemeris>(window, k_min, PhaseSearchOpts::default());
|
|
113
|
+
let out: Vec<MjdPeriod> = periods
|
|
114
|
+
.into_iter()
|
|
115
|
+
.map(|p| MjdPeriod {
|
|
116
|
+
start_mjd: p.start.value(),
|
|
117
|
+
end_mjd: p.end.value(),
|
|
118
|
+
})
|
|
119
|
+
.collect();
|
|
120
|
+
to_js(&out)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Find periods where geocentric Moon illumination is below `kMax` ∈ [0, 1].
|
|
124
|
+
#[wasm_bindgen(js_name = "moonIlluminationBelow")]
|
|
125
|
+
pub fn moon_illumination_below(
|
|
126
|
+
start_mjd: f64,
|
|
127
|
+
end_mjd: f64,
|
|
128
|
+
k_max: f64,
|
|
129
|
+
) -> Result<JsValue, JsError> {
|
|
130
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
131
|
+
let periods = illumination_below::<Vsop87Ephemeris>(window, k_max, PhaseSearchOpts::default());
|
|
132
|
+
let out: Vec<MjdPeriod> = periods
|
|
133
|
+
.into_iter()
|
|
134
|
+
.map(|p| MjdPeriod {
|
|
135
|
+
start_mjd: p.start.value(),
|
|
136
|
+
end_mjd: p.end.value(),
|
|
137
|
+
})
|
|
138
|
+
.collect();
|
|
139
|
+
to_js(&out)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/// Find periods where geocentric Moon illumination is in `[kMin, kMax]`.
|
|
143
|
+
#[wasm_bindgen(js_name = "moonIlluminationRange")]
|
|
144
|
+
pub fn moon_illumination_range(
|
|
145
|
+
start_mjd: f64,
|
|
146
|
+
end_mjd: f64,
|
|
147
|
+
k_min: f64,
|
|
148
|
+
k_max: f64,
|
|
149
|
+
) -> Result<JsValue, JsError> {
|
|
150
|
+
let window = make_window(start_mjd, end_mjd)?;
|
|
151
|
+
let periods =
|
|
152
|
+
illumination_range::<Vsop87Ephemeris>(window, k_min, k_max, PhaseSearchOpts::default());
|
|
153
|
+
let out: Vec<MjdPeriod> = periods
|
|
154
|
+
.into_iter()
|
|
155
|
+
.map(|p| MjdPeriod {
|
|
156
|
+
start_mjd: p.start.value(),
|
|
157
|
+
end_mjd: p.end.value(),
|
|
158
|
+
})
|
|
159
|
+
.collect();
|
|
160
|
+
to_js(&out)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
164
|
+
// Helpers
|
|
165
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
166
|
+
|
|
167
|
+
fn label_to_string(label: MoonPhaseLabel) -> String {
|
|
168
|
+
match label {
|
|
169
|
+
MoonPhaseLabel::NewMoon => "NewMoon",
|
|
170
|
+
MoonPhaseLabel::WaxingCrescent => "WaxingCrescent",
|
|
171
|
+
MoonPhaseLabel::FirstQuarter => "FirstQuarter",
|
|
172
|
+
MoonPhaseLabel::WaxingGibbous => "WaxingGibbous",
|
|
173
|
+
MoonPhaseLabel::FullMoon => "FullMoon",
|
|
174
|
+
MoonPhaseLabel::WaningGibbous => "WaningGibbous",
|
|
175
|
+
MoonPhaseLabel::LastQuarter => "LastQuarter",
|
|
176
|
+
MoonPhaseLabel::WaningCrescent => "WaningCrescent",
|
|
177
|
+
}
|
|
178
|
+
.to_string()
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
fn phase_kind_to_string(kind: siderust::calculus::lunar::phase::PhaseKind) -> String {
|
|
182
|
+
use siderust::calculus::lunar::phase::PhaseKind;
|
|
183
|
+
match kind {
|
|
184
|
+
PhaseKind::NewMoon => "NewMoon",
|
|
185
|
+
PhaseKind::FirstQuarter => "FirstQuarter",
|
|
186
|
+
PhaseKind::FullMoon => "FullMoon",
|
|
187
|
+
PhaseKind::LastQuarter => "LastQuarter",
|
|
188
|
+
}
|
|
189
|
+
.to_string()
|
|
190
|
+
}
|
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Vallés Puig, Ramon
|
|
3
|
+
|
|
4
|
+
//! Cartesian position type for WebAssembly bindings.
|
|
5
|
+
|
|
6
|
+
use serde::Serialize;
|
|
7
|
+
use wasm_bindgen::prelude::*;
|
|
8
|
+
|
|
9
|
+
// Frame and center string constants
|
|
10
|
+
pub const FRAME_ECL: &str = "EclipticMeanJ2000";
|
|
11
|
+
pub const FRAME_EQ: &str = "EquatorialMeanJ2000";
|
|
12
|
+
pub const FRAME_ICRS: &str = "ICRS";
|
|
13
|
+
|
|
14
|
+
pub const CENTER_BARY: &str = "Barycentric";
|
|
15
|
+
pub const CENTER_HELIO: &str = "Heliocentric";
|
|
16
|
+
pub const CENTER_GEO: &str = "Geocentric";
|
|
17
|
+
|
|
18
|
+
pub const UNIT_AU: &str = "au";
|
|
19
|
+
pub const UNIT_KM: &str = "km";
|
|
20
|
+
|
|
21
|
+
/// A 3D cartesian position with frame, center, and unit metadata.
|
|
22
|
+
#[wasm_bindgen]
|
|
23
|
+
#[derive(Clone, Serialize)]
|
|
24
|
+
pub struct Position {
|
|
25
|
+
x: f64,
|
|
26
|
+
y: f64,
|
|
27
|
+
z: f64,
|
|
28
|
+
frame: String,
|
|
29
|
+
center: String,
|
|
30
|
+
unit: String,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
#[wasm_bindgen]
|
|
34
|
+
impl Position {
|
|
35
|
+
/// Create a new position with explicit coordinates, frame, center, and unit.
|
|
36
|
+
#[wasm_bindgen(constructor)]
|
|
37
|
+
pub fn new(
|
|
38
|
+
x: f64,
|
|
39
|
+
y: f64,
|
|
40
|
+
z: f64,
|
|
41
|
+
frame: String,
|
|
42
|
+
center: String,
|
|
43
|
+
unit: String,
|
|
44
|
+
) -> Result<Position, JsError> {
|
|
45
|
+
validate_frame(&frame)?;
|
|
46
|
+
validate_center(¢er)?;
|
|
47
|
+
validate_unit(&unit)?;
|
|
48
|
+
Ok(Self { x, y, z, frame, center, unit })
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// X coordinate.
|
|
52
|
+
#[wasm_bindgen(getter)]
|
|
53
|
+
pub fn x(&self) -> f64 {
|
|
54
|
+
self.x
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/// Y coordinate.
|
|
58
|
+
#[wasm_bindgen(getter)]
|
|
59
|
+
pub fn y(&self) -> f64 {
|
|
60
|
+
self.y
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/// Z coordinate.
|
|
64
|
+
#[wasm_bindgen(getter)]
|
|
65
|
+
pub fn z(&self) -> f64 {
|
|
66
|
+
self.z
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/// Reference frame (e.g., "EclipticMeanJ2000", "ICRS").
|
|
70
|
+
#[wasm_bindgen(getter)]
|
|
71
|
+
pub fn frame(&self) -> String {
|
|
72
|
+
self.frame.clone()
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/// Coordinate center (e.g., "Barycentric", "Heliocentric", "Geocentric").
|
|
76
|
+
#[wasm_bindgen(getter)]
|
|
77
|
+
pub fn center(&self) -> String {
|
|
78
|
+
self.center.clone()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// Distance unit ("au" or "km").
|
|
82
|
+
#[wasm_bindgen(getter)]
|
|
83
|
+
pub fn unit(&self) -> String {
|
|
84
|
+
self.unit.clone()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Euclidean distance from origin.
|
|
88
|
+
#[wasm_bindgen]
|
|
89
|
+
pub fn magnitude(&self) -> f64 {
|
|
90
|
+
(self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/// Subtract another position to get a displacement vector.
|
|
94
|
+
#[wasm_bindgen]
|
|
95
|
+
pub fn subtract(&self, other: &Position) -> Result<Displacement, JsError> {
|
|
96
|
+
if self.frame != other.frame {
|
|
97
|
+
return Err(JsError::new(&format!(
|
|
98
|
+
"Cannot subtract positions in different frames: '{}' vs '{}'",
|
|
99
|
+
self.frame, other.frame
|
|
100
|
+
)));
|
|
101
|
+
}
|
|
102
|
+
if self.center != other.center {
|
|
103
|
+
return Err(JsError::new(&format!(
|
|
104
|
+
"Cannot subtract positions with different centers: '{}' vs '{}'",
|
|
105
|
+
self.center, other.center
|
|
106
|
+
)));
|
|
107
|
+
}
|
|
108
|
+
if self.unit != other.unit {
|
|
109
|
+
return Err(JsError::new(&format!(
|
|
110
|
+
"Cannot subtract positions with different units: '{}' vs '{}'",
|
|
111
|
+
self.unit, other.unit
|
|
112
|
+
)));
|
|
113
|
+
}
|
|
114
|
+
Ok(Displacement {
|
|
115
|
+
dx: self.x - other.x,
|
|
116
|
+
dy: self.y - other.y,
|
|
117
|
+
dz: self.z - other.z,
|
|
118
|
+
frame: self.frame.clone(),
|
|
119
|
+
unit: self.unit.clone(),
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/// Add a displacement to get a new position.
|
|
124
|
+
#[wasm_bindgen(js_name = "addDisplacement")]
|
|
125
|
+
pub fn add_displacement(&self, d: &Displacement) -> Result<Position, JsError> {
|
|
126
|
+
if self.frame != d.frame {
|
|
127
|
+
return Err(JsError::new(&format!(
|
|
128
|
+
"Cannot add displacement in different frame: '{}' vs '{}'",
|
|
129
|
+
self.frame, d.frame
|
|
130
|
+
)));
|
|
131
|
+
}
|
|
132
|
+
if self.unit != d.unit {
|
|
133
|
+
return Err(JsError::new(&format!(
|
|
134
|
+
"Cannot add displacement with different unit: '{}' vs '{}'",
|
|
135
|
+
self.unit, d.unit
|
|
136
|
+
)));
|
|
137
|
+
}
|
|
138
|
+
Ok(Position {
|
|
139
|
+
x: self.x + d.dx,
|
|
140
|
+
y: self.y + d.dy,
|
|
141
|
+
z: self.z + d.dz,
|
|
142
|
+
frame: self.frame.clone(),
|
|
143
|
+
center: self.center.clone(),
|
|
144
|
+
unit: self.unit.clone(),
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
impl Position {
|
|
150
|
+
/// Internal constructor without validation (for Rust callers).
|
|
151
|
+
pub(crate) fn new_internal(
|
|
152
|
+
x: f64,
|
|
153
|
+
y: f64,
|
|
154
|
+
z: f64,
|
|
155
|
+
frame: &str,
|
|
156
|
+
center: &str,
|
|
157
|
+
unit: &str,
|
|
158
|
+
) -> Self {
|
|
159
|
+
Self {
|
|
160
|
+
x,
|
|
161
|
+
y,
|
|
162
|
+
z,
|
|
163
|
+
frame: frame.to_string(),
|
|
164
|
+
center: center.to_string(),
|
|
165
|
+
unit: unit.to_string(),
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// A displacement vector (difference between two positions).
|
|
171
|
+
#[wasm_bindgen]
|
|
172
|
+
#[derive(Clone, Serialize)]
|
|
173
|
+
pub struct Displacement {
|
|
174
|
+
dx: f64,
|
|
175
|
+
dy: f64,
|
|
176
|
+
dz: f64,
|
|
177
|
+
frame: String,
|
|
178
|
+
unit: String,
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
#[wasm_bindgen]
|
|
182
|
+
impl Displacement {
|
|
183
|
+
/// Create a new displacement.
|
|
184
|
+
#[wasm_bindgen(constructor)]
|
|
185
|
+
pub fn new(
|
|
186
|
+
dx: f64,
|
|
187
|
+
dy: f64,
|
|
188
|
+
dz: f64,
|
|
189
|
+
frame: String,
|
|
190
|
+
unit: String,
|
|
191
|
+
) -> Result<Displacement, JsError> {
|
|
192
|
+
validate_frame(&frame)?;
|
|
193
|
+
validate_unit(&unit)?;
|
|
194
|
+
Ok(Self { dx, dy, dz, frame, unit })
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/// X component of displacement.
|
|
198
|
+
#[wasm_bindgen(getter)]
|
|
199
|
+
pub fn dx(&self) -> f64 {
|
|
200
|
+
self.dx
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/// Y component of displacement.
|
|
204
|
+
#[wasm_bindgen(getter)]
|
|
205
|
+
pub fn dy(&self) -> f64 {
|
|
206
|
+
self.dy
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/// Z component of displacement.
|
|
210
|
+
#[wasm_bindgen(getter)]
|
|
211
|
+
pub fn dz(&self) -> f64 {
|
|
212
|
+
self.dz
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/// Reference frame.
|
|
216
|
+
#[wasm_bindgen(getter)]
|
|
217
|
+
pub fn frame(&self) -> String {
|
|
218
|
+
self.frame.clone()
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/// Distance unit.
|
|
222
|
+
#[wasm_bindgen(getter)]
|
|
223
|
+
pub fn unit(&self) -> String {
|
|
224
|
+
self.unit.clone()
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/// Euclidean magnitude.
|
|
228
|
+
#[wasm_bindgen]
|
|
229
|
+
pub fn magnitude(&self) -> f64 {
|
|
230
|
+
(self.dx * self.dx + self.dy * self.dy + self.dz * self.dz).sqrt()
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/// Scale displacement by a factor.
|
|
234
|
+
#[wasm_bindgen]
|
|
235
|
+
pub fn scale(&self, factor: f64) -> Displacement {
|
|
236
|
+
Displacement {
|
|
237
|
+
dx: self.dx * factor,
|
|
238
|
+
dy: self.dy * factor,
|
|
239
|
+
dz: self.dz * factor,
|
|
240
|
+
frame: self.frame.clone(),
|
|
241
|
+
unit: self.unit.clone(),
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/// Add another displacement.
|
|
246
|
+
#[wasm_bindgen]
|
|
247
|
+
pub fn add(&self, other: &Displacement) -> Result<Displacement, JsError> {
|
|
248
|
+
if self.frame != other.frame || self.unit != other.unit {
|
|
249
|
+
return Err(JsError::new(
|
|
250
|
+
"Cannot add displacements with different frame/unit",
|
|
251
|
+
));
|
|
252
|
+
}
|
|
253
|
+
Ok(Displacement {
|
|
254
|
+
dx: self.dx + other.dx,
|
|
255
|
+
dy: self.dy + other.dy,
|
|
256
|
+
dz: self.dz + other.dz,
|
|
257
|
+
frame: self.frame.clone(),
|
|
258
|
+
unit: self.unit.clone(),
|
|
259
|
+
})
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
fn validate_frame(f: &str) -> Result<(), JsError> {
|
|
264
|
+
match f {
|
|
265
|
+
FRAME_ECL | FRAME_EQ | FRAME_ICRS | "ICRF" | "EquatorialMeanOfDate" | "EquatorialTrueOfDate" => Ok(()),
|
|
266
|
+
_ => Err(JsError::new(&format!(
|
|
267
|
+
"Unknown frame '{}'. Valid: EclipticMeanJ2000, EquatorialMeanJ2000, ICRS, ICRF",
|
|
268
|
+
f
|
|
269
|
+
))),
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fn validate_center(c: &str) -> Result<(), JsError> {
|
|
274
|
+
match c {
|
|
275
|
+
CENTER_BARY | CENTER_HELIO | CENTER_GEO => Ok(()),
|
|
276
|
+
_ => Err(JsError::new(&format!(
|
|
277
|
+
"Unknown center '{}'. Valid: Barycentric, Heliocentric, Geocentric",
|
|
278
|
+
c
|
|
279
|
+
))),
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
fn validate_unit(u: &str) -> Result<(), JsError> {
|
|
284
|
+
match u {
|
|
285
|
+
UNIT_AU | UNIT_KM => Ok(()),
|
|
286
|
+
_ => Err(JsError::new(&format!(
|
|
287
|
+
"Unknown unit '{}'. Valid: au, km",
|
|
288
|
+
u
|
|
289
|
+
))),
|
|
290
|
+
}
|
|
291
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Vallés Puig, Ramon
|
|
3
|
+
|
|
4
|
+
//! Star — catalog and custom stars for altitude/azimuth/coordinate queries.
|
|
5
|
+
|
|
6
|
+
use wasm_bindgen::prelude::*;
|
|
7
|
+
|
|
8
|
+
use qtty::length::nominal::SolarRadiuses;
|
|
9
|
+
use qtty::*;
|
|
10
|
+
use siderust::bodies::{self, Star as SiderustStar};
|
|
11
|
+
use siderust::coordinates::centers::Geocentric;
|
|
12
|
+
use siderust::coordinates::frames::EquatorialMeanJ2000;
|
|
13
|
+
use siderust::coordinates::spherical;
|
|
14
|
+
use siderust::targets::CoordinateWithPM;
|
|
15
|
+
use siderust::time::JulianDate;
|
|
16
|
+
use std::borrow::Cow;
|
|
17
|
+
|
|
18
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
19
|
+
// Star class
|
|
20
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
/// A star with physical parameters and sky coordinates.
|
|
23
|
+
#[wasm_bindgen]
|
|
24
|
+
pub struct Star {
|
|
25
|
+
pub(crate) inner: SiderustStar<'static>,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
#[wasm_bindgen]
|
|
29
|
+
impl Star {
|
|
30
|
+
/// Create a custom star.
|
|
31
|
+
///
|
|
32
|
+
/// @param name — Display name.
|
|
33
|
+
/// @param distanceLy — Distance in light-years.
|
|
34
|
+
/// @param massSolar — Mass in solar masses (M☉).
|
|
35
|
+
/// @param radiusSolar — Radius in solar radii (R☉).
|
|
36
|
+
/// @param luminositySolar — Luminosity in solar luminosities (L☉).
|
|
37
|
+
/// @param raDeg — Right ascension at J2000.0 in degrees.
|
|
38
|
+
/// @param decDeg — Declination at J2000.0 in degrees.
|
|
39
|
+
#[wasm_bindgen(constructor)]
|
|
40
|
+
pub fn new(
|
|
41
|
+
name: &str,
|
|
42
|
+
distance_ly: f64,
|
|
43
|
+
mass_solar: f64,
|
|
44
|
+
radius_solar: f64,
|
|
45
|
+
luminosity_solar: f64,
|
|
46
|
+
ra_deg: f64,
|
|
47
|
+
dec_deg: f64,
|
|
48
|
+
) -> Result<Star, JsError> {
|
|
49
|
+
for (label, v) in [
|
|
50
|
+
("distanceLy", distance_ly),
|
|
51
|
+
("massSolar", mass_solar),
|
|
52
|
+
("radiusSolar", radius_solar),
|
|
53
|
+
("luminositySolar", luminosity_solar),
|
|
54
|
+
("raDeg", ra_deg),
|
|
55
|
+
("decDeg", dec_deg),
|
|
56
|
+
] {
|
|
57
|
+
if !v.is_finite() {
|
|
58
|
+
return Err(JsError::new(&format!(
|
|
59
|
+
"{label} must be finite (not NaN or ±infinity)"
|
|
60
|
+
)));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
let pos = spherical::Position::<Geocentric, EquatorialMeanJ2000, LightYear>::new(
|
|
65
|
+
Degrees::new(ra_deg),
|
|
66
|
+
Degrees::new(dec_deg),
|
|
67
|
+
LightYears::new(distance_ly),
|
|
68
|
+
);
|
|
69
|
+
let target =
|
|
70
|
+
CoordinateWithPM::<spherical::Position<Geocentric, EquatorialMeanJ2000, LightYear>>::new_static(
|
|
71
|
+
pos,
|
|
72
|
+
JulianDate::J2000,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
let star = SiderustStar::new(
|
|
76
|
+
Cow::<'static, str>::Owned(name.to_string()),
|
|
77
|
+
LightYears::new(distance_ly),
|
|
78
|
+
SolarMasses::new(mass_solar),
|
|
79
|
+
SolarRadiuses::new(radius_solar),
|
|
80
|
+
SolarLuminosities::new(luminosity_solar),
|
|
81
|
+
target,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
Ok(Self { inner: star })
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/// Look up a star from the built-in catalog by name.
|
|
88
|
+
///
|
|
89
|
+
/// Supported names (case-insensitive): Vega, Sirius, Polaris, Canopus,
|
|
90
|
+
/// Arcturus, Rigel, Betelgeuse, Procyon, Aldebaran, Altair.
|
|
91
|
+
pub fn catalog(name: &str) -> Result<Star, JsError> {
|
|
92
|
+
let star: &SiderustStar<'static> = match name.to_uppercase().as_str() {
|
|
93
|
+
"VEGA" => &bodies::VEGA,
|
|
94
|
+
"SIRIUS" => &bodies::SIRIUS,
|
|
95
|
+
"POLARIS" => &bodies::POLARIS,
|
|
96
|
+
"CANOPUS" => &bodies::CANOPUS,
|
|
97
|
+
"ARCTURUS" => &bodies::ARCTURUS,
|
|
98
|
+
"RIGEL" => &bodies::RIGEL,
|
|
99
|
+
"BETELGEUSE" => &bodies::BETELGEUSE,
|
|
100
|
+
"PROCYON" => &bodies::PROCYON,
|
|
101
|
+
"ALDEBARAN" => &bodies::ALDEBARAN,
|
|
102
|
+
"ALTAIR" => &bodies::ALTAIR,
|
|
103
|
+
_ => {
|
|
104
|
+
return Err(JsError::new(&format!(
|
|
105
|
+
"Unknown catalog star: \"{name}\". Available: Vega, Sirius, Polaris, Canopus, Arcturus, Rigel, Betelgeuse, Procyon, Aldebaran, Altair."
|
|
106
|
+
)));
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
Ok(Self {
|
|
110
|
+
inner: star.clone(),
|
|
111
|
+
})
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ── accessors ────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
/// Star name.
|
|
117
|
+
#[wasm_bindgen(getter)]
|
|
118
|
+
pub fn name(&self) -> String {
|
|
119
|
+
self.inner.name.to_string()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// Distance in light-years.
|
|
123
|
+
#[wasm_bindgen(getter, js_name = "distanceLy")]
|
|
124
|
+
pub fn distance_ly(&self) -> f64 {
|
|
125
|
+
self.inner.distance.value()
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/// Mass in solar masses (M☉).
|
|
129
|
+
#[wasm_bindgen(getter, js_name = "massSolar")]
|
|
130
|
+
pub fn mass_solar(&self) -> f64 {
|
|
131
|
+
self.inner.mass.value()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/// Radius in solar radii (R☉).
|
|
135
|
+
#[wasm_bindgen(getter, js_name = "radiusSolar")]
|
|
136
|
+
pub fn radius_solar(&self) -> f64 {
|
|
137
|
+
self.inner.radius.value()
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/// Luminosity in solar luminosities (L☉).
|
|
141
|
+
#[wasm_bindgen(getter, js_name = "luminositySolar")]
|
|
142
|
+
pub fn luminosity_solar(&self) -> f64 {
|
|
143
|
+
self.inner.luminosity.value()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/// Right ascension at J2000.0 in degrees.
|
|
147
|
+
#[wasm_bindgen(getter, js_name = "raDeg")]
|
|
148
|
+
pub fn ra_deg(&self) -> f64 {
|
|
149
|
+
self.inner.coordinate.get_position().azimuth.value()
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/// Declination at J2000.0 in degrees.
|
|
153
|
+
#[wasm_bindgen(getter, js_name = "decDeg")]
|
|
154
|
+
pub fn dec_deg(&self) -> f64 {
|
|
155
|
+
self.inner.coordinate.get_position().polar.value()
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/// Human-readable representation.
|
|
159
|
+
pub fn format(&self) -> String {
|
|
160
|
+
format!(
|
|
161
|
+
"Star({}, d={:.1} ly, RA={:.4}°, Dec={:.4}°)",
|
|
162
|
+
self.inner.name,
|
|
163
|
+
self.inner.distance.value(),
|
|
164
|
+
self.inner.coordinate.get_position().azimuth.value(),
|
|
165
|
+
self.inner.coordinate.get_position().polar.value(),
|
|
166
|
+
)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/// List all catalog star names.
|
|
171
|
+
#[wasm_bindgen(js_name = "listCatalogStars")]
|
|
172
|
+
pub fn list_catalog_stars() -> JsValue {
|
|
173
|
+
let names: Vec<&str> = vec![
|
|
174
|
+
"Vega", "Sirius", "Polaris", "Canopus", "Arcturus", "Rigel", "Betelgeuse", "Procyon",
|
|
175
|
+
"Aldebaran", "Altair",
|
|
176
|
+
];
|
|
177
|
+
serde_wasm_bindgen::to_value(&names).unwrap()
|
|
178
|
+
}
|