H3D API  2.4.1
Bound.h
Go to the documentation of this file.
1 // Copyright 2004-2019, SenseGraphics AB
3 //
4 // This file is part of H3D API.
5 //
6 // H3D API is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // H3D API is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with H3D API; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // A commercial license is also available. Please contact us at
21 // www.sensegraphics.com for more information.
22 //
23 //
27 //
29 #ifndef __H3DBOUND_H__
30 #define __H3DBOUND_H__
31 
32 #include <H3D/H3DApi.h>
33 #include <H3D/FieldTemplates.h>
34 #include <H3D/RefCountSField.h>
35 #include <H3D/SFVec3f.h>
36 #include <H3D/SFMatrix4f.h>
37 
39 #include <H3DUtil/Exception.h>
40 
41 namespace H3D {
44  class H3DAPI_API Bound: public RefCountedClass {
45  public:
47  virtual bool isInside( const Vec3f &p ) = 0;
48 
51  virtual bool lineSegmentIntersect( const Vec3f &from,
52  const Vec3f &to ) = 0;
53 
56  virtual bool movingSphereIntersect( const Vec3f &from,
57  const Vec3f &to,
58  H3DFloat radius ) = 0;
59 
63  template< class Iterator >
64  static inline Bound *boundUnion( Iterator begin, Iterator end );
65 
69  template< class Iterator >
70  static inline Bound *SFBoundUnion( Iterator begin, Iterator end );
71 
73  virtual Vec3f closestPoint( const Vec3f &p ) = 0;
74 
76  virtual void render() {}
77  };
78 
82  class H3DAPI_API InfiniteBound: public Bound {
83  public:
85  virtual bool isInside( const Vec3f &/*p*/ ){
86  return true;
87  }
88 
90  virtual bool lineSegmentIntersect( const Vec3f& /*from*/,
91  const Vec3f &/*to*/ ) {
92  return true;
93  }
94 
97  virtual bool movingSphereIntersect( const Vec3f &/*from*/,
98  const Vec3f &/*to*/,
99  H3DFloat /*radius*/ ) {
100  return true;
101  }
102 
103  virtual Vec3f closestPoint( const Vec3f &p ) {
104  return p;
105  }
106  };
107 
111  class H3DAPI_API EmptyBound: public Bound {
112  public:
114  virtual bool isInside( const Vec3f &/*p*/ ){
115  return false;
116  }
117 
119  virtual bool lineSegmentIntersect( const Vec3f& /*from*/,
120  const Vec3f &/*to*/ ) {
121  return false;
122  }
123 
126  virtual bool movingSphereIntersect( const Vec3f &/*from*/,
127  const Vec3f &/*to*/,
128  H3DFloat /*radius*/ ) {
129  return false;
130  }
131 
132  virtual Vec3f closestPoint( const Vec3f &p ) {
133  return p;
134  }
135  };
136 
137 
138 
144  class H3DAPI_API BoxBound: public Bound {
145  public:
146 
148  BoxBound( Inst< SFVec3f > _center = 0,
149  Inst< SFVec3f > _size = 0 ):
150  center( _center ),
151  size( _size ) {
152  // set default values
153  center->setValue( Vec3f( 0, 0, 0 ) );
154  size->setValue( Vec3f( 0, 0, 0 ) );
155  }
156 
160  template< class InputIterator >
161  void fitAroundPoints( InputIterator begin,
162  InputIterator end ) {
163  if( begin == end ) {
164  center->setValue( Vec3f( 0, 0, 0 ) );
165  size->setValue( Vec3f( 0, 0, 0 ) );
166  return;
167  }
168  InputIterator i = begin;
169  Vec3f min_p( *i );
170  Vec3f max_p( *i );
171  ++i;
172  for( ; i != end; ++i ) {
173  if( (*i).x < min_p.x ) min_p.x = (H3DFloat) (*i).x;
174  if( (*i).y < min_p.y ) min_p.y = (H3DFloat) (*i).y;
175  if( (*i).z < min_p.z ) min_p.z = (H3DFloat) (*i).z;
176  if( (*i).x > max_p.x ) max_p.x = (H3DFloat) (*i).x;
177  if( (*i).y > max_p.y ) max_p.y = (H3DFloat) (*i).y;
178  if( (*i).z > max_p.z ) max_p.z = (H3DFloat) (*i).z;
179  }
180  Vec3f s = max_p - min_p;
181  center->setValue( min_p + s / 2.0 );
182  size->setValue( s );
183  }
184 
185  template< class InputIterator >
186  void fitAround2DPoints( InputIterator begin,
187  InputIterator end ) {
188  if( begin == end ) {
189  center->setValue( Vec3f( 0, 0, 0 ) );
190  size->setValue( Vec3f( 0, 0, 0 ) );
191  return;
192  }
193  InputIterator i = begin;
194  Vec2f min_p(*i);
195  Vec2f max_p(*i);
196  ++i;
197  for( ; i != end; ++i ) {
198  if( (*i).x < min_p.x ) min_p.x = (*i).x;
199  if( (*i).y < min_p.y ) min_p.y = (*i).y;
200  if( (*i).x > max_p.x ) max_p.x = (*i).x;
201  if( (*i).y > max_p.y ) max_p.y = (*i).y;
202  }
203  Vec2f s = max_p - min_p;
204  Vec2f c = min_p + s / 2.0;
205  center->setValue( Vec3f( c.x, c.y, 0.f ) );
206  size->setValue( Vec3f( s.x, s.y, 0.f ) );
207  }
208 
210  virtual bool isInside( const Vec3f &p ){
211  Vec3f half_size = size->getValue() / 2.0;
212  const Vec3f c = center->getValue();
213  return ( p.x <= ( c.x + half_size.x ) &&
214  p.x >= ( c.x - half_size.x ) &&
215  p.y <= ( c.y + half_size.y ) &&
216  p.y >= ( c.y - half_size.y ) &&
217  p.z <= ( c.z + half_size.z ) &&
218  p.z >= ( c.z - half_size.z ) );
219  }
220 
223  virtual bool lineSegmentIntersect( const Vec3f& from,
224  const Vec3f &to ) {
225  // algorithm from "Realtime Collision Detection" book
226  Vec3f e = size->getValue() / 2.0;
227  const Vec3f c = center->getValue();
228  // line center
229  Vec3f m = (from + to ) * 0.5f;
230  // halflength vector
231  Vec3f d = to - m;
232  // translate to origin
233  m = m -c;
234 
235  H3DFloat adx = H3DAbs( d.x );
236  if( H3DAbs( m.x ) > e.x + adx ) return false;
237  H3DFloat ady = H3DAbs( d.y );
238  if( H3DAbs( m.y ) > e.y + ady ) return false;
239  H3DFloat adz = H3DAbs( d.z );
240  if( H3DAbs( m.z ) > e.z + adz ) return false;
241 
242  adx += Constants::f_epsilon;
243  ady += Constants::f_epsilon;
244  adz += Constants::f_epsilon;
245 
246  if( H3DAbs( m.y * d.z - m.z * d.y ) > e.y * adz + e.z * ady )
247  return false;
248  if( H3DAbs( m.z * d.x - m.x * d.z ) > e.x * adz + e.z * adx )
249  return false;
250  if( H3DAbs( m.x * d.y - m.y * d.x ) > e.x * ady + e.y * adx )
251  return false;
252 
253  return true;
254  }
255 
258  virtual bool movingSphereIntersect( const Vec3f &from,
259  const Vec3f &to,
260  H3DFloat radius );
261 
262  virtual Vec3f closestPoint( const Vec3f &p ) {
263  const Vec3f &c = center->getValue();
264  const Vec3f &half_s = size->getValue() / 2;
265 
266  Vec3f min = c - half_s;
267  Vec3f max = c + half_s;
268 
269  Vec3f result;
270  // for each coordinate axis, if the point coordinate value
271  // is outside box, clamp it to the box, e;se keep it as it is
272  for( int i = 0; i < 3; ++i ) {
273  H3DFloat v = p[i];
274  if( v < min[i] ) v = min[i];
275  if( v > max[i] ) v = max[i];
276  result[i] = v;
277  }
278  return result;
279  }
280 
282  virtual void render();
283 
285  H3DUniquePtr< SFVec3f > center;
287  H3DUniquePtr< SFVec3f > size;
288  };
289 
295  public:
298 
304  class Center: public TypedField< SFVec3f,
305  SFBoxBound,
306  SFMatrix4f > {
307  virtual void update() {
308  BoxBound *bb =
309  static_cast< SFBoxBound * >( routes_in[0] )->getValue();
310  if( bb ) {
311  const Matrix4f &_matrix =
312  static_cast< SFMatrix4f * >( routes_in[1] )->getValue();
313  value = _matrix * bb->center->getValue();
314  }
315  }
316  };
317 
318 
324  class Size: public TypedField< SFVec3f,
325  SFBoxBound,
326  SFMatrix4f > {
327  virtual void update() {
328  BoxBound *bb =
329  static_cast< SFBoxBound * >( routes_in[0] )->getValue();
330  const Matrix4f &_matrix =
331  static_cast< SFMatrix4f * >( routes_in[1] )->getValue();
332 
333  if (bb) {
334  const Vec3f &bb_center = bb->center->getValue();
335  const Vec3f &half_bb_size = bb->size->getValue() / 2.0;
336 
337  Vec3f trf_bb = bb_center + half_bb_size;
338  Vec3f llc_bb = bb_center - half_bb_size;
339 
340  // transform each corder and fit a new BoxBound around them.
341  vector<Vec3f> corners;
342  // +++
343  Vec3f point = trf_bb;
344  corners.push_back(_matrix * point);
345  // ++-
346  point.z = llc_bb.z;
347  corners.push_back(_matrix * point);
348  // +--
349  point.y = llc_bb.y;
350  corners.push_back(_matrix * point);
351  // +-+
352  point.z = trf_bb.z;
353  corners.push_back(_matrix * point);
354  // --+
355  point.x = llc_bb.x;
356  corners.push_back(_matrix * point);
357  // -++
358  point.y = trf_bb.y;
359  corners.push_back(_matrix * point);
360  // -+-
361  point.z = llc_bb.z;
362  corners.push_back(_matrix * point);
363  // ---
364  point.y = llc_bb.y;
365  corners.push_back(_matrix * point);
366 
367  vector< Vec3f >::iterator i = corners.begin();
368  Vec3f min = *i;
369  Vec3f max = *i;
370  ++i;
371  for (; i != corners.end(); ++i) {
372  if ((*i).x < min.x) min.x = (*i).x;
373  if ((*i).y < min.y) min.y = (*i).y;
374  if ((*i).z < min.z) min.z = (*i).z;
375  if ((*i).x > max.x) max.x = (*i).x;
376  if ((*i).y > max.y) max.y = (*i).y;
377  if ((*i).z > max.z) max.z = (*i).z;
378  }
379  value = max - min;
380  }
381  }
382  };
383 
386  Inst< Center > _center = 0,
387  Inst< Size > _size = 0,
388  Inst< SFMatrix4f > _matrix = 0,
389  Inst< SFBoxBound > _boxBound = 0 ) :
390  BoxBound( _center, _size ),
391  matrix( _matrix ),
392  boxBound( _boxBound ) {
393 
394  boxBound->route( center );
395  matrix->route( center );
396 
397  boxBound->route( size );
398  matrix->route( size );
399  }
401  H3DUniquePtr< SFMatrix4f > matrix;
403  H3DUniquePtr< SFBoxBound > boxBound;
404  };
405 
406 
409  namespace BoundInternal {
410  template< class Iterator >
411  inline Bound *SFBoundGetBound( const Iterator &i ) {
412  return static_cast< RefCountSField< Bound > * >(*i)->getValue();
413  }
414 
415  template< class Iterator >
416  inline Bound *boundGetBound( const Iterator &i ) {
417  return *i;
418  }
419 
422  template< class Iterator >
423  inline Bound *boundUnionBase( Iterator begin,
424  Iterator end,
425  Bound *(*getBound) ( const Iterator & ) ) {
426  BoxBound *box_bound = NULL;
427  for( Iterator i = begin; i != end; ++i ) {
428  Bound *b = getBound( i );
429  if( b ) {
430  BoxBound *bb = dynamic_cast< BoxBound * >( b );
431 
432  if( bb ) {
433  if( !box_bound ) {
434  box_bound = new BoxBound;
435  box_bound->center->setValue( bb->center->getValue() );
436  box_bound->size->setValue( bb->size->getValue() );
437  } else {
438  const Vec3f &union_center = box_bound->center->getValue();
439  const Vec3f &half_union_size = box_bound->size->getValue()/2.0;
440  const Vec3f &bb_center = bb->center->getValue();
441  const Vec3f &half_bb_size = bb->size->getValue()/2.0;
442 
443  Vec3f trf_union = union_center + half_union_size;
444  Vec3f llc_union = union_center - half_union_size;
445  Vec3f trf_bb = bb_center + half_bb_size;
446  Vec3f llc_bb = bb_center - half_bb_size;
447 
448  Vec3f trf_new =
449  Vec3f( trf_union.x > trf_bb.x ? trf_union.x: trf_bb.x,
450  trf_union.y > trf_bb.y ? trf_union.y: trf_bb.y,
451  trf_union.z > trf_bb.z ? trf_union.z: trf_bb.z );
452 
453  Vec3f llc_new =
454  Vec3f( llc_union.x < llc_bb.x ? llc_union.x: llc_bb.x,
455  llc_union.y < llc_bb.y ? llc_union.y: llc_bb.y,
456  llc_union.z < llc_bb.z ? llc_union.z: llc_bb.z );
457  Vec3f new_size = trf_new - llc_new;
458  Vec3f new_center = llc_new + new_size / 2.0;
459  box_bound->center->setValue( new_center );
460  box_bound->size->setValue( new_size );
461  }
462  } else {
463  InfiniteBound *ib = dynamic_cast< InfiniteBound * >( b );
464  if( ib ) {
465  if( box_bound ) delete box_bound;
466  return new InfiniteBound;
467  } else {
468  EmptyBound *eb = dynamic_cast< EmptyBound * >( b );
469  if( eb ) {
470  // do nothing
471  } else {
472  stringstream s;
473  s << "Unsupported Bound type "
474  << typeid( *(b) ).name();
476  }
477  }
478  }
479  }
480  }
481  if( box_bound )
482  return box_bound;
483  else
484  // There were no Bounds specified by the iterators so return an
485  // EmptyBound.
486  return new EmptyBound;
487  }
488  }
489 
490  template< class Iterator >
491  inline Bound *Bound::boundUnion( Iterator begin,
492  Iterator end ) {
493  using namespace BoundInternal;
494  return boundUnionBase( begin, end, boundGetBound< Iterator > );
495  }
496 
497  template< class Iterator >
498  inline Bound *Bound::SFBoundUnion( Iterator begin,
499  Iterator end ) {
500  using namespace BoundInternal;
501  return boundUnionBase( begin, end, SFBoundGetBound< Iterator > );
502  }
503 }
504 
505 #endif
Bound * boundUnionBase(Iterator begin, Iterator end, Bound *(*getBound)(const Iterator &))
Returns a Bound that is the union between all the bounds.
Definition: Bound.h:423
#define H3D_FULL_LOCATION
Contains different templates to modify field behaviour.
Base header file that handles all configuration related settings.
Contains the RefCountSField class.
Contains the SFMatrix4f field class.
Contains the SFVec3f field class.
The Bound class is the abstract base class for all classes specifying bounding objects.
Definition: Bound.h:44
virtual bool isInside(const Vec3f &p)=0
Determines if a given point is inside the bound or not.
virtual bool lineSegmentIntersect(const Vec3f &from, const Vec3f &to)=0
Checks a line segment for intersection with the bound.
static Bound * SFBoundUnion(Iterator begin, Iterator end)
Returns a Bound that is the union between the Bound objects in the SFBound fields specified by the it...
Definition: Bound.h:498
virtual void render()
Render the outline of the bound with OpenGL.
Definition: Bound.h:76
virtual Vec3f closestPoint(const Vec3f &p)=0
Returns the closest point on the bound to the given point.
static Bound * boundUnion(Iterator begin, Iterator end)
Returns a Bound that is the union between all the bounds specified by the iterators.
Definition: Bound.h:491
virtual bool movingSphereIntersect(const Vec3f &from, const Vec3f &to, H3DFloat radius)=0
Checks a moving sphere for intersection with the bound.
The BoxBound is a Bound class that specifies the bound using an axis-aligned bounding box.
Definition: Bound.h:144
BoxBound(Inst< SFVec3f > _center=0, Inst< SFVec3f > _size=0)
Constructor.
Definition: Bound.h:148
virtual Vec3f closestPoint(const Vec3f &p)
Returns the closest point on the bound to the given point.
Definition: Bound.h:262
virtual bool lineSegmentIntersect(const Vec3f &from, const Vec3f &to)
Checks a line segment for intersection with the bound.
Definition: Bound.h:223
virtual bool isInside(const Vec3f &p)
Determines if a given point is inside the bound or not.
Definition: Bound.h:210
void fitAroundPoints(InputIterator begin, InputIterator end)
This function sets the BoxBound to encompass all the points between the begin and end iterators.
Definition: Bound.h:161
H3DUniquePtr< SFVec3f > center
The center point of the bounding box.
Definition: Bound.h:285
H3DUniquePtr< SFVec3f > size
The size of the bounding box.
Definition: Bound.h:287
An EmptyBound is a Bound that encompasses nothing.
Definition: Bound.h:111
virtual bool isInside(const Vec3f &)
Determines if a given point is inside the bound or not.
Definition: Bound.h:114
virtual Vec3f closestPoint(const Vec3f &p)
Returns the closest point on the bound to the given point.
Definition: Bound.h:132
virtual bool lineSegmentIntersect(const Vec3f &, const Vec3f &)
Returns false always.
Definition: Bound.h:119
virtual bool movingSphereIntersect(const Vec3f &, const Vec3f &, H3DFloat)
Checks a moving sphere for intersection with the bound.
Definition: Bound.h:126
An InfiniteBound is a Bound that encompasses everything.
Definition: Bound.h:82
virtual bool movingSphereIntersect(const Vec3f &, const Vec3f &, H3DFloat)
Checks a moving sphere for intersection with the bound.
Definition: Bound.h:97
virtual Vec3f closestPoint(const Vec3f &p)
Returns the closest point on the bound to the given point.
Definition: Bound.h:103
virtual bool isInside(const Vec3f &)
Determines if a given point is inside the bound or not.
Definition: Bound.h:85
virtual bool lineSegmentIntersect(const Vec3f &, const Vec3f &)
Returns true always.
Definition: Bound.h:90
RefCountSField is almost like any SField but it encapsulates a pointer to a RefCountedClass.
Definition: RefCountSField.h:42
virtual RefClass * getValue(int id=0)
Get the value of the field.
Definition: RefCountSField.h:217
The SFMatrix4f field contains a Matrix4f.
Definition: SFMatrix4f.h:41
virtual const Vec3f & getValue(int id=0)
Get the value of the field.
Definition: SField.h:235
Vec3f value
The encapsulated value.
Definition: SField.h:176
The Center field updates itself from the boxBound and matrix fields.
Definition: Bound.h:306
The Size field updates itself from the boxBound and matrix fields.
Definition: Bound.h:326
A TransformedBoxBound is a wrapper around another BoxBound and its values are the values of the BoxBo...
Definition: Bound.h:294
RefCountSField< BoxBound > SFBoxBound
The BoxBound object is reference counted by the field.
Definition: Bound.h:297
H3DUniquePtr< SFBoxBound > boxBound
The BoxBound which values are to be transformed.
Definition: Bound.h:403
TransformedBoxBound(Inst< Center > _center=0, Inst< Size > _size=0, Inst< SFMatrix4f > _matrix=0, Inst< SFBoxBound > _boxBound=0)
Constructor.
Definition: Bound.h:385
H3DUniquePtr< SFMatrix4f > matrix
The matrix to transform with.
Definition: Bound.h:401
A template modifier class for adding type checking on the routes to any Field class.
Definition: TypedField.h:84
F H3DAbs(F f)
Vec2f()
float H3DFloat
H3D API namespace.
Definition: Anchor.h:38