1 // This is brl/bbas/bgui3d/bgui3d_viewer_tableau.cxx
2 #include <iostream>
3 #include <cmath>
4 #include "bgui3d_viewer_tableau.h"
5 //:
6 // \file
7
8 #include <cassert>
9 #ifdef _MSC_VER
10 # include "vcl_msvc_warnings.h"
11 #endif
12 #include "bgui3d_algo.h"
13 #include "vgui/vgui_gl.h"
14 #include "vgui/vgui_utils.h"
15 #include "vnl/vnl_quaternion.h"
16 #include "vnl/vnl_double_3x3.h"
17 #include "vnl/vnl_double_3x4.h"
18 #include "vnl/vnl_double_3.h"
19 #include "vnl/vnl_det.h"
20
21 #include "vgl/vgl_point_2d.h"
22 #include "vgl/vgl_point_3d.h"
23 #include <vgl/algo/vgl_rotation_3d.h>
24 #include "vpgl/vpgl_perspective_camera.h"
25
26 #include <Inventor/nodes/SoOrthographicCamera.h>
27 #include <Inventor/nodes/SoPerspectiveCamera.h>
28
29 #include <Inventor/nodes/SoSeparator.h>
30 #include <Inventor/SoDB.h>
31 #include <Inventor/SbViewportRegion.h>
32 #include <Inventor/nodes/SoNode.h>
33 #include <Inventor/nodes/SoSwitch.h>
34 #include <Inventor/VRMLnodes/SoVRMLViewpoint.h>
35 #include <Inventor/SoSceneManager.h>
36
37 #include <Inventor/nodes/SoDirectionalLight.h>
38 #include <Inventor/actions/SoSearchAction.h>
39 #include <Inventor/nodekits/SoBaseKit.h>
40 #include <Inventor/actions/SoGetBoundingBoxAction.h>
41 #include <Inventor/actions/SoGetMatrixAction.h>
42 #include <Inventor/nodes/SoText2.h>
43
44 #include <Inventor/nodes/SoTranslation.h>
45 #include <Inventor/sensors/SoAlarmSensor.h>
46
47 //: Constructor
bgui3d_viewer_tableau(SoNode * scene_root)48 bgui3d_viewer_tableau::bgui3d_viewer_tableau(SoNode * scene_root)
49 : bgui3d_tableau(NULL),
50 user_scene_root_(NULL),
51 camera_group_(NULL),
52 scene_camera_(NULL),
53 stored_camera_(NULL),
54 headlight_(NULL)
55 {
56 this->set_scene_root(scene_root);
57 }
58
59
60 //: Destructor
~bgui3d_viewer_tableau()61 bgui3d_viewer_tableau::~bgui3d_viewer_tableau()
62 {
63 if (scene_camera_)
64 scene_camera_->unref();
65 if (headlight_)
66 headlight_->unref();
67 }
68
69
70 void
set_scene_root(SoNode * scene_root)71 bgui3d_viewer_tableau::set_scene_root(SoNode* scene_root)
72 {
73 if (!scene_root)
74 bgui3d_tableau::set_scene_root(scene_root);
75
76 user_scene_root_ = scene_root;
77
78 // Build the super scene graph
79 SoSeparator *super_root = new SoSeparator;
80 super_root->setName("bgui3d_viewer_root");
81
82 // Create a headlight if one does not exist
83 // By inserting this before any scenegraph camera, the
84 // light will always be pointing in the correct direction.
85 if (!headlight_) {
86 headlight_ = new SoDirectionalLight;
87 headlight_->direction.setValue(1, -1, -10);
88 headlight_->setName("headlight");
89 headlight_->ref();
90 }
91 super_root->addChild(headlight_);
92
93 // add the text and its translation to shift it to the top right
94 SoTranslation* trans = new SoTranslation;
95 trans->translation = SbVec3f(-.98f,.93f,0);
96 super_root->addChild( trans );
97
98 text_ = new SoText2;
99 text_->string.deleteValues(0, -1); // empty the string
100 super_root->addChild( text_ );
101
102 //: Make a group of all the cameras in the scene
103 camera_group_ = new SoSwitch;
104 camera_group_->setName("bgui3dCameraGroup");
105 super_root->addChild(camera_group_);
106
107 // Make the default Camera
108 SoCamera* camera = (SoCamera*)SoPerspectiveCamera::getClassTypeId().createInstance();
109 camera->setName("Examiner_Camera");
110 camera_group_->addChild(camera);
111 camera->nearDistance = 0.5f;
112 camera->farDistance = 1000.0f;
113
114 // Set the camera to view the whole scene
115 camera->viewAll(scene_root, get_viewport_region());
116
117 // find existing VRML viewpoints in the scene and make cameras
118 this->collect_vrml_cameras(scene_root);
119
120 // find and used the first user scene camera (if it exists)
121 std::vector<SoCamera*> user_cams = find_cameras(user_scene_root_);
122 if (!user_cams.empty()) {
123 camera_group_->whichChild.setValue(-1);
124 this->set_camera(user_cams[0]);
125 }
126 else {
127 // if not, use the first examiner camera
128 assert(camera_group_->getChildren()->getLength() > 0);
129
130 if (camera_group_->whichChild.getValue() < 0)
131 camera_group_->whichChild.setValue(0);
132 int cam_idx = camera_group_->whichChild.getValue();
133
134 SoChildList* list = camera_group_->getChildren();
135 this->set_camera((SoCamera*)(*list)[cam_idx]);
136 }
137
138 // The users scene should be added last
139 if (scene_root)
140 super_root->addChild(scene_root);
141
142 bgui3d_tableau::set_scene_root(super_root);
143
144 save_home_position();
145 }
146
147
148 //--------------Camera Methods--------------------
149
150 //: Set the camera viewing the scene
151 // \note this does not add the camera to a scene graph
152 void
set_camera(SoCamera * camera)153 bgui3d_viewer_tableau::set_camera(SoCamera *camera)
154 {
155 if (scene_camera_) {
156 scene_camera_->unref();
157 }
158
159 scene_camera_ = camera;
160
161 if (scene_camera_) {
162 scene_camera_->ref();
163 SoType cam_type = scene_camera_->getTypeId();
164 if ( cam_type == SoOrthographicCamera::getClassTypeId() )
165 camera_type_ = ORTHOGONAL;
166 else
167 camera_type_ = PERSPECTIVE;
168 }
169 }
170
171
172 //: Set the scene camera
173 // Generate an SoCamera from a camera matrix and use it
174 // \note Only handles perspective cameras for now
175 bool
set_camera(const vpgl_proj_camera<double> & camera)176 bgui3d_viewer_tableau::set_camera(const vpgl_proj_camera<double>& camera)
177 {
178 SoPerspectiveCamera* new_cam = new SoPerspectiveCamera;
179 new_cam->ref();
180 new_cam->setName("Camera_Matrix");
181
182 vnl_double_3x3 K, R;
183 vnl_double_3 t;
184
185 vnl_double_3x4 cam = camera.get_matrix();
186 if (vnl_det(vnl_double_3x3(cam.extract(3,3))) < 0)
187 cam *= -1.0;
188 if ( bgui3d_decompose_camera(cam, K, R, t) ) {
189 new_cam->aspectRatio = float(K[0][2]/K[1][2]);
190 new_cam->heightAngle = float(2*std::atan2(K[1][2],K[1][1]));
191
192 vnl_double_3 C = -R.transpose()*t;
193 new_cam->position.setValue( float(C[0]), float(C[1]), float(C[2]) );
194
195 // the identity camera requires a 180 degree rotation about the
196 // x-axis to project to images with the origin in the upper left
197 R.scale_row(1,-1);
198 R.scale_row(2,-1);
199
200 // create a rotation matrix
201 SbMatrix rot = SbMatrix::identity();
202
203 for (int i=0; i<3; ++i)
204 for ( int j=0; j<3; ++j)
205 rot[j][i] = float(R[j][i]);
206
207 new_cam->orientation.setValue(SbRotation(rot));
208
209 new_cam->nearDistance = 1.0f;
210 new_cam->farDistance = 1000.0f;
211 }
212
213 if ( user_scene_root_ ) {
214 camera_group_->addChild(new_cam);
215 int num_cameras = camera_group_->getChildren()->getLength();
216 this->select_camera(num_cameras -1);
217 this->set_camera(new_cam);
218
219 this->set_clipping_planes();
220 }
221
222 new_cam->unref();
223
224 return true;
225 }
226
227
228 //: Get the scene camera.
229 // Creates a vpgl camera (either perspective or affine) from the active SoCamera
230 std::unique_ptr<vpgl_proj_camera<double> >
camera() const231 bgui3d_viewer_tableau::camera() const
232 {
233 if (!scene_camera_)
234 return std::unique_ptr<vpgl_proj_camera<double> >(nullptr);
235
236 const SbVec3f& t_vec = scene_camera_->position.getValue();
237 vnl_double_3 t(t_vec[0], t_vec[1], t_vec[2]);
238
239 float q1,q2,q3,q4;
240 scene_camera_->orientation.getValue().getValue(q1,q2,q3,q4);
241 // inverse and rotate 180 degrees around Z
242 vgl_rotation_3d<double> R(vnl_quaternion<double>(q2,-q1,q4,q3));
243
244 GLint vp[4];
245 vgui_utils::get_glViewport(vp);
246 unsigned width = vp[2];
247 unsigned height = vp[3];
248
249 switch (camera_type_)
250 {
251 case PERSPECTIVE: {
252 SoPerspectiveCamera* cam = (SoPerspectiveCamera*)scene_camera_;
253 double f = 1.0/(std::tan(cam->heightAngle.getValue()/2.0));
254 double sx = 1.0, sy = 1.0;
255 if (width < height)
256 sy = double(width)/height;
257 else
258 sx = double(height)/width;
259 vgl_point_2d<double> p(0, 0);
260 vpgl_calibration_matrix<double> K(f,p,sx,sy);
261 vgl_point_3d<double> c(t[0],t[1],t[2]);
262 return std::unique_ptr<vpgl_proj_camera<double> >
263 ( new vpgl_perspective_camera<double>(K,c,R) );
264 }
265 case ORTHOGONAL:
266 #if 0
267 SoOrthographicCamera* cam = (SoOrthographicCamera*)scene_camera_;
268 double h = cam->height.getValue();
269 #endif // 0
270 std::cerr << "WARNING: not implemented yet\n";
271 return std::unique_ptr<vpgl_proj_camera<double> >(nullptr);
272 default:
273 std::cerr << "WARNING: no such camera_type_\n";
274 return std::unique_ptr<vpgl_proj_camera<double> >(nullptr);
275 }
276 }
277
278
279 //: Select the active camera by index.
280 // A negative index selects the first user scene camera
281 void
select_camera(int camera_index)282 bgui3d_viewer_tableau::select_camera(int camera_index)
283 {
284 int num_cameras = camera_group_->getChildren()->getLength();
285
286 if (camera_index >= 0 && camera_index < num_cameras) {
287 if (camera_index != camera_group_->whichChild.getValue()) {
288 camera_group_->whichChild.setValue(camera_index);
289 SoChildList* list = camera_group_->getChildren();
290 this->set_camera((SoCamera*)(*list)[camera_index]);
291 }
292 }
293 else {
294 std::vector<SoCamera*> user_cams = find_cameras(user_scene_root_);
295 if (!user_cams.empty()) {
296 camera_group_->whichChild.setValue(-1);
297 this->set_camera(user_cams[0]);
298 }
299 }
300 }
301
302
303 //: Return the camera viewing the scene
304 SoCamera*
camera_node() const305 bgui3d_viewer_tableau::camera_node() const
306 {
307 // FIX ME
308 return scene_camera_;
309 }
310
311
312 //: Set the camera type (Perspective or Orthogonal)
313 void
set_camera_type(camera_type_enum type)314 bgui3d_viewer_tableau::set_camera_type(camera_type_enum type)
315 {
316 SoType ptype = SoPerspectiveCamera::getClassTypeId();
317 SoType otype = SoOrthographicCamera::getClassTypeId();
318 SoCamera* newCamera;
319 if ( camera_type_ != type )
320 {
321 if ( camera_type_ == PERSPECTIVE && type == ORTHOGONAL )
322 {
323 newCamera = (SoCamera *)otype.createInstance();
324 convertPerspective2Ortho((SoPerspectiveCamera*)scene_camera_, (SoOrthographicCamera*)newCamera);
325 }
326 else if ( camera_type_ == ORTHOGONAL && type == PERSPECTIVE )
327 {
328 newCamera = (SoCamera *)ptype.createInstance();
329 convertOrtho2Perspective((SoOrthographicCamera*)scene_camera_, (SoPerspectiveCamera*)newCamera);
330 }
331 else
332 assert(!"This camera type is not supported");
333
334 newCamera->ref();
335 std::vector<SoGroup *> cameraparents = get_parents_of_node(this->scene_camera_);
336 for (std::vector<SoGroup *>::iterator cp = cameraparents.begin(); cp != cameraparents.end(); ++cp)
337 {
338 (*cp)->replaceChild((*cp)->findChild(this->scene_camera_), newCamera);
339 }
340
341 this->set_camera(newCamera);
342
343 camera_group_->whichChild.setValue(camera_group_->findChild(this->scene_camera_));
344 newCamera->unref();
345 }
346 }
347
348
349 //: Return the camera type (Perspective or Orthogonal)
350 bgui3d_viewer_tableau::camera_type_enum
camera_type() const351 bgui3d_viewer_tableau::camera_type() const
352 {
353 return camera_type_;
354 }
355
356
357 //: Toggle the camera type between Perspective and Orthogonal
358 void
toggle_camera_type()359 bgui3d_viewer_tableau::toggle_camera_type()
360 {
361 if (camera_type_ == ORTHOGONAL)
362 set_camera_type(PERSPECTIVE);
363 else
364 set_camera_type(ORTHOGONAL);
365 }
366
367
368 //: Adjust the camera to view the entire scene
369 void
view_all()370 bgui3d_viewer_tableau::view_all()
371 {
372 scene_camera_->viewAll( user_scene_root_, get_viewport_region() );
373 }
374
375
376 //: Save the current camera as the home position
377 void
save_home_position()378 bgui3d_viewer_tableau::save_home_position()
379 {
380 if (! this->scene_camera_) return; // probably a scene-less viewer
381
382 // We use SoType::createInstance() to store a copy of the camera,
383 // not just assuming it's either a perspective or an orthographic
384 // camera.
385
386 SoType t = this->scene_camera_->getTypeId();
387 assert(t.isDerivedFrom(SoNode::getClassTypeId()));
388 assert(t.canCreateInstance());
389
390 if (this->stored_camera_)
391 this->stored_camera_->unref();
392
393 this->stored_camera_ = (SoNode *)t.createInstance();
394 this->stored_camera_->ref();
395 this->stored_camera_->copyContents(this->scene_camera_, false);
396 }
397
398
399 //: Restore the saved home position of the camera
400 void
reset_to_home_position()401 bgui3d_viewer_tableau::reset_to_home_position()
402 {
403 if (! this->scene_camera_) { return; } // probably a scene-less viewer
404 if (! this->stored_camera_) { return; }
405
406 SoType t = this->scene_camera_->getTypeId();
407 SoType s = this->stored_camera_->getTypeId();
408
409 // most common case
410 if (t == s) {
411 this->scene_camera_->copyContents(this->stored_camera_, false);
412 }
413 // handle common case #1
414 else if (t == SoOrthographicCamera::getClassTypeId() &&
415 s == SoPerspectiveCamera::getClassTypeId()) {
416 this->convertPerspective2Ortho((SoPerspectiveCamera *)this->stored_camera_,
417 (SoOrthographicCamera *)this->scene_camera_);
418 camera_type_ = ORTHOGONAL;
419 }
420 // handle common case #2
421 else if (t == SoPerspectiveCamera::getClassTypeId() &&
422 s == SoOrthographicCamera::getClassTypeId()) {
423 this->convertOrtho2Perspective((SoOrthographicCamera *)this->stored_camera_,
424 (SoPerspectiveCamera *)this->scene_camera_);
425 camera_type_ = PERSPECTIVE;
426 }
427 // otherwise, cameras have changed in ways we don't understand since
428 // the last saveHomePosition() invocation, and so we're just going
429 // to ignore the reset request
430 }
431
432 //-------------------------------------------------
433
434 //-------------Headlight Methods-------------------
435
436 //: Activate a headlight
437 void
set_headlight(bool enable)438 bgui3d_viewer_tableau::set_headlight(bool enable)
439 {
440 headlight_->on = enable;
441 }
442
443
444 //: Is the headlight active
445 bool
is_headlight() const446 bgui3d_viewer_tableau::is_headlight() const
447 {
448 return headlight_->on.getValue() != 0;
449 }
450
451
452 //: Return the headlight
453 SoDirectionalLight*
headlight() const454 bgui3d_viewer_tableau::headlight() const
455 {
456 return headlight_;
457 }
458
459 //-------------------------------------------------
460
461 //-------------Text2 Methods-------------------
462
setTextCallback(void * data,SoSensor *)463 static void setTextCallback( void *data, SoSensor * /*sensor*/ )
464 {
465 ((SoText2*)data)->string.deleteValues(0, 1);
466 }
467
setText(const std::string & string)468 void bgui3d_viewer_tableau::setText( const std::string& string )
469 {
470 int numStrings = text_->string.getNum();
471 text_->string.set1Value( numStrings, string.c_str() );
472 SoAlarmSensor* alarm = new SoAlarmSensor( setTextCallback, text_ );
473 alarm->setTimeFromNow( 7.0 );
474 alarm->schedule();
475 }
476
477 //---------------------------------------------------
478
479 //: convert camera to perspective
480 void
convertOrtho2Perspective(const SoOrthographicCamera * in,SoPerspectiveCamera * out)481 bgui3d_viewer_tableau::convertOrtho2Perspective(const SoOrthographicCamera * in,
482 SoPerspectiveCamera * out)
483 {
484 out->aspectRatio.setValue(in->aspectRatio.getValue());
485 out->focalDistance.setValue(in->focalDistance.getValue());
486 out->orientation.setValue(in->orientation.getValue());
487 out->position.setValue(in->position.getValue());
488 out->viewportMapping.setValue(in->viewportMapping.getValue());
489 out->setName(in->getName());
490
491 float focaldist = in->focalDistance.getValue();
492
493 // focalDistance==0.0f happens for empty scenes.
494 if (focaldist != 0.0f) {
495 out->heightAngle = 2.0f * (float)std::atan(in->height.getValue() / 2.0 / focaldist);
496 }
497 else {
498 // 45?is the default value of this field in SoPerspectiveCamera.
499 out->heightAngle = (float)(M_PI / 4.0);
500 }
501 }
502
503
504 //: convert camera to orthographic
505 void
convertPerspective2Ortho(const SoPerspectiveCamera * in,SoOrthographicCamera * out)506 bgui3d_viewer_tableau::convertPerspective2Ortho(const SoPerspectiveCamera * in,
507 SoOrthographicCamera * out)
508 {
509 out->aspectRatio.setValue(in->aspectRatio.getValue());
510 out->focalDistance.setValue(in->focalDistance.getValue());
511 out->orientation.setValue(in->orientation.getValue());
512 out->position.setValue(in->position.getValue());
513 out->viewportMapping.setValue(in->viewportMapping.getValue());
514 out->setName(in->getName());
515
516 float focaldist = in->focalDistance.getValue();
517
518 out->height = 2.0f * focaldist * (float)std::tan(in->heightAngle.getValue() / 2.0);
519 }
520
521 void
set_clipping_planes()522 bgui3d_viewer_tableau::set_clipping_planes()
523 {
524 SoGetBoundingBoxAction action( get_viewport_region() );
525
526 action.apply( scene_root_ );
527
528 SbXfBox3f xbox = action.getXfBoundingBox();
529
530 SbMatrix cammat;
531
532 SoSearchAction searchaction;
533 searchaction.reset();
534 searchaction.setSearchingAll(TRUE);
535 searchaction.setInterest(SoSearchAction::FIRST);
536 searchaction.setNode(scene_camera_);
537 searchaction.apply(scene_root_);
538
539 SoGetMatrixAction matrixaction(get_viewport_region());
540 SbMatrix inverse = SbMatrix::identity();
541 if (searchaction.getPath()) {
542 matrixaction.apply(searchaction.getPath());
543 inverse = matrixaction.getInverse();
544 }
545
546 xbox.transform(inverse);
547
548 SbMatrix mat;
549 mat.setTranslate(- scene_camera_->position.getValue());
550 xbox.transform(mat);
551 mat = scene_camera_->orientation.getValue().inverse();
552 xbox.transform(mat);
553 SbBox3f box = xbox.project();
554
555 // Bounding box was calculated in camera space, so we need to "flip"
556 // the box (because camera is pointing in the (0,0,-1) direction
557 // from origo.
558 float nearval = -box.getMax()[2];
559 float farval = -box.getMin()[2];
560
561 // FIXME: what if we have a weird scale transform in the scenegraph?
562 // Could we end up with nearval > farval then? Investigate, then
563 // either use an assert() (if it can't happen) or an SoWinSwap()
564 // (to handle it). 20020116 mortene.
565
566 // Check if scene is completely behind us.
567 if (farval <= 0.0f) { return; }
568
569 if ( scene_camera_->isOfType(SoPerspectiveCamera::getClassTypeId())) {
570 // Disallow negative and small near clipping plane distance.
571
572 float nearlimit; // the smallest value allowed for nearval
573 #if 0
574 if (this->autoclipstrategy == SoWinViewer::CONSTANT_NEAR_PLANE) {
575 nearlimit = this->autoclipvalue;
576 }
577 else {
578 assert(this->autoclipstrategy == SoWinViewer::VARIABLE_NEAR_PLANE);
579 #endif // 0
580 // From glFrustum() documentation: Depth-buffer precision is
581 // affected by the values specified for znear and zfar. The
582 // greater the ratio of zfar to znear is, the less effective the
583 // depth buffer will be at distinguishing between surfaces that
584 // are near each other. If r = far/near, roughly log (2) r bits
585 // of depth buffer precision are lost. Because r approaches
586 // infinity as znear approaches zero, you should never set znear
587 // to zero.
588 GLint depthbits[1];
589 // assume 16-bit depth
590 // it is unsafe to use GL functions here because a GL context
591 // might not have been created yet.
592 depthbits[0] = 16;
593 #if 0
594 glGetIntegerv(GL_DEPTH_BITS, depthbits);
595 #endif // 0
596
597 int use_bits = (int) (float(depthbits[0]) * 0.4f + 0.001f);
598 float r = (float)(1 << use_bits);
599 nearlimit = farval / r;
600 #if 0
601 }
602 #endif // 0
603
604 if (nearlimit >= farval) {
605 // (The "5000" magic constant was found by fiddling around a bit
606 // on an OpenGL implementation with a 16-bit depth-buffer
607 // resolution, adjusting to find something that would work well
608 // with both a very "stretched" / deep scene and a more compact
609 // single-model one.)
610 nearlimit = farval / 5000.0f;
611 }
612
613 // adjust the near plane if the value is too small.
614 if (nearval < nearlimit) {
615 nearval = nearlimit;
616 }
617
618 #if 0
619 if (this->autoclipcb) {
620 SbVec2f nearfar;
621 nearfar[0] = nearval;
622 nearfar[1] = farval;
623
624 nearfar = this->autoclipcb(this->autoclipuserdata, nearfar);
625
626 nearval = nearfar[0];
627 farval = nearfar[1];
628 }
629 #endif // 0
630 }
631 // Some slack around the bounding box, in case the scene fits
632 // exactly inside it. This is done to minimize the chance of
633 // artefacts caused by the limitation of the z-buffer
634 // resolution. One common artefact if this is not done is that the
635 // near clipping plane cuts into the corners of the model as it's
636 // rotated.
637 const float SLACK = 0.001f;
638
639 // FrustumCamera can be found in the SmallChange CVS module. We
640 // should not change the nearDistance for this camera, as this will
641 // modify the frustum.
642 if (scene_camera_->getTypeId().getName() == "FrustumCamera") {
643 nearval = scene_camera_->nearDistance.getValue();
644 farval *= (1.0f + SLACK);
645 if (farval <= nearval) {
646 // nothing is visible, so just set farval to som value > nearval.
647 farval = nearval + 10.0f;
648 }
649 scene_camera_->farDistance = farval;
650 }
651 else {
652 scene_camera_->nearDistance = nearval * (1.0f - SLACK);
653 scene_camera_->farDistance = farval * (1.0f + SLACK);
654 }
655 }
656
657
658 std::vector<SoGroup*>
get_parents_of_node(SoNode * node)659 bgui3d_viewer_tableau::get_parents_of_node(SoNode * node)
660 {
661 SbBool oldsearch = SoBaseKit::isSearchingChildren();
662 SoBaseKit::setSearchingChildren(TRUE);
663
664 assert(node && "get_parent_of_node() called with null argument");
665
666 SoSearchAction search;
667 search.setSearchingAll(TRUE);
668 search.setNode(node);
669 search.setInterest(SoSearchAction::ALL);
670 search.apply(this->scene_root());
671 SoPathList & pl = search.getPaths();
672
673 std::vector<SoGroup*> parents;
674 for (int i = 0; i < pl.getLength(); ++i) {
675 SoFullPath * p = (SoFullPath*) pl[i];
676 if (p->getLength() > 0)
677 parents.push_back((SoGroup*)p->getNodeFromTail(1));
678 }
679 SoBaseKit::setSearchingChildren(oldsearch);
680 return parents;
681 }
682
683
684 std::vector<SoCamera*>
find_cameras(SoNode * root) const685 bgui3d_viewer_tableau::find_cameras(SoNode* root) const
686 {
687 assert(camera_group_);
688 SoSearchAction sa;
689
690 // Search for existing cameras
691 sa.setType(SoCamera::getClassTypeId());
692 sa.setInterest(SoSearchAction::ALL);
693 sa.setSearchingAll(TRUE);
694 sa.apply(root);
695 SoPathList & pl = sa.getPaths();
696
697 std::vector<SoCamera*> cameras;
698 for (int i = 0; i < pl.getLength(); ++i) {
699 SoFullPath * p = (SoFullPath*) pl[i];
700 if (p->getTail()->isOfType(SoCamera::getClassTypeId())) {
701 SoCamera * camera = (SoCamera*) p->getTail();
702 cameras.push_back(camera);
703 }
704 }
705 sa.reset();
706
707 return cameras;
708 }
709
710
711 //: Find the VRML viewpoint nodes in the scenegraph and make camera.
712 // The cameras are added to the camera group (outside the user scene)
collect_vrml_cameras(SoNode * root) const713 void bgui3d_viewer_tableau::collect_vrml_cameras(SoNode* root) const
714 {
715 assert(camera_group_);
716 SoSearchAction sa;
717
718 // Search for VRML viewpoints and create cameras
719 sa.setType(SoVRMLViewpoint::getClassTypeId());
720 sa.setInterest(SoSearchAction::ALL);
721 sa.setSearchingAll(TRUE);
722 sa.apply(root);
723 SoPathList & pl2 = sa.getPaths();
724
725 for (int i = 0; i < pl2.getLength(); ++i) {
726 SoFullPath * p = (SoFullPath*) pl2[i];
727 if (p->getTail()->isOfType(SoVRMLViewpoint::getClassTypeId())) {
728 SoVRMLViewpoint * vp = (SoVRMLViewpoint*) p->getTail();
729 SoPerspectiveCamera * camera = (SoPerspectiveCamera *)
730 SoPerspectiveCamera::getClassTypeId().createInstance();
731 camera->nearDistance = 0.5f;
732 camera->farDistance = 5000.0f;
733 camera->position = vp->position;
734 camera->orientation = vp->orientation;
735 camera->heightAngle = vp->fieldOfView;
736 camera->setName(vp->description.getValue());
737 camera_group_->addChild( camera );
738 }
739 }
740 sa.reset();
741 }
742