Panda3D
|
00001 // Filename: boundingSphere.cxx 00002 // Created by: drose (01Oct99) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "boundingSphere.h" 00016 #include "boundingBox.h" 00017 #include "boundingHexahedron.h" 00018 #include "boundingLine.h" 00019 #include "boundingPlane.h" 00020 #include "config_mathutil.h" 00021 #include "dcast.h" 00022 00023 #include <math.h> 00024 #include <algorithm> 00025 00026 TypeHandle BoundingSphere::_type_handle; 00027 00028 //////////////////////////////////////////////////////////////////// 00029 // Function: BoundingSphere::make_copy 00030 // Access: Public, Virtual 00031 // Description: 00032 //////////////////////////////////////////////////////////////////// 00033 BoundingVolume *BoundingSphere:: 00034 make_copy() const { 00035 return new BoundingSphere(*this); 00036 } 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: BoundingSphere::get_min 00040 // Access: Public, Virtual 00041 // Description: 00042 //////////////////////////////////////////////////////////////////// 00043 LPoint3f BoundingSphere:: 00044 get_min() const { 00045 nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); 00046 nassertr(!is_infinite(), LPoint3f(0.0f, 0.0f, 0.0f)); 00047 return LPoint3f(_center[0] - _radius, 00048 _center[1] - _radius, 00049 _center[2] - _radius); 00050 } 00051 00052 //////////////////////////////////////////////////////////////////// 00053 // Function: BoundingSphere::get_max 00054 // Access: Public, Virtual 00055 // Description: 00056 //////////////////////////////////////////////////////////////////// 00057 LPoint3f BoundingSphere:: 00058 get_max() const { 00059 nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); 00060 nassertr(!is_infinite(), LPoint3f(0.0f, 0.0f, 0.0f)); 00061 return LPoint3f(_center[0] + _radius, 00062 _center[1] + _radius, 00063 _center[2] + _radius); 00064 } 00065 00066 //////////////////////////////////////////////////////////////////// 00067 // Function: BoundingSphere::get_volume 00068 // Access: Public, Virtual 00069 // Description: 00070 //////////////////////////////////////////////////////////////////// 00071 float BoundingSphere:: 00072 get_volume() const { 00073 nassertr(!is_infinite(), 0.0f); 00074 if (is_empty()) { 00075 return 0.0f; 00076 } 00077 00078 // Volume of a sphere: four-thirds pi r cubed. 00079 return 4.0f / 3.0f * MathNumbers::pi_f * _radius * _radius * _radius; 00080 } 00081 00082 //////////////////////////////////////////////////////////////////// 00083 // Function: BoundingSphere::get_approx_center 00084 // Access: Public, Virtual 00085 // Description: 00086 //////////////////////////////////////////////////////////////////// 00087 LPoint3f BoundingSphere:: 00088 get_approx_center() const { 00089 nassertr(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f)); 00090 nassertr(!is_infinite(), LPoint3f(0.0f, 0.0f, 0.0f)); 00091 return get_center(); 00092 } 00093 00094 //////////////////////////////////////////////////////////////////// 00095 // Function: BoundingSphere::xform 00096 // Access: Public, Virtual 00097 // Description: 00098 //////////////////////////////////////////////////////////////////// 00099 void BoundingSphere:: 00100 xform(const LMatrix4f &mat) { 00101 nassertv(!mat.is_nan()); 00102 00103 if (!is_empty() && !is_infinite()) { 00104 // First, determine the longest axis of the matrix, in case it 00105 // contains a non-uniform scale. 00106 00107 /* 00108 LVector3f x,y,z; 00109 mat.get_row3(x,0); 00110 mat.get_row3(y,1); 00111 mat.get_row3(z,2); 00112 00113 float xd = dot(x, x); 00114 float yd = dot(y, y); 00115 float zd = dot(z, z); 00116 */ 00117 float xd,yd,zd,scale; 00118 00119 #define ROW_DOTTED(mat,ROWNUM) \ 00120 (mat._m.m._##ROWNUM##0*mat._m.m._##ROWNUM##0 + \ 00121 mat._m.m._##ROWNUM##1*mat._m.m._##ROWNUM##1 + \ 00122 mat._m.m._##ROWNUM##2*mat._m.m._##ROWNUM##2) 00123 00124 xd = ROW_DOTTED(mat,0); 00125 yd = ROW_DOTTED(mat,1); 00126 zd = ROW_DOTTED(mat,2); 00127 00128 scale = max(xd,yd); 00129 scale = max(scale,zd); 00130 scale = sqrtf(scale); 00131 00132 // Transform the radius 00133 _radius *= scale; 00134 00135 // Transform the center 00136 _center = _center * mat; 00137 } 00138 } 00139 00140 //////////////////////////////////////////////////////////////////// 00141 // Function: BoundingSphere::output 00142 // Access: Public, Virtual 00143 // Description: 00144 //////////////////////////////////////////////////////////////////// 00145 void BoundingSphere:: 00146 output(ostream &out) const { 00147 if (is_empty()) { 00148 out << "bsphere, empty"; 00149 } else if (is_infinite()) { 00150 out << "bsphere, infinite"; 00151 } else { 00152 out << "bsphere, c (" << _center << "), r " << _radius; 00153 } 00154 } 00155 00156 //////////////////////////////////////////////////////////////////// 00157 // Function: BoundingSphere::as_bounding_sphere 00158 // Access: Public, Virtual 00159 // Description: Virtual downcast method. Returns this object as a 00160 // pointer of the indicated type, if it is in fact that 00161 // type. Returns NULL if it is not that type. 00162 //////////////////////////////////////////////////////////////////// 00163 const BoundingSphere *BoundingSphere:: 00164 as_bounding_sphere() const { 00165 return this; 00166 } 00167 00168 //////////////////////////////////////////////////////////////////// 00169 // Function: BoundingSphere::extend_other 00170 // Access: Protected, Virtual 00171 // Description: 00172 //////////////////////////////////////////////////////////////////// 00173 bool BoundingSphere:: 00174 extend_other(BoundingVolume *other) const { 00175 return other->extend_by_sphere(this); 00176 } 00177 00178 //////////////////////////////////////////////////////////////////// 00179 // Function: BoundingSphere::around_other 00180 // Access: Protected, Virtual 00181 // Description: 00182 //////////////////////////////////////////////////////////////////// 00183 bool BoundingSphere:: 00184 around_other(BoundingVolume *other, 00185 const BoundingVolume **first, 00186 const BoundingVolume **last) const { 00187 return other->around_spheres(first, last); 00188 } 00189 00190 //////////////////////////////////////////////////////////////////// 00191 // Function: BoundingSphere::contains_other 00192 // Access: Protected, Virtual 00193 // Description: 00194 //////////////////////////////////////////////////////////////////// 00195 int BoundingSphere:: 00196 contains_other(const BoundingVolume *other) const { 00197 return other->contains_sphere(this); 00198 } 00199 00200 00201 //////////////////////////////////////////////////////////////////// 00202 // Function: BoundingSphere::extend_by_point 00203 // Access: Protected, Virtual 00204 // Description: 00205 //////////////////////////////////////////////////////////////////// 00206 bool BoundingSphere:: 00207 extend_by_point(const LPoint3f &point) { 00208 nassertr(!point.is_nan(), false); 00209 00210 if (is_empty()) { 00211 _center = point; 00212 _radius = 0.0f; 00213 _flags = 0; 00214 } else if (!is_infinite()) { 00215 LVector3f v = point - _center; 00216 float dist2 = dot(v, v); 00217 if (dist2 > _radius * _radius) { 00218 _radius = sqrtf(dist2); 00219 } 00220 } 00221 return true; 00222 } 00223 00224 //////////////////////////////////////////////////////////////////// 00225 // Function: BoundingSphere::extend_by_sphere 00226 // Access: Protected, Virtual 00227 // Description: 00228 //////////////////////////////////////////////////////////////////// 00229 bool BoundingSphere:: 00230 extend_by_sphere(const BoundingSphere *sphere) { 00231 nassertr(!sphere->is_empty() && !sphere->is_infinite(), false); 00232 nassertr(!is_infinite(), false); 00233 00234 if (is_empty()) { 00235 _center = sphere->_center; 00236 _radius = sphere->_radius; 00237 _flags = 0; 00238 } else { 00239 float dist = length(sphere->_center - _center); 00240 00241 _radius = max(_radius, dist + sphere->_radius); 00242 } 00243 return true; 00244 } 00245 00246 //////////////////////////////////////////////////////////////////// 00247 // Function: BoundingSphere::extend_by_box 00248 // Access: Protected, Virtual 00249 // Description: 00250 //////////////////////////////////////////////////////////////////// 00251 bool BoundingSphere:: 00252 extend_by_box(const BoundingBox *box) { 00253 const LVector3f &min1 = box->get_minq(); 00254 const LVector3f &max1 = box->get_maxq(); 00255 00256 if (is_empty()) { 00257 _center = (min1 + max1) * 0.5f; 00258 _radius = length(LVector3f(max1 - _center)); 00259 _flags = 0; 00260 00261 } else { 00262 // Find the minimum radius necessary to reach the corner. 00263 float max_dist2 = -1.0; 00264 for (int i = 0; i < 8; ++i) { 00265 float dist2 = (box->get_point(i) - _center).length_squared(); 00266 if (dist2 > max_dist2) { 00267 max_dist2 = dist2; 00268 } 00269 } 00270 if (max_dist2 > _radius * _radius) { 00271 _radius = csqrt(max_dist2); 00272 } 00273 } 00274 00275 return true; 00276 } 00277 00278 //////////////////////////////////////////////////////////////////// 00279 // Function: BoundingSphere::extend_by_hexahedron 00280 // Access: Protected, Virtual 00281 // Description: 00282 //////////////////////////////////////////////////////////////////// 00283 bool BoundingSphere:: 00284 extend_by_hexahedron(const BoundingHexahedron *hexahedron) { 00285 nassertr(!hexahedron->is_empty(), false); 00286 00287 BoundingBox box(hexahedron->get_min(), hexahedron->get_max()); 00288 box.local_object(); 00289 return extend_by_box(&box); 00290 } 00291 00292 //////////////////////////////////////////////////////////////////// 00293 // Function: BoundingSphere::extend_by_finite 00294 // Access: Protected 00295 // Description: 00296 //////////////////////////////////////////////////////////////////// 00297 bool BoundingSphere:: 00298 extend_by_finite(const FiniteBoundingVolume *volume) { 00299 nassertr(!volume->is_empty(), false); 00300 00301 BoundingBox box(volume->get_min(), volume->get_max()); 00302 box.local_object(); 00303 return extend_by_box(&box); 00304 } 00305 00306 //////////////////////////////////////////////////////////////////// 00307 // Function: BoundingSphere::around_points 00308 // Access: Protected, Virtual 00309 // Description: 00310 //////////////////////////////////////////////////////////////////// 00311 bool BoundingSphere:: 00312 around_points(const LPoint3f *first, const LPoint3f *last) { 00313 nassertr(first != last, false); 00314 00315 // First, get the box of all the points to construct a bounding 00316 // box. 00317 const LPoint3f *p = first; 00318 00319 #ifndef NDEBUG 00320 // Skip any NaN points. 00321 int skipped_nan = 0; 00322 while (p != last && (*p).is_nan()) { 00323 ++p; 00324 ++skipped_nan; 00325 } 00326 if (p == last) { 00327 mathutil_cat.warning() 00328 << "BoundingSphere around NaN\n"; 00329 return false; 00330 } 00331 #endif 00332 00333 LPoint3f min_box = *p; 00334 LPoint3f max_box = *p; 00335 ++p; 00336 00337 #ifndef NDEBUG 00338 // Skip more NaN points. 00339 while (p != last && (*p).is_nan()) { 00340 ++p; 00341 ++skipped_nan; 00342 } 00343 #endif 00344 00345 if (p == last) { 00346 // Only one point; we have a radius of zero. This is not the same 00347 // thing as an empty sphere, because our volume contains one 00348 // point; an empty sphere contains no points. 00349 _center = min_box; 00350 _radius = 0.0f; 00351 00352 } else { 00353 // More than one point; we have a nonzero radius. 00354 while (p != last) { 00355 #ifndef NDEBUG 00356 // Skip more NaN points. 00357 if ((*p).is_nan()) { 00358 ++skipped_nan; 00359 } else 00360 #endif 00361 { 00362 min_box.set(min(min_box[0], (*p)[0]), 00363 min(min_box[1], (*p)[1]), 00364 min(min_box[2], (*p)[2])); 00365 max_box.set(max(max_box[0], (*p)[0]), 00366 max(max_box[1], (*p)[1]), 00367 max(max_box[2], (*p)[2])); 00368 } 00369 ++p; 00370 } 00371 00372 // Now take the center of the bounding box as the center of the sphere. 00373 _center = (min_box + max_box) * 0.5f; 00374 00375 // Now walk back through to get the max distance from center. 00376 float max_dist2 = 0.0f; 00377 for (p = first; p != last; ++p) { 00378 LVector3f v = (*p) - _center; 00379 float dist2 = dot(v, v); 00380 max_dist2 = max(max_dist2, dist2); 00381 } 00382 00383 _radius = sqrtf(max_dist2); 00384 } 00385 00386 #ifndef NDEBUG 00387 if (skipped_nan != 0) { 00388 mathutil_cat.warning() 00389 << "BoundingSphere ignored " << skipped_nan << " NaN points of " 00390 << (last - first) << " total.\n"; 00391 } 00392 #endif 00393 00394 _flags = 0; 00395 00396 return true; 00397 } 00398 00399 //////////////////////////////////////////////////////////////////// 00400 // Function: BoundingSphere::around_spheres 00401 // Access: Protected, Virtual 00402 // Description: 00403 //////////////////////////////////////////////////////////////////// 00404 bool BoundingSphere:: 00405 around_spheres(const BoundingVolume **first, 00406 const BoundingVolume **last) { 00407 return around_finite(first, last); 00408 } 00409 00410 //////////////////////////////////////////////////////////////////// 00411 // Function: BoundingSphere::around_boxes 00412 // Access: Protected, Virtual 00413 // Description: 00414 //////////////////////////////////////////////////////////////////// 00415 bool BoundingSphere:: 00416 around_boxes(const BoundingVolume **first, 00417 const BoundingVolume **last) { 00418 return around_finite(first, last); 00419 } 00420 00421 //////////////////////////////////////////////////////////////////// 00422 // Function: BoundingSphere::around_hexahedrons 00423 // Access: Protected, Virtual 00424 // Description: 00425 //////////////////////////////////////////////////////////////////// 00426 bool BoundingSphere:: 00427 around_hexahedrons(const BoundingVolume **first, 00428 const BoundingVolume **last) { 00429 return around_finite(first, last); 00430 } 00431 00432 //////////////////////////////////////////////////////////////////// 00433 // Function: BoundingSphere::around_finite 00434 // Access: Protected 00435 // Description: 00436 //////////////////////////////////////////////////////////////////// 00437 bool BoundingSphere:: 00438 around_finite(const BoundingVolume **first, 00439 const BoundingVolume **last) { 00440 nassertr(first != last, false); 00441 00442 // We're given a set of bounding volumes, all of which are finite, 00443 // and at least the first one of which is guaranteed to be nonempty. 00444 // Some others may not be. 00445 00446 // First, get the box of all the points to construct a bounding 00447 // box. 00448 const BoundingVolume **p = first; 00449 nassertr(!(*p)->is_empty() && !(*p)->is_infinite(), false); 00450 const FiniteBoundingVolume *vol = (*p)->as_finite_bounding_volume(); 00451 nassertr(vol != (FiniteBoundingVolume *)NULL, false); 00452 LPoint3f min_box = vol->get_min(); 00453 LPoint3f max_box = vol->get_max(); 00454 00455 bool any_spheres = (vol->as_bounding_sphere() != NULL); 00456 00457 for (++p; p != last; ++p) { 00458 nassertr(!(*p)->is_infinite(), false); 00459 if (!(*p)->is_empty()) { 00460 vol = (*p)->as_finite_bounding_volume(); 00461 if (vol == (FiniteBoundingVolume *)NULL) { 00462 set_infinite(); 00463 return true; 00464 } 00465 LPoint3f min1 = vol->get_min(); 00466 LPoint3f max1 = vol->get_max(); 00467 min_box.set(min(min_box[0], min1[0]), 00468 min(min_box[1], min1[1]), 00469 min(min_box[2], min1[2])); 00470 max_box.set(max(max_box[0], max1[0]), 00471 max(max_box[1], max1[1]), 00472 max(max_box[2], max1[2])); 00473 00474 if (vol->as_bounding_sphere() != NULL) { 00475 any_spheres = true; 00476 } 00477 } 00478 } 00479 00480 // Now take the center of the bounding box as the center of the sphere. 00481 _center = (min_box + max_box) * 0.5f; 00482 00483 if (!any_spheres) { 00484 // Since there are no spheres in the list, we have to make this 00485 // sphere fully enclose all of the bounding boxes. 00486 _radius = length(max_box - _center); 00487 00488 } else { 00489 // We might be able to go tighter, by lopping off the corners of 00490 // the spheres. 00491 _radius = 0.0f; 00492 for (p = first; p != last; ++p) { 00493 if (!(*p)->is_empty()) { 00494 const BoundingSphere *sphere = (*p)->as_bounding_sphere(); 00495 if (sphere != (BoundingSphere *)NULL) { 00496 // This is a sphere; consider its corner. 00497 float dist = length(sphere->_center - _center); 00498 _radius = max(_radius, dist + sphere->_radius); 00499 00500 } else { 00501 // This is a nonsphere. We fit around it. 00502 const FiniteBoundingVolume *vol = (*p)->as_finite_bounding_volume(); 00503 nassertr(vol != (FiniteBoundingVolume *)NULL, false); 00504 00505 BoundingBox box(vol->get_min(), vol->get_max()); 00506 box.local_object(); 00507 00508 // Find the minimum radius necessary to reach the corner. 00509 float max_dist2 = -1.0; 00510 for (int i = 0; i < 8; ++i) { 00511 float dist2 = (box.get_point(i) - _center).length_squared(); 00512 if (dist2 > max_dist2) { 00513 max_dist2 = dist2; 00514 } 00515 } 00516 _radius = max(_radius, csqrt(max_dist2)); 00517 } 00518 } 00519 } 00520 } 00521 00522 _flags = 0; 00523 return true; 00524 } 00525 00526 //////////////////////////////////////////////////////////////////// 00527 // Function: BoundingSphere::contains_point 00528 // Access: Protected, Virtual 00529 // Description: 00530 //////////////////////////////////////////////////////////////////// 00531 int BoundingSphere:: 00532 contains_point(const LPoint3f &point) const { 00533 nassertr(!point.is_nan(), IF_no_intersection); 00534 00535 if (is_empty()) { 00536 return IF_no_intersection; 00537 00538 } else if (is_infinite()) { 00539 return IF_possible | IF_some | IF_all; 00540 00541 } else { 00542 LVector3f v = point - _center; 00543 float dist2 = dot(v, v); 00544 return (dist2 <= _radius * _radius) ? 00545 IF_possible | IF_some | IF_all : IF_no_intersection; 00546 } 00547 } 00548 00549 //////////////////////////////////////////////////////////////////// 00550 // Function: BoundingSphere::contains_lineseg 00551 // Access: Protected, Virtual 00552 // Description: 00553 //////////////////////////////////////////////////////////////////// 00554 int BoundingSphere:: 00555 contains_lineseg(const LPoint3f &a, const LPoint3f &b) const { 00556 nassertr(!a.is_nan() && !b.is_nan(), IF_no_intersection); 00557 00558 if (a == b) { 00559 return contains_point(a); 00560 } 00561 if (is_empty()) { 00562 return IF_no_intersection; 00563 00564 } else if (is_infinite()) { 00565 return IF_possible | IF_some | IF_all; 00566 00567 } else { 00568 LPoint3f from = a; 00569 LVector3f delta = b - a; 00570 float t1, t2; 00571 00572 // Solve the equation for the intersection of a line with a sphere 00573 // using the quadratic equation. 00574 float A = dot(delta, delta); 00575 00576 nassertr(A != 0.0f, 0); // Trivial line segment. 00577 00578 LVector3f fc = from - _center; 00579 float B = 2.0f * dot(delta, fc); 00580 float C = dot(fc, fc) - _radius * _radius; 00581 00582 float radical = B*B - 4.0f*A*C; 00583 00584 if (IS_NEARLY_ZERO(radical)) { 00585 // Tangent. 00586 t1 = t2 = -B / (2.0f*A); 00587 return (t1 >= 0.0f && t1 <= 1.0f) ? 00588 IF_possible | IF_some : IF_no_intersection; 00589 } 00590 00591 if (radical < 0.0f) { 00592 // No real roots: no intersection with the line. 00593 return IF_no_intersection; 00594 } 00595 00596 float reciprocal_2A = 1.0f/(2.0f*A); 00597 float sqrt_radical = sqrtf(radical); 00598 00599 t1 = ( -B - sqrt_radical ) * reciprocal_2A; 00600 t2 = ( -B + sqrt_radical ) * reciprocal_2A; 00601 00602 if (t1 >= 0.0f && t2 <= 1.0f) { 00603 return IF_possible | IF_some | IF_all; 00604 } else if (t1 <= 1.0f && t2 >= 0.0f) { 00605 return IF_possible | IF_some; 00606 } else { 00607 return IF_no_intersection; 00608 } 00609 } 00610 } 00611 00612 //////////////////////////////////////////////////////////////////// 00613 // Function: BoundingSphere::contains_sphere 00614 // Access: Protected, Virtual 00615 // Description: Double-dispatch support: called by contains_other() 00616 // when the type we're testing for intersection is known 00617 // to be a sphere. 00618 //////////////////////////////////////////////////////////////////// 00619 int BoundingSphere:: 00620 contains_sphere(const BoundingSphere *sphere) const { 00621 nassertr(!is_empty() && !is_infinite(), 0); 00622 nassertr(!sphere->is_empty() && !sphere->is_infinite(), 0); 00623 00624 LVector3f v = sphere->_center - _center; 00625 float dist2 = dot(v, v); 00626 00627 if (_radius >= sphere->_radius && 00628 dist2 <= (_radius - sphere->_radius) * (_radius - sphere->_radius)) { 00629 // The other sphere is completely within this sphere. 00630 return IF_possible | IF_some | IF_all; 00631 00632 } else if (dist2 > (_radius + sphere->_radius) * (_radius + sphere->_radius)) { 00633 // The other sphere is completely outside this sphere. 00634 return IF_no_intersection; 00635 00636 } else { 00637 // The other sphere is partially within this sphere. 00638 return IF_possible | IF_some; 00639 } 00640 } 00641 00642 //////////////////////////////////////////////////////////////////// 00643 // Function: BoundingSphere::contains_box 00644 // Access: Protected, Virtual 00645 // Description: Double-dispatch support: called by contains_other() 00646 // when the type we're testing for intersection is known 00647 // to be a box. 00648 //////////////////////////////////////////////////////////////////// 00649 int BoundingSphere:: 00650 contains_box(const BoundingBox *box) const { 00651 return box->contains_sphere(this) & ~IF_all; 00652 } 00653 00654 //////////////////////////////////////////////////////////////////// 00655 // Function: BoundingSphere::contains_hexahedron 00656 // Access: Protected, Virtual 00657 // Description: Double-dispatch support: called by contains_other() 00658 // when the type we're testing for intersection is known 00659 // to be a hexahedron. 00660 //////////////////////////////////////////////////////////////////// 00661 int BoundingSphere:: 00662 contains_hexahedron(const BoundingHexahedron *hexahedron) const { 00663 return hexahedron->contains_sphere(this) & ~IF_all; 00664 } 00665 00666 //////////////////////////////////////////////////////////////////// 00667 // Function: BoundingSphere::contains_line 00668 // Access: Protected, Virtual 00669 // Description: Double-dispatch support: called by contains_other() 00670 // when the type we're testing for intersection is known 00671 // to be a line. 00672 //////////////////////////////////////////////////////////////////// 00673 int BoundingSphere:: 00674 contains_line(const BoundingLine *line) const { 00675 return line->contains_sphere(this) & ~IF_all; 00676 } 00677 00678 //////////////////////////////////////////////////////////////////// 00679 // Function: BoundingSphere::contains_plane 00680 // Access: Protected, Virtual 00681 // Description: Double-dispatch support: called by contains_other() 00682 // when the type we're testing for intersection is known 00683 // to be a plane. 00684 //////////////////////////////////////////////////////////////////// 00685 int BoundingSphere:: 00686 contains_plane(const BoundingPlane *plane) const { 00687 return plane->contains_sphere(this) & ~IF_all; 00688 }