1
//! Bounding boxes that know their coordinate space.
2

            
3
use crate::rect::Rect;
4
use crate::transform::Transform;
5

            
6
9928070
#[derive(Debug, Default, Copy, Clone)]
7
pub struct BoundingBox {
8
4964035
    transform: Transform,
9
4964035
    pub rect: Option<Rect>,     // without stroke
10
4964035
    pub ink_rect: Option<Rect>, // with stroke
11
}
12

            
13
impl BoundingBox {
14
4964500
    pub fn new() -> BoundingBox {
15
4964500
        Default::default()
16
4964500
    }
17

            
18
4966746
    pub fn with_transform(self, transform: Transform) -> BoundingBox {
19
4966746
        BoundingBox { transform, ..self }
20
4966746
    }
21

            
22
951207
    pub fn with_rect(self, rect: Rect) -> BoundingBox {
23
951207
        BoundingBox {
24
951207
            rect: Some(rect),
25
            ..self
26
        }
27
951207
    }
28

            
29
506391
    pub fn with_ink_rect(self, ink_rect: Rect) -> BoundingBox {
30
506391
        BoundingBox {
31
506391
            ink_rect: Some(ink_rect),
32
            ..self
33
        }
34
506391
    }
35

            
36
    pub fn clear(mut self) {
37
        self.rect = None;
38
        self.ink_rect = None;
39
    }
40

            
41
1960717
    fn combine(&mut self, src: &BoundingBox, clip: bool) {
42
1960717
        if src.rect.is_none() && src.ink_rect.is_none() {
43
            return;
44
        }
45

            
46
        // this will panic!() if it's not invertible... should we check on our own?
47
3905976
        let transform = self
48
            .transform
49
            .invert()
50
            .unwrap()
51
1952726
            .pre_transform(&src.transform);
52

            
53
1952726
        self.rect = combine_rects(self.rect, src.rect, &transform, clip);
54
1952726
        self.ink_rect = combine_rects(self.ink_rect, src.ink_rect, &transform, clip);
55
1960717
    }
56

            
57
1960484
    pub fn insert(&mut self, src: &BoundingBox) {
58
1960484
        self.combine(src, false);
59
1960484
    }
60

            
61
293
    pub fn clip(&mut self, src: &BoundingBox) {
62
293
        self.combine(src, true);
63
293
    }
64
}
65

            
66
3911008
fn combine_rects(
67
    r1: Option<Rect>,
68
    r2: Option<Rect>,
69
    transform: &Transform,
70
    clip: bool,
71
) -> Option<Rect> {
72
3911008
    match (r1, r2, clip) {
73
1445150
        (r1, None, _) => r1,
74
1112551
        (None, Some(r2), _) => Some(transform.transform_rect(&r2)),
75
295
        (Some(r1), Some(r2), true) => transform
76
            .transform_rect(&r2)
77
            .intersection(&r1)
78
1
            .or_else(|| Some(Rect::default())),
79
1353012
        (Some(r1), Some(r2), false) => Some(transform.transform_rect(&r2).union(&r1)),
80
    }
81
3911008
}
82

            
83
#[cfg(test)]
84
mod tests {
85
    use super::*;
86

            
87
    #[test]
88
2
    fn combine() {
89
1
        let r1 = Rect::new(1.0, 2.0, 3.0, 4.0);
90
1
        let r2 = Rect::new(1.5, 2.5, 3.5, 4.5);
91
1
        let r3 = Rect::new(10.0, 11.0, 12.0, 13.0);
92
1
        let t = Transform::new_unchecked(1.0, 0.0, 0.0, 1.0, 0.5, 0.5);
93

            
94
1
        let res = combine_rects(None, None, &t, true);
95
1
        assert_eq!(res, None);
96

            
97
1
        let res = combine_rects(None, None, &t, false);
98
1
        assert_eq!(res, None);
99

            
100
1
        let res = combine_rects(Some(r1), None, &t, true);
101
1
        assert_eq!(res, Some(r1));
102

            
103
1
        let res = combine_rects(Some(r1), None, &t, false);
104
1
        assert_eq!(res, Some(r1));
105

            
106
1
        let res = combine_rects(None, Some(r2), &t, true);
107
1
        assert_eq!(res, Some(Rect::new(2.0, 3.0, 4.0, 5.0)));
108

            
109
1
        let res = combine_rects(None, Some(r2), &t, false);
110
1
        assert_eq!(res, Some(Rect::new(2.0, 3.0, 4.0, 5.0)));
111

            
112
1
        let res = combine_rects(Some(r1), Some(r2), &t, true);
113
1
        assert_eq!(res, Some(Rect::new(2.0, 3.0, 3.0, 4.0)));
114

            
115
1
        let res = combine_rects(Some(r1), Some(r3), &t, true);
116
1
        assert_eq!(res, Some(Rect::default()));
117

            
118
1
        let res = combine_rects(Some(r1), Some(r2), &t, false);
119
1
        assert_eq!(res, Some(Rect::new(1.0, 2.0, 4.0, 5.0)));
120
2
    }
121
}