/*!
# **kalast**

Thermophysical model for binary systems of asteroids.

## Using **kalast**

You will need the last stable build of the [rust compiler](https://www.rust-lang.org)
and the official package manager: [cargo](https://github.com/rust-lang/cargo).

Simply add the following to your `Cargo.toml` file:

```.ignore
[dependencies]
kalast = "0.1.6"
```

Most useful functionalities of **kalast** are grouped in the root module `kalast::`.

However, the recommended way to use nalgebra is to import types and traits explicitly, and call free-functions using the na:: prefix:

```no_run
use kalast::{Body, Properties, Time, World, ASTRONAUMICAL_UNIT, HOUR, TAU, V3};
use std::path::Path;

fn main() {
    // Instanciate a celestial body named 'Dimorphos', at a distance of 1.664 AU from
    // the Sun, from a 3D object shape model located at 'rsc/obj/dimorphos.obj',
    // with a complete set of ground physical properties.
    let mut body = Body::new(
        "Dimorphos",
        V3::new(0.0, 1.0, 0.0) * ASTRONAUMICAL_UNIT * 1.664,
        Path::new("rsc/obj/dimorphos.obj"),
        Properties::new(
            11.92 * HOUR,        // rotation period
            11.92 * HOUR,        // revolution period
            162.0 * TAU / 360.0, // obliquity
            500.0,               // thermal inertia
            2146.0,              // density
            600.0,               // heat capacity
            0.07,                // albedo
            0.9,                 // emissivity
        ),
    );
    body.set_faces_mask_equator(); // only computes temperatures for equator

    // Create a simulation time that lasts 50 revolution period of the body with 30 seconds steps.
    // The residual 0.75 period is for the last frame to be at noon (max temperature peek at
    // longitude=0°, according to this initial bodies setup).
    let time = Time::new(50.75 * body.properties.revolution_period(), 30.0);

    let mut world = World::new(time, body, None); // define the world of the simulation
    world.start(); // run the simulation
    world.save(Path::new("rsc/temperatures/dimorphos_equator.txt")); // save the temperatures to a file
}
```

## Features

**kalast** is meant for binary system of asteroids surface thermophysical modelling. The physics of this engine includes these features:

+ custom shape model
+ celestial body revolution
+ compute surface temperatures from solar flux
+ ground 1D heat transfert conduction
+ celestial body mask view (example only equator)
+ TODO: mutual heating from primary/moon
+ TODO: self heating
+ TODO: mutual occultations
+ TODO: shadowing

## Explore

If your want to explore the documentation, you can visite these pages:

+ [`Object3D`]: parse 3D object file and compute atributes of faces (centers, normals, ...)
+ [`Body`]: the representation for a celestial body
+ [`Properties`]: all the properties to characterise a body
+ [`World`]: the simulation manager
*/

extern crate alga;
extern crate indicatif;
#[macro_use]
extern crate itertools;
extern crate nalgebra as na;
extern crate num_traits;
extern crate obj;

/// Base features.
pub mod base;
/// Collection of generic functions for math, physics, matrix operations, or for the usage of other
/// crates.
pub mod toolbox;

use alga::general::RingCommutative;
use na::Scalar;
use na::{
    DVector, Dynamic, Matrix, Matrix3x1, Matrix3xX, SliceStorage, SliceStorageMut, VecStorage, U1,
    U10,
};
use num_traits::{NumCast, ToPrimitive};
use std::cmp::PartialOrd;

pub use crate::base::*;
pub use crate::toolbox::*;

/// Type alias for [`Matrix3xX`]. The matrix has a fixed number of rows (3) and a dynamical number of
/// columns.
pub type V3X<T> = Matrix3xX<T>;

/// Type alias for [`Matrix3x1`]. The matrix has a fixed number of rows (3) and a fixed number of
/// columns (1).
pub type V3<T> = Matrix3x1<T>;

/// Type alias for [`DVector`]. The matrix is a vector of X columns.
pub type VX<T> = DVector<T>;

/// Type alias for [`Object3D`]. The matrix has a fixed number of rows (10) and a dynamical number
/// of columns.
pub type Matrix10xX<T> = Matrix<T, U10, Dynamic, VecStorage<T, U10, Dynamic>>;

/// Type alias for [`Object3D`]. The slice matrix has a fixed number of rows (10) and a fixed
/// number of columns (1).
pub type MatrixSlice10x1<'a, T, RStride = U1, CStride = U10> =
    Matrix<T, U10, U1, SliceStorage<'a, T, U10, U1, RStride, CStride>>;

/// Type alias for [`Object3D`]. The mutable slice matrix has a fixed number of rows (10) and a
/// fixed number of columns (1).
pub type MatrixSliceMut10x1<'a, T, RStride = U1, CStride = U10> =
    Matrix<T, U10, U1, SliceStorageMut<'a, T, U10, U1, RStride, CStride>>;

/// Trait that extends [`Scalar`] to create integer matrices like float matrices. It aims to be the
/// equivalent of [`nalgebra::RealField`] but for integer.
pub trait SuperScalar:
    Scalar + RingCommutative + PartialOrd + std::ops::Div + ToPrimitive + NumCast + Copy
{
}

impl<T> SuperScalar for T where
    T: Scalar + RingCommutative + PartialOrd + std::ops::Div + ToPrimitive + NumCast + Copy
{
}
