OpenWalnut 1.2.5

WPickHandler.cpp

00001 //---------------------------------------------------------------------------
00002 //
00003 // Project: OpenWalnut ( http://www.openwalnut.org )
00004 //
00005 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
00006 // For more information see http://www.openwalnut.org/copying
00007 //
00008 // This file is part of OpenWalnut.
00009 //
00010 // OpenWalnut is free software: you can redistribute it and/or modify
00011 // it under the terms of the GNU Lesser General Public License as published by
00012 // the Free Software Foundation, either version 3 of the License, or
00013 // (at your option) any later version.
00014 //
00015 // OpenWalnut is distributed in the hope that it will be useful,
00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 // GNU Lesser General Public License for more details.
00019 //
00020 // You should have received a copy of the GNU Lesser General Public License
00021 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
00022 //
00023 //---------------------------------------------------------------------------
00024 
00025 #include <iostream>
00026 #include <string>
00027 
00028 #include <osg/Vec3>
00029 
00030 #include "../common/math/linearAlgebra/WLinearAlgebra.h"
00031 
00032 #include "WPickHandler.h"
00033 #include "WPickInfo.h"
00034 
00035 WPickHandler::WPickHandler()
00036     : m_hitResult( WPickInfo() ),
00037       m_startPick( WPickInfo() ),
00038       m_shift( false ),
00039       m_ctrl( false ),
00040       m_viewerName( "" ),
00041       m_paintMode( 0 ),
00042       m_mouseButton( WPickInfo::NOMOUSE )
00043 {
00044 }
00045 
00046 WPickHandler::WPickHandler( std::string viewerName )
00047     : m_hitResult( WPickInfo() ),
00048       m_startPick( WPickInfo() ),
00049       m_shift( false ),
00050       m_ctrl( false ),
00051       m_viewerName( viewerName ),
00052       m_paintMode( 0 ),
00053       m_mouseButton( WPickInfo::NOMOUSE )
00054 {
00055 }
00056 
00057 WPickHandler::~WPickHandler()
00058 {
00059 }
00060 
00061 WPickInfo WPickHandler::getHitResult()
00062 {
00063     return m_hitResult;
00064 }
00065 
00066 boost::signals2::signal1< void, WPickInfo >* WPickHandler::getPickSignal()
00067 {
00068     return &m_pickSignal;
00069 }
00070 
00071 bool WPickHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
00072 {
00073     switch ( ea.getEventType() )
00074     {
00075         case osgGA::GUIEventAdapter::DRAG : // Mouse pushed an dragged
00076         case osgGA::GUIEventAdapter::PUSH : // Mousebutton pushed
00077         {
00078             unsigned int buttonMask = ea.getButtonMask();
00079             if( buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON )
00080             {
00081                 m_mouseButton = WPickInfo::MOUSE_RIGHT;
00082                 osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
00083                 if( view )
00084                 {
00085                     pick( view, ea );
00086                 }
00087             }
00088             if( ( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) && ( m_paintMode == 1 ) )
00089             {
00090                 m_mouseButton = WPickInfo::MOUSE_LEFT;
00091                 osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
00092                 if( view )
00093                 {
00094                     pick( view, ea );
00095                 }
00096             }
00097             return false;
00098         }
00099         case osgGA::GUIEventAdapter::RELEASE : // Mousebutton released
00100         {
00101             m_mouseButton = WPickInfo::NOMOUSE;
00102             osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
00103             if( view )
00104             {
00105                 unpick();
00106             }
00107             return false;
00108         }
00109         case osgGA::GUIEventAdapter::KEYUP : // Key on keyboard released.
00110         {
00111             m_shift = false;
00112             m_ctrl = false;
00113             return false;
00114         }
00115         case osgGA::GUIEventAdapter::KEYDOWN : // Key on keyboard pushed.
00116         {
00117             if( ea.getKey() == 'c' )
00118             {
00119                 osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
00120                 osg::ref_ptr< osgGA::GUIEventAdapter > event = new osgGA::GUIEventAdapter( ea );
00121                 event->setX( ( ea.getXmin() + ea.getXmax() ) * 0.5 );
00122                 event->setY( ( ea.getYmin() + ea.getYmax() ) * 0.5 );
00123                 if( view )
00124                 {
00125                     pick( view, *event );
00126                 }
00127             }
00128             if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L )
00129             {
00130                 m_shift = true;
00131             }
00132             if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L ||  ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_R )
00133             {
00134                 m_ctrl = true;
00135             }
00136             return false;
00137         }
00138         default:
00139             return false;
00140     }
00141 }
00142 
00143 void WPickHandler::unpick( )
00144 {
00145     if( m_hitResult != WPickInfo() )
00146     {
00147         m_hitResult = WPickInfo( "unpick", m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
00148         m_startPick = WPickInfo();
00149     }
00150     m_pickSignal( getHitResult() );
00151 }
00152 
00153 std::string extractSuitableName( osgUtil::LineSegmentIntersector::Intersections::iterator hitr )
00154 {
00155     if( !hitr->nodePath.empty() && !( hitr->nodePath.back()->getName().empty() ) )
00156     {
00157         return hitr->nodePath.back()->getName();
00158     }
00159     else if( hitr->drawable.valid() )
00160     {
00161         return  hitr->drawable->className();
00162     }
00163     assert( 0 && "This should not happen. Tell \"wiebel\" if it does." );
00164     return ""; // This line will not be reached.
00165 }
00166 
00167 void WPickHandler::updatePickInfoModifierKeys( WPickInfo* pickInfo )
00168 {
00169     if( m_shift )
00170     {
00171         pickInfo->setModifierKey( WPickInfo::SHIFT );
00172     }
00173 
00174     if( m_ctrl )
00175     {
00176         pickInfo->setModifierKey( WPickInfo::STRG );
00177     }
00178 }
00179 
00180 void WPickHandler::pick( osgViewer::View* view, const osgGA::GUIEventAdapter& ea )
00181 {
00182     osgUtil::LineSegmentIntersector::Intersections intersections;
00183     m_hitResult = WPickInfo();
00184     float x = ea.getX(); // pixel position in x direction
00185     float y = ea.getY(); // pixel position in x direction
00186 
00187     WPickInfo pickInfo;
00188 
00189     updatePickInfoModifierKeys( &pickInfo );
00190 
00191     // if we are in another viewer than the main view we just need the pixel position
00192     if( m_viewerName != "" && m_viewerName != "main" )
00193     {
00194         pickInfo = WPickInfo( "", m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
00195                               m_startPick.getModifierKey(), m_mouseButton, m_startPick.getPickNormal() );
00196         m_hitResult = pickInfo;
00197 
00198         // if nothing was picked before remember the currently picked.
00199         m_startPick = pickInfo;
00200 
00201         m_pickSignal( getHitResult() );
00202 
00203         return;
00204     }
00205 
00206     bool intersetionsExist = view->computeIntersections( x, y, intersections );
00207 
00208     // if something is picked, get the right thing from the list, because it might be hidden.
00209     bool startPickIsStillInList = false;
00210     osgUtil::LineSegmentIntersector::Intersections::iterator hitr;
00211     if( intersetionsExist )
00212     {
00213         assert( intersections.size() );
00214         hitr = intersections.begin();
00215 
00216         bool ignoreFirst = m_ctrl;
00217 
00218         while( hitr != intersections.end() )
00219         {
00220             std::string nodeName = extractSuitableName( hitr );
00221             // now we skip everything that starts with an underscore if not in paint mode
00222             if(  nodeName[0] == '_' && ( m_paintMode == 0  ) )
00223             {
00224                 ++hitr;
00225             }
00226             // if ctrl is pressed we skip the first thing that gets hit by the pick
00227             else if( ignoreFirst )
00228             {
00229                 ++hitr;
00230                 ignoreFirst = false;
00231             }
00232             else
00233             {
00234                 break;
00235             }
00236         }
00237 
00238         if( hitr == intersections.end() )
00239         {
00240             // after everything was ignored nothing pickable remained and we have noting picked before
00241             // we just stop further processing.
00242             if(  m_startPick.getName() == "" )
00243             {
00244                 return;
00245             }
00246         }
00247 
00248         // if we have a previous pick we search for it in the list
00249         if( m_startPick.getName() != ""  && m_startPick.getName() != "unpick" )
00250         {
00251             while( ( hitr != intersections.end() ) && !startPickIsStillInList )
00252             {
00253                 WPickInfo pickInfoTmp( extractSuitableName( hitr ), m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
00254                 startPickIsStillInList |= ( pickInfoTmp.getName() == m_startPick.getName() );
00255 
00256                 if( !startPickIsStillInList ) // if iteration not finished yet go on in list
00257                 {
00258                     ++hitr;
00259                 }
00260             }
00261         }
00262     } // end of if( intersetionsExist )
00263     else
00264     {
00265         // if we found no intersection and we have noting picked before
00266         // we want to return "nothing" in order to provide the pixel coordinates
00267         // even though we did not hit anything.
00268         if(  m_startPick.getName() == "" )
00269         {
00270             pickInfo = WPickInfo( "nothing", m_viewerName, WPosition( 0.0, 0.0, 0.0 ), std::make_pair( x, y ),
00271                                   m_startPick.getModifierKey(), m_mouseButton, WVector3d( 0.0, 0.0, 0.0 ) );
00272 
00273             m_hitResult = pickInfo;
00274             m_pickSignal( getHitResult() );
00275             return;
00276         }
00277     }
00278 
00279     // Set the new pickInfo if the previously picked is still in list or we have a pick in conjunction with previously no pick
00280     if( startPickIsStillInList || ( intersetionsExist && ( m_startPick.getName() == "unpick" || m_startPick.getName() == "" ) ) )
00281     {
00282         // if nothing was picked before, or the previously picked was found: set new pickInfo
00283         WPosition pickPos;
00284         pickPos[0] = hitr->getWorldIntersectPoint()[0];
00285         pickPos[1] = hitr->getWorldIntersectPoint()[1];
00286         pickPos[2] = hitr->getWorldIntersectPoint()[2];
00287 
00288         WVector3d pickNormal;
00289         pickNormal[0] = hitr->getWorldIntersectNormal()[0];
00290         pickNormal[1] = hitr->getWorldIntersectNormal()[1];
00291         pickNormal[2] = hitr->getWorldIntersectNormal()[2];
00292         pickInfo = WPickInfo( extractSuitableName( hitr ), m_viewerName, pickPos, std::make_pair( x, y ),
00293                               pickInfo.getModifierKey(), m_mouseButton, pickNormal );
00294     }
00295 
00296     // Use the old PickInfo with updated pixel info if we have previously picked something but the old is not in list anymore
00297     if( !startPickIsStillInList && m_startPick.getName() != ""  && m_startPick.getName() != "unpick" )
00298     {
00299         pickInfo = WPickInfo( m_startPick.getName(), m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
00300                               m_startPick.getModifierKey(), m_mouseButton, m_startPick.getPickNormal() );
00301     }
00302 
00303     m_hitResult = pickInfo;
00304 
00305     // if nothing was picked before remember the currently picked.
00306     m_startPick = pickInfo;
00307 
00308     m_pickSignal( getHitResult() );
00309 }
00310 
00311 void WPickHandler::setPaintMode( int mode )
00312 {
00313     m_paintMode = mode;
00314 }
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends