132 lines
4.1 KiB
C++
132 lines
4.1 KiB
C++
#include <osg/GL>
|
|
#include <osg/Matrix>
|
|
#include <osg/io_utils>
|
|
#include <osg/ComputeBoundsVisitor>
|
|
#include <osgGA/CameraManipulator>
|
|
#include <string.h>
|
|
|
|
using namespace osg;
|
|
using namespace osgGA;
|
|
|
|
CameraManipulator::CameraManipulator()
|
|
{
|
|
_intersectTraversalMask = 0xffffffff;
|
|
|
|
_autoComputeHomePosition = true;
|
|
|
|
_homeEye.set(0.0,-1.0,0.0);
|
|
_homeCenter.set(0.0,0.0,0.0);
|
|
_homeUp.set(0.0,0.0,1.0);
|
|
}
|
|
|
|
|
|
CameraManipulator::CameraManipulator(const CameraManipulator& mm, const CopyOp& copyOp)
|
|
: osg::Object(mm, copyOp),
|
|
osg::Callback(mm, copyOp),
|
|
inherited(mm, copyOp),
|
|
_intersectTraversalMask(mm._intersectTraversalMask),
|
|
_autoComputeHomePosition(mm._autoComputeHomePosition),
|
|
_homeEye(mm._homeEye),
|
|
_homeCenter(mm._homeCenter),
|
|
_homeUp(mm._homeUp),
|
|
_coordinateFrameCallback(dynamic_cast<CoordinateFrameCallback*>(copyOp(mm._coordinateFrameCallback.get())))
|
|
{
|
|
}
|
|
|
|
|
|
CameraManipulator::~CameraManipulator()
|
|
{
|
|
}
|
|
|
|
|
|
std::string CameraManipulator::getManipulatorName() const
|
|
{
|
|
const char* className = this->className();
|
|
const char* manipString = strstr(className, "Manipulator");
|
|
if (!manipString)
|
|
return std::string(className);
|
|
else
|
|
return std::string(className, manipString-className);
|
|
}
|
|
|
|
|
|
bool CameraManipulator::handle(const GUIEventAdapter&,GUIActionAdapter&)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
/** Compute the home position.
|
|
*
|
|
* The computation considers camera's fov (field of view) and model size and
|
|
* positions camera far enough to fit the model to the screen.
|
|
*
|
|
* camera parameter enables computations of camera's fov. If camera is NULL,
|
|
* scene to camera distance can not be computed and default value is used,
|
|
* based on model size only.
|
|
*
|
|
* useBoundingBox parameter enables to use bounding box instead of bounding sphere
|
|
* for scene bounds. Bounding box provide more precise scene center that may be
|
|
* important for many applications.*/
|
|
void CameraManipulator::computeHomePosition(const osg::Camera *camera, bool useBoundingBox)
|
|
{
|
|
if (getNode())
|
|
{
|
|
osg::BoundingSphere boundingSphere;
|
|
|
|
OSG_INFO<<" CameraManipulator::computeHomePosition("<<camera<<", "<<useBoundingBox<<")"<<std::endl;
|
|
|
|
if (useBoundingBox)
|
|
{
|
|
// compute bounding box
|
|
// (bounding box computes model center more precisely than bounding sphere)
|
|
osg::ComputeBoundsVisitor cbVisitor;
|
|
getNode()->accept(cbVisitor);
|
|
osg::BoundingBox &bb = cbVisitor.getBoundingBox();
|
|
|
|
if (bb.valid()) boundingSphere.expandBy(bb);
|
|
else boundingSphere = getNode()->getBound();
|
|
}
|
|
else
|
|
{
|
|
// compute bounding sphere
|
|
boundingSphere = getNode()->getBound();
|
|
}
|
|
|
|
OSG_INFO<<" boundingSphere.center() = ("<<boundingSphere.center()<<")"<<std::endl;
|
|
OSG_INFO<<" boundingSphere.radius() = "<<boundingSphere.radius()<<std::endl;
|
|
|
|
// set dist to default
|
|
double dist = 3.5f * boundingSphere.radius();
|
|
|
|
if (camera)
|
|
{
|
|
|
|
// try to compute dist from frustum
|
|
double left,right,bottom,top,zNear,zFar;
|
|
if (camera->getProjectionMatrixAsFrustum(left,right,bottom,top,zNear,zFar))
|
|
{
|
|
double vertical2 = fabs(right - left) / zNear / 2.;
|
|
double horizontal2 = fabs(top - bottom) / zNear / 2.;
|
|
double dim = horizontal2 < vertical2 ? horizontal2 : vertical2;
|
|
double viewAngle = atan2(dim,1.);
|
|
dist = boundingSphere.radius() / sin(viewAngle);
|
|
}
|
|
else
|
|
{
|
|
// try to compute dist from ortho
|
|
if (camera->getProjectionMatrixAsOrtho(left,right,bottom,top,zNear,zFar))
|
|
{
|
|
dist = fabs(zFar - zNear) / 2.;
|
|
}
|
|
}
|
|
}
|
|
|
|
// set home position
|
|
setHomePosition(boundingSphere.center() + osg::Vec3d(0.0,-dist,0.0f),
|
|
boundingSphere.center(),
|
|
osg::Vec3d(0.0f,0.0f,1.0f),
|
|
_autoComputeHomePosition);
|
|
}
|
|
}
|