engine/map/src/tile.rs
2024-08-23 13:22:09 +02:00

191 lines
6.5 KiB
Rust

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<f32>) -> 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<f32>,
pub right_bottom: Vector3<f32>,
pub left_top: Vector3<f32>,
pub right_top: Vector3<f32>,
}
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
}
}