1 /**************************************************************************\
2  * Copyright (c) Kongsberg Oil & Gas Technologies AS
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  * Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * Neither the name of the copyright holder nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32 
33 /*!
34   \class SbBox3s SbBox3s.h Inventor/SbBox3s.h
35   \brief The SbBox3s class is a 3 dimensional box with short
36   integer coordinates.
37 
38   \ingroup base
39 
40   This box class is used by other classes in Coin for data
41   exchange. It provides storage for two box corners with short integer
42   coordinates.
43 
44   \sa SbBox2s, SbBox2f, SbBox2d, SbBox3f, SbBox3d, SbXfBox3f.
45   \since Coin 2.0
46   \since TGS Inventor ?.?
47 */
48 
49 
50 #include <Inventor/SbBox3s.h>
51 
52 #include <limits>
53 #include <cassert>
54 
55 #include <Inventor/SbBox3i32.h>
56 #include <Inventor/SbBox3f.h>
57 #include <Inventor/SbBox3d.h>
58 #if COIN_DEBUG
59 #include <Inventor/errors/SoDebugError.h>
60 #endif // COIN_DEBUG
61 
62 /*!
63   \fn SbBox3s::SbBox3s(void)
64   The default constructor makes an empty box.
65 */
66 
67 /*!
68   \fn SbBox3s::SbBox3s(short xmin, short ymin, short zmin, short xmax, short ymax, short zmax)
69 
70   Constructs a box with the given corner coordinates.
71 
72   \a xmin should be less than \a xmax, \a ymin should be less than \a
73   ymax, and \a zmin should be less than \a zmax if you want to make a
74   valid box.
75 */
76 
77 /*!
78   \fn SbBox3s::SbBox3s(const SbVec3s & minvec, const SbVec3s & maxvec)
79 
80   Constructs a box with the given corners.
81 
82   The coordinates of \a min should be less than the coordinates of
83   \a max if you want to make a valid box.
84 */
85 
86 /*!
87   \fn SbBox3s & SbBox3s::setBounds(short xmin, short ymin, short zmin, short xmax, short ymax, short zmax)
88 
89   Reset the boundaries of the box.
90 
91   \a xmin should be less than \a xmax, \a ymin should be less than \a
92   ymax, and \a zmin should be less than \a xmax if you want to make a
93   valid box.
94 
95   Returns reference to self.
96 
97   \sa getBounds().
98 */
99 
100 /*!
101   \fn SbBox3s & SbBox3s::setBounds(const SbVec3s & minvec, const SbVec3s & maxvec)
102 
103   Reset the boundaries of the box with the given corners.
104 
105   The coordinates of \a minvec should be less than the coordinates of
106   \a maxvec if you want to make a valid box.
107 
108   Returns reference to self.
109 
110   \sa getBounds().
111 */
112 
113 /*!
114   Reset the boundaries to the boundaries of the given \a box.
115 
116   Returns reference to self.
117 
118   \sa getBounds().
119 */
120 
121 SbBox3s &
setBounds(const SbBox3i32 & box)122 SbBox3s::setBounds(const SbBox3i32 & box)
123 {
124   if (box.isEmpty()) {
125     makeEmpty();
126   } else {
127     minpt.setValue(box.getMin());
128     maxpt.setValue(box.getMax());
129   }
130   return *this;
131 }
132 
133 /*!
134   Reset the boundaries to the boundaries of the given \a box.
135 
136   Returns reference to self.
137 
138   \sa getBounds().
139 */
140 
141 SbBox3s &
setBounds(const SbBox3f & box)142 SbBox3s::setBounds(const SbBox3f & box)
143 {
144   if (box.isEmpty()) {
145     makeEmpty();
146   } else {
147     minpt.setValue(box.getMin());
148     maxpt.setValue(box.getMax());
149   }
150   return *this;
151 }
152 
153 /*!
154   Reset the boundaries to the boundaries of the given \a box.
155 
156   Returns reference to self.
157 
158   \sa getBounds().
159 */
160 
161 SbBox3s &
setBounds(const SbBox3d & box)162 SbBox3s::setBounds(const SbBox3d & box)
163 {
164   if (box.isEmpty()) {
165     makeEmpty();
166   } else {
167     minpt.setValue(box.getMin());
168     maxpt.setValue(box.getMax());
169   }
170   return *this;
171 }
172 
173 /*!
174   Marks this as an empty box.
175 
176   \sa isEmpty().
177 */
178 void
makeEmpty(void)179 SbBox3s::makeEmpty(void)
180 {
181   this->minpt.setValue(std::numeric_limits<short>::max(), std::numeric_limits<short>::max(), std::numeric_limits<short>::max());
182   this->maxpt.setValue(-std::numeric_limits<short>::max(), -std::numeric_limits<short>::max(), -std::numeric_limits<short>::max());
183 }
184 
185 /*!
186   \fn const SbVec3s & SbBox3s::getMin(void) const
187 
188   Returns the minimum point. This should usually be the lower left corner
189   point of the box.
190 
191   \sa getOrigin(), getMax().
192 */
193 
194 /*!
195   \fn const SbVec3s & SbBox3s::getMax(void) const
196 
197   Returns the maximum point. This should usually be the upper right corner
198   point of the box.
199 
200   \sa getMin().
201 */
202 
203 /*!
204   Extend the boundaries of the box by the given point, i.e. make the
205   point fit inside the box if it isn't already within it.
206  */
207 void
extendBy(const SbVec3s & point)208 SbBox3s::extendBy(const SbVec3s & point)
209 {
210   // The explicit casts are done to humour the HPUX aCC compiler,
211   // which will otherwise say ``Template deduction failed to find a
212   // match for the call to 'SbMin'''. mortene.
213   this->minpt.setValue(SbMin(static_cast<short>(point[0]), static_cast<short>(this->minpt[0])),
214                        SbMin(static_cast<short>(point[1]), static_cast<short>(this->minpt[1])),
215                        SbMin(static_cast<short>(point[2]), static_cast<short>(this->minpt[2])));
216   this->maxpt.setValue(SbMax(static_cast<short>(point[0]), static_cast<short>(this->maxpt[0])),
217                        SbMax(static_cast<short>(point[1]), static_cast<short>(this->maxpt[1])),
218                        SbMax(static_cast<short>(point[2]), static_cast<short>(this->maxpt[2])));
219 }
220 
221 /*!
222   Extend the boundaries of the box by the given \a box parameter. This
223   is equal to calling extendBy() twice with the corner points.
224  */
225 void
extendBy(const SbBox3s & box)226 SbBox3s::extendBy(const SbBox3s & box)
227 {
228   if (box.isEmpty()) { return; }
229 
230   this->extendBy(box.getMin());
231   this->extendBy(box.getMax());
232 }
233 
234 /*!
235   Check if the given point lies within the boundaries of this box.
236  */
237 SbBool
intersect(const SbVec3s & point) const238 SbBox3s::intersect(const SbVec3s & point) const
239 {
240   if((point[0] >= this->minpt[0]) && (point[0] <= this->maxpt[0]) &&
241      (point[1] >= this->minpt[1]) && (point[1] <= this->maxpt[1]) &&
242      (point[2] >= this->minpt[2]) && (point[2] <= this->maxpt[2])) return TRUE;
243   return FALSE;
244 }
245 
246 /*!
247   Check if \a box lies wholly or partly within the boundaries
248   of this box.
249  */
250 SbBool
intersect(const SbBox3s & box) const251 SbBox3s::intersect(const SbBox3s & box) const
252 {
253   if((box.getMax()[0] < this->getMin()[0]) ||
254      (box.getMax()[1] < this->getMin()[1]) ||
255      (box.getMax()[2] < this->getMin()[2]) ||
256      (box.getMin()[0] > this->getMax()[0]) ||
257      (box.getMin()[1] > this->getMax()[1]) ||
258      (box.getMin()[2] > this->getMax()[2])) return FALSE;
259   return TRUE;
260 }
261 
262 /*!
263 */
264 
265 SbVec3f
getClosestPoint(const SbVec3f & pt) const266 SbBox3s::getClosestPoint(const SbVec3f & pt) const
267 {
268   SbVec3f closest = pt;
269 
270   SbVec3f center = this->getCenter();
271   float devx = closest[0] - center[0];
272   float devy = closest[1] - center[1];
273   float devz = closest[2] - center[2];
274   float halfwidth = float(this->maxpt[0] - this->minpt[0]) / 2.0f;
275   float halfheight = float(this->maxpt[1] - this->minpt[1]) / 2.0f;
276   float halfdepth = float(this->maxpt[2] - this->minpt[2]) / 2.0f;
277 
278   // Move point to be on the nearest plane of the box.
279   if ((fabs(devx) > fabs(devy)) && (fabs(devx) > fabs(devz)))
280     closest[0] = center[0] + halfwidth * ((devx < 0.0f) ? -1.0f : 1.0f);
281   else if (fabs(devy) > fabs(devz))
282     closest[1] = center[1] + halfheight * ((devy < 0.0f) ? -1.0f : 1.0f);
283   else
284     closest[2] = center[2] + halfdepth * ((devz < 0.0f) ? -1.0f : 1.0f);
285 
286   // Clamp to be inside box.
287   closest[0] = SbMin(SbMax(closest[0], float(minpt[0])), float(maxpt[0]));
288   closest[1] = SbMin(SbMax(closest[1], float(minpt[1])), float(maxpt[1]));
289   closest[2] = SbMin(SbMax(closest[2], float(minpt[2])), float(maxpt[2]));
290 
291   return closest;
292 }
293 
294 /*!
295   \fn void SbBox3s::getBounds(short & xmin, short & ymin, short & zmin, short & xmax, short & ymax, short & zmax) const
296 
297   Returns the box boundary coordinates.
298 
299   \sa setBounds(), getMin(), getMax().
300 */
301 
302 /*!
303   \fn void SbBox3s::getBounds(SbVec3s & minvec, SbVec3s & maxvec) const
304 
305   Returns the box corner points.
306 
307   \sa setBounds(), getMin(), getMax().
308 */
309 
310 /*!
311   \fn void SbBox3s::getOrigin(short & originX, short & originY, short & originZ) const
312 
313   Returns the coordinates of the box origin (i.e. the lower left corner).
314 
315   \sa getMin().
316 */
317 
318 /*!
319   \fn void SbBox3s::getSize(short & sizeX, short & sizeY, short & sizeZ) const
320 
321   Returns width and height of box.
322 */
323 
324 /*!
325   \fn int operator == (const SbBox3s & b1, const SbBox3s & b2)
326   \relates SbBox3s
327 
328   Check \a b1 and \a b2 for equality.
329 */
330 
331 /*!
332   \fn int operator != (const SbBox3s & b1, const SbBox3s & b2)
333   \relates SbBox3s
334 
335   Check \a b1 and \a b2 for inequality.
336 */
337 
338 /*!
339   \fn SbBool SbBox3s::hasVolume(void) const
340 */
341 
342 #ifdef COIN_TEST_SUITE
BOOST_AUTO_TEST_CASE(checkSize)343 BOOST_AUTO_TEST_CASE(checkSize) {
344   SbVec3s min(1,2,3);
345   SbVec3s max(3,4,5);
346 
347   SbVec3s diff = max - min;
348 
349 
350   SbBox3s box(min, max);
351 
352   BOOST_CHECK_MESSAGE(box.getSize() == diff,
353                       "Box has incorrect size");
354 
355 }
356 #endif //COIN_TEST_SUITE
357