1// pathfinder/geometry/src/basic/rect.rs
2//
3// Copyright © 2019 The Pathfinder Project Developers.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! 2D axis-aligned rectangles, optimized with SIMD.
12
13use crate::vector::{IntoVector2F, Vector2F, Vector2I};
14use pathfinder_simd::default::{F32x4, I32x4};
15use std::ops::{Add, Mul, Sub};
16
17#[derive(Clone, Copy, Debug, PartialEq, Default)]
18pub struct RectF(pub F32x4);
19
20impl RectF {
21 #[inline]
22 pub fn new(origin: Vector2F, size: Vector2F) -> RectF {
23 RectF(origin.0.concat_xy_xy(origin.0 + size.0))
24 }
25
26 #[inline]
27 pub fn from_points(origin: Vector2F, lower_right: Vector2F) -> RectF {
28 RectF(origin.0.concat_xy_xy(lower_right.0))
29 }
30
31 // Accessors
32
33 #[inline]
34 pub fn origin(self) -> Vector2F {
35 Vector2F(self.0.xy())
36 }
37
38 #[inline]
39 pub fn size(self) -> Vector2F {
40 Vector2F(self.0.zw() - self.0.xy())
41 }
42
43 #[inline]
44 pub fn origin_x(self) -> f32 {
45 self.0.x()
46 }
47
48 #[inline]
49 pub fn origin_y(self) -> f32 {
50 self.0.y()
51 }
52
53 #[inline]
54 pub fn width(self) -> f32 {
55 self.0.z() - self.0.x()
56 }
57
58 #[inline]
59 pub fn height(self) -> f32 {
60 self.0.w() - self.0.y()
61 }
62
63 #[inline]
64 pub fn upper_right(self) -> Vector2F {
65 Vector2F(self.0.zy())
66 }
67
68 #[inline]
69 pub fn lower_left(self) -> Vector2F {
70 Vector2F(self.0.xw())
71 }
72
73 #[inline]
74 pub fn lower_right(self) -> Vector2F {
75 Vector2F(self.0.zw())
76 }
77
78 // Mutators
79
80 #[inline]
81 pub fn set_origin_x(&mut self, x: f32) {
82 self.0.set_x(x)
83 }
84
85 #[inline]
86 pub fn set_origin_y(&mut self, y: f32) {
87 self.0.set_y(y)
88 }
89
90 #[inline]
91 pub fn contains_point(self, point: Vector2F) -> bool {
92 // self.origin <= point && point <= self.lower_right
93 let point = point.0.to_f32x4();
94 self.0.concat_xy_xy(point).packed_le(point.concat_xy_zw(self.0)).all_true()
95 }
96
97 #[inline]
98 pub fn contains_rect(self, other: RectF) -> bool {
99 // self.origin <= other.origin && other.lower_right <= self.lower_right
100 self.0.concat_xy_zw(other.0).packed_le(other.0.concat_xy_zw(self.0)).all_true()
101 }
102
103 #[inline]
104 pub fn is_empty(self) -> bool {
105 self.origin() == self.lower_right()
106 }
107
108 #[inline]
109 pub fn union_point(self, point: Vector2F) -> RectF {
110 RectF::from_points(self.origin().min(point), self.lower_right().max(point))
111 }
112
113 #[inline]
114 pub fn union_rect(self, other: RectF) -> RectF {
115 RectF::from_points(
116 self.origin().min(other.origin()),
117 self.lower_right().max(other.lower_right()),
118 )
119 }
120
121 #[inline]
122 pub fn intersects(self, other: RectF) -> bool {
123 // self.origin < other.lower_right && other.origin < self.lower_right
124 self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true()
125 }
126
127 #[inline]
128 pub fn intersection(self, other: RectF) -> Option<RectF> {
129 if !self.intersects(other) {
130 None
131 } else {
132 Some(RectF::from_points(
133 self.origin().max(other.origin()),
134 self.lower_right().min(other.lower_right()),
135 ))
136 }
137 }
138
139 #[inline]
140 pub fn min_x(self) -> f32 {
141 self.0[0]
142 }
143
144 #[inline]
145 pub fn min_y(self) -> f32 {
146 self.0[1]
147 }
148
149 #[inline]
150 pub fn max_x(self) -> f32 {
151 self.0[2]
152 }
153
154 #[inline]
155 pub fn max_y(self) -> f32 {
156 self.0[3]
157 }
158
159 #[inline]
160 pub fn center(self) -> Vector2F {
161 self.origin() + self.size() * 0.5
162 }
163
164 /// Rounds all points to the nearest integer.
165 #[inline]
166 pub fn round(self) -> RectF {
167 RectF(self.0.to_i32x4().to_f32x4())
168 }
169
170 #[inline]
171 pub fn round_out(self) -> RectF {
172 RectF::from_points(self.origin().floor(), self.lower_right().ceil())
173 }
174
175 #[inline]
176 pub fn dilate<A>(self, amount: A) -> RectF where A: IntoVector2F {
177 let amount = amount.into_vector_2f();
178 RectF::from_points(self.origin() - amount, self.lower_right() + amount)
179 }
180
181 #[inline]
182 pub fn contract<A>(self, amount: A) -> RectF where A: IntoVector2F {
183 let amount = amount.into_vector_2f();
184 RectF::from_points(self.origin() + amount, self.lower_right() - amount)
185 }
186
187 #[inline]
188 pub fn to_i32(&self) -> RectI {
189 RectI(self.0.to_i32x4())
190 }
191}
192
193impl Add<Vector2F> for RectF {
194 type Output = RectF;
195 #[inline]
196 fn add(self, other: Vector2F) -> RectF {
197 RectF::new(self.origin() + other, self.size())
198 }
199}
200
201impl Add<f32> for RectF {
202 type Output = RectF;
203 #[inline]
204 fn add(self, other: f32) -> RectF {
205 RectF::new(self.origin() + other, self.size())
206 }
207}
208
209impl Mul<Vector2F> for RectF {
210 type Output = RectF;
211 #[inline]
212 fn mul(self, factors: Vector2F) -> RectF {
213 RectF(self.0 * factors.0.concat_xy_xy(factors.0))
214 }
215}
216
217impl Mul<f32> for RectF {
218 type Output = RectF;
219 #[inline]
220 fn mul(self, factor: f32) -> RectF {
221 RectF(self.0 * F32x4::splat(factor))
222 }
223}
224
225impl Sub<Vector2F> for RectF {
226 type Output = RectF;
227 #[inline]
228 fn sub(self, other: Vector2F) -> RectF {
229 RectF::new(self.origin() - other, self.size())
230 }
231}
232
233impl Sub<f32> for RectF {
234 type Output = RectF;
235 #[inline]
236 fn sub(self, other: f32) -> RectF {
237 RectF::new(self.origin() - other, self.size())
238 }
239}
240
241/// NB: The origin is inclusive, while the lower right point is exclusive.
242#[derive(Clone, Copy, Debug, PartialEq, Default)]
243pub struct RectI(pub I32x4);
244
245impl RectI {
246 #[inline]
247 pub fn new(origin: Vector2I, size: Vector2I) -> RectI {
248 RectI(origin.0.concat_xy_xy(origin.0 + size.0))
249 }
250
251 #[inline]
252 pub fn from_points(origin: Vector2I, lower_right: Vector2I) -> RectI {
253 RectI(origin.0.concat_xy_xy(lower_right.0))
254 }
255
256 // Accessors
257
258 #[inline]
259 pub fn origin(&self) -> Vector2I {
260 Vector2I(self.0.xy())
261 }
262
263 #[inline]
264 pub fn size(&self) -> Vector2I {
265 Vector2I(self.0.zw() - self.0.xy())
266 }
267
268 #[inline]
269 pub fn origin_x(self) -> i32 {
270 self.0.x()
271 }
272
273 #[inline]
274 pub fn origin_y(self) -> i32 {
275 self.0.y()
276 }
277
278 #[inline]
279 pub fn width(self) -> i32 {
280 self.0.z() - self.0.x()
281 }
282
283 #[inline]
284 pub fn height(self) -> i32 {
285 self.0.w() - self.0.y()
286 }
287
288 #[inline]
289 pub fn upper_right(&self) -> Vector2I {
290 Vector2I(self.0.zy())
291 }
292
293 #[inline]
294 pub fn lower_left(&self) -> Vector2I {
295 Vector2I(self.0.xw())
296 }
297
298 #[inline]
299 pub fn lower_right(&self) -> Vector2I {
300 Vector2I(self.0.zw())
301 }
302
303 #[inline]
304 pub fn scale(self, factor: i32) -> RectI {
305 RectI(self.0 * I32x4::splat(factor))
306 }
307
308 #[inline]
309 pub fn scale_xy(self, factors: Vector2I) -> RectI {
310 RectI(self.0 * factors.0.concat_xy_xy(factors.0))
311 }
312
313 #[inline]
314 pub fn min_x(self) -> i32 {
315 self.0[0]
316 }
317
318 #[inline]
319 pub fn min_y(self) -> i32 {
320 self.0[1]
321 }
322
323 #[inline]
324 pub fn max_x(self) -> i32 {
325 self.0[2]
326 }
327
328 #[inline]
329 pub fn max_y(self) -> i32 {
330 self.0[3]
331 }
332
333 #[inline]
334 pub fn intersects(self, other: RectI) -> bool {
335 // self.origin < other.lower_right && other.origin < self.lower_right
336 self.0.concat_xy_xy(other.0).packed_lt(other.0.concat_zw_zw(self.0)).all_true()
337 }
338
339 #[inline]
340 pub fn intersection(self, other: RectI) -> Option<RectI> {
341 if !self.intersects(other) {
342 None
343 } else {
344 Some(RectI::from_points(
345 self.origin().max(other.origin()),
346 self.lower_right().min(other.lower_right()),
347 ))
348 }
349 }
350
351 #[inline]
352 pub fn contains_point(&self, point: Vector2I) -> bool {
353 // self.origin <= point && point <= self.lower_right - 1
354 let lower_right = self.lower_right() - 1;
355 self.origin()
356 .0
357 .concat_xy_xy(point.0)
358 .packed_le(point.0.concat_xy_xy(lower_right.0))
359 .all_true()
360 }
361
362 #[inline]
363 pub fn contract(self, amount: Vector2I) -> RectI {
364 RectI::from_points(self.origin() + amount, self.lower_right() - amount)
365 }
366
367 #[inline]
368 pub fn to_f32(&self) -> RectF {
369 RectF(self.0.to_f32x4())
370 }
371}
372