OpenWalnut  1.4.0
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 <string>
26 
27 #include "../common/WLogger.h"
28 
29 #include "WPickHandler.h"
30 
32  : m_hitResult( WPickInfo() ),
33  m_startPick( WPickInfo() ),
34  m_shift( false ),
35  m_ctrl( false ),
36  m_viewerName( "" ),
37  m_paintMode( 0 ),
38  m_mouseButton( WPickInfo::NOMOUSE ),
39  m_inPickMode( false ),
40  m_scrollWheel( 0 )
41 {
42 }
43 
44 WPickHandler::WPickHandler( std::string viewerName )
45  : m_hitResult( WPickInfo() ),
46  m_startPick( WPickInfo() ),
47  m_shift( false ),
48  m_ctrl( false ),
49  m_viewerName( viewerName ),
50  m_paintMode( 0 ),
51  m_mouseButton( WPickInfo::NOMOUSE ),
52  m_inPickMode( false ),
53  m_scrollWheel( 0 )
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::SCROLL : // Wheel
110  {
111  if( m_inPickMode )
112  {
113  switch( ea.getScrollingMotion() )
114  {
115  case osgGA::GUIEventAdapter::SCROLL_UP:
116  m_scrollWheel++;
117  break;
118  case osgGA::GUIEventAdapter::SCROLL_DOWN:
119  m_scrollWheel--;
120  case osgGA::GUIEventAdapter::SCROLL_2D:
121  // FIXME: the osg doc tells us nothing about this value, but is seems to be always 120 or -120
122  if( ea.getScrollingDeltaY() > 0 )
123  {
124  m_scrollWheel++;
125  }
126  else
127  {
128  m_scrollWheel--;
129  }
130  break;
131  default:
132  break;
133  }
134 
135  // handle as pick event
136  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
137  if( view )
138  {
139  pick( view, ea );
140  }
141  ea.setHandled( true );
142  return true;
143  }
144  return false;
145  }
146  case osgGA::GUIEventAdapter::KEYUP : // Key on keyboard released.
147  {
148  m_shift = false;
149  m_ctrl = false;
150  return false;
151  }
152  case osgGA::GUIEventAdapter::KEYDOWN : // Key on keyboard pushed.
153  {
154  if( ea.getKey() == 'c' )
155  {
156  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
157  osg::ref_ptr< osgGA::GUIEventAdapter > event = new osgGA::GUIEventAdapter( ea );
158  event->setX( ( ea.getXmin() + ea.getXmax() ) * 0.5 );
159  event->setY( ( ea.getYmin() + ea.getYmax() ) * 0.5 );
160  if( view )
161  {
162  pick( view, *event );
163  }
164  }
165  if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L )
166  {
167  m_shift = true;
168  }
169  if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_R )
170  {
171  m_ctrl = true;
172  }
173  return false;
174  }
175  default:
176  return false;
177  }
178 }
179 
181 {
182  m_inPickMode = false;
183  if( m_hitResult != WPickInfo() )
184  {
185  m_hitResult = WPickInfo( "unpick", m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
187  m_scrollWheel = 0;
188  }
190 }
191 
192 std::string extractSuitableName( osgUtil::LineSegmentIntersector::Intersections::iterator hitr )
193 {
194  if( !hitr->nodePath.empty() && !( hitr->nodePath.back()->getName().empty() ) )
195  {
196  return hitr->nodePath.back()->getName();
197  }
198  else if( hitr->drawable.valid() )
199  {
200  return hitr->drawable->className();
201  }
202  assert( 0 && "This should not happen. Tell \"wiebel\" if it does." );
203  return ""; // This line will not be reached.
204 }
205 
207 {
208  if( m_shift )
209  {
210  pickInfo->setModifierKey( WPickInfo::SHIFT );
211  }
212 
213  if( m_ctrl )
214  {
215  pickInfo->setModifierKey( WPickInfo::STRG );
216  }
217 }
218 
219 void WPickHandler::pick( osgViewer::View* view, const osgGA::GUIEventAdapter& ea )
220 {
221  osgUtil::LineSegmentIntersector::Intersections intersections;
223  float x = ea.getX(); // pixel position in x direction
224  float y = ea.getY(); // pixel position in x direction
225 
226  WPickInfo pickInfo;
227 
228  updatePickInfoModifierKeys( &pickInfo );
229 
230  // if we are in another viewer than the main view we just need the pixel position
231  if( m_viewerName != "" && m_viewerName != "Main View" )
232  {
233  pickInfo = WPickInfo( "", m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
235  m_hitResult = pickInfo;
236 
237  // if nothing was picked before remember the currently picked.
238  m_startPick = pickInfo;
239 
241 
242  return;
243  }
244 
245  bool intersetionsExist = view->computeIntersections( x, y, intersections, 0xFFFFFFF0 );
246 
247  // if something is picked, get the right thing from the list, because it might be hidden.
248  bool startPickIsStillInList = false;
249  osgUtil::LineSegmentIntersector::Intersections::iterator hitr;
250  if( intersetionsExist )
251  {
252  assert( intersections.size() );
253  hitr = intersections.begin();
254 
255  bool ignoreFirst = m_ctrl;
256 
257  while( hitr != intersections.end() )
258  {
259  std::string nodeName = extractSuitableName( hitr );
260  // now we skip everything that starts with an underscore if not in paint mode
261  if( nodeName[0] == '_' && ( m_paintMode == 0 ) )
262  {
263  ++hitr;
264  }
265  // if ctrl is pressed we skip the first thing that gets hit by the pick
266  else if( ignoreFirst )
267  {
268  ++hitr;
269  ignoreFirst = false;
270  }
271  else
272  {
273  break;
274  }
275  }
276 
277  if( hitr == intersections.end() )
278  {
279  // after everything was ignored nothing pickable remained and we have noting picked before
280  // we just stop further processing.
281  if( m_startPick.getName() == "" )
282  {
283  return;
284  }
285  }
286 
287  // if we have a previous pick we search for it in the list
288  if( m_startPick.getName() != "" && m_startPick.getName() != "unpick" )
289  {
290  while( ( hitr != intersections.end() ) && !startPickIsStillInList )
291  {
292  WPickInfo pickInfoTmp( extractSuitableName( hitr ), m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
293  startPickIsStillInList |= ( pickInfoTmp.getName() == m_startPick.getName() );
294 
295  if( !startPickIsStillInList ) // if iteration not finished yet go on in list
296  {
297  ++hitr;
298  }
299  }
300  }
301  } // end of if( intersetionsExist )
302  else
303  {
304  // if we found no intersection and we have noting picked before
305  // we want to return "nothing" in order to provide the pixel coordinates
306  // even though we did not hit anything.
307  if( m_startPick.getName() == "" )
308  {
309  pickInfo = WPickInfo( "nothing", m_viewerName, WPosition( 0.0, 0.0, 0.0 ), std::make_pair( x, y ),
311 
312  m_hitResult = pickInfo;
314  return;
315  }
316  }
317 
318  // Set the new pickInfo if the previously picked is still in list or we have a pick in conjunction with previously no pick
319  if( startPickIsStillInList || ( intersetionsExist && ( m_startPick.getName() == "unpick" || m_startPick.getName() == "" ) ) )
320  {
321  // if nothing was picked before, or the previously picked was found: set new pickInfo
322  WPosition pickPos;
323  pickPos[0] = hitr->getWorldIntersectPoint()[0];
324  pickPos[1] = hitr->getWorldIntersectPoint()[1];
325  pickPos[2] = hitr->getWorldIntersectPoint()[2];
326 
327  WVector3d pickNormal;
328  pickNormal[0] = hitr->getWorldIntersectNormal()[0];
329  pickNormal[1] = hitr->getWorldIntersectNormal()[1];
330  pickNormal[2] = hitr->getWorldIntersectNormal()[2];
331  pickInfo = WPickInfo( extractSuitableName( hitr ), m_viewerName, pickPos, std::make_pair( x, y ),
332  pickInfo.getModifierKey(), m_mouseButton, pickNormal, m_scrollWheel );
333  }
334 
335  // Use the old PickInfo with updated pixel info if we have previously picked something but the old is not in list anymore
336  if( !startPickIsStillInList && m_startPick.getName() != "" && m_startPick.getName() != "unpick" )
337  {
338  pickInfo = WPickInfo( m_startPick.getName(), m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
340  }
341 
342  m_hitResult = pickInfo;
343 
344  // if nothing was picked before remember the currently picked.
345  m_startPick = pickInfo;
346  m_inPickMode = true;
347 
349 }
350 
352 {
353  m_paintMode = mode;
354 }
bool m_inPickMode
if true, the pick handler currently is in pick mode.
Definition: WPickHandler.h:119
WVector3d getPickNormal() const
Get normal at position where object was hit.
Definition: WPickInfo.h:258
WPosition getPickPosition() const
Get position where object was hit.
Definition: WPickInfo.h:253
void setPaintMode(int mode)
setter for paint mode
This only is a 3d double vector.
void setModifierKey(const modifierKey &modKey)
Set the modifier key associated with the pick.
Definition: WPickInfo.h:228
WPickInfo m_hitResult
Textual representation of the result of a pick.
Definition: WPickHandler.h:111
void updatePickInfoModifierKeys(WPickInfo *pickInfo)
Sets the current modifiers to the provided pickInfo.
virtual void pick(osgViewer::View *view, const osgGA::GUIEventAdapter &ea)
Send a pick signal with the pick information as string.
int m_paintMode
the paint mode
Definition: WPickHandler.h:116
WPickHandler()
Constructor that initalizes members with sensible defaults.
modifierKey getModifierKey() const
Get the modifier key associated with the pick.
Definition: WPickInfo.h:223
boost::signals2::signal1< void, WPickInfo > * getPickSignal()
returns the m_pickSignal to for registering to it.
WPickInfo getHitResult()
Gives information about the picked object.
virtual void unpick()
Send a pick signal with the string "unpick".
bool m_ctrl
is ctrl pressed?
Definition: WPickHandler.h:114
bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
Deals with the events found by the osg.
int32_t m_scrollWheel
the virtual value of the scrollwheel
Definition: WPickHandler.h:121
Encapsulates info for pick action.
Definition: WPickInfo.h:41
WPickInfo m_startPick
indicates what was first picked. Should be "" after unpick.
Definition: WPickHandler.h:112
boost::signals2::signal1< void, WPickInfo > m_pickSignal
One can register to this signal to receive pick events.
Definition: WPickHandler.h:131
virtual ~WPickHandler()
Virtual destructor needed because of virtual function.
std::string m_viewerName
which viewer sends the signal
Definition: WPickHandler.h:115
bool m_shift
is shift pressed?
Definition: WPickHandler.h:113
WPickInfo::WMouseButton m_mouseButton
stores mouse button that initiated the pick
Definition: WPickHandler.h:117
std::string getName() const
Get name of picked object.
Definition: WPickInfo.h:243