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