Playground

Loading...
  • Language Client
  • Language Server
  • Example File
Shortcuts:
- Pressing Ctrl+S in the editor formats the code.
- Pressing Ctrl+Space opens the code completion menu.
- Pressing Ctrl+Click on a variable or field jumps to its definition.
- Press F2 on a variable or field to rename it.

Exported Rust Module

The source code above can use exported constructions from Rust's algebra.rs module via the script's use algebra; import statement.

use std::{
    f64::consts::PI,
    fmt::{Display, Formatter},
    ops::{Add, Mul, Neg},
};

use ad_astra::export;

/// An example package with basic 2D coordinate system transformation features.
#[export(package)]
#[derive(Default)]
struct Package;

/// Converts degrees to radians.
#[export]
pub fn deg(degrees: f64) -> f64 {
    PI * degrees / 180.0
}

/// Converts radians to degrees.
#[export]
pub fn rad(radians: f64) -> f64 {
    180.0 * radians / PI
}

/// Rounds a floating-point number up to the nearest integer.
#[export]
pub fn round(value: f64) -> i64 {
    value.round() as i64
}

/// A 2D vector.
#[export]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Vector {
    /// The x-coordinate of the vector.
    pub x: f64,

    /// The y-coordinate of the vector.
    pub y: f64,
}

#[export]
impl Neg for Vector {
    type Output = Self;

    fn neg(mut self) -> Self::Output {
        self.x = -self.x;
        self.y = -self.y;

        self
    }
}

#[export]
impl Add for Vector {
    type Output = Self;

    fn add(mut self, rhs: Self) -> Self::Output {
        self.x += rhs.x;
        self.y += rhs.y;

        self
    }
}

#[export]
impl Display for Vector {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.write_fmt(format_args!("vec({}, {})", self.x, self.y))
    }
}

#[export]
impl Vector {
    /// Constructs a new 2D vector.
    #[export(name "vec")]
    pub fn new(x: f64, y: f64) -> Self {
        Self { x, y }
    }

    /// Returns the magnitude (or length) of the vector.
    pub fn radius(&self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }

    /// Returns the angle of the vector in the 2D coordinate system.
    pub fn angle(&self) -> f64 {
        self.y.atan2(self.x)
    }

    /// Normalizes this vector by setting its magnitude to 1 while preserving
    /// the original angle.
    pub fn normalize(&mut self) -> &mut Self {
        let r = self.radius();

        self.x /= r;
        self.y /= r;

        self
    }

    /// Transforms this vector using the provided transformation matrix.
    pub fn transform(&mut self, matrix: &Matrix) -> &mut Self {
        let x = matrix.x.x * self.x + matrix.x.y * self.y;
        let y = matrix.y.x * self.x + matrix.y.y * self.y;

        self.x = x;
        self.y = y;

        self
    }
}

/// A 2x2 transformation matrix.
#[export]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Matrix {
    x: Vector,
    y: Vector,
}

#[export]
impl Mul for Matrix {
    type Output = Self;

    fn mul(self, rhs: Matrix) -> Self::Output {
        Self {
            x: Vector {
                x: self.x.x * rhs.x.x + self.x.y * rhs.y.x,
                y: self.x.x * rhs.x.y + self.x.y * rhs.y.y,
            },
            y: Vector {
                x: self.y.x * rhs.x.x + self.y.y * rhs.y.x,
                y: self.y.x * rhs.x.y + self.y.y * rhs.y.y,
            },
        }
    }
}

#[export]
impl Matrix {
    /// Creates a 2x2 transformation matrix that rotates the coordinate system
    /// by the specified angle in radians.
    pub fn rotation(angle: f64) -> Self {
        let (sin, cos) = angle.sin_cos();

        Self {
            x: Vector { x: cos, y: -sin },
            y: Vector { x: sin, y: cos },
        }
    }

    /// Computes the determinant of this matrix.
    pub fn det(&self) -> f64 {
        self.x.x * self.y.y - self.x.y * self.y.x
    }

    /// Constructs a new matrix that is the inverse of this one.
    pub fn invert(&self) -> Self {
        let det = self.det();

        Self {
            x: Vector {
                x: self.y.y / det,
                y: -self.x.y / det,
            },
            y: Vector {
                x: -self.y.x / det,
                y: self.x.x / det,
            },
        }
    }
}