use rustial_math::GeoCoord;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AltitudeMode {
#[default]
Absolute,
RelativeToGround,
ClampToGround,
}
#[derive(Debug, Clone)]
pub struct ModelMesh {
pub positions: Vec<[f32; 3]>,
pub normals: Vec<[f32; 3]>,
pub uvs: Vec<[f32; 2]>,
pub indices: Vec<u32>,
}
#[derive(Debug, Clone)]
pub struct ModelInstance {
pub position: GeoCoord,
pub altitude_mode: AltitudeMode,
pub heading: f64,
pub pitch: f64,
pub roll: f64,
pub scale: f64,
pub mesh: ModelMesh,
}
impl ModelInstance {
pub fn new(position: GeoCoord, mesh: ModelMesh) -> Self {
Self {
position,
altitude_mode: AltitudeMode::default(),
heading: 0.0,
pitch: 0.0,
roll: 0.0,
scale: 1.0,
mesh,
}
}
pub fn resolve_altitude(&self, terrain_elevation: Option<f64>) -> f64 {
match self.altitude_mode {
AltitudeMode::Absolute => self.position.alt,
AltitudeMode::RelativeToGround => {
let ground = terrain_elevation.unwrap_or(0.0);
ground + self.position.alt
}
AltitudeMode::ClampToGround => terrain_elevation.unwrap_or(0.0),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn dummy_mesh() -> ModelMesh {
ModelMesh {
positions: vec![[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [0.0, 1.0, 0.0]],
normals: vec![[0.0, 0.0, 1.0]; 3],
uvs: vec![[0.0, 0.0], [1.0, 0.0], [0.0, 1.0]],
indices: vec![0, 1, 2],
}
}
#[test]
fn altitude_absolute() {
let inst = ModelInstance {
position: GeoCoord::new(0.0, 0.0, 500.0),
altitude_mode: AltitudeMode::Absolute,
..ModelInstance::new(GeoCoord::default(), dummy_mesh())
};
assert!((inst.resolve_altitude(Some(100.0)) - 500.0).abs() < 1e-6);
}
#[test]
fn altitude_relative() {
let inst = ModelInstance {
position: GeoCoord::new(0.0, 0.0, 50.0),
altitude_mode: AltitudeMode::RelativeToGround,
..ModelInstance::new(GeoCoord::default(), dummy_mesh())
};
assert!((inst.resolve_altitude(Some(100.0)) - 150.0).abs() < 1e-6);
}
#[test]
fn altitude_clamp() {
let inst = ModelInstance {
position: GeoCoord::new(0.0, 0.0, 999.0),
altitude_mode: AltitudeMode::ClampToGround,
..ModelInstance::new(GeoCoord::default(), dummy_mesh())
};
assert!((inst.resolve_altitude(Some(200.0)) - 200.0).abs() < 1e-6);
}
}