1 #include <osg/GL>
2 #include <osg/Matrix>
3 #include <osg/io_utils>
4 #include <osg/ComputeBoundsVisitor>
5 #include <osgGA/CameraManipulator>
6 #include <string.h>
7 
8 using namespace osg;
9 using namespace osgGA;
10 
CameraManipulator()11 CameraManipulator::CameraManipulator()
12 {
13     _intersectTraversalMask = 0xffffffff;
14 
15     _autoComputeHomePosition = true;
16 
17     _homeEye.set(0.0,-1.0,0.0);
18     _homeCenter.set(0.0,0.0,0.0);
19     _homeUp.set(0.0,0.0,1.0);
20 }
21 
22 
CameraManipulator(const CameraManipulator & mm,const CopyOp & copyOp)23 CameraManipulator::CameraManipulator(const CameraManipulator& mm, const CopyOp& copyOp)
24    : osg::Callback(mm, copyOp),
25      inherited(mm, copyOp),
26      _intersectTraversalMask(mm._intersectTraversalMask),
27      _autoComputeHomePosition(mm._autoComputeHomePosition),
28      _homeEye(mm._homeEye),
29      _homeCenter(mm._homeCenter),
30      _homeUp(mm._homeUp),
31      _coordinateFrameCallback(dynamic_cast<CoordinateFrameCallback*>(copyOp(mm._coordinateFrameCallback.get())))
32 {
33 }
34 
35 
~CameraManipulator()36 CameraManipulator::~CameraManipulator()
37 {
38 }
39 
40 
getManipulatorName() const41 std::string CameraManipulator::getManipulatorName() const
42 {
43     const char* className = this->className();
44     const char* manipString = strstr(className, "Manipulator");
45     if (!manipString)
46         return std::string(className);
47     else
48         return std::string(className, manipString-className);
49 }
50 
51 
handle(const GUIEventAdapter &,GUIActionAdapter &)52 bool CameraManipulator::handle(const GUIEventAdapter&,GUIActionAdapter&)
53 {
54     return false;
55 }
56 
57 
58 /** Compute the home position.
59  *
60  *  The computation considers camera's fov (field of view) and model size and
61  *  positions camera far enough to fit the model to the screen.
62  *
63  *  camera parameter enables computations of camera's fov. If camera is NULL,
64  *  scene to camera distance can not be computed and default value is used,
65  *  based on model size only.
66  *
67  *  useBoundingBox parameter enables to use bounding box instead of bounding sphere
68  *  for scene bounds. Bounding box provide more precise scene center that may be
69  *  important for many applications.*/
computeHomePosition(const osg::Camera * camera,bool useBoundingBox)70 void CameraManipulator::computeHomePosition(const osg::Camera *camera, bool useBoundingBox)
71 {
72     if (getNode())
73     {
74         osg::BoundingSphere boundingSphere;
75 
76         OSG_INFO<<" CameraManipulator::computeHomePosition("<<camera<<", "<<useBoundingBox<<")"<<std::endl;
77 
78         if (useBoundingBox)
79         {
80             // compute bounding box
81             // (bounding box computes model center more precisely than bounding sphere)
82             osg::ComputeBoundsVisitor cbVisitor;
83             getNode()->accept(cbVisitor);
84             osg::BoundingBox &bb = cbVisitor.getBoundingBox();
85 
86             if (bb.valid()) boundingSphere.expandBy(bb);
87             else boundingSphere = getNode()->getBound();
88         }
89         else
90         {
91             // compute bounding sphere
92             boundingSphere = getNode()->getBound();
93         }
94 
95         OSG_INFO<<"    boundingSphere.center() = ("<<boundingSphere.center()<<")"<<std::endl;
96         OSG_INFO<<"    boundingSphere.radius() = "<<boundingSphere.radius()<<std::endl;
97 
98         // set dist to default
99         double dist = 3.5f * boundingSphere.radius();
100 
101         if (camera)
102         {
103 
104             // try to compute dist from frustum
105             double left,right,bottom,top,zNear,zFar;
106             if (camera->getProjectionMatrixAsFrustum(left,right,bottom,top,zNear,zFar))
107             {
108                 double vertical2 = fabs(right - left) / zNear / 2.;
109                 double horizontal2 = fabs(top - bottom) / zNear / 2.;
110                 double dim = horizontal2 < vertical2 ? horizontal2 : vertical2;
111                 double viewAngle = atan2(dim,1.);
112                 dist = boundingSphere.radius() / sin(viewAngle);
113             }
114             else
115             {
116                 // try to compute dist from ortho
117                 if (camera->getProjectionMatrixAsOrtho(left,right,bottom,top,zNear,zFar))
118                 {
119                     dist = fabs(zFar - zNear) / 2.;
120                 }
121             }
122         }
123 
124         // set home position
125         setHomePosition(boundingSphere.center() + osg::Vec3d(0.0,-dist,0.0f),
126                         boundingSphere.center(),
127                         osg::Vec3d(0.0f,0.0f,1.0f),
128                         _autoComputeHomePosition);
129     }
130 }
131