SceneViewer.cpp
Go to the documentation of this file.
1/*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2012-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package MemoryX::gui-plugins::SceneEditor
19 * @date 2015
20 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
21 * GNU General Public License
22 */
23
24#include "SceneViewer.h"
25
28#include <Inventor/SoPickedPoint.h>
29#include <Inventor/actions/SoRayPickAction.h>
30#include <Inventor/events/SoLocation2Event.h>
31#include <Inventor/events/SoMouseButtonEvent.h>
32
34 SoQtExaminerViewer(widget), control(control)
35{
36 this->setBackgroundColor(SbColor(100 / 255.0f, 100 / 255.0f, 100 / 255.0f));
37 this->setAccumulationBuffer(false);
38 this->setHeadlight(true);
39 this->setViewing(false);
40 this->setDecoration(false);
41#ifdef WIN32
42#ifndef _DEBUG
43 this->setAntialiasing(true, 4);
44#endif
45#endif
46 this->setTransparencyType(SoGLRenderAction::SORTED_OBJECT_BLEND);
47 this->setFeedbackVisibility(true);
48}
49
50//Override the default navigation behaviour of the SoQtExaminerViewer
51SbBool
52scene3D::SceneViewer::processSoEvent(const SoEvent* const event)
53{
54 const SoType type(event->getTypeId());
55
56 //Remapping mouse press events
57 if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId()))
58 {
59 SoMouseButtonEvent* const ev = (SoMouseButtonEvent*)event;
60 const int button = ev->getButton();
61 const SbBool press = ev->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
62
63 //LEFT MOUSE BUTTON
64 if (button == SoMouseButtonEvent::BUTTON1)
65 {
67 {
68 if (!controller->getScene()->getSelectionManager()->getCreateOperations())
69 {
70 //SelectionManager is not creating Operations, so we shouldn't either!
71 return SoQtRenderArea::processSoEvent(ev);
72 }
73 }
74
75 if (press)
76 {
77 /*We could just pass action into scenegraph here. There is only one litte thing
78 that doesnt work then: deselecting by clicking into void is performed as
79 many single deselection operations in controller. Undoing then performs
80 every deselection seperately, which is annoying. SoSelection on the other
81 hand doesn't tell us this 'click into void' event so we have to check ourself before this action
82 goes into scenegraph. */
83
84 SoRayPickAction rp(this->getViewportRegion());
85 rp.setPickAll(false);
86 rp.setPoint(event->getPosition());
87 rp.apply(this->getSceneGraph());
88 SoPickedPoint* picked = rp.getPickedPoint();
89
90 if (!picked)
91 {
92 /*We clicked into the void here, so we handle this event ourselves, instead of
93 leaving this up to the SoSelection Node... Tell controller to deselect everything
94 in one big operation block and then return, if there are any objects selected of course*/
95
96 //Shift click into void doesnt change anything
97 if (!ev->wasShiftDown())
98 {
99 if (controller::ControllerPtr controller = control.lock())
100 {
101 if (controller->getScene()
102 ->getSelectionManager()
103 ->getAllSelected()
104 .size() != 0)
105 {
106 std::shared_ptr<std::vector<controller::OperationPtr>> operations(
107 new std::vector<controller::OperationPtr>());
108
109 // deselect all objects
110 for (scene3D::SceneObjectPtr object : controller->getScene()
111 ->getSelectionManager()
112 ->getAllSelected())
113 {
115 new controller::DeselectOperation(
116 controller->getMemoryXController(),
117 controller->getScene(),
118 object->getObjectId()));
119 operations->push_back(deselect);
120 }
121
122 controller->execute(controller::Controller::EXECUTE_ON_WM |
125 operations);
126 }
127 }
128 }
129
130 return TRUE;
131 }
132 else
133 {
134 /* The performed click is above something!*/
135
136 /*We have to make sure we didn't click on a manipulator before we can make more decisions here. In the case we have clicked one,
137 we can simply pass the event into scenegraph, because we dont have to change the behaviour here!*/
138
139 SoFullPath* p = (SoFullPath*)picked->getPath();
140
141 for (int i = 0; i < p->getLength(); i++)
142 {
143 SoNode* n = p->getNode(i);
144
145 if (n->isOfType(SoTransformManip::getClassTypeId()))
146 {
147 //Manipulator found, pass event into scenegraph
148 return SoQtRenderArea::processSoEvent(ev);
149 }
150 }
151
152 /* Seems like we selected something and it is not a manipulator, must be an object! Let's check some last cases we have
153 to manually handle.*/
154
155 if (!ev->wasShiftDown())
156 {
157 /*If shift is not down we might get the case where mutiple objects are deselected before the picked object
158 is selected. We just do this work for the SoSelection node and group all deselect operations and the select operation
159 into one block (which is what SoSelection can't do for us). */
160 if (controller::ControllerPtr controller = control.lock())
161 {
162 //Is there more than one object already selected?
163 if (controller->getScene()
164 ->getSelectionManager()
165 ->getAllSelected()
166 .size() > 0)
167 {
168 //Find out which object to select
169 SceneObjectPtr obj;
170
171 for (int i = 0; i < picked->getPath()->getLength(); i++)
172 {
173 SoNode* n = picked->getPath()->getNode(i);
174
175 if (n->isOfType(SceneObject::getClassTypeId()))
176 {
177 obj.reset((SceneObject*)n);
178 }
179 }
180
181 //Is there only one object selected and it is also the object we want to select here?
182 if (controller->getScene()
183 ->getSelectionManager()
184 ->getAllSelected()
185 .size() == 1 &&
186 controller->getScene()->getSelectionManager()->isSelected(obj))
187 {
188 //No need to do something, pass this to Selection node, default behaviour.
189 return SoQtRenderArea::processSoEvent(ev);
190 }
191 else
192 {
193 //Deselect all and select object in one block operation
194 std::shared_ptr<std::vector<controller::OperationPtr>>
195 operations(new std::vector<controller::OperationPtr>());
196
197 // deselect all objects
198 for (scene3D::SceneObjectPtr object :
199 controller->getScene()
200 ->getSelectionManager()
201 ->getAllSelected())
202 {
204 new controller::DeselectOperation(
205 controller->getMemoryXController(),
206 controller->getScene(),
207 object->getObjectId()));
208 operations->push_back(deselect);
209 }
210
211 controller->execute(
215 operations);
216
217 //Let SoSelection node handle the selection
218 return SoQtRenderArea::processSoEvent(ev);
219 }
220 }
221 else
222 {
223 //Nothing selected, so its gonna be only one operation. Let SoSelection node do this.
224 return SoQtRenderArea::processSoEvent(ev);
225 }
226 }
227 }
228 else
229 {
230 /*If shift is down and an object is being picked, selection list can only grow by one element
231 or one element is deselected. We therefore don't need to put all operations into one block of operations
232 because it can only be one operation at once. Just pass this event right into the scenegraph and let
233 the SoSelection node handle it automatically. */
234 return SoQtRenderArea::processSoEvent(ev);
235 }
236 }
237 }
238 else
239 {
240 return SoQtRenderArea::processSoEvent(ev);
241 }
242 }
243
244 //RIGHT MOUSE BUTTON
245 if (button == SoMouseButtonEvent::BUTTON2)
246 {
247 /*Right mouse button has no functionality yet, so ignore it.*/
248 return TRUE;
249 }
250
251 //MIDDLE MOUSE BUTTON
252 if (button == SoMouseButtonEvent::BUTTON3)
253 {
254 /*Middle mouse button now is used for all changes in camera perspective.
255 To also display the cool little rotation cursor, viewing mode is set to on
256 while button is down*/
257
258 //Enable or disable viewing mode while BUTTON3 pressed
259 if (press)
260 {
261 if (!this->isViewing())
262 {
263 this->setViewing(true);
264 }
265 }
266 else
267 {
268 if (this->isViewing())
269 {
270 this->setViewing(false);
271 }
272 }
273
274 //Remap BUTTON3 to BUTTON1
275 ev->setButton(SoMouseButtonEvent::BUTTON1);
276
277 //Make sure this REALLY only can happen when viewing mode is on.
278 //Zooming can also turn it on and it leads to weird effects when doing both
279 //(deselections in scene etc.) because SoQtExaminerViewer passes BUTTON1
280 //events up to scenegraph when not in viewing mode.
281 if (this->isViewing())
282 {
283 return SoQtExaminerViewer::processSoEvent(ev);
284 }
285 }
286
287 //MOUSE WHEEL UP AND DOWN
288 if (button == SoMouseButtonEvent::BUTTON4 || button == SoMouseButtonEvent::BUTTON5)
289 {
290 /*Zooming is allowed, so just use it. We have to temporarily turn viewing mode
291 on to make SoQtExaminerViewer allow zooming.*/
292
293 //Swap BUTTON4 and BUTTON5 because zooming out while scrolling up is just retarded
294 ev->setButton(button == SoMouseButtonEvent::BUTTON4 ? SoMouseButtonEvent::BUTTON5
295 : SoMouseButtonEvent::BUTTON4);
296
297 //Zooming is allowed, so just pass it and temporarily set viewing mode on, if it is not already
298 //(otherwise coin gives us warning messages...)
299 if (!this->isViewing())
300 {
301 if (!this->isViewing())
302 {
303 this->setViewing(true);
304 }
305
306 SoQtExaminerViewer::processSoEvent(ev);
307
308 if (this->isViewing())
309 {
310 this->setViewing(false);
311 }
312 }
313 else
314 {
315 SoQtExaminerViewer::processSoEvent(ev);
316 }
317
318 return TRUE;
319 }
320 }
321
322 // Keyboard handling
323 if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId()))
324 {
325 const SoKeyboardEvent* const ev = (const SoKeyboardEvent*)event;
326
327 /*The escape key and super key (windows key) is used to switch between
328 viewing modes. We need to disable this behaviour completely.*/
329
330 //65513 seems to be the super key, which is not available in the enum of keys in coin....
331 if (ev->getKey() == SoKeyboardEvent::ESCAPE || ev->getKey() == 65513)
332 {
333 return TRUE;
334 }
335 else if (ev->getKey() == SoKeyboardEvent::S && ev->getState() == SoButtonEvent::DOWN)
336 {
337 if (!this->isSeekMode())
338 {
339 if (!this->isViewing())
340 {
341 this->setViewing(true);
342 }
343
344 SoQtExaminerViewer::processSoEvent(ev);
345 this->setSeekTime(0.5);
346 this->seekToPoint(ev->getPosition());
347
348 if (this->isViewing())
349 {
350 this->setViewing(false);
351 }
352 }
353 }
354 else
355 {
356 SoQtExaminerViewer::processSoEvent(ev);
357 }
358
359 SoQtExaminerViewer::processSoEvent(ev);
360 }
361
362 //Let all move events trough
363 if (type.isDerivedFrom(SoLocation2Event::getClassTypeId()))
364 {
365 return SoQtExaminerViewer::processSoEvent(event);
366 }
367
368 //YOU SHALL NOT PASS!
369 return TRUE;
370}
static const int UNDOABLE
A flag to save the executed operations to the history.
Definition Controller.h:80
static const int EXECUTE_ON_WM
A Flag to execute operations on the WorkingMemory.
Definition Controller.h:66
static const int EXECUTE_ON_SCENE
A flag to execute operations on the Scene.
Definition Controller.h:73
SceneViewer(const controller::ControllerPtr &control, QWidget *widget)
Constructor Creates an Instance of the Class.
This file is part of ArmarX.
std::shared_ptr< Controller > ControllerPtr
std::shared_ptr< Operation > OperationPtr
constexpr auto n() noexcept
boost::intrusive_ptr< SceneObject > SceneObjectPtr