Developer Documentation
QtBaseViewerPicking.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 
51 
52 //=============================================================================
53 //
54 // CLASS QtBaseViewer - IMPLEMENTATION
55 //
56 //=============================================================================
57 
58 
59 //== INCLUDES =================================================================
60 
61 #include "QtBaseViewer.hh"
62 #include "QtGLGraphicsScene.hh"
63 #include "QtGLGraphicsView.hh"
64 
65 //== NAMESPACES ===============================================================
66 
67 namespace ACG {
68 namespace QtWidgets {
69 
70 //== IMPLEMENTATION ==========================================================
71 
72 static const unsigned int SELECTION_BUFFER_SIZE = 10000;
73 static const unsigned int NAME_STACK_SIZE = 2;
74 
75 //== IMPLEMENTATION ==========================================================
76 
77 
78 void QtBaseViewer::renderPicking(bool _renderPicking, ACG::SceneGraph::PickTarget _mode) {
79  renderPicking_ = _renderPicking;
80  pickRendererMode_ = _mode;
81 }
82 
83 //-----------------------------------------------------------------------------
84 
85 
87  const QPoint& _mousePos,
88  unsigned int& _nodeIdx,
89  unsigned int& _targetIdx,
90  Vec3d* _hitPointPtr )
91 {
92  if (sceneGraphRoot_)
93  {
94  GLint w = glWidth(),
95  h = glHeight(),
96  x = _mousePos.x(),
97  y = h - _mousePos.y();
98  GLint viewport[4] = {0,0,w,h};
99  GLuint nameBuffer[ NAME_STACK_SIZE ];
100 
101  // reduce stack usage
102  std::vector<GLuint> selectionBuffer(SELECTION_BUFFER_SIZE);
103 
104 
105  // Initialize name buffer
106  nameBuffer[0] = 0;
107  nameBuffer[1] = 0;
108 
109  const GLMatrixd& modelview = glstate_->modelview();
110  const GLMatrixd& projection = glstate_->projection();
111 
112 
113  // prepare GL state
114  makeCurrent();
115 
116  glSelectBuffer( SELECTION_BUFFER_SIZE, &selectionBuffer[0] );
117  glRenderMode(GL_SELECT);
118  glMatrixMode(GL_PROJECTION);
119  glLoadIdentity();
120 // gluPickMatrix((GLdouble) x, (GLdouble) y, 3, 3, viewport);
121  // gluPickMatrix implementation as in mesa3d
122  // Translate and scale the picked region to the entire window
123  const float deltax = 3.0f, deltay = 3.0f;
124  glTranslatef(float(viewport[2] - 2 * (x - viewport[0])) / deltax,
125  float(viewport[3] - 2 * (y - viewport[1])) / deltay, 0.0f);
126  glScalef(viewport[2] / deltax, viewport[3] / deltay, 1.0);
127 
128  glMultMatrixd(projection.get_raw_data());
129  glMatrixMode(GL_MODELVIEW);
130  glLoadMatrixd(modelview.get_raw_data());
131  ACG::GLState::disable(GL_LIGHTING);
132  glClear(GL_DEPTH_BUFFER_BIT);
133  glstate_->pick_init (false);
134 
135  // do the picking
136  SceneGraph::PickAction action(*glstate_, _pickTarget, curDrawMode_);
137  SceneGraph::traverse(sceneGraphRoot_, action);
138  int hits = glRenderMode(GL_RENDER);
139 
140  // restore GL state
141  glMatrixMode( GL_PROJECTION );
142  glLoadMatrixd(projection.get_raw_data());
143  glMatrixMode( GL_MODELVIEW );
144  glLoadMatrixd(modelview.get_raw_data());
145  ACG::GLState::enable(GL_LIGHTING);
146 
147 
148  // process hit record
149  if ( hits > 0 )
150  {
151  GLuint *ptr = &selectionBuffer[0],
152  z,
153  min_z=~(0u),
154  max_z=0;
155 
156  for (int i=0; i<hits; ++i)
157  {
158  const GLuint num_names = *ptr++;
159  if ( num_names != NAME_STACK_SIZE )
160  {
161  std::cerr << "QtBaseViewer::pick() : namestack error\n\n";
162  return false;
163  }
164 
165  if ( (z = *ptr++) < min_z )
166  {
167  min_z = z;
168  max_z = *ptr++;
169  for (unsigned int j=0; j<num_names; ++j)
170  nameBuffer[j] = *ptr++;
171  }
172  else ptr += 1+num_names;
173  }
174 
175  _nodeIdx = nameBuffer[0];
176  _targetIdx = nameBuffer[1];
177 
178  if (_hitPointPtr)
179  {
180  GLuint zscale=~(0u);
181  GLdouble min_zz = ((GLdouble)min_z) / ((GLdouble)zscale);
182  GLdouble max_zz = ((GLdouble)max_z) / ((GLdouble)zscale);
183  GLdouble zz = 0.5F * (min_zz + max_zz);
184  *_hitPointPtr = glstate_->unproject(Vec3d(x,y,zz));
185  }
186 
187  return true;
188  }
189  else if (hits < 0)
190  std::cerr << "QtBaseViewer::pick() : selection buffer overflow\n\n";
191  }
192 
193  return false;
194 }
195 
196 
197 //-----------------------------------------------------------------------------
198 
199 
200 bool
202 fast_pick( const QPoint& _mousePos,
203  Vec3d& _hitPoint )
204 {
205  // get x,y,z values of pixel
206  GLint x(_mousePos.x()), y(glHeight() - _mousePos.y());
207  GLfloat z;
208 
209 
210  makeCurrent();
211  glPixelStorei(GL_PACK_ALIGNMENT, 1);
212  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
213  glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &z);
214 
215 
216  if (z < 0.99999)
217  {
218  _hitPoint = glstate_->unproject( Vec3d(x, y, z) );
219  return true;
220  }
221  else return false;
222 }
223 
224 //-----------------------------------------------------------------------------
225 
226 
227 void QtBaseViewer::pickMode( int _id )
228 {
229  if (_id < (int) pick_modes_.size() )
230  {
231  pick_mode_idx_ = _id;
233 
234  // adjust mouse tracking
235  if ( actionMode_ == PickingMode )
237 
238  // adjust Cursor
239  if ( actionMode_ == PickingMode )
240  glView_->setCursor(pick_modes_[pick_mode_idx_].cursor);
241 
242  // emit signal
244  }
245 }
246 
247 
248 //-----------------------------------------------------------------------------
249 
250 
251 void QtBaseViewer::addPickMode(const std::string& _name,
252  bool _tracking,
253  int _pos,
254  bool _visible,
255  QCursor _cursor)
256 {
257  if ((unsigned int)_pos < pick_modes_.size())
258  {
259  std::vector<PickMode>::iterator it = pick_modes_.begin();
260  it += _pos+1;
261  pick_modes_.insert(it, PickMode(_name, _tracking, _visible, _cursor));
262  }
263  else
264  pick_modes_.push_back(PickMode(_name, _tracking, _visible, _cursor));
265 
266  updatePickMenu();
267 }
268 
269 //-----------------------------------------------------------------------------
270 
271 void QtBaseViewer::setPickModeCursor(const std::string& _name, QCursor _cursor)
272 {
273  for (uint i=0; i < pick_modes_.size(); i++)
274  if ( pick_modes_[i].name == _name ){
275  pick_modes_[i].cursor = _cursor;
276 
277  //switch cursor if pickMode is active
278  if (pick_mode_name_ == _name && actionMode_ == PickingMode)
279  glView_->setCursor(_cursor);
280  break;
281  }
282 }
283 
284 //-----------------------------------------------------------------------------
285 
286 void QtBaseViewer::setPickModeMouseTracking(const std::string& _name, bool _mouseTracking)
287 {
288  for (uint i=0; i < pick_modes_.size(); i++)
289  if ( pick_modes_[i].name == _name ){
290  pick_modes_[i].tracking = _mouseTracking;
291 
292  //switch cursor if pickMode is active
293  if (pick_mode_name_ == _name && actionMode_ == PickingMode)
294  trackMouse(_mouseTracking);
295  break;
296  }
297 }
298 
299 //-----------------------------------------------------------------------------
300 
301 
303 {
304  pick_modes_.clear();
305  pick_mode_idx_ = -1;
306  pick_mode_name_ = "";
307  updatePickMenu();
308 }
309 
310 
311 //-----------------------------------------------------------------------------
312 
313 
314 const std::string& QtBaseViewer::pickMode() const
315 {
316  return pick_mode_name_;
317 }
318 
319 
320 //-----------------------------------------------------------------------------
321 
322 
323 void QtBaseViewer::pickMode(const std::string& _name)
324 {
325  for (unsigned int i=0; i<pick_modes_.size(); ++i)
326  {
327  if (pick_modes_[i].name == _name)
328  {
329  pickMode( i );
330  updatePickMenu();
331  return;
332  }
333  }
334 }
335 
336 //-----------------------------------------------------------------------------
337 
340 }
341 
342 
343 //=============================================================================
344 } // namespace QtWidgets
345 } // namespace ACG
346 //=============================================================================
static void enable(GLenum _cap)
replaces glEnable, but supports locking
Definition: GLState.cc:1490
std::vector< PickMode > pick_modes_
void signalPickModeChanged(const std::string &)
unsigned int glHeight() const
get height of QGLWidget
void pick_init(bool _color)
initialize name/color picking stack (like glInitNames())
Definition: GLState.cc:1039
unsigned int glWidth() const
get width of QGLWidget
ACG::SceneGraph::PickTarget pickRendererMode_
PickTarget
What target to use for picking.
Definition: BaseNode.hh:99
void addPickMode(const std::string &_name, bool _mouse_tracking=false, int _pos=-1, bool _visible=true, QCursor _cursor=Qt::ArrowCursor)
add pick mode
Vec3d unproject(const Vec3d &_winPoint) const
unproject point in window coordinates _winPoint to world coordinates
Definition: GLState.cc:649
const Scalar * get_raw_data() const
Definition: Matrix4x4T.hh:262
void traverse(BaseNode *_node, Action &_action)
Definition: SceneGraph.hh:143
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
bool pick(SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, unsigned int &_nodeIdx, unsigned int &_targetIdx, Vec3d *_hitPointPtr=0)
static void disable(GLenum _cap)
replaces glDisable, but supports locking
Definition: GLState.cc:1504
virtual void makeCurrent()
Makes this widget the current widget for OpenGL operations.
const GLMatrixd & projection() const
get projection matrix
Definition: GLState.hh:789
ActionMode actionMode() const
get action mode
const std::string & pickMode() const
void renderPicking(bool _renderPicking, ACG::SceneGraph::PickTarget _mode)
const GLMatrixd & modelview() const
get modelview matrix
Definition: GLState.hh:794
void updatePickMenu()
update pick mode menu
void trackMouse(bool _track)
Enable/disable mouse tracking (move events with no button press)
void setPickModeMouseTracking(const std::string &_name, bool _mouseTracking)
set mouseTracking for the pick mode
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
void setPickModeCursor(const std::string &_name, QCursor _cursor)
set a new cursor for the pick mode
bool fast_pick(const QPoint &_mousePos, Vec3d &_hitPoint)