Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand docs for Box{2,3}D::{contains,contains_inclusive,from_points} #539

Merged
merged 1 commit into from
Nov 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading