[4] | 1 | /************************************************************** ggt-head beg |
---|
| 2 | * |
---|
| 3 | * GGT: Generic Graphics Toolkit |
---|
| 4 | * |
---|
| 5 | * Original Authors: |
---|
| 6 | * Allen Bierbaum |
---|
| 7 | * |
---|
| 8 | * ----------------------------------------------------------------- |
---|
| 9 | * File: Containment.h,v |
---|
| 10 | * Date modified: 2005/05/16 14:19:44 |
---|
| 11 | * Version: 1.17 |
---|
| 12 | * ----------------------------------------------------------------- |
---|
| 13 | * |
---|
| 14 | *********************************************************** ggt-head end */ |
---|
| 15 | /*************************************************************** ggt-cpr beg |
---|
| 16 | * |
---|
| 17 | * GGT: The Generic Graphics Toolkit |
---|
| 18 | * Copyright (C) 2001,2002 Allen Bierbaum |
---|
| 19 | * |
---|
| 20 | * This library is free software; you can redistribute it and/or |
---|
| 21 | * modify it under the terms of the GNU Lesser General Public |
---|
| 22 | * License as published by the Free Software Foundation; either |
---|
| 23 | * version 2.1 of the License, or (at your option) any later version. |
---|
| 24 | * |
---|
| 25 | * This library is distributed in the hope that it will be useful, |
---|
| 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
| 28 | * Lesser General Public License for more details. |
---|
| 29 | * |
---|
| 30 | * You should have received a copy of the GNU Lesser General Public |
---|
| 31 | * License along with this library; if not, write to the Free Software |
---|
| 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
| 33 | * |
---|
| 34 | ************************************************************ ggt-cpr end */ |
---|
| 35 | #ifndef _GMTL_CONTAINMENT_H_ |
---|
| 36 | #define _GMTL_CONTAINMENT_H_ |
---|
| 37 | |
---|
| 38 | // new stuff |
---|
| 39 | #include <vector> |
---|
| 40 | #include <gmtl/Sphere.h> |
---|
| 41 | #include <gmtl/AABox.h> |
---|
| 42 | #include <gmtl/VecOps.h> |
---|
| 43 | |
---|
| 44 | // old stuff |
---|
| 45 | //#include <gmtl/OOBox.h> |
---|
| 46 | //#include <gmtl/AABox.h> |
---|
| 47 | //#include <gmtl/Fit/GaussPointsFit.h> |
---|
| 48 | //#include <gmtl/matVecFuncs.h> |
---|
| 49 | //#include <gmtl/Quat.h> |
---|
| 50 | |
---|
| 51 | namespace gmtl |
---|
| 52 | { |
---|
| 53 | |
---|
| 54 | //----------------------------------------------------------------------------- |
---|
| 55 | // Sphere |
---|
| 56 | //----------------------------------------------------------------------------- |
---|
| 57 | |
---|
| 58 | /** |
---|
| 59 | * Tests if the given point is inside or on the surface of the given spherical |
---|
| 60 | * volume. |
---|
| 61 | * |
---|
| 62 | * @param container the sphere to test against |
---|
| 63 | * @param pt the point to test with |
---|
| 64 | * |
---|
| 65 | * @return true if pt is inside container, false otherwise |
---|
| 66 | */ |
---|
| 67 | template< class DATA_TYPE > |
---|
| 68 | bool isInVolume( const Sphere<DATA_TYPE>& container, |
---|
| 69 | const Point<DATA_TYPE, 3>& pt ) |
---|
| 70 | { |
---|
| 71 | // The point is inside the sphere if the vector computed from the center of |
---|
| 72 | // the sphere to the point has a magnitude less than or equal to the radius |
---|
| 73 | // of the sphere. |
---|
| 74 | // |pt - center| <= radius |
---|
| 75 | return ( length(gmtl::Vec<DATA_TYPE,3>(pt - container.mCenter)) <= container.mRadius ); |
---|
| 76 | } |
---|
| 77 | |
---|
| 78 | /** |
---|
| 79 | * Tests if the given sphere is completely inside or on the surface of the given |
---|
| 80 | * spherical volume. |
---|
| 81 | * |
---|
| 82 | * @param container the sphere acting as the container |
---|
| 83 | * @param sphere the sphere that may be inside container |
---|
| 84 | * |
---|
| 85 | * @return true if sphere is inside container, false otherwise |
---|
| 86 | */ |
---|
| 87 | template< class DATA_TYPE > |
---|
| 88 | bool isInVolume( const Sphere<DATA_TYPE>& container, |
---|
| 89 | const Sphere<DATA_TYPE>& sphere ) |
---|
| 90 | { |
---|
| 91 | // the sphere is inside container if the distance between the centers of the |
---|
| 92 | // spheres plus the radius of the inner sphere is less than or equal to the |
---|
| 93 | // radius of the containing sphere. |
---|
| 94 | // |sphere.center - container.center| + sphere.radius <= container.radius |
---|
| 95 | return ( length(gmtl::Vec<DATA_TYPE,3>(sphere.mCenter - container.mCenter)) + sphere.mRadius |
---|
| 96 | <= container.mRadius ); |
---|
| 97 | } |
---|
| 98 | |
---|
| 99 | /** |
---|
| 100 | * Modifies the existing sphere to tightly enclose itself and the given point. |
---|
| 101 | * |
---|
| 102 | * @param container [in,out] the sphere that will be extended |
---|
| 103 | * @param pt [in] the point which the sphere should contain |
---|
| 104 | */ |
---|
| 105 | template< class DATA_TYPE > |
---|
| 106 | void extendVolume( Sphere<DATA_TYPE>& container, |
---|
| 107 | const Point<DATA_TYPE, 3>& pt ) |
---|
| 108 | { |
---|
| 109 | // check if we already contain the point |
---|
| 110 | if ( isInVolume( container, pt ) ) |
---|
| 111 | { |
---|
| 112 | return; |
---|
| 113 | } |
---|
| 114 | |
---|
| 115 | // make a vector pointing from the center of the sphere to pt. this is the |
---|
| 116 | // direction in which we need to move the sphere's center |
---|
| 117 | Vec<DATA_TYPE, 3> dir = pt - container.mCenter; |
---|
| 118 | DATA_TYPE len = normalize( dir ); |
---|
| 119 | |
---|
| 120 | // compute what the new radius should be |
---|
| 121 | DATA_TYPE newRadius = (len + container.mRadius) * DATA_TYPE(0.5); |
---|
| 122 | |
---|
| 123 | // compute the new center for the sphere |
---|
| 124 | Point<DATA_TYPE, 3> newCenter = container.mCenter + |
---|
| 125 | (dir * (newRadius - container.mRadius)); |
---|
| 126 | |
---|
| 127 | // modify container to its new values |
---|
| 128 | container.mCenter = newCenter; |
---|
| 129 | container.mRadius = newRadius; |
---|
| 130 | } |
---|
| 131 | |
---|
| 132 | /** |
---|
| 133 | * Modifies the container to tightly enclose itself and the given sphere. |
---|
| 134 | * |
---|
| 135 | * @param container [in,out] the sphere that will be extended |
---|
| 136 | * @param sphere [in] the sphere which container should contain |
---|
| 137 | */ |
---|
| 138 | template< class DATA_TYPE > |
---|
| 139 | void extendVolume( Sphere<DATA_TYPE>& container, |
---|
| 140 | const Sphere<DATA_TYPE>& sphere ) |
---|
| 141 | { |
---|
| 142 | // check if we already contain the sphere |
---|
| 143 | if ( isInVolume( container, sphere ) ) |
---|
| 144 | { |
---|
| 145 | return; |
---|
| 146 | } |
---|
| 147 | |
---|
| 148 | // make a vector pointing from the center of container to sphere. this is the |
---|
| 149 | // direction in which we need to move container's center |
---|
| 150 | Vec<DATA_TYPE, 3> dir = sphere.mCenter - container.mCenter; |
---|
| 151 | DATA_TYPE len = normalize( dir ); |
---|
| 152 | |
---|
| 153 | // compute what the new radius should be |
---|
| 154 | DATA_TYPE newRadius = (len + sphere.mRadius + container.mRadius) * |
---|
| 155 | DATA_TYPE(0.5); |
---|
| 156 | |
---|
| 157 | // compute the new center for container |
---|
| 158 | Point<DATA_TYPE, 3> newCenter = container.mCenter + |
---|
| 159 | (dir * (newRadius - container.mRadius)); |
---|
| 160 | |
---|
| 161 | // modify container to its new values |
---|
| 162 | container.mCenter = newCenter; |
---|
| 163 | container.mRadius = newRadius; |
---|
| 164 | } |
---|
| 165 | |
---|
| 166 | /** |
---|
| 167 | * Modifies the given sphere to tightly enclose all points in the given |
---|
| 168 | * std::vector. This operation is O(n) and uses sqrt(..) liberally. :( |
---|
| 169 | * |
---|
| 170 | * @param container [out] the sphere that will be modified to tightly |
---|
| 171 | * enclose all the points in pts |
---|
| 172 | * @param pts [in] the list of points to contain |
---|
| 173 | * |
---|
| 174 | * @pre pts must contain at least 2 points |
---|
| 175 | */ |
---|
| 176 | template< class DATA_TYPE > |
---|
| 177 | void makeVolume( Sphere<DATA_TYPE>& container, |
---|
| 178 | const std::vector< Point<DATA_TYPE, 3> >& pts ) |
---|
| 179 | { |
---|
| 180 | gmtlASSERT( pts.size() > 0 && "pts must contain at least 1 point" ); |
---|
| 181 | |
---|
| 182 | // Implementation based on the Sphere Centered at Average of Points algorithm |
---|
| 183 | // found in "3D Game Engine Design" by Devud G, Eberly (pg. 27) |
---|
| 184 | typename std::vector< Point<DATA_TYPE, 3> >::const_iterator itr = pts.begin(); |
---|
| 185 | |
---|
| 186 | // compute the average of the points as the center |
---|
| 187 | Point<DATA_TYPE, 3> sum = *itr; |
---|
| 188 | ++itr; |
---|
| 189 | while ( itr != pts.end() ) |
---|
| 190 | { |
---|
| 191 | sum += *itr; |
---|
| 192 | ++itr; |
---|
| 193 | } |
---|
| 194 | container.mCenter = sum / DATA_TYPE(pts.size()); |
---|
| 195 | |
---|
| 196 | // compute the distance from the computed center to point furthest from that |
---|
| 197 | // center as the radius |
---|
| 198 | DATA_TYPE radiusSqr(0); |
---|
| 199 | for ( itr = pts.begin(); itr != pts.end(); ++itr ) |
---|
| 200 | { |
---|
| 201 | DATA_TYPE len = lengthSquared( gmtl::Vec<DATA_TYPE,3>( (*itr) - container.mCenter) ); |
---|
| 202 | if ( len > radiusSqr ) |
---|
| 203 | radiusSqr = len; |
---|
| 204 | } |
---|
| 205 | |
---|
| 206 | container.mRadius = Math::sqrt( radiusSqr ); |
---|
| 207 | } |
---|
| 208 | |
---|
| 209 | /* |
---|
| 210 | template< class DATA_TYPE > |
---|
| 211 | void makeVolume( Sphere<DATA_TYPE>& container, |
---|
| 212 | const std::vector< Point<DATA_TYPE, 3> >& pts ) |
---|
| 213 | { |
---|
| 214 | gmtlASSERT( pts.size() > 1 && "pts must contain at least 2 points" ); |
---|
| 215 | |
---|
| 216 | // make a sphere around the first 2 points and then extend the sphere by each |
---|
| 217 | // point thereafter. we could probably be smarter about this ... |
---|
| 218 | std::vector< Point<DATA_TYPE, 3> >::const_iterator itr = pts.begin(); |
---|
| 219 | |
---|
| 220 | // make the initial sphere |
---|
| 221 | const Point<DATA_TYPE, 3>& first = *itr; |
---|
| 222 | ++itr; |
---|
| 223 | const Point<DATA_TYPE, 3>& second = *itr; |
---|
| 224 | ++itr; |
---|
| 225 | const Vec<DATA_TYPE, 3> dir = second - first; |
---|
| 226 | container.mRadius = length(dir) * DATA_TYPE(0.5); |
---|
| 227 | container.mCenter = first + (dir * container.mRadius); |
---|
| 228 | |
---|
| 229 | // iterate through the remaining points and extend the container to fit each |
---|
| 230 | // point. yay code reuse! |
---|
| 231 | while ( itr != pts.end() ) |
---|
| 232 | { |
---|
| 233 | extendVolume( container, *itr ); |
---|
| 234 | ++itr; |
---|
| 235 | } |
---|
| 236 | } |
---|
| 237 | */ |
---|
| 238 | /** |
---|
| 239 | * Modifies the given sphere to tightly enclose all spheres in the given |
---|
| 240 | * std::vector. This operation is O(n) and uses sqrt(..) liberally. :( |
---|
| 241 | * |
---|
| 242 | * @param container [out] the sphere that will be modified to tightly |
---|
| 243 | * enclose all the spheres in spheres |
---|
| 244 | * @param spheres [in] the list of spheres to contain |
---|
| 245 | * |
---|
| 246 | * @pre spheres must contain at least 2 points |
---|
| 247 | */ |
---|
| 248 | /* |
---|
| 249 | template< class DATA_TYPE > |
---|
| 250 | void makeVolume( Sphere<DATA_TYPE>& container, |
---|
| 251 | const std::vector< Sphere<DATA_TYPE> >& spheres ) |
---|
| 252 | { |
---|
| 253 | gmtlASSERT( spheres.size() > 1 && "spheres must contain at least 2 points" ); |
---|
| 254 | |
---|
| 255 | // make a sphere around the first 2 points and then extend the sphere by each |
---|
| 256 | // point thereafter. we could probably be smarter about this ... |
---|
| 257 | std::vector< Sphere<DATA_TYPE> >::const_iterator itr = spheres.begin(); |
---|
| 258 | |
---|
| 259 | // make the initial sphere |
---|
| 260 | const Sphere<DATA_TYPE>& first = *itr; |
---|
| 261 | ++itr; |
---|
| 262 | const Sphere<DATA_TYPE>& second = *itr; |
---|
| 263 | ++itr; |
---|
| 264 | const Vec<DATA_TYPE, 3> dir = second.mCenter - first.mCenter; |
---|
| 265 | container.mRadius = (length(dir) + first.mRadius + second.mRadius) * |
---|
| 266 | DATA_TYPE(0.5); |
---|
| 267 | container.mCenter = first.mCenter + |
---|
| 268 | (dir * (container.mRadius - first.mRadius)); |
---|
| 269 | |
---|
| 270 | // iterate through the remaining points and extend the container to fit each |
---|
| 271 | // point. yay code reuse! |
---|
| 272 | while ( itr != spheres.end() ) |
---|
| 273 | { |
---|
| 274 | extendVolume( container, *itr ); |
---|
| 275 | ++itr; |
---|
| 276 | } |
---|
| 277 | } |
---|
| 278 | */ |
---|
| 279 | /** |
---|
| 280 | * Tests if the given point is on the surface of the container with zero |
---|
| 281 | * tolerance. |
---|
| 282 | * |
---|
| 283 | * @param container the container to test against |
---|
| 284 | * @param pt the test point |
---|
| 285 | * |
---|
| 286 | * @return true if pt is on the surface of container, false otherwise |
---|
| 287 | */ |
---|
| 288 | template< class DATA_TYPE > |
---|
| 289 | bool isOnVolume( const Sphere<DATA_TYPE>& container, |
---|
| 290 | const Point<DATA_TYPE, 3>& pt ) |
---|
| 291 | { |
---|
| 292 | // |center - pt| - radius == 0 |
---|
| 293 | return ( length(gmtl::Vec<DATA_TYPE,3>(container.mCenter - pt)) - container.mRadius == 0 ); |
---|
| 294 | } |
---|
| 295 | |
---|
| 296 | /** |
---|
| 297 | * Tests of the given point is on the surface of the container with the given |
---|
| 298 | * tolerance. |
---|
| 299 | * |
---|
| 300 | * @param container the container to test against |
---|
| 301 | * @param pt the test point |
---|
| 302 | * @param tol the epsilon tolerance |
---|
| 303 | * |
---|
| 304 | * @return true if pt is on the surface of container, false otherwise |
---|
| 305 | */ |
---|
| 306 | template< class DATA_TYPE > |
---|
| 307 | bool isOnVolume( const Sphere<DATA_TYPE>& container, |
---|
| 308 | const Point<DATA_TYPE, 3>& pt, |
---|
| 309 | const DATA_TYPE& tol ) |
---|
| 310 | { |
---|
| 311 | gmtlASSERT( tol >= 0 && "tolerance must be positive" ); |
---|
| 312 | |
---|
| 313 | // abs( |center-pt| - radius ) < tol |
---|
| 314 | return ( Math::abs( length( gmtl::Vec<DATA_TYPE,3>(container.mCenter - pt)) - container.mRadius ) |
---|
| 315 | <= tol ); |
---|
| 316 | } |
---|
| 317 | |
---|
| 318 | //----------------------------------------------------------------------------- |
---|
| 319 | // AABox |
---|
| 320 | //----------------------------------------------------------------------------- |
---|
| 321 | |
---|
| 322 | /** |
---|
| 323 | * Tests if the given point is inside (or on) the surface of the given AABox |
---|
| 324 | * volume. |
---|
| 325 | * |
---|
| 326 | * @param container the AABox to test against |
---|
| 327 | * @param pt the point to test with |
---|
| 328 | * |
---|
| 329 | * @return true if pt is inside container, false otherwise |
---|
| 330 | */ |
---|
| 331 | template< class DATA_TYPE> |
---|
| 332 | bool isInVolume(const AABox<DATA_TYPE>& container, |
---|
| 333 | const Point<DATA_TYPE, 3>& pt) |
---|
| 334 | { |
---|
| 335 | if (! container.isEmpty()) |
---|
| 336 | { |
---|
| 337 | return ( pt[0] >= container.mMin[0] && |
---|
| 338 | pt[1] >= container.mMin[1] && |
---|
| 339 | pt[2] >= container.mMin[2] && |
---|
| 340 | pt[0] <= container.mMax[0] && |
---|
| 341 | pt[1] <= container.mMax[1] && |
---|
| 342 | pt[2] <= container.mMax[2]); |
---|
| 343 | } |
---|
| 344 | else |
---|
| 345 | { |
---|
| 346 | return false; |
---|
| 347 | } |
---|
| 348 | } |
---|
| 349 | |
---|
| 350 | /** |
---|
| 351 | * Tests if the given point is inside (not on) the surface of the given AABox |
---|
| 352 | * volume. This method is "exclusive" because it does not consider the surface |
---|
| 353 | * to be a part of the space. |
---|
| 354 | * |
---|
| 355 | * @param container the AABox to test against |
---|
| 356 | * @param pt the point to test with |
---|
| 357 | * |
---|
| 358 | * @return true if pt is inside container (but not on surface), false otherwise |
---|
| 359 | */ |
---|
| 360 | template< class DATA_TYPE> |
---|
| 361 | bool isInVolumeExclusive(const AABox<DATA_TYPE>& container, |
---|
| 362 | const Point<DATA_TYPE, 3>& pt) |
---|
| 363 | { |
---|
| 364 | if (! container.isEmpty()) |
---|
| 365 | { |
---|
| 366 | return ( pt[0] > container.mMin[0] && |
---|
| 367 | pt[1] > container.mMin[1] && |
---|
| 368 | pt[2] > container.mMin[2] && |
---|
| 369 | pt[0] < container.mMax[0] && |
---|
| 370 | pt[1] < container.mMax[1] && |
---|
| 371 | pt[2] < container.mMax[2]); |
---|
| 372 | } |
---|
| 373 | else |
---|
| 374 | { |
---|
| 375 | return false; |
---|
| 376 | } |
---|
| 377 | } |
---|
| 378 | |
---|
| 379 | |
---|
| 380 | |
---|
| 381 | |
---|
| 382 | /** |
---|
| 383 | * Tests if the given AABox is completely inside or on the surface of the given |
---|
| 384 | * AABox container. |
---|
| 385 | * |
---|
| 386 | * @param container the AABox acting as the container |
---|
| 387 | * @param box the AABox that may be inside container |
---|
| 388 | * |
---|
| 389 | * @return true if AABox is inside container, false otherwise |
---|
| 390 | */ |
---|
| 391 | template< class DATA_TYPE > |
---|
| 392 | bool isInVolume(const AABox<DATA_TYPE>& container, |
---|
| 393 | const AABox<DATA_TYPE>& box) |
---|
| 394 | { |
---|
| 395 | // Empty boxes don't overlap |
---|
| 396 | if (container.isEmpty() || box.isEmpty()) |
---|
| 397 | { |
---|
| 398 | return false; |
---|
| 399 | } |
---|
| 400 | |
---|
| 401 | // Test that the boxes are not overlapping on any axis |
---|
| 402 | if (container.mMax[0] < box.mMin[0] || container.mMin[0] > box.mMax[0] || |
---|
| 403 | container.mMax[1] < box.mMin[1] || container.mMin[1] > box.mMax[1] || |
---|
| 404 | container.mMax[2] < box.mMin[2] || container.mMin[2] > box.mMax[2]) |
---|
| 405 | { |
---|
| 406 | return false; |
---|
| 407 | } |
---|
| 408 | else |
---|
| 409 | { |
---|
| 410 | return true; |
---|
| 411 | } |
---|
| 412 | } |
---|
| 413 | |
---|
| 414 | /** |
---|
| 415 | * Modifies the existing AABox to tightly enclose itself and the given point. |
---|
| 416 | * |
---|
| 417 | * @param container [in,out] the AABox that will be extended |
---|
| 418 | * @param pt [in] the point which the AABox should contain |
---|
| 419 | */ |
---|
| 420 | template< class DATA_TYPE > |
---|
| 421 | void extendVolume(AABox<DATA_TYPE>& container, |
---|
| 422 | const Point<DATA_TYPE, 3>& pt) |
---|
| 423 | { |
---|
| 424 | if (! container.isEmpty()) |
---|
| 425 | { |
---|
| 426 | // X coord |
---|
| 427 | if (pt[0] > container.mMax[0]) |
---|
| 428 | { |
---|
| 429 | container.mMax[0] = pt[0]; |
---|
| 430 | } |
---|
| 431 | else if (pt[0] < container.mMin[0]) |
---|
| 432 | { |
---|
| 433 | container.mMin[0] = pt[0]; |
---|
| 434 | } |
---|
| 435 | |
---|
| 436 | // Y coord |
---|
| 437 | if (pt[1] > container.mMax[1]) |
---|
| 438 | { |
---|
| 439 | container.mMax[1] = pt[1]; |
---|
| 440 | } |
---|
| 441 | else if (pt[1] < container.mMin[1]) |
---|
| 442 | { |
---|
| 443 | container.mMin[1] = pt[1]; |
---|
| 444 | } |
---|
| 445 | |
---|
| 446 | // Z coord |
---|
| 447 | if (pt[2] > container.mMax[2]) |
---|
| 448 | { |
---|
| 449 | container.mMax[2] = pt[2]; |
---|
| 450 | } |
---|
| 451 | else if (pt[2] < container.mMin[2]) |
---|
| 452 | { |
---|
| 453 | container.mMin[2] = pt[2]; |
---|
| 454 | } |
---|
| 455 | } |
---|
| 456 | else |
---|
| 457 | { |
---|
| 458 | // Make a box with essentially zero volume at the point |
---|
| 459 | container.setMin(pt); |
---|
| 460 | container.setMax(pt); |
---|
| 461 | container.setEmpty(false); |
---|
| 462 | } |
---|
| 463 | } |
---|
| 464 | |
---|
| 465 | /** |
---|
| 466 | * Modifies the container to tightly enclose itself and the given AABox. |
---|
| 467 | * |
---|
| 468 | * @param container [in,out] the AABox that will be extended |
---|
| 469 | * @param box [in] the AABox which container should contain |
---|
| 470 | */ |
---|
| 471 | template< class DATA_TYPE > |
---|
| 472 | void extendVolume(AABox<DATA_TYPE>& container, |
---|
| 473 | const AABox<DATA_TYPE>& box) |
---|
| 474 | { |
---|
| 475 | // Can't extend by an empty box |
---|
| 476 | if (box.isEmpty()) |
---|
| 477 | { |
---|
| 478 | return; |
---|
| 479 | } |
---|
| 480 | |
---|
| 481 | // An empty container is extended to be the box |
---|
| 482 | if (container.isEmpty()) |
---|
| 483 | { |
---|
| 484 | container = box; |
---|
| 485 | } |
---|
| 486 | |
---|
| 487 | // Just extend by the corners of the box |
---|
| 488 | extendVolume(container, box.getMin()); |
---|
| 489 | extendVolume(container, box.getMax()); |
---|
| 490 | } |
---|
| 491 | |
---|
| 492 | /** |
---|
| 493 | * Creates an AABox that tightly encloses the given Sphere. |
---|
| 494 | * |
---|
| 495 | * @param box set to the box |
---|
| 496 | */ |
---|
| 497 | template< class DATA_TYPE > |
---|
| 498 | void makeVolume(AABox<DATA_TYPE>& box, const Sphere<DATA_TYPE>& sph) |
---|
| 499 | { |
---|
| 500 | const gmtl::Point<DATA_TYPE, 3>& center = sph.getCenter(); |
---|
| 501 | const DATA_TYPE& radius = sph.getRadius(); |
---|
| 502 | |
---|
| 503 | // Calculate the min and max points for the box |
---|
| 504 | gmtl::Point<DATA_TYPE, 3> min_pt(center[0] - radius, |
---|
| 505 | center[1] - radius, |
---|
| 506 | center[2] - radius); |
---|
| 507 | gmtl::Point<DATA_TYPE, 3> max_pt(center[0] + radius, |
---|
| 508 | center[1] + radius, |
---|
| 509 | center[2] + radius); |
---|
| 510 | |
---|
| 511 | box.setMin(min_pt); |
---|
| 512 | box.setMax(max_pt); |
---|
| 513 | box.setEmpty(radius == DATA_TYPE(0)); |
---|
| 514 | } |
---|
| 515 | |
---|
| 516 | /* |
---|
| 517 | //------------------------------------------------------------------------------ |
---|
| 518 | // Begin old GMTL code |
---|
| 519 | //------------------------------------------------------------------------------ |
---|
| 520 | inline void computeContainment( AABox& box, const std::vector<gmtl::Point3>& points, |
---|
| 521 | Point3& minPt, Point3& maxPt ) |
---|
| 522 | //void MgcContAlignedBox (int iQuantity, const MgcVector3* akPoint, |
---|
| 523 | // MgcVector3& rkMin, MgcVector3& rkMax) |
---|
| 524 | { |
---|
| 525 | if (points.empty()) |
---|
| 526 | return; |
---|
| 527 | |
---|
| 528 | minPt = points[0]; |
---|
| 529 | maxPt = minPt; |
---|
| 530 | |
---|
| 531 | for (unsigned i = 1; i < points.size(); i++) |
---|
| 532 | { |
---|
| 533 | if ( points[i][Xelt] < minPt[Xelt] ) |
---|
| 534 | minPt[Xelt] = points[i][Xelt]; |
---|
| 535 | else if ( points[i][Xelt] > maxPt[Xelt] ) |
---|
| 536 | maxPt[Xelt] = points[i][Xelt]; |
---|
| 537 | |
---|
| 538 | if ( points[i][Yelt] < minPt[Yelt] ) |
---|
| 539 | minPt[Yelt] = points[i][Yelt]; |
---|
| 540 | else if ( points[i][Yelt] > maxPt[Yelt] ) |
---|
| 541 | maxPt[Yelt] = points[i][Yelt]; |
---|
| 542 | |
---|
| 543 | if ( points[i][Zelt] < minPt[Zelt] ) |
---|
| 544 | minPt[Zelt] = points[i][Zelt]; |
---|
| 545 | else if ( points[i][Zelt] > maxPt[Zelt] ) |
---|
| 546 | maxPt[Zelt] = points[i][Zelt]; |
---|
| 547 | } |
---|
| 548 | |
---|
| 549 | // Now update the box |
---|
| 550 | box.makeEmpty(); |
---|
| 551 | box.mMax = maxPt; |
---|
| 552 | box.mMin = minPt; |
---|
| 553 | } |
---|
| 554 | //---------------------------------------------------------------------------- |
---|
| 555 | //---------------------------------------------------------------------------- |
---|
| 556 | //MgcBox3 MgcContOrientedBox (int iQuantity, const MgcVector3* akPoint) |
---|
| 557 | inline void computeContainment( OOBox& box, const std::vector<gmtl::Point3>& points) |
---|
| 558 | { |
---|
| 559 | //MgcGaussPointsFit(iQuantity,akPoint,kBox.Center(),kBox.Axes(), |
---|
| 560 | // kBox.Extents()); |
---|
| 561 | |
---|
| 562 | gmtl::GaussPointsFit(points.size(), &points[0], box.center(), box.axes(), box.halfLens()); |
---|
| 563 | |
---|
| 564 | // Let C be the box center and let U0, U1, and U2 be the box axes. Each |
---|
| 565 | // input point is of the form X = C + y0*U0 + y1*U1 + y2*U2. The |
---|
| 566 | // following code computes min(y0), max(y0), min(y1), max(y1), min(y2), |
---|
| 567 | // and max(y2). The box center is then adjusted to be |
---|
| 568 | // C' = C + 0.5*(min(y0)+max(y0))*U0 + 0.5*(min(y1)+max(y1))*U1 + |
---|
| 569 | // 0.5*(min(y2)+max(y2))*U2 |
---|
| 570 | #ifdef _DEBUG |
---|
| 571 | gmtl::OOBox box_test; |
---|
| 572 | box_test = box; |
---|
| 573 | gmtl::Vec3 ax0 = box_test.axis(0); |
---|
| 574 | gmtl::Vec3 ax1 = box_test.axis(1); |
---|
| 575 | gmtl::Vec3 ax2 = box_test.axis(2); |
---|
| 576 | #endif |
---|
| 577 | |
---|
| 578 | gmtlASSERT(box.axis(0).isNormalized()); |
---|
| 579 | gmtlASSERT(box.axis(1).isNormalized()); |
---|
| 580 | gmtlASSERT(box.axis(2).isNormalized()); |
---|
| 581 | |
---|
| 582 | // XXX: Sign is sometimes wrong here |
---|
| 583 | // This is hack code to make it "work right" |
---|
| 584 | Vec3 cross; |
---|
| 585 | cross = box.axis(0).cross(box.axis(1)); |
---|
| 586 | cross.normalize(); |
---|
| 587 | box.axis(2) = cross; |
---|
| 588 | |
---|
| 589 | Vec3 kDiff = points[0] - box.center(); |
---|
| 590 | float fY0Min = kDiff.dot(box.axis(0)), fY0Max = fY0Min; |
---|
| 591 | float fY1Min = kDiff.dot(box.axis(1)), fY1Max = fY1Min; |
---|
| 592 | float fY2Min = kDiff.dot(box.axis(2)), fY2Max = fY2Min; |
---|
| 593 | |
---|
| 594 | float fY0, fY1, fY2; |
---|
| 595 | |
---|
| 596 | for (unsigned i = 1; i < points.size(); i++) |
---|
| 597 | { |
---|
| 598 | kDiff = points[i] - box.center(); |
---|
| 599 | |
---|
| 600 | fY0 = kDiff.dot(box.axis(0)); |
---|
| 601 | if ( fY0 < fY0Min ) |
---|
| 602 | fY0Min = fY0; |
---|
| 603 | else if ( fY0 > fY0Max ) |
---|
| 604 | fY0Max = fY0; |
---|
| 605 | |
---|
| 606 | fY1 = kDiff.dot(box.axis(1)); |
---|
| 607 | if ( fY1 < fY1Min ) |
---|
| 608 | fY1Min = fY1; |
---|
| 609 | else if ( fY1 > fY1Max ) |
---|
| 610 | fY1Max = fY1; |
---|
| 611 | |
---|
| 612 | fY2 = kDiff.dot(box.axis(2)); |
---|
| 613 | if ( fY2 < fY2Min ) |
---|
| 614 | fY2Min = fY2; |
---|
| 615 | else if ( fY2 > fY2Max ) |
---|
| 616 | fY2Max = fY2; |
---|
| 617 | } |
---|
| 618 | |
---|
| 619 | box.center() += (0.5*(fY0Min+fY0Max))*box.axis(0) + |
---|
| 620 | (0.5*(fY1Min+fY1Max))*box.axis(1) + |
---|
| 621 | (0.5*(fY2Min+fY2Max))*box.axis(2); |
---|
| 622 | |
---|
| 623 | box.halfLen(0) = 0.5*(fY0Max - fY0Min); |
---|
| 624 | box.halfLen(1) = 0.5*(fY1Max - fY1Min); |
---|
| 625 | box.halfLen(2) = 0.5*(fY2Max - fY2Min); |
---|
| 626 | } |
---|
| 627 | |
---|
| 628 | */ |
---|
| 629 | /* |
---|
| 630 | inline void computeContainment (OOBox& out_box, const OOBox& box0, const OOBox& box1, bool fast=true) |
---|
| 631 | { |
---|
| 632 | gmtl::OOBox ret_box; // The resulting box |
---|
| 633 | |
---|
| 634 | if (fast) |
---|
| 635 | { |
---|
| 636 | ret_box.center() = 0.5*(box0.center() + box1.center()); // Center at average |
---|
| 637 | |
---|
| 638 | // Average the quats to get a new orientation |
---|
| 639 | Quat quat0, quat1; |
---|
| 640 | quat0.makeAxes(box0.axis(0), box0.axis(1), box0.axis(2)); |
---|
| 641 | quat1.makeAxes(box1.axis(0), box1.axis(1), box1.axis(2)); |
---|
| 642 | if ( quat0.dot(quat1) < 0.0 ) |
---|
| 643 | quat1 = -quat1; |
---|
| 644 | |
---|
| 645 | Quat full_quat = quat0 + quat1; |
---|
| 646 | |
---|
| 647 | //float inv_len = 1.0/Math::sqrt(full_quat.norm()); |
---|
| 648 | //full_quat = inv_len*full_quat; |
---|
| 649 | full_quat.normalize(); |
---|
| 650 | full_quat.getAxes(ret_box.axis(0), ret_box.axis(1), ret_box.axis(2)); |
---|
| 651 | |
---|
| 652 | // Now that we have new orientation, extend half lens to cover the volume |
---|
| 653 | // |
---|
| 654 | unsigned i, j; |
---|
| 655 | Point3 verts[8]; |
---|
| 656 | Vec3 diff; |
---|
| 657 | float aDot; |
---|
| 658 | |
---|
| 659 | ret_box.halfLen(0) = 0.0; |
---|
| 660 | ret_box.halfLen(1) = 0.0; |
---|
| 661 | ret_box.halfLen(2) = 0.0; |
---|
| 662 | |
---|
| 663 | box0.getVerts(verts); |
---|
| 664 | for (i = 0; i < 8; i++) |
---|
| 665 | { |
---|
| 666 | diff = verts[i] - ret_box.center(); |
---|
| 667 | for (j = 0; j < 3; j++) // For each axis of box0 |
---|
| 668 | { |
---|
| 669 | aDot = Math::abs(diff.dot(ret_box.axis(j))); |
---|
| 670 | if ( aDot > ret_box.halfLen(j) ) |
---|
| 671 | ret_box.halfLen(j) = aDot; |
---|
| 672 | } |
---|
| 673 | } |
---|
| 674 | |
---|
| 675 | box1.getVerts(verts); |
---|
| 676 | for (i = 0; i < 8; i++) |
---|
| 677 | { |
---|
| 678 | diff = verts[i] - ret_box.center(); |
---|
| 679 | for (j = 0; j < 3; j++) |
---|
| 680 | { |
---|
| 681 | aDot = Math::abs(diff.dot(ret_box.axis(j))); |
---|
| 682 | if ( aDot > ret_box.halfLen(j) ) |
---|
| 683 | ret_box.halfLen(j) = aDot; |
---|
| 684 | } |
---|
| 685 | } |
---|
| 686 | } |
---|
| 687 | else // Tighter fit |
---|
| 688 | { |
---|
| 689 | // Hack that will do it correctly, but is slow |
---|
| 690 | Point3 verts[8]; |
---|
| 691 | std::vector<gmtl::Point3> vert_points; |
---|
| 692 | |
---|
| 693 | box0.getVerts(verts); |
---|
| 694 | for (unsigned i=0;i<8;i++) vert_points.push_back(verts[i]); |
---|
| 695 | box1.getVerts(verts); |
---|
| 696 | for (unsigned i=0;i<8;i++) vert_points.push_back(verts[i]); |
---|
| 697 | |
---|
| 698 | computeContainment(ret_box, vert_points); |
---|
| 699 | } |
---|
| 700 | |
---|
| 701 | out_box = ret_box; |
---|
| 702 | } |
---|
| 703 | */ |
---|
| 704 | |
---|
| 705 | |
---|
| 706 | } |
---|
| 707 | |
---|
| 708 | #endif |
---|