use crate::gradient::Gradient;
use crate::mesh::Mesh;
pub fn ordered_indexes(mesh: &impl Mesh, gradient: &Gradient, backward: bool) -> Vec<usize> {
let mut indexes: Vec<usize> = (0..mesh.len()).collect();
indexes.sort_by(|&a, &b| {
let dist_a = gradient.get_distance(a);
let dist_b = gradient.get_distance(b);
match dist_a.partial_cmp(&dist_b) {
Some(std::cmp::Ordering::Equal) => {
if backward {
b.cmp(&a) } else {
a.cmp(&b) }
}
Some(ord) => ord,
None => std::cmp::Ordering::Equal,
}
});
indexes
}
#[cfg(test)]
mod tests {
use super::*;
use crate::distance::*;
use crate::mesh_2d::Full2D;
#[test]
fn test_ordered_indexes_basic() {
let mesh = Full2D::new(5, 5);
let mut gradient = Gradient::from_mesh(&mesh);
gradient.set_distance(12, 0.0);
gradient.spread(&mesh);
let ordered = ordered_indexes(&mesh, &gradient, false);
assert_eq!(ordered.len(), 25);
assert_eq!(ordered[0], 12);
for i in 0..ordered.len() - 1 {
let dist_curr = gradient.get_distance(ordered[i]);
let dist_next = gradient.get_distance(ordered[i + 1]);
assert!(
dist_curr <= dist_next,
"Index {} (dist {}) should come before index {} (dist {})",
ordered[i],
dist_curr,
ordered[i + 1],
dist_next
);
}
}
#[test]
fn test_ordered_indexes_backward_tiebreaking() {
let mesh = Full2D::new(3, 1);
let mut gradient = Gradient::from_mesh(&mesh);
gradient.set_distance(1, 0.0);
gradient.spread(&mesh);
assert_eq!(gradient.get_distance(0), DISTANCE_STRAIGHT);
assert_eq!(gradient.get_distance(2), DISTANCE_STRAIGHT);
let ordered_forward = ordered_indexes(&mesh, &gradient, false);
let ordered_backward = ordered_indexes(&mesh, &gradient, true);
assert_eq!(ordered_forward[0], 1);
assert_eq!(ordered_backward[0], 1);
assert_eq!(ordered_forward[1], 0);
assert_eq!(ordered_forward[2], 2);
assert_eq!(ordered_backward[1], 2);
assert_eq!(ordered_backward[2], 0);
}
#[test]
fn test_ordered_indexes_unreachable_at_end() {
use crate::mesh_2d::Compact2D;
let map = "\
.#.
.#.";
let mesh = Compact2D::from_text(map).expect("Failed to parse map");
let mut gradient = Gradient::from_mesh(&mesh);
gradient.set_distance(0, 0.0);
gradient.spread(&mesh);
let ordered = ordered_indexes(&mesh, &gradient, false);
let last_idx = ordered.len() - 1;
assert_eq!(
gradient.get_distance(ordered[last_idx]),
DISTANCE_MAX,
"Last index should be unreachable"
);
}
#[test]
fn test_ordered_indexes_single_node() {
let mesh = Full2D::new(1, 1);
let gradient = Gradient::from_mesh(&mesh);
let ordered = ordered_indexes(&mesh, &gradient, false);
assert_eq!(ordered.len(), 1);
assert_eq!(ordered[0], 0);
}
}