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
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}