irox_stats/
rects.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
// SPDX-License-Identifier: MIT
// Copyright 2025 IROX Contributors
//

use crate::points::{Double2D, Vec2D};

#[allow(unused_imports)]
use irox_tools::f64::FloatExt;

#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Ord)]
pub struct Rect2D {
    pub origin: Double2D,
    pub far_point: Double2D,
}
impl Rect2D {
    pub const fn empty() -> Rect2D {
        Self {
            origin: Double2D::new(f64::INFINITY, f64::INFINITY),
            far_point: Double2D::new(f64::NEG_INFINITY, f64::NEG_INFINITY),
        }
    }
    #[must_use]
    pub fn new(origin: Double2D, size: Vec2D) -> Self {
        Self {
            origin,
            far_point: origin.translate(&size),
        }
    }
    #[must_use]
    pub fn origin(&self) -> Double2D {
        self.origin
    }
    #[must_use]
    pub fn size(&self) -> Vec2D {
        self.far_point - self.origin
    }

    #[must_use]
    pub fn far_point(&self) -> Double2D {
        self.far_point
    }

    #[must_use]
    pub fn far_horiz(&self) -> Double2D {
        Double2D {
            x: self.far_point.x,
            y: self.origin.y,
        }
    }
    #[must_use]
    pub fn far_vert(&self) -> Double2D {
        Double2D {
            x: self.origin.x,
            y: self.far_point.y,
        }
    }

    #[must_use]
    pub fn corners(&self) -> [Double2D; 4] {
        [
            self.origin,
            self.far_horiz(),
            self.far_point(),
            self.far_vert(),
        ]
    }

    #[must_use]
    pub fn contains(&self, point: Double2D) -> bool {
        let Double2D { x, y } = point;
        let Double2D { x: fx, y: fy } = self.far_point();
        x >= self.origin.x && x <= fx && y >= self.origin.y && y <= fy
    }
    #[must_use]
    pub fn intersects(&self, other: &Rect2D) -> bool {
        for mypt in self.corners() {
            if other.contains(mypt) {
                return true;
            }
        }
        for pt in other.corners() {
            if self.contains(pt) {
                return true;
            }
        }
        false
    }

    pub fn add_point(&mut self, x: f64, y: f64) {
        self.origin.x = self.origin.x.min(x);
        self.origin.y = self.origin.y.min(y);
        self.far_point.x = self.far_point.x.max(x);
        self.far_point.y = self.far_point.y.max(y);
    }

    #[must_use]
    pub fn height(&self) -> f64 {
        (self.far_point.y - self.origin.y).abs()
    }
    #[must_use]
    pub fn width(&self) -> f64 {
        (self.far_point.x - self.origin.x).abs()
    }
    #[must_use]
    pub fn center(&self) -> Double2D {
        let y = self.height() / 2. + self.origin.y;
        let x = self.width() / 2. + self.origin.x;
        Double2D::new(x, y)
    }
    #[must_use]
    pub fn lower_left_quadrant(&self) -> Rect2D {
        Rect2D {
            origin: self.origin,
            far_point: self.center(),
        }
    }
    #[must_use]
    pub fn upper_left_quadrant(&self) -> Rect2D {
        let ctr = self.center();
        Rect2D {
            origin: Double2D::new(self.origin.x, ctr.y),
            far_point: Double2D::new(ctr.x, self.far_point.y),
        }
    }
    #[must_use]
    pub fn upper_right_quadrant(&self) -> Rect2D {
        Rect2D {
            origin: self.center(),
            far_point: self.far_point,
        }
    }
    #[must_use]
    pub fn lower_right_quadrant(&self) -> Rect2D {
        let ctr = self.center();
        Rect2D {
            origin: Double2D::new(ctr.x, self.origin.y),
            far_point: Double2D::new(self.far_point.x, ctr.y),
        }
    }
}

#[cfg(feature = "emath")]
impl From<emath::Rect> for Rect2D {
    fn from(rect: emath::Rect) -> Self {
        Self {
            origin: rect.min.into(),
            far_point: rect.max.into(),
        }
    }
}
#[cfg(feature = "emath")]
impl From<Rect2D> for emath::Rect {
    fn from(rect: Rect2D) -> Self {
        Self {
            min: rect.origin.into(),
            max: rect.far_point.into(),
        }
    }
}