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:
@@ -1,3 +1,8 @@
|
||||
use orbital_mechanics::bodies;
|
||||
use orbital_mechanics::bodies::CelestialBody;
|
||||
use orbital_mechanics::lagrange;
|
||||
use orbital_mechanics::orbits;
|
||||
use nalgebra::Vector3;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// How a station is placed in the solar system.
|
||||
@@ -12,29 +17,13 @@ pub enum StationPlacement {
|
||||
w: f64, // Argument of perihelion (degrees)
|
||||
m0: f64, // Mean anomaly at epoch (degrees)
|
||||
},
|
||||
/// Station in orbit around a planet
|
||||
PlanetaryOrbit {
|
||||
parent_body_id: usize,
|
||||
altitude_km: f64,
|
||||
inclination: f64,
|
||||
},
|
||||
/// Station at a Lagrange point
|
||||
LagrangePoint {
|
||||
primary_body_id: usize, // e.g., Sun
|
||||
secondary_body_id: usize, // e.g., Earth
|
||||
point: LagrangePointId,
|
||||
planet_id: usize,
|
||||
point: u8, // 1-5
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum LagrangePointId {
|
||||
L1,
|
||||
L2,
|
||||
L3,
|
||||
L4,
|
||||
L5,
|
||||
}
|
||||
|
||||
/// A mass driver relay station.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Station {
|
||||
@@ -42,3 +31,116 @@ pub struct Station {
|
||||
pub name: String,
|
||||
pub placement: StationPlacement,
|
||||
}
|
||||
|
||||
/// Simulation configuration for mass driver network.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SimConfig {
|
||||
pub stations: Vec<Station>,
|
||||
pub launch_velocity_kms: f64, // km/s
|
||||
}
|
||||
|
||||
/// Compute position of a station at a given Julian Date.
|
||||
pub fn station_position(
|
||||
station: &Station,
|
||||
all_bodies: &[CelestialBody],
|
||||
jd: f64,
|
||||
) -> Vector3<f64> {
|
||||
match &station.placement {
|
||||
StationPlacement::SolarOrbit { a, e, i, omega, w, m0 } => {
|
||||
// Treat station as a body with fixed elements
|
||||
let body = CelestialBody {
|
||||
name: "station",
|
||||
id: 999,
|
||||
mu: 0.0,
|
||||
radius_km: 0.0,
|
||||
elements: orbital_mechanics::bodies::KeplerianElements {
|
||||
a: *a,
|
||||
e: *e,
|
||||
i: *i,
|
||||
l: *m0 + *w + *omega, // mean longitude = M + w + Omega
|
||||
w_bar: *w + *omega, // longitude of perihelion
|
||||
omega: *omega,
|
||||
},
|
||||
rates: orbital_mechanics::bodies::KeplerianRates {
|
||||
a: 0.0, e: 0.0, i: 0.0,
|
||||
// Mean longitude rate from Kepler's third law: n = sqrt(mu/a^3) in deg/century
|
||||
l: (orbital_mechanics::constants::MU_SUN
|
||||
/ (*a * orbital_mechanics::constants::AU_KM).powi(3))
|
||||
.sqrt()
|
||||
* orbital_mechanics::constants::SECONDS_PER_DAY
|
||||
* orbital_mechanics::constants::DAYS_PER_CENTURY
|
||||
* (180.0 / std::f64::consts::PI),
|
||||
w_bar: 0.0,
|
||||
omega: 0.0,
|
||||
},
|
||||
color: [255, 255, 255],
|
||||
};
|
||||
// Use a temporary slice with just Sun + this station
|
||||
let temp = vec![all_bodies[0].clone(), body];
|
||||
orbits::position_at_epoch(&temp, 1, jd)
|
||||
}
|
||||
StationPlacement::LagrangePoint { planet_id, point } => {
|
||||
lagrange::lagrange_point_position(all_bodies, *planet_id, *point, jd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute positions of all stations. Returns flat [x,y,z, x,y,z, ...] in AU.
|
||||
pub fn all_station_positions(
|
||||
stations: &[Station],
|
||||
all_bodies: &[CelestialBody],
|
||||
jd: f64,
|
||||
) -> Vec<f64> {
|
||||
let mut result = Vec::with_capacity(stations.len() * 3);
|
||||
for station in stations {
|
||||
let pos = station_position(station, all_bodies, jd);
|
||||
result.push(pos.x);
|
||||
result.push(pos.y);
|
||||
result.push(pos.z);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Generate a default set of stations for a given target count.
|
||||
/// Places stations at key Lagrange points of the major planets.
|
||||
pub fn generate_default_stations(target_count: usize) -> Vec<Station> {
|
||||
let mut stations = Vec::new();
|
||||
let mut id = 0;
|
||||
|
||||
// Priority order: inner planets first, then outer
|
||||
let planet_priority = [
|
||||
(bodies::id::EARTH, "Earth"),
|
||||
(bodies::id::MARS, "Mars"),
|
||||
(bodies::id::VENUS, "Venus"),
|
||||
(bodies::id::JUPITER, "Jupiter"),
|
||||
(bodies::id::MERCURY, "Mercury"),
|
||||
(bodies::id::SATURN, "Saturn"),
|
||||
(bodies::id::NEPTUNE, "Neptune"),
|
||||
(bodies::id::URANUS, "Uranus"),
|
||||
(bodies::id::PLUTO, "Pluto"),
|
||||
(bodies::id::CERES, "Ceres"),
|
||||
];
|
||||
|
||||
// Lagrange points to place at each planet (in priority order)
|
||||
let lp_priority: &[u8] = &[1, 2, 4, 5, 3];
|
||||
|
||||
for &lp in lp_priority {
|
||||
for &(planet_id, planet_name) in &planet_priority {
|
||||
if stations.len() >= target_count {
|
||||
return stations;
|
||||
}
|
||||
stations.push(Station {
|
||||
id,
|
||||
name: format!("{} L{}", planet_name, lp),
|
||||
placement: StationPlacement::LagrangePoint {
|
||||
planet_id,
|
||||
point: lp,
|
||||
},
|
||||
});
|
||||
id += 1;
|
||||
}
|
||||
}
|
||||
|
||||
stations.truncate(target_count);
|
||||
stations
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user