contrib/brl/bbas/bgui3d/bgui3d_viewer_tableau.cxx
Go to the documentation of this file.
00001 // This is brl/bbas/bgui3d/bgui3d_viewer_tableau.cxx
00002 #include "bgui3d_viewer_tableau.h"
00003 //:
00004 // \file
00005 
00006 #include <vcl_iostream.h>
00007 #include <vcl_cassert.h>
00008 #include <vcl_cmath.h>
00009 #include "bgui3d_algo.h"
00010 #include <vgui/vgui_gl.h>
00011 #include <vnl/vnl_quaternion.h>
00012 #include <vnl/vnl_double_3x3.h>
00013 #include <vnl/vnl_double_3x4.h>
00014 #include <vnl/vnl_double_3.h>
00015 #include <vnl/vnl_det.h>
00016 
00017 #include <vgl/vgl_point_2d.h>
00018 #include <vgl/vgl_point_3d.h>
00019 #include <vgl/algo/vgl_rotation_3d.h>
00020 #include <vpgl/vpgl_perspective_camera.h>
00021 
00022 #include <Inventor/nodes/SoOrthographicCamera.h>
00023 #include <Inventor/nodes/SoPerspectiveCamera.h>
00024 
00025 #include <Inventor/nodes/SoSeparator.h>
00026 #include <Inventor/SoDB.h>
00027 #include <Inventor/SbViewportRegion.h>
00028 #include <Inventor/nodes/SoNode.h>
00029 #include <Inventor/nodes/SoSwitch.h>
00030 #include <Inventor/VRMLnodes/SoVRMLViewpoint.h>
00031 #include <Inventor/SoSceneManager.h>
00032 
00033 #include <Inventor/nodes/SoDirectionalLight.h>
00034 #include <Inventor/actions/SoSearchAction.h>
00035 #include <Inventor/nodekits/SoBaseKit.h>
00036 #include <Inventor/actions/SoGetBoundingBoxAction.h>
00037 #include <Inventor/actions/SoGetMatrixAction.h>
00038 #include <Inventor/nodes/SoText2.h>
00039 
00040 #include <Inventor/nodes/SoTranslation.h>
00041 #include <Inventor/sensors/SoAlarmSensor.h>
00042 
00043 //: Constructor
00044 bgui3d_viewer_tableau::bgui3d_viewer_tableau(SoNode * scene_root)
00045  : bgui3d_tableau(NULL),
00046    user_scene_root_(NULL),
00047    camera_group_(NULL),
00048    scene_camera_(NULL),
00049    stored_camera_(NULL),
00050    headlight_(NULL)
00051 {
00052   this->set_scene_root(scene_root);
00053 }
00054 
00055 
00056 //: Destructor
00057 bgui3d_viewer_tableau::~bgui3d_viewer_tableau()
00058 {
00059   if (scene_camera_)
00060     scene_camera_->unref();
00061   if (headlight_)
00062     headlight_->unref();
00063 }
00064 
00065 
00066 void
00067 bgui3d_viewer_tableau::set_scene_root(SoNode* scene_root)
00068 {
00069   if (!scene_root)
00070     bgui3d_tableau::set_scene_root(scene_root);
00071 
00072   user_scene_root_ = scene_root;
00073 
00074   // Build the super scene graph
00075   SoSeparator *super_root = new SoSeparator;
00076   super_root->setName("bgui3d_viewer_root");
00077 
00078   // Create a headlight if one does not exist
00079   // By inserting this before any scenegraph camera, the
00080   // light will always be pointing in the correct direction.
00081   if (!headlight_) {
00082     headlight_ = new SoDirectionalLight;
00083     headlight_->direction.setValue(1, -1, -10);
00084     headlight_->setName("headlight");
00085     headlight_->ref();
00086   }
00087   super_root->addChild(headlight_);
00088 
00089   // add the text and its translation to shift it to the top right
00090   SoTranslation* trans = new SoTranslation;
00091   trans->translation = SbVec3f(-.98f,.93f,0);
00092   super_root->addChild( trans );
00093 
00094   text_ = new SoText2;
00095   text_->string.deleteValues(0, -1); // empty the string
00096   super_root->addChild( text_ );
00097 
00098   //: Make a group of all the cameras in the scene
00099   camera_group_ = new SoSwitch;
00100   camera_group_->setName("bgui3dCameraGroup");
00101   super_root->addChild(camera_group_);
00102 
00103   // Make the default Camera
00104   SoCamera* camera = (SoCamera*)SoPerspectiveCamera::getClassTypeId().createInstance();
00105   camera->setName("Examiner_Camera");
00106   camera_group_->addChild(camera);
00107   camera->nearDistance = 0.5f;
00108   camera->farDistance = 1000.0f;
00109 
00110   // Set the camera to view the whole scene
00111   camera->viewAll(scene_root, get_viewport_region());
00112 
00113   // find existing VRML viewpoints in the scene and make cameras
00114   this->collect_vrml_cameras(scene_root);
00115 
00116   // find and used the first user scene camera (if it exists)
00117   vcl_vector<SoCamera*> user_cams = find_cameras(user_scene_root_);
00118   if (!user_cams.empty()) {
00119     camera_group_->whichChild.setValue(-1);
00120     this->set_camera(user_cams[0]);
00121   }
00122   else {
00123     // if not, use the first examiner camera
00124     assert(camera_group_->getChildren()->getLength() > 0);
00125 
00126     if (camera_group_->whichChild.getValue() < 0)
00127       camera_group_->whichChild.setValue(0);
00128     int cam_idx = camera_group_->whichChild.getValue();
00129 
00130     SoChildList* list = camera_group_->getChildren();
00131     this->set_camera((SoCamera*)(*list)[cam_idx]);
00132   }
00133 
00134   // The users scene should be added last
00135   if (scene_root)
00136     super_root->addChild(scene_root);
00137 
00138   bgui3d_tableau::set_scene_root(super_root);
00139 
00140   save_home_position();
00141 }
00142 
00143 
00144 //--------------Camera Methods--------------------
00145 
00146 //: Set the camera viewing the scene
00147 // \note this does not add the camera to a scene graph
00148 void
00149 bgui3d_viewer_tableau::set_camera(SoCamera *camera)
00150 {
00151   if (scene_camera_) {
00152     scene_camera_->unref();
00153   }
00154 
00155   scene_camera_ = camera;
00156 
00157   if (scene_camera_) {
00158     scene_camera_->ref();
00159     SoType cam_type = scene_camera_->getTypeId();
00160     if ( cam_type == SoOrthographicCamera::getClassTypeId() )
00161       camera_type_ = ORTHOGONAL;
00162     else
00163       camera_type_ = PERSPECTIVE;
00164   }
00165 }
00166 
00167 
00168 //: Set the scene camera
00169 // Generate an SoCamera from a camera matrix and use it
00170 // \note Only handles perspective cameras for now
00171 bool
00172 bgui3d_viewer_tableau::set_camera(const vpgl_proj_camera<double>& camera)
00173 {
00174   SoPerspectiveCamera* new_cam = new SoPerspectiveCamera;
00175   new_cam->ref();
00176   new_cam->setName("Camera_Matrix");
00177 
00178   vnl_double_3x3 K, R;
00179   vnl_double_3 t;
00180 
00181   vnl_double_3x4 cam = camera.get_matrix();
00182   if (vnl_det(vnl_double_3x3(cam.extract(3,3))) < 0)
00183     cam *= -1.0;
00184   if ( bgui3d_decompose_camera(cam, K, R, t) ) {
00185     new_cam->aspectRatio = float(K[0][2]/K[1][2]);
00186     new_cam->heightAngle = float(2*vcl_atan2(K[1][2],K[1][1]));
00187 
00188     vnl_double_3 C = -R.transpose()*t;
00189     new_cam->position.setValue( float(C[0]), float(C[1]), float(C[2]) );
00190 
00191     // the identity camera requires a 180 degree rotation about the
00192     // x-axis to project to images with the origin in the upper left
00193     R.scale_row(1,-1);
00194     R.scale_row(2,-1);
00195 
00196     // create a rotation matrix
00197     SbMatrix rot = SbMatrix::identity();
00198 
00199     for (int i=0; i<3; ++i)
00200       for ( int j=0; j<3; ++j)
00201         rot[j][i] = float(R[j][i]);
00202 
00203     new_cam->orientation.setValue(SbRotation(rot));
00204 
00205     new_cam->nearDistance = 1.0f;
00206     new_cam->farDistance = 1000.0f;
00207   }
00208 
00209   if ( user_scene_root_ ) {
00210     camera_group_->addChild(new_cam);
00211     int num_cameras = camera_group_->getChildren()->getLength();
00212     this->select_camera(num_cameras -1);
00213     this->set_camera(new_cam);
00214 
00215     this->set_clipping_planes();
00216   }
00217 
00218   new_cam->unref();
00219 
00220   return true;
00221 }
00222 
00223 
00224 //: Get the scene camera.
00225 // Creates a vpgl camera (either perspective or affine) from the active SoCamera
00226 vcl_auto_ptr<vpgl_proj_camera<double> >
00227 bgui3d_viewer_tableau::camera() const
00228 {
00229   if (!scene_camera_)
00230     return vcl_auto_ptr<vpgl_proj_camera<double> >(NULL);
00231 
00232   const SbVec3f& t_vec = scene_camera_->position.getValue();
00233   vnl_double_3 t(t_vec[0], t_vec[1], t_vec[2]);
00234 
00235   float q1,q2,q3,q4;
00236   scene_camera_->orientation.getValue().getValue(q1,q2,q3,q4);
00237   // inverse and rotate 180 degrees around Z
00238   vgl_rotation_3d<double> R(vnl_quaternion<double>(q2,-q1,q4,q3));
00239 
00240   GLint vp[4];
00241   glGetIntegerv(GL_VIEWPORT, vp);
00242   unsigned width = vp[2];
00243   unsigned height = vp[3];
00244 
00245   switch (camera_type_)
00246   {
00247    case PERSPECTIVE: {
00248     SoPerspectiveCamera* cam = (SoPerspectiveCamera*)scene_camera_;
00249     double f = 1.0/(vcl_tan(cam->heightAngle.getValue()/2.0));
00250     double sx = 1.0, sy = 1.0;
00251     if (width < height)
00252       sy = double(width)/height;
00253     else
00254       sx = double(height)/width;
00255     vgl_point_2d<double> p(0, 0);
00256     vpgl_calibration_matrix<double> K(f,p,sx,sy);
00257     vgl_point_3d<double> c(t[0],t[1],t[2]);
00258     return vcl_auto_ptr<vpgl_proj_camera<double> >
00259            ( new vpgl_perspective_camera<double>(K,c,R) );
00260     }
00261    case ORTHOGONAL:
00262 #if 0
00263     SoOrthographicCamera* cam = (SoOrthographicCamera*)scene_camera_;
00264     double h = cam->height.getValue();
00265 #endif // 0
00266     vcl_cerr << "WARNING: not implemented yet\n";
00267     return vcl_auto_ptr<vpgl_proj_camera<double> >(NULL);
00268    default:
00269     vcl_cerr << "WARNING: no such camera_type_\n";
00270     return vcl_auto_ptr<vpgl_proj_camera<double> >(NULL);
00271   }
00272 }
00273 
00274 
00275 //: Select the active camera by index.
00276 // A negative index selects the first user scene camera
00277 void
00278 bgui3d_viewer_tableau::select_camera(int camera_index)
00279 {
00280   int num_cameras = camera_group_->getChildren()->getLength();
00281 
00282   if (camera_index >= 0 && camera_index < num_cameras) {
00283     if (camera_index != camera_group_->whichChild.getValue()) {
00284       camera_group_->whichChild.setValue(camera_index);
00285       SoChildList* list = camera_group_->getChildren();
00286       this->set_camera((SoCamera*)(*list)[camera_index]);
00287     }
00288   }
00289   else {
00290     vcl_vector<SoCamera*> user_cams = find_cameras(user_scene_root_);
00291     if (!user_cams.empty()) {
00292       camera_group_->whichChild.setValue(-1);
00293       this->set_camera(user_cams[0]);
00294     }
00295   }
00296 }
00297 
00298 
00299 //: Return the camera viewing the scene
00300 SoCamera*
00301 bgui3d_viewer_tableau::camera_node() const
00302 {
00303   // FIX ME
00304   return scene_camera_;
00305 }
00306 
00307 
00308 //: Set the camera type (Perspective or Orthogonal)
00309 void
00310 bgui3d_viewer_tableau::set_camera_type(camera_type_enum type)
00311 {
00312   SoType ptype = SoPerspectiveCamera::getClassTypeId();
00313   SoType otype = SoOrthographicCamera::getClassTypeId();
00314   SoCamera* newCamera;
00315   if ( camera_type_ != type )
00316   {
00317     if ( camera_type_ == PERSPECTIVE && type == ORTHOGONAL )
00318     {
00319       newCamera = (SoCamera *)otype.createInstance();
00320       convertPerspective2Ortho((SoPerspectiveCamera*)scene_camera_, (SoOrthographicCamera*)newCamera);
00321     }
00322     else if ( camera_type_ == ORTHOGONAL && type == PERSPECTIVE )
00323     {
00324       newCamera = (SoCamera *)ptype.createInstance();
00325       convertOrtho2Perspective((SoOrthographicCamera*)scene_camera_, (SoPerspectiveCamera*)newCamera);
00326     }
00327     else
00328       assert(!"This camera type is not supported");
00329 
00330     newCamera->ref();
00331     vcl_vector<SoGroup *> cameraparents = get_parents_of_node(this->scene_camera_);
00332     for (vcl_vector<SoGroup *>::iterator cp = cameraparents.begin(); cp != cameraparents.end(); ++cp)
00333     {
00334       (*cp)->replaceChild((*cp)->findChild(this->scene_camera_), newCamera);
00335     }
00336 
00337     this->set_camera(newCamera);
00338 
00339     camera_group_->whichChild.setValue(camera_group_->findChild(this->scene_camera_));
00340     newCamera->unref();
00341   }
00342 }
00343 
00344 
00345 //: Return the camera type (Perspective or Orthogonal)
00346 bgui3d_viewer_tableau::camera_type_enum
00347 bgui3d_viewer_tableau::camera_type() const
00348 {
00349   return camera_type_;
00350 }
00351 
00352 
00353 //: Toggle the camera type between Perspective and Orthogonal
00354 void
00355 bgui3d_viewer_tableau::toggle_camera_type()
00356 {
00357   if (camera_type_ == ORTHOGONAL)
00358     set_camera_type(PERSPECTIVE);
00359   else
00360     set_camera_type(ORTHOGONAL);
00361 }
00362 
00363 
00364 //: Adjust the camera to view the entire scene
00365 void
00366 bgui3d_viewer_tableau::view_all()
00367 {
00368   scene_camera_->viewAll( user_scene_root_, get_viewport_region() );
00369 }
00370 
00371 
00372 //: Save the current camera as the home position
00373 void
00374 bgui3d_viewer_tableau::save_home_position()
00375 {
00376   if (! this->scene_camera_) return; // probably a scene-less viewer
00377 
00378   // We use SoType::createInstance() to store a copy of the camera,
00379   // not just assuming it's either a perspective or an orthographic
00380   // camera.
00381 
00382   SoType t = this->scene_camera_->getTypeId();
00383   assert(t.isDerivedFrom(SoNode::getClassTypeId()));
00384   assert(t.canCreateInstance());
00385 
00386   if (this->stored_camera_)
00387     this->stored_camera_->unref();
00388 
00389   this->stored_camera_ = (SoNode *)t.createInstance();
00390   this->stored_camera_->ref();
00391   this->stored_camera_->copyContents(this->scene_camera_, false);
00392 }
00393 
00394 
00395 //: Restore the saved home position of the camera
00396 void
00397 bgui3d_viewer_tableau::reset_to_home_position()
00398 {
00399   if (! this->scene_camera_) { return; } // probably a scene-less viewer
00400   if (! this->stored_camera_) { return; }
00401 
00402   SoType t = this->scene_camera_->getTypeId();
00403   SoType s = this->stored_camera_->getTypeId();
00404 
00405   // most common case
00406   if (t == s) {
00407     this->scene_camera_->copyContents(this->stored_camera_, false);
00408   }
00409   // handle common case #1
00410   else if (t == SoOrthographicCamera::getClassTypeId() &&
00411            s == SoPerspectiveCamera::getClassTypeId()) {
00412     this->convertPerspective2Ortho((SoPerspectiveCamera *)this->stored_camera_,
00413                                    (SoOrthographicCamera *)this->scene_camera_);
00414     camera_type_ = ORTHOGONAL;
00415   }
00416   // handle common case #2
00417   else if (t == SoPerspectiveCamera::getClassTypeId() &&
00418            s == SoOrthographicCamera::getClassTypeId()) {
00419     this->convertOrtho2Perspective((SoOrthographicCamera *)this->stored_camera_,
00420                                    (SoPerspectiveCamera *)this->scene_camera_);
00421     camera_type_ = PERSPECTIVE;
00422   }
00423   // otherwise, cameras have changed in ways we don't understand since
00424   // the last saveHomePosition() invocation, and so we're just going
00425   // to ignore the reset request
00426 }
00427 
00428 //-------------------------------------------------
00429 
00430 //-------------Headlight Methods-------------------
00431 
00432 //: Activate a headlight
00433 void
00434 bgui3d_viewer_tableau::set_headlight(bool enable)
00435 {
00436   headlight_->on = enable;
00437 }
00438 
00439 
00440 //: Is the headlight active
00441 bool
00442 bgui3d_viewer_tableau::is_headlight() const
00443 {
00444   return headlight_->on.getValue() != 0;
00445 }
00446 
00447 
00448 //: Return the headlight
00449 SoDirectionalLight*
00450 bgui3d_viewer_tableau::headlight() const
00451 {
00452   return headlight_;
00453 }
00454 
00455 //-------------------------------------------------
00456 
00457 //-------------Text2 Methods-------------------
00458 
00459 static void setTextCallback( void *data, SoSensor * /*sensor*/ )
00460 {
00461   ((SoText2*)data)->string.deleteValues(0, 1);
00462 }
00463 
00464 void bgui3d_viewer_tableau::setText( const vcl_string& string )
00465 {
00466   int numStrings = text_->string.getNum();
00467   text_->string.set1Value( numStrings, string.c_str() );
00468   SoAlarmSensor* alarm = new SoAlarmSensor( setTextCallback, text_ );
00469   alarm->setTimeFromNow( 7.0 );
00470   alarm->schedule();
00471 }
00472 
00473 //---------------------------------------------------
00474 
00475 //: convert camera to perspective
00476 void
00477 bgui3d_viewer_tableau::convertOrtho2Perspective(const SoOrthographicCamera * in,
00478                                                 SoPerspectiveCamera * out)
00479 {
00480   out->aspectRatio.setValue(in->aspectRatio.getValue());
00481   out->focalDistance.setValue(in->focalDistance.getValue());
00482   out->orientation.setValue(in->orientation.getValue());
00483   out->position.setValue(in->position.getValue());
00484   out->viewportMapping.setValue(in->viewportMapping.getValue());
00485   out->setName(in->getName());
00486 
00487   float focaldist = in->focalDistance.getValue();
00488 
00489   // focalDistance==0.0f happens for empty scenes.
00490   if (focaldist != 0.0f) {
00491     out->heightAngle = 2.0f * (float)vcl_atan(in->height.getValue() / 2.0 / focaldist);
00492   }
00493   else {
00494     // 45?is the default value of this field in SoPerspectiveCamera.
00495     out->heightAngle = (float)(M_PI / 4.0);
00496   }
00497 }
00498 
00499 
00500 //: convert camera to orthographic
00501 void
00502 bgui3d_viewer_tableau::convertPerspective2Ortho(const SoPerspectiveCamera * in,
00503                                                 SoOrthographicCamera * out)
00504 {
00505   out->aspectRatio.setValue(in->aspectRatio.getValue());
00506   out->focalDistance.setValue(in->focalDistance.getValue());
00507   out->orientation.setValue(in->orientation.getValue());
00508   out->position.setValue(in->position.getValue());
00509   out->viewportMapping.setValue(in->viewportMapping.getValue());
00510   out->setName(in->getName());
00511 
00512   float focaldist = in->focalDistance.getValue();
00513 
00514   out->height = 2.0f * focaldist * (float)vcl_tan(in->heightAngle.getValue() / 2.0);
00515 }
00516 
00517 void
00518 bgui3d_viewer_tableau::set_clipping_planes()
00519 {
00520   SoGetBoundingBoxAction action( get_viewport_region() );
00521 
00522   action.apply( scene_root_ );
00523 
00524   SbXfBox3f xbox = action.getXfBoundingBox();
00525 
00526   SbMatrix cammat;
00527 
00528   SoSearchAction searchaction;
00529   searchaction.reset();
00530   searchaction.setSearchingAll(TRUE);
00531   searchaction.setInterest(SoSearchAction::FIRST);
00532   searchaction.setNode(scene_camera_);
00533   searchaction.apply(scene_root_);
00534 
00535   SoGetMatrixAction matrixaction(get_viewport_region());
00536   SbMatrix inverse = SbMatrix::identity();
00537   if (searchaction.getPath()) {
00538     matrixaction.apply(searchaction.getPath());
00539     inverse = matrixaction.getInverse();
00540   }
00541 
00542   xbox.transform(inverse);
00543 
00544   SbMatrix mat;
00545   mat.setTranslate(- scene_camera_->position.getValue());
00546   xbox.transform(mat);
00547   mat = scene_camera_->orientation.getValue().inverse();
00548   xbox.transform(mat);
00549   SbBox3f box = xbox.project();
00550 
00551   // Bounding box was calculated in camera space, so we need to "flip"
00552   // the box (because camera is pointing in the (0,0,-1) direction
00553   // from origo.
00554   float nearval = -box.getMax()[2];
00555   float farval = -box.getMin()[2];
00556 
00557   // FIXME: what if we have a weird scale transform in the scenegraph?
00558   // Could we end up with nearval > farval then? Investigate, then
00559   // either use an assert() (if it can't happen) or an SoWinSwap()
00560   // (to handle it). 20020116 mortene.
00561 
00562   // Check if scene is completely behind us.
00563   if (farval <= 0.0f) { return; }
00564 
00565   if ( scene_camera_->isOfType(SoPerspectiveCamera::getClassTypeId())) {
00566     // Disallow negative and small near clipping plane distance.
00567 
00568     float nearlimit; // the smallest value allowed for nearval
00569 #if 0
00570     if (this->autoclipstrategy == SoWinViewer::CONSTANT_NEAR_PLANE) {
00571       nearlimit = this->autoclipvalue;
00572     }
00573     else {
00574       assert(this->autoclipstrategy == SoWinViewer::VARIABLE_NEAR_PLANE);
00575 #endif // 0
00576       // From glFrustum() documentation: Depth-buffer precision is
00577       // affected by the values specified for znear and zfar. The
00578       // greater the ratio of zfar to znear is, the less effective the
00579       // depth buffer will be at distinguishing between surfaces that
00580       // are near each other. If r = far/near, roughly log (2) r bits
00581       // of depth buffer precision are lost. Because r approaches
00582       // infinity as znear approaches zero, you should never set znear
00583       // to zero.
00584       GLint depthbits[1];
00585       // assume 16-bit depth
00586       // it is unsafe to use GL functions here because a GL context
00587       // might not have been created yet.
00588       depthbits[0] = 16;
00589 #if 0
00590       glGetIntegerv(GL_DEPTH_BITS, depthbits);
00591 #endif // 0
00592 
00593       int use_bits = (int) (float(depthbits[0]) * 0.4f + 0.001f);
00594       float r = (float)(1 << use_bits);
00595       nearlimit = farval / r;
00596 #if 0
00597     }
00598 #endif // 0
00599 
00600     if (nearlimit >= farval) {
00601       // (The "5000" magic constant was found by fiddling around a bit
00602       // on an OpenGL implementation with a 16-bit depth-buffer
00603       // resolution, adjusting to find something that would work well
00604       // with both a very "stretched" / deep scene and a more compact
00605       // single-model one.)
00606       nearlimit = farval / 5000.0f;
00607     }
00608 
00609     // adjust the near plane if the value is too small.
00610     if (nearval < nearlimit) {
00611       nearval = nearlimit;
00612     }
00613 
00614 #if 0
00615     if (this->autoclipcb) {
00616       SbVec2f nearfar;
00617       nearfar[0] = nearval;
00618       nearfar[1] = farval;
00619 
00620       nearfar = this->autoclipcb(this->autoclipuserdata, nearfar);
00621 
00622       nearval = nearfar[0];
00623       farval = nearfar[1];
00624     }
00625 #endif // 0
00626   }
00627   // Some slack around the bounding box, in case the scene fits
00628   // exactly inside it. This is done to minimize the chance of
00629   // artefacts caused by the limitation of the z-buffer
00630   // resolution. One common artefact if this is not done is that the
00631   // near clipping plane cuts into the corners of the model as it's
00632   // rotated.
00633   const float SLACK = 0.001f;
00634 
00635   // FrustumCamera can be found in the SmallChange CVS module. We
00636   // should not change the nearDistance for this camera, as this will
00637   // modify the frustum.
00638   if (scene_camera_->getTypeId().getName() == "FrustumCamera") {
00639     nearval = scene_camera_->nearDistance.getValue();
00640     farval *= (1.0f + SLACK);
00641     if (farval <= nearval) {
00642       // nothing is visible, so just set farval to som value > nearval.
00643       farval = nearval + 10.0f;
00644     }
00645     scene_camera_->farDistance = farval;
00646   }
00647   else {
00648     scene_camera_->nearDistance = nearval * (1.0f - SLACK);
00649     scene_camera_->farDistance = farval * (1.0f + SLACK);
00650   }
00651 }
00652 
00653 
00654 vcl_vector<SoGroup*>
00655 bgui3d_viewer_tableau::get_parents_of_node(SoNode * node)
00656 {
00657   SbBool oldsearch = SoBaseKit::isSearchingChildren();
00658   SoBaseKit::setSearchingChildren(TRUE);
00659 
00660   assert(node && "get_parent_of_node() called with null argument");
00661 
00662   SoSearchAction search;
00663   search.setSearchingAll(TRUE);
00664   search.setNode(node);
00665   search.setInterest(SoSearchAction::ALL);
00666   search.apply(this->scene_root());
00667   SoPathList & pl = search.getPaths();
00668 
00669   vcl_vector<SoGroup*> parents;
00670   for (int i = 0; i < pl.getLength(); ++i) {
00671     SoFullPath * p = (SoFullPath*) pl[i];
00672     if (p->getLength() > 0)
00673       parents.push_back((SoGroup*)p->getNodeFromTail(1));
00674   }
00675   SoBaseKit::setSearchingChildren(oldsearch);
00676   return parents;
00677 }
00678 
00679 
00680 vcl_vector<SoCamera*>
00681 bgui3d_viewer_tableau::find_cameras(SoNode* root) const
00682 {
00683   assert(camera_group_);
00684   SoSearchAction sa;
00685 
00686   // Search for existing cameras
00687   sa.setType(SoCamera::getClassTypeId());
00688   sa.setInterest(SoSearchAction::ALL);
00689   sa.setSearchingAll(TRUE);
00690   sa.apply(root);
00691   SoPathList & pl = sa.getPaths();
00692 
00693   vcl_vector<SoCamera*> cameras;
00694   for (int i = 0; i < pl.getLength(); ++i) {
00695     SoFullPath * p = (SoFullPath*) pl[i];
00696     if (p->getTail()->isOfType(SoCamera::getClassTypeId())) {
00697       SoCamera * camera = (SoCamera*) p->getTail();
00698       cameras.push_back(camera);
00699     }
00700   }
00701   sa.reset();
00702 
00703   return cameras;
00704 }
00705 
00706 
00707 //: Find the VRML viewpoint nodes in the scenegraph and make camera.
00708 // The cameras are added to the camera group (outside the user scene)
00709 void bgui3d_viewer_tableau::collect_vrml_cameras(SoNode* root) const
00710 {
00711   assert(camera_group_);
00712   SoSearchAction sa;
00713 
00714   // Search for VRML viewpoints and create cameras
00715   sa.setType(SoVRMLViewpoint::getClassTypeId());
00716   sa.setInterest(SoSearchAction::ALL);
00717   sa.setSearchingAll(TRUE);
00718   sa.apply(root);
00719   SoPathList & pl2 = sa.getPaths();
00720 
00721   for (int i = 0; i < pl2.getLength(); ++i) {
00722     SoFullPath * p = (SoFullPath*) pl2[i];
00723     if (p->getTail()->isOfType(SoVRMLViewpoint::getClassTypeId())) {
00724       SoVRMLViewpoint * vp = (SoVRMLViewpoint*) p->getTail();
00725       SoPerspectiveCamera * camera = (SoPerspectiveCamera *)
00726           SoPerspectiveCamera::getClassTypeId().createInstance();
00727       camera->nearDistance = 0.5f;
00728       camera->farDistance = 5000.0f;
00729       camera->position = vp->position;
00730       camera->orientation = vp->orientation;
00731       camera->heightAngle = vp->fieldOfView;
00732       camera->setName(vp->description.getValue());
00733       camera_group_->addChild( camera );
00734     }
00735   }
00736   sa.reset();
00737 }