OpenWalnut  1.5.0dev
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 "WPickHandler.h"
28 #include "../common/WAssert.h"
29 
30 const std::string WPickHandler::unpickString = "unpick";
31 
33  : m_hitResult( WPickInfo() ),
34  m_startPick( WPickInfo() ),
35  m_shift( false ),
36  m_ctrl( false ),
37  m_viewerName( "" ),
38  m_paintMode( false ),
39  m_mouseButton( WPickInfo::NOMOUSE ),
40  m_inPickMode( false ),
41  m_scrollWheel( 0 )
42 {
43 }
44 
45 WPickHandler::WPickHandler( std::string viewerName )
46  : m_hitResult( WPickInfo() ),
47  m_startPick( WPickInfo() ),
48  m_shift( false ),
49  m_ctrl( false ),
50  m_viewerName( viewerName ),
51  m_paintMode( false ),
52  m_mouseButton( WPickInfo::NOMOUSE ),
53  m_inPickMode( false ),
54  m_scrollWheel( 0 )
55 {
56 }
57 
59 {
60 }
61 
63 {
64  return m_hitResult;
65 }
66 
67 boost::signals2::signal< void( WPickInfo ) >* WPickHandler::getPickSignal()
68 {
69  return &m_pickSignal;
70 }
71 
72 bool WPickHandler::handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa )
73 {
74  switch( ea.getEventType() )
75  {
76  case osgGA::GUIEventAdapter::DRAG : // Mouse pushed an dragged
77  case osgGA::GUIEventAdapter::PUSH : // Mousebutton pushed
78  {
79  unsigned int buttonMask = ea.getButtonMask();
80  if( buttonMask == osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON )
81  {
82  m_mouseButton = WPickInfo::MOUSE_RIGHT;
83  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
84  if( view )
85  {
86  pick( view, ea );
87  }
88  }
89  if( ( buttonMask == osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON ) && ( m_paintMode ) )
90  {
91  m_mouseButton = WPickInfo::MOUSE_LEFT;
92  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
93  if( view )
94  {
95  pick( view, ea );
96  }
97  }
98  return false;
99  }
100  case osgGA::GUIEventAdapter::RELEASE : // Mousebutton released
101  {
102  m_mouseButton = WPickInfo::NOMOUSE;
103  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
104  if( view )
105  {
106  unpick();
107  }
108  return false;
109  }
110  case osgGA::GUIEventAdapter::SCROLL : // Wheel
111  {
112  if( m_inPickMode )
113  {
114  switch( ea.getScrollingMotion() )
115  {
116  case osgGA::GUIEventAdapter::SCROLL_UP:
117  m_scrollWheel++;
118  break;
119  case osgGA::GUIEventAdapter::SCROLL_DOWN:
120  m_scrollWheel--;
121  break;
122  case osgGA::GUIEventAdapter::SCROLL_2D:
123  // FIXME: the osg doc tells us nothing about this value, but is seems to be always 120 or -120
124  if( ea.getScrollingDeltaY() > 0 )
125  {
126  m_scrollWheel++;
127  }
128  else
129  {
130  m_scrollWheel--;
131  }
132  break;
133  default:
134  break;
135  }
136 
137  // handle as pick event
138  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
139  if( view )
140  {
141  pick( view, ea );
142  }
143  ea.setHandled( true );
144  return true;
145  }
146  return false;
147  }
148  case osgGA::GUIEventAdapter::KEYUP : // Key on keyboard released.
149  {
150  m_shift = false;
151  m_ctrl = false;
152  return false;
153  }
154  case osgGA::GUIEventAdapter::KEYDOWN : // Key on keyboard pushed.
155  {
156  if( ea.getKey() == 'c' )
157  {
158  osgViewer::View* view = static_cast< osgViewer::View* >( &aa );
159  osg::ref_ptr< osgGA::GUIEventAdapter > event = new osgGA::GUIEventAdapter( ea );
160  event->setX( ( ea.getXmin() + ea.getXmax() ) * 0.5 );
161  event->setY( ( ea.getYmin() + ea.getYmax() ) * 0.5 );
162  if( view )
163  {
164  pick( view, *event );
165  }
166  }
167  if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Shift_L )
168  {
169  m_shift = true;
170  }
171  if( ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_L || ea.getKey() == osgGA::GUIEventAdapter::KEY_Control_R )
172  {
173  m_ctrl = true;
174  }
175  return false;
176  }
177  default:
178  return false;
179  }
180 }
181 
183 {
184  m_inPickMode = false;
185  if( m_hitResult != WPickInfo() )
186  {
187  m_hitResult = WPickInfo( WPickHandler::unpickString, m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
189  m_scrollWheel = 0;
190  }
192 }
193 
194 std::string extractSuitableName( osgUtil::LineSegmentIntersector::Intersections::iterator hitr )
195 {
196  if( !hitr->nodePath.empty() && !( hitr->nodePath.back()->getName().empty() ) )
197  {
198  return hitr->nodePath.back()->getName();
199  }
200  else if( hitr->drawable.valid() )
201  {
202  return hitr->drawable->className();
203  }
204  assert( 0 && "This should not happen. Tell \"wiebel\" if it does." );
205  return ""; // This line will not be reached.
206 }
207 
209 {
210  if( m_shift )
211  {
212  pickInfo->setModifierKey( WPickInfo::SHIFT );
213  }
214 
215  if( m_ctrl )
216  {
217  pickInfo->setModifierKey( WPickInfo::STRG );
218  }
219 }
220 
221 void WPickHandler::pick( osgViewer::View* view, const osgGA::GUIEventAdapter& ea )
222 {
223  osgUtil::LineSegmentIntersector::Intersections intersections;
225  float x = ea.getX(); // pixel position in x direction
226  float y = ea.getY(); // pixel position in y direction
227 
228  WPickInfo pickInfo;
229 
230  updatePickInfoModifierKeys( &pickInfo );
231 
232  // if we are in another viewer than the main view we just need the pixel position
233  if( m_viewerName != "" && m_viewerName != "Main View" )
234  {
235  pickInfo = WPickInfo( "", m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
237  m_hitResult = pickInfo;
238 
239  // if nothing was picked before remember the currently picked.
240  m_startPick = pickInfo;
241 
243 
244  return;
245  }
246 
247  bool intersetionsExist = view->computeIntersections( x, y, intersections, 0xFFFFFFF0 );
248 
249  // if something is picked, get the right thing from the list, because it might be hidden.
250  bool startPickIsStillInList = false;
251  osgUtil::LineSegmentIntersector::Intersections::iterator hitr;
252  if( intersetionsExist )
253  {
254  hitr = intersections.begin();
255 
256 
257  while( hitr != intersections.end() )
258  {
259  std::string nodeName = extractSuitableName( hitr );
260  std::cout << nodeName << std::endl;
261 
262  ++hitr;
263  }
264  std::cout << "-----------" << std::endl;
265 
266 
267  assert( intersections.size() );
268  hitr = intersections.begin();
269 
270  bool ignoreFirst = m_ctrl;
271 
272  while( hitr != intersections.end() )
273  {
274  std::string nodeName = extractSuitableName( hitr );
275  WAssert( nodeName.size() > 2, "Geode name too short for picking." );
276 
277  // now we skip everything that starts with two underscores
278  if( nodeName[0] == '_' && nodeName[1] == '_' )
279  {
280  ++hitr;
281  }
282  // now we skip everything that starts with an underscore if not in paint mode
283  else if( nodeName[0] == '_' && ( !m_paintMode ) )
284  {
285  ++hitr;
286  }
287  // // now we skip stuff with non-expressive names often used
288  // else if( nodeName == "Geometry" )
289  // {
290  // ++hitr;
291  // }
292  // if ctrl is pressed we skip the first thing that gets hit by the pick
293  else if( ignoreFirst )
294  {
295  ++hitr;
296  ignoreFirst = false;
297  }
298  else
299  {
300  break;
301  }
302  }
303 
304  if( hitr == intersections.end() )
305  {
306  // after everything was ignored nothing pickable remained and we have nothing picked before
307  // we just stop further processing.
308  if( m_startPick.getName() == "" )
309  {
310  return;
311  }
312  }
313 
314  // if we have a previous pick we search for it in the list
316  {
317  while( ( hitr != intersections.end() ) && !startPickIsStillInList )
318  {
319  WPickInfo pickInfoTmp( extractSuitableName( hitr ), m_viewerName, WPosition(), std::make_pair( 0, 0 ), WPickInfo::NONE );
320  startPickIsStillInList |= ( pickInfoTmp.getName() == m_startPick.getName() );
321 
322  if( !startPickIsStillInList ) // if iteration not finished yet go on in list
323  {
324  ++hitr;
325  }
326  }
327  }
328  } // end of if( intersetionsExist )
329  else
330  {
331  // if we found no intersection and we have noting picked before
332  // we want to return "nothing" in order to provide the pixel coordinates
333  // even though we did not hit anything.
334  if( m_startPick.getName() == "" )
335  {
336  pickInfo = WPickInfo( "nothing", m_viewerName, WPosition( 0.0, 0.0, 0.0 ), std::make_pair( x, y ),
338 
339  m_hitResult = pickInfo;
341  return;
342  }
343  }
344 
345  // Set the new pickInfo if the previously picked is still in list or we have a pick in conjunction with previously no pick
346  if( startPickIsStillInList || ( intersetionsExist && ( m_startPick.getName() == WPickHandler::unpickString || m_startPick.getName() == "" ) ) )
347  {
348  // if nothing was picked before, or the previously picked was found: set new pickInfo
349  WPosition pickPos;
350  pickPos[0] = hitr->getWorldIntersectPoint()[0];
351  pickPos[1] = hitr->getWorldIntersectPoint()[1];
352  pickPos[2] = hitr->getWorldIntersectPoint()[2];
353 
354  WVector3d pickNormal;
355  // For whatever reason the intersection algorithm gets the wrong normals, so we grab them ourselves
356  /*pickNormal[0] = hitr->getWorldIntersectNormal()[0];
357  pickNormal[1] = hitr->getWorldIntersectNormal()[1];
358  pickNormal[2] = hitr->getWorldIntersectNormal()[2];*/
359 
360  const osgUtil::LineSegmentIntersector::Intersection::IndexList& vil = hitr->indexList;
361  osg::ref_ptr< osg::Geometry > geo = dynamic_cast< osg::Geometry* >( hitr->drawable.get() );
362  float* normals = ( float* ) geo->getNormalArray()->getDataPointer();
363  size_t vertexIdx = vil[0];
364  pickNormal[0] = normals[vertexIdx * 3];
365  pickNormal[1] = normals[vertexIdx * 3 + 1];
366  pickNormal[2] = normals[vertexIdx * 3 + 2];
367 
368  pickInfo = WPickInfo( extractSuitableName( hitr ), m_viewerName, pickPos, std::make_pair( x, y ),
369  pickInfo.getModifierKey(), m_mouseButton, pickNormal, m_scrollWheel );
370  }
371 
372  // Use the old PickInfo with updated pixel info if we have previously picked something but the old is not in list anymore
373  if( !startPickIsStillInList && m_startPick.getName() != "" && m_startPick.getName() != WPickHandler::unpickString )
374  {
375  pickInfo = WPickInfo( m_startPick.getName(), m_viewerName, m_startPick.getPickPosition(), std::make_pair( x, y ),
377  }
378 
379  m_hitResult = pickInfo;
380 
381  // if nothing was picked before remember the currently picked.
382  m_startPick = pickInfo;
383  m_inPickMode = true;
384 
386 }
387 
388 void WPickHandler::setPaintMode( bool paintMode )
389 {
390  m_paintMode = paintMode;
391 }
392 
394 {
395  WAssert( mode == 1 || mode == 0, "Unexpected value" );
396  if( mode == 1 )
397  {
398  m_paintMode = true;
399  }
400  else
401  {
402  m_paintMode = false;
403  }
404 }
virtual void unpick()
Send a pick signal with the unpickString.
WPickInfo m_hitResult
Textual representation of the result of a pick.
Definition: WPickHandler.h:128
WPickHandler()
Constructor that initalizes members with sensible defaults.
bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &aa)
Deals with the events found by the osg.
bool m_shift
is shift pressed?
Definition: WPickHandler.h:130
WPickInfo m_startPick
indicates what was first picked. Should be "" after unpick.
Definition: WPickHandler.h:129
boost::signals2::signal< void(WPickInfo) > m_pickSignal
One can register to this signal to receive pick events.
Definition: WPickHandler.h:126
std::string m_viewerName
which viewer sends the signal
Definition: WPickHandler.h:132
void updatePickInfoModifierKeys(WPickInfo *pickInfo)
Sets the current modifiers to the provided pickInfo.
bool m_ctrl
is ctrl pressed?
Definition: WPickHandler.h:131
boost::signals2::signal< void(WPickInfo) > * getPickSignal()
virtual void pick(osgViewer::View *view, const osgGA::GUIEventAdapter &ea)
Send a pick signal with the pick information as string.
WPickInfo::WMouseButton m_mouseButton
stores mouse button that initiated the pick
Definition: WPickHandler.h:134
bool m_inPickMode
if true, the pick handler currently is in pick mode.
Definition: WPickHandler.h:136
WPickInfo getHitResult()
Gives information about the picked object.
int32_t m_scrollWheel
the virtual value of the scrollwheel
Definition: WPickHandler.h:138
virtual ~WPickHandler()
Virtual destructor needed because of virtual function.
bool m_paintMode
the paint mode
Definition: WPickHandler.h:133
OW_API_DEPRECATED void setPaintMode(int mode)
setter for paint mode
static const std::string unpickString
The string indicating picking has stopped.
Definition: WPickHandler.h:104
Encapsulates info for pick action.
Definition: WPickInfo.h:42
WPosition getPickPosition() const
Get position where object was hit.
Definition: WPickInfo.h:253
void setModifierKey(const modifierKey &modKey)
Set the modifier key associated with the pick.
Definition: WPickInfo.h:228
WVector3d getPickNormal() const
Get normal at position where object was hit.
Definition: WPickInfo.h:258
std::string getName() const
Get name of picked object.
Definition: WPickInfo.h:243
modifierKey getModifierKey() const
Get the modifier key associated with the pick.
Definition: WPickInfo.h:223
This only is a 3d double vector.