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
use crate::Result;
use std::fmt;
/// A scale and an offset that transforms xyz coordinates.
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Transform {
/// The scale.
pub scale: f64,
/// The offset.
pub offset: f64,
}
impl Transform {
/// Applies this transform to an i32, returning a float.
///
/// # Examples
///
/// ```
/// use las::Transform;
/// let transform = Transform { scale: 2., offset: 1. };
/// assert_eq!(3., transform.direct(1));
/// ```
pub fn direct(&self, n: i32) -> f64 {
self.scale * f64::from(n) + self.offset
}
/// Applies the inverse transform, and rounds the result.
///
/// Returns an error if the resultant value can't be represented as an i32.
///
/// # Examples
///
/// ```
/// use las::Transform;
/// let transform = Transform { scale: 2., offset: 1. };
/// assert_eq!(1, transform.inverse(2.9).unwrap());
/// ```
pub fn inverse(&self, n: f64) -> Result<i32> {
use crate::Error;
use std::i32;
let n = ((n - self.offset) / self.scale).round();
if n > f64::from(i32::MAX) || n < f64::from(i32::MIN) {
Err(Error::InverseTransform {
n,
transform: *self,
})
} else {
Ok(n as i32)
}
}
}
impl Default for Transform {
fn default() -> Transform {
Transform {
scale: 0.001,
offset: 0.,
}
}
}
impl fmt::Display for Transform {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "`{} * x + {}`", self.scale, self.offset)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::i32;
#[test]
fn too_large() {
let transform = Transform::default();
let n = i32::MAX as f64 * transform.scale + 1.;
assert!(transform.inverse(n).is_err());
}
#[test]
fn too_small() {
let transform = Transform::default();
let n = i32::MIN as f64 * transform.scale - 1.;
assert!(transform.inverse(n).is_err());
}
}