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 #include <Inventor/events/SoMouseButtonEvent.h>
26 #include <Inventor/events/SoLocation2Event.h>
27 #include <Inventor/actions/SoRayPickAction.h>
28 #include <Inventor/SoPickedPoint.h>
29 
30 #include "../controller/DeselectOperation.h"
31 #include "../controller/SelectOperation.h"
32 
33 
34 scene3D::SceneViewer::SceneViewer(const controller::ControllerPtr& control, QWidget* widget) : 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
51 SbBool scene3D::SceneViewer::processSoEvent(const SoEvent* const event)
52 {
53  const SoType type(event->getTypeId());
54 
55  //Remapping mouse press events
56  if (type.isDerivedFrom(SoMouseButtonEvent::getClassTypeId()))
57  {
58  SoMouseButtonEvent* const ev = (SoMouseButtonEvent*) event;
59  const int button = ev->getButton();
60  const SbBool press = ev->getState() == SoButtonEvent::DOWN ? TRUE : FALSE;
61 
62  //LEFT MOUSE BUTTON
63  if (button == SoMouseButtonEvent::BUTTON1)
64  {
66  {
67  if (!controller->getScene()->getSelectionManager()->getCreateOperations())
68  {
69  //SelectionManager is not creating Operations, so we shouldn't either!
70  return SoQtRenderArea::processSoEvent(ev);
71  }
72  }
73 
74  if (press)
75  {
76  /*We could just pass action into scenegraph here. There is only one litte thing
77  that doesnt work then: deselecting by clicking into void is performed as
78  many single deselection operations in controller. Undoing then performs
79  every deselection seperately, which is annoying. SoSelection on the other
80  hand doesn't tell us this 'click into void' event so we have to check ourself before this action
81  goes into scenegraph. */
82 
83  SoRayPickAction rp(this->getViewportRegion());
84  rp.setPickAll(false);
85  rp.setPoint(event->getPosition());
86  rp.apply(this->getSceneGraph());
87  SoPickedPoint* picked = rp.getPickedPoint();
88 
89  if (!picked)
90  {
91  /*We clicked into the void here, so we handle this event ourselves, instead of
92  leaving this up to the SoSelection Node... Tell controller to deselect everything
93  in one big operation block and then return, if there are any objects selected of course*/
94 
95  //Shift click into void doesnt change anything
96  if (!ev->wasShiftDown())
97  {
99  {
100  if (controller->getScene()->getSelectionManager()->getAllSelected().size() != 0)
101  {
102  std::shared_ptr<std::vector<controller::OperationPtr>> operations(new std::vector<controller::OperationPtr>());
103 
104  // deselect all objects
105  for (scene3D::SceneObjectPtr object : controller->getScene()->getSelectionManager()->getAllSelected())
106  {
107  controller::OperationPtr deselect(new controller::DeselectOperation(controller->getMemoryXController(), controller->getScene(), object->getObjectId()));
108  operations->push_back(deselect);
109  }
110 
112  }
113  }
114  }
115 
116  return TRUE;
117  }
118  else
119  {
120  /* The performed click is above something!*/
121 
122  /*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,
123  we can simply pass the event into scenegraph, because we dont have to change the behaviour here!*/
124 
125  SoFullPath* p = (SoFullPath*) picked->getPath();
126 
127  for (int i = 0; i < p->getLength(); i++)
128  {
129  SoNode* n = p->getNode(i);
130 
131  if (n->isOfType(SoTransformManip::getClassTypeId()))
132  {
133  //Manipulator found, pass event into scenegraph
134  return SoQtRenderArea::processSoEvent(ev);
135  }
136  }
137 
138  /* Seems like we selected something and it is not a manipulator, must be an object! Let's check some last cases we have
139  to manually handle.*/
140 
141  if (!ev->wasShiftDown())
142  {
143  /*If shift is not down we might get the case where mutiple objects are deselected before the picked object
144  is selected. We just do this work for the SoSelection node and group all deselect operations and the select operation
145  into one block (which is what SoSelection can't do for us). */
147  {
148  //Is there more than one object already selected?
149  if (controller->getScene()->getSelectionManager()->getAllSelected().size() > 0)
150  {
151  //Find out which object to select
152  SceneObjectPtr obj;
153 
154  for (int i = 0; i < picked->getPath()->getLength(); i++)
155  {
156  SoNode* n = picked->getPath()->getNode(i);
157 
158  if (n->isOfType(SceneObject::getClassTypeId()))
159  {
160  obj.reset((SceneObject*) n);
161  }
162  }
163 
164  //Is there only one object selected and it is also the object we want to select here?
165  if (controller->getScene()->getSelectionManager()->getAllSelected().size() == 1
166  && controller->getScene()->getSelectionManager()->isSelected(obj))
167  {
168  //No need to do something, pass this to Selection node, default behaviour.
169  return SoQtRenderArea::processSoEvent(ev);
170  }
171  else
172  {
173  //Deselect all and select object in one block operation
174  std::shared_ptr<std::vector<controller::OperationPtr>> operations(new std::vector<controller::OperationPtr>());
175 
176  // deselect all objects
177  for (scene3D::SceneObjectPtr object : controller->getScene()->getSelectionManager()->getAllSelected())
178  {
179  controller::OperationPtr deselect(new controller::DeselectOperation(controller->getMemoryXController(), controller->getScene(), object->getObjectId()));
180  operations->push_back(deselect);
181  }
182 
184 
185  //Let SoSelection node handle the selection
186  return SoQtRenderArea::processSoEvent(ev);
187  }
188  }
189  else
190  {
191  //Nothing selected, so its gonna be only one operation. Let SoSelection node do this.
192  return SoQtRenderArea::processSoEvent(ev);
193  }
194  }
195  }
196  else
197  {
198  /*If shift is down and an object is being picked, selection list can only grow by one element
199  or one element is deselected. We therefore don't need to put all operations into one block of operations
200  because it can only be one operation at once. Just pass this event right into the scenegraph and let
201  the SoSelection node handle it automatically. */
202  return SoQtRenderArea::processSoEvent(ev);
203  }
204  }
205  }
206  else
207  {
208  return SoQtRenderArea::processSoEvent(ev);
209  }
210  }
211 
212  //RIGHT MOUSE BUTTON
213  if (button == SoMouseButtonEvent::BUTTON2)
214  {
215  /*Right mouse button has no functionality yet, so ignore it.*/
216  return TRUE;
217  }
218 
219  //MIDDLE MOUSE BUTTON
220  if (button == SoMouseButtonEvent::BUTTON3)
221  {
222  /*Middle mouse button now is used for all changes in camera perspective.
223  To also display the cool little rotation cursor, viewing mode is set to on
224  while button is down*/
225 
226  //Enable or disable viewing mode while BUTTON3 pressed
227  if (press)
228  {
229  if (!this->isViewing())
230  {
231  this->setViewing(true);
232  }
233  }
234  else
235  {
236  if (this->isViewing())
237  {
238  this->setViewing(false);
239  }
240  }
241 
242  //Remap BUTTON3 to BUTTON1
243  ev->setButton(SoMouseButtonEvent::BUTTON1);
244 
245  //Make sure this REALLY only can happen when viewing mode is on.
246  //Zooming can also turn it on and it leads to weird effects when doing both
247  //(deselections in scene etc.) because SoQtExaminerViewer passes BUTTON1
248  //events up to scenegraph when not in viewing mode.
249  if (this->isViewing())
250  {
251  return SoQtExaminerViewer::processSoEvent(ev);
252  }
253  }
254 
255  //MOUSE WHEEL UP AND DOWN
256  if (button == SoMouseButtonEvent::BUTTON4 || button == SoMouseButtonEvent::BUTTON5)
257  {
258  /*Zooming is allowed, so just use it. We have to temporarily turn viewing mode
259  on to make SoQtExaminerViewer allow zooming.*/
260 
261  //Swap BUTTON4 and BUTTON5 because zooming out while scrolling up is just retarded
262  ev->setButton(button == SoMouseButtonEvent::BUTTON4 ?
263  SoMouseButtonEvent::BUTTON5 : SoMouseButtonEvent::BUTTON4);
264 
265  //Zooming is allowed, so just pass it and temporarily set viewing mode on, if it is not already
266  //(otherwise coin gives us warning messages...)
267  if (!this->isViewing())
268  {
269  if (!this->isViewing())
270  {
271  this->setViewing(true);
272  }
273 
274  SoQtExaminerViewer::processSoEvent(ev);
275 
276  if (this->isViewing())
277  {
278  this->setViewing(false);
279  }
280  }
281  else
282  {
283  SoQtExaminerViewer::processSoEvent(ev);
284  }
285 
286  return TRUE;
287  }
288  }
289 
290  // Keyboard handling
291  if (type.isDerivedFrom(SoKeyboardEvent::getClassTypeId()))
292  {
293  const SoKeyboardEvent* const ev = (const SoKeyboardEvent*) event;
294 
295  /*The escape key and super key (windows key) is used to switch between
296  viewing modes. We need to disable this behaviour completely.*/
297 
298  //65513 seems to be the super key, which is not available in the enum of keys in coin....
299  if (ev->getKey() == SoKeyboardEvent::ESCAPE || ev->getKey() == 65513)
300  {
301  return TRUE;
302  }
303  else if (ev->getKey() == SoKeyboardEvent::S && ev->getState() == SoButtonEvent::DOWN)
304  {
305  if (!this->isSeekMode())
306  {
307  if (!this->isViewing())
308  {
309  this->setViewing(true);
310  }
311 
312  SoQtExaminerViewer::processSoEvent(ev);
313  this->setSeekTime(0.5);
314  this->seekToPoint(ev->getPosition());
315 
316  if (this->isViewing())
317  {
318  this->setViewing(false);
319  }
320  }
321  }
322  else
323  {
324  SoQtExaminerViewer::processSoEvent(ev);
325  }
326 
327  SoQtExaminerViewer::processSoEvent(ev);
328  }
329 
330  //Let all move events trough
331  if (type.isDerivedFrom(SoLocation2Event::getClassTypeId()))
332  {
333  return SoQtExaminerViewer::processSoEvent(event);
334  }
335 
336  //YOU SHALL NOT PASS!
337  return TRUE;
338 }
scene3D::SceneViewer::SceneViewer
SceneViewer(const controller::ControllerPtr &control, QWidget *widget)
Constructor Creates an Instance of the Class.
Definition: SceneViewer.cpp:34
controller::Controller::EXECUTE_ON_SCENE
static const int EXECUTE_ON_SCENE
A flag to execute operations on the Scene.
Definition: Controller.h:73
controller::Controller::UNDOABLE
static const int UNDOABLE
A flag to save the executed operations to the history.
Definition: Controller.h:80
controller
Definition: AddOperation.h:39
controller::ControllerPtr
std::shared_ptr< Controller > ControllerPtr
Definition: ClassDefinitions.h:41
controller::DeselectOperation
A operation to deselect a object.
Definition: DeselectOperation.h:41
SceneViewer.h
controller::OperationPtr
std::shared_ptr< Operation > OperationPtr
Definition: ClassDefinitions.h:54
scene3D::SceneObjectPtr
boost::intrusive_ptr< SceneObject > SceneObjectPtr
Definition: PointerDefinitions.h:40
controller::Controller::EXECUTE_ON_WM
static const int EXECUTE_ON_WM
A Flag to execute operations on the WorkingMemory.
Definition: Controller.h:66
control
This file is part of ArmarX.