OpenWalnut  1.2.5
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
WPickHandler.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <iostream>
26 #include <string>
27 
28 #include <osg/Vec3>
29 
30 #include "../common/math/linearAlgebra/WLinearAlgebra.h"
31 
32 #include "WPickHandler.h"
33 #include "WPickInfo.h"
34 
36  : m_hitResult( WPickInfo() ),
37  m_startPick( WPickInfo() ),
38  m_shift( false ),
39  m_ctrl( false ),
40  m_viewerName( "" ),
41  m_paintMode( 0 ),
42  m_mouseButton( WPickInfo::NOMOUSE )
43 {
44 }
45 
46 WPickHandler::WPickHandler( std::string viewerName )
47  : m_hitResult( WPickInfo() ),
48  m_startPick( WPickInfo() ),
49  m_shift( false ),
50  m_ctrl( false ),
51  m_viewerName( viewerName ),
52  m_paintMode( 0 ),
53  m_mouseButton( WPickInfo::NOMOUSE )
54 {
55 }
56 
58 {
59 }
60 
62 {
63  return m_hitResult;
64 }
65 
66 boost::signals2::signal1< void, WPickInfo >* WPickHandler::getPickSignal()
67 {
68  return &m_pickSignal;
69 }
70 
71 bool WPickHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
72 {
73  switch ( ea.getEventType() )
74  {
75  case osgGA::GUIEventAdapter::DRAG : // Mouse pushed an dragged
76  case osgGA::GUIEventAdapter::PUSH : // Mousebutton pushed
77  {
78  unsigned int buttonMask = ea.getButtonMask();
79  if( buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON )
80  {
81  m_mouseButton = WPickInfo::MOUSE_RIGHT;
82  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
83  if( view )
84  {
85  pick( view, ea );
86  }
87  }
88  if( ( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) && ( m_paintMode == 1 ) )
89  {
90  m_mouseButton = WPickInfo::MOUSE_LEFT;
91  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
92  if( view )
93  {
94  pick( view, ea );
95  }
96  }
97  return false;
98  }
99  case osgGA::GUIEventAdapter::RELEASE : // Mousebutton released
100  {
101  m_mouseButton = WPickInfo::NOMOUSE;
102  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
103  if( view )
104  {
105  unpick();
106  }
107  return false;
108  }
109  case osgGA::GUIEventAdapter::KEYUP : // Key on keyboard released.
110  {
111  m_shift = false;
112  m_ctrl = false;
113  return false;
114  }
115  case osgGA::GUIEventAdapter::KEYDOWN : // Key on keyboard pushed.
116  {
117  if( ea.getKey() == 'c' )
118  {
119  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
120  osg::ref_ptr< osgGA::GUIEventAdapter > event = new osgGA::GUIEventAdapter( ea );
121  event->setX( ( ea.getXmin() + ea.getXmax() ) * 0.5 );
122  event->setY( ( ea.getYmin() + ea.getYmax() ) * 0.5 );
123  if( view )
124  {
125  pick( view, *event );
126  }
127  }
128  if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L )
129  {
130  m_shift = true;
131  }
132  if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_R )
133  {
134  m_ctrl = true;
135  }
136  return false;
137  }
138  default:
139  return false;
140  }
141 }
142 
144 {
145  if( m_hitResult != WPickInfo() )
146  {
147  m_hitResult = WPickInfo( "unpick", m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
149  }
151 }
152 
153 std::string extractSuitableName( osgUtil::LineSegmentIntersector::Intersections::iterator hitr )
154 {
155  if( !hitr->nodePath.empty() && !( hitr->nodePath.back()->getName().empty() ) )
156  {
157  return hitr->nodePath.back()->getName();
158  }
159  else if( hitr->drawable.valid() )
160  {
161  return hitr->drawable->className();
162  }
163  assert( 0 && "This should not happen. Tell \"wiebel\" if it does." );
164  return ""; // This line will not be reached.
165 }
166 
168 {
169  if( m_shift )
170  {
171  pickInfo->setModifierKey( WPickInfo::SHIFT );
172  }
173 
174  if( m_ctrl )
175  {
176  pickInfo->setModifierKey( WPickInfo::STRG );
177  }
178 }
179 
180 void WPickHandler::pick( osgViewer::View* view, const osgGA::GUIEventAdapter& ea )
181 {
182  osgUtil::LineSegmentIntersector::Intersections intersections;
184  float x = ea.getX(); // pixel position in x direction
185  float y = ea.getY(); // pixel position in x direction
186 
187  WPickInfo pickInfo;
188 
189  updatePickInfoModifierKeys( &pickInfo );
190 
191  // if we are in another viewer than the main view we just need the pixel position
192  if( m_viewerName != "" && m_viewerName != "main" )
193  {
194  pickInfo = WPickInfo( "", m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
196  m_hitResult = pickInfo;
197 
198  // if nothing was picked before remember the currently picked.
199  m_startPick = pickInfo;
200 
202 
203  return;
204  }
205 
206  bool intersetionsExist = view->computeIntersections( x, y, intersections );
207 
208  // if something is picked, get the right thing from the list, because it might be hidden.
209  bool startPickIsStillInList = false;
210  osgUtil::LineSegmentIntersector::Intersections::iterator hitr;
211  if( intersetionsExist )
212  {
213  assert( intersections.size() );
214  hitr = intersections.begin();
215 
216  bool ignoreFirst = m_ctrl;
217 
218  while( hitr != intersections.end() )
219  {
220  std::string nodeName = extractSuitableName( hitr );
221  // now we skip everything that starts with an underscore if not in paint mode
222  if( nodeName[0] == '_' && ( m_paintMode == 0 ) )
223  {
224  ++hitr;
225  }
226  // if ctrl is pressed we skip the first thing that gets hit by the pick
227  else if( ignoreFirst )
228  {
229  ++hitr;
230  ignoreFirst = false;
231  }
232  else
233  {
234  break;
235  }
236  }
237 
238  if( hitr == intersections.end() )
239  {
240  // after everything was ignored nothing pickable remained and we have noting picked before
241  // we just stop further processing.
242  if( m_startPick.getName() == "" )
243  {
244  return;
245  }
246  }
247 
248  // if we have a previous pick we search for it in the list
249  if( m_startPick.getName() != "" && m_startPick.getName() != "unpick" )
250  {
251  while( ( hitr != intersections.end() ) && !startPickIsStillInList )
252  {
253  WPickInfo pickInfoTmp( extractSuitableName( hitr ), m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
254  startPickIsStillInList |= ( pickInfoTmp.getName() == m_startPick.getName() );
255 
256  if( !startPickIsStillInList ) // if iteration not finished yet go on in list
257  {
258  ++hitr;
259  }
260  }
261  }
262  } // end of if( intersetionsExist )
263  else
264  {
265  // if we found no intersection and we have noting picked before
266  // we want to return "nothing" in order to provide the pixel coordinates
267  // even though we did not hit anything.
268  if( m_startPick.getName() == "" )
269  {
270  pickInfo = WPickInfo( "nothing", m_viewerName, WPosition( 0.0, 0.0, 0.0 ), std::make_pair( x, y ),
271  m_startPick.getModifierKey(), m_mouseButton, WVector3d( 0.0, 0.0, 0.0 ) );
272 
273  m_hitResult = pickInfo;
275  return;
276  }
277  }
278 
279  // Set the new pickInfo if the previously picked is still in list or we have a pick in conjunction with previously no pick
280  if( startPickIsStillInList || ( intersetionsExist && ( m_startPick.getName() == "unpick" || m_startPick.getName() == "" ) ) )
281  {
282  // if nothing was picked before, or the previously picked was found: set new pickInfo
283  WPosition pickPos;
284  pickPos[0] = hitr->getWorldIntersectPoint()[0];
285  pickPos[1] = hitr->getWorldIntersectPoint()[1];
286  pickPos[2] = hitr->getWorldIntersectPoint()[2];
287 
288  WVector3d pickNormal;
289  pickNormal[0] = hitr->getWorldIntersectNormal()[0];
290  pickNormal[1] = hitr->getWorldIntersectNormal()[1];
291  pickNormal[2] = hitr->getWorldIntersectNormal()[2];
292  pickInfo = WPickInfo( extractSuitableName( hitr ), m_viewerName, pickPos, std::make_pair( x, y ),
293  pickInfo.getModifierKey(), m_mouseButton, pickNormal );
294  }
295 
296  // Use the old PickInfo with updated pixel info if we have previously picked something but the old is not in list anymore
297  if( !startPickIsStillInList && m_startPick.getName() != "" && m_startPick.getName() != "unpick" )
298  {
299  pickInfo = WPickInfo( m_startPick.getName(), m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
301  }
302 
303  m_hitResult = pickInfo;
304 
305  // if nothing was picked before remember the currently picked.
306  m_startPick = pickInfo;
307 
309 }
310 
312 {
313  m_paintMode = mode;
314 }