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
|
//! Useful mathematical operations in graphical contexts.
pub mod rect;
pub mod vec2;
use std::cmp::Ordering;
use nalgebra::RealField;
use num_traits::Pow;
pub use self::rect::*;
pub use self::vec2::*;
/// 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<T>(num: T, step: T) -> T
where
T: RealField,
{
// Only positive steps will be accepted.
assert!(step > T::zero());
let lower_bound = (num / step).floor() * 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
}
}
/// Like round, but instead of rounding to a certain fraction, rounds to the nth
/// decimal place instead of taking a granularity.
pub fn round_nth_decimal<T>(num: T, decimal_place: u16) -> T
where
T: RealField + Pow<u16, Output = T>,
{
round(num, nalgebra::convert::<f64, T>(0.1).pow(decimal_place))
}
/// 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.);
}
}
|