Add mass driver station system with Lagrange point placement
- Lagrange point computation (L1-L5) for any Sun-planet pair in Rust - Station generation: auto-place at Lagrange points by priority (inner → outer planets) - Station panel UI: count slider (5-50), launch velocity slider (5-100 km/s) with info tooltip - Blue diamond markers on 2D canvas with labels when zoomed in - Active station list in sidebar (Earth L1, Mars L2, Jupiter L4, etc.) - WASM API: generate_stations(), get_station_positions(), get_station_names() - Station positions update every frame (co-rotating with planets at Lagrange points) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
105
crates/orbital-mechanics/src/lagrange.rs
Normal file
105
crates/orbital-mechanics/src/lagrange.rs
Normal file
@@ -0,0 +1,105 @@
|
||||
use crate::bodies::CelestialBody;
|
||||
use crate::constants::*;
|
||||
use crate::orbits::position_at_epoch;
|
||||
use nalgebra::Vector3;
|
||||
|
||||
/// Approximate position of a Lagrange point for a Sun-planet system.
|
||||
///
|
||||
/// L1: Between Sun and planet (closer to planet)
|
||||
/// L2: Beyond planet (away from Sun)
|
||||
/// L3: Opposite side of Sun from planet
|
||||
/// L4: 60° ahead of planet in its orbit
|
||||
/// L5: 60° behind of planet in its orbit
|
||||
///
|
||||
/// Returns position in AU, ecliptic coordinates.
|
||||
pub fn lagrange_point_position(
|
||||
bodies: &[CelestialBody],
|
||||
planet_id: usize,
|
||||
point: u8, // 1-5
|
||||
jd: f64,
|
||||
) -> Vector3<f64> {
|
||||
let planet_pos = position_at_epoch(bodies, planet_id, jd);
|
||||
let sun_pos = Vector3::zeros();
|
||||
|
||||
let r = planet_pos.norm(); // Distance from Sun
|
||||
if r < 1e-10 {
|
||||
return sun_pos;
|
||||
}
|
||||
|
||||
let planet = &bodies[planet_id];
|
||||
// Mass ratio: mu = m_planet / (m_sun + m_planet)
|
||||
let mu = planet.mu / (MU_SUN + planet.mu);
|
||||
|
||||
// Hill sphere radius approximation
|
||||
let r_hill = r * (mu / 3.0).powf(1.0 / 3.0);
|
||||
|
||||
// Unit vector from Sun to planet
|
||||
let u = planet_pos / r;
|
||||
// Perpendicular in ecliptic plane (rotate 90° CCW)
|
||||
let u_perp = Vector3::new(-u.y, u.x, 0.0);
|
||||
|
||||
match point {
|
||||
1 => {
|
||||
// L1: between Sun and planet, distance r_hill inside planet orbit
|
||||
planet_pos - u * r_hill
|
||||
}
|
||||
2 => {
|
||||
// L2: beyond planet, distance r_hill outside planet orbit
|
||||
planet_pos + u * r_hill
|
||||
}
|
||||
3 => {
|
||||
// L3: opposite side of Sun, approximately at planet's orbital radius
|
||||
-planet_pos * (1.0 + 5.0 * mu / 12.0)
|
||||
}
|
||||
4 => {
|
||||
// L4: 60° ahead of planet (leading)
|
||||
let angle = std::f64::consts::FRAC_PI_3; // 60°
|
||||
let cos_a = angle.cos();
|
||||
let sin_a = angle.sin();
|
||||
(u * cos_a + u_perp * sin_a) * r
|
||||
}
|
||||
5 => {
|
||||
// L5: 60° behind planet (trailing)
|
||||
let angle = std::f64::consts::FRAC_PI_3;
|
||||
let cos_a = angle.cos();
|
||||
let sin_a = angle.sin();
|
||||
(u * cos_a - u_perp * sin_a) * r
|
||||
}
|
||||
_ => sun_pos,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::bodies::all_bodies;
|
||||
|
||||
#[test]
|
||||
fn test_l1_between_sun_and_planet() {
|
||||
let bodies = all_bodies();
|
||||
let earth_pos = position_at_epoch(&bodies, bodies::id::EARTH, J2000_JD);
|
||||
let l1 = lagrange_point_position(&bodies, bodies::id::EARTH, 1, J2000_JD);
|
||||
|
||||
// L1 should be between Sun (0,0,0) and Earth
|
||||
let l1_dist = l1.norm();
|
||||
let earth_dist = earth_pos.norm();
|
||||
assert!(l1_dist < earth_dist, "L1 should be closer to Sun than Earth");
|
||||
assert!(l1_dist > 0.9, "L1 should be close to 1 AU");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_l4_l5_equilateral() {
|
||||
let bodies = all_bodies();
|
||||
let earth_pos = position_at_epoch(&bodies, bodies::id::EARTH, J2000_JD);
|
||||
let l4 = lagrange_point_position(&bodies, bodies::id::EARTH, 4, J2000_JD);
|
||||
let l5 = lagrange_point_position(&bodies, bodies::id::EARTH, 5, J2000_JD);
|
||||
|
||||
let earth_r = earth_pos.norm();
|
||||
let l4_r = l4.norm();
|
||||
let l5_r = l5.norm();
|
||||
|
||||
// L4 and L5 should be at roughly the same distance as the planet
|
||||
assert!((l4_r - earth_r).abs() < 0.01);
|
||||
assert!((l5_r - earth_r).abs() < 0.01);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod bodies;
|
||||
pub mod constants;
|
||||
pub mod kepler;
|
||||
pub mod lagrange;
|
||||
pub mod orbits;
|
||||
|
||||
pub use nalgebra::Vector3;
|
||||
|
||||
Reference in New Issue
Block a user