1 /*
2  * Copyright (c) 2011-2021, The DART development contributors
3  * All rights reserved.
4  *
5  * The list of contributors can be found at:
6  *   https://github.com/dartsim/dart/blob/master/LICENSE
7  *
8  * This file is provided under the following "BSD-style" License:
9  *   Redistribution and use in source and binary forms, with or
10  *   without modification, are permitted provided that the following
11  *   conditions are met:
12  *   * Redistributions of source code must retain the above copyright
13  *     notice, this list of conditions and the following disclaimer.
14  *   * Redistributions in binary form must reproduce the above
15  *     copyright notice, this list of conditions and the following
16  *     disclaimer in the documentation and/or other materials provided
17  *     with the distribution.
18  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
19  *   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  *   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  *   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  *   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  *   USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  *   AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  *   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  *   POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <osgGA/GUIEventAdapter>
34 
35 #include "dart/gui/osg/DefaultEventHandler.hpp"
36 #include "dart/gui/osg/MouseEventHandler.hpp"
37 #include "dart/gui/osg/ShapeFrameNode.hpp"
38 #include "dart/gui/osg/Utils.hpp"
39 #include "dart/gui/osg/Viewer.hpp"
40 #include "dart/gui/osg/render/ShapeNode.hpp"
41 
42 #include "dart/dynamics/Entity.hpp"
43 #include "dart/dynamics/ShapeFrame.hpp"
44 
45 #include <iostream>
46 
47 namespace dart {
48 namespace gui {
49 namespace osg {
50 
DefaultEventHandler(Viewer * _viewer)51 DefaultEventHandler::DefaultEventHandler(Viewer* _viewer)
52   : mViewer(_viewer),
53     mLastCursorPosition(Eigen::Vector2d::Zero()),
54     mLastModKeyMask(0)
55 {
56   mViewer->addInstructionText("Spacebar:     Turn simulation on/off\n");
57   mViewer->addInstructionText("Ctrl+H:       Turn headlights on/off\n");
58 
59   for (std::size_t i = 0; i < NUM_MOUSE_BUTTONS; ++i)
60     for (std::size_t j = 0; j < BUTTON_NOTHING; ++j)
61       mSuppressButtonPicks[i][j] = false;
62   mSuppressMovePicks = false;
63 
64   clearButtonEvents();
65 }
66 
67 //==============================================================================
~DefaultEventHandler()68 DefaultEventHandler::~DefaultEventHandler()
69 {
70   // Do nothing
71 }
72 
73 //==============================================================================
getButtonEvent(MouseButton button) const74 MouseButtonEvent DefaultEventHandler::getButtonEvent(MouseButton button) const
75 {
76   return mLastButtonEvent[button];
77 }
78 
79 //==============================================================================
getModKeyMask() const80 int DefaultEventHandler::getModKeyMask() const
81 {
82   return mLastModKeyMask;
83 }
84 
85 //==============================================================================
getWindowCursorX() const86 double DefaultEventHandler::getWindowCursorX() const
87 {
88   return mLastCursorPosition[0];
89 }
90 
91 //==============================================================================
getWindowCursorY() const92 double DefaultEventHandler::getWindowCursorY() const
93 {
94   return mLastCursorPosition[1];
95 }
96 
97 //==============================================================================
getDeltaCursor(const Eigen::Vector3d & _fromPosition,ConstraintType _constraint,const Eigen::Vector3d & _constraintVector) const98 Eigen::Vector3d DefaultEventHandler::getDeltaCursor(
99     const Eigen::Vector3d& _fromPosition,
100     ConstraintType _constraint,
101     const Eigen::Vector3d& _constraintVector) const
102 {
103   ::osg::Vec3d eye, center, up;
104   mViewer->getCamera()->getViewMatrixAsLookAt(eye, center, up);
105 
106   Eigen::Vector3d near, far;
107   getNearAndFarPointUnderCursor(near, far);
108   Eigen::Vector3d v1 = far - near;
109 
110   if (LINE_CONSTRAINT == _constraint)
111   {
112     const Eigen::Vector3d& b1 = near;
113     const Eigen::Vector3d& v2 = _constraintVector;
114     const Eigen::Vector3d& b2 = _fromPosition;
115 
116     double v1_v1 = v1.dot(v1);
117     double v2_v2 = v2.dot(v2);
118     double v2_v1 = v2.dot(v1);
119 
120     double denominator = v1_v1 * v2_v2 - v2_v1 * v2_v1;
121     double s;
122     if (fabs(denominator) < 1e-10)
123       s = 0;
124     else
125       s = (v1_v1 * (v2.dot(b1) - v2.dot(b2))
126            + v2_v1 * (v1.dot(b2) - v1.dot(b1)))
127           / denominator;
128 
129     return v2 * s;
130   }
131   else if (PLANE_CONSTRAINT == _constraint)
132   {
133     const Eigen::Vector3d& n = _constraintVector;
134     double s = n.dot(_fromPosition - near) / n.dot(v1);
135     return near - _fromPosition + s * v1;
136   }
137   else
138   {
139     Eigen::Vector3d n = osgToEigVec3(center - eye);
140     double s = n.dot(_fromPosition - near) / n.dot(v1);
141     return near - _fromPosition + s * v1;
142   }
143 
144   return Eigen::Vector3d::Zero();
145 }
146 
147 //==============================================================================
getNearAndFarPointUnderCursor(Eigen::Vector3d & near,Eigen::Vector3d & far,double distance) const148 void DefaultEventHandler::getNearAndFarPointUnderCursor(
149     Eigen::Vector3d& near, Eigen::Vector3d& far, double distance) const
150 {
151   ::osg::Camera* C = mViewer->getCamera();
152   ::osg::Matrix VPW = C->getViewMatrix() * C->getProjectionMatrix()
153                       * C->getViewport()->computeWindowMatrix();
154   ::osg::Matrix invVPW;
155   invVPW.invert(VPW);
156 
157   double x = getWindowCursorX(), y = getWindowCursorY();
158   auto osgNear = ::osg::Vec3d(x, y, 0.0) * invVPW;
159   auto osgFar = ::osg::Vec3d(x, y, distance) * invVPW;
160 
161   near = osgToEigVec3(osgNear);
162   far = osgToEigVec3(osgFar);
163 }
164 
165 //==============================================================================
getButtonPicks(MouseButton button,MouseButtonEvent event) const166 const std::vector<PickInfo>& DefaultEventHandler::getButtonPicks(
167     MouseButton button, MouseButtonEvent event) const
168 {
169   if (BUTTON_NOTHING == event)
170     return mMovePicks;
171 
172   return mButtonPicks[button][event];
173 }
174 
175 //==============================================================================
getMovePicks() const176 const std::vector<PickInfo>& DefaultEventHandler::getMovePicks() const
177 {
178   return mMovePicks;
179 }
180 
181 //==============================================================================
suppressButtonPicks(MouseButton button,MouseButtonEvent event)182 void DefaultEventHandler::suppressButtonPicks(
183     MouseButton button, MouseButtonEvent event)
184 {
185   if (BUTTON_NOTHING == event)
186     mSuppressMovePicks = true;
187   else
188     mSuppressButtonPicks[button][event] = true;
189 }
190 
191 //==============================================================================
suppressMovePicks()192 void DefaultEventHandler::suppressMovePicks()
193 {
194   mSuppressMovePicks = true;
195 }
196 
197 //==============================================================================
activateButtonPicks(MouseButton button,MouseButtonEvent event)198 void DefaultEventHandler::activateButtonPicks(
199     MouseButton button, MouseButtonEvent event)
200 {
201   if (BUTTON_NOTHING == event)
202     mSuppressMovePicks = false;
203   else
204     mSuppressButtonPicks[button][event] = false;
205 }
206 
207 //==============================================================================
activateMovePicks()208 void DefaultEventHandler::activateMovePicks()
209 {
210   mSuppressMovePicks = false;
211 }
212 
213 //==============================================================================
pick(std::vector<PickInfo> & infoVector,const::osgGA::GUIEventAdapter & ea)214 void DefaultEventHandler::pick(
215     std::vector<PickInfo>& infoVector, const ::osgGA::GUIEventAdapter& ea)
216 {
217   ::osgUtil::LineSegmentIntersector::Intersections hlist;
218 
219   infoVector.clear();
220   if (mViewer->computeIntersections(ea, hlist))
221   {
222     infoVector.reserve(hlist.size());
223     for (const ::osgUtil::LineSegmentIntersector::Intersection& intersect :
224          hlist)
225     {
226       ::osg::Drawable* drawable = intersect.drawable;
227       render::ShapeNode* shape
228           = dynamic_cast<render::ShapeNode*>(drawable->getParent(0));
229       if (shape)
230       {
231         PickInfo info;
232         info.shape = shape->getShape();
233         info.frame = shape->getParentShapeFrameNode()->getShapeFrame();
234         info.normal
235             = osgToEigVec3(intersect.getWorldIntersectNormal()).cast<double>();
236         info.position = osgToEigVec3(intersect.getWorldIntersectPoint());
237 
238         infoVector.push_back(info);
239       }
240     }
241   }
242 }
243 
244 //==============================================================================
addMouseEventHandler(MouseEventHandler * handler)245 void DefaultEventHandler::addMouseEventHandler(MouseEventHandler* handler)
246 {
247   mMouseEventHandlers.insert(handler);
248   handler->mEventHandler = this;
249   handler->addSubject(this);
250 }
251 
252 //==============================================================================
getMouseEventHandlers() const253 const std::set<MouseEventHandler*>& DefaultEventHandler::getMouseEventHandlers()
254     const
255 {
256   return mMouseEventHandlers;
257 }
258 
259 //==============================================================================
wasActive(MouseButtonEvent event)260 static bool wasActive(MouseButtonEvent event)
261 {
262   return ((event == BUTTON_PUSH) || (event == BUTTON_DRAG));
263 }
264 
265 //==============================================================================
assignEventToButtons(MouseButtonEvent (& mLastButtonEvent)[NUM_MOUSE_BUTTONS],const::osgGA::GUIEventAdapter & ea)266 static void assignEventToButtons(
267     MouseButtonEvent (&mLastButtonEvent)[NUM_MOUSE_BUTTONS],
268     const ::osgGA::GUIEventAdapter& ea)
269 {
270   MouseButtonEvent event = BUTTON_NOTHING;
271   if (ea.getEventType() == ::osgGA::GUIEventAdapter::PUSH)
272     event = BUTTON_PUSH;
273   else if (ea.getEventType() == ::osgGA::GUIEventAdapter::DRAG)
274     event = BUTTON_DRAG;
275   else if (ea.getEventType() == ::osgGA::GUIEventAdapter::RELEASE)
276     event = BUTTON_RELEASE;
277 
278   if (BUTTON_RELEASE == event)
279   {
280     if ((ea.getButtonMask() & ::osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON) == 0
281         && wasActive(mLastButtonEvent[LEFT_MOUSE]))
282       mLastButtonEvent[LEFT_MOUSE] = event;
283 
284     if ((ea.getButtonMask() & ::osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON) == 0
285         && wasActive(mLastButtonEvent[RIGHT_MOUSE]))
286       mLastButtonEvent[RIGHT_MOUSE] = event;
287 
288     if ((ea.getButtonMask() & ::osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON)
289             == 0
290         && wasActive(mLastButtonEvent[MIDDLE_MOUSE]))
291       mLastButtonEvent[MIDDLE_MOUSE] = event;
292   }
293   else
294   {
295     if (ea.getButtonMask() & ::osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
296       mLastButtonEvent[LEFT_MOUSE] = event;
297 
298     if (ea.getButtonMask() & ::osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
299       mLastButtonEvent[RIGHT_MOUSE] = event;
300 
301     if (ea.getButtonMask() & ::osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON)
302       mLastButtonEvent[MIDDLE_MOUSE] = event;
303   }
304 }
305 
306 //==============================================================================
handle(const::osgGA::GUIEventAdapter & ea,::osgGA::GUIActionAdapter &)307 bool DefaultEventHandler::handle(
308     const ::osgGA::GUIEventAdapter& ea, ::osgGA::GUIActionAdapter&)
309 {
310   mLastModKeyMask = ea.getModKeyMask();
311 
312   switch (ea.getEventType())
313   {
314     case ::osgGA::GUIEventAdapter::PUSH:
315     case ::osgGA::GUIEventAdapter::DRAG:
316     case ::osgGA::GUIEventAdapter::RELEASE:
317     case ::osgGA::GUIEventAdapter::MOVE:
318       mLastCursorPosition[0] = ea.getX();
319       mLastCursorPosition[1] = ea.getY();
320 
321       break;
322 
323     default:
324       break;
325   }
326 
327   switch (ea.getEventType())
328   {
329     case ::osgGA::GUIEventAdapter::KEYDOWN:
330     {
331       switch (ea.getKey())
332       {
333         case 8: // ctrl+h
334         {
335           mViewer->switchHeadlights(!mViewer->checkHeadlights());
336           return true;
337         }
338 
339         case ' ':
340         {
341           if (mViewer->isAllowingSimulation())
342           {
343             mViewer->simulate(!mViewer->isSimulating());
344             return true;
345           }
346           break;
347         }
348       }
349       break;
350     }
351 
352     case ::osgGA::GUIEventAdapter::MOVE:
353     {
354       if (!mSuppressMovePicks)
355         pick(mMovePicks, ea);
356 
357       triggerMouseEventHandlers();
358       break;
359     }
360 
361     case ::osgGA::GUIEventAdapter::PUSH:
362     case ::osgGA::GUIEventAdapter::DRAG:
363     case ::osgGA::GUIEventAdapter::RELEASE:
364 
365       assignEventToButtons(mLastButtonEvent, ea);
366       eventPick(ea);
367 
368       mViewer->updateDragAndDrops();
369 
370       triggerMouseEventHandlers();
371       break;
372 
373     default:
374       break;
375   }
376 
377   return false;
378 }
379 
380 //==============================================================================
triggerMouseEventHandlers()381 void DefaultEventHandler::triggerMouseEventHandlers()
382 {
383   for (MouseEventHandler* h : mMouseEventHandlers)
384   {
385     h->update();
386   }
387 }
388 
389 //==============================================================================
eventPick(const::osgGA::GUIEventAdapter & ea)390 void DefaultEventHandler::eventPick(const ::osgGA::GUIEventAdapter& ea)
391 {
392   MouseButtonEvent mbe;
393   switch (ea.getEventType())
394   {
395     case ::osgGA::GUIEventAdapter::PUSH:
396       mbe = BUTTON_PUSH;
397       break;
398     case ::osgGA::GUIEventAdapter::DRAG:
399       mbe = BUTTON_DRAG;
400       break;
401     case ::osgGA::GUIEventAdapter::RELEASE:
402       mbe = BUTTON_RELEASE;
403       break;
404     default:
405       return;
406   }
407 
408   if (((ea.getButtonMask() & ::osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
409        && !mSuppressButtonPicks[LEFT_MOUSE][mbe])
410       || ((ea.getButtonMask() & ::osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
411           && !mSuppressButtonPicks[RIGHT_MOUSE][mbe])
412       || ((ea.getButtonMask() & ::osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON)
413           && !mSuppressButtonPicks[MIDDLE_MOUSE][mbe]))
414   {
415     pick(mTempPicks, ea);
416 
417     if (ea.getButtonMask() & ::osgGA::GUIEventAdapter::LEFT_MOUSE_BUTTON)
418       mButtonPicks[LEFT_MOUSE][mbe] = mTempPicks;
419 
420     if (ea.getButtonMask() & ::osgGA::GUIEventAdapter::RIGHT_MOUSE_BUTTON)
421       mButtonPicks[RIGHT_MOUSE][mbe] = mTempPicks;
422 
423     if (ea.getButtonMask() & ::osgGA::GUIEventAdapter::MIDDLE_MOUSE_BUTTON)
424       mButtonPicks[MIDDLE_MOUSE][mbe] = mTempPicks;
425   }
426 }
427 
428 //==============================================================================
clearButtonEvents()429 void DefaultEventHandler::clearButtonEvents()
430 {
431   for (std::size_t i = 0; i < NUM_MOUSE_BUTTONS; ++i)
432     mLastButtonEvent[i] = BUTTON_NOTHING;
433 }
434 
435 //==============================================================================
handleDestructionNotification(const dart::common::Subject * _subject)436 void DefaultEventHandler::handleDestructionNotification(
437     const dart::common::Subject* _subject)
438 {
439   MouseEventHandler* meh = const_cast<MouseEventHandler*>(
440       dynamic_cast<const MouseEventHandler*>(_subject));
441   std::set<MouseEventHandler*>::iterator it = mMouseEventHandlers.find(meh);
442   if (it != mMouseEventHandlers.end())
443     mMouseEventHandlers.erase(it);
444 }
445 
446 } // namespace osg
447 } // namespace gui
448 } // namespace dart
449