00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00200 Vec3f e = size->getValue() / 2.0;
00201 const Vec3f c = center->getValue();
00202
00203 Vec3f m = (from + to ) * 0.5f;
00204
00205 Vec3f d = to - m;
00206
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
00239
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
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
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
00446
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