// Copyright (C) 2025 Christian Mauduit <ufoot@ufoot.org>

//! Distance constants and utilities for pathfinding.
//!
//! This module defines standard distance values used throughout the pathfinding
//! algorithms, particularly for grid-based meshes.

use std::f64::consts::SQRT_2;

/// Minimum distance value, representing zero distance.
///
/// This is typically used to mark target nodes in a gradient,
/// indicating they are at the destination with no distance to travel.
///
/// # Example
///
/// ```
/// use shortestpath::{DISTANCE_MIN, Gradient, mesh_2d::Full2D};
///
/// let mesh = Full2D::new(5, 5);
/// let mut gradient = Gradient::from_mesh(&mesh);
///
/// // Set target node with minimum distance
/// gradient.set_distance(12, DISTANCE_MIN);
/// ```
pub const DISTANCE_MIN: f64 = 0.0;

/// Maximum distance value, representing unreachable or uninitialized nodes.
///
/// This is used to initialize gradient nodes before pathfinding computation.
/// Nodes that remain at `DISTANCE_MAX` after gradient spreading are unreachable
/// from the target.
///
/// # Example
///
/// ```
/// use shortestpath::{DISTANCE_MAX, Gradient};
///
/// let gradient = Gradient::with_len(10);
/// // All nodes start at DISTANCE_MAX (unreachable)
/// assert_eq!(gradient.get_distance(0), DISTANCE_MAX);
/// ```
pub const DISTANCE_MAX: f64 = f64::MAX;

/// Distance for orthogonal (straight) movement in a grid.
///
/// This represents the cost of moving horizontally or vertically in a grid-based
/// mesh (north, south, east, west). The value is 1.0, making it the base unit
/// of distance.
///
/// # Example
///
/// ```
/// use shortestpath::{DISTANCE_STRAIGHT, Gate};
///
/// // Moving right in a grid has straight distance
/// let gate = Gate::new(5, DISTANCE_STRAIGHT);
/// assert_eq!(gate.distance, 1.0);
/// ```
pub const DISTANCE_STRAIGHT: f64 = 1.0;

/// Distance for diagonal movement in a grid.
///
/// This represents the cost of moving diagonally in a grid-based mesh
/// (northeast, northwest, southeast, southwest). The value is √2 (approximately 1.414),
/// which is the Euclidean distance for diagonal movement in a unit grid.
///
/// Using the correct diagonal distance ensures that pathfinding produces
/// geometrically accurate shortest paths.
///
/// # Example
///
/// ```
/// use shortestpath::{DISTANCE_DIAGONAL, Gate};
///
/// // Moving diagonally in a grid
/// let gate = Gate::new(6, DISTANCE_DIAGONAL);
/// assert!((gate.distance - 1.414).abs() < 0.001);
/// ```
pub const DISTANCE_DIAGONAL: f64 = SQRT_2;

/// Distance for 3D diagonal movement across layers.
///
/// This represents the cost of moving diagonally in three dimensions simultaneously
/// (e.g., northeast and up). The value is √3 (approximately 1.732), which is the
/// Euclidean distance for 3D diagonal movement in a unit grid.
///
/// This is used in true 3D meshes where movement can be diagonal across layers,
/// unlike 2.5D meshes which only support orthogonal vertical movement.
///
/// Note: Unlike [`DISTANCE_DIAGONAL`] which uses `std::f64::consts::SQRT_2`,
/// there is no `SQRT_3` constant in Rust's standard library, so we compute
/// and store the value directly.
///
/// # Example
///
/// ```
/// use shortestpath::{DISTANCE_DIAGONAL_3D, Gate};
///
/// // Moving diagonally in 3D space (e.g., northeast and up)
/// let gate = Gate::new(7, DISTANCE_DIAGONAL_3D);
/// assert!((gate.distance - 1.732).abs() < 0.001);
/// ```
pub const DISTANCE_DIAGONAL_3D: f64 = 1.732_050_807_568_877_2; // sqrt(3), no std constant available

/// Precision threshold for floating-point distance comparisons.
///
/// This internal constant is used when comparing distances for equality,
/// accounting for floating-point arithmetic precision issues. Two distances
/// that differ by less than this threshold are considered equal.
///
/// Used internally by `Gate::eq()` for comparing gate distances.
pub(crate) const DISTANCE_PRECISION: f64 = 1e-9;
