|
@@ -91,16 +91,11 @@ impl ShadowLine {
|
|
|
}
|
|
|
|
|
|
fn add(&mut self, other: Shadow) {
|
|
|
- let index = {
|
|
|
- let mut index = 0;
|
|
|
- while index < self.shadows.len() {
|
|
|
- if self.shadows[index].start >= other.start {
|
|
|
- break;
|
|
|
- }
|
|
|
- index += 1;
|
|
|
- }
|
|
|
- index
|
|
|
- };
|
|
|
+ let index = self
|
|
|
+ .shadows
|
|
|
+ .iter()
|
|
|
+ .position(|sh| sh.start >= other.start)
|
|
|
+ .unwrap_or(self.shadows.len());
|
|
|
|
|
|
// find whether there's an overlapping previous and next
|
|
|
// shadow segment
|
|
@@ -114,27 +109,42 @@ impl ShadowLine {
|
|
|
.get(index - 1)
|
|
|
.filter(|sh| sh.end > other.start)
|
|
|
};
|
|
|
- let next = if index == self.shadows.len() {
|
|
|
- None
|
|
|
- } else {
|
|
|
- self.shadows.get(index).filter(|sh| sh.start < other.end)
|
|
|
- };
|
|
|
+ let next = self.shadows.get(index).filter(|sh| sh.start < other.end);
|
|
|
|
|
|
match (previous, next) {
|
|
|
- // two overlapping segments: join them together
|
|
|
+ // 1 2 3 4 5 6 7 1 2 3 4 5 6 7
|
|
|
+ // [prev] [next] => [prev.......]
|
|
|
+ // [other]
|
|
|
+ //
|
|
|
+ // two overlapping segments: join them together,
|
|
|
+ // specifically extending the previous one and deleting
|
|
|
+ // the second
|
|
|
(Some(_), Some(n)) => {
|
|
|
self.shadows[index - 1].end = n.end;
|
|
|
self.shadows.remove(index);
|
|
|
}
|
|
|
- // just one overlapping segment: extend the segment in the
|
|
|
- // appropriate direction
|
|
|
+ // 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
|
|
|
+ // [prev] [next] => [prev] [next...]
|
|
|
+ // [other]
|
|
|
+ //
|
|
|
+ // just overlapping a later segment: pull the later
|
|
|
+ // segment's start point earlier
|
|
|
(None, Some(_)) => {
|
|
|
self.shadows[index].start = other.start;
|
|
|
}
|
|
|
+ // 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
|
|
|
+ // [prev] [next] => [prev...] [next]
|
|
|
+ // [other]
|
|
|
+ //
|
|
|
+ // just overlapping an earlier segment: pull the earlier
|
|
|
+ // segment's end point later
|
|
|
(Some(_), None) => {
|
|
|
self.shadows[index - 1].end = other.end;
|
|
|
}
|
|
|
- // no overlapping segments: add this one
|
|
|
+ // 1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
|
|
|
+ // [p] [n] => [p] [other] [n]
|
|
|
+ // [other]
|
|
|
+ // no overlapping segments: just add this one in between
|
|
|
(None, None) => {
|
|
|
self.shadows.insert(index, other);
|
|
|
}
|
|
@@ -145,13 +155,19 @@ impl ShadowLine {
|
|
|
pub struct Viewshed<T> {
|
|
|
pub vis: Board<bool>,
|
|
|
blocking: Box<fn(&T) -> bool>,
|
|
|
+ pub range: Option<usize>,
|
|
|
}
|
|
|
|
|
|
impl<T> Viewshed<T> {
|
|
|
pub fn create(original: &Board<T>, blocking: fn(&T) -> bool) -> Viewshed<T> {
|
|
|
let vis = Board::new_from(original.width(), original.height(), |_, _| false);
|
|
|
let blocking = Box::new(blocking);
|
|
|
- Viewshed { vis, blocking }
|
|
|
+ let range = None;
|
|
|
+ Viewshed {
|
|
|
+ vis,
|
|
|
+ blocking,
|
|
|
+ range,
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
pub fn visibility(&self, coord: impl Into<Coord>) -> bool {
|
|
@@ -198,9 +214,16 @@ impl<T> Viewshed<T> {
|
|
|
let visible = !line.in_shadow(&projection);
|
|
|
self.vis[pos] = visible;
|
|
|
|
|
|
- if visible && (self.blocking)(&board[pos]) {
|
|
|
- line.add(projection);
|
|
|
- full_shadow = line.is_full_shadow();
|
|
|
+ if visible {
|
|
|
+ let out_of_range = if let Some(r) = self.range {
|
|
|
+ ((row.pow(2) + col.pow(2)) as f32).sqrt() >= r as f32
|
|
|
+ } else {
|
|
|
+ false
|
|
|
+ };
|
|
|
+ if out_of_range || (self.blocking)(&board[pos]) {
|
|
|
+ line.add(projection);
|
|
|
+ full_shadow = line.is_full_shadow();
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|