Developer Documentation
QtLasso.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 QtLasso - IMPLEMENTATION
55 //
56 //=============================================================================
57 
58 //== INCLUDES =================================================================
59 
60 
61 //ACG
62 #include "QtLasso.hh"
63 #include "QtColorTranslator.hh"
64 
65 // stdc++
66 
67 
68 
69 //== NAMESPACES ===============================================================
70 
71 namespace ACG {
72 
73 
74 //== IMPLEMENTATION ==========================================================
75 
76 
77 
78 #define MASK(x,y) (mask_[(x)+(y)*mask_width_])
79 
80 
81 //-----------------------------------------------------------------------------
82 
83 
84 QtLasso::
85 QtLasso(GLState& _glstate) :
86  glstate_(_glstate),
87  mask_(0),
88  mask_width_(0),
89  mask_height_(0),
90  is_active_(false)
91 {
92 }
93 
94 
95 //-----------------------------------------------------------------------------
96 
97 
98 QtLasso::
99 ~QtLasso()
100 {
101  free_mask();
102 }
103 
104 
105 //-----------------------------------------------------------------------------
106 
107 
108 void
109 QtLasso::
110 slotMouseEvent(QMouseEvent* _event)
111 {
112  bool emit_signal = false;
113 
114 
115  // setup 2D projection
116  unsigned int width = glstate_.viewport_width();
117  unsigned int height = glstate_.viewport_height();
118 
119  ACG::GLState::drawBuffer( GL_FRONT );
120 
121  glMatrixMode(GL_PROJECTION);
122  glPushMatrix();
123  GLMatrixf orthoProj;
124  orthoProj.identity();
125  orthoProj.ortho(0.0f, float(width-1), 0.0f, float(height-1), -1.0f, 1.0f);
126  glLoadMatrixf(orthoProj.data());
127 
128 
129  glMatrixMode(GL_MODELVIEW);
130  glPushMatrix();
131  glLoadIdentity();
132 
133  ACG::GLState::disable(GL_DEPTH_TEST);
134  ACG::GLState::disable(GL_LIGHTING);
135  ACG::GLState::disable(GL_DITHER);
136  glLineWidth(2.0);
137  glColor3ub(0, 255, 10);
138 
139  glFinish();
140 
141 
142 
143  // process mouse event
144  switch(_event->type())
145  {
146  case QEvent::MouseButtonPress:
147  {
148  Vec2i p(_event->pos().x(), height-_event->pos().y()-1);
149 
150  // initialize
151  if (!is_active())
152  {
153  is_active_ = true;
154  first_point_ = last_point_ = p;
155  }
156 
157  // draw line
158  glBegin(GL_LINES);
159  glVertex(last_point_);
160  glVertex(p);
161  glEnd();
162  last_point_ = rubberband_point_ = p;
163  break;
164  }
165 
166 
167  case QEvent::MouseMove:
168  {
169  if (is_active())
170  {
171  Vec2i p(_event->pos().x(), height-_event->pos().y());
172 
173  // draw freehand
174  if (_event->modifiers() & Qt::LeftButton)
175  {
176  glBegin(GL_LINES);
177  glVertex(last_point_);
178  glVertex(p);
179  glEnd();
180  last_point_ = rubberband_point_ = p;
181  }
182 
183  // draw rubber band
184  else
185  {
186  ACG::GLState::enable(GL_COLOR_LOGIC_OP);
187  glLogicOp(GL_XOR);
188  glBegin(GL_LINES);
189  glVertex(last_point_);
190  glVertex(rubberband_point_);
191  glVertex(last_point_);
192  glVertex(p);
193  glEnd();
194  ACG::GLState::disable(GL_COLOR_LOGIC_OP);
195  rubberband_point_ = p;
196  }
197  }
198  break;
199  }
200 
201 
202  case QEvent::MouseButtonDblClick:
203  {
204  if (is_active())
205  {
206  // close polygon
207  glBegin(GL_LINES);
208  glVertex(last_point_);
209  glVertex(first_point_);
210  glEnd();
211  glFinish();
212 
213 
214  // mark reference point (0,0) with border color
215  glPointSize(1.0);
216  glBegin(GL_POINTS);
217  glVertex2i(0, 0);
218  glEnd();
219  glPointSize(glstate_.point_size());
220 
221 
222  // create mask and precompute matrix
223  create_mask();
224  is_active_ = false;
225 
226  emit_signal = true;
227  }
228  break;
229  }
230 
231 
232  default: // avoid warning
233  break;
234  }
235 
236 
237  // restore GL settings
238  ACG::GLState::drawBuffer(GL_BACK);
239  glReadBuffer(GL_BACK);
240 
241  glLineWidth(glstate_.line_width());
242  glColor4fv(glstate_.base_color().data());
243  ACG::GLState::enable(GL_DEPTH_TEST);
244 
245  glMatrixMode(GL_PROJECTION );
246  glPopMatrix();
247 
248  glMatrixMode(GL_MODELVIEW);
249  glPopMatrix();
250 
251  glFinish();
252 
253 
254 
255  // emit signal
256  if (emit_signal)
257  {
258  if (_event->modifiers() & Qt::ShiftModifier)
259  emit(signalLassoSelection(AddToSelection));
260 
261  else if (_event->modifiers() & Qt::ControlModifier)
262  emit(signalLassoSelection(DelFromSelection));
263 
264  else
265  emit(signalLassoSelection(NewSelection));
266  }
267 }
268 
269 
270 //-----------------------------------------------------------------------------
271 
272 
273 void
274 QtLasso::
275 create_mask()
276 {
277  unsigned int x, y, xx, yy, i;
278  GLubyte *fbuffer;
279  QRgb rgb, borderRgb;
280 
281 
282  // GL context
283  const unsigned int w = glstate_.viewport_width();
284  const unsigned int h = glstate_.viewport_height();
285  const unsigned int size = w*h;
286 
287 
288  // alloc mask
289  free_mask();
290  mask_ = new unsigned char[size];
291  mask_width_ = w;
292  mask_height_ = h;
293 
294 
295  // alloc framebuffer
296  fbuffer = new GLubyte[3*size];
297  assert( fbuffer );
298 
299 
300  // read framebuffer
301  glReadBuffer( GL_FRONT );
302  glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, fbuffer);
303  glReadBuffer( GL_BACK );
304 
305 
306  // read lasso color
307  borderRgb = qRgb( fbuffer[0], fbuffer[1], fbuffer[2] );
308  fbuffer[0] = fbuffer[1] = fbuffer[2] = 0;
309 
310 
311  // mark lasso pixels
312  for (y = 0; y < h; ++y)
313  {
314  const unsigned int offset = y*w;
315 
316  for (x = 0; x < w; ++x)
317  {
318  i = 3*(offset + x);
319  rgb = qRgb(fbuffer[i], fbuffer[i+1], fbuffer[i+2]);
320  mask_[offset+x] = (rgb == borderRgb) ? 3 : 1;
321  }
322  }
323 
324 
325  // seed fill
326  std::vector<Vec2i> toDo;
327  toDo.reserve(w*h);
328  toDo.push_back(Vec2i(0,0));
329 
330  while (!toDo.empty())
331  {
332  Vec2i p = toDo.back();
333  toDo.pop_back();
334 
335  x = p[0];
336  y = p[1];
337  unsigned char &s = MASK(x, y);
338 
339  if (s != 3)
340  {
341  s = 0;
342 
343  xx = x-1; yy = y;
344  if ((xx<w) && (MASK(xx,yy)==1))
345  {
346  toDo.push_back(Vec2i(xx,yy));
347  MASK(xx,yy) = 2;
348  }
349 
350  xx = x+1; yy = y;
351  if ((xx<w) && (MASK(xx,yy)==1))
352  {
353  toDo.push_back(Vec2i(xx,yy));
354  MASK(xx,yy) = 2;
355  }
356 
357  xx = x; yy = y-1;
358  if ((yy<h) && (MASK(xx,yy)==1))
359  {
360  toDo.push_back(Vec2i(xx,yy));
361  MASK(xx,yy) = 2;
362  }
363 
364  xx = x; yy = y+1;
365  if ((yy<h) && (MASK(xx,yy)==1))
366  {
367  toDo.push_back(Vec2i(xx,yy));
368  MASK(xx,yy) = 2;
369  }
370  }
371  }
372 
373 
374  // free
375  delete[] fbuffer;
376 }
377 
378 
379 //-----------------------------------------------------------------------------
380 
381 
382 void
383 QtLasso::
384 free_mask()
385 {
386  if (mask_)
387  {
388  delete[] mask_;
389  mask_ = 0;
390  mask_width_ = mask_height_ = 0;
391  }
392 }
393 
394 
395 //-----------------------------------------------------------------------------
396 
397 
398 bool
399 QtLasso::
400 is_vertex_selected(const Vec3d& _v)
401 {
402  unsigned int x, y, w, h;
403 
404 
405  // size changed?
406  w = glstate_.viewport_width();
407  h = glstate_.viewport_height();
408  if ((w != mask_width_) || (h != mask_height_))
409  {
410  std::cerr << "Lasso: viewport size has changed.\n";
411  return false;
412  }
413 
414 
415  // project vertex to 2D integer coordinates
416  Vec3d v = glstate_.project(_v);
417  x = (unsigned int)(v[0] + 0.5);
418  y = (unsigned int)(v[1] + 0.5);
419 
420 
421  // near and far plane clipping
422  if (v[2] < 0.0 || v[2] > 1.0)
423  return false;
424 
425 
426  // visible ?
427  return ((v[2]>0.0) && (x<w) && (y<h) && (MASK(x,y)));
428 }
429 
430 
431 //=============================================================================
432 } // namespace ACG
433 //=============================================================================
static void enable(GLenum _cap)
replaces glEnable, but supports locking
Definition: GLState.cc:1490
GLMatrixT< float > GLMatrixf
typedef
Definition: GLMatrixT.hh:330
void glVertex(const Vec2i &_v)
Wrapper: glVertex for Vec2i.
Definition: gl.hh:97
void identity()
setup an identity matrix
Definition: Matrix4x4T.cc:256
VectorT< signed int, 2 > Vec2i
Definition: VectorT.hh:104
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
static void disable(GLenum _cap)
replaces glDisable, but supports locking
Definition: GLState.cc:1504
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition: GLState.cc:1953
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127