1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! Implementation of the general laser point type used throughout the crate.

use crate::lerp::Lerp;

/// A position in 2D space represented by x and y coordinates.
pub type Position = [f32; 2];

/// Red, green and blue channels of a single colour.
pub type Rgb = [f32; 3];

/// The point type used within the laser frame stream API.
///
/// The point represents the location to which the scanner should point and the colour that the
/// scanner should be at this point.
///
/// If two consecutive points have two different colours, the `color` values will be linearly
/// interpolated.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Point {
    /// The position of the point. `-1` represents the minimum value along the axis and `1`
    /// represents the maximum.
    pub position: Position,
    /// The color of the point.
    pub color: Rgb,
    /// The minimum number of extra times this point should be drawn.
    ///
    /// `0` is the default used for drawing sequences of smooth line segments.
    ///
    /// Values greater than `0` are useful for accenting individual points.
    pub weight: u32,
}

/// The **Point** type used for describing raw laser streams.
///
/// The point represents the location to which the scanner should point and the colour that the
/// scanner should be at this point.
///
/// If two consecutive points have two different colours, the `color` values will be linearly
/// interpolated.
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct RawPoint {
    /// The position of the point. `-1` represents the minimum value along the axis and `1`
    /// represents the maximum.
    pub position: Position,
    /// The color of the point.
    pub color: Rgb,
}

impl Point {
    /// The default weight for points used to draw lines.
    pub const DEFAULT_LINE_POINT_WEIGHT: u32 = 0;

    /// Create a **Point** at the given position with the given colour with a default weight.
    pub fn new(position: Position, color: Rgb) -> Self {
        Point::with_weight(position, color, Self::DEFAULT_LINE_POINT_WEIGHT)
    }

    /// The same as `Point::new` but allows for specifying the weight of the point.
    pub fn with_weight(position: Position, color: Rgb, weight: u32) -> Self {
        Point { position, color, weight }
    }

    /// Create a blank point at `[0, 0]`.
    pub fn centered_blank() -> Self {
        Point::new([0.0, 0.0], [0.0, 0.0, 0.0])
    }

    /// Returns a point with the same position as `self` but with a black (blank) color.
    pub fn blanked(&self) -> Self {
        let mut blanked = *self;
        blanked.color = [0.0, 0.0, 0.0];
        blanked
    }

    /// Whether or not the point is blank.
    ///
    /// A point is considered blank if the colour is black.
    pub fn is_blank(&self) -> bool {
        color_is_blank(self.color)
    }

    /// Converts to a single raw point with the same position and color.
    pub fn to_raw(&self) -> RawPoint {
        RawPoint::new(self.position, self.color)
    }

    /// Converts to `weight` number of raw points with the same position and color.
    pub fn to_raw_weighted(&self) -> impl Iterator<Item = RawPoint> {
        let Point { position, color, weight } = *self;
        (0..weight).map(move |_| RawPoint::new(position, color))
    }
}

impl RawPoint {
    /// Create a **Point** at the given position with the given colour.
    pub fn new(position: Position, color: Rgb) -> Self {
        RawPoint { position, color }
    }

    /// Convert to a point compatible with a laser *frame* stream with the given weight.
    pub fn with_weight(&self, weight: u32) -> Point {
        Point::with_weight(self.position, self.color, weight)
    }

    /// Create a blank point at `[0, 0]`.
    pub fn centered_blank() -> Self {
        RawPoint::new([0.0, 0.0], [0.0, 0.0, 0.0])
    }

    /// Returns a point with the same position as `self` but with a black (blank) color.
    pub fn blanked(&self) -> Self {
        let mut blanked = *self;
        blanked.color = [0.0, 0.0, 0.0];
        blanked
    }

    /// Whether or not the point is blank.
    ///
    /// A point is considered blank if the colour is black.
    pub fn is_blank(&self) -> bool {
        color_is_blank(self.color)
    }
}

impl Lerp for RawPoint {
    type Scalar = f32;
    fn lerp(&self, other: &Self, amt: f32) -> Self {
        RawPoint::new(self.position.lerp(&other.position, amt), self.color.lerp(&other.color, amt))
    }
}

/// Whether or not the given point is blank (black).
pub fn color_is_blank([r, g, b]: Rgb) -> bool {
    r == 0.0 && g == 0.0 && b == 0.0
}