|
7 | 7 | use godot_ffi as sys;
|
8 | 8 | use sys::{ffi_methods, GodotFfi};
|
9 | 9 |
|
10 |
| -use super::{real, Rect2i, Vector2}; |
| 10 | +use super::{real, Rect2i, RectSide, Vector2}; |
11 | 11 |
|
12 | 12 | /// 2D axis-aligned bounding box.
|
13 | 13 | ///
|
@@ -44,6 +44,180 @@ impl Rect2 {
|
44 | 44 | }
|
45 | 45 | }
|
46 | 46 |
|
| 47 | + /// Returns a rectangle with equivalent position and area, modified so that the top-left corner is the origin and `width` and `height` are positive. |
| 48 | + /// |
| 49 | + /// _Godot equivalent: `Rect2.abs()`_ |
| 50 | + #[inline] |
| 51 | + pub fn abs(&self) -> Self { |
| 52 | + Self { |
| 53 | + position: self.position + Vector2::new(self.size.x.min(0.0), self.size.y.min(0.0)), |
| 54 | + size: self.size.abs(), |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + /// Returns true if this rectangle (inclusively) encloses `b`. This is true when `self` covers all the area of `b`, and possibly (but not necessarily) more. |
| 59 | + /// |
| 60 | + /// _Godot equivalent: `Rect2.encloses(Rect2 b)`_ |
| 61 | + #[inline] |
| 62 | + pub fn encloses(&self, b: Rect2) -> bool { |
| 63 | + b.position.x >= self.position.x |
| 64 | + && b.position.y >= self.position.y |
| 65 | + && b.position.x + b.size.x <= self.position.x + self.size.x |
| 66 | + && b.position.y + b.size.y <= self.position.y + self.size.y |
| 67 | + } |
| 68 | + |
| 69 | + /// Returns a copy of this rectangle expanded to include a given point. |
| 70 | + /// |
| 71 | + /// Note: This method is not reliable for `Rect2` with a negative size. Use [`abs`][Self::abs] |
| 72 | + /// to get a positive sized equivalent rectangle for expanding. |
| 73 | + /// |
| 74 | + /// _Godot equivalent: `Rect2.expand(Vector2 to)`_ |
| 75 | + #[inline] |
| 76 | + pub fn expand(&self, to: &Vector2) -> Self { |
| 77 | + self.merge(&Rect2::new(*to, Vector2::ZERO)) |
| 78 | + } |
| 79 | + |
| 80 | + /// Returns a larger rectangle that contains this `Rect2` and `b`. |
| 81 | + /// |
| 82 | + /// Note: This method is not reliable for `Rect2` with a negative size. Use [`abs`][Self::abs] |
| 83 | + /// to get a positive sized equivalent rectangle for merging. |
| 84 | + /// |
| 85 | + /// _Godot equivalent: `Rect2.merge(Rect2 b)`_ |
| 86 | + #[inline] |
| 87 | + pub fn merge(&self, b: &Self) -> Self { |
| 88 | + let position = Vector2::new( |
| 89 | + self.position.x.min(b.position.x), |
| 90 | + self.position.y.min(b.position.y), |
| 91 | + ); |
| 92 | + let end = Vector2::new( |
| 93 | + (self.position.x + self.size.x).max(b.position.x + b.size.x), |
| 94 | + (self.position.y + self.size.y).max(b.position.y + b.size.y), |
| 95 | + ); |
| 96 | + |
| 97 | + Self { |
| 98 | + position, |
| 99 | + size: end - position, |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + /// Returns the area of the rectangle. |
| 104 | + /// |
| 105 | + /// _Godot equivalent: `Rect2.get_area()`_ |
| 106 | + #[inline] |
| 107 | + pub fn area(&self) -> real { |
| 108 | + self.size.x * self.size.y |
| 109 | + } |
| 110 | + |
| 111 | + /// Returns the center of the Rect2, which is equal to `position + (size / 2)`. |
| 112 | + /// |
| 113 | + /// _Godot equivalent: `Rect2.get_center()`_ |
| 114 | + #[inline] |
| 115 | + pub fn center(&self) -> Vector2 { |
| 116 | + self.position + (self.size / 2.0) |
| 117 | + } |
| 118 | + |
| 119 | + /// Returns a copy of the Rect2 grown by the specified `amount` on all sides. |
| 120 | + /// |
| 121 | + /// _Godot equivalent: `Rect2.grow(float amount)`_ |
| 122 | + #[inline] |
| 123 | + pub fn grow(&self, amount: real) -> Self { |
| 124 | + let position = self.position - Vector2::new(amount, amount); |
| 125 | + let size = self.size + Vector2::new(amount, amount) * 2.0; |
| 126 | + |
| 127 | + Self { position, size } |
| 128 | + } |
| 129 | + |
| 130 | + /// Returns a copy of the Rect2 grown by the specified amount on each side individually. |
| 131 | + /// |
| 132 | + /// _Godot equivalent: `Rect2.grow_individual(float left, float top, float right, float bottom)`_ |
| 133 | + #[inline] |
| 134 | + pub fn grow_individual(&self, left: real, top: real, right: real, bottom: real) -> Self { |
| 135 | + Self::from_components( |
| 136 | + self.position.x - left, |
| 137 | + self.position.y - top, |
| 138 | + self.size.x + left + right, |
| 139 | + self.size.y + top + bottom, |
| 140 | + ) |
| 141 | + } |
| 142 | + |
| 143 | + /// Returns a copy of the `Rect2` grown by the specified `amount` on the specified `RectSide`. |
| 144 | + /// |
| 145 | + /// `amount` may be negative, but care must be taken: If the resulting `size` has |
| 146 | + /// negative components the computation may be incorrect. |
| 147 | + /// |
| 148 | + /// _Godot equivalent: `Rect2.grow_side(int side, float amount)`_ |
| 149 | + #[inline] |
| 150 | + pub fn grow_side(&self, side: &RectSide, amount: real) -> Self { |
| 151 | + match side { |
| 152 | + RectSide::Left => self.grow_individual(amount, 0.0, 0.0, 0.0), |
| 153 | + RectSide::Top => self.grow_individual(0.0, amount, 0.0, 0.0), |
| 154 | + RectSide::Right => self.grow_individual(0.0, 0.0, amount, 0.0), |
| 155 | + RectSide::Bottom => self.grow_individual(0.0, 0.0, 0.0, amount), |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + /// Returns `true` if the Rect2 has area, and `false` if the Rect2 is linear, empty, or has a negative size. See also `get_area`. |
| 160 | + /// |
| 161 | + /// _Godot equivalent: `Rect2.has_area()`_ |
| 162 | + #[inline] |
| 163 | + pub fn has_area(&self) -> bool { |
| 164 | + self.size.x > 0.0 && self.size.y > 0.0 |
| 165 | + } |
| 166 | + |
| 167 | + /// Returns `true` if the Rect2 contains a point. By convention, the right and bottom edges of the Rect2 are considered exclusive, so points on these edges are not included. |
| 168 | + /// |
| 169 | + /// Note: This method is not reliable for Rect2 with a negative size. Use `abs` to get a positive sized equivalent rectangle to check for contained points. |
| 170 | + /// |
| 171 | + /// _Godot equivalent: `Rect2.has_area()`_ |
| 172 | + #[inline] |
| 173 | + pub fn has_point(&self, point: Vector2) -> bool { |
| 174 | + let point = point - self.position; |
| 175 | + |
| 176 | + point.abs() == point && point.x < self.size.x && point.y < self.size.y |
| 177 | + } |
| 178 | + |
| 179 | + /// Returns the intersection of this Rect2 and `b`. If the rectangles do not intersect, an empty Rect2 is returned. |
| 180 | + /// |
| 181 | + /// _Godot equivalent: `Rect2.intersection(Rect2 b)`_ |
| 182 | + #[inline] |
| 183 | + pub fn intersection(&self, b: &Self) -> Option<Self> { |
| 184 | + if !self.intersects(b, true) { |
| 185 | + return None; |
| 186 | + } |
| 187 | + |
| 188 | + let mut rect = *b; |
| 189 | + rect.position.x = rect.position.x.max(self.position.x); |
| 190 | + rect.position.y = rect.position.y.max(self.position.y); |
| 191 | + |
| 192 | + let end = self.end(); |
| 193 | + let end_b = b.end(); |
| 194 | + |
| 195 | + rect.size.x = end.x.min(end_b.x) - rect.position.x; |
| 196 | + rect.size.y = end.y.min(end_b.y) - rect.position.y; |
| 197 | + |
| 198 | + Some(rect) |
| 199 | + } |
| 200 | + |
| 201 | + /// Returns `true` if the Rect2 overlaps with `b` (i.e. they have at least one point in common). |
| 202 | + /// |
| 203 | + /// If `include_borders` is `true`, they will also be considered overlapping if their borders touch, even without intersection. |
| 204 | + /// |
| 205 | + /// _Godot equivalent: `Rect2.intersects(Rect2 b, bool include_borders)`_ |
| 206 | + #[inline] |
| 207 | + pub fn intersects(&self, b: &Self, include_borders: bool) -> bool { |
| 208 | + if include_borders { |
| 209 | + return self.position.x <= b.position.x + b.size.x |
| 210 | + && self.position.x + self.size.x >= b.position.x |
| 211 | + && self.position.y <= b.position.y + b.size.y |
| 212 | + && self.position.y + self.size.y >= b.position.y; |
| 213 | + } |
| 214 | + |
| 215 | + self.position.x < b.position.x + b.size.x |
| 216 | + && self.position.x + self.size.x > b.position.x |
| 217 | + && self.position.y < b.position.y + b.size.y |
| 218 | + && self.position.y + self.size.y > b.position.y |
| 219 | + } |
| 220 | + |
47 | 221 | /// Create a new `Rect2` from a `Rect2i`, using `as` for `i32` to `real` conversions.
|
48 | 222 | ///
|
49 | 223 | /// _Godot equivalent: `Rect2(Rect2i from)`_
|
|
0 commit comments