newton 0.5.1

A Newtonian physics simulator written in Rust.
Documentation
// Newton - A Newtonian physics simulator written in Rust.
// Copyright (C) 2017 Cooper Paul EdenDay
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
// Electronic mail: cedenday@protonmail.com

use units::{self, Eval};
use vector::Vector;

#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
pub struct Body {
    tick_time: units::Time,
    mass: units::Mass,
    position: Vector<units::Length>,
    velocity: Vector<units::Velocity>,
    new_acceleration: Vector<units::Acceleration>,
    old_acceleration: Vector<units::Acceleration>,
}

impl Body {
    pub fn new(tick_time: units::Time,
               mass: units::Mass,
               position: Vector<units::Length>,
               velocity: Option<Vector<units::Velocity>>)
               -> Body {
        let default_velocity = Vector::new([units::Velocity::new(0.0); 3]);
        let velocity = velocity.unwrap_or(default_velocity);
        let acceleration = Vector::new([units::Acceleration::new(0.0); 3]);

        Body {
            tick_time: tick_time,
            mass: mass,
            position: position,
            velocity: velocity,
            new_acceleration: acceleration,
            old_acceleration: acceleration,
        }
    }

    pub fn get_position(&self) -> Vector<units::Length> {
        self.position
    }

    pub fn display(&self) -> [f32; 3] {
        let mut x = self.position.get().iter().map(|a| a.eval() as f32);
        [x.next().unwrap(), x.next().unwrap(), x.next().unwrap()]
    }

    pub fn get_velocity(&self) -> Vector<units::Velocity> {
        self.velocity
    }

    pub fn get_acceleration(&self) -> Vector<units::Acceleration> {
        self.new_acceleration
    }

    pub fn tick(&mut self) {
        let velocity_half: Vector<units::Velocity> = self.velocity
            .get()
            .iter()
            .zip(self.old_acceleration.get().iter())
            .map(|(v, a)| v.eval() + 0.5 * a.eval() * self.tick_time.eval())
            .map(units::Velocity::new)
            .collect();

        self.position = self.position
            .get()
            .iter()
            .zip(velocity_half.get().iter())
            .map(|(x, v)| x.eval() + v.eval() * self.tick_time.eval())
            .map(units::Length::new)
            .collect();

        self.velocity = velocity_half
            .get()
            .iter()
            .zip(self.new_acceleration.get().iter())
            .map(|(v, a)| v.eval() + 0.5 * a.eval() * self.tick_time.eval())
            .map(units::Velocity::new)
            .collect();

        self.old_acceleration = self.new_acceleration;
        self.new_acceleration = Vector::new([units::Acceleration::new(0.0); 3]);
    }

    fn apply_acceleration(&mut self, acceleration: Vector<units::Acceleration>) {
        self.new_acceleration = self.new_acceleration + acceleration;
    }

    pub fn apply_force(&mut self, force: Vector<units::Force>) {
        let acceleration = force
            .get()
            .iter()
            .map(|f| f.acceleration_mass(self.mass))
            .collect();
        self.apply_acceleration(acceleration);
    }

    pub fn direction(&self, other: &Body) -> Vector<units::Length> {
        Vector::displacement(&self.position, &other.position).normalize()
    }

    pub fn apply_force_towards(&mut self, other: &Body, force: units::Force) {
        let direction = Body::direction(self, other);
        let force = direction
            .get()
            .iter()
            .map(|x| units::Force::new(x.eval() * force.eval()))
            .collect();
        self.apply_force(force);
    }
}