fast_sweeping/
fast_sweeping.rs

1use crate::{min3, DistanceField, DistanceFieldAlgorithm, Grid, Obstacles};
2
3pub struct NaiveFastSweepingMethod {
4    step_size: f32,
5    num_iter: usize,
6}
7
8impl DistanceFieldAlgorithm for NaiveFastSweepingMethod {
9    fn calculate_distance_field(&self, distance_field: &mut DistanceField, obstacles: &Obstacles) {
10        self.fast_sweeping(distance_field, obstacles)
11    }
12}
13
14impl NaiveFastSweepingMethod {
15    pub fn new(step_size: f32, num_iter: usize) -> Self {
16        Self {
17            step_size,
18            num_iter,
19        }
20    }
21
22    fn fast_sweeping(&self, distance_field: &mut DistanceField, obstacles: &Obstacles) {
23        self.initialize(distance_field, obstacles);
24        self.perform_sweeps(distance_field);
25    }
26
27    fn initialize(&self, distance_field: &mut DistanceField, obstacles: &Obstacles) {
28        distance_field
29            .iter_mut()
30            .zip(obstacles.iter())
31            .for_each(|(dist, &is_obstacle)| {
32                *dist = if is_obstacle {
33                    0_f32
34                } else {
35                    DistanceField::MAX_DISTANCE
36                };
37            });
38    }
39
40    fn perform_sweeps(&self, distance_field: &mut DistanceField) {
41        let num_iter = self.num_iter;
42        for _i in 0..num_iter {
43            self.sweep_topleft_bottomright(distance_field);
44            self.sweep_bottomright_topleft(distance_field);
45            self.sweep_topright_borromleft(distance_field);
46            self.sweep_bottomleft_topright(distance_field);
47        }
48    }
49
50    // First forward sweep (sweeping from top-left to bottom-right)
51    fn sweep_topleft_bottomright(&self, distance_field: &mut DistanceField) {
52        let step_size = self.step_size;
53        let height = distance_field.height();
54        let width = distance_field.width();
55
56        for y in 1..height {
57            // Initialize the left neighbor as the left-most pixel in the row.
58            let mut left_neighbor = *distance_field.get_at(0, y);
59            for x in 1..width {
60                let center = *distance_field.get_at(x, y);
61                let up_neighbor = *distance_field.get_at(x, y - 1);
62
63                let new_value = min3(center, up_neighbor + step_size, left_neighbor + step_size);
64                distance_field.set_at(x, y, new_value);
65
66                // Replace the left neighbor with the new center value.
67                // This skips the otherwise required reload in the next iteration.
68                left_neighbor = new_value;
69            }
70        }
71    }
72
73    // Second forward sweep (sweeping from bottom-right to top-left)
74    fn sweep_bottomright_topleft(&self, distance_field: &mut DistanceField) {
75        let step_size = self.step_size;
76        let height = distance_field.height();
77        let width = distance_field.width();
78
79        for y in (0..(height - 1)).rev() {
80            // Initialize the right neighbor as the right-most pixel in the row.
81            let mut right_neighbor = *distance_field.get_at(width - 1, y);
82            for x in (0..(width - 1)).rev() {
83                let center = *distance_field.get_at(x, y);
84                let down_neighbor = *distance_field.get_at(x, y + 1);
85
86                let new_value = min3(
87                    center,
88                    down_neighbor + step_size,
89                    right_neighbor + step_size,
90                );
91                distance_field.set_at(x, y, new_value);
92
93                // Replace the right neighbor with the new center value.
94                // This skips the otherwise required reload in the next iteration.
95                right_neighbor = new_value;
96            }
97        }
98    }
99
100    // Third backward sweep (sweeping from top-right to bottom-left)
101    fn sweep_topright_borromleft(&self, distance_field: &mut DistanceField) {
102        let step_size = self.step_size;
103        let height = distance_field.height();
104        let width = distance_field.width();
105
106        for y in 1..height {
107            // Initialize the right neighbor as the right-most pixel in the row.
108            let mut right_neighbor = *distance_field.get_at(width - 1, y);
109            for x in (0..(width - 1)).rev() {
110                let center = *distance_field.get_at(x, y);
111                let up_neighbor = *distance_field.get_at(x, y - 1);
112
113                let new_value = min3(center, up_neighbor + step_size, right_neighbor + step_size);
114                distance_field.set_at(x, y, new_value);
115
116                // Replace the right neighbor with the new center value.
117                // This skips the otherwise required reload in the next iteration.
118                right_neighbor = new_value;
119            }
120        }
121    }
122
123    // Fourth backward sweep (sweeping from bottom-left to top-right)
124    fn sweep_bottomleft_topright(&self, distance_field: &mut DistanceField) {
125        let step_size = self.step_size;
126        let height = distance_field.height();
127        let width = distance_field.width();
128
129        for y in (0..(height - 1)).rev() {
130            // Initialize the left neighbor as the left-most pixel in the row.
131            let mut left_neighbor = *distance_field.get_at(0, y);
132            for x in 1..width {
133                let center = *distance_field.get_at(x, y);
134                let down_neighbor = *distance_field.get_at(x, y + 1);
135
136                let new_value = min3(center, down_neighbor + step_size, left_neighbor + step_size);
137                distance_field.set_at(x, y, new_value);
138
139                // Replace the left neighbor with the new center value.
140                // This skips the otherwise required reload in the next iteration.
141                left_neighbor = new_value;
142            }
143        }
144    }
145}
146
147#[cfg(test)]
148mod tests {
149    use super::*;
150
151    #[test]
152    fn it_works() {
153        let mut obstacles = Obstacles::new(640, 480);
154
155        for y in 100..200 {
156            obstacles.set_at(100, y, true);
157        }
158
159        for x in 100..400 {
160            obstacles.set_at(x, 200, true);
161        }
162
163        for x in 100..200 {
164            obstacles.set_at(400 + x, 200 + x, true);
165        }
166
167        let mut distance_field = DistanceField::from(&obstacles);
168
169        let naive = NaiveFastSweepingMethod::new(0.1, 5);
170        naive.calculate_distance_field(&mut distance_field, &obstacles);
171    }
172}