BoundingSphere 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
  2. *
  3. * This library is open source and may be redistributed and/or modified under
  4. * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
  5. * (at your option) any later version. The full license is in LICENSE file
  6. * included with this distribution, and on the openscenegraph.org website.
  7. *
  8. * This library is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * OpenSceneGraph Public License for more details.
  12. */
  13. #ifndef OSG_BOUNDINGSPHERE
  14. #define OSG_BOUNDINGSPHERE 1
  15. #include <osg/Config>
  16. #include <osg/Export>
  17. #include <osg/Vec3f>
  18. #include <osg/Vec3d>
  19. namespace osg {
  20. template<typename VT>
  21. class BoundingBoxImpl;
  22. /** General purpose bounding sphere class for enclosing nodes/objects/vertices.
  23. * Bounds internal osg::Nodes in the scene, assists in view frustum culling,
  24. * etc. Similar in function to BoundingBox, it's quicker for evaluating
  25. * culling but generally will not cull as aggressively because it encloses a
  26. * greater volume.
  27. */
  28. template<typename VT>
  29. class BoundingSphereImpl
  30. {
  31. public:
  32. typedef VT vec_type;
  33. typedef typename VT::value_type value_type;
  34. vec_type _center;
  35. value_type _radius;
  36. /** Construct a default bounding sphere with radius to -1.0f, representing an invalid/unset bounding sphere.*/
  37. BoundingSphereImpl() : _center(0.0,0.0,0.0),_radius(-1.0) {}
  38. /** Creates a bounding sphere initialized to the given extents. */
  39. BoundingSphereImpl(const vec_type& cntr, value_type rad) : _center(cntr),_radius(rad) {}
  40. /** Creates a bounding sphere initialized to the given extents. */
  41. BoundingSphereImpl(const BoundingSphereImpl& bs) : _center(bs._center),_radius(bs._radius) {}
  42. /** Creates a bounding sphere initialized to the given extents. */
  43. BoundingSphereImpl(const BoundingBoxImpl<VT>& bb) : _center(0.0,0.0,0.0),_radius(-1.0) { expandBy(bb); }
  44. /** Clear the bounding sphere. Reset to default values. */
  45. inline void init()
  46. {
  47. _center.set(0.0,0.0,0.0);
  48. _radius = -1.0;
  49. }
  50. /** Returns true of the bounding sphere extents are valid, false
  51. * otherwise. */
  52. inline bool valid() const { return _radius>=0.0; }
  53. inline bool operator == (const BoundingSphereImpl& rhs) const { return _center==rhs._center && _radius==rhs._radius; }
  54. inline bool operator != (const BoundingSphereImpl& rhs) const { return _center!=rhs._center || _radius!=rhs._radius; }
  55. /** Set the bounding sphere to the given center/radius using floats. */
  56. inline void set(const vec_type& center,value_type radius)
  57. {
  58. _center = center;
  59. _radius = radius;
  60. }
  61. /** Returns the center of the bounding sphere. */
  62. inline vec_type& center() { return _center; }
  63. /** Returns the const center of the bounding sphere. */
  64. inline const vec_type& center() const { return _center; }
  65. /** Returns the radius of the bounding sphere. */
  66. inline value_type& radius() { return _radius; }
  67. /** Returns the const radius of the bounding sphere. */
  68. inline value_type radius() const { return _radius; }
  69. /** Returns the squared length of the radius. Note, For performance
  70. * reasons, the calling method is responsible for checking to make
  71. * sure the sphere is valid. */
  72. inline value_type radius2() const { return _radius*_radius; }
  73. /** Expands the sphere to encompass the given point. Repositions the
  74. * sphere center to minimize the radius increase. If the sphere is
  75. * uninitialized, set its center to v and radius to zero. */
  76. template<typename vector_type>
  77. void expandBy(const vector_type& v);
  78. /** Expands the sphere to encompass the given point. Does not
  79. * reposition the sphere center. If the sphere is
  80. * uninitialized, set its center to v and radius to zero. */
  81. template<typename vector_type>
  82. void expandRadiusBy(const vector_type& v);
  83. /** Expands the sphere to encompass the given sphere. Repositions the
  84. * sphere center to minimize the radius increase. If the sphere is
  85. * uninitialized, set its center and radius to match sh. */
  86. void expandBy(const BoundingSphereImpl& sh);
  87. /** Expands the sphere to encompass the given sphere. Does not
  88. * repositions the sphere center. If the sphere is
  89. * uninitialized, set its center and radius to match sh. */
  90. void expandRadiusBy(const BoundingSphereImpl& sh);
  91. /** Expands the sphere to encompass the given box. Repositions the
  92. * sphere center to minimize the radius increase. */
  93. template<typename BBT>
  94. void expandBy(const BoundingBoxImpl<BBT>& bb);
  95. /** Expands the sphere to encompass the given box. Does not
  96. * repositions the sphere center. */
  97. template<typename BBT>
  98. void expandRadiusBy(const BoundingBoxImpl<BBT>& bb);
  99. /** Returns true if v is within the sphere. */
  100. inline bool contains(const vec_type& v) const
  101. {
  102. return valid() && ((v-_center).length2()<=radius2());
  103. }
  104. /** Returns true if there is a non-empty intersection with the given
  105. * bounding sphere. */
  106. inline bool intersects( const BoundingSphereImpl& bs ) const
  107. {
  108. return valid() && bs.valid() &&
  109. ((_center - bs._center).length2() <= (_radius + bs._radius)*(_radius + bs._radius));
  110. }
  111. };
  112. template<typename VT>
  113. template<typename vector_type>
  114. void BoundingSphereImpl<VT>::expandBy(const vector_type& v)
  115. {
  116. if (valid())
  117. {
  118. vec_type dv = vec_type(v)-_center;
  119. value_type r = dv.length();
  120. if (r>_radius)
  121. {
  122. value_type dr = (r-_radius)*0.5;
  123. _center += dv*(dr/r);
  124. _radius += dr;
  125. } // else do nothing as vertex is within sphere.
  126. }
  127. else
  128. {
  129. _center = v;
  130. _radius = 0.0;
  131. }
  132. }
  133. template<typename VT>
  134. template<typename vector_type>
  135. void BoundingSphereImpl<VT>::expandRadiusBy(const vector_type& v)
  136. {
  137. if (valid())
  138. {
  139. value_type r = (vec_type(v)-_center).length();
  140. if (r>_radius) _radius = r;
  141. // else do nothing as vertex is within sphere.
  142. }
  143. else
  144. {
  145. _center = v;
  146. _radius = 0.0;
  147. }
  148. }
  149. template<typename VT>
  150. void BoundingSphereImpl<VT>::expandBy(const BoundingSphereImpl& sh)
  151. {
  152. // ignore operation if incoming BoundingSphere is invalid.
  153. if (!sh.valid()) return;
  154. // This sphere is not set so use the inbound sphere
  155. if (!valid())
  156. {
  157. _center = sh._center;
  158. _radius = sh._radius;
  159. return;
  160. }
  161. // Calculate d == The distance between the sphere centers
  162. double d = ( _center - sh.center() ).length();
  163. // New sphere is already inside this one
  164. if ( d + sh.radius() <= _radius )
  165. {
  166. return;
  167. }
  168. // New sphere completely contains this one
  169. if ( d + _radius <= sh.radius() )
  170. {
  171. _center = sh._center;
  172. _radius = sh._radius;
  173. return;
  174. }
  175. // Build a new sphere that completely contains the other two:
  176. //
  177. // The center point lies halfway along the line between the furthest
  178. // points on the edges of the two spheres.
  179. //
  180. // Computing those two points is ugly - so we'll use similar triangles
  181. double new_radius = (_radius + d + sh.radius() ) * 0.5;
  182. double ratio = ( new_radius - _radius ) / d ;
  183. _center[0] += ( sh.center()[0] - _center[0] ) * ratio;
  184. _center[1] += ( sh.center()[1] - _center[1] ) * ratio;
  185. _center[2] += ( sh.center()[2] - _center[2] ) * ratio;
  186. _radius = new_radius;
  187. }
  188. template<typename VT>
  189. void BoundingSphereImpl<VT>::expandRadiusBy(const BoundingSphereImpl& sh)
  190. {
  191. if (sh.valid())
  192. {
  193. if (valid())
  194. {
  195. value_type r = (sh._center-_center).length()+sh._radius;
  196. if (r>_radius) _radius = r;
  197. // else do nothing as vertex is within sphere.
  198. }
  199. else
  200. {
  201. _center = sh._center;
  202. _radius = sh._radius;
  203. }
  204. }
  205. }
  206. template<typename VT>
  207. template<typename BBT>
  208. void BoundingSphereImpl<VT>::expandBy(const BoundingBoxImpl<BBT>& bb)
  209. {
  210. if (bb.valid())
  211. {
  212. if (valid())
  213. {
  214. BoundingBoxImpl<vec_type> newbb(bb);
  215. for(unsigned int c=0;c<8;++c)
  216. {
  217. vec_type v = bb.corner(c)-_center; // get the direction vector from corner
  218. v.normalize(); // normalise it.
  219. v *= -_radius; // move the vector in the opposite direction distance radius.
  220. v += _center; // move to absolute position.
  221. newbb.expandBy(v); // add it into the new bounding box.
  222. }
  223. _center = newbb.center();
  224. _radius = newbb.radius();
  225. }
  226. else
  227. {
  228. _center = bb.center();
  229. _radius = bb.radius();
  230. }
  231. }
  232. }
  233. template<typename VT>
  234. template<typename BBT>
  235. void BoundingSphereImpl<VT>::expandRadiusBy(const BoundingBoxImpl<BBT>& bb)
  236. {
  237. if (bb.valid())
  238. {
  239. if (valid())
  240. {
  241. for(unsigned int c=0;c<8;++c)
  242. {
  243. expandRadiusBy(bb.corner(c));
  244. }
  245. }
  246. else
  247. {
  248. _center = bb.center();
  249. _radius = bb.radius();
  250. }
  251. }
  252. }
  253. typedef BoundingSphereImpl<Vec3f> BoundingSpheref;
  254. typedef BoundingSphereImpl<Vec3d> BoundingSphered;
  255. #ifdef OSG_USE_FLOAT_BOUNDINGSPHERE
  256. typedef BoundingSpheref BoundingSphere;
  257. #else
  258. typedef BoundingSphered BoundingSphere;
  259. #endif
  260. }
  261. #endif