00001
00002 #include "bgui3d_viewer_tableau.h"
00003
00004
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
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
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
00075 SoSeparator *super_root = new SoSeparator;
00076 super_root->setName("bgui3d_viewer_root");
00077
00078
00079
00080
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
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);
00096 super_root->addChild( text_ );
00097
00098
00099 camera_group_ = new SoSwitch;
00100 camera_group_->setName("bgui3dCameraGroup");
00101 super_root->addChild(camera_group_);
00102
00103
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
00111 camera->viewAll(scene_root, get_viewport_region());
00112
00113
00114 this->collect_vrml_cameras(scene_root);
00115
00116
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
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
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
00145
00146
00147
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
00169
00170
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
00192
00193 R.scale_row(1,-1);
00194 R.scale_row(2,-1);
00195
00196
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
00225
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
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
00276
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
00300 SoCamera*
00301 bgui3d_viewer_tableau::camera_node() const
00302 {
00303
00304 return scene_camera_;
00305 }
00306
00307
00308
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
00346 bgui3d_viewer_tableau::camera_type_enum
00347 bgui3d_viewer_tableau::camera_type() const
00348 {
00349 return camera_type_;
00350 }
00351
00352
00353
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
00365 void
00366 bgui3d_viewer_tableau::view_all()
00367 {
00368 scene_camera_->viewAll( user_scene_root_, get_viewport_region() );
00369 }
00370
00371
00372
00373 void
00374 bgui3d_viewer_tableau::save_home_position()
00375 {
00376 if (! this->scene_camera_) return;
00377
00378
00379
00380
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
00396 void
00397 bgui3d_viewer_tableau::reset_to_home_position()
00398 {
00399 if (! this->scene_camera_) { return; }
00400 if (! this->stored_camera_) { return; }
00401
00402 SoType t = this->scene_camera_->getTypeId();
00403 SoType s = this->stored_camera_->getTypeId();
00404
00405
00406 if (t == s) {
00407 this->scene_camera_->copyContents(this->stored_camera_, false);
00408 }
00409
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
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
00424
00425
00426 }
00427
00428
00429
00430
00431
00432
00433 void
00434 bgui3d_viewer_tableau::set_headlight(bool enable)
00435 {
00436 headlight_->on = enable;
00437 }
00438
00439
00440
00441 bool
00442 bgui3d_viewer_tableau::is_headlight() const
00443 {
00444 return headlight_->on.getValue() != 0;
00445 }
00446
00447
00448
00449 SoDirectionalLight*
00450 bgui3d_viewer_tableau::headlight() const
00451 {
00452 return headlight_;
00453 }
00454
00455
00456
00457
00458
00459 static void setTextCallback( void *data, SoSensor * )
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
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
00490 if (focaldist != 0.0f) {
00491 out->heightAngle = 2.0f * (float)vcl_atan(in->height.getValue() / 2.0 / focaldist);
00492 }
00493 else {
00494
00495 out->heightAngle = (float)(M_PI / 4.0);
00496 }
00497 }
00498
00499
00500
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
00552
00553
00554 float nearval = -box.getMax()[2];
00555 float farval = -box.getMin()[2];
00556
00557
00558
00559
00560
00561
00562
00563 if (farval <= 0.0f) { return; }
00564
00565 if ( scene_camera_->isOfType(SoPerspectiveCamera::getClassTypeId())) {
00566
00567
00568 float nearlimit;
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
00577
00578
00579
00580
00581
00582
00583
00584 GLint depthbits[1];
00585
00586
00587
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
00602
00603
00604
00605
00606 nearlimit = farval / 5000.0f;
00607 }
00608
00609
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
00628
00629
00630
00631
00632
00633 const float SLACK = 0.001f;
00634
00635
00636
00637
00638 if (scene_camera_->getTypeId().getName() == "FrustumCamera") {
00639 nearval = scene_camera_->nearDistance.getValue();
00640 farval *= (1.0f + SLACK);
00641 if (farval <= nearval) {
00642
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
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
00708
00709 void bgui3d_viewer_tableau::collect_vrml_cameras(SoNode* root) const
00710 {
00711 assert(camera_group_);
00712 SoSearchAction sa;
00713
00714
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 }