WPickHandler.cpp 12.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------

#include <string>

#include "WPickHandler.h"
28
#include "../common/WAssert.h"
29

30 31
const std::string WPickHandler::unpickString = "unpick";

Mathias Goldau's avatar
[MERGE]  
Mathias Goldau committed
32 33 34
WPickHandler::WPickHandler()
    : m_hitResult( WPickInfo() ),
      m_startPick( WPickInfo() ),
35
      m_shift( false ),
36
      m_ctrl( false ),
37
      m_viewerName( "" ),
38
      m_paintMode( false ),
39 40 41
      m_mouseButton( WPickInfo::NOMOUSE ),
      m_inPickMode( false ),
      m_scrollWheel( 0 )
42 43
{
}
44 45 46 47 48

WPickHandler::WPickHandler( std::string viewerName )
    : m_hitResult( WPickInfo() ),
      m_startPick( WPickInfo() ),
      m_shift( false ),
49
      m_ctrl( false ),
50
      m_viewerName( viewerName ),
51
      m_paintMode( false ),
52 53 54
      m_mouseButton( WPickInfo::NOMOUSE ),
      m_inPickMode( false ),
      m_scrollWheel( 0 )
55 56 57
{
}

58 59 60 61
WPickHandler::~WPickHandler()
{
}

62
WPickInfo WPickHandler::getHitResult()
63
{
schurade's avatar
schurade committed
64
    return m_hitResult;
65 66
}

67
boost::signals2::signal< void( WPickInfo ) >* WPickHandler::getPickSignal()
68 69 70 71
{
    return &m_pickSignal;
}

72 73
bool WPickHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
{
74
    switch( ea.getEventType() )
75
    {
76
        case osgGA::GUIEventAdapter::DRAG : // Mouse pushed an dragged
77
        case osgGA::GUIEventAdapter::PUSH : // Mousebutton pushed
78 79 80 81
        {
            unsigned int buttonMask = ea.getButtonMask();
            if( buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON )
            {
82 83
                m_mouseButton = WPickInfo::MOUSE_RIGHT;
                osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
84
                if( view )
85 86 87 88
                {
                    pick( view, ea );
                }
            }
89
            if( ( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) && ( m_paintMode ) )
90 91
            {
                m_mouseButton = WPickInfo::MOUSE_LEFT;
92
                osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
93
                if( view )
94 95 96 97 98 99 100
                {
                    pick( view, ea );
                }
            }
            return false;
        }
        case osgGA::GUIEventAdapter::RELEASE : // Mousebutton released
101
        {
102
            m_mouseButton = WPickInfo::NOMOUSE;
103
            osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
104
            if( view )
105
            {
106
                unpick();
107
            }
108 109
            return false;
        }
110 111 112 113 114 115 116 117 118 119 120
        case osgGA::GUIEventAdapter::SCROLL : // Wheel
        {
            if( m_inPickMode )
            {
                switch( ea.getScrollingMotion() )
                {
                    case osgGA::GUIEventAdapter::SCROLL_UP:
                        m_scrollWheel++;
                        break;
                    case osgGA::GUIEventAdapter::SCROLL_DOWN:
                        m_scrollWheel--;
121
                        break;
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
                    case osgGA::GUIEventAdapter::SCROLL_2D:
                        // FIXME: the osg doc tells us nothing about this value, but is seems to be always 120 or -120
                        if( ea.getScrollingDeltaY() > 0 )
                        {
                            m_scrollWheel++;
                        }
                        else
                        {
                            m_scrollWheel--;
                        }
                        break;
                    default:
                        break;
                }

                // handle as pick event
                osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
                if( view )
                {
                    pick( view, ea );
                }
                ea.setHandled( true );
                return true;
            }
            return false;
        }
148 149 150
        case osgGA::GUIEventAdapter::KEYUP : // Key on keyboard released.
        {
            m_shift = false;
151
            m_ctrl = false;
152 153
            return false;
        }
154
        case osgGA::GUIEventAdapter::KEYDOWN : // Key on keyboard pushed.
155
        {
156
            if( ea.getKey() == 'c' )
157 158 159 160 161
            {
                osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
                osg::ref_ptr< osgGA::GUIEventAdapter > event = new osgGA::GUIEventAdapter( ea );
                event->setX( ( ea.getXmin() + ea.getXmax() ) * 0.5 );
                event->setY( ( ea.getYmin() + ea.getYmax() ) * 0.5 );
162
                if( view )
163 164 165 166
                {
                    pick( view, *event );
                }
            }
167
            if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L )
168 169 170
            {
                m_shift = true;
            }
171
            if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L ||  ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_R )
172 173 174
            {
                m_ctrl = true;
            }
175 176 177 178 179 180 181
            return false;
        }
        default:
            return false;
    }
}

182 183
void WPickHandler::unpick( )
{
184
    m_inPickMode = false;
185
    if( m_hitResult != WPickInfo() )
186
    {
187
        m_hitResult = WPickInfo( WPickHandler::unpickString, m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
188
        m_startPick = WPickInfo();
189
        m_scrollWheel = 0;
190 191 192 193
    }
    m_pickSignal( getHitResult() );
}

194 195
std::string extractSuitableName( osgUtil::LineSegmentIntersector::Intersections::iterator hitr )
{
196
    if( !hitr->nodePath.empty() && !( hitr->nodePath.back()->getName().empty() ) )
197 198 199
    {
        return hitr->nodePath.back()->getName();
    }
200
    else if( hitr->drawable.valid() )
201 202 203
    {
        return  hitr->drawable->className();
    }
204 205
    assert( 0 && "This should not happen. Tell \"wiebel\" if it does." );
    return ""; // This line will not be reached.
206 207
}

208 209 210 211 212 213 214
void WPickHandler::updatePickInfoModifierKeys( WPickInfo* pickInfo )
{
    if( m_shift )
    {
        pickInfo->setModifierKey( WPickInfo::SHIFT );
    }

215
    if( m_ctrl )
216 217 218 219 220
    {
        pickInfo->setModifierKey( WPickInfo::STRG );
    }
}

221 222 223
void WPickHandler::pick( osgViewer::View* view, const osgGA::GUIEventAdapter& ea )
{
    osgUtil::LineSegmentIntersector::Intersections intersections;
224
    m_hitResult = WPickInfo();
225
    float x = ea.getX(); // pixel position in x direction
226
    float y = ea.getY(); // pixel position in y direction
227

228 229
    WPickInfo pickInfo;

230
    updatePickInfoModifierKeys( &pickInfo );
231

232
    // if we are in another viewer than the main view we just need the pixel position
233
    if( m_viewerName != "" && m_viewerName != "Main View" )
234 235
    {
        pickInfo = WPickInfo( "", m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
236
                              m_startPick.getModifierKey(), m_mouseButton, m_startPick.getPickNormal(), m_scrollWheel );
237 238 239 240 241 242 243 244 245 246
        m_hitResult = pickInfo;

        // if nothing was picked before remember the currently picked.
        m_startPick = pickInfo;

        m_pickSignal( getHitResult() );

        return;
    }

247
    bool intersetionsExist = view->computeIntersections( x, y, intersections, 0xFFFFFFF0 );
248 249 250 251 252

    // if something is picked, get the right thing from the list, because it might be hidden.
    bool startPickIsStillInList = false;
    osgUtil::LineSegmentIntersector::Intersections::iterator hitr;
    if( intersetionsExist )
253
    {
254 255
        assert( intersections.size() );
        hitr = intersections.begin();
256

257
        bool ignoreFirst = m_ctrl;
258

259
        while( hitr != intersections.end() )
260
        {
261
            std::string nodeName = extractSuitableName( hitr );
Alexander Wiebel's avatar
Alexander Wiebel committed
262
            // now we skip everything that starts with an underscore if not in paint mode
263
            if(  nodeName[0] == '_' && ( !m_paintMode ) )
264 265 266
            {
                ++hitr;
            }
267 268 269 270 271
            // // now we skip stuff with non-expressive names often used
            // else if( nodeName == "Geometry" )
            // {
            //     ++hitr;
            // }
272
            // if ctrl is pressed we skip the first thing that gets hit by the pick
273
            else if( ignoreFirst )
274 275 276 277
            {
                ++hitr;
                ignoreFirst = false;
            }
278 279 280 281
            else
            {
                break;
            }
282 283
        }

284
        if( hitr == intersections.end() )
285
        {
286
            // after everything was ignored nothing pickable remained and we have nothing picked before
287 288 289 290 291
            // we just stop further processing.
            if(  m_startPick.getName() == "" )
            {
                return;
            }
292 293
        }

294
        // if we have a previous pick we search for it in the list
295
        if( m_startPick.getName() != ""  && m_startPick.getName() != WPickHandler::unpickString )
296
        {
297
            while( ( hitr != intersections.end() ) && !startPickIsStillInList )
298
            {
299
                WPickInfo pickInfoTmp( extractSuitableName( hitr ), m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
300 301 302 303 304 305
                startPickIsStillInList |= ( pickInfoTmp.getName() == m_startPick.getName() );

                if( !startPickIsStillInList ) // if iteration not finished yet go on in list
                {
                    ++hitr;
                }
306
            }
307
        }
308 309
    } // end of if( intersetionsExist )
    else
310
    {
311
        // if we found no intersection and we have noting picked before
312 313 314 315
        // we want to return "nothing" in order to provide the pixel coordinates
        // even though we did not hit anything.
        if(  m_startPick.getName() == "" )
        {
316
            pickInfo = WPickInfo( "nothing", m_viewerName, WPosition( 0.0, 0.0, 0.0 ), std::make_pair( x, y ),
317
                                  m_startPick.getModifierKey(), m_mouseButton, WVector3d( 0.0, 0.0, 0.0 ), m_scrollWheel );
318

319 320 321 322
            m_hitResult = pickInfo;
            m_pickSignal( getHitResult() );
            return;
        }
323
    }
324

325
    // Set the new pickInfo if the previously picked is still in list or we have a pick in conjunction with previously no pick
326
    if( startPickIsStillInList || ( intersetionsExist && ( m_startPick.getName() == WPickHandler::unpickString || m_startPick.getName() == "" ) ) )
327 328
    {
        // if nothing was picked before, or the previously picked was found: set new pickInfo
329
        WPosition pickPos;
330 331 332 333
        pickPos[0] = hitr->getWorldIntersectPoint()[0];
        pickPos[1] = hitr->getWorldIntersectPoint()[1];
        pickPos[2] = hitr->getWorldIntersectPoint()[2];

334
        WVector3d pickNormal;
335 336 337
        pickNormal[0] = hitr->getWorldIntersectNormal()[0];
        pickNormal[1] = hitr->getWorldIntersectNormal()[1];
        pickNormal[2] = hitr->getWorldIntersectNormal()[2];
338
        pickInfo = WPickInfo( extractSuitableName( hitr ), m_viewerName, pickPos, std::make_pair( x, y ),
339
                              pickInfo.getModifierKey(), m_mouseButton, pickNormal, m_scrollWheel );
340
    }
341

342
    // Use the old PickInfo with updated pixel info if we have previously picked something but the old is not in list anymore
343
    if( !startPickIsStillInList && m_startPick.getName() != ""  && m_startPick.getName() != WPickHandler::unpickString )
344
    {
345
        pickInfo = WPickInfo( m_startPick.getName(), m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
346
                              m_startPick.getModifierKey(), m_mouseButton, m_startPick.getPickNormal(), m_scrollWheel );
347
    }
348

349 350 351 352
    m_hitResult = pickInfo;

    // if nothing was picked before remember the currently picked.
    m_startPick = pickInfo;
353
    m_inPickMode = true;
354

355
    m_pickSignal( getHitResult() );
356
}
357

358 359 360 361 362
void WPickHandler::setPaintMode( bool paintMode )
{
    m_paintMode = paintMode;
}

363 364
void WPickHandler::setPaintMode( int mode )
{
365 366 367 368 369 370 371 372 373
    WAssert( mode == 1 || mode == 0, "Unexpected value" );
    if( mode == 1 )
    {
        m_paintMode = true;
    }
    else
    {
        m_paintMode = false;
    }
374
}