Bound.h

Go to the documentation of this file.
00001 
00003 //    Copyright 2004, SenseGraphics AB
00004 //
00005 //    This file is part of H3D API.
00006 //
00007 //    H3D API is free software; you can redistribute it and/or modify
00008 //    it under the terms of the GNU General Public License as published by
00009 //    the Free Software Foundation; either version 2 of the License, or
00010 //    (at your option) any later version.
00011 //
00012 //    H3D API is distributed in the hope that it will be useful,
00013 //    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //    GNU General Public License for more details.
00016 //
00017 //    You should have received a copy of the GNU General Public License
00018 //    along with H3D API; if not, write to the Free Software
00019 //    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 //    A commercial license is also available. Please contact us at 
00022 //    www.sensegraphics.com for more information.
00023 //
00024 //
00028 //
00030 #ifndef __H3DBOUND_H__
00031 #define __H3DBOUND_H__
00032 
00033 #include "H3DApi.h"
00034 #include "FieldTemplates.h"
00035 #include "RefCountedClass.h"
00036 #include "RefCountSField.h"
00037 #include "Exception.h"
00038 #include "SFVec3f.h"
00039 #include "SFMatrix4f.h"
00040 
00041 namespace H3D {
00044   class H3DAPI_API Bound: public RefCountedClass {
00045   public:
00047     virtual bool isInside( const Vec3f &p ) = 0;
00048 
00051     virtual bool lineSegmentIntersect( const Vec3f& from,
00052                                        const Vec3f &to ) = 0;
00053 
00057     template< class Iterator >
00058     static inline Bound *boundUnion( Iterator begin, Iterator end );
00059 
00063     template< class Iterator >
00064     static inline Bound *SFBoundUnion( Iterator begin, Iterator end );
00065 
00066     virtual Vec3f closestPoint( const Vec3f &p ) = 0;
00067   };
00068 
00072   class H3DAPI_API InfiniteBound: public Bound {
00073   public:
00075     virtual bool isInside( const Vec3f &p ){ 
00076       return true;
00077     }
00078 
00080     virtual bool lineSegmentIntersect( const Vec3f& from,
00081                                        const Vec3f &to ) {
00082       return true;
00083     }
00084     
00085     virtual Vec3f closestPoint( const Vec3f &p ) {
00086       return p;
00087     }
00088   };  
00089 
00093   class H3DAPI_API EmptyBound: public Bound {
00094   public:
00096     virtual bool isInside( const Vec3f &p ){ 
00097       return false;
00098     }
00099 
00101     virtual bool lineSegmentIntersect( const Vec3f& from,
00102                                        const Vec3f &to ) {
00103       return false;
00104     }
00105 
00106     virtual Vec3f closestPoint( const Vec3f &p ) {
00107       return p;
00108     }
00109   };  
00110 
00111   
00112   
00118   class H3DAPI_API BoxBound: public Bound {
00119   public:
00120     
00122     BoxBound( Inst< SFVec3f > _center = 0,
00123               Inst< SFVec3f > _size   = 0 ):
00124       center( _center ),
00125       size( _size ) {
00126       // set default values
00127       center->setValue( Vec3f( 0, 0, 0 ) );
00128       size->setValue( Vec3f( 0, 0, 0 ) );
00129     }
00130 
00134     template< class InputIterator >
00135     void fitAroundPoints( InputIterator begin,
00136                           InputIterator end ) {
00137       if( begin == end ) {
00138         center->setValue( Vec3f( 0, 0, 0 ) );
00139         size->setValue( Vec3f( 0, 0, 0 ) );
00140         return;
00141       }
00142       InputIterator i = begin;
00143       Vec3f min = *i;
00144       Vec3f max = *i;
00145       i++;
00146       for( ; i != end; ++i ) {
00147         if( (*i).x < min.x ) min.x = (*i).x;
00148         if( (*i).y < min.y ) min.y = (*i).y;
00149         if( (*i).z < min.z ) min.z = (*i).z;
00150         if( (*i).x > max.x ) max.x = (*i).x;
00151         if( (*i).y > max.y ) max.y = (*i).y;
00152         if( (*i).z > max.z ) max.z = (*i).z;
00153       }
00154       Vec3f s = max - min;
00155       center->setValue( min + s / 2.0 );
00156       size->setValue( s );
00157     }
00158 
00159     template< class InputIterator >
00160     void fitAround2DPoints( InputIterator begin,
00161                             InputIterator end ) {
00162       if( begin == end ) {
00163         center->setValue( Vec3f( 0, 0, 0 ) );
00164         size->setValue( Vec3f( 0, 0, 0 ) );
00165         return;
00166       }
00167       InputIterator i = begin;
00168       Vec2f min = *i;
00169       Vec2f max = *i;
00170       i++;
00171       for( ; i != end; ++i ) {
00172         if( (*i).x < min.x ) min.x = (*i).x;
00173         if( (*i).y < min.y ) min.y = (*i).y;
00174         if( (*i).x > max.x ) max.x = (*i).x;
00175         if( (*i).y > max.y ) max.y = (*i).y;
00176       }
00177       Vec2f s = max - min;
00178       Vec2f c = min + s / 2.0;
00179       center->setValue( Vec3f( c.x, c.y, 0.f ) );
00180       size->setValue( Vec3f( s.x, s.y, 0.f ) );
00181     }
00182 
00184     virtual bool isInside( const Vec3f &p ){ 
00185       Vec3f half_size = size->getValue() / 2.0;
00186       const Vec3f c = center->getValue();
00187       return ( p.x <= ( c.x + half_size.x ) &&
00188                p.x >= ( c.x - half_size.x ) &&
00189                p.y <= ( c.y + half_size.y ) &&
00190                p.y >= ( c.y - half_size.y ) &&
00191                p.z <= ( c.z + half_size.z ) &&
00192                p.z >= ( c.z - half_size.z ) );
00193     }
00194 
00197     virtual bool lineSegmentIntersect( const Vec3f& from,
00198                                        const Vec3f &to ) {
00199       // algorithm from "Realtime Collision Detection" book
00200       Vec3f e = size->getValue() / 2.0; 
00201       const Vec3f c = center->getValue();       
00202       // line center
00203       Vec3f m = (from + to ) * 0.5f;
00204       // halflength vector
00205       Vec3f d = to - m;
00206       // translate to origin
00207       m = m -c; 
00208       
00209       H3DFloat adx = H3DAbs( d.x );
00210       if( H3DAbs( m.x ) > e.x + adx ) return false;
00211       H3DFloat ady = H3DAbs( d.y );
00212       if( H3DAbs( m.y ) > e.y + ady ) return false;
00213       H3DFloat adz = H3DAbs( d.z );
00214       if( H3DAbs( m.z ) > e.z + adz ) return false;
00215 
00216       adx += Constants::f_epsilon;
00217       ady += Constants::f_epsilon;
00218       adz += Constants::f_epsilon;
00219 
00220       if( H3DAbs( m.y * d.z - m.z * d.y ) > e.y * adz + e.z * ady ) 
00221         return false;
00222       if( H3DAbs( m.z * d.x - m.x * d.z ) > e.x * adz + e.z * adx ) 
00223         return false;
00224       if( H3DAbs( m.x * d.y - m.y * d.x ) > e.x * ady + e.y * adx ) 
00225         return false;
00226 
00227       return true;
00228     }
00229 
00230     virtual Vec3f closestPoint( const Vec3f &p ) {
00231       const Vec3f &c = center->getValue();
00232       const Vec3f &half_s = size->getValue() / 2;
00233       
00234       Vec3f min = c - half_s;
00235       Vec3f max = c + half_s;
00236 
00237       Vec3f result;
00238       // for each coordinate axis, if the point coordinate value
00239       // is outside box, clamp it to the box, e;se keep it as it is
00240       for( int i = 0; i < 3; i++ ) {
00241         H3DFloat v = p[i];
00242         if( v < min[i] ) v = min[i];
00243         if( v > max[i] ) v = max[i];
00244         result[i] = v;
00245       }
00246       return result;
00247     }
00248 
00250     auto_ptr< SFVec3f > center;
00252     auto_ptr< SFVec3f > size;
00253   };  
00254 
00259   class TransformedBoxBound: public BoxBound {
00260   public:
00262     typedef RefCountSField< BoxBound > SFBoxBound;
00263     
00269     class Center: public TypedField< SFVec3f,
00270                   SFBoxBound,
00271                   SFMatrix4f > {
00272       virtual void update() {
00273         BoxBound *bb = 
00274           static_cast< SFBoxBound * >( routes_in[0] )->getValue();
00275         const Matrix4f &matrix = 
00276           static_cast< SFMatrix4f * >( routes_in[1] )->getValue();
00277         value = matrix * bb->center->getValue();
00278       }
00279     };
00280 
00281     
00287     class Size: public TypedField< SFVec3f,
00288                 SFBoxBound,
00289                 SFMatrix4f > {
00290       virtual void update() {
00291         BoxBound *bb = 
00292           static_cast< SFBoxBound * >( routes_in[0] )->getValue();
00293         const Matrix4f &matrix = 
00294           static_cast< SFMatrix4f * >( routes_in[1] )->getValue();
00295   
00296         const Vec3f &bb_center       = bb->center->getValue();
00297         const Vec3f &half_bb_size    = bb->size->getValue()/2.0;
00298   
00299         Vec3f trf_bb = bb_center + half_bb_size;
00300         Vec3f llc_bb = bb_center - half_bb_size;
00301 
00302         // transform each corder and fit a new BoxBound around them.
00303         vector<Vec3f> corners;
00304         // +++
00305         Vec3f point = trf_bb;
00306         corners.push_back( matrix * point );
00307         // ++-
00308         point.z = llc_bb.z;
00309         corners.push_back( matrix * point );
00310         // +--
00311         point.y = llc_bb.y;
00312         corners.push_back( matrix * point );
00313         // +-+
00314         point.z = trf_bb.z;
00315         corners.push_back( matrix * point );
00316         // --+
00317         point.x = llc_bb.x;
00318         corners.push_back( matrix * point );
00319         // -++
00320         point.y = trf_bb.y;
00321         corners.push_back( matrix * point );
00322         // -+-
00323         point.z = llc_bb.z;
00324         corners.push_back( matrix * point );
00325         // ---
00326         point.y = llc_bb.y;
00327         corners.push_back( matrix * point );
00328   
00329         vector< Vec3f >::iterator i = corners.begin();
00330         Vec3f min = *i;
00331         Vec3f max = *i;
00332         i++;
00333         for( ; i != corners.end(); ++i ) {
00334           if( (*i).x < min.x ) min.x = (*i).x;
00335           if( (*i).y < min.y ) min.y = (*i).y;
00336           if( (*i).z < min.z ) min.z = (*i).z;
00337           if( (*i).x > max.x ) max.x = (*i).x;
00338           if( (*i).y > max.y ) max.y = (*i).y;
00339           if( (*i).z > max.z ) max.z = (*i).z;
00340         }
00341         value = max - min;
00342       }
00343     };
00344     
00346     TransformedBoxBound( 
00347                         Inst< Center > _center = 0,
00348                         Inst< Size > _size   = 0,
00349                         Inst< SFMatrix4f >  _matrix = 0,
00350                         Inst< SFBoxBound >  _boxBound = 0 ) :
00351       BoxBound( _center, _size ),
00352       matrix( _matrix ),
00353       boxBound( _boxBound ) {
00354       
00355       boxBound->route( center );
00356       matrix->route( center );
00357       
00358       boxBound->route( size );
00359       matrix->route( size );
00360     }
00362     auto_ptr< SFMatrix4f >  matrix;
00364     auto_ptr< SFBoxBound >  boxBound;
00365   };
00366 
00367 
00370   namespace BoundInternal { 
00371     template< class Iterator >
00372     inline Bound *SFBoundGetBound( const Iterator &i ) {
00373       return static_cast< RefCountSField< Bound > * >(*i)->getValue();
00374     }
00375     
00376     template< class Iterator >
00377     inline Bound *boundGetBound( const Iterator &i ) {
00378       return *i;
00379     }
00380     
00383     template< class Iterator >
00384     inline Bound *boundUnionBase( Iterator begin, 
00385                                   Iterator end,
00386                                   Bound *(*getBound) ( const Iterator & ) ) {
00387       BoxBound *box_bound = NULL;
00388       for( Iterator i = begin; i != end; i++ ) {
00389         Bound *b = getBound( i );
00390         if( b ) {
00391           BoxBound *bb = dynamic_cast< BoxBound * >( b );
00392           
00393           if( bb ) {
00394             if( !box_bound ) {
00395               box_bound = new BoxBound;
00396               box_bound->center->setValue( bb->center->getValue() );
00397               box_bound->size->setValue( bb->size->getValue() );
00398             } else {
00399               const Vec3f &union_center    = box_bound->center->getValue(); 
00400               const Vec3f &half_union_size = box_bound->size->getValue()/2.0; 
00401               const Vec3f &bb_center       = bb->center->getValue();
00402               const Vec3f &half_bb_size    = bb->size->getValue()/2.0;
00403               
00404               Vec3f trf_union = union_center + half_union_size;
00405               Vec3f llc_union = union_center - half_union_size;
00406               Vec3f trf_bb = bb_center + half_bb_size;
00407               Vec3f llc_bb = bb_center - half_bb_size;
00408               
00409               Vec3f trf_new = 
00410                 Vec3f( trf_union.x > trf_bb.x ? trf_union.x: trf_bb.x,
00411                        trf_union.y > trf_bb.y ? trf_union.y: trf_bb.y,
00412                        trf_union.z > trf_bb.z ? trf_union.z: trf_bb.z );
00413               
00414               Vec3f llc_new = 
00415                 Vec3f( llc_union.x < llc_bb.x ? llc_union.x: llc_bb.x,
00416                        llc_union.y < llc_bb.y ? llc_union.y: llc_bb.y,
00417                        llc_union.z < llc_bb.z ? llc_union.z: llc_bb.z );
00418               Vec3f new_size = trf_new - llc_new;
00419               Vec3f new_center = llc_new + new_size / 2.0;
00420               box_bound->center->setValue( new_center );
00421               box_bound->size->setValue( new_size );
00422             }
00423           } else {
00424             InfiniteBound *ib = dynamic_cast< InfiniteBound * >( b );
00425             if( ib ) {
00426               if( box_bound ) delete box_bound;
00427               return new InfiniteBound;
00428             } else {
00429               EmptyBound *eb = dynamic_cast< EmptyBound * >( b );
00430               if( eb ) {
00431                 // do nothing
00432               } else {
00433                 stringstream s;
00434                 s << "Unsupported Bound type " 
00435                   << typeid( *(b) ).name();
00436                 throw Exception::H3DAPIException( s.str(), H3D_FULL_LOCATION );
00437               }
00438             }
00439           }
00440         }
00441       }
00442       if( box_bound )
00443         return box_bound;
00444       else 
00445         // There were no Bounds specified by the iterators so return an 
00446         // EmptyBound.
00447         return new EmptyBound;
00448     }
00449   }
00450 
00451   template< class Iterator >
00452   inline Bound *Bound::boundUnion( Iterator begin, 
00453                                    Iterator end ) {
00454     using namespace BoundInternal;
00455     return boundUnionBase( begin, end, boundGetBound< Iterator > );
00456   }
00457   
00458   template< class Iterator >
00459   inline Bound *Bound::SFBoundUnion( Iterator begin, 
00460                                      Iterator end ) {
00461     using namespace BoundInternal;
00462     return boundUnionBase( begin, end, SFBoundGetBound< Iterator > );
00463   }
00464 }
00465 
00466 #endif

Generated on Thu Aug 24 12:38:32 2006 for H3D API by  doxygen 1.4.5