Skip to main content

morphological_operations/
morphological_operations.rs

1//! Morphological Operations Demo
2//!
3//! Demonstrates shape analysis with erosion, dilation, opening, and closing
4
5use terrain_forge::{
6    algorithms,
7    spatial::{morphological_transform, MorphologyOp, StructuringElement},
8    Grid, Tile,
9};
10
11fn main() {
12    println!("=== Morphological Operations Demo ===\n");
13
14    // Generate a cellular automata cave
15    let mut grid = Grid::new(30, 20);
16    let algo = algorithms::get("cellular").unwrap();
17    algo.generate(&mut grid, 98765);
18
19    println!("1. Original Cave System (30x20):");
20    print_grid(&grid);
21
22    // Erosion - shrink shapes
23    println!("\n2. Erosion (3x3 rectangle):");
24    let rect_element = StructuringElement::rectangle(3, 3);
25    let eroded = morphological_transform(&grid, MorphologyOp::Erosion, &rect_element);
26    print_grid(&eroded);
27
28    // Dilation - expand shapes
29    println!("\n3. Dilation (3x3 rectangle):");
30    let dilated = morphological_transform(&grid, MorphologyOp::Dilation, &rect_element);
31    print_grid(&dilated);
32
33    // Opening - erosion followed by dilation (removes small features)
34    println!("\n4. Opening (removes small features):");
35    let opened = morphological_transform(&grid, MorphologyOp::Opening, &rect_element);
36    print_grid(&opened);
37
38    // Closing - dilation followed by erosion (fills small gaps)
39    println!("\n5. Closing (fills small gaps):");
40    let closed = morphological_transform(&grid, MorphologyOp::Closing, &rect_element);
41    print_grid(&closed);
42
43    // Different structuring elements
44    println!("\n6. Circular Structuring Element (radius 2):");
45    let circle_element = StructuringElement::circle(2);
46    let circle_eroded = morphological_transform(&grid, MorphologyOp::Erosion, &circle_element);
47    print_grid(&circle_eroded);
48
49    println!("\n7. Cross Structuring Element (size 5):");
50    let cross_element = StructuringElement::cross(5);
51    let cross_dilated = morphological_transform(&grid, MorphologyOp::Dilation, &cross_element);
52    print_grid(&cross_dilated);
53
54    // Iterative processing
55    println!("\n8. Multiple Iterations (3x erosion):");
56    let mut iterative = grid.clone();
57    for i in 1..=3 {
58        iterative = morphological_transform(&iterative, MorphologyOp::Erosion, &rect_element);
59        println!("   Iteration {}:", i);
60        print_grid_compact(&iterative);
61    }
62
63    // Performance comparison
64    println!("\n9. Performance Analysis:");
65    let elements = [
66        ("Rectangle 3x3", StructuringElement::rectangle(3, 3)),
67        ("Circle r=2", StructuringElement::circle(2)),
68        ("Cross 5x5", StructuringElement::cross(5)),
69    ];
70
71    for (name, element) in &elements {
72        let start = std::time::Instant::now();
73        let _ = morphological_transform(&grid, MorphologyOp::Erosion, element);
74        println!("   {} erosion: {:?}", name, start.elapsed());
75    }
76
77    // Shape analysis
78    println!("\n10. Shape Analysis:");
79    let original_floors = grid.count(|t| t.is_floor());
80    let eroded_floors = eroded.count(|t| t.is_floor());
81    let dilated_floors = dilated.count(|t| t.is_floor());
82
83    println!("   Original floors: {}", original_floors);
84    println!(
85        "   After erosion: {} ({:.1}% reduction)",
86        eroded_floors,
87        100.0 * (original_floors - eroded_floors) as f32 / original_floors as f32
88    );
89    println!(
90        "   After dilation: {} ({:.1}% increase)",
91        dilated_floors,
92        100.0 * (dilated_floors - original_floors) as f32 / original_floors as f32
93    );
94}
95
96fn print_grid(grid: &Grid<Tile>) {
97    for y in 0..grid.height() {
98        for x in 0..grid.width() {
99            let tile = grid.get(x as i32, y as i32).unwrap();
100            print!("{}", if tile.is_floor() { "." } else { "#" });
101        }
102        println!();
103    }
104}
105
106fn print_grid_compact(grid: &Grid<Tile>) {
107    for y in 0..grid.height().min(8) {
108        print!("     ");
109        for x in 0..grid.width() {
110            let tile = grid.get(x as i32, y as i32).unwrap();
111            print!("{}", if tile.is_floor() { "." } else { "#" });
112        }
113        println!();
114    }
115    if grid.height() > 8 {
116        println!("     ... ({} more rows)", grid.height() - 8);
117    }
118}