Skip to content

Commit

Permalink
Expand docs for Box{2,3}D::{contains,contains_inclusive,from_points} (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
airwoodix authored Nov 18, 2024
1 parent 1aebabe commit f17b125
Show file tree
Hide file tree
Showing 3 changed files with 194 additions and 14 deletions.
98 changes: 92 additions & 6 deletions src/box2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, U>) -> 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<T, U>) -> bool {
// Use bitwise and instead of && to avoid emitting branches.
Expand Down Expand Up @@ -358,7 +398,53 @@ impl<T, U> Box2D<T, U>
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::<Point2D<i32>>());
/// assert!(rect.is_empty());
/// ```
pub fn from_points<I>(points: I) -> Self
where
I: IntoIterator,
Expand Down
104 changes: 98 additions & 6 deletions src/box3d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, U>) -> bool {
(self.min.x <= other.x)
Expand All @@ -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<T, U>) -> bool {
(self.min.x <= other.x)
Expand Down Expand Up @@ -325,7 +370,54 @@ impl<T, U> Box3D<T, U>
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::<Point3D<i32>>());
/// assert!(box3.is_empty());
/// ```
pub fn from_points<I>(points: I) -> Self
where
I: IntoIterator,
Expand Down
6 changes: 4 additions & 2 deletions src/rect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<I>(points: I) -> Self
where
I: IntoIterator,
Expand Down

0 comments on commit f17b125

Please sign in to comment.