| 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 | |
|---|
| 14 | #ifndef OSG_BOUNDINGBOX |
|---|
| 15 | #define OSG_BOUNDINGBOX 1 |
|---|
| 16 | |
|---|
| 17 | #include <osg/Config> |
|---|
| 18 | #include <osg/Export> |
|---|
| 19 | #include <osg/Vec3> |
|---|
| 20 | #include <osg/Vec3d> |
|---|
| 21 | #include <float.h> |
|---|
| 22 | |
|---|
| 23 | namespace osg { |
|---|
| 24 | |
|---|
| 25 | template<typename VT> |
|---|
| 26 | class BoundingSphereImpl; |
|---|
| 27 | |
|---|
| 28 | /** General purpose axis-aligned bounding box class for enclosing objects/vertices. |
|---|
| 29 | * Bounds leaf objects in a scene such as osg::Drawable objects. Used for frustum |
|---|
| 30 | * culling etc. |
|---|
| 31 | */ |
|---|
| 32 | template<typename VT> |
|---|
| 33 | class BoundingBoxImpl |
|---|
| 34 | { |
|---|
| 35 | public: |
|---|
| 36 | typedef VT vec_type; |
|---|
| 37 | typedef typename VT::value_type value_type; |
|---|
| 38 | |
|---|
| 39 | /** Minimum extent. (Smallest X, Y, and Z values of all coordinates.) */ |
|---|
| 40 | vec_type _min; |
|---|
| 41 | /** Maximum extent. (Greatest X, Y, and Z values of all coordinates.) */ |
|---|
| 42 | vec_type _max; |
|---|
| 43 | |
|---|
| 44 | /** Creates an uninitialized bounding box. */ |
|---|
| 45 | inline BoundingBoxImpl() : |
|---|
| 46 | _min(FLT_MAX, |
|---|
| 47 | FLT_MAX, |
|---|
| 48 | FLT_MAX), |
|---|
| 49 | _max(-FLT_MAX, |
|---|
| 50 | -FLT_MAX, |
|---|
| 51 | -FLT_MAX) |
|---|
| 52 | {} |
|---|
| 53 | |
|---|
| 54 | /** Creates a bounding box initialized to the given extents. */ |
|---|
| 55 | inline BoundingBoxImpl(value_type xmin, value_type ymin, value_type zmin, |
|---|
| 56 | value_type xmax, value_type ymax, value_type zmax) : |
|---|
| 57 | _min(xmin,ymin,zmin), |
|---|
| 58 | _max(xmax,ymax,zmax) {} |
|---|
| 59 | |
|---|
| 60 | /** Creates a bounding box initialized to the given extents. */ |
|---|
| 61 | inline BoundingBoxImpl(const vec_type& min,const vec_type& max) : |
|---|
| 62 | _min(min), |
|---|
| 63 | _max(max) {} |
|---|
| 64 | |
|---|
| 65 | /** Clear the bounding box. Erases existing minimum and maximum extents. */ |
|---|
| 66 | inline void init() |
|---|
| 67 | { |
|---|
| 68 | _min.set(FLT_MAX, |
|---|
| 69 | FLT_MAX, |
|---|
| 70 | FLT_MAX); |
|---|
| 71 | _max.set(-FLT_MAX, |
|---|
| 72 | -FLT_MAX, |
|---|
| 73 | -FLT_MAX); |
|---|
| 74 | } |
|---|
| 75 | |
|---|
| 76 | /** Returns true if the bounding box extents are valid, false otherwise. */ |
|---|
| 77 | inline bool valid() const |
|---|
| 78 | { |
|---|
| 79 | return _max.x()>=_min.x() && _max.y()>=_min.y() && _max.z()>=_min.z(); |
|---|
| 80 | } |
|---|
| 81 | |
|---|
| 82 | /** Sets the bounding box extents. */ |
|---|
| 83 | inline void set (value_type xmin, value_type ymin, value_type zmin, |
|---|
| 84 | value_type xmax, value_type ymax, value_type zmax) |
|---|
| 85 | { |
|---|
| 86 | _min.set(xmin,ymin,zmin); |
|---|
| 87 | _max.set(xmax,ymax,zmax); |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | /** Sets the bounding box extents. */ |
|---|
| 91 | inline void set(const vec_type& min,const vec_type& max) |
|---|
| 92 | { |
|---|
| 93 | _min = min; |
|---|
| 94 | _max = max; |
|---|
| 95 | } |
|---|
| 96 | |
|---|
| 97 | |
|---|
| 98 | inline value_type& xMin() { return _min.x(); } |
|---|
| 99 | inline value_type xMin() const { return _min.x(); } |
|---|
| 100 | |
|---|
| 101 | inline value_type& yMin() { return _min.y(); } |
|---|
| 102 | inline value_type yMin() const { return _min.y(); } |
|---|
| 103 | |
|---|
| 104 | inline value_type& zMin() { return _min.z(); } |
|---|
| 105 | inline value_type zMin() const { return _min.z(); } |
|---|
| 106 | |
|---|
| 107 | inline value_type& xMax() { return _max.x(); } |
|---|
| 108 | inline value_type xMax() const { return _max.x(); } |
|---|
| 109 | |
|---|
| 110 | inline value_type& yMax() { return _max.y(); } |
|---|
| 111 | inline value_type yMax() const { return _max.y(); } |
|---|
| 112 | |
|---|
| 113 | inline value_type& zMax() { return _max.z(); } |
|---|
| 114 | inline value_type zMax() const { return _max.z(); } |
|---|
| 115 | |
|---|
| 116 | /** Calculates and returns the bounding box center. */ |
|---|
| 117 | inline const vec_type center() const |
|---|
| 118 | { |
|---|
| 119 | return (_min+_max)*0.5; |
|---|
| 120 | } |
|---|
| 121 | |
|---|
| 122 | /** Calculates and returns the bounding box radius. */ |
|---|
| 123 | inline value_type radius() const |
|---|
| 124 | { |
|---|
| 125 | return sqrt(radius2()); |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | /** Calculates and returns the squared length of the bounding box radius. |
|---|
| 129 | * Note, radius2() is faster to calculate than radius(). */ |
|---|
| 130 | inline value_type radius2() const |
|---|
| 131 | { |
|---|
| 132 | return 0.25*((_max-_min).length2()); |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | /** Returns a specific corner of the bounding box. |
|---|
| 136 | * pos specifies the corner as a number between 0 and 7. |
|---|
| 137 | * Each bit selects an axis, X, Y, or Z from least- to |
|---|
| 138 | * most-significant. Unset bits select the minimum value |
|---|
| 139 | * for that axis, and set bits select the maximum. */ |
|---|
| 140 | inline const vec_type corner(unsigned int pos) const |
|---|
| 141 | { |
|---|
| 142 | return vec_type(pos&1?_max.x():_min.x(),pos&2?_max.y():_min.y(),pos&4?_max.z():_min.z()); |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | /** Expands the bounding box to include the given coordinate. |
|---|
| 146 | * If the box is uninitialized, set its min and max extents to v. */ |
|---|
| 147 | inline void expandBy(const vec_type& v) |
|---|
| 148 | { |
|---|
| 149 | if(v.x()<_min.x()) _min.x() = v.x(); |
|---|
| 150 | if(v.x()>_max.x()) _max.x() = v.x(); |
|---|
| 151 | |
|---|
| 152 | if(v.y()<_min.y()) _min.y() = v.y(); |
|---|
| 153 | if(v.y()>_max.y()) _max.y() = v.y(); |
|---|
| 154 | |
|---|
| 155 | if(v.z()<_min.z()) _min.z() = v.z(); |
|---|
| 156 | if(v.z()>_max.z()) _max.z() = v.z(); |
|---|
| 157 | } |
|---|
| 158 | |
|---|
| 159 | /** Expands the bounding box to include the given coordinate. |
|---|
| 160 | * If the box is uninitialized, set its min and max extents to |
|---|
| 161 | * Vec3(x,y,z). */ |
|---|
| 162 | inline void expandBy(value_type x,value_type y,value_type z) |
|---|
| 163 | { |
|---|
| 164 | if(x<_min.x()) _min.x() = x; |
|---|
| 165 | if(x>_max.x()) _max.x() = x; |
|---|
| 166 | |
|---|
| 167 | if(y<_min.y()) _min.y() = y; |
|---|
| 168 | if(y>_max.y()) _max.y() = y; |
|---|
| 169 | |
|---|
| 170 | if(z<_min.z()) _min.z() = z; |
|---|
| 171 | if(z>_max.z()) _max.z() = z; |
|---|
| 172 | } |
|---|
| 173 | |
|---|
| 174 | /** Expands this bounding box to include the given bounding box. |
|---|
| 175 | * If this box is uninitialized, set it equal to bb. */ |
|---|
| 176 | void expandBy(const BoundingBoxImpl& bb) |
|---|
| 177 | { |
|---|
| 178 | if (!bb.valid()) return; |
|---|
| 179 | |
|---|
| 180 | if(bb._min.x()<_min.x()) _min.x() = bb._min.x(); |
|---|
| 181 | if(bb._max.x()>_max.x()) _max.x() = bb._max.x(); |
|---|
| 182 | |
|---|
| 183 | if(bb._min.y()<_min.y()) _min.y() = bb._min.y(); |
|---|
| 184 | if(bb._max.y()>_max.y()) _max.y() = bb._max.y(); |
|---|
| 185 | |
|---|
| 186 | if(bb._min.z()<_min.z()) _min.z() = bb._min.z(); |
|---|
| 187 | if(bb._max.z()>_max.z()) _max.z() = bb._max.z(); |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | /** Expands this bounding box to include the given sphere. |
|---|
| 191 | * If this box is uninitialized, set it to include sh. */ |
|---|
| 192 | void expandBy(const BoundingSphereImpl<VT>& sh) |
|---|
| 193 | { |
|---|
| 194 | if (!sh.valid()) return; |
|---|
| 195 | |
|---|
| 196 | if(sh._center.x()-sh._radius<_min.x()) _min.x() = sh._center.x()-sh._radius; |
|---|
| 197 | if(sh._center.x()+sh._radius>_max.x()) _max.x() = sh._center.x()+sh._radius; |
|---|
| 198 | |
|---|
| 199 | if(sh._center.y()-sh._radius<_min.y()) _min.y() = sh._center.y()-sh._radius; |
|---|
| 200 | if(sh._center.y()+sh._radius>_max.y()) _max.y() = sh._center.y()+sh._radius; |
|---|
| 201 | |
|---|
| 202 | if(sh._center.z()-sh._radius<_min.z()) _min.z() = sh._center.z()-sh._radius; |
|---|
| 203 | if(sh._center.z()+sh._radius>_max.z()) _max.z() = sh._center.z()+sh._radius; |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | |
|---|
| 207 | /** Returns the intersection of this bounding box and the specified bounding box. */ |
|---|
| 208 | BoundingBoxImpl intersect(const BoundingBoxImpl& bb) const |
|---|
| 209 | { return BoundingBoxImpl(osg::maximum(xMin(),bb.xMin()),osg::maximum(yMin(),bb.yMin()),osg::maximum(zMin(),bb.zMin()), |
|---|
| 210 | osg::minimum(xMax(),bb.xMax()),osg::minimum(yMax(),bb.yMax()),osg::minimum(zMax(),bb.zMax())); |
|---|
| 211 | |
|---|
| 212 | } |
|---|
| 213 | |
|---|
| 214 | /** Return true if this bounding box intersects the specified bounding box. */ |
|---|
| 215 | bool intersects(const BoundingBoxImpl& bb) const |
|---|
| 216 | { return osg::maximum(xMin(),bb.xMin()) <= osg::minimum(xMax(),bb.xMax()) && |
|---|
| 217 | osg::maximum(yMin(),bb.yMin()) <= osg::minimum(yMax(),bb.yMax()) && |
|---|
| 218 | osg::maximum(zMin(),bb.zMin()) <= osg::minimum(zMax(),bb.zMax()); |
|---|
| 219 | |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | /** Returns true if this bounding box contains the specified coordinate. */ |
|---|
| 223 | inline bool contains(const vec_type& v) const |
|---|
| 224 | { |
|---|
| 225 | return valid() && |
|---|
| 226 | (v.x()>=_min.x() && v.x()<=_max.x()) && |
|---|
| 227 | (v.y()>=_min.y() && v.y()<=_max.y()) && |
|---|
| 228 | (v.z()>=_min.z() && v.z()<=_max.z()); |
|---|
| 229 | } |
|---|
| 230 | }; |
|---|
| 231 | |
|---|
| 232 | typedef BoundingBoxImpl<Vec3f> BoundingBoxf; |
|---|
| 233 | typedef BoundingBoxImpl<Vec3d> BoundingBoxd; |
|---|
| 234 | |
|---|
| 235 | #ifdef OSG_USE_FLOAT_BOUNDINGBOX |
|---|
| 236 | typedef BoundingBoxf BoundingBox; |
|---|
| 237 | #else |
|---|
| 238 | typedef BoundingBoxd BoundingBox; |
|---|
| 239 | #endif |
|---|
| 240 | |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | #endif |
|---|