1+ package math ;
2+
3+ /**
4+ * The {@code Bounds} class represents a 3D axis-aligned bounding box (AABB),
5+ * defined by two {@link Vector3f} points: the minimum and maximum corners. This
6+ * class provides various utility methods for manipulating and querying the
7+ * bounding box, such as checking if a point is contained within the bounds,
8+ * expanding the bounds, and testing for intersections with rays or other
9+ * bounds.
10+ *
11+ * <p>
12+ * A bounding box is often used in 3D graphics for collision detection, frustum
13+ * culling, and other spatial queries.
14+ * </p>
15+ */
16+ public class Bounds {
17+
18+ /**
19+ * The minimum corner of the bounding box.
20+ */
21+ private Vector3f min ;
22+
23+ /**
24+ * The maximum corner of the bounding box.
25+ */
26+ private Vector3f max ;
27+
28+ /**
29+ * Constructs a new {@code Bounds} object with the specified minimum and
30+ * maximum corners.
31+ *
32+ * @param min the minimum corner of the bounding box
33+ * @param max the maximum corner of the bounding box
34+ * @throws IllegalArgumentException if either {@code min} or {@code max} is
35+ * {@code null}
36+ */
37+ public Bounds (Vector3f min , Vector3f max ) {
38+ if (min == null ) {
39+ throw new IllegalArgumentException ("Min cannot be null." );
40+ }
41+ if (max == null ) {
42+ throw new IllegalArgumentException ("Max cannot be null." );
43+ }
44+ this .min = new Vector3f (min );
45+ this .max = new Vector3f (max );
46+ }
47+
48+ /**
49+ * Returns the closest point on the bounding box to the given {@code point}.
50+ * The closest point is determined by clamping each coordinate of the point
51+ * between the minimum and maximum bounds of the box.
52+ *
53+ * @param point the point to clamp to the bounding box
54+ * @return a new {@code Vector3f} representing the closest point on the
55+ * bounding box
56+ */
57+ public Vector3f closestPoint (Vector3f point ) {
58+ float x = Math .max (min .x , Math .min (max .x , point .x ));
59+ float y = Math .max (min .y , Math .min (max .y , point .y ));
60+ float z = Math .max (min .z , Math .min (max .z , point .z ));
61+ return new Vector3f (x , y , z );
62+ }
63+
64+ /**
65+ * Checks if the given {@code point} is inside the bounding box. The point is
66+ * considered inside if all of its coordinates are between the minimum and
67+ * maximum coordinates of the box.
68+ *
69+ * @param point the point to check
70+ * @return {@code true} if the point is inside the bounding box, {@code false}
71+ * otherwise
72+ */
73+ public boolean contains (Vector3f point ) {
74+ return point .x >= min .x && point .x <= max .x && point .y >= min .y
75+ && point .y <= max .y && point .z >= min .z && point .z <= max .z ;
76+ }
77+
78+ /**
79+ * Expands the bounding box to encompass the given {@code point}. If the point
80+ * is outside the current bounds, the box will be enlarged to include it.
81+ *
82+ * @param point the point to include in the bounding box
83+ */
84+ public void encapsulate (Vector3f point ) {
85+ min = new Vector3f (Math .min (min .x , point .x ), Math .min (min .y , point .y ),
86+ Math .min (min .z , point .z ));
87+ max = new Vector3f (Math .max (max .x , point .x ), Math .max (max .y , point .y ),
88+ Math .max (max .z , point .z ));
89+ }
90+
91+ /**
92+ * Expands the bounding box by the given {@code amount}. The expansion is done
93+ * uniformly along all axes, increasing the size of the bounding box by the
94+ * specified amount.
95+ *
96+ * @param amount the amount to expand the bounding box by
97+ */
98+ public void expand (float amount ) {
99+ Vector3f expansion = new Vector3f (amount / 2 , amount / 2 , amount / 2 );
100+ min = min .subtract (expansion );
101+ max = max .add (expansion );
102+ }
103+
104+ /**
105+ * Tests if the given {@code ray} intersects the bounding box. The
106+ * intersection is checked using the slab method, which determines if the ray
107+ * intersects the box along each axis.
108+ *
109+ * @param ray the ray to test for intersection
110+ * @return {@code true} if the ray intersects the bounding box, {@code false}
111+ * otherwise
112+ */
113+ public boolean intersectRay (Ray3f ray ) {
114+ Vector3f invDir = ray .getDirection ().reciprocal ();
115+ Vector3f tMin = min .subtract (ray .getOrigin ()).mult (invDir );
116+ Vector3f tMax = max .subtract (ray .getOrigin ()).mult (invDir );
117+
118+ float t1 = Math .min (tMin .x , tMax .x );
119+ float t2 = Math .max (tMin .x , tMax .x );
120+
121+ for (int i = 1 ; i < 3 ; i ++) { // For y and z axes
122+ t1 = Math .max (t1 , Math .min (tMin .get (i ), tMax .get (i )));
123+ t2 = Math .min (t2 , Math .max (tMin .get (i ), tMax .get (i )));
124+ }
125+
126+ return t1 <= t2 && t2 >= 0 ;
127+ }
128+
129+ /**
130+ * Tests if this bounding box intersects another {@code Bounds}. The
131+ * intersection is checked by comparing the min and max coordinates of both
132+ * boxes.
133+ *
134+ * @param other the other bounding box to check for intersection
135+ * @return {@code true} if the bounding boxes intersect, {@code false}
136+ * otherwise
137+ */
138+ public boolean intersects (Bounds other ) {
139+ return min .x <= other .max .x && max .x >= other .min .x && min .y <= other .max .y
140+ && max .y >= other .min .y && min .z <= other .max .z && max .z >= other .min .z ;
141+ }
142+
143+ /**
144+ * Calculates the squared distance from the given {@code point} to the closest
145+ * point on the bounding box. This method avoids calculating the square root
146+ * for performance reasons, returning the squared distance instead.
147+ *
148+ * @param point the point to calculate the squared distance from
149+ * @return the squared distance from the point to the closest point on the
150+ * bounding box
151+ */
152+ public float sqrDistance (Vector3f point ) {
153+ float dx = Math .max (0 , Math .max (min .x - point .x , point .x - max .x ));
154+ float dy = Math .max (0 , Math .max (min .y - point .y , point .y - max .y ));
155+ float dz = Math .max (0 , Math .max (min .z - point .z , point .z - max .z ));
156+ return dx * dx + dy * dy + dz * dz ;
157+ }
158+
159+ /**
160+ * Sets the minimum and maximum corners of the bounding box to the specified
161+ * values.
162+ *
163+ * @param min the new minimum corner
164+ * @param max the new maximum corner
165+ */
166+ public void setMinMax (Vector3f min , Vector3f max ) {
167+ this .min = new Vector3f (min );
168+ this .max = new Vector3f (max );
169+ }
170+
171+ /**
172+ * Returns the minimum corner of the bounding box.
173+ *
174+ * @return the minimum corner of the bounding box
175+ */
176+ public Vector3f getMin () {
177+ return min ;
178+ }
179+
180+ /**
181+ * Returns the maximum corner of the bounding box.
182+ *
183+ * @return the maximum corner of the bounding box
184+ */
185+ public Vector3f getMax () {
186+ return max ;
187+ }
188+
189+ }
0 commit comments