@@ -7,7 +7,7 @@ use num::{Bounded, Zero};
77impl Aabb {
88 /// Computes the intersection of a segment with this Aabb.
99 ///
10- /// Returns `None` if there is no intersection.
10+ /// Returns `None` if there is no intersection or if `pa` is invalid (contains `NaN`) .
1111 #[ inline]
1212 pub fn clip_segment ( & self , pa : & Point < Real > , pb : & Point < Real > ) -> Option < Segment > {
1313 let ab = pb - pa;
@@ -18,7 +18,7 @@ impl Aabb {
1818 /// Computes the parameters of the two intersection points between a line and this Aabb.
1919 ///
2020 /// The parameters are such that the point are given by `orig + dir * parameter`.
21- /// Returns `None` if there is no intersection.
21+ /// Returns `None` if there is no intersection or if `orig` is invalid (contains `NaN`) .
2222 #[ inline]
2323 pub fn clip_line_parameters (
2424 & self ,
@@ -30,7 +30,7 @@ impl Aabb {
3030
3131 /// Computes the intersection segment between a line and this Aabb.
3232 ///
33- /// Returns `None` if there is no intersection.
33+ /// Returns `None` if there is no intersection or if `orig` is invalid (contains `NaN`) .
3434 #[ inline]
3535 pub fn clip_line ( & self , orig : & Point < Real > , dir : & Vector < Real > ) -> Option < Segment > {
3636 clip_aabb_line ( self , orig, dir)
@@ -40,7 +40,7 @@ impl Aabb {
4040 /// Computes the parameters of the two intersection points between a ray and this Aabb.
4141 ///
4242 /// The parameters are such that the point are given by `ray.orig + ray.dir * parameter`.
43- /// Returns `None` if there is no intersection.
43+ /// Returns `None` if there is no intersection or if `ray.orig` is invalid (contains `NaN`) .
4444 #[ inline]
4545 pub fn clip_ray_parameters ( & self , ray : & Ray ) -> Option < ( Real , Real ) > {
4646 self . clip_line_parameters ( & ray. origin , & ray. dir )
@@ -67,6 +67,15 @@ impl Aabb {
6767}
6868
6969/// Computes the segment given by the intersection of a line and an Aabb.
70+ ///
71+ /// Returns the two intersections represented as `(t, normal, side)` such that:
72+ /// - `origin + dir * t` gives the intersection points.
73+ /// - `normal` is the face normal at the intersection. This is equal to the zero vector if `dir`
74+ /// is invalid (a zero vector or NaN) and `origin` is inside the AABB.
75+ /// - `side` is the side of the AABB that was hit. This is an integer in [-3, 3] where `1` represents
76+ /// the `+X` axis, `2` the `+Y` axis, etc., and negative values represent the corresponding
77+ /// negative axis. The special value of `0` indicates that the provided `dir` is zero or `NaN`
78+ /// and the line origin is inside the AABB.
7079pub fn clip_aabb_line (
7180 aabb : & Aabb ,
7281 origin : & Point < Real > ,
@@ -133,9 +142,12 @@ pub fn clip_aabb_line(
133142 let near = if near_diag {
134143 ( tmin, -dir. normalize ( ) , near_side)
135144 } else {
136- // If near_side is 0, the index calculation would be invalid (-1).
145+ // If near_side is 0, we are in a special case where `dir` is
146+ // zero or NaN. Return `Some` only if the ray starts inside the
147+ // aabb.
137148 if near_side == 0 {
138- return None ;
149+ let zero = ( 0.0 , Vector :: zeros ( ) , 0 ) ;
150+ return aabb. contains_local_point ( origin) . then_some ( ( zero, zero) ) ;
139151 }
140152
141153 let mut normal = Vector :: zeros ( ) ;
@@ -152,9 +164,12 @@ pub fn clip_aabb_line(
152164 let far = if far_diag {
153165 ( tmax, -dir. normalize ( ) , far_side)
154166 } else {
155- // If far_side is 0, the index calculation would be invalid (-1).
167+ // If far_side is 0, we are in a special case where `dir` is
168+ // zero or NaN. Return `Some` only if the ray starts inside the
169+ // aabb.
156170 if far_side == 0 {
157- return None ;
171+ let zero = ( 0.0 , Vector :: zeros ( ) , 0 ) ;
172+ return aabb. contains_local_point ( origin) . then_some ( ( zero, zero) ) ;
158173 }
159174
160175 let mut normal = Vector :: zeros ( ) ;
@@ -181,13 +196,23 @@ mod test {
181196 & Point :: origin( ) ,
182197 & Vector :: zeros( ) ,
183198 )
199+ . is_some( ) ) ;
200+ assert ! ( clip_aabb_line(
201+ & Aabb :: new( Vector :: repeat( 1.0 ) . into( ) , Vector :: repeat( 2.0 ) . into( ) ) ,
202+ & Point :: origin( ) ,
203+ & Vector :: zeros( ) ,
204+ )
184205 . is_none( ) ) ;
185206 }
186207
187208 #[ test]
188209 pub fn clip_empty_aabb_segment ( ) {
189- let aabb_empty = Aabb :: new ( Point :: origin ( ) , Point :: origin ( ) ) ;
190- assert ! ( aabb_empty
210+ let aabb_origin = Aabb :: new ( Point :: origin ( ) , Point :: origin ( ) ) ;
211+ let aabb_shifted = Aabb :: new ( Vector :: repeat ( 1.0 ) . into ( ) , Vector :: repeat ( 2.0 ) . into ( ) ) ;
212+ assert ! ( aabb_origin
213+ . clip_segment( & Point :: origin( ) , & Point :: from( Vector :: repeat( Real :: NAN ) ) )
214+ . is_some( ) ) ;
215+ assert ! ( aabb_shifted
191216 . clip_segment( & Point :: origin( ) , & Point :: from( Vector :: repeat( Real :: NAN ) ) )
192217 . is_none( ) ) ;
193218 }
0 commit comments