From 600853b667a1f1965790f3d06c97f8c9730398c9 Mon Sep 17 00:00:00 2001 From: Etienne Wodey Date: Mon, 18 Nov 2024 18:24:22 +0100 Subject: [PATCH] Expand docs for Box{2,3}D::{contains,contains_inclusive,from_points} --- src/box2d.rs | 98 +++++++++++++++++++++++++++++++++++++++++++++--- src/box3d.rs | 104 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/rect.rs | 6 ++- 3 files changed, 194 insertions(+), 14 deletions(-) diff --git a/src/box2d.rs b/src/box2d.rs index e49b1c0..f930b08 100644 --- a/src/box2d.rs +++ b/src/box2d.rs @@ -180,17 +180,57 @@ where & (self.max.y > other.min.y) } - /// Returns `true` if this box2d contains the point `p`. A point is considered - /// in the box2d if it lies on the left or top edges, but outside if it lies - /// on the right or bottom edges. + /// Returns `true` if this [`Box2D`] contains the point `p`. + /// + /// Points on the top and left edges are inside the box, whereas + /// points on the bottom and right edges are outside the box. + /// See [`Box2D::contains_inclusive`] for a variant that also includes those + /// latter points. + /// + /// # Examples + /// + /// ``` + /// use euclid::default::{Box2D, Point2D}; + /// + /// let rect = Box2D::new(Point2D::origin(), Point2D::new(2, 2)); + /// + /// assert!(rect.contains(Point2D::new(1, 1))); + /// + /// assert!(rect.contains(Point2D::new(0, 1))); // left edge + /// assert!(rect.contains(Point2D::new(1, 0))); // top edge + /// assert!(rect.contains(Point2D::origin())); + /// + /// assert!(!rect.contains(Point2D::new(2, 1))); // right edge + /// assert!(!rect.contains(Point2D::new(1, 2))); // bottom edge + /// assert!(!rect.contains(Point2D::new(2, 2))); + /// ``` #[inline] pub fn contains(&self, p: Point2D) -> bool { // Use bitwise and instead of && to avoid emitting branches. (self.min.x <= p.x) & (p.x < self.max.x) & (self.min.y <= p.y) & (p.y < self.max.y) } - /// Returns `true` if this box contains the point `p`. A point is considered - /// in the box2d if it lies on any edge of the box2d. + /// Returns `true` if this box contains the point `p`. + /// + /// This is like [`Box2D::contains`], but points on the bottom and right + /// edges are also inside the box. + /// + /// # Examples + /// ``` + /// use euclid::default::{Box2D, Point2D}; + /// + /// let rect = Box2D::new(Point2D::origin(), Point2D::new(2, 2)); + /// + /// assert!(rect.contains_inclusive(Point2D::new(1, 1))); + /// + /// assert!(rect.contains_inclusive(Point2D::new(0, 1))); // left edge + /// assert!(rect.contains_inclusive(Point2D::new(1, 0))); // top edge + /// assert!(rect.contains_inclusive(Point2D::origin())); + /// + /// assert!(rect.contains_inclusive(Point2D::new(2, 1))); // right edge + /// assert!(rect.contains_inclusive(Point2D::new(1, 2))); // bottom edge + /// assert!(rect.contains_inclusive(Point2D::new(2, 2))); + /// ``` #[inline] pub fn contains_inclusive(&self, p: Point2D) -> bool { // Use bitwise and instead of && to avoid emitting branches. @@ -358,7 +398,53 @@ impl Box2D where T: Copy + Zero + PartialOrd, { - /// Returns the smallest box containing all of the provided points. + /// Returns the smallest box enclosing all of the provided points. + /// + /// The top/bottom/left/right-most points are exactly on the box's edges. + /// Since [`Box2D::contains`] excludes points that are on the right-most and + /// bottom-most edges, not all points passed to [`Box2D::from_points`] are + /// contained in the returned [`Box2D`] when probed with [`Box2D::contains`], but + /// are when probed with [`Box2D::contains_inclusive`]. + /// + /// For example: + /// + /// ``` + /// use euclid::default::{Point2D, Box2D}; + /// + /// let a = Point2D::origin(); + /// let b = Point2D::new(1, 2); + /// let rect = Box2D::from_points([a, b]); + /// + /// assert_eq!(rect.width(), 1); + /// assert_eq!(rect.height(), 2); + /// + /// assert!(rect.contains(a)); + /// assert!(!rect.contains(b)); + /// assert!(rect.contains_inclusive(b)); + /// ``` + /// + /// In particular, calling [`Box2D::from_points`] with a single point + /// results in an empty [`Box2D`]: + /// + /// ``` + /// use euclid::default::{Point2D, Box2D}; + /// + /// let a = Point2D::new(1, 0); + /// let rect = Box2D::from_points([a]); + /// + /// assert!(rect.is_empty()); + /// assert!(!rect.contains(a)); + /// assert!(rect.contains_inclusive(a)); + /// ``` + /// + /// The [`Box2D`] enclosing no points is also empty: + /// + /// ``` + /// use euclid::default::{Box2D, Point2D}; + /// + /// let rect = Box2D::from_points(std::iter::empty::>()); + /// assert!(rect.is_empty()); + /// ``` pub fn from_points(points: I) -> Self where I: IntoIterator, diff --git a/src/box3d.rs b/src/box3d.rs index 8117029..eb43556 100644 --- a/src/box3d.rs +++ b/src/box3d.rs @@ -155,9 +155,32 @@ where && self.max.z > other.min.z } - /// Returns `true` if this box3d contains the point `p`. A point is considered - /// in the box3d if it lies on the front, left or top faces, but outside if it lies - /// on the back, right or bottom faces. + /// Returns `true` if this [`Box3D`] contains the point `p`. + /// + /// Points on the front, left, and top faces are inside the box, whereas + /// points on the back, right, and bottom faces are outside the box. + /// See [`Box3D::contains_inclusive`] for a variant that also includes those + /// latter points. + /// + /// # Examples + /// + /// ``` + /// use euclid::default::{Box3D, Point3D}; + /// + /// let cube = Box3D::new(Point3D::origin(), Point3D::new(2, 2, 2)); + /// + /// assert!(cube.contains(Point3D::new(1, 1, 1))); + /// + /// assert!(cube.contains(Point3D::new(0, 1, 1))); // front face + /// assert!(cube.contains(Point3D::new(1, 0, 1))); // left face + /// assert!(cube.contains(Point3D::new(1, 1, 0))); // top face + /// assert!(cube.contains(Point3D::new(0, 0, 0))); + /// + /// assert!(!cube.contains(Point3D::new(2, 1, 1))); // back face + /// assert!(!cube.contains(Point3D::new(1, 2, 1))); // right face + /// assert!(!cube.contains(Point3D::new(1, 1, 2))); // bottom face + /// assert!(!cube.contains(Point3D::new(2, 2, 2))); + /// ``` #[inline] pub fn contains(&self, other: Point3D) -> bool { (self.min.x <= other.x) @@ -168,8 +191,30 @@ where & (other.z < self.max.z) } - /// Returns `true` if this box3d contains the point `p`. A point is considered - /// in the box3d if it lies on any face of the box3d. + /// Returns `true` if this [`Box3D`] contains the point `p`. + /// + /// This is like [`Box3D::contains`], but points on the back, right, + /// and bottom faces are also inside the box. + /// + /// # Examples + /// + /// ``` + /// use euclid::default::{Box3D, Point3D}; + /// + /// let cube = Box3D::new(Point3D::origin(), Point3D::new(2, 2, 2)); + /// + /// assert!(cube.contains_inclusive(Point3D::new(1, 1, 1))); + /// + /// assert!(cube.contains_inclusive(Point3D::new(0, 1, 1))); // front face + /// assert!(cube.contains_inclusive(Point3D::new(1, 0, 1))); // left face + /// assert!(cube.contains_inclusive(Point3D::new(1, 1, 0))); // top face + /// assert!(cube.contains_inclusive(Point3D::new(0, 0, 0))); // front-left-top corner + /// + /// assert!(cube.contains_inclusive(Point3D::new(2, 1, 1))); // back face + /// assert!(cube.contains_inclusive(Point3D::new(1, 2, 1))); // right face + /// assert!(cube.contains_inclusive(Point3D::new(1, 1, 2))); // bottom face + /// assert!(cube.contains_inclusive(Point3D::new(2, 2, 2))); // back-right-bottom corner + /// ``` #[inline] pub fn contains_inclusive(&self, other: Point3D) -> bool { (self.min.x <= other.x) @@ -325,7 +370,54 @@ impl Box3D where T: Copy + Zero + PartialOrd, { - /// Returns the smallest box containing all of the provided points. + /// Returns the smallest box enclosing all of the provided points. + /// + /// The top/bottom/left/right/front/back-most points are exactly on the box's edges. + /// Since [`Box3D::contains`] excludes points that are on the right/bottom/back-most + /// faces, not all points passed to [`Box3D::from_points`] are + /// contained in the returned [`Box3D`] when probed with [`Box3D::contains`], but + /// are when probed with [`Box3D::contains_inclusive`]. + /// + /// For example: + /// + /// ``` + /// use euclid::default::{Point3D, Box3D}; + /// + /// let a = Point3D::origin(); + /// let b = Point3D::new(1, 2, 3); + /// let box3 = Box3D::from_points([a, b]); + /// + /// assert_eq!(box3.width(), 1); + /// assert_eq!(box3.height(), 2); + /// assert_eq!(box3.depth(), 3); + /// + /// assert!(box3.contains(a)); + /// assert!(!box3.contains(b)); + /// assert!(box3.contains_inclusive(b)); + /// ``` + /// + /// In particular, calling [`Box3D::from_points`] with a single point + /// results in an empty [`Box3D`]: + /// + /// ``` + /// use euclid::default::{Point3D, Box3D}; + /// + /// let a = Point3D::new(1, 0, 1); + /// let box3 = Box3D::from_points([a]); + /// + /// assert!(box3.is_empty()); + /// assert!(!box3.contains(a)); + /// assert!(box3.contains_inclusive(a)); + /// ``` + /// + /// The [`Box3D`] enclosing no points is also empty: + /// + /// ``` + /// use euclid::default::{Box3D, Point3D}; + /// + /// let box3 = Box3D::from_points(std::iter::empty::>()); + /// assert!(box3.is_empty()); + /// ``` pub fn from_points(points: I) -> Self where I: IntoIterator, diff --git a/src/rect.rs b/src/rect.rs index 8bdc8f0..1021044 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -328,10 +328,12 @@ where /// /// Note: This function has a behavior that can be surprising because /// the right-most and bottom-most points are exactly on the edge - /// of the rectangle while the `contains` function is has exclusive + /// of the rectangle while the [`Rect::contains`] function is has exclusive /// semantic on these edges. This means that the right-most and bottom-most - /// points provided to `from_points` will count as not contained by the rect. + /// points provided to [`Rect::from_points`] will count as not contained by the rect. /// This behavior may change in the future. + /// + /// See [`Box2D::from_points`] for more details. pub fn from_points(points: I) -> Self where I: IntoIterator,