191 lines
6.5 KiB
Rust
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
|
|
}
|
|
}
|