use engine::prelude::cgmath::{Vector2, Vector3}; use super::{mapdata::Coordinate, surface::Surface}; #[derive(Clone, Copy, Debug)] pub enum SlopeDirection { LeftToRight, RightToLeft, TopToBottom, BottomToTop, DiagonalBottomLeftToTopRight, DiagonalTopLeftToBottomRight, DiagonalTopRightToBottomLeft, DiagonalBottomRightToTopLeft, } impl SlopeDirection { pub fn from_direction(direction: Vector2) -> SlopeDirection { if direction.x < 0.0 { if direction.y < 0.0 { if Self::almost_eq(direction.x, direction.y) { SlopeDirection::DiagonalTopRightToBottomLeft } else if direction.x < direction.y { SlopeDirection::RightToLeft } else { SlopeDirection::TopToBottom } } else if Self::almost_eq(direction.x.abs(), direction.y) { SlopeDirection::DiagonalBottomRightToTopLeft } else if direction.x.abs() < direction.y { SlopeDirection::BottomToTop } else { SlopeDirection::RightToLeft } } else if direction.y < 0.0 { if Self::almost_eq(direction.x, direction.y.abs()) { SlopeDirection::DiagonalTopLeftToBottomRight } else if direction.x < direction.y.abs() { SlopeDirection::TopToBottom } else { SlopeDirection::LeftToRight } } else if Self::almost_eq(direction.x, direction.y) { SlopeDirection::DiagonalBottomLeftToTopRight } else if direction.x < direction.y { SlopeDirection::BottomToTop } else { SlopeDirection::LeftToRight } } #[inline] fn almost_eq(f1: f32, f2: f32) -> bool { let epsilon = 0.001; (f1 + epsilon > f2) && (f1 - epsilon < f2) } } #[derive(Debug)] pub struct Tile { pub left_bottom: Vector3, pub right_bottom: Vector3, pub left_top: Vector3, pub right_top: Vector3, } impl Tile { pub fn new(base_coord: Coordinate, surface: &Surface) -> Tile { Tile { left_bottom: surface.point(base_coord.x, base_coord.y), right_bottom: surface.point(base_coord.x + 1, base_coord.y), left_top: surface.point(base_coord.x, base_coord.y + 1), right_top: surface.point(base_coord.x + 1, base_coord.y + 1), } } /// checks for the slope in given direction with given threshold /// /// returns `true` when slope is below threshold, `false` otherwise pub fn check_slope( &self, threshold: f32, direction: SlopeDirection, increase_only: bool, ) -> bool { match direction { SlopeDirection::LeftToRight => { let bottom_difference = self.left_bottom.z - self.right_bottom.z; // check bottom slope against threshold if !Self::check_directed_slope(bottom_difference, threshold, increase_only) { return false; } let top_difference = self.left_top.z - self.right_top.z; //check top slope against threshold if !Self::check_directed_slope(top_difference, threshold, increase_only) { return false; } } SlopeDirection::RightToLeft => { let bottom_difference = self.right_bottom.z - self.left_bottom.z; if !Self::check_directed_slope(bottom_difference, threshold, increase_only) { return false; } let top_difference = self.right_top.z - self.left_top.z; if !Self::check_directed_slope(top_difference, threshold, increase_only) { return false; } } SlopeDirection::BottomToTop => { let left_difference = self.left_bottom.z - self.left_top.z; if !Self::check_directed_slope(left_difference, threshold, increase_only) { return false; } let right_difference = self.right_bottom.z - self.right_top.z; if !Self::check_directed_slope(right_difference, threshold, increase_only) { return false; } } SlopeDirection::TopToBottom => { let left_difference = self.left_top.z - self.left_bottom.z; if !Self::check_directed_slope(left_difference, threshold, increase_only) { return false; } let right_difference = self.right_top.z - self.right_bottom.z; if !Self::check_directed_slope(right_difference, threshold, increase_only) { return false; } } SlopeDirection::DiagonalBottomLeftToTopRight => { let diagonal_difference = self.left_bottom.z - self.right_top.z; if !Self::check_directed_slope(diagonal_difference, threshold, increase_only) { return false; } } SlopeDirection::DiagonalBottomRightToTopLeft => { let diagonal_difference = self.right_bottom.z - self.left_top.z; if !Self::check_directed_slope(diagonal_difference, threshold, increase_only) { return false; } } SlopeDirection::DiagonalTopLeftToBottomRight => { let diagonal_difference = self.left_top.z - self.right_bottom.z; if !Self::check_directed_slope(diagonal_difference, threshold, increase_only) { return false; } } SlopeDirection::DiagonalTopRightToBottomLeft => { let diagonal_difference = self.right_top.z - self.left_bottom.z; if !Self::check_directed_slope(diagonal_difference, threshold, increase_only) { return false; } } } true } #[inline] fn check_directed_slope(difference: f32, threshold: f32, increase_only: bool) -> bool { // check slope against threshold if difference.abs() > threshold { // if increase only, check for increase if increase_only { if difference < 0.0 { return false; } } else { return false; } } true } }