Skip to main content

DistanceTransform

Struct DistanceTransform 

Source
pub struct DistanceTransform { /* private fields */ }
Expand description

Distance transform result

Implementations§

Source§

impl DistanceTransform

Source

pub fn new(width: usize, height: usize) -> Self

Source

pub fn get(&self, x: usize, y: usize) -> f32

Examples found in repository?
examples/distance_transforms.rs (line 63)
60fn print_distance_field(transform: &terrain_forge::spatial::DistanceTransform) {
61    for y in 0..transform.height() {
62        for x in 0..transform.width() {
63            let dist = transform.get(x, y);
64            if dist == f32::INFINITY {
65                print!("## ");
66            } else if dist < 10.0 {
67                print!("{:2.0} ", dist);
68            } else {
69                print!("++ ");
70            }
71        }
72        println!();
73    }
74}
More examples
Hide additional examples
examples/spatial_workflow.rs (line 52)
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}
Source

pub fn set(&mut self, x: usize, y: usize, distance: f32)

Source

pub fn width(&self) -> usize

Examples found in repository?
examples/distance_transforms.rs (line 62)
60fn print_distance_field(transform: &terrain_forge::spatial::DistanceTransform) {
61    for y in 0..transform.height() {
62        for x in 0..transform.width() {
63            let dist = transform.get(x, y);
64            if dist == f32::INFINITY {
65                print!("## ");
66            } else if dist < 10.0 {
67                print!("{:2.0} ", dist);
68            } else {
69                print!("++ ");
70            }
71        }
72        println!();
73    }
74}
More examples
Hide additional examples
examples/spatial_workflow.rs (line 51)
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}
Source

pub fn height(&self) -> usize

Examples found in repository?
examples/distance_transforms.rs (line 61)
60fn print_distance_field(transform: &terrain_forge::spatial::DistanceTransform) {
61    for y in 0..transform.height() {
62        for x in 0..transform.width() {
63            let dist = transform.get(x, y);
64            if dist == f32::INFINITY {
65                print!("## ");
66            } else if dist < 10.0 {
67                print!("{:2.0} ", dist);
68            } else {
69                print!("++ ");
70            }
71        }
72        println!();
73    }
74}
More examples
Hide additional examples
examples/spatial_workflow.rs (line 50)
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}

Trait Implementations§

Source§

impl Clone for DistanceTransform

Source§

fn clone(&self) -> DistanceTransform

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for DistanceTransform

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V