iced_graphics/
damage.rs
1use crate::core::{Point, Rectangle};
3
4pub fn diff<T>(
6 previous: &[T],
7 current: &[T],
8 bounds: impl Fn(&T) -> Vec<Rectangle>,
9 diff: impl Fn(&T, &T) -> Vec<Rectangle>,
10) -> Vec<Rectangle> {
11 let damage = previous.iter().zip(current).flat_map(|(a, b)| diff(a, b));
12
13 if previous.len() == current.len() {
14 damage.collect()
15 } else {
16 let (smaller, bigger) = if previous.len() < current.len() {
17 (previous, current)
18 } else {
19 (current, previous)
20 };
21
22 damage
24 .chain(bigger[smaller.len()..].iter().flat_map(bounds))
25 .collect()
26 }
27}
28
29pub fn list<T>(
31 previous: &[T],
32 current: &[T],
33 bounds: impl Fn(&T) -> Vec<Rectangle>,
34 are_equal: impl Fn(&T, &T) -> bool,
35) -> Vec<Rectangle> {
36 diff(previous, current, &bounds, |a, b| {
37 if are_equal(a, b) {
38 vec![]
39 } else {
40 bounds(a).into_iter().chain(bounds(b)).collect()
41 }
42 })
43}
44
45pub fn group(mut damage: Vec<Rectangle>, bounds: Rectangle) -> Vec<Rectangle> {
48 const AREA_THRESHOLD: f32 = 20_000.0;
49
50 damage.sort_by(|a, b| {
51 a.center()
52 .distance(Point::ORIGIN)
53 .total_cmp(&b.center().distance(Point::ORIGIN))
54 });
55
56 let mut output = Vec::new();
57 let mut scaled = damage
58 .into_iter()
59 .filter_map(|region| region.intersection(&bounds))
60 .filter(|region| region.width >= 1.0 && region.height >= 1.0);
61
62 if let Some(mut current) = scaled.next() {
63 for region in scaled {
64 let union = current.union(®ion);
65
66 if union.area() - current.area() - region.area() <= AREA_THRESHOLD {
67 current = union;
68 } else {
69 output.push(current);
70 current = region;
71 }
72 }
73
74 output.push(current);
75 }
76
77 output
78}