Skip to main content

morphological_transform

Function morphological_transform 

Source
pub fn morphological_transform<C: Cell>(
    grid: &Grid<C>,
    op: MorphologyOp,
    element: &StructuringElement,
) -> Grid<Tile>
Expand description

Apply morphological transformation to grid

Examples found in repository?
examples/morphological_operations.rs (line 25)
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}
More examples
Hide additional examples
examples/spatial_workflow.rs (line 34)
14fn main() {
15    println!("=== Complete Spatial Analysis Workflow ===\n");
16
17    // Step 1: Generate base dungeon
18    println!("1. Generating Base Dungeon:");
19    let mut grid = Grid::new(40, 30);
20    let algo = algorithms::get("bsp").unwrap();
21    algo.generate(&mut grid, 42424);
22
23    let original_floors = grid.count(|t| t.is_floor());
24    println!(
25        "   Generated {}x{} dungeon with {} floor tiles",
26        grid.width(),
27        grid.height(),
28        original_floors
29    );
30
31    // Step 2: Clean up with morphological operations
32    println!("\n2. Cleaning Up Small Features:");
33    let cleanup_element = StructuringElement::rectangle(3, 3);
34    let cleaned = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
35
36    let cleaned_floors = cleaned.count(|t| t.is_floor());
37    println!(
38        "   Removed {} small features ({} floors remaining)",
39        original_floors - cleaned_floors,
40        cleaned_floors
41    );
42
43    // Step 3: Analyze distances from walls
44    println!("\n3. Analyzing Distance from Walls:");
45    let distance_map = distance_field(&cleaned, DistanceMetric::Euclidean);
46
47    let mut max_distance = 0.0;
48    let mut center_points = Vec::new();
49
50    for y in 0..distance_map.height() {
51        for x in 0..distance_map.width() {
52            let dist = distance_map.get(x, y);
53            if dist != f32::INFINITY {
54                if dist > max_distance {
55                    max_distance = dist;
56                    center_points.clear();
57                    center_points.push((x, y));
58                } else if (dist - max_distance).abs() < 0.1 {
59                    center_points.push((x, y));
60                }
61            }
62        }
63    }
64
65    println!("   Maximum distance from walls: {:.1}", max_distance);
66    println!("   Found {} center points", center_points.len());
67
68    // Step 4: Create strategic pathfinding network
69    println!("\n4. Creating Strategic Pathfinding Network:");
70
71    // Use the most central points as strategic locations
72    let strategic_points: Vec<_> = center_points.into_iter().take(3).collect();
73    println!("   Strategic points: {:?}", strategic_points);
74
75    let constraints = PathfindingConstraints::default();
76    let strategic_dijkstra = dijkstra_map(&cleaned, &strategic_points, &constraints);
77
78    // Step 5: Generate AI movement flow field
79    println!("\n5. Generating AI Movement Flow Field:");
80    let flow_field = flow_field_from_dijkstra(&strategic_dijkstra);
81
82    // Analyze flow field coverage
83    let mut flow_coverage = 0;
84    for y in 0..flow_field.height() {
85        for x in 0..flow_field.width() {
86            let (dx, dy) = flow_field.get_direction(x, y);
87            if dx != 0 || dy != 0 {
88                flow_coverage += 1;
89            }
90        }
91    }
92
93    println!("   Flow field covers {} cells", flow_coverage);
94
95    // Step 6: Identify chokepoints using morphological analysis
96    println!("\n6. Identifying Chokepoints:");
97    let thin_element = StructuringElement::rectangle(2, 2);
98    let thinned = morphological_transform(&cleaned, MorphologyOp::Erosion, &thin_element);
99
100    let mut chokepoints = Vec::new();
101    for y in 1..cleaned.height() - 1 {
102        for x in 1..cleaned.width() - 1 {
103            if let (Some(original), Some(thinned_cell)) = (
104                cleaned.get(x as i32, y as i32),
105                thinned.get(x as i32, y as i32),
106            ) {
107                if original.is_floor() && !thinned_cell.is_floor() {
108                    // This was a floor that got eroded - potential chokepoint
109                    let neighbors = count_floor_neighbors(&cleaned, x, y);
110                    if (2..=4).contains(&neighbors) {
111                        chokepoints.push((x, y));
112                    }
113                }
114            }
115        }
116    }
117
118    println!("   Found {} potential chokepoints", chokepoints.len());
119
120    // Step 7: Performance summary
121    println!("\n7. Performance Summary:");
122
123    let start = std::time::Instant::now();
124    let _ = morphological_transform(&grid, MorphologyOp::Opening, &cleanup_element);
125    println!("   Morphological cleanup: {:?}", start.elapsed());
126
127    let start = std::time::Instant::now();
128    let _ = distance_field(&cleaned, DistanceMetric::Euclidean);
129    println!("   Distance field calculation: {:?}", start.elapsed());
130
131    let start = std::time::Instant::now();
132    let _ = dijkstra_map(&cleaned, &strategic_points, &constraints);
133    println!("   Dijkstra map generation: {:?}", start.elapsed());
134
135    let start = std::time::Instant::now();
136    let _ = flow_field_from_dijkstra(&strategic_dijkstra);
137    println!("   Flow field generation: {:?}", start.elapsed());
138
139    // Step 8: Spatial analysis results
140    println!("\n8. Spatial Analysis Results:");
141    println!("   Original dungeon: {} floors", original_floors);
142    println!("   After cleanup: {} floors", cleaned_floors);
143    println!("   Strategic locations: {}", strategic_points.len());
144    println!("   Chokepoints identified: {}", chokepoints.len());
145    println!(
146        "   Flow field coverage: {:.1}%",
147        100.0 * flow_coverage as f32 / cleaned_floors as f32
148    );
149
150    println!("\n✅ Spatial analysis workflow complete!");
151    println!("   The dungeon is now ready for:");
152    println!("   - AI pathfinding using flow fields");
153    println!("   - Strategic placement at center points");
154    println!("   - Tactical analysis of chokepoints");
155    println!("   - Distance-based gameplay mechanics");
156}