OpenWalnut
1.2.5
|
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 }