Advanced camera inputs and added moon (moon not working yet)
This commit is contained in:
parent
8ce9493d00
commit
55faf5c4d3
@ -1,5 +1,5 @@
|
|||||||
use cgmath::{Rotation3, Vector3};
|
use cgmath::{Rotation3, Vector3};
|
||||||
use solar_engine::{Application, Body, Key, KeyState, Light, LightType, Simulator};
|
use solar_engine::{Application, Body, InputEvent, Key, Light, LightType, MouseButton, Simulator};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
@ -21,6 +21,17 @@ pub async fn run() {
|
|||||||
mass: 5.972e24,
|
mass: 5.972e24,
|
||||||
radius: 6.371e6,
|
radius: 6.371e6,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let earth_position = sim.bodies[1].position;
|
||||||
|
let earth_velocity = sim.bodies[1].velocity;
|
||||||
|
|
||||||
|
sim.add_body(Body {
|
||||||
|
name: "Moon".into(),
|
||||||
|
position: earth_position + Vector3::new(384.4e6, 0.0, 0.0),
|
||||||
|
velocity: earth_velocity + Vector3::new(0.0, 1022.0, 0.0),
|
||||||
|
mass: 7.342e22,
|
||||||
|
radius: 1.737e6,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let sim_clone = simulator.clone();
|
let sim_clone = simulator.clone();
|
||||||
@ -81,30 +92,50 @@ pub async fn run() {
|
|||||||
|
|
||||||
state.set_instances(instances);
|
state.set_instances(instances);
|
||||||
})
|
})
|
||||||
.on_input(move |state, event| {
|
.on_input({
|
||||||
if event.state == KeyState::Pressed {
|
let simulator = simulator.clone();
|
||||||
return match event.key {
|
move |state, event| {
|
||||||
Key::Period => {
|
match event {
|
||||||
let mut sim = simulator.write().unwrap();
|
InputEvent::MouseDragged { delta, button: MouseButton::Left } => {
|
||||||
sim.increase_timewarp();
|
state.camera_mut().rotate_yaw_pitch(-delta.x as f32 * 0.1, delta.y as f32 * 0.1);
|
||||||
println!("Timewarp: {}", sim.get_timewarp());
|
|
||||||
}
|
}
|
||||||
Key::Comma => {
|
InputEvent::MouseWheel { delta } => {
|
||||||
let mut sim = simulator.write().unwrap();
|
state.camera_mut().zoom(delta * 0.05);
|
||||||
sim.decrease_timewarp();
|
|
||||||
println!("Timewarp: {}", sim.get_timewarp());
|
|
||||||
}
|
}
|
||||||
Key::Minus => {
|
InputEvent::KeyPressed { key, .. } => {
|
||||||
let mut sim = simulator.write().unwrap();
|
match key {
|
||||||
sim.reset_timewarp();
|
Key::ArrowLeft => {
|
||||||
println!("Timewarp: {}", sim.get_timewarp());
|
state.camera_mut().translate(Vector3::new(-1.0, 0.0, 0.0));
|
||||||
|
}
|
||||||
|
Key::ArrowRight => {
|
||||||
|
state.camera_mut().translate(Vector3::new(1.0, 0.0, 0.0));
|
||||||
|
}
|
||||||
|
Key::ArrowUp => {
|
||||||
|
state.camera_mut().translate(Vector3::new(0.0, 1.0, 0.0));
|
||||||
|
}
|
||||||
|
Key::ArrowDown => {
|
||||||
|
state.camera_mut().translate(Vector3::new(0.0, -1.0, 0.0));
|
||||||
|
}
|
||||||
|
Key::Period => {
|
||||||
|
let mut sim = simulator.write().unwrap();
|
||||||
|
sim.increase_timewarp();
|
||||||
|
println!("Timewarp: {}", sim.get_timewarp());
|
||||||
|
}
|
||||||
|
Key::Comma => {
|
||||||
|
let mut sim = simulator.write().unwrap();
|
||||||
|
sim.decrease_timewarp();
|
||||||
|
println!("Timewarp: {}", sim.get_timewarp());
|
||||||
|
}
|
||||||
|
Key::Minus => {
|
||||||
|
let mut sim = simulator.write().unwrap();
|
||||||
|
sim.reset_timewarp();
|
||||||
|
println!("Timewarp: {}", sim.get_timewarp());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Key::ArrowLeft => state.camera_mut().rotate_yaw_pitch(-5.0, 0.0),
|
|
||||||
Key::ArrowRight => state.camera_mut().rotate_yaw_pitch(5.0, 0.0),
|
|
||||||
Key::ArrowUp => state.camera_mut().zoom(-0.2),
|
|
||||||
Key::ArrowDown => state.camera_mut().zoom(0.2),
|
|
||||||
_ => {}
|
_ => {}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
|
|||||||
@ -1,19 +1,20 @@
|
|||||||
use winit::application::ApplicationHandler;
|
use winit::application::ApplicationHandler;
|
||||||
use winit::event::{Modifiers, WindowEvent};
|
use winit::event::{ElementState, Modifiers, MouseScrollDelta, WindowEvent};
|
||||||
use winit::event_loop::ActiveEventLoop;
|
use winit::event_loop::ActiveEventLoop;
|
||||||
use winit::window::{Window, WindowId};
|
use winit::window::{Window, WindowId};
|
||||||
use crate::input::{from_winit_input, InputEvent};
|
use crate::input::{InputEvent, InputTracker};
|
||||||
|
|
||||||
pub struct StateApplication<'a> {
|
pub struct StateApplication<'a> {
|
||||||
state: Option<crate::state::State<'a>>,
|
state: Option<crate::state::State<'a>>,
|
||||||
modifiers: Modifiers,
|
modifiers: Modifiers,
|
||||||
update_fn: Option<Box<dyn FnMut(&mut crate::state::State<'a>) + 'a>>,
|
update_fn: Option<Box<dyn FnMut(&mut crate::state::State<'a>) + 'a>>,
|
||||||
input_fn: Option<Box<dyn FnMut(&mut crate::state::State<'a>, &InputEvent) + 'a>>,
|
input_fn: Option<Box<dyn FnMut(&mut crate::state::State<'a>, &InputEvent) + 'a>>,
|
||||||
|
input_tracker: InputTracker
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> StateApplication<'a> {
|
impl<'a> StateApplication<'a> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { state: None, update_fn: None, input_fn: None, modifiers: Modifiers::default() }
|
Self { state: None, update_fn: None, input_fn: None, modifiers: Modifiers::default(), input_tracker: InputTracker::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn on_update<F: FnMut(&mut crate::state::State<'a>) + 'a>(mut self, func: F) -> Self {
|
pub fn on_update<F: FnMut(&mut crate::state::State<'a>) + 'a>(mut self, func: F) -> Self {
|
||||||
@ -63,18 +64,18 @@ impl<'a> ApplicationHandler for StateApplication<'a> {
|
|||||||
|
|
||||||
self.state.as_mut().unwrap().render().unwrap();
|
self.state.as_mut().unwrap().render().unwrap();
|
||||||
}
|
}
|
||||||
WindowEvent::KeyboardInput { event, .. } => {
|
|
||||||
if let Some(state) = self.state.as_mut() {
|
|
||||||
if let Some(input_fn) = self.input_fn.as_mut() {
|
|
||||||
let key_event = from_winit_input(&event, self.modifiers);
|
|
||||||
input_fn(state, &key_event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WindowEvent::ModifiersChanged(modifiers) => {
|
WindowEvent::ModifiersChanged(modifiers) => {
|
||||||
self.modifiers = modifiers;
|
self.modifiers = modifiers;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {
|
||||||
|
if let Some(state) = self.state.as_mut() {
|
||||||
|
if let Some(event) = self.input_tracker.handle_window_event(&event, self.modifiers) {
|
||||||
|
if let Some(input_fn) = self.input_fn.as_mut() {
|
||||||
|
input_fn(state, &event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,19 +35,27 @@ impl Camera {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_yaw_pitch(&mut self, yaw: f32, pitch: f32) {
|
pub fn rotate_yaw_pitch(&mut self, yaw: f32, pitch: f32) {
|
||||||
let dir = (self.target - self.eye).normalize();
|
let offset = self.eye - self.target;
|
||||||
|
let distance = offset.magnitude();
|
||||||
|
|
||||||
|
let yaw_q = Quaternion::from_axis_angle(Vector3::unit_y(), Rad(yaw.to_radians()));
|
||||||
|
let right = offset.cross(self.up).normalize();
|
||||||
|
let pitch_q = Quaternion::from_axis_angle(right, Rad(pitch.to_radians()));
|
||||||
|
|
||||||
|
let rotation = yaw_q * pitch_q;
|
||||||
|
let new_offset = rotation.rotate_vector(offset);
|
||||||
|
|
||||||
|
self.eye = self.target + new_offset;
|
||||||
|
self.up = rotation.rotate_vector(self.up);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn translate(&mut self, translation: Vector3<f32>) {
|
||||||
|
let dir = (self.target - self.eye).normalize();
|
||||||
let horizontal = Vector3::unit_y().cross(dir).normalize();
|
let horizontal = Vector3::unit_y().cross(dir).normalize();
|
||||||
let vertical = horizontal.cross(dir).normalize();
|
let vertical = horizontal.cross(dir).normalize();
|
||||||
|
|
||||||
let pitch_q = Quaternion::from_axis_angle(vertical, Rad(pitch.to_radians()));
|
self.eye += horizontal * translation.x + vertical * translation.y;
|
||||||
let yaw_q = Quaternion::from_axis_angle(Vector3::unit_y(), Rad(yaw.to_radians()));
|
self.target += horizontal * translation.x + vertical * translation.y;
|
||||||
|
|
||||||
let rotation = yaw_q * pitch_q;
|
|
||||||
let rotated = rotation.rotate_vector(dir).normalize();
|
|
||||||
|
|
||||||
let distance = (self.target - self.eye).magnitude();
|
|
||||||
self.eye = self.target - rotated * distance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zoom(&mut self, amount: f32) {
|
pub fn zoom(&mut self, amount: f32) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use log::info;
|
use cgmath::Vector2;
|
||||||
use winit::event::{ElementState, KeyEvent, Modifiers};
|
use winit::event::{ElementState, KeyEvent, MouseScrollDelta, Modifiers, WindowEvent};
|
||||||
use winit::keyboard::{Key as WinitKey, ModifiersKeyState};
|
use winit::keyboard::{Key as WinitKey, ModifiersKeyState};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
@ -33,16 +33,9 @@ pub enum Key {
|
|||||||
Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
|
Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
|
||||||
NumpadAdd, NumpadSubtract, NumpadMultiply, NumpadDivide, NumpadEnter,
|
NumpadAdd, NumpadSubtract, NumpadMultiply, NumpadDivide, NumpadEnter,
|
||||||
|
|
||||||
// Unknown
|
|
||||||
Unknown,
|
Unknown,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
pub enum KeyState {
|
|
||||||
Pressed,
|
|
||||||
Released,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct KeyModifiers {
|
pub struct KeyModifiers {
|
||||||
pub lshift: bool,
|
pub lshift: bool,
|
||||||
@ -55,35 +48,121 @@ pub struct KeyModifiers {
|
|||||||
pub lsuper_key: bool,
|
pub lsuper_key: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct InputEvent {
|
pub enum MouseButton {
|
||||||
pub key: Key,
|
Left,
|
||||||
pub state: KeyState,
|
Right,
|
||||||
pub text: String,
|
Middle,
|
||||||
pub modifiers: KeyModifiers,
|
Other(u16),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_winit_input(event: &KeyEvent, modifiers: Modifiers) -> InputEvent {
|
#[derive(Debug, Clone)]
|
||||||
InputEvent {
|
pub enum InputEvent {
|
||||||
key: map_winit_key(&event.logical_key),
|
KeyPressed {
|
||||||
state: match event.state {
|
key: Key,
|
||||||
ElementState::Pressed => KeyState::Pressed,
|
modifiers: KeyModifiers,
|
||||||
ElementState::Released => KeyState::Released,
|
text: String,
|
||||||
|
},
|
||||||
|
KeyReleased {
|
||||||
|
key: Key,
|
||||||
|
modifiers: KeyModifiers,
|
||||||
|
},
|
||||||
|
MouseMoved {
|
||||||
|
position: (f64, f64),
|
||||||
|
},
|
||||||
|
MouseDragged {
|
||||||
|
delta: Vector2<f64>,
|
||||||
|
button: MouseButton,
|
||||||
|
},
|
||||||
|
MouseWheel {
|
||||||
|
delta: f32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct InputTracker {
|
||||||
|
pub last_cursor_pos: Option<(f64, f64)>,
|
||||||
|
pub dragging_button: Option<MouseButton>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InputTracker {
|
||||||
|
pub fn handle_window_event(&mut self, event: &WindowEvent, modifiers: Modifiers) -> Option<InputEvent> {
|
||||||
|
match event {
|
||||||
|
WindowEvent::KeyboardInput { event, .. } => {
|
||||||
|
Some(handle_keyboard_input(event, modifiers))
|
||||||
|
}
|
||||||
|
WindowEvent::CursorMoved { position, .. } => {
|
||||||
|
if let (Some(last), Some(button)) = (self.last_cursor_pos, self.dragging_button) {
|
||||||
|
let delta = Vector2::new(position.x - last.0, position.y - last.1);
|
||||||
|
self.last_cursor_pos = Some((position.x, position.y));
|
||||||
|
Some(InputEvent::MouseDragged { delta, button })
|
||||||
|
} else {
|
||||||
|
self.last_cursor_pos = Some((position.x, position.y));
|
||||||
|
Some(InputEvent::MouseMoved {
|
||||||
|
position: (position.x, position.y),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WindowEvent::MouseInput { state, button, .. } => {
|
||||||
|
let mapped = map_button(*button);
|
||||||
|
match state {
|
||||||
|
ElementState::Pressed => {
|
||||||
|
self.dragging_button = Some(mapped);
|
||||||
|
}
|
||||||
|
ElementState::Released => {
|
||||||
|
self.dragging_button = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
WindowEvent::MouseWheel { delta, .. } => {
|
||||||
|
let scroll = match delta {
|
||||||
|
MouseScrollDelta::LineDelta(_, y) => *y,
|
||||||
|
MouseScrollDelta::PixelDelta(p) => p.y as f32,
|
||||||
|
};
|
||||||
|
Some(InputEvent::MouseWheel { delta: scroll })
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_keyboard_input(event: &KeyEvent, modifiers: Modifiers) -> InputEvent {
|
||||||
|
let key = map_winit_key(&event.logical_key);
|
||||||
|
let mods = KeyModifiers {
|
||||||
|
lshift: modifiers.lshift_state() == ModifiersKeyState::Pressed,
|
||||||
|
rshift: modifiers.rshift_state() == ModifiersKeyState::Pressed,
|
||||||
|
lcontrol: modifiers.lcontrol_state() == ModifiersKeyState::Pressed,
|
||||||
|
rcontrol: modifiers.rcontrol_state() == ModifiersKeyState::Pressed,
|
||||||
|
lalt: modifiers.lalt_state() == ModifiersKeyState::Pressed,
|
||||||
|
ralt: modifiers.ralt_state() == ModifiersKeyState::Pressed,
|
||||||
|
rsuper_key: modifiers.rsuper_state() == ModifiersKeyState::Pressed,
|
||||||
|
lsuper_key: modifiers.lsuper_state() == ModifiersKeyState::Pressed,
|
||||||
|
};
|
||||||
|
|
||||||
|
match event.state {
|
||||||
|
ElementState::Pressed => InputEvent::KeyPressed {
|
||||||
|
key,
|
||||||
|
modifiers: mods,
|
||||||
|
text: event.text.clone().unwrap_or_default().into(),
|
||||||
},
|
},
|
||||||
text: event.text.clone().unwrap_or_default().into(),
|
ElementState::Released => InputEvent::KeyReleased {
|
||||||
modifiers: KeyModifiers {
|
key,
|
||||||
lshift: modifiers.lshift_state() == ModifiersKeyState::Pressed,
|
modifiers: mods,
|
||||||
rshift: modifiers.rshift_state() == ModifiersKeyState::Pressed,
|
|
||||||
lcontrol: modifiers.lcontrol_state() == ModifiersKeyState::Pressed,
|
|
||||||
rcontrol: modifiers.rcontrol_state() == ModifiersKeyState::Pressed,
|
|
||||||
lalt: modifiers.lalt_state() == ModifiersKeyState::Pressed,
|
|
||||||
ralt: modifiers.ralt_state() == ModifiersKeyState::Pressed,
|
|
||||||
rsuper_key: modifiers.rsuper_state() == ModifiersKeyState::Pressed,
|
|
||||||
lsuper_key: modifiers.lsuper_state() == ModifiersKeyState::Pressed,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn map_button(button: winit::event::MouseButton) -> MouseButton {
|
||||||
|
match button {
|
||||||
|
winit::event::MouseButton::Left => MouseButton::Left,
|
||||||
|
winit::event::MouseButton::Right => MouseButton::Right,
|
||||||
|
winit::event::MouseButton::Middle => MouseButton::Middle,
|
||||||
|
winit::event::MouseButton::Other(n) => MouseButton::Other(n),
|
||||||
|
_ => MouseButton::Other(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map_winit_key(key: &WinitKey) -> Key {
|
pub fn map_winit_key(key: &WinitKey) -> Key {
|
||||||
use Key::*;
|
use Key::*;
|
||||||
use winit::keyboard::NamedKey;
|
use winit::keyboard::NamedKey;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub use state::State;
|
|||||||
pub use input::Key;
|
pub use input::Key;
|
||||||
pub use input::map_winit_key;
|
pub use input::map_winit_key;
|
||||||
pub use input::InputEvent;
|
pub use input::InputEvent;
|
||||||
pub use input::KeyState;
|
pub use input::MouseButton;
|
||||||
|
|
||||||
pub use light::Light;
|
pub use light::Light;
|
||||||
pub use light::LightType;
|
pub use light::LightType;
|
||||||
@ -1,3 +1,4 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use cgmath::{InnerSpace, Vector3};
|
use cgmath::{InnerSpace, Vector3};
|
||||||
use crate::body::Body;
|
use crate::body::Body;
|
||||||
@ -51,40 +52,30 @@ impl Simulator {
|
|||||||
|
|
||||||
let masses: Vec<f64> = self.bodies.iter().map(|b| b.mass).collect();
|
let masses: Vec<f64> = self.bodies.iter().map(|b| b.mass).collect();
|
||||||
|
|
||||||
fn compute_accelerations(states: &[State], masses: &[f64]) -> Vec<Vector3<f64>> {
|
fn compute_accelerations(states: &[State], masses: &[f64], ownership: &HashMap<usize, usize>) -> Vec<Vector3<f64>> {
|
||||||
let n = states.len();
|
let mut accels = vec![Vector3::new(0.0, 0.0, 0.0); states.len()];
|
||||||
let accels = (0..n).map(|_| Mutex::new(Vector3::new(0.0, 0.0, 0.0))).collect::<Vec<_>>();
|
|
||||||
|
|
||||||
(0..n).into_par_iter().for_each(|i| {
|
for (&i, &j) in ownership {
|
||||||
for j in (i + 1)..n {
|
let r = states[j].position - states[i].position;
|
||||||
let r = states[j].position - states[i].position;
|
let dist_sq = r.magnitude2();
|
||||||
let dist_sq = r.magnitude2();
|
let dist = dist_sq.sqrt();
|
||||||
let dist = dist_sq.sqrt();
|
|
||||||
|
|
||||||
if dist < 1e-8 {
|
if dist < 1e-8 {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
let force = G * masses[i] * masses[j] / dist_sq;
|
|
||||||
let accel = force * r / (dist * masses[i]);
|
|
||||||
let accel_j = -force * r / (dist * masses[j]);
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut a_i_lock = accels[i].lock().unwrap();
|
|
||||||
*a_i_lock += accel;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let mut a_j_lock = accels[j].lock().unwrap();
|
|
||||||
*a_j_lock += accel_j;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
accels.into_iter().map(|mutex| mutex.into_inner().unwrap()).collect()
|
let force = G * masses[i] * masses[j] / dist_sq;
|
||||||
|
let accel = force * r / (dist * masses[i]);
|
||||||
|
|
||||||
|
accels[i] += accel;
|
||||||
|
}
|
||||||
|
|
||||||
|
accels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ownership = self.compute_soi_owners();
|
||||||
let k1_pos = original_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
let k1_pos = original_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
||||||
let k1_vel = compute_accelerations(&original_states, &masses);
|
let k1_vel = compute_accelerations(&original_states, &masses, &ownership);
|
||||||
|
|
||||||
let mut temp_states: Vec<State> = original_states.iter().enumerate().map(|(i, s)| {
|
let mut temp_states: Vec<State> = original_states.iter().enumerate().map(|(i, s)| {
|
||||||
State {
|
State {
|
||||||
@ -94,7 +85,7 @@ impl Simulator {
|
|||||||
}).collect();
|
}).collect();
|
||||||
|
|
||||||
let k2_pos = temp_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
let k2_pos = temp_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
||||||
let k2_vel = compute_accelerations(&temp_states, &masses);
|
let k2_vel = compute_accelerations(&temp_states, &masses, &ownership);
|
||||||
|
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
temp_states[i].position = original_states[i].position + k2_pos[i] * (dt / 2.0);
|
temp_states[i].position = original_states[i].position + k2_pos[i] * (dt / 2.0);
|
||||||
@ -102,7 +93,7 @@ impl Simulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let k3_pos = temp_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
let k3_pos = temp_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
||||||
let k3_vel = compute_accelerations(&temp_states, &masses);
|
let k3_vel = compute_accelerations(&temp_states, &masses, &ownership);
|
||||||
|
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
temp_states[i].position = original_states[i].position + k3_pos[i] * dt;
|
temp_states[i].position = original_states[i].position + k3_pos[i] * dt;
|
||||||
@ -110,7 +101,7 @@ impl Simulator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let k4_pos = temp_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
let k4_pos = temp_states.iter().map(|s| s.velocity).collect::<Vec<_>>();
|
||||||
let k4_vel = compute_accelerations(&temp_states, &masses);
|
let k4_vel = compute_accelerations(&temp_states, &masses, &ownership);
|
||||||
|
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let body = &mut self.bodies[i];
|
let body = &mut self.bodies[i];
|
||||||
@ -122,6 +113,33 @@ impl Simulator {
|
|||||||
self.time += dt;
|
self.time += dt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compute_soi_owners(&self) -> HashMap<usize, usize> {
|
||||||
|
let mut ownership = HashMap::new();
|
||||||
|
for (i, body) in self.bodies.iter().enumerate() {
|
||||||
|
let mut min_distance = f64::MAX;
|
||||||
|
let mut dominant_index = None;
|
||||||
|
|
||||||
|
for (j, other) in self.bodies.iter().enumerate() {
|
||||||
|
if i == j {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let r = (body.position - other.position).magnitude();
|
||||||
|
let soi_radius = r * (body.mass / other.mass).powf(2.0 / 5.0);
|
||||||
|
|
||||||
|
if r < soi_radius && r < min_distance {
|
||||||
|
min_distance = r;
|
||||||
|
dominant_index = Some(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(j) = dominant_index {
|
||||||
|
ownership.insert(i, j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ownership
|
||||||
|
}
|
||||||
|
|
||||||
pub fn increase_timewarp(&mut self) {
|
pub fn increase_timewarp(&mut self) {
|
||||||
if let Some(new) = self.timewarp.checked_mul(2) {
|
if let Some(new) = self.timewarp.checked_mul(2) {
|
||||||
if new <= MAX_TIMEWARP {
|
if new <= MAX_TIMEWARP {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user