[go: up one dir, main page]

sdl2/
rect.rs

1//! Rectangles and points.
2
3use crate::sys;
4use std::convert::{AsMut, AsRef};
5use std::hash::{Hash, Hasher};
6use std::mem;
7use std::ops::{
8    Add, AddAssign, BitAnd, BitOr, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Sub,
9    SubAssign,
10};
11use std::ptr;
12
13/// The maximal integer value that can be used for rectangles.
14///
15/// This value is smaller than strictly needed, but is useful in ensuring that
16/// rect sizes will never have to be truncated when clamping.
17pub fn max_int_value() -> u32 {
18    i32::MAX as u32 / 2
19}
20
21/// The minimal integer value that can be used for rectangle positions
22/// and points.
23///
24/// This value is needed, because otherwise the width of a rectangle created
25/// from a point would be able to exceed the maximum width.
26pub fn min_int_value() -> i32 {
27    i32::MIN / 2
28}
29
30fn clamp_size(val: u32) -> u32 {
31    if val == 0 {
32        1
33    } else if val > max_int_value() {
34        max_int_value()
35    } else {
36        val
37    }
38}
39
40fn clamp_position(val: i32) -> i32 {
41    if val > max_int_value() as i32 {
42        max_int_value() as i32
43    } else if val < min_int_value() {
44        min_int_value()
45    } else {
46        val
47    }
48}
49
50fn clamped_mul(a: i32, b: i32) -> i32 {
51    match a.checked_mul(b) {
52        Some(val) => val,
53        None => {
54            if (a < 0) ^ (b < 0) {
55                min_int_value()
56            } else {
57                max_int_value() as i32
58            }
59        }
60    }
61}
62
63fn clamp_f32_size(val: f32) -> f32 {
64    if val <= 0.0 {
65        1.0
66    } else {
67        val
68    }
69}
70
71/// A (non-empty) rectangle.
72///
73/// The width and height of a `Rect` must always be strictly positive (never
74/// zero).  In cases where empty rects may need to represented, it is
75/// recommended to use `Option<Rect>`, with `None` representing an empty
76/// rectangle (see, for example, the output of the
77/// [`intersection`](#method.intersection) method).
78// Uses repr(transparent) to allow pointer casting between Rect and SDL_Rect (see
79// `Rect::raw_slice`)
80#[repr(transparent)]
81#[derive(Clone, Copy)]
82pub struct Rect {
83    raw: sys::SDL_Rect,
84}
85
86impl ::std::fmt::Debug for Rect {
87    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
88        fmt.debug_struct("Rect")
89            .field("x", &self.raw.x)
90            .field("y", &self.raw.y)
91            .field("w", &self.raw.w)
92            .field("h", &self.raw.h)
93            .finish()
94    }
95}
96
97impl PartialEq for Rect {
98    fn eq(&self, other: &Rect) -> bool {
99        self.raw.x == other.raw.x
100            && self.raw.y == other.raw.y
101            && self.raw.w == other.raw.w
102            && self.raw.h == other.raw.h
103    }
104}
105
106impl Eq for Rect {}
107
108impl Hash for Rect {
109    fn hash<H: Hasher>(&self, state: &mut H) {
110        self.raw.x.hash(state);
111        self.raw.y.hash(state);
112        self.raw.w.hash(state);
113        self.raw.h.hash(state);
114    }
115}
116
117impl Rect {
118    /// Creates a new rectangle from the given values.
119    ///
120    /// The width and height are clamped to ensure that the right and bottom
121    /// sides of the rectangle does not exceed i32::MAX (the value
122    /// 2147483647, the maximal positive size of an i32).  This means that the
123    /// rect size will behave oddly if you move it very far to the right or
124    /// downwards on the screen.
125    ///
126    /// `Rect`s must always be non-empty, so a `width` and/or `height` argument
127    /// of 0 will be replaced with 1.
128    pub fn new(x: i32, y: i32, width: u32, height: u32) -> Rect {
129        let raw = sys::SDL_Rect {
130            x: clamp_position(x),
131            y: clamp_position(y),
132            w: clamp_size(width) as i32,
133            h: clamp_size(height) as i32,
134        };
135        Rect { raw }
136    }
137
138    /// Creates a new rectangle centered on the given position.
139    ///
140    /// The width and height are clamped to ensure that the right and bottom
141    /// sides of the rectangle does not exceed i32::MAX (the value
142    /// 2147483647, the maximal positive size of an i32).  This means that the
143    /// rect size will behave oddly if you move it very far to the right or
144    /// downwards on the screen.
145    ///
146    /// `Rect`s must always be non-empty, so a `width` and/or `height` argument
147    /// of 0 will be replaced with 1.
148    pub fn from_center<P>(center: P, width: u32, height: u32) -> Rect
149    where
150        P: Into<Point>,
151    {
152        let raw = sys::SDL_Rect {
153            x: 0,
154            y: 0,
155            w: clamp_size(width) as i32,
156            h: clamp_size(height) as i32,
157        };
158        let mut rect = Rect { raw };
159        rect.center_on(center.into());
160        rect
161    }
162
163    /// The horizontal position of this rectangle.
164    #[inline]
165    pub fn x(&self) -> i32 {
166        self.raw.x
167    }
168
169    /// The vertical position of this rectangle.
170    #[inline]
171    pub fn y(&self) -> i32 {
172        self.raw.y
173    }
174
175    /// The width of this rectangle.
176    pub fn width(&self) -> u32 {
177        self.raw.w as u32
178    }
179
180    /// The height of this rectangle.
181    pub fn height(&self) -> u32 {
182        self.raw.h as u32
183    }
184
185    /// Returns the width and height of this rectangle.
186    pub fn size(&self) -> (u32, u32) {
187        (self.width(), self.height())
188    }
189
190    /// Sets the horizontal position of this rectangle to the given value,
191    /// clamped to be less than or equal to i32::MAX / 2.
192    pub fn set_x(&mut self, x: i32) {
193        self.raw.x = clamp_position(x);
194    }
195
196    /// Sets the vertical position of this rectangle to the given value,
197    /// clamped to be less than or equal to i32::MAX / 2.
198    pub fn set_y(&mut self, y: i32) {
199        self.raw.y = clamp_position(y);
200    }
201
202    /// Sets the width of this rectangle to the given value,
203    /// clamped to be less than or equal to i32::MAX / 2.
204    ///
205    /// `Rect`s must always be non-empty, so a `width` argument of 0 will be
206    /// replaced with 1.
207    pub fn set_width(&mut self, width: u32) {
208        self.raw.w = clamp_size(width) as i32;
209    }
210
211    /// Sets the height of this rectangle to the given value,
212    /// clamped to be less than or equal to i32::MAX / 2.
213    ///
214    /// `Rect`s must always be non-empty, so a `height` argument of 0 will be
215    /// replaced with 1.
216    pub fn set_height(&mut self, height: u32) {
217        self.raw.h = clamp_size(height) as i32;
218    }
219
220    /// Returns the x-position of the left side of this rectangle.
221    pub fn left(&self) -> i32 {
222        self.raw.x
223    }
224
225    /// Returns the x-position of the right side of this rectangle.
226    pub fn right(&self) -> i32 {
227        self.raw.x + self.raw.w
228    }
229
230    /// Returns the y-position of the top side of this rectangle.
231    pub fn top(&self) -> i32 {
232        self.raw.y
233    }
234
235    /// Returns the y-position of the bottom side of this rectangle.
236    pub fn bottom(&self) -> i32 {
237        self.raw.y + self.raw.h
238    }
239
240    /// Shifts this rectangle to the left by `offset`.
241    ///
242    /// # Example
243    ///
244    /// ```
245    /// use sdl2::rect::Rect;
246    /// assert_eq!(Rect::new(5, 5, 10, 10).left_shifted(5), Rect::new(0, 5, 10, 10));
247    /// ```
248    pub fn left_shifted(mut self, offset: i32) -> Rect {
249        self.offset(-offset, 0);
250        self
251    }
252
253    /// Shifts this rectangle to the right by `offset`.
254    ///
255    /// # Example
256    ///
257    /// ```
258    /// use sdl2::rect::Rect;
259    /// assert_eq!(Rect::new(5, 5, 10, 10).right_shifted(5), Rect::new(10, 5, 10, 10));
260    /// ```
261    pub fn right_shifted(mut self, offset: i32) -> Rect {
262        self.offset(offset, 0);
263        self
264    }
265
266    /// Shifts this rectangle to the top by `offset`.
267    ///
268    /// # Example
269    ///
270    /// ```
271    /// use sdl2::rect::Rect;
272    /// assert_eq!(Rect::new(5, 5, 10, 10).top_shifted(5), Rect::new(5, 0, 10, 10));
273    /// ```
274    pub fn top_shifted(mut self, offset: i32) -> Rect {
275        self.offset(0, -offset);
276        self
277    }
278
279    /// Shifts this rectangle to the bottom by `offset`.
280    ///
281    /// # Example
282    ///
283    /// ```
284    /// use sdl2::rect::Rect;
285    /// assert_eq!(Rect::new(5, 5, 10, 10).bottom_shifted(5), Rect::new(5, 10, 10, 10));
286    /// ```
287    pub fn bottom_shifted(mut self, offset: i32) -> Rect {
288        self.offset(0, offset);
289        self
290    }
291
292    /// Returns the center position of this rectangle.
293    ///
294    /// Note that if the width or height is not a multiple of two,
295    /// the center will be rounded down.
296    ///
297    /// # Example
298    ///
299    /// ```
300    /// use sdl2::rect::{Rect,Point};
301    /// let rect = Rect::new(1,0,2,3);
302    /// assert_eq!(Point::new(2,1),rect.center());
303    /// ```
304    pub fn center(&self) -> Point {
305        let x = self.raw.x + (self.raw.w / 2);
306        let y = self.raw.y + (self.raw.h / 2);
307        Point::new(x, y)
308    }
309
310    /// Returns the top-left corner of this rectangle.
311    ///
312    /// # Example
313    ///
314    /// ```
315    /// use sdl2::rect::{Rect, Point};
316    /// let rect = Rect::new(1, 0, 2, 3);
317    /// assert_eq!(Point::new(1, 0), rect.top_left());
318    /// ```
319    pub fn top_left(&self) -> Point {
320        Point::new(self.left(), self.top())
321    }
322
323    /// Returns the top-right corner of this rectangle.
324    ///
325    /// # Example
326    ///
327    /// ```
328    /// use sdl2::rect::{Rect, Point};
329    /// let rect = Rect::new(1, 0, 2, 3);
330    /// assert_eq!(Point::new(3, 0), rect.top_right());
331    /// ```
332    pub fn top_right(&self) -> Point {
333        Point::new(self.right(), self.top())
334    }
335
336    /// Returns the bottom-left corner of this rectangle.
337    ///
338    /// # Example
339    ///
340    /// ```
341    /// use sdl2::rect::{Rect, Point};
342    /// let rect = Rect::new(1, 0, 2, 3);
343    /// assert_eq!(Point::new(1, 3), rect.bottom_left());
344    /// ```
345    pub fn bottom_left(&self) -> Point {
346        Point::new(self.left(), self.bottom())
347    }
348
349    /// Returns the bottom-right corner of this rectangle.
350    ///
351    /// # Example
352    ///
353    /// ```
354    /// use sdl2::rect::{Rect, Point};
355    /// let rect = Rect::new(1, 0, 2, 3);
356    /// assert_eq!(Point::new(3, 3), rect.bottom_right());
357    /// ```
358    pub fn bottom_right(&self) -> Point {
359        Point::new(self.right(), self.bottom())
360    }
361
362    /// Sets the position of the right side of this rectangle to the given
363    /// value, clamped to be less than or equal to i32::MAX / 2.
364    pub fn set_right(&mut self, right: i32) {
365        self.raw.x = clamp_position(clamp_position(right) - self.raw.w);
366    }
367
368    /// Sets the position of the bottom side of this rectangle to the given
369    /// value, clamped to be less than or equal to i32::MAX / 2.
370    pub fn set_bottom(&mut self, bottom: i32) {
371        self.raw.y = clamp_position(clamp_position(bottom) - self.raw.h);
372    }
373
374    /// Centers the rectangle on the given point (in place).
375    #[inline]
376    pub fn center_on<P>(&mut self, point: P)
377    where
378        P: Into<(i32, i32)>,
379    {
380        let (x, y) = point.into();
381        self.raw.x = clamp_position(clamp_position(x) - self.raw.w / 2);
382        self.raw.y = clamp_position(clamp_position(y) - self.raw.h / 2);
383    }
384
385    /// Centers the rectangle on the given point.
386    #[inline]
387    pub fn centered_on<P>(mut self, point: P) -> Rect
388    where
389        P: Into<(i32, i32)>,
390    {
391        self.center_on(point);
392        self
393    }
394
395    /// Move this rect and clamp the positions to prevent over/underflow.
396    /// This also clamps the size to prevent overflow.
397    #[inline]
398    pub fn offset(&mut self, x: i32, y: i32) {
399        match self.raw.x.checked_add(x) {
400            Some(val) => self.raw.x = clamp_position(val),
401            None => {
402                if x >= 0 {
403                    self.raw.x = max_int_value() as i32;
404                } else {
405                    self.raw.x = i32::MIN;
406                }
407            }
408        }
409        match self.raw.y.checked_add(y) {
410            Some(val) => self.raw.y = clamp_position(val),
411            None => {
412                if y >= 0 {
413                    self.raw.y = max_int_value() as i32;
414                } else {
415                    self.raw.y = i32::MIN;
416                }
417            }
418        }
419    }
420
421    /// Moves this rect to the given position after clamping the values.
422    pub fn reposition<P>(&mut self, point: P)
423    where
424        P: Into<(i32, i32)>,
425    {
426        let (x, y) = point.into();
427        self.raw.x = clamp_position(x);
428        self.raw.y = clamp_position(y);
429    }
430
431    /// Resizes this rect to the given size after clamping the values.
432    pub fn resize(&mut self, width: u32, height: u32) {
433        self.raw.w = clamp_size(width) as i32;
434        self.raw.h = clamp_size(height) as i32;
435    }
436
437    /// Checks whether this rectangle contains a given point.
438    ///
439    /// Points along the right and bottom edges are not considered to be inside
440    /// the rectangle; this way, a 1-by-1 rectangle contains only a single
441    /// point.  Another way to look at it is that this method returns true if
442    /// and only if the given point would be painted by a call to
443    /// [`Renderer::fill_rect`](
444    /// ../render/struct.Renderer.html#method.fill_rect).
445    ///
446    /// # Examples
447    ///
448    /// ```
449    /// use sdl2::rect::{Rect, Point};
450    /// let rect = Rect::new(1, 2, 3, 4);
451    /// assert!(rect.contains_point(Point::new(1, 2)));
452    /// assert!(!rect.contains_point(Point::new(0, 1)));
453    /// assert!(rect.contains_point(Point::new(3, 5)));
454    /// assert!(!rect.contains_point(Point::new(4, 6)));
455    /// ```
456    pub fn contains_point<P>(&self, point: P) -> bool
457    where
458        P: Into<(i32, i32)>,
459    {
460        let (x, y) = point.into();
461        let inside_x = x >= self.left() && x < self.right();
462        inside_x && (y >= self.top() && y < self.bottom())
463    }
464
465    /// Checks whether this rectangle completely contains another rectangle.
466    ///
467    /// This method returns true if and only if every point contained by
468    /// `other` is also contained by `self`; in other words, if the
469    /// intersection of `self` and `other` is equal to `other`.
470    ///
471    /// # Examples
472    ///
473    /// ```
474    /// use sdl2::rect::Rect;
475    /// let rect = Rect::new(1, 2, 3, 4);
476    /// assert!(rect.contains_rect(rect));
477    /// assert!(rect.contains_rect(Rect::new(3, 3, 1, 1)));
478    /// assert!(!rect.contains_rect(Rect::new(2, 1, 1, 1)));
479    /// assert!(!rect.contains_rect(Rect::new(3, 3, 2, 1)));
480    /// ```
481    pub fn contains_rect(&self, other: Rect) -> bool {
482        other.left() >= self.left()
483            && other.right() <= self.right()
484            && other.top() >= self.top()
485            && other.bottom() <= self.bottom()
486    }
487
488    /// Returns the underlying C Rect.
489    // this can prevent introducing UB until
490    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
491    #[allow(clippy::trivially_copy_pass_by_ref)]
492    pub fn raw(&self) -> *const sys::SDL_Rect {
493        &self.raw
494    }
495
496    pub fn raw_mut(&mut self) -> *mut sys::SDL_Rect {
497        &mut self.raw
498    }
499
500    #[doc(alias = "SDL_Rect")]
501    pub fn raw_slice(slice: &[Rect]) -> *const sys::SDL_Rect {
502        slice.as_ptr() as *const sys::SDL_Rect
503    }
504
505    pub fn from_ll(raw: sys::SDL_Rect) -> Rect {
506        Rect::new(raw.x, raw.y, raw.w as u32, raw.h as u32)
507    }
508
509    /// Calculate a minimal rectangle enclosing a set of points.
510    /// If a clipping rectangle is given, only points that are within it will be
511    /// considered.
512    #[doc(alias = "SDL_EnclosePoints")]
513    pub fn from_enclose_points<R>(points: &[Point], clipping_rect: R) -> Option<Rect>
514    where
515        R: Into<Option<Rect>>,
516    {
517        let clipping_rect = clipping_rect.into();
518
519        if points.is_empty() {
520            return None;
521        }
522
523        let mut out = mem::MaybeUninit::uninit();
524
525        let clip_ptr = match clipping_rect.as_ref() {
526            Some(r) => r.raw(),
527            None => ptr::null(),
528        };
529
530        let result = unsafe {
531            sys::SDL_EnclosePoints(
532                Point::raw_slice(points),
533                points.len() as i32,
534                clip_ptr,
535                out.as_mut_ptr(),
536            ) != sys::SDL_bool::SDL_FALSE
537        };
538
539        if result {
540            let out = unsafe { out.assume_init() };
541
542            // Return an error if the dimensions are too large.
543            Some(Rect::from_ll(out))
544        } else {
545            None
546        }
547    }
548
549    /// Determines whether two rectangles intersect.
550    ///
551    /// Rectangles that share an edge but don't actually overlap are not
552    /// considered to intersect.
553    ///
554    /// # Examples
555    ///
556    /// ```
557    /// use sdl2::rect::Rect;
558    /// let rect = Rect::new(0, 0, 5, 5);
559    /// assert!(rect.has_intersection(rect));
560    /// assert!(rect.has_intersection(Rect::new(2, 2, 5, 5)));
561    /// assert!(!rect.has_intersection(Rect::new(5, 0, 5, 5)));
562    /// ```
563    #[doc(alias = "SDL_HasIntersection")]
564    pub fn has_intersection(&self, other: Rect) -> bool {
565        unsafe { sys::SDL_HasIntersection(self.raw(), other.raw()) != sys::SDL_bool::SDL_FALSE }
566    }
567
568    /// Calculates the intersection of two rectangles.
569    ///
570    /// Returns `None` if the two rectangles don't intersect.  Rectangles that
571    /// share an edge but don't actually overlap are not considered to
572    /// intersect.
573    ///
574    /// The bitwise AND operator `&` can also be used.
575    ///
576    /// # Examples
577    ///
578    /// ```
579    /// use sdl2::rect::Rect;
580    /// let rect = Rect::new(0, 0, 5, 5);
581    /// assert_eq!(rect.intersection(rect), Some(rect));
582    /// assert_eq!(rect.intersection(Rect::new(2, 2, 5, 5)),
583    ///            Some(Rect::new(2, 2, 3, 3)));
584    /// assert_eq!(rect.intersection(Rect::new(5, 0, 5, 5)), None);
585    /// ```
586    #[doc(alias = "SDL_IntersectRect")]
587    pub fn intersection(&self, other: Rect) -> Option<Rect> {
588        let mut out = mem::MaybeUninit::uninit();
589
590        let success = unsafe {
591            sys::SDL_IntersectRect(self.raw(), other.raw(), out.as_mut_ptr())
592                != sys::SDL_bool::SDL_FALSE
593        };
594
595        if success {
596            let out = unsafe { out.assume_init() };
597            Some(Rect::from_ll(out))
598        } else {
599            None
600        }
601    }
602
603    /// Calculates the union of two rectangles (i.e. the smallest rectangle
604    /// that contains both).
605    ///
606    /// The bitwise OR operator `|` can also be used.
607    ///
608    /// # Examples
609    ///
610    /// ```
611    /// use sdl2::rect::Rect;
612    /// let rect = Rect::new(0, 0, 5, 5);
613    /// assert_eq!(rect.union(rect), rect);
614    /// assert_eq!(rect.union(Rect::new(2, 2, 5, 5)), Rect::new(0, 0, 7, 7));
615    /// assert_eq!(rect.union(Rect::new(5, 0, 5, 5)), Rect::new(0, 0, 10, 5));
616    /// ```
617    #[doc(alias = "SDL_UnionRect")]
618    pub fn union(&self, other: Rect) -> Rect {
619        let mut out = mem::MaybeUninit::uninit();
620
621        unsafe {
622            // If `self` and `other` are both empty, `out` remains uninitialized.
623            // Because empty rectangles aren't allowed in Rect, we don't need to worry about this.
624            sys::SDL_UnionRect(self.raw(), other.raw(), out.as_mut_ptr())
625        };
626
627        let out = unsafe { out.assume_init() };
628
629        Rect::from_ll(out)
630    }
631
632    /// Calculates the intersection of a rectangle and a line segment and
633    /// returns the points of their intersection.
634    #[doc(alias = "SDL_IntersectRectAndLine")]
635    pub fn intersect_line(&self, start: Point, end: Point) -> Option<(Point, Point)> {
636        let (mut start_x, mut start_y) = (start.x(), start.y());
637        let (mut end_x, mut end_y) = (end.x(), end.y());
638
639        let intersected = unsafe {
640            sys::SDL_IntersectRectAndLine(
641                self.raw(),
642                &mut start_x,
643                &mut start_y,
644                &mut end_x,
645                &mut end_y,
646            ) != sys::SDL_bool::SDL_FALSE
647        };
648
649        if intersected {
650            Some((Point::new(start_x, start_y), Point::new(end_x, end_y)))
651        } else {
652            None
653        }
654    }
655}
656
657impl Deref for Rect {
658    type Target = sys::SDL_Rect;
659
660    /// # Example
661    ///
662    /// ```rust
663    /// use sdl2::rect::Rect;
664    /// let rect = Rect::new(2, 3, 4, 5);
665    /// assert_eq!(2, rect.x);
666    /// ```
667    fn deref(&self) -> &sys::SDL_Rect {
668        &self.raw
669    }
670}
671
672impl DerefMut for Rect {
673    /// # Example
674    ///
675    /// ```rust
676    /// use sdl2::rect::Rect;
677    /// let mut rect = Rect::new(2, 3, 4, 5);
678    /// rect.x = 60;
679    /// assert_eq!(60, rect.x);
680    /// ```
681    fn deref_mut(&mut self) -> &mut sys::SDL_Rect {
682        &mut self.raw
683    }
684}
685
686impl From<Rect> for sys::SDL_Rect {
687    fn from(val: Rect) -> Self {
688        val.raw
689    }
690}
691
692impl From<Rect> for (i32, i32, u32, u32) {
693    fn from(val: Rect) -> Self {
694        (val.raw.x, val.raw.y, val.raw.w as u32, val.raw.h as u32)
695    }
696}
697
698impl From<sys::SDL_Rect> for Rect {
699    fn from(raw: sys::SDL_Rect) -> Rect {
700        Rect { raw }
701    }
702}
703
704impl From<(i32, i32, u32, u32)> for Rect {
705    fn from((x, y, width, height): (i32, i32, u32, u32)) -> Rect {
706        Rect::new(x, y, width, height)
707    }
708}
709
710impl AsRef<sys::SDL_Rect> for Rect {
711    fn as_ref(&self) -> &sys::SDL_Rect {
712        &self.raw
713    }
714}
715
716impl AsMut<sys::SDL_Rect> for Rect {
717    fn as_mut(&mut self) -> &mut sys::SDL_Rect {
718        &mut self.raw
719    }
720}
721
722// Intersection
723impl BitAnd<Rect> for Rect {
724    type Output = Option<Rect>;
725    #[doc(alias = "SDL_Point")]
726    fn bitand(self, rhs: Rect) -> Option<Rect> {
727        self.intersection(rhs)
728    }
729}
730
731// Union
732impl BitOr<Rect> for Rect {
733    type Output = Rect;
734    fn bitor(self, rhs: Rect) -> Rect {
735        self.union(rhs)
736    }
737}
738
739/// Immutable point type, consisting of x and y.
740// Uses repr(transparent) to allow pointer casting between Point and SDL_Point (see
741// `Point::raw_slice`)
742#[repr(transparent)]
743#[derive(Copy, Clone)]
744pub struct Point {
745    raw: sys::SDL_Point,
746}
747
748impl ::std::fmt::Debug for Point {
749    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
750        fmt.debug_struct("Point")
751            .field("x", &self.raw.x)
752            .field("y", &self.raw.y)
753            .finish()
754    }
755}
756
757impl PartialEq for Point {
758    fn eq(&self, other: &Point) -> bool {
759        self.raw.x == other.raw.x && self.raw.y == other.raw.y
760    }
761}
762
763impl Eq for Point {}
764
765impl Hash for Point {
766    fn hash<H: Hasher>(&self, state: &mut H) {
767        self.raw.x.hash(state);
768        self.raw.y.hash(state);
769    }
770}
771
772impl Deref for Point {
773    type Target = sys::SDL_Point;
774
775    /// # Example
776    ///
777    /// ```rust
778    /// use sdl2::rect::Point;
779    /// let point = Point::new(2, 3);
780    /// assert_eq!(2, point.x);
781    /// ```
782    fn deref(&self) -> &sys::SDL_Point {
783        &self.raw
784    }
785}
786
787impl DerefMut for Point {
788    /// # Example
789    ///
790    /// ```rust
791    /// use sdl2::rect::Point;
792    /// let mut point = Point::new(2, 3);
793    /// point.x = 4;
794    /// assert_eq!(4, point.x);
795    /// ```
796    fn deref_mut(&mut self) -> &mut sys::SDL_Point {
797        &mut self.raw
798    }
799}
800
801impl AsRef<sys::SDL_Point> for Point {
802    fn as_ref(&self) -> &sys::SDL_Point {
803        &self.raw
804    }
805}
806
807impl AsMut<sys::SDL_Point> for Point {
808    fn as_mut(&mut self) -> &mut sys::SDL_Point {
809        &mut self.raw
810    }
811}
812
813impl From<sys::SDL_Point> for Point {
814    fn from(prim: sys::SDL_Point) -> Point {
815        Point { raw: prim }
816    }
817}
818
819impl From<(i32, i32)> for Point {
820    fn from((x, y): (i32, i32)) -> Point {
821        Point::new(x, y)
822    }
823}
824
825impl From<Point> for sys::SDL_Point {
826    fn from(val: Point) -> Self {
827        val.raw
828    }
829}
830
831impl From<Point> for (i32, i32) {
832    fn from(val: Point) -> Self {
833        (val.x(), val.y())
834    }
835}
836
837impl Point {
838    /// Creates a new point from the given coordinates.
839    pub fn new(x: i32, y: i32) -> Point {
840        Point {
841            raw: sys::SDL_Point {
842                x: clamp_position(x),
843                y: clamp_position(y),
844            },
845        }
846    }
847
848    pub fn from_ll(raw: sys::SDL_Point) -> Point {
849        Point::new(raw.x, raw.y)
850    }
851
852    #[doc(alias = "SDL_Point")]
853    pub fn raw_slice(slice: &[Point]) -> *const sys::SDL_Point {
854        slice.as_ptr() as *const sys::SDL_Point
855    }
856    // this can prevent introducing UB until
857    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
858    #[allow(clippy::trivially_copy_pass_by_ref)]
859    pub fn raw(&self) -> *const sys::SDL_Point {
860        &self.raw
861    }
862
863    /// Returns a new point by shifting this point's coordinates by the given
864    /// x and y values.
865    pub fn offset(self, x: i32, y: i32) -> Point {
866        let x = match self.raw.x.checked_add(x) {
867            Some(val) => val,
868            None => {
869                if x < 0 {
870                    min_int_value()
871                } else {
872                    max_int_value() as i32
873                }
874            }
875        };
876        let y = match self.raw.y.checked_add(y) {
877            Some(val) => val,
878            None => {
879                if y < 0 {
880                    min_int_value()
881                } else {
882                    max_int_value() as i32
883                }
884            }
885        };
886        Point::new(x, y)
887    }
888
889    /// Returns a new point by multiplying this point's coordinates by the
890    /// given scale factor.
891    pub fn scale(self, f: i32) -> Point {
892        Point::new(clamped_mul(self.raw.x, f), clamped_mul(self.raw.y, f))
893    }
894
895    /// Returns the x-coordinate of this point.
896    pub fn x(self) -> i32 {
897        self.raw.x
898    }
899
900    /// Returns the y-coordinate of this point.
901    pub fn y(self) -> i32 {
902        self.raw.y
903    }
904}
905
906impl Add for Point {
907    type Output = Point;
908
909    fn add(self, rhs: Point) -> Point {
910        self.offset(rhs.x(), rhs.y())
911    }
912}
913
914impl AddAssign for Point {
915    fn add_assign(&mut self, rhs: Point) {
916        self.raw.x = clamp_position(self.x() + rhs.x());
917        self.raw.y = clamp_position(self.y() + rhs.y());
918    }
919}
920
921impl Neg for Point {
922    type Output = Point;
923
924    fn neg(self) -> Point {
925        Point::new(-self.x(), -self.y())
926    }
927}
928
929impl Sub for Point {
930    type Output = Point;
931
932    fn sub(self, rhs: Point) -> Point {
933        self.offset(-rhs.x(), -rhs.y())
934    }
935}
936
937impl SubAssign for Point {
938    fn sub_assign(&mut self, rhs: Point) {
939        self.raw.x = clamp_position(self.x() - rhs.x());
940        self.raw.y = clamp_position(self.y() - rhs.y());
941    }
942}
943
944impl Mul<i32> for Point {
945    type Output = Point;
946
947    fn mul(self, rhs: i32) -> Point {
948        self.scale(rhs)
949    }
950}
951
952impl MulAssign<i32> for Point {
953    fn mul_assign(&mut self, rhs: i32) {
954        self.raw.x = clamped_mul(self.x(), rhs);
955        self.raw.y = clamped_mul(self.y(), rhs);
956    }
957}
958
959impl Div<i32> for Point {
960    type Output = Point;
961
962    fn div(self, rhs: i32) -> Point {
963        Point::new(self.x() / rhs, self.y() / rhs)
964    }
965}
966
967impl DivAssign<i32> for Point {
968    fn div_assign(&mut self, rhs: i32) {
969        self.raw.x /= rhs;
970        self.raw.y /= rhs;
971    }
972}
973
974impl std::iter::Sum for Point {
975    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
976        iter.fold(Point::new(0, 0), Point::add)
977    }
978}
979
980/// A (non-empty) rectangle with float precision.
981///
982/// The width and height of a `FRect` must always be strictly positive (never
983/// zero). In cases where empty rects may need to be represented, it is
984/// recommended to use `Option<FRect>`, with `None` representing an empty
985/// rectangle (see, for example, the output of the
986/// [`intersection`](#method.intersection) method).
987#[derive(Clone, Copy)]
988pub struct FRect {
989    raw: sys::SDL_FRect,
990}
991
992impl ::std::fmt::Debug for FRect {
993    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
994        return write!(
995            fmt,
996            "FRect {{ x: {}, y: {}, w: {}, h: {} }}",
997            self.raw.x, self.raw.y, self.raw.w, self.raw.h
998        );
999    }
1000}
1001
1002impl PartialEq for FRect {
1003    fn eq(&self, other: &FRect) -> bool {
1004        self.raw.x == other.raw.x
1005            && self.raw.y == other.raw.y
1006            && self.raw.w == other.raw.w
1007            && self.raw.h == other.raw.h
1008    }
1009}
1010
1011impl FRect {
1012    /// Creates a new rectangle with float precision from the given values.
1013    ///
1014    /// `FRect`s must always be non-empty, so a `width` and/or `height` argument
1015    /// of 0 or less will be replaced with 1.
1016    pub fn new(x: f32, y: f32, width: f32, height: f32) -> FRect {
1017        let raw = sys::SDL_FRect {
1018            x,
1019            y,
1020            w: clamp_f32_size(width),
1021            h: clamp_f32_size(height),
1022        };
1023        FRect { raw }
1024    }
1025
1026    /// Creates a new rectangle with float precision centered on the given position.
1027    ///
1028    /// `FRect`s must always be non-empty, so a `width` and/or `height` argument
1029    /// of 0 or less will be replaced with 1.
1030    pub fn from_center<P>(center: P, width: f32, height: f32) -> FRect
1031    where
1032        P: Into<FPoint>,
1033    {
1034        let raw = sys::SDL_FRect {
1035            x: 0.0,
1036            y: 0.0,
1037            w: clamp_f32_size(width),
1038            h: clamp_f32_size(height),
1039        };
1040        let mut rect = FRect { raw };
1041        rect.center_on(center.into());
1042        rect
1043    }
1044
1045    /// The horizontal position of this rectangle.
1046    #[inline]
1047    pub fn x(&self) -> f32 {
1048        self.raw.x
1049    }
1050
1051    /// The vertical position of this rectangle.
1052    #[inline]
1053    pub fn y(&self) -> f32 {
1054        self.raw.y
1055    }
1056
1057    /// The width of this rectangle.
1058    pub fn width(&self) -> f32 {
1059        self.raw.w as f32
1060    }
1061
1062    /// The height of this rectangle.
1063    pub fn height(&self) -> f32 {
1064        self.raw.h as f32
1065    }
1066
1067    /// Returns the width and height of this rectangle.
1068    pub fn size(&self) -> (f32, f32) {
1069        (self.width(), self.height())
1070    }
1071
1072    /// Sets the horizontal position of this rectangle to the given value,
1073    /// clamped to be less than or equal to i32::max_value() / 2.
1074    pub fn set_x(&mut self, x: f32) {
1075        self.raw.x = x;
1076    }
1077
1078    /// Sets the vertical position of this rectangle to the given value,
1079    /// clamped to be less than or equal to i32::max_value() / 2.
1080    pub fn set_y(&mut self, y: f32) {
1081        self.raw.y = y;
1082    }
1083
1084    /// Sets the width of this rectangle to the given value,
1085    /// clamped to be less than or equal to i32::max_value() / 2.
1086    ///
1087    /// `FRect`s must always be non-empty, so a `width` argument of 0 will be
1088    /// replaced with 1.
1089    pub fn set_width(&mut self, width: f32) {
1090        self.raw.w = clamp_f32_size(width);
1091    }
1092
1093    /// Sets the height of this rectangle to the given value,
1094    /// clamped to be less than or equal to i32::max_value() / 2.
1095    ///
1096    /// `FRect`s must always be non-empty, so a `height` argument of 0 will be
1097    /// replaced with 1.
1098    pub fn set_height(&mut self, height: f32) {
1099        self.raw.h = clamp_f32_size(height);
1100    }
1101
1102    /// Returns the x-position of the left side of this rectangle.
1103    pub fn left(&self) -> f32 {
1104        self.raw.x
1105    }
1106
1107    /// Returns the x-position of the right side of this rectangle.
1108    pub fn right(&self) -> f32 {
1109        self.raw.x + self.raw.w
1110    }
1111
1112    /// Returns the y-position of the top side of this rectangle.
1113    pub fn top(&self) -> f32 {
1114        self.raw.y
1115    }
1116
1117    /// Returns the y-position of the bottom side of this rectangle.
1118    pub fn bottom(&self) -> f32 {
1119        self.raw.y + self.raw.h
1120    }
1121
1122    /// Shifts this rectangle to the left by `offset`.
1123    ///
1124    /// # Example
1125    ///
1126    /// ```
1127    /// use sdl2::rect::FRect;
1128    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).left_shifted(5.0), FRect::new(-5.0, 0.0, 10.0, 10.0));
1129    /// ```
1130    pub fn left_shifted(mut self, offset: f32) -> FRect {
1131        self.offset(-offset, self.y());
1132        self
1133    }
1134
1135    /// Shifts this rectangle to the right by `offset`.
1136    ///
1137    /// # Example
1138    ///
1139    /// ```
1140    /// use sdl2::rect::FRect;
1141    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).right_shifted(5.0), FRect::new(5.0, 0.0, 10.0, 10.0));
1142    /// ```
1143    pub fn right_shifted(mut self, offset: f32) -> FRect {
1144        self.offset(offset, self.y());
1145        self
1146    }
1147
1148    /// Shifts this rectangle to the top by `offset`.
1149    ///
1150    /// # Example
1151    ///
1152    /// ```
1153    /// use sdl2::rect::FRect;
1154    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).top_shifted(5.00), FRect::new(0.0, -5.0, 10.0, 10.0));
1155    /// ```
1156    pub fn top_shifted(mut self, offset: f32) -> FRect {
1157        self.offset(self.x(), -offset);
1158        self
1159    }
1160
1161    /// Shifts this rectangle to the bottom by `offset`.
1162    ///
1163    /// # Example
1164    ///
1165    /// ```
1166    /// use sdl2::rect::FRect;
1167    /// assert_eq!(FRect::new(0.0, 0.0, 10.0, 10.0).bottom_shifted(5.0), FRect::new(0.0, 5.0, 10.0, 10.0));
1168    /// ```
1169    pub fn bottom_shifted(mut self, offset: f32) -> FRect {
1170        self.offset(self.x(), offset);
1171        self
1172    }
1173
1174    /// Returns the center position of this rectangle.
1175    ///
1176    /// Note that if the width or height is not a multiple of two,
1177    /// the center will be rounded down.
1178    ///
1179    /// # Example
1180    ///
1181    /// ```
1182    /// use sdl2::rect::{FRect, FPoint};
1183    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1184    /// assert_eq!(FPoint::new(2.0, 1.5), rect.center());
1185    /// ```
1186    pub fn center(&self) -> FPoint {
1187        let x = self.raw.x + (self.raw.w / 2.0);
1188        let y = self.raw.y + (self.raw.h / 2.0);
1189        FPoint::new(x, y)
1190    }
1191
1192    /// Returns the top-left corner of this rectangle.
1193    ///
1194    /// # Example
1195    ///
1196    /// ```
1197    /// use sdl2::rect::{FRect, FPoint};
1198    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1199    /// assert_eq!(FPoint::new(1.0, 0.0), rect.top_left());
1200    /// ```
1201    pub fn top_left(&self) -> FPoint {
1202        FPoint::new(self.left(), self.top())
1203    }
1204
1205    /// Returns the top-right corner of this rectangle.
1206    ///
1207    /// # Example
1208    ///
1209    /// ```
1210    /// use sdl2::rect::{FRect, FPoint};
1211    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1212    /// assert_eq!(FPoint::new(3.0, 0.0), rect.top_right());
1213    /// ```
1214    pub fn top_right(&self) -> FPoint {
1215        FPoint::new(self.right(), self.top())
1216    }
1217
1218    /// Returns the bottom-left corner of this rectangle.
1219    ///
1220    /// # Example
1221    ///
1222    /// ```
1223    /// use sdl2::rect::{FRect, FPoint};
1224    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1225    /// assert_eq!(FPoint::new(1.0, 3.0), rect.bottom_left());
1226    /// ```
1227    pub fn bottom_left(&self) -> FPoint {
1228        FPoint::new(self.left(), self.bottom())
1229    }
1230
1231    /// Returns the bottom-right corner of this rectangle.
1232    ///
1233    /// # Example
1234    ///
1235    /// ```
1236    /// use sdl2::rect::{FRect, FPoint};
1237    /// let rect = FRect::new(1.0, 0.0, 2.0, 3.0);
1238    /// assert_eq!(FPoint::new(3.0, 3.0), rect.bottom_right());
1239    /// ```
1240    pub fn bottom_right(&self) -> FPoint {
1241        FPoint::new(self.right(), self.bottom())
1242    }
1243
1244    /// Sets the position of the right side of this rectangle to the given
1245    /// value, clamped to be greater than 0.
1246    pub fn set_right(&mut self, right: f32) {
1247        self.raw.x = clamp_f32_size(clamp_f32_size(right) - self.raw.w);
1248    }
1249
1250    /// Sets the position of the bottom side of this rectangle to the given
1251    /// value, clamped to be greater than 0.
1252    pub fn set_bottom(&mut self, bottom: f32) {
1253        self.raw.y = clamp_f32_size(clamp_f32_size(bottom) - self.raw.h);
1254    }
1255
1256    /// Centers the rectangle on the given point (in place).
1257    #[inline]
1258    pub fn center_on<P>(&mut self, point: P)
1259    where
1260        P: Into<(f32, f32)>,
1261    {
1262        let (x, y) = point.into();
1263        self.raw.x = x - self.raw.w / 2.0;
1264        self.raw.y = y - self.raw.h / 2.0;
1265    }
1266
1267    /// Centers the rectangle on the given point.
1268    #[inline]
1269    pub fn centered_on<P>(mut self, point: P) -> FRect
1270    where
1271        P: Into<(f32, f32)>,
1272    {
1273        self.center_on(point);
1274        self
1275    }
1276
1277    /// Move this rect.
1278    #[inline]
1279    pub fn offset(&mut self, x: f32, y: f32) {
1280        self.raw.x += x;
1281        self.raw.y += y;
1282    }
1283
1284    /// Moves this rect to the given position.
1285    pub fn reposition<P>(&mut self, point: P)
1286    where
1287        P: Into<(f32, f32)>,
1288    {
1289        let (x, y) = point.into();
1290        self.raw.x = x;
1291        self.raw.y = y;
1292    }
1293
1294    /// Resizes this rect to the given size after clamping the values.
1295    pub fn resize(&mut self, width: f32, height: f32) {
1296        self.raw.w = clamp_f32_size(width);
1297        self.raw.h = clamp_f32_size(height);
1298    }
1299
1300    /// Checks whether this rectangle contains a given point.
1301    ///
1302    /// Points along the right and bottom edges are not considered to be inside
1303    /// the rectangle. Another way to look at it is that this method returns true if
1304    /// and only if the given point would be painted by a call to
1305    /// [`Renderer::fill_frect`](
1306    /// ../render/struct.Renderer.html#method.fill_frect).
1307    ///
1308    /// # Examples
1309    ///
1310    /// ```
1311    /// use sdl2::rect::{FRect, FPoint};
1312    /// let rect = FRect::new(1.0, 2.0, 3.0, 4.0);
1313    /// assert!(rect.contains_point(FPoint::new(1.0, 2.0)));
1314    /// assert!(!rect.contains_point(FPoint::new(0.0, 1.0)));
1315    /// assert!(rect.contains_point(FPoint::new(3.0, 5.0)));
1316    /// assert!(!rect.contains_point(FPoint::new(4.0, 6.0)));
1317    /// ```
1318    pub fn contains_point<P>(&self, point: P) -> bool
1319    where
1320        P: Into<(f32, f32)>,
1321    {
1322        let (x, y) = point.into();
1323        let inside_x = x >= self.left() && x < self.right();
1324        inside_x && (y >= self.top() && y < self.bottom())
1325    }
1326
1327    /// Checks whether this rectangle completely contains another rectangle.
1328    ///
1329    /// This method returns true if and only if every point contained by
1330    /// `other` is also contained by `self`; in other words, if the
1331    /// intersection of `self` and `other` is equal to `other`.
1332    ///
1333    /// # Examples
1334    ///
1335    /// ```
1336    /// use sdl2::rect::FRect;
1337    /// let rect = FRect::new(1.0, 2.0, 3.0, 4.0);
1338    /// assert!(rect.contains_rect(rect));
1339    /// assert!(rect.contains_rect(FRect::new(3.0, 3.0, 1.0, 1.0)));
1340    /// assert!(!rect.contains_rect(FRect::new(2.0, 1.0, 1.0, 1.0)));
1341    /// assert!(!rect.contains_rect(FRect::new(3.0, 3.0, 2.0, 1.0)));
1342    /// ```
1343    pub fn contains_rect(&self, other: FRect) -> bool {
1344        other.left() >= self.left()
1345            && other.right() <= self.right()
1346            && other.top() >= self.top()
1347            && other.bottom() <= self.bottom()
1348    }
1349
1350    /// Returns the underlying C FRect.
1351    // this can prevent introducing UB until
1352    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
1353    #[allow(clippy::trivially_copy_pass_by_ref)]
1354    pub fn raw(&self) -> *const sys::SDL_FRect {
1355        &self.raw
1356    }
1357
1358    pub fn raw_mut(&mut self) -> *mut sys::SDL_FRect {
1359        self.raw() as *mut _
1360    }
1361
1362    #[doc(alias = "SDL_FRect")]
1363    pub fn raw_slice(slice: &[FRect]) -> *const sys::SDL_FRect {
1364        slice.as_ptr() as *const sys::SDL_FRect
1365    }
1366
1367    pub fn from_ll(raw: sys::SDL_FRect) -> FRect {
1368        FRect::new(raw.x, raw.y, raw.w, raw.h)
1369    }
1370
1371    /// Calculate a minimal rectangle enclosing a set of points.
1372    /// If a clipping rectangle is given, only points that are within it will be
1373    /// considered.
1374    #[doc(alias = "SDL_EncloseFPoints")]
1375    pub fn from_enclose_points<R: Into<Option<FRect>>>(
1376        points: &[FPoint],
1377        clipping_rect: R,
1378    ) -> Option<FRect>
1379    where
1380        R: Into<Option<FRect>>,
1381    {
1382        let clipping_rect = clipping_rect.into();
1383
1384        if points.is_empty() {
1385            return None;
1386        }
1387
1388        let mut out = mem::MaybeUninit::uninit();
1389
1390        let clip_ptr = match clipping_rect.as_ref() {
1391            Some(r) => r.raw(),
1392            None => ptr::null(),
1393        };
1394
1395        let result = unsafe {
1396            sys::SDL_EncloseFPoints(
1397                FPoint::raw_slice(points),
1398                points.len() as i32,
1399                clip_ptr,
1400                out.as_mut_ptr(),
1401            ) != sys::SDL_bool::SDL_FALSE
1402        };
1403
1404        if result {
1405            let out = unsafe { out.assume_init() };
1406
1407            // Return an error if the dimensions are too large.
1408            Some(FRect::from_ll(out))
1409        } else {
1410            None
1411        }
1412    }
1413
1414    /// Determines whether two rectangles intersect.
1415    ///
1416    /// Rectangles that share an edge but don't actually overlap are not
1417    /// considered to intersect.
1418    ///
1419    /// # Examples
1420    ///
1421    /// ```
1422    /// use sdl2::rect::FRect;
1423    /// let rect = FRect::new(0.0, 0.0, 5.0, 5.0);
1424    /// assert!(rect.has_intersection(rect));
1425    /// assert!(rect.has_intersection(FRect::new(2.0, 2.0, 5.0, 5.0)));
1426    /// assert!(!rect.has_intersection(FRect::new(5.0, 0.0, 5.0, 5.0)));
1427    /// ```
1428    #[doc(alias = "SDL_HasIntersectionF")]
1429    pub fn has_intersection(&self, other: FRect) -> bool {
1430        unsafe { sys::SDL_HasIntersectionF(self.raw(), other.raw()) != sys::SDL_bool::SDL_FALSE }
1431    }
1432
1433    /// Calculates the intersection of two rectangles.
1434    ///
1435    /// Returns `None` if the two rectangles don't intersect.  Rectangles that
1436    /// share an edge but don't actually overlap are not considered to
1437    /// intersect.
1438    ///
1439    /// The bitwise AND operator `&` can also be used.
1440    ///
1441    /// # Examples
1442    ///
1443    /// ```
1444    /// use sdl2::rect::FRect;
1445    /// let rect = FRect::new(0.0, 0.0, 5.0, 5.0);
1446    /// assert_eq!(rect.intersection(rect), Some(rect));
1447    /// assert_eq!(rect.intersection(FRect::new(2.0, 2.0, 5.0, 5.0)),
1448    ///            Some(FRect::new(2.0, 2.0, 3.0, 3.0)));
1449    /// assert_eq!(rect.intersection(FRect::new(5.0, 0.0, 5.0, 5.0)), None);
1450    /// ```
1451    #[doc(alias = "SDL_IntersectFRect")]
1452    pub fn intersection(&self, other: FRect) -> Option<FRect> {
1453        let mut out = mem::MaybeUninit::uninit();
1454
1455        let success = unsafe {
1456            sys::SDL_IntersectFRect(self.raw(), other.raw(), out.as_mut_ptr())
1457                != sys::SDL_bool::SDL_FALSE
1458        };
1459
1460        if success {
1461            let out = unsafe { out.assume_init() };
1462            Some(FRect::from_ll(out))
1463        } else {
1464            None
1465        }
1466    }
1467
1468    /// Calculates the union of two rectangles (i.e. the smallest rectangle
1469    /// that contains both).
1470    ///
1471    /// The bitwise OR operator `|` can also be used.
1472    ///
1473    /// # Examples
1474    ///
1475    /// ```
1476    /// use sdl2::rect::FRect;
1477    /// let rect = FRect::new(0.0, 0.0, 5.0, 5.0);
1478    /// assert_eq!(rect.union(rect), rect);
1479    /// assert_eq!(rect.union(FRect::new(2.0, 2.0, 5.0, 5.0)), FRect::new(0.0, 0.0, 7.0, 7.0));
1480    /// assert_eq!(rect.union(FRect::new(5.0, 0.0, 5.0, 5.0)), FRect::new(0.0, 0.0, 10.0, 5.0));
1481    /// ```
1482    #[doc(alias = "SDL_UnionFRect")]
1483    pub fn union(&self, other: FRect) -> FRect {
1484        let mut out = mem::MaybeUninit::uninit();
1485
1486        unsafe {
1487            // If `self` and `other` are both empty, `out` remains uninitialized.
1488            // Because empty rectangles aren't allowed in Rect, we don't need to worry about this.
1489            sys::SDL_UnionFRect(self.raw(), other.raw(), out.as_mut_ptr())
1490        };
1491
1492        let out = unsafe { out.assume_init() };
1493
1494        FRect::from_ll(out)
1495    }
1496
1497    /// Calculates the intersection of a rectangle and a line segment and
1498    /// returns the points of their intersection.
1499    #[doc(alias = "SDL_IntersectFRectAndLine")]
1500    pub fn intersect_line(&self, start: FPoint, end: FPoint) -> Option<(FPoint, FPoint)> {
1501        let (mut start_x, mut start_y) = (start.x(), start.y());
1502        let (mut end_x, mut end_y) = (end.x(), end.y());
1503
1504        let intersected = unsafe {
1505            sys::SDL_IntersectFRectAndLine(
1506                self.raw(),
1507                &mut start_x,
1508                &mut start_y,
1509                &mut end_x,
1510                &mut end_y,
1511            ) != sys::SDL_bool::SDL_FALSE
1512        };
1513
1514        if intersected {
1515            Some((FPoint::new(start_x, start_y), FPoint::new(end_x, end_y)))
1516        } else {
1517            None
1518        }
1519    }
1520}
1521
1522impl Deref for FRect {
1523    type Target = sys::SDL_FRect;
1524
1525    /// # Example
1526    ///
1527    /// ```rust
1528    /// use sdl2::rect::FRect;
1529    /// let rect = FRect::new(2.0, 3.0, 4.0, 5.0);
1530    /// assert_eq!(2.0, rect.x);
1531    /// ```
1532    fn deref(&self) -> &sys::SDL_FRect {
1533        &self.raw
1534    }
1535}
1536
1537impl DerefMut for FRect {
1538    /// # Example
1539    ///
1540    /// ```rust
1541    /// use sdl2::rect::FRect;
1542    /// let mut rect = FRect::new(2.0, 3.0, 4.0, 5.0);
1543    /// rect.x = 60.0;
1544    /// assert_eq!(60.0, rect.x);
1545    /// ```
1546    fn deref_mut(&mut self) -> &mut sys::SDL_FRect {
1547        &mut self.raw
1548    }
1549}
1550
1551impl Into<sys::SDL_FRect> for FRect {
1552    fn into(self) -> sys::SDL_FRect {
1553        self.raw
1554    }
1555}
1556
1557impl Into<(f32, f32, f32, f32)> for FRect {
1558    fn into(self) -> (f32, f32, f32, f32) {
1559        (self.raw.x, self.raw.y, self.raw.w, self.raw.h)
1560    }
1561}
1562
1563impl From<sys::SDL_FRect> for FRect {
1564    fn from(raw: sys::SDL_FRect) -> FRect {
1565        FRect { raw }
1566    }
1567}
1568
1569impl From<(f32, f32, f32, f32)> for FRect {
1570    fn from((x, y, width, height): (f32, f32, f32, f32)) -> FRect {
1571        FRect::new(x, y, width, height)
1572    }
1573}
1574
1575impl AsRef<sys::SDL_FRect> for FRect {
1576    fn as_ref(&self) -> &sys::SDL_FRect {
1577        &self.raw
1578    }
1579}
1580
1581impl AsMut<sys::SDL_FRect> for FRect {
1582    fn as_mut(&mut self) -> &mut sys::SDL_FRect {
1583        &mut self.raw
1584    }
1585}
1586
1587// Intersection
1588impl BitAnd<FRect> for FRect {
1589    type Output = Option<FRect>;
1590    #[doc(alias = "SDL_FPoint")]
1591    fn bitand(self, rhs: FRect) -> Option<FRect> {
1592        self.intersection(rhs)
1593    }
1594}
1595
1596// Union
1597impl BitOr<FRect> for FRect {
1598    type Output = FRect;
1599    fn bitor(self, rhs: FRect) -> FRect {
1600        self.union(rhs)
1601    }
1602}
1603
1604/// Immutable point type with float precision, consisting of x and y.
1605#[derive(Copy, Clone)]
1606pub struct FPoint {
1607    raw: sys::SDL_FPoint,
1608}
1609
1610impl ::std::fmt::Debug for FPoint {
1611    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
1612        return write!(fmt, "FPoint {{ x: {}, y: {} }}", self.raw.x, self.raw.y);
1613    }
1614}
1615
1616impl PartialEq for FPoint {
1617    fn eq(&self, other: &FPoint) -> bool {
1618        self.raw.x == other.raw.x && self.raw.y == other.raw.y
1619    }
1620}
1621
1622impl Deref for FPoint {
1623    type Target = sys::SDL_FPoint;
1624
1625    /// # Example
1626    ///
1627    /// ```rust
1628    /// use sdl2::rect::FPoint;
1629    /// let point = FPoint::new(2.0, 3.0);
1630    /// assert_eq!(2.0, point.x);
1631    /// ```
1632    fn deref(&self) -> &sys::SDL_FPoint {
1633        &self.raw
1634    }
1635}
1636
1637impl DerefMut for FPoint {
1638    /// # Example
1639    ///
1640    /// ```rust
1641    /// use sdl2::rect::FPoint;
1642    /// let mut point = FPoint::new(2.0, 3.0);
1643    /// point.x = 4.0;
1644    /// assert_eq!(4.0, point.x);
1645    /// ```
1646    fn deref_mut(&mut self) -> &mut sys::SDL_FPoint {
1647        &mut self.raw
1648    }
1649}
1650
1651impl AsRef<sys::SDL_FPoint> for FPoint {
1652    fn as_ref(&self) -> &sys::SDL_FPoint {
1653        &self.raw
1654    }
1655}
1656
1657impl AsMut<sys::SDL_FPoint> for FPoint {
1658    fn as_mut(&mut self) -> &mut sys::SDL_FPoint {
1659        &mut self.raw
1660    }
1661}
1662
1663impl From<sys::SDL_FPoint> for FPoint {
1664    fn from(prim: sys::SDL_FPoint) -> FPoint {
1665        FPoint { raw: prim }
1666    }
1667}
1668
1669impl From<(f32, f32)> for FPoint {
1670    fn from((x, y): (f32, f32)) -> FPoint {
1671        FPoint::new(x, y)
1672    }
1673}
1674
1675impl Into<sys::SDL_FPoint> for FPoint {
1676    fn into(self) -> sys::SDL_FPoint {
1677        self.raw
1678    }
1679}
1680
1681impl Into<(f32, f32)> for FPoint {
1682    fn into(self) -> (f32, f32) {
1683        (self.x(), self.y())
1684    }
1685}
1686
1687impl FPoint {
1688    /// Creates a new point from the given coordinates.
1689    pub fn new(x: f32, y: f32) -> FPoint {
1690        FPoint {
1691            raw: sys::SDL_FPoint { x, y },
1692        }
1693    }
1694
1695    pub fn from_ll(raw: sys::SDL_FPoint) -> FPoint {
1696        FPoint::new(raw.x, raw.y)
1697    }
1698
1699    #[doc(alias = "SDL_FPoint")]
1700    pub fn raw_slice(slice: &[FPoint]) -> *const sys::SDL_FPoint {
1701        slice.as_ptr() as *const sys::SDL_FPoint
1702    }
1703
1704    // this can prevent introducing UB until
1705    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
1706    #[allow(clippy::trivially_copy_pass_by_ref)]
1707    pub fn raw(&self) -> *const sys::SDL_FPoint {
1708        &self.raw
1709    }
1710
1711    /// Returns a new point by shifting this point's coordinates by the given
1712    /// x and y values.
1713    pub fn offset(self, x: f32, y: f32) -> FPoint {
1714        let x = self.raw.x + x;
1715        let y = self.raw.y + y;
1716        FPoint::new(x, y)
1717    }
1718
1719    /// Returns a new point by multiplying this point's coordinates by the
1720    /// given scale factor.
1721    pub fn scale(self, f: f32) -> FPoint {
1722        FPoint::new(self.raw.x * f, self.raw.y * f)
1723    }
1724
1725    /// Returns the x-coordinate of this point.
1726    pub fn x(self) -> f32 {
1727        self.raw.x
1728    }
1729
1730    /// Returns the y-coordinate of this point.
1731    pub fn y(self) -> f32 {
1732        self.raw.y
1733    }
1734}
1735
1736impl Add for FPoint {
1737    type Output = FPoint;
1738
1739    fn add(self, rhs: FPoint) -> FPoint {
1740        self.offset(rhs.x(), rhs.y())
1741    }
1742}
1743
1744impl AddAssign for FPoint {
1745    fn add_assign(&mut self, rhs: FPoint) {
1746        self.raw.x = self.x() + rhs.x();
1747        self.raw.y = self.y() + rhs.y();
1748    }
1749}
1750
1751impl Neg for FPoint {
1752    type Output = FPoint;
1753
1754    fn neg(self) -> FPoint {
1755        FPoint::new(-self.x(), -self.y())
1756    }
1757}
1758
1759impl Sub for FPoint {
1760    type Output = FPoint;
1761
1762    fn sub(self, rhs: FPoint) -> FPoint {
1763        self.offset(-rhs.x(), -rhs.y())
1764    }
1765}
1766
1767impl SubAssign for FPoint {
1768    fn sub_assign(&mut self, rhs: FPoint) {
1769        self.raw.x = self.x() - rhs.x();
1770        self.raw.y = self.y() - rhs.y();
1771    }
1772}
1773
1774impl Mul<f32> for FPoint {
1775    type Output = FPoint;
1776
1777    fn mul(self, rhs: f32) -> FPoint {
1778        self.scale(rhs)
1779    }
1780}
1781
1782impl MulAssign<f32> for FPoint {
1783    fn mul_assign(&mut self, rhs: f32) {
1784        self.raw.x = self.x() * rhs;
1785        self.raw.y = self.y() * rhs;
1786    }
1787}
1788
1789impl Div<f32> for FPoint {
1790    type Output = FPoint;
1791
1792    fn div(self, rhs: f32) -> FPoint {
1793        FPoint::new(self.x() / rhs, self.y() / rhs)
1794    }
1795}
1796
1797impl DivAssign<f32> for FPoint {
1798    fn div_assign(&mut self, rhs: f32) {
1799        self.raw.x /= rhs;
1800        self.raw.y /= rhs;
1801    }
1802}
1803
1804impl std::iter::Sum for FPoint {
1805    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
1806        iter.fold(FPoint::new(0.0, 0.0), FPoint::add)
1807    }
1808}
1809
1810#[cfg(test)]
1811mod test {
1812    use super::{max_int_value, min_int_value, FPoint, FRect, Point, Rect};
1813
1814    /// Used to compare "literal" (unclamped) rect values.
1815    fn tuple(x: i32, y: i32, w: u32, h: u32) -> (i32, i32, u32, u32) {
1816        (x, y, w, h)
1817    }
1818
1819    #[test]
1820    fn centered() {
1821        // Tests both center_on and centered_on
1822        assert_eq!(
1823            Rect::new(0, 0, 10, 10).centered_on((0, 0)),
1824            Rect::new(-5, -5, 10, 10)
1825        );
1826    }
1827
1828    #[test]
1829    fn enclose_points_valid() {
1830        assert_eq!(
1831            Some(tuple(2, 4, 4, 6)),
1832            Rect::from_enclose_points(&[Point::new(2, 4), Point::new(5, 9)], None)
1833                .map(|r| r.into())
1834        );
1835    }
1836
1837    #[test]
1838    fn enclose_points_outside_clip_rect() {
1839        assert_eq!(
1840            Rect::from_enclose_points(
1841                &[Point::new(0, 0), Point::new(10, 10)],
1842                Some(Rect::new(3, 3, 1, 1))
1843            ),
1844            None
1845        );
1846    }
1847
1848    #[test]
1849    fn enclose_points_max_values() {
1850        // Try to enclose the top-left-most and bottom-right-most points.
1851        assert_eq!(
1852            Some(tuple(
1853                min_int_value(),
1854                min_int_value(),
1855                max_int_value(),
1856                max_int_value()
1857            )),
1858            Rect::from_enclose_points(
1859                &[
1860                    Point::new(i32::MIN, i32::MIN),
1861                    Point::new(i32::MAX, i32::MAX)
1862                ],
1863                None
1864            )
1865            .map(|r| r.into())
1866        );
1867    }
1868
1869    #[test]
1870    fn has_intersection() {
1871        let rect = Rect::new(0, 0, 10, 10);
1872        assert!(rect.has_intersection(Rect::new(9, 9, 10, 10)));
1873        // edge
1874        assert!(!rect.has_intersection(Rect::new(10, 10, 10, 10)));
1875        // out
1876        assert!(!rect.has_intersection(Rect::new(11, 11, 10, 10)));
1877    }
1878
1879    #[test]
1880    fn intersection() {
1881        let rect = Rect::new(0, 0, 10, 10);
1882        assert_eq!(rect & Rect::new(9, 9, 10, 10), Some(Rect::new(9, 9, 1, 1)));
1883        assert_eq!(rect & Rect::new(11, 11, 10, 10), None);
1884    }
1885
1886    #[test]
1887    fn union() {
1888        assert_eq!(
1889            Rect::new(0, 0, 1, 1) | Rect::new(9, 9, 1, 1),
1890            Rect::new(0, 0, 10, 10)
1891        );
1892    }
1893
1894    #[test]
1895    fn intersect_line() {
1896        assert_eq!(
1897            Rect::new(1, 1, 5, 5).intersect_line(Point::new(0, 0), Point::new(10, 10)),
1898            Some((Point::new(1, 1), Point::new(5, 5)))
1899        );
1900    }
1901
1902    #[test]
1903    fn clamp_size_zero() {
1904        assert_eq!(tuple(0, 0, 1, 1), Rect::new(0, 0, 0, 0).into());
1905    }
1906
1907    #[test]
1908    fn clamp_position_min() {
1909        assert_eq!(
1910            tuple(min_int_value(), min_int_value(), 1, 1),
1911            Rect::new(i32::MIN, i32::MIN, 1, 1).into()
1912        );
1913    }
1914
1915    #[test]
1916    fn clamp_size_max() {
1917        assert_eq!(
1918            tuple(0, 0, max_int_value(), max_int_value()),
1919            Rect::new(0, 0, max_int_value() + 1, max_int_value() + 1).into()
1920        );
1921    }
1922
1923    #[test]
1924    fn clamp_i32_max() {
1925        assert_eq!(
1926            tuple(0, 0, max_int_value(), max_int_value()),
1927            Rect::new(0, 0, i32::MAX as u32, i32::MAX as u32).into()
1928        )
1929    }
1930
1931    #[test]
1932    fn clamp_position_max() {
1933        assert_eq!(
1934            tuple(max_int_value() as i32, max_int_value() as i32, 1, 1),
1935            Rect::new(max_int_value() as i32 + 1, max_int_value() as i32 + 1, 1, 1).into()
1936        );
1937    }
1938
1939    #[test]
1940    fn shifted() {
1941        // Groups all functions into a single assertion
1942        let rect = Rect::new(5, 5, 10, 10)
1943            .left_shifted(5)
1944            .right_shifted(5)
1945            .top_shifted(5)
1946            .bottom_shifted(5);
1947        assert_eq!(rect, Rect::new(5, 5, 10, 10));
1948    }
1949
1950    #[test]
1951    fn rect_into() {
1952        let test: (i32, i32, u32, u32) = (-11, 5, 50, 20);
1953        assert_eq!(test, Rect::new(-11, 5, 50, 20).into());
1954    }
1955
1956    #[test]
1957    fn rect_from() {
1958        assert_eq!(Rect::from((-11, 5, 50, 20)), Rect::new(-11, 5, 50, 20));
1959    }
1960
1961    #[test]
1962    fn point_into() {
1963        let test: (i32, i32) = (-11, 5);
1964        assert_eq!(test, Point::new(-11, 5).into());
1965    }
1966
1967    #[test]
1968    fn point_from() {
1969        let test: (i32, i32) = (-11, 5);
1970        assert_eq!(test, Point::new(-11, 5).into());
1971    }
1972
1973    #[test]
1974    fn point_add() {
1975        assert_eq!(Point::new(-5, 7), Point::new(-11, 5) + Point::new(6, 2));
1976    }
1977
1978    #[test]
1979    fn point_add_assign() {
1980        let mut point = Point::new(-11, 5);
1981        point += Point::new(6, 2);
1982        assert_eq!(point, Point::new(-11, 5) + Point::new(6, 2));
1983    }
1984
1985    #[test]
1986    fn point_sub() {
1987        assert_eq!(Point::new(-17, 3), Point::new(-11, 5) - Point::new(6, 2));
1988    }
1989
1990    #[test]
1991    fn point_sub_assign() {
1992        let mut point = Point::new(-11, 5);
1993        point -= Point::new(6, 2);
1994        assert_eq!(point, Point::new(-11, 5) - Point::new(6, 2));
1995    }
1996
1997    #[test]
1998    fn point_mul() {
1999        assert_eq!(Point::new(-33, 15), Point::new(-11, 5) * 3);
2000    }
2001
2002    #[test]
2003    fn point_mul_assign() {
2004        let mut point = Point::new(-11, 5);
2005        point *= 3;
2006        assert_eq!(point, Point::new(-11, 5) * 3);
2007    }
2008
2009    #[test]
2010    fn point_mul_clamp() {
2011        assert_eq!(
2012            Point::new(0x7fffffff, -0x7fffffff),
2013            Point::new(-1000000, 5000000) * -3000000
2014        );
2015    }
2016
2017    #[test]
2018    fn point_mul_assign_clamp() {
2019        let mut point = Point::new(-1000000, 5000000);
2020        point *= -3000000;
2021        assert_eq!(point, Point::new(-1000000, 5000000) * -3000000);
2022    }
2023
2024    #[test]
2025    fn point_div() {
2026        assert_eq!(Point::new(-3, 1), Point::new(-11, 5) / 3);
2027    }
2028
2029    #[test]
2030    fn point_div_assign() {
2031        let mut point = Point::new(-11, 5);
2032        point /= 3;
2033        assert_eq!(point, Point::new(-11, 5) / 3);
2034    }
2035
2036    #[test]
2037    fn point_sum() {
2038        let points_sum: Point = vec![Point::new(-11, 5), Point::new(6, 2)].into_iter().sum();
2039        assert_eq!(Point::new(-5, 7), points_sum);
2040    }
2041
2042    #[test]
2043    fn frect_centered() {
2044        // Tests both center_on and centered_on
2045        assert_eq!(
2046            FRect::new(0.0, 0.0, 10.0, 10.0).centered_on((0.0, 0.0)),
2047            FRect::new(-5.0, -5.0, 10.0, 10.0)
2048        );
2049    }
2050
2051    #[test]
2052    fn frect_enclose_points_valid() {
2053        assert_eq!(
2054            Some((2.0, 4.0, 4.0, 6.0)),
2055            FRect::from_enclose_points(&[FPoint::new(2.0, 4.0), FPoint::new(5.0, 9.0)], None)
2056                .map(|r| r.into())
2057        );
2058    }
2059
2060    #[test]
2061    fn frect_enclose_points_outside_clip_rect() {
2062        assert_eq!(
2063            FRect::from_enclose_points(
2064                &[FPoint::new(0.0, 0.0), FPoint::new(10.0, 10.0)],
2065                Some(FRect::new(3.0, 3.0, 1.0, 1.0))
2066            ),
2067            None
2068        );
2069    }
2070
2071    #[test]
2072    fn frect_has_intersection() {
2073        let rect = FRect::new(0.0, 0.0, 10.0, 10.0);
2074        assert!(rect.has_intersection(FRect::new(9.0, 9.0, 10.0, 10.0)));
2075        // edge
2076        assert!(!rect.has_intersection(FRect::new(10.0, 10.0, 10.0, 10.0)));
2077        // out
2078        assert!(!rect.has_intersection(FRect::new(11.0, 11.0, 10.0, 10.0)));
2079    }
2080
2081    #[test]
2082    fn frect_intersection() {
2083        let rect = FRect::new(0.0, 0.0, 10.0, 10.0);
2084        assert_eq!(
2085            rect & FRect::new(9.0, 9.0, 10.0, 10.0),
2086            Some(FRect::new(9.0, 9.0, 1.0, 1.0))
2087        );
2088        assert_eq!(rect & FRect::new(11.0, 11.0, 10.0, 10.0), None);
2089    }
2090
2091    #[test]
2092    fn frect_union() {
2093        assert_eq!(
2094            FRect::new(0.0, 0.0, 1.0, 1.0) | FRect::new(9.0, 9.0, 1.0, 1.0),
2095            FRect::new(0.0, 0.0, 10.0, 10.0)
2096        );
2097    }
2098
2099    #[test]
2100    fn frect_intersect_line() {
2101        assert_eq!(
2102            FRect::new(1.0, 1.0, 5.0, 5.0)
2103                .intersect_line(FPoint::new(0.0, 0.0), FPoint::new(10.0, 10.0)),
2104            Some((FPoint::new(1.0, 1.0), FPoint::new(5.0, 5.0)))
2105        );
2106    }
2107
2108    #[test]
2109    fn frect_shifted() {
2110        // Groups all functions into a single assertion
2111        let rect = FRect::new(0.0, 0.0, 10.0, 10.0)
2112            .left_shifted(5.0)
2113            .right_shifted(5.0)
2114            .top_shifted(5.0)
2115            .bottom_shifted(5.0);
2116        assert_eq!(rect, FRect::new(0.0, 0.0, 10.0, 10.0));
2117    }
2118
2119    #[test]
2120    fn frect_into() {
2121        let test: (f32, f32, f32, f32) = (-11.0, 5.0, 50.0, 20.0);
2122        assert_eq!(test, FRect::new(-11.0, 5.0, 50.0, 20.0).into());
2123    }
2124
2125    #[test]
2126    fn frect_from() {
2127        assert_eq!(
2128            FRect::from((-11.0, 5.0, 50.0, 20.0)),
2129            FRect::new(-11.0, 5.0, 50.0, 20.0)
2130        );
2131    }
2132
2133    #[test]
2134    fn fpoint_into() {
2135        let test: (f32, f32) = (-11.0, 5.0);
2136        assert_eq!(test, FPoint::new(-11.0, 5.0).into());
2137    }
2138
2139    #[test]
2140    fn fpoint_from() {
2141        let test: (f32, f32) = (-11.0, 5.0);
2142        assert_eq!(test, FPoint::new(-11.0, 5.0).into());
2143    }
2144
2145    #[test]
2146    fn fpoint_add() {
2147        assert_eq!(
2148            FPoint::new(-5.0, 7.0),
2149            FPoint::new(-11.0, 5.0) + FPoint::new(6.0, 2.0)
2150        );
2151    }
2152
2153    #[test]
2154    fn fpoint_add_assign() {
2155        let mut point = FPoint::new(-11.0, 5.0);
2156        point += FPoint::new(6.0, 2.0);
2157        assert_eq!(point, FPoint::new(-11.0, 5.0) + FPoint::new(6.0, 2.0));
2158    }
2159
2160    #[test]
2161    fn fpoint_sub() {
2162        assert_eq!(
2163            FPoint::new(-17.0, 3.0),
2164            FPoint::new(-11.0, 5.0) - FPoint::new(6.0, 2.0)
2165        );
2166    }
2167
2168    #[test]
2169    fn fpoint_sub_assign() {
2170        let mut point = FPoint::new(-11.0, 5.0);
2171        point -= FPoint::new(6.0, 2.0);
2172        assert_eq!(point, FPoint::new(-11.0, 5.0) - FPoint::new(6.0, 2.0));
2173    }
2174
2175    #[test]
2176    fn fpoint_mul() {
2177        assert_eq!(FPoint::new(-33.0, 15.0), FPoint::new(-11.0, 5.0) * 3.0);
2178    }
2179
2180    #[test]
2181    fn fpoint_mul_assign() {
2182        let mut point = FPoint::new(-11.0, 5.0);
2183        point *= 3.0;
2184        assert_eq!(point, FPoint::new(-11.0, 5.0) * 3.0);
2185    }
2186
2187    #[test]
2188    fn fpoint_div() {
2189        assert_eq!(FPoint::new(-3.0, 1.0), FPoint::new(-9.0, 3.0) / 3.0);
2190    }
2191
2192    #[test]
2193    fn fpoint_div_assign() {
2194        let mut point = FPoint::new(-11.0, 5.0);
2195        point /= 3.0;
2196        assert_eq!(point, FPoint::new(-11.0, 5.0) / 3.0);
2197    }
2198
2199    #[test]
2200    fn fpoint_sum() {
2201        let points_sum: FPoint = vec![FPoint::new(-11.0, 5.0), FPoint::new(6.0, 2.0)]
2202            .into_iter()
2203            .sum();
2204        assert_eq!(FPoint::new(-5.0, 7.0), points_sum);
2205    }
2206}