OpenWalnut
1.4.0
|
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 <string> 00026 00027 #include "../common/WLogger.h" 00028 00029 #include "WPickHandler.h" 00030 00031 WPickHandler::WPickHandler() 00032 : m_hitResult( WPickInfo() ), 00033 m_startPick( WPickInfo() ), 00034 m_shift( false ), 00035 m_ctrl( false ), 00036 m_viewerName( "" ), 00037 m_paintMode( 0 ), 00038 m_mouseButton( WPickInfo::NOMOUSE ), 00039 m_inPickMode( false ), 00040 m_scrollWheel( 0 ) 00041 { 00042 } 00043 00044 WPickHandler::WPickHandler( std::string viewerName ) 00045 : m_hitResult( WPickInfo() ), 00046 m_startPick( WPickInfo() ), 00047 m_shift( false ), 00048 m_ctrl( false ), 00049 m_viewerName( viewerName ), 00050 m_paintMode( 0 ), 00051 m_mouseButton( WPickInfo::NOMOUSE ), 00052 m_inPickMode( false ), 00053 m_scrollWheel( 0 ) 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::SCROLL : // Wheel 00110 { 00111 if( m_inPickMode ) 00112 { 00113 switch( ea.getScrollingMotion() ) 00114 { 00115 case osgGA::GUIEventAdapter::SCROLL_UP: 00116 m_scrollWheel++; 00117 break; 00118 case osgGA::GUIEventAdapter::SCROLL_DOWN: 00119 m_scrollWheel--; 00120 case osgGA::GUIEventAdapter::SCROLL_2D: 00121 // FIXME: the osg doc tells us nothing about this value, but is seems to be always 120 or -120 00122 if( ea.getScrollingDeltaY() > 0 ) 00123 { 00124 m_scrollWheel++; 00125 } 00126 else 00127 { 00128 m_scrollWheel--; 00129 } 00130 break; 00131 default: 00132 break; 00133 } 00134 00135 // handle as pick event 00136 osgViewer::View* view = static_cast< osgViewer::View* >( &aa ); 00137 if( view ) 00138 { 00139 pick( view, ea ); 00140 } 00141 ea.setHandled( true ); 00142 return true; 00143 } 00144 return false; 00145 } 00146 case osgGA::GUIEventAdapter::KEYUP : // Key on keyboard released. 00147 { 00148 m_shift = false; 00149 m_ctrl = false; 00150 return false; 00151 } 00152 case osgGA::GUIEventAdapter::KEYDOWN : // Key on keyboard pushed. 00153 { 00154 if( ea.getKey() == 'c' ) 00155 { 00156 osgViewer::View* view = static_cast< osgViewer::View* >( &aa ); 00157 osg::ref_ptr< osgGA::GUIEventAdapter > event = new osgGA::GUIEventAdapter( ea ); 00158 event->setX( ( ea.getXmin() + ea.getXmax() ) * 0.5 ); 00159 event->setY( ( ea.getYmin() + ea.getYmax() ) * 0.5 ); 00160 if( view ) 00161 { 00162 pick( view, *event ); 00163 } 00164 } 00165 if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L ) 00166 { 00167 m_shift = true; 00168 } 00169 if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_R ) 00170 { 00171 m_ctrl = true; 00172 } 00173 return false; 00174 } 00175 default: 00176 return false; 00177 } 00178 } 00179 00180 void WPickHandler::unpick( ) 00181 { 00182 m_inPickMode = false; 00183 if( m_hitResult != WPickInfo() ) 00184 { 00185 m_hitResult = WPickInfo( "unpick", m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE ); 00186 m_startPick = WPickInfo(); 00187 m_scrollWheel = 0; 00188 } 00189 m_pickSignal( getHitResult() ); 00190 } 00191 00192 std::string extractSuitableName( osgUtil::LineSegmentIntersector::Intersections::iterator hitr ) 00193 { 00194 if( !hitr->nodePath.empty() && !( hitr->nodePath.back()->getName().empty() ) ) 00195 { 00196 return hitr->nodePath.back()->getName(); 00197 } 00198 else if( hitr->drawable.valid() ) 00199 { 00200 return hitr->drawable->className(); 00201 } 00202 assert( 0 && "This should not happen. Tell \"wiebel\" if it does." ); 00203 return ""; // This line will not be reached. 00204 } 00205 00206 void WPickHandler::updatePickInfoModifierKeys( WPickInfo* pickInfo ) 00207 { 00208 if( m_shift ) 00209 { 00210 pickInfo->setModifierKey( WPickInfo::SHIFT ); 00211 } 00212 00213 if( m_ctrl ) 00214 { 00215 pickInfo->setModifierKey( WPickInfo::STRG ); 00216 } 00217 } 00218 00219 void WPickHandler::pick( osgViewer::View* view, const osgGA::GUIEventAdapter& ea ) 00220 { 00221 osgUtil::LineSegmentIntersector::Intersections intersections; 00222 m_hitResult = WPickInfo(); 00223 float x = ea.getX(); // pixel position in x direction 00224 float y = ea.getY(); // pixel position in x direction 00225 00226 WPickInfo pickInfo; 00227 00228 updatePickInfoModifierKeys( &pickInfo ); 00229 00230 // if we are in another viewer than the main view we just need the pixel position 00231 if( m_viewerName != "" && m_viewerName != "Main View" ) 00232 { 00233 pickInfo = WPickInfo( "", m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ), 00234 m_startPick.getModifierKey(), m_mouseButton, m_startPick.getPickNormal(), m_scrollWheel ); 00235 m_hitResult = pickInfo; 00236 00237 // if nothing was picked before remember the currently picked. 00238 m_startPick = pickInfo; 00239 00240 m_pickSignal( getHitResult() ); 00241 00242 return; 00243 } 00244 00245 bool intersetionsExist = view->computeIntersections( x, y, intersections, 0xFFFFFFF0 ); 00246 00247 // if something is picked, get the right thing from the list, because it might be hidden. 00248 bool startPickIsStillInList = false; 00249 osgUtil::LineSegmentIntersector::Intersections::iterator hitr; 00250 if( intersetionsExist ) 00251 { 00252 assert( intersections.size() ); 00253 hitr = intersections.begin(); 00254 00255 bool ignoreFirst = m_ctrl; 00256 00257 while( hitr != intersections.end() ) 00258 { 00259 std::string nodeName = extractSuitableName( hitr ); 00260 // now we skip everything that starts with an underscore if not in paint mode 00261 if( nodeName[0] == '_' && ( m_paintMode == 0 ) ) 00262 { 00263 ++hitr; 00264 } 00265 // if ctrl is pressed we skip the first thing that gets hit by the pick 00266 else if( ignoreFirst ) 00267 { 00268 ++hitr; 00269 ignoreFirst = false; 00270 } 00271 else 00272 { 00273 break; 00274 } 00275 } 00276 00277 if( hitr == intersections.end() ) 00278 { 00279 // after everything was ignored nothing pickable remained and we have noting picked before 00280 // we just stop further processing. 00281 if( m_startPick.getName() == "" ) 00282 { 00283 return; 00284 } 00285 } 00286 00287 // if we have a previous pick we search for it in the list 00288 if( m_startPick.getName() != "" && m_startPick.getName() != "unpick" ) 00289 { 00290 while( ( hitr != intersections.end() ) && !startPickIsStillInList ) 00291 { 00292 WPickInfo pickInfoTmp( extractSuitableName( hitr ), m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE ); 00293 startPickIsStillInList |= ( pickInfoTmp.getName() == m_startPick.getName() ); 00294 00295 if( !startPickIsStillInList ) // if iteration not finished yet go on in list 00296 { 00297 ++hitr; 00298 } 00299 } 00300 } 00301 } // end of if( intersetionsExist ) 00302 else 00303 { 00304 // if we found no intersection and we have noting picked before 00305 // we want to return "nothing" in order to provide the pixel coordinates 00306 // even though we did not hit anything. 00307 if( m_startPick.getName() == "" ) 00308 { 00309 pickInfo = WPickInfo( "nothing", m_viewerName, WPosition( 0.0, 0.0, 0.0 ), std::make_pair( x, y ), 00310 m_startPick.getModifierKey(), m_mouseButton, WVector3d( 0.0, 0.0, 0.0 ), m_scrollWheel ); 00311 00312 m_hitResult = pickInfo; 00313 m_pickSignal( getHitResult() ); 00314 return; 00315 } 00316 } 00317 00318 // Set the new pickInfo if the previously picked is still in list or we have a pick in conjunction with previously no pick 00319 if( startPickIsStillInList || ( intersetionsExist && ( m_startPick.getName() == "unpick" || m_startPick.getName() == "" ) ) ) 00320 { 00321 // if nothing was picked before, or the previously picked was found: set new pickInfo 00322 WPosition pickPos; 00323 pickPos[0] = hitr->getWorldIntersectPoint()[0]; 00324 pickPos[1] = hitr->getWorldIntersectPoint()[1]; 00325 pickPos[2] = hitr->getWorldIntersectPoint()[2]; 00326 00327 WVector3d pickNormal; 00328 pickNormal[0] = hitr->getWorldIntersectNormal()[0]; 00329 pickNormal[1] = hitr->getWorldIntersectNormal()[1]; 00330 pickNormal[2] = hitr->getWorldIntersectNormal()[2]; 00331 pickInfo = WPickInfo( extractSuitableName( hitr ), m_viewerName, pickPos, std::make_pair( x, y ), 00332 pickInfo.getModifierKey(), m_mouseButton, pickNormal, m_scrollWheel ); 00333 } 00334 00335 // Use the old PickInfo with updated pixel info if we have previously picked something but the old is not in list anymore 00336 if( !startPickIsStillInList && m_startPick.getName() != "" && m_startPick.getName() != "unpick" ) 00337 { 00338 pickInfo = WPickInfo( m_startPick.getName(), m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ), 00339 m_startPick.getModifierKey(), m_mouseButton, m_startPick.getPickNormal(), m_scrollWheel ); 00340 } 00341 00342 m_hitResult = pickInfo; 00343 00344 // if nothing was picked before remember the currently picked. 00345 m_startPick = pickInfo; 00346 m_inPickMode = true; 00347 00348 m_pickSignal( getHitResult() ); 00349 } 00350 00351 void WPickHandler::setPaintMode( int mode ) 00352 { 00353 m_paintMode = mode; 00354 }