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