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