aboutsummaryrefslogtreecommitdiff
path: root/src/math/mod.rs
blob: b84d270eb43ebc2a00d8b6b3dacf338780a8c46b (plain) (blame)
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
pub mod line_segment;
pub mod polygon;
pub mod rect;
pub mod triangle;
pub mod vec2;

pub use self::line_segment::*;
pub use self::polygon::*;
pub use self::rect::*;
pub use self::triangle::*;
pub use self::vec2::*;

use nalgebra::Scalar;
use std::cmp::Ordering;

/// Trait that describes an area in the vector space on the field of T
pub trait Surface<T: Scalar + Copy> {
    /// Checks if a point lies on this surface.
    fn contains_point(&self, point: &Vec2<T>) -> bool;

    /// Checks if a line segment is entirely contained by this surface.
    fn contains_line_segment(&self, line_segment: &LineSegment<T>) -> bool;

    /// Checks if a rectangle is entirely contained inside this surface.
    fn contains_rect(&self, rect: &Rect<T>) -> bool;

    /// Checks if a polygon is contained wholly by this surface.
    fn contains_polygon(&self, polygon: &Polygon<T>) -> bool;
}

/// Round a floating point number to the nearest step given by the step argument. For instance, if
/// the step is 0.5, then all numbers from 0.0 to 0.24999... will be 0., while all numbers from
/// 0.25 to 0.74999... will be 0.5 and so on.
pub fn round(num: f32, step: f32) -> f32 {
    // Only positive steps will be accepted.
    assert!(step > 0.);

    let lower_bound = ((num / step) as i32) as f32 * step;
    let upper_bound = lower_bound + step;

    // Compare the distances and prefer the smaller. If they are the same, prefer the upper bound.
    if (num - lower_bound) < (upper_bound - num) {
        lower_bound
    } else {
        upper_bound
    }
}

/// Works like `std::cmp::max`, however also allows partial comparisons. It is specifically
/// designed so functions that should be able to use f32 and f64 work, eventhough these do not
/// implement Ord. The downside of this function however is, that its behaviour is undefined when
/// `f32::NaN` for instance were to be passed.
pub(crate) fn partial_max<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    match a.partial_cmp(&b) {
        Some(Ordering::Greater) => a,
        _ => b,
    }
}
/// Like `partial_max`, but for minimum values. Comes with the same downside, too.
pub(crate) fn partial_min<T>(a: T, b: T) -> T
where
    T: PartialOrd,
{
    match a.partial_cmp(&b) {
        Some(Ordering::Less) => a,
        _ => b,
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn partial_max() {
        assert_eq!(super::partial_max(0., 0.), 0.);
        assert_eq!(super::partial_max(-1., 1.), 1.);
        assert_eq!(super::partial_max(-2., -1.), -1.);
        assert_eq!(super::partial_max(2., 1.), 2.);
    }

    #[test]
    fn partial_min() {
        assert_eq!(super::partial_min(0., 0.), 0.);
        assert_eq!(super::partial_min(-1., 1.), -1.);
        assert_eq!(super::partial_min(-2., -1.), -2.);
        assert_eq!(super::partial_min(2., 1.), 1.);
    }
}