use crate::Point;
#[derive(Clone, Debug, PartialEq)]
pub struct Scale {
factor: f64,
centre: Point,
}
impl std::fmt::Display for Scale {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "Scale by {} about {}", self.factor, self.centre)
}
}
impl Scale {
pub const fn new(factor: f64, centre: Point) -> Self {
Self { factor, centre }
}
pub const fn factor(&self) -> f64 {
self.factor
}
pub const fn centre(&self) -> &Point {
&self.centre
}
pub fn apply_to_point(&self, point: &Point) -> Point {
let self_center_x = self.centre.x();
let self_center_y = self.centre.y();
let dx = point.x() - self_center_x;
let dy = point.y() - self_center_y;
let new_x = (dx * self.factor) + self_center_x;
let new_y = (dy * self.factor) + self_center_y;
Point::new(new_x, new_y)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_scale_new() {
let scale = Scale::new(2.0, Point::integer(10, 20, 1e-9));
assert_eq!(scale.factor(), 2.0);
assert_eq!(scale.centre(), &Point::integer(10, 20, 1e-9));
}
#[test]
fn test_scale_getters() {
let centre = Point::integer(5, 10, 1e-9);
let scale = Scale::new(1.5, centre);
assert_eq!(scale.factor(), 1.5);
assert_eq!(scale.centre(), ¢re);
}
#[test]
fn test_scale_apply_at_centre() {
let centre = Point::integer(10, 10, 1e-9);
let scale = Scale::new(2.0, centre);
let scaled = scale.apply_to_point(¢re);
assert_eq!(scaled, centre);
}
#[test]
fn test_scale_double() {
let scale = Scale::new(2.0, Point::integer(0, 0, 1e-9));
let point = Point::integer(10, 5, 1e-9);
let scaled = scale.apply_to_point(&point);
let expected = Point::integer(20, 10, 1e-9);
assert_eq!(scaled.x(), expected.x());
assert_eq!(scaled.y(), expected.y());
}
#[test]
fn test_scale_display() {
let scale = Scale::new(2.5, Point::integer(10, 20, 1e-9));
insta::assert_snapshot!(scale.to_string(), @"Scale by 2.5 about Point(10 (1.000e-9), 20 (1.000e-9))");
}
#[test]
fn test_scale_half() {
let scale = Scale::new(0.5, Point::integer(0, 0, 1e-9));
let point = Point::integer(20, 10, 1e-9);
let scaled = scale.apply_to_point(&point);
let expected = Point::integer(10, 5, 1e-9);
assert_eq!(scaled.x(), expected.x());
assert_eq!(scaled.y(), expected.y());
}
#[test]
fn test_scale_by_zero() {
let scale = Scale::new(0.0, Point::integer(0, 0, 1e-9));
let point = Point::integer(10, 20, 1e-9);
let scaled = scale.apply_to_point(&point);
assert_eq!(scaled.x().absolute_value(), 0.0);
assert_eq!(scaled.y().absolute_value(), 0.0);
}
#[test]
fn test_scale_by_zero_nonorigin_centre() {
let centre = Point::integer(5, 5, 1e-9);
let scale = Scale::new(0.0, centre);
let point = Point::integer(10, 20, 1e-9);
let scaled = scale.apply_to_point(&point);
assert_eq!(scaled.x(), centre.x());
assert_eq!(scaled.y(), centre.y());
}
#[test]
fn test_scale_negative() {
let scale = Scale::new(-1.0, Point::integer(0, 0, 1e-9));
let point = Point::integer(10, 5, 1e-9);
let scaled = scale.apply_to_point(&point);
let expected = Point::integer(-10, -5, 1e-9);
assert_eq!(scaled.x(), expected.x());
assert_eq!(scaled.y(), expected.y());
}
#[test]
fn test_scale_negative_with_centre() {
let centre = Point::integer(10, 10, 1e-9);
let scale = Scale::new(-2.0, centre);
let point = Point::integer(15, 20, 1e-9);
let scaled = scale.apply_to_point(&point);
let expected = Point::integer(0, -10, 1e-9);
assert_eq!(scaled.x(), expected.x());
assert_eq!(scaled.y(), expected.y());
}
}