Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
SceneBase.cpp
1 #include <GLviewer/Scenes/SceneBase.hh>
2 #include <list>
3 #include <Base/Geometry/HomgPoint3D.hh>
4 #include <Base/Geometry/HomgPlane3D.hh>
5 #include <Base/Math/Random.hh>
6 
7 using namespace std;
8 using namespace BIAS;
9 using namespace BIAS;
10 
11 double SceneBase::animationSpeed_ = 1.0;
12 
13 SceneBase::SceneBase() :
14  IsActive_(true), ActiveChannel_(C_BothMono),camera_(NULL), velocity_(0,0,0) {
15  SetColorMask();
16  mass_ = -1.0;
17  gravityImmunity_ = false;
18  elasticity_ = 0.95; // power ball
19  renderBoundingBox_ = false;
22 
23 }
24 
25 
27  if(IsActive_) {
28  GLboolean maskHist[4];
29  glGetBooleanv(GL_COLOR_WRITEMASK, maskHist);
30  glColorMask(colorMask_[0], colorMask_[1],
31  colorMask_[2], colorMask_[3]);
33  Draw();
34  glColorMask(maskHist[0], maskHist[1],
35  maskHist[2], maskHist[3]);
36 
37  }
38 }
39 
40 
41 std::list<BIAS::HomgPoint3D >
43  const BIAS::Vector3<double>& b2) {
44  std::list<BIAS::HomgPoint3D > cornerlist;
45  HomgPoint3D bcur(b1);
46  cornerlist.push_back(bcur);
47  bcur[0] = b2[0];
48  cornerlist.push_back(bcur);
49  bcur[1] = b2[1];
50  cornerlist.push_back(bcur);
51  bcur[0] = b1[0];
52  cornerlist.push_back(bcur);
53  bcur[2] = b2[2];
54  bcur[1] = b1[1];
55  cornerlist.push_back(bcur);
56  bcur[0] = b2[0];
57  cornerlist.push_back(bcur);
58  bcur[1] = b2[1];
59  cornerlist.push_back(bcur);
60  bcur[0] = b1[0];
61  cornerlist.push_back(bcur);
62  return cornerlist;
63 }
64 
65 std::list<BIAS::HomgPlane3D >
67  const BIAS::Vector3<double>& b2) {
68  std::list<HomgPlane3D > facelist;
69  facelist.push_back(HomgPlane3D(0,0,1,-b1[2]));
70  facelist.push_back(HomgPlane3D(0,0,-1,b2[2]));
71  facelist.push_back(HomgPlane3D(0,1,0,-b1[1]));
72  facelist.push_back(HomgPlane3D(0,-1,0,b2[1]));
73  facelist.push_back(HomgPlane3D(1,0,0,-b1[0]));
74  facelist.push_back(HomgPlane3D(-1,0,0,b2[0]));
75  return facelist;
76 }
77 
79  // sceneoctree has a finer colision algorithm, call that !
80  // NOT HERE, this is a base class. Derive from it and overload this method !!!
81 
82  BIAS::Vector3<double> thismin(0,0,0);
83  BIAS::Vector3<double> thismax(0,0,0);
84  GetBoundingBox(thismin, thismax);
85  BIAS::Vector3<double> othermin(0,0,0);
86  BIAS::Vector3<double> othermax(0,0,0);
87  otherScene->GetBoundingBox(othermin,othermax);
88 
89  std::list<HomgPoint3D > thiscorners =
90  CornersFromBoundingBox(thismin,thismax);
91 
92  std::list<BIAS::HomgPlane3D> otherfaces =
93  FacesFromBoundingBox(othermin, othermax);
94 
95  // simple test:
96  // for wcs-aligned bounding boxes NOT to intersect, all corner points of
97  // this must be on an outside of one of the six faces of the other
98  bool outside = true;
99  std::list<BIAS::HomgPlane3D >::iterator itfaces;
100  for (itfaces=otherfaces.begin(); itfaces!=otherfaces.end(); itfaces++) {
101  outside = true;
102  std::list<BIAS::HomgPoint3D >::iterator itcorners;
103  for (itcorners=thiscorners.begin(); itcorners!=thiscorners.end();
104  itcorners++) {
105  if (itfaces->ScalarProduct(*itcorners)>=0.0) {
106  outside = false;
107  break;
108  }
109  }
110  if (outside) {
111  break;
112  }
113  }
114 
115  return !outside;
116 }
117 
119  Vector3<double>& contactnormal) {
120 
121  // sceneoctree has a finer colision algorithm, call that !
122  // NOT HERE, this is a base class. Derive from it and overload this method !!!
123 
124  Vector3<double> relativeSpeed(velocity_ - otherScene->velocity_);
125  // BIASWARN("relative speed is "<<relativeSpeed);
126  BIAS::Vector3<double> thismin(0,0,0);
127  BIAS::Vector3<double> thismax(0,0,0);
128  GetBoundingBox(thismin, thismax);
129  BIAS::Vector3<double> othermin(0,0,0);
130  BIAS::Vector3<double> othermax(0,0,0);
131  otherScene->GetBoundingBox(othermin,othermax);
132 
133  std::list<HomgPoint3D > thiscorners =
134  CornersFromBoundingBox(thismin,thismax);
135 
136  std::list<BIAS::HomgPlane3D> otherfaces =
137  FacesFromBoundingBox(othermin, othermax);
138 
139  std::list<HomgPoint3D > othercorners =
140  CornersFromBoundingBox(othermin,othermax);
141 
142  std::list<BIAS::HomgPlane3D> thisfaces =
143  FacesFromBoundingBox(thismin, thismax);
144 
145 
146  // check which face has the earliest collision with one of the bbcorners of the other object
147  std::list<BIAS::HomgPlane3D >::iterator itfaces;
148  double besttsofar = 1e100;
149  for (itfaces=otherfaces.begin(); itfaces!=otherfaces.end(); itfaces++) {
150  std::list<BIAS::HomgPoint3D >::iterator itcorners;
151  for (itcorners=thiscorners.begin(); itcorners!=thiscorners.end();
152  itcorners++) {
153  // compute time to contact this plane:
154  double t = -1.0;
155  Vector3<double> x(itcorners->GetEuclidian());
156  Vector3<double> n(itfaces->GetNormalVector());
157  double denominator = relativeSpeed.ScalarProduct(n);
158  if (fabs(denominator)>1e-9) {
159  // movement NOT parallel to plane
160  t = (-x.ScalarProduct(n) - (*itfaces)[3]) / denominator;
161  if (t<=0.0) {
162  //BIASWARN("negative t"<<t<<" "<< *itcorners<<" "<< *itfaces <<" "
163  // <<relativeSpeed);
164  }
165  }
166 
167  if (t>0.0 && t<besttsofar) {
168  // check whether
169  Vector3<double> cp = x + t * relativeSpeed;
170 
171  if (cp[0]>=othermin[0] && cp[1]>=othermin[1] && cp[2]>=othermin[2]
172  && cp[0]<=othermax[0] && cp[1]<=othermax[1] && cp[2]<=othermax[2]){
173  besttsofar = t;
174  contactnormal = itfaces->GetNormalVector();
175  }
176  }
177  }
178  }
179 
180  // now change the roles
181  // DO NOT DELETE THIS CODE. IT IS REALLY IMPORTANT :-)
182  for (itfaces=thisfaces.begin(); itfaces!=thisfaces.end(); itfaces++) {
183  std::list<BIAS::HomgPoint3D >::iterator itcorners;
184  for (itcorners=othercorners.begin(); itcorners!=othercorners.end();
185  itcorners++) {
186  // compute time to contact this plane:
187  double t = -1.0;
188  Vector3<double> x(itcorners->GetEuclidian());
189  Vector3<double> n(itfaces->GetNormalVector());
190  double denominator = -1.0 * relativeSpeed.ScalarProduct(n);
191  if (fabs(denominator)>1e-9) {
192  // movement NOT parallel to plane
193  t = (-x.ScalarProduct(n) - (*itfaces)[3]) / denominator;
194  if (t<=0.0) {
195  // BIASWARN("negative t"<<t<<" "<< *itcorners<<" "<< *itfaces <<" "
196  // <<relativeSpeed);
197  }
198  }
199 
200  if (t>0.0 && t<besttsofar) {
201  // check whether
202  Vector3<double> cp = x + t * relativeSpeed;
203 
204  if (cp[0]>=othermin[0] && cp[1]>=othermin[1] && cp[2]>=othermin[2]
205  && cp[0]<=othermax[0] && cp[1]<=othermax[1] && cp[2]<=othermax[2]){
206  besttsofar = t;
207  contactnormal = itfaces->GetNormalVector();
208  }
209  }
210 
211  }
212  }
213 
214  return besttsofar;
215 }
216 
217 
219  const BIAS::Vector3<double>& contact) {
220 
221  // sceneoctree has a finer colision algorithm, call that !
222  // NOT HERE, this is a base class. Derive from it and overload this method !!!
223 
224  // dont collide the static surrounding, like the room
225  if (otherscene->gravityImmunity_) return;
226 
227  // cout<<"performing collision between "<<typeid(*this).name()<<" and "
228  // <<typeid(*otherscene).name()<<endl;
229 
230  // check velocities
231  if ((velocity_-otherscene->velocity_).NormL2()<1e-10) {
232  // so slow contact that they do fly peacefully near each other
233 #ifdef BIAS_DEBUG
234  BIASWARN("slow contact: "<<velocity_<<"<->"<<otherscene->velocity_
235  <<", no collision");
236 #endif
237  return;
238  } else {
239  //BIASWARN("collision velocity: "<<velocity_<<"<->"<<otherscene->velocity_);
240  }
241 
242  BIAS::Vector3<double> thismin(0,0,0),thismax(0,0,0);
243  GetBoundingBox(thismin, thismax);
244  BIAS::Vector3<double> thismean(0.5 * thismin + 0.5 * thismax);
245  //cout<<"this: "<< thismean <<" "<< thismin <<" "<<thismax <<endl;
246  BIAS::Vector3<double> othermin(0,0,0),othermax(0,0,0);
247  otherscene->GetBoundingBox(othermin,othermax);
248  BIAS::Vector3<double> othermean(0.5 * othermin + 0.5 * othermax);
249  //cout<<"other: "<< othermean <<" "<< othermin <<" "<< othermax <<endl;
250 
251 
252  // there are several ways to determine the direction of collision
253  // a) velocities, valid for points
254  // b) centers of gravity, maybe nicer for larger scenes
255 
256  BIAS::Vector3<double> collisiondirection(thismean-othermean);
257  if (contact[0]!=-1e10) {
258  // have plane normal for which collision happened
259  collisiondirection = contact;
260  }
261 
262  if (collisiondirection.NormL2()<1e-10) {
263 #ifdef BIAS_DEBUG
264  BIASWARN("collision only using velocities");
265 #endif
266  collisiondirection = velocity_-otherscene->velocity_;
267  if (collisiondirection.NormL2()<1e-10) {
268  collisiondirection = Vector3<double>(1,0,0);
269 #ifdef BIAS_DEBUG
270  BIASWARN("no collision direction could be detected, using x");
271 #endif
272  }
273  }
274  // get a real unit vector
275  collisiondirection.Normalize();
276  //BIASWARN("collision direction is "<<collisiondirection);
277 
278  // reduce to a 1D problem: compute velocities in direction of collision
279  double v1 = collisiondirection.ScalarProduct(velocity_);
280  double m1 = mass_;
281 
282  double v2 = collisiondirection.ScalarProduct(otherscene->velocity_);
283  double m2 = otherscene->mass_;
284 
285  // check if both scenes must change their velocity or whether one of them
286  // has an infinite weight (like a wall, which does not move)
287  // m<=0 means infinite weight
288  if (m1<0.0) {
289  m1 = 1;
290  m2 = 0;
291  }
292  if (m2<0.0) {
293  m1 = 0;
294  m2 = 1;
295  }
296 
297  // compute collision if it was 100% elastic (no energy/momentum loss)
298  // and then for 100% unelastic (glue together)
299 
300  // elastic collision:
301  double v1elas = ((m1-m2)* v1 + 2.0*m2*v2)/(m1+m2);
302  double v2elas = ((m2-m1)* v2 + 2.0*m1*v1)/(m1+m2);
303 
304  // plastic collision
305  double v2plas = (m1*v1 + m2*v2) / (m1+m2);
306  double v1plas = v2plas;
307 
308  // compute elasticity as a mean between the two materials
309  double elasticity = 0.5*(elasticity_ + otherscene->elasticity_);
310 
311  if (m1>=0.0) {
312  // compute new velocity as a linear combination of theoretic elastic model
313  // and theoretic unelastic model.
314  // the velocity components orthogonal to the collision dir do not change.
315  velocity_ = elasticity * (velocity_ - v1 * collisiondirection)
316  + collisiondirection * (elasticity * v1elas + (1.0-elasticity)*v1plas);
317  }
318  if (m2>=0.0) {
319  // old 3d velocity - velocity in collision direction + new vel in collision)
320  otherscene->velocity_ =
321  elasticity * (otherscene->velocity_ - v2 * collisiondirection)
322  + collisiondirection * (elasticity * v2elas + (1.0-elasticity)*v2plas);
323  }
324 }
325 
326 void SceneBase::ApplyTimeStep(const double& delta,
327  const BIAS::Vector3<double>& gravity,
328  const double& frictioncoefficient) {
329  if (mass_>0.0 && !gravityImmunity_) {
330  if (velocity_.NormL2()<1e10 || velocity_.ScalarProduct(gravity)<=0.0)
331  velocity_ += delta * gravity;
332  if (delta==1.0) {
333  velocity_ *= frictioncoefficient;
334  } else {
335  velocity_ *= pow(frictioncoefficient, delta);
336  }
337  }
338  // Random R;
339  //velocity_[0] += R.GetUniformDistributed(0.1, -0.1);
340  //velocity_[1] += R.GetUniformDistributed(0.1, -0.1);
341  //velocity_[2] += R.GetUniformDistributed(0.1, -0.1);
342  MoveScene(delta);
343 }
344 
345 void SceneBase::MoveScene(const double& delta) {
346 // BIASWARN("No movement implemented for this scene type: "<<
347 // typeid(*this).name());
348 }
349 
350 void SceneBase::DumpInfo() const {
351  cout<<"Scene type: "<<typeid(*this).name()<<endl;
352  cout<<"active "<< IsActive_ <<endl;
353  cout<<"active channel "<<ActiveChannel_<<endl;
354  cout<<"GLProjection: "<<camera_<<endl;
355  cout<<"color mask:"<<colorMask_[0]<<colorMask_[1]
356  <<colorMask_[2]<<colorMask_[3]<<endl;
357  cout<<"mass: "<<mass_<<endl;
358  cout<<"velocity: "<<velocity_<<endl;
359  cout<<"elasticity: "<<elasticity_<<endl;
360 }
361 
363  Vector3<double> bbmin,bbmax;
364  GetBoundingBox(bbmin,bbmax);
365  std::list<BIAS::HomgPoint3D > listvertices =
366  CornersFromBoundingBox(bbmin,bbmax);
367 
368  vector< Vector3<double> > vertices;
369  vertices.resize(listvertices.size());
370  list<HomgPoint3D>::iterator it = listvertices.begin();
371  int i = 0;
372  for(; it!=listvertices.end(); it++) {
373  vertices[i++] = it->GetEuclidian();
374  }
375 
376  glColor3f(255,0,0);
377  glBegin(GL_LINES);
378  glVertex3dv(vertices[0].GetData());
379  glVertex3dv(vertices[1].GetData());
380  glVertex3dv(vertices[1].GetData());
381  glVertex3dv(vertices[2].GetData());
382  glVertex3dv(vertices[2].GetData());
383  glVertex3dv(vertices[3].GetData());
384  glVertex3dv(vertices[3].GetData());
385  glVertex3dv(vertices[0].GetData());
386  glVertex3dv(vertices[4].GetData());
387  glVertex3dv(vertices[5].GetData());
388  glVertex3dv(vertices[5].GetData());
389  glVertex3dv(vertices[6].GetData());
390  glVertex3dv(vertices[6].GetData());
391  glVertex3dv(vertices[7].GetData());
392  glVertex3dv(vertices[7].GetData());
393  glVertex3dv(vertices[4].GetData());
394  glVertex3dv(vertices[0].GetData());
395  glVertex3dv(vertices[4].GetData());
396  glVertex3dv(vertices[5].GetData());
397  glVertex3dv(vertices[1].GetData());
398  glVertex3dv(vertices[2].GetData());
399  glVertex3dv(vertices[6].GetData());
400  glVertex3dv(vertices[3].GetData());
401  glVertex3dv(vertices[7].GetData());
402  glEnd();
403 
404 }
405 
406 
407 void SceneBase::AnimationAndCollision(std::vector<SceneBase*> scenes,
408  const Vector3<double>& gravity,
409  const double& friction) {
410 
411  if (animationSpeed_>0.0) {
412  // simple animation:
413  for (unsigned int i=0; i<scenes.size(); i++) {
414  // 9.81 m/s^2
415  scenes[i]->ApplyTimeStep(animationSpeed_, gravity, friction); // 0 10 0
416  }
417  // check for collision
418  for (unsigned int i=0; i<scenes.size(); i++) {
419  for (unsigned int j=i+1; j<scenes.size(); j++) {
420  if (scenes[i]->GetGravityImmunity() &&
421  scenes[j]->GetGravityImmunity()) {
422  // BIASWARN("no weight, no hit.");
423  // dont check static scene
424  continue;
425  }
426 
427  if (scenes[i]->HasBoundingBoxCollision(scenes[j])) {
428  double timetocontact = 1.0;
429  //BIASWARN("detected collision between scenes "<<i<<" and "<<j);
430  // collision ! change momentum !
431  //BIASWARN("one step back for colliding objects");
432  scenes[i]->MoveScene(-animationSpeed_);
433  scenes[j]->MoveScene(-animationSpeed_);
434 
435  Vector3<double> contactnormal(0,0,1);
436  double ttc = scenes[i]->TimeToContact(scenes[j], contactnormal);
437  if (ttc<0.0) ttc = 0.0;
438  if (ttc>animationSpeed_) ttc = animationSpeed_;
439 
440  timetocontact = ttc;
441  scenes[i]->MoveScene(timetocontact);
442  scenes[j]->MoveScene(timetocontact);
443 
444  if (isnan(contactnormal[0]) ||isnan(contactnormal[1])
445  ||isnan(contactnormal[2]) ) {
446  BIASWARN("contact normal is nan !");
447  contactnormal=Vector3<double>(-1e10,-1e10,-1e10);
448  }
449 
450  //BIASWARN("Before collision velocities are "<<scenes[i]->velocity_<<
451  // " and "<<scenes[j]->velocity_<<", now colliding");
452  scenes[i]->PerformCollision(scenes[j],contactnormal);
453  //BIASWARN("After collision velocities are "<<scenes[i]->velocity_<<
454  // " and "<<scenes[j]->velocity_);
455 
456 
457  // this would require another collision test:
458  scenes[i]->MoveScene(animationSpeed_-timetocontact);
459  scenes[j]->MoveScene(animationSpeed_-timetocontact);
460 
461  }
462  //cout<<"XXX velocities are "<<scenes_[i]->velocity_<<
463  // " and "<<scenes_[j]->velocity_<<endl;
464 
465  }
466  }
467  }
468 }
virtual void Render()
this is the entry point seen from GLProjectionParametersBase.
Definition: SceneBase.cpp:26
bool renderBoundingBox_
show the bounding box ?
Definition: SceneBase.hh:278
virtual void MoveScene(const double &delta=1.0)
this moves the scene (no rotation yet)
Definition: SceneBase.cpp:345
static double animationSpeed_
how long does a single step in time take for animations ?
Definition: SceneBase.hh:254
bool gravityImmunity_
if true, scene is not accelerated by gravity
Definition: SceneBase.hh:274
void ScalarProduct(const Vector3< T > &argvec, T &result) const
scalar product (=inner product) of two vectors, storing the result in result
Definition: Vector3.hh:603
GLboolean colorMask_[4]
Definition: SceneBase.hh:267
TRIANGLEMESH_DRAW_STYLE dTriangleMeshDrawStyle_
Definition: SceneBase.hh:261
std::list< BIAS::HomgPlane3D > FacesFromBoundingBox(const BIAS::Vector3< double > &b1, const BIAS::Vector3< double > &b2)
Definition: SceneBase.cpp:66
virtual void PerformCollision(SceneBase *otherscene, const BIAS::Vector3< double > &contactnormal=BIAS::Vector3< double >(-1e10,-1e10,-1e10))
compute momentum of each scene after collision
Definition: SceneBase.cpp:218
virtual double TimeToContact(SceneBase *otherScene, BIAS::Vector3< double > &collisionpoint)
compute time to contact of bounding boxes
Definition: SceneBase.cpp:118
bool GetGravityImmunity() const
is this scene accelerated by gravity ?
Definition: SceneBase.hh:194
virtual void Draw()=0
To do anything usefull, overload this method, assume context is ready and draw.
std::list< BIAS::HomgPoint3D > CornersFromBoundingBox(const BIAS::Vector3< double > &b1, const BIAS::Vector3< double > &b2)
Definition: SceneBase.cpp:42
void ApplyTimeStep(const double &delta=1.0, const BIAS::Vector3< double > &gravity=BIAS::Vector3< double >(0,-9.81, 0), const double &frictioncoefficient=0.999)
change position using a small time step of delta seconds and change velocity using gravity vector in ...
Definition: SceneBase.cpp:326
void DumpInfo() const
dump info about the scene
Definition: SceneBase.cpp:350
BIAS::Vector3< double > velocity_
scene velocity in m/s
Definition: SceneBase.hh:272
double mass_
for collision:
Definition: SceneBase.hh:270
POINT_DRAW_STYLE dPointDrawStyle_
Definition: SceneBase.hh:260
enum EChannel ActiveChannel_
Definition: SceneBase.hh:265
class HomgPoint3D describes a point with 3 degrees of freedom in projective coordinates.
Definition: HomgPoint3D.hh:61
virtual bool HasBoundingBoxCollision(SceneBase *otherScene)
check if bounding boxes of two scenes overlap
Definition: SceneBase.cpp:78
Base class for all scenes.
Definition: SceneBase.hh:68
static void AnimationAndCollision(std::vector< SceneBase * > scenes, const BIAS::Vector3< double > &gravity=BIAS::Vector3< double >(0, 10, 0), const double &friction=0.999)
call this method for a vector of scenes to solve the collision problem.
Definition: SceneBase.cpp:407
virtual void RenderBoundingBox()
render the bounding box of the scene using gl-lines
Definition: SceneBase.cpp:362
double elasticity_
the more elastic the less enegry is lost in collisions
Definition: SceneBase.hh:276
virtual void GetBoundingBox(BIAS::Vector3< double > &themin, BIAS::Vector3< double > &themax)
Determine and return the bouning box of all elements of the scene.
Definition: SceneBase.hh:148
Vector3< T > & Normalize()
normalize this vector to length 1
Definition: Vector3.hh:663
double NormL2() const
the L2 norm sqrt(a^2 + b^2 + c^2)
Definition: Vector3.hh:633
void SetColorMask(bool red=true, bool green=true, bool blue=true, bool alpha=true)
sets a color mask for the scene rendering
Definition: SceneBase.hh:139
BIAS::GLProjectionParametersInterface * camera_
Definition: SceneBase.hh:266
A homogeneous plane (in P^3) All points X on the plane p fulfill p &#39; * X = 0.
Definition: HomgPlane3D.hh:46