rustial-engine 0.0.1

Framework-agnostic 2.5D map engine for rustial
Documentation
//! Point-cloud / scatter descriptors.

use crate::models::AltitudeMode;
use rustial_math::GeoCoord;

/// A single point-cloud instance anchored to a geographic position.
#[derive(Debug, Clone)]
pub struct PointInstance {
    /// Geographic anchor position.
    pub position: GeoCoord,
    /// Point radius in meters.
    pub radius: f64,
    /// Intensity value used by fallback colour ramps.
    pub intensity: f32,
    /// Optional per-instance RGBA colour override.
    pub color: Option<[f32; 4]>,
    /// Stable pick identifier returned by the picking system.
    pub pick_id: u64,
    /// Altitude mode for this point.
    pub altitude_mode: AltitudeMode,
}

impl PointInstance {
    /// Create a point instance with the given position and radius.
    pub fn new(position: GeoCoord, radius: f64) -> Self {
        Self {
            position,
            radius,
            intensity: 1.0,
            color: None,
            pick_id: 0,
            altitude_mode: AltitudeMode::ClampToGround,
        }
    }

    /// Set the intensity.
    pub fn with_intensity(mut self, intensity: f32) -> Self {
        self.intensity = intensity;
        self
    }

    /// Set the pick id.
    pub fn with_pick_id(mut self, id: u64) -> Self {
        self.pick_id = id;
        self
    }

    /// Set an RGBA colour override.
    pub fn with_color(mut self, color: [f32; 4]) -> Self {
        self.color = Some(color);
        self
    }

    /// Set the altitude mode.
    pub fn with_altitude_mode(mut self, altitude_mode: AltitudeMode) -> Self {
        self.altitude_mode = altitude_mode;
        self
    }
}

/// A collection of [`PointInstance`]s with a generation counter.
#[derive(Debug, Clone)]
pub struct PointInstanceSet {
    /// The point instances.
    pub points: Vec<PointInstance>,
    /// Structural generation counter. Bump when the number or identity
    /// of points changes.
    pub generation: u64,
}

impl PointInstanceSet {
    /// Create a new set from existing points.
    pub fn new(points: Vec<PointInstance>) -> Self {
        Self {
            points,
            generation: 0,
        }
    }

    /// Number of points.
    #[inline]
    pub fn len(&self) -> usize {
        self.points.len()
    }

    /// Whether the set is empty.
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.points.is_empty()
    }
}

impl Default for PointInstanceSet {
    fn default() -> Self {
        Self::new(Vec::new())
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn point_instance_defaults() {
        let point = PointInstance::new(GeoCoord::from_lat_lon(0.0, 0.0), 4.0);
        assert!((point.radius - 4.0).abs() < 1e-9);
        assert!((point.intensity - 1.0).abs() < 1e-6);
        assert!(point.color.is_none());
        assert_eq!(point.pick_id, 0);
    }

    #[test]
    fn point_instance_builder() {
        let point = PointInstance::new(GeoCoord::from_lat_lon(0.0, 0.0), 2.5)
            .with_intensity(0.25)
            .with_pick_id(42)
            .with_color([1.0, 0.0, 0.0, 1.0])
            .with_altitude_mode(AltitudeMode::Absolute);
        assert_eq!(point.pick_id, 42);
        assert_eq!(point.color, Some([1.0, 0.0, 0.0, 1.0]));
        assert!((point.intensity - 0.25).abs() < 1e-6);
        assert_eq!(point.altitude_mode, AltitudeMode::Absolute);
    }

    #[test]
    fn point_instance_set_len() {
        let set = PointInstanceSet::new(vec![
            PointInstance::new(GeoCoord::from_lat_lon(0.0, 0.0), 2.0),
            PointInstance::new(GeoCoord::from_lat_lon(1.0, 1.0), 3.0),
        ]);
        assert_eq!(set.len(), 2);
        assert!(!set.is_empty());
    }
}