1. 程式人生 > >[osg][osgEarth]EarthManipulator關於oe漫遊器的handle部分解讀

[osg][osgEarth]EarthManipulator關於oe漫遊器的handle部分解讀

make bin ngs gui ice tracking val isset efficient

bool
EarthManipulator::handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
{
    bool handled = false;

    // first order of business: make sure the CSN is established.
    if ( !established() )
        return false;

    // make sure the camera projection is up to date:
    osg::View* view = aa.asView();
    updateProjection( view
->getCamera() ); double time_s_now = osg::Timer::instance()->time_s(); if ( ea.getEventType() == osgGA::GUIEventAdapter::FRAME ) { _time_s_last_frame = _time_s_now; _time_s_now = time_s_now; _delta_t = _time_s_now - _time_s_last_frame; if ( _node.valid() ) {
if ( _pendingViewpoint.isSet() ) { setViewpoint( _pendingViewpoint.get(), _pendingViewpointDuration.as(Units::SECONDS) ); _pendingViewpoint.unset(); aa.requestRedraw(); } else if ( isSettingViewpoint() && !isTethering() ) {
if ( _frameCount < 2 ) _setVPStartTime->set(_time_s_now, Units::SECONDS); setViewpointFrame( time_s_now ); } if (_thrown) { double decayFactor = 1.0 - _settings->getThrowDecayRate(); _throw_dx = osg::absolute(_throw_dx) > osg::absolute(_dx * 0.01) ? _throw_dx * decayFactor : 0.0; _throw_dy = osg::absolute(_throw_dy) > osg::absolute(_dy * 0.01) ? _throw_dy * decayFactor : 0.0; if (_throw_dx == 0.0 && _throw_dy == 0.0) _thrown = false; else handleMovementAction(_last_action._type, _throw_dx, _throw_dy, aa.asView()); } aa.requestContinuousUpdate( isSettingViewpoint() || _thrown ); if ( _continuous ) { handleContinuousAction( _last_action, aa.asView() ); aa.requestRedraw(); } else { _continuous_dx = 0.0; _continuous_dy = 0.0; } if ( _task.valid() && _task->_type != TASK_NONE ) { bool stillRunning = serviceTask(); if ( stillRunning ) { aa.requestContinuousUpdate( true ); } else { // turn off the continuous, but we still need one last redraw // to process the final state. aa.requestContinuousUpdate( false ); aa.requestRedraw(); } } } _frameCount++; return false; } // the camera manipulator runs last after any other event handlers. So bail out // if the incoming event has already been handled by another handler. if ( ea.getHandled() ) { return false; } // form the current Action based on the event type: Action action = ACTION_NULL; // if tethering is active, check to see whether the incoming event // will break the tether. if ( isTethering() ) { const ActionTypeVector& atv = _settings->getBreakTetherActions(); if ( atv.size() > 0 ) { const Action& action = _settings->getAction( ea.getEventType(), ea.getButtonMask(), ea.getModKeyMask() ); if ( std::find(atv.begin(), atv.end(), action._type) != atv.end() ) { clearViewpoint(); } } } if ( ea.isMultiTouchEvent() ) { // not a mouse event; clear the mouse queue. resetMouse( aa, false ); // queue up a touch event set and figure out the current state: addTouchEvents(ea); TouchEvents te; if ( parseTouchEvents(te) ) { for( TouchEvents::iterator i = te.begin(); i != te.end(); ++i ) { action = _settings->getAction(i->_eventType, i->_mbmask, 0); if (action._type != ACTION_NULL) { _last_event = i->_eventType; // here we adjust for action scale, global sensitivy double dx = i->_dx, dy = i->_dy; dx *= _settings->getMouseSensitivity(); dy *= _settings->getMouseSensitivity(); applyOptionsToDeltas( action, dx, dy ); _dx = dx; _dy = dy; if (action._type == ACTION_GOTO) handlePointAction(action, ea.getX(), ea.getY(), view); else handleMovementAction(action._type, dx, dy, view); aa.requestRedraw(); } } handled = true; } else { // The only multitouch event we want passed on if not handled is a release handled = ea.getEventType() != osgGA::GUIEventAdapter::RELEASE; // if a new push occurs we want to reset the dx/dy values to stop/prevent throwing if (ea.getEventType() == osgGA::GUIEventAdapter::PUSH) _dx = _dy = 0.0; } } if ( !handled ) { // not a touch event; clear the touch queue. //_touchPointQueue.clear(); switch( ea.getEventType() ) { case osgGA::GUIEventAdapter::PUSH: resetMouse( aa ); addMouseEvent( ea ); _mouse_down_event = &ea; aa.requestRedraw(); handled = true; break; case osgGA::GUIEventAdapter::RELEASE: if ( _continuous ) { // bail out of continuous mode if necessary: _continuous = false; aa.requestContinuousUpdate( false ); } else { action = _last_action; _throw_dx = fabs(_dx) > 0.01 ? _dx : 0.0; _throw_dy = fabs(_dy) > 0.01 ? _dy : 0.0; if (_settings->getThrowingEnabled() && ( time_s_now - _time_s_last_event < 0.05 ) && (_throw_dx != 0.0 || _throw_dy != 0.0)) { _thrown = true; aa.requestRedraw(); aa.requestContinuousUpdate( true ); } else if ( isMouseClick( &ea ) ) { addMouseEvent( ea ); if ( _mouse_down_event ) { action = _settings->getAction( EVENT_MOUSE_CLICK, _mouse_down_event->getButtonMask(), _mouse_down_event->getModKeyMask() ); if ( handlePointAction( action, ea.getX(), ea.getY(), aa.asView() )) aa.requestRedraw(); } resetMouse( aa ); } else { resetMouse( aa ); addMouseEvent( ea ); } } handled = true; break; case osgGA::GUIEventAdapter::DOUBLECLICK: // bail out of continuous mode if necessary: _continuous = false; addMouseEvent( ea ); if (_mouse_down_event) { action = _settings->getAction( ea.getEventType(), _mouse_down_event->getButtonMask(), _mouse_down_event->getModKeyMask() ); if ( handlePointAction( action, ea.getX(), ea.getY(), aa.asView() ) ) aa.requestRedraw(); resetMouse( aa ); handled = true; } break; case osgGA::GUIEventAdapter::MOVE: // MOVE not currently bindable //NOP break; case osgGA::GUIEventAdapter::DRAG: { action = _settings->getAction( ea.getEventType(), ea.getButtonMask(), ea.getModKeyMask() ); addMouseEvent( ea ); bool wasContinuous = _continuous; _continuous = action.getBoolOption(OPTION_CONTINUOUS, false); if ( handleMouseAction( action, aa.asView() ) ) aa.requestRedraw(); if ( _continuous && !wasContinuous ) _last_continuous_action_time = time_s_now; //_time_s_now; aa.requestContinuousUpdate(_continuous); _thrown = false; handled = true; } break; case osgGA::GUIEventAdapter::KEYDOWN: if ( ea.getKey() < osgGA::GUIEventAdapter::KEY_Shift_L ) { resetMouse( aa ); action = _settings->getAction( ea.getEventType(), ea.getKey(), ea.getModKeyMask() ); if ( handleKeyboardAction( action ) ) aa.requestRedraw(); handled = true; } break; case osgGA::GUIEventAdapter::KEYUP: resetMouse( aa ); _task->_type = TASK_NONE; handled = true; break; case osgGA::GUIEventAdapter::SCROLL: resetMouse( aa ); addMouseEvent( ea ); action = _settings->getAction( ea.getEventType(), ea.getScrollingMotion(), ea.getModKeyMask() ); if ( handleScrollAction( action, action.getDoubleOption(OPTION_DURATION, 0.2) ) ) aa.requestRedraw(); handled = true; break; default: break; } } // if a new task was started, request continuous updates. if ( _task.valid() && _task->_type != TASK_NONE ) { aa.requestContinuousUpdate( true ); } if ( handled && action._type != ACTION_NULL ) { _last_action = action; _time_s_last_event = time_s_now; } return handled; }

仔細分析:

            else if ( isSettingViewpoint() && !isTethering() )
            {
                if ( _frameCount < 2 )
                    _setVPStartTime->set(_time_s_now, Units::SECONDS);

                setViewpointFrame( time_s_now );
            }

這是需要調整相機漫遊器位置了

isSettingViewpoint

這個函數主要是判斷當前_setVP0和_setVP1是否有值

有值就從當前_setVP0視點經過一條弧線飛到_setVP1視點下

飛行過程調用的函數就是setViewpointFrame()

// returns "t" [0..1], the interpolation coefficient.
double
CVRECameraManipulator::setViewpointFrame(double time_s)
{
    if ( !_setVPStartTime.isSet() )
    {
        _setVPStartTime->set( time_s, Units::SECONDS );
        return 0.0;
    }
    else
    {
        // Start point is the current manipulator center:
        osg::Vec3d startWorld;
        osg::ref_ptr<osg::Node> startNode;
        if ( _setVP0->getNode(startNode) )
            startWorld = computeWorld(startNode);
        else
            _setVP0->focalPoint()->transform( _srs.get() ).toWorld(startWorld);

        // End point is the world coordinates of the target viewpoint:
        osg::Vec3d endWorld;
        osg::ref_ptr<osg::Node> endNode;
        if ( _setVP1->getNode(endNode) )
            endWorld = computeWorld(endNode);
        else
            _setVP1->focalPoint()->transform( _srs.get() ).toWorld(endWorld);

        // Remaining time is the full duration minus the time since initiation:
        double elapsed = time_s - _setVPStartTime->as(Units::SECONDS);
        double t = std::min(1.0, elapsed / _setVPDuration.as(Units::SECONDS));

        double tp = t;

        if ( _setVPArcHeight > 0.0 )
        {
            if ( tp <= 0.5 )
            {
                double t2 = 2.0*tp;
                tp = 0.5*t2;
            }
            else
            {
                double t2 = 2.0*(tp-0.5);
                tp = 0.5+(0.5*t2);
            }

            // the more smoothsteps you do, the more pronounced the fade-in/out effect
            tp = smoothStepInterp( tp );
        }
        else if ( t > 0.0 )
        {
            tp = smoothStepInterp( tp );
        }

        osg::Vec3d newCenter =
            _srs->isGeographic() ? nlerp(startWorld, endWorld, tp) : lerp(startWorld, endWorld, tp);

        // Calculate the delta-heading, and make sure we are going in the shortest direction:
        Angle d_azim = _setVP1->heading().get() - _setVP0->heading().get();
        if ( d_azim.as(Units::RADIANS) > osg::PI )
            d_azim = d_azim - Angle(2.0*osg::PI, Units::RADIANS);
        else if ( d_azim.as(Units::RADIANS) < -osg::PI )
            d_azim = d_azim + Angle(2.0*osg::PI, Units::RADIANS);
        double newAzim = _setVP0->heading()->as(Units::RADIANS) + tp*d_azim.as(Units::RADIANS);

        // Calculate the new pitch:
        Angle d_pitch = _setVP1->pitch().get() - _setVP0->pitch().get();
        double newPitch = _setVP0->pitch()->as(Units::RADIANS) + tp*d_pitch.as(Units::RADIANS);

        // Calculate the new range:
        Distance d_range = _setVP1->range().get() - _setVP0->range().get();
        double newRange =
            _setVP0->range()->as(Units::METERS) +
            d_range.as(Units::METERS)*tp + sin(osg::PI*tp)*_setVPArcHeight;

        // Calculate the offsets
        osg::Vec3d offset0 = _setVP0->positionOffset().getOrUse(osg::Vec3d(0,0,0));
        osg::Vec3d offset1 = _setVP1->positionOffset().getOrUse(osg::Vec3d(0,0,0));
        osg::Vec3d newOffset = offset0 + (offset1-offset0)*tp;

        // Activate.
        setLookAt( newCenter, newAzim, newPitch, newRange, newOffset );

        // interpolate tether rotation:
        _tetherRotation.slerp(tp, _tetherRotationVP0, _tetherRotationVP1);

        // At t=1 the transition is complete.
        if ( t >= 1.0 )
        {
            _setVP0.unset();

            // If this was a transition into a tether, keep the endpoint around so we can
            // continue tracking it.
            if ( !isTethering() )
            {
                _setVP1.unset();
            }
        }

        return tp;
    }
}

setViewpointFrame函數返回的就是0到1之間的插值系數。

        // Remaining time is the full duration minus the time since initiation:
        double elapsed = time_s - _setVPStartTime->as(Units::SECONDS);
        double t = std::min(1.0, elapsed / _setVPDuration.as(Units::SECONDS));

剩余時間是整個時間減去自啟動以來的時間:

  elapsed     是間隔時間

  t | tp      是間隔系數

_setVPArcHeight   是弧頂高(初始和結束兩點之間如果,有一個是最高點則,弧頂高為0)

到vrecameraManipulator.cpp 1172行,未完

[osg][osgEarth]EarthManipulator關於oe漫遊器的handle部分解讀