summaryrefslogtreecommitdiff
path: root/src/math/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/math/mod.rs')
-rw-r--r--src/math/mod.rs93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/math/mod.rs b/src/math/mod.rs
new file mode 100644
index 0000000..8b22972
--- /dev/null
+++ b/src/math/mod.rs
@@ -0,0 +1,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.);
+ }
+}