phys_geom/
interval.rs

1// Copyright (C) 2020-2025 phys-geom authors. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! One-dimensional interval arithmetic utilities.
16//!
17//! This module provides functionality for working with one-dimensional intervals
18//! on the real number line. Intervals are fundamental for various geometric
19//! algorithms including:
20//! - Collision detection and response
21//! - Spatial partitioning and culling
22//! - Numerical robustness in geometric computations
23//! - Bounding box projections and intersections
24//!
25//! # Overview
26//!
27//! An interval represents a closed range [min, max] on the real number line.
28//! The interval is inclusive, meaning both endpoints are considered part of
29//! the interval.
30//!
31//! # Examples
32//!
33//! ```rust
34//! use phys_geom::Interval;
35//!
36//! // Create an interval from 0.0 to 1.0
37//! let interval = Interval::new(0.0, 1.0);
38//!
39//! // Check properties
40//! assert_eq!(interval.min(), 0.0);
41//! assert_eq!(interval.max(), 1.0);
42//!
43//! // Check overlap with another interval
44//! let other = Interval::new(0.5, 1.5);
45//! assert!(interval.overlaps(&other));
46//! ```
47//! # Mathematical Properties
48//!
49//! The interval maintains the invariant that `min <= max`. This is enforced
50//! at creation time and all operations preserve this invariant.
51
52use crate::math::Real;
53
54/// A one-dimensional interval on the real number line.
55///
56/// An interval represents a closed range [min, max] where both endpoints
57/// are included. This is a fundamental building block for many geometric
58/// algorithms, particularly in collision detection and spatial queries.
59///
60/// # Mathematical Representation
61///
62/// The interval represents all real numbers x such that: `min <= x <= max`
63///
64/// # Examples
65///
66/// ```rust
67/// use phys_geom::Interval;
68///
69/// // Create an interval representing the range [0.0, 1.0]
70/// let interval = Interval::new(0.0, 1.0);
71///
72/// // Check if a value is within the interval
73/// let contains_0_5 = interval.min() <= 0.5 && 0.5 <= interval.max();
74/// assert!(contains_0_5);
75/// ```
76///
77/// # Common Applications
78///
79/// - **Separating Axis Theorem**: Testing overlap of projected shapes
80/// - **AABB Operations**: Computing intersections along specific axes
81/// - **Numerical Robustness**: Handling floating-point precision issues
82/// - **Spatial Partitioning**: Determining object overlaps in 1D
83///
84/// # Invariants
85///
86/// The struct maintains the invariant that `min <= max`. This is enforced
87/// at construction time and preserved by all operations.
88///
89/// # Memory Layout
90///
91/// The struct contains exactly two `Real` values and is designed to be
92/// efficient for both computation and memory usage.
93#[derive(Debug, PartialEq, Clone, Copy)]
94pub struct Interval {
95    /// The minimum (lower) bound of the interval
96    min: Real,
97    /// The maximum (upper) bound of the interval
98    max: Real,
99}
100
101impl Interval {
102    /// Creates a new interval with the specified bounds.
103    ///
104    /// This function creates a closed interval [min, max] that includes both endpoints.
105    ///
106    /// # Arguments
107    ///
108    /// * `min` - The minimum (lower) bound of the interval
109    /// * `max` - The maximum (upper) bound of the interval
110    ///
111    /// # Returns
112    ///
113    /// A new `Interval` instance representing the range [min, max].
114    ///
115    /// # Panics
116    ///
117    /// Panics if `min > max`, as this would violate the interval invariant.
118    ///
119    /// # Examples
120    ///
121    /// ```rust
122    /// use phys_geom::Interval;
123    ///
124    /// // Create a valid interval
125    /// let interval = Interval::new(0.0, 1.0);
126    /// assert_eq!(interval.min(), 0.0);
127    /// assert_eq!(interval.max(), 1.0);
128    ///
129    /// // This would panic: Interval::new(1.0, 0.0);
130    /// ```
131    ///
132    /// # Edge Cases
133    ///
134    /// - `min == max`: Creates a zero-width interval (single point)
135    /// - `min < max`: Creates a normal interval with positive width
136    #[must_use]
137    #[inline]
138    pub fn new(min: Real, max: Real) -> Self {
139        assert!(min <= max);
140        Self { min, max }
141    }
142
143    /// Returns the minimum (lower) bound of the interval.
144    ///
145    /// # Returns
146    ///
147    /// The minimum value as a `Real`.
148    ///
149    /// # Examples
150    ///
151    /// ```rust
152    /// use phys_geom::Interval;
153    ///
154    /// let interval = Interval::new(0.0, 1.0);
155    /// assert_eq!(interval.min(), 0.0);
156    /// ```
157    #[must_use]
158    #[inline]
159    pub fn min(&self) -> Real {
160        self.min
161    }
162
163    /// Returns the maximum (upper) bound of the interval.
164    ///
165    /// # Returns
166    ///
167    /// The maximum value as a `Real`.
168    ///
169    /// # Examples
170    ///
171    /// ```rust
172    /// use phys_geom::Interval;
173    ///
174    /// let interval = Interval::new(0.0, 1.0);
175    /// assert_eq!(interval.max(), 1.0);
176    /// ```
177    #[must_use]
178    #[inline]
179    pub fn max(&self) -> Real {
180        self.max
181    }
182
183    /// Checks if this interval overlaps with another interval.
184    ///
185    /// Two intervals overlap if they have at least one point in common.
186    /// Since these are closed intervals, the overlap condition is:
187    /// `self.min <= other.max && self.max >= other.min`
188    ///
189    /// # Arguments
190    ///
191    /// * `other` - The other interval to test for overlap
192    ///
193    /// # Returns
194    ///
195    /// `true` if the intervals overlap, `false` otherwise.
196    ///
197    /// # Examples
198    ///
199    /// ```rust
200    /// use phys_geom::Interval;
201    ///
202    /// let a = Interval::new(0.0, 2.0);
203    /// let b = Interval::new(1.0, 3.0);
204    /// let c = Interval::new(2.5, 4.0);
205    ///
206    /// assert!(a.overlaps(&b));  // Overlap in [1.0, 2.0]
207    /// assert!(!a.overlaps(&c)); // No overlap
208    /// assert!(b.overlaps(&c));  // Overlap at point 2.5
209    /// ```
210    ///
211    /// # Edge Cases
212    ///
213    /// - **Touching intervals**: `[0,1]` and `[1,2]` overlap at point 1
214    /// - **Zero-width intervals**: `[1,1]` overlaps with `[0,2]` but not with `[2,3]`
215    /// - **Identical intervals**: Always overlap with themselves
216    ///
217    /// # Mathematical Definition
218    ///
219    /// The overlap condition can be written as:
220    /// `overlap = [max(self.min, other.min), min(self.max, other.max)]` is non-empty
221    ///
222    /// Note: This is a closed interval, meaning that the bounds are included
223    /// in the overlap calculation.
224    #[must_use]
225    #[inline]
226    pub fn overlaps(&self, other: &Self) -> bool {
227        self.min <= other.max && self.max >= other.min
228    }
229}