Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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 //=============================================================================
ACG::GLState::enable
static void enable(GLenum _cap)
replaces glEnable, but supports locking
Definition: GLState.cc:1490
ACG
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
ACG::Vec2i
VectorT< signed int, 2 > Vec2i
Definition: VectorT.hh:104
ACG::GLMatrixf
GLMatrixT< float > GLMatrixf
typedef
Definition: GLMatrixT.hh:325
ACG::Vec3d
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
ACG::GLState::drawBuffer
static void drawBuffer(GLenum _mode)
replaces glDrawBuffer, supports locking
Definition: GLState.cc:1953
ACG::Matrix4x4T::identity
void identity()
setup an identity matrix
Definition: Matrix4x4T.cc:256
ACG::GLState::disable
static void disable(GLenum _cap)
replaces glDisable, but supports locking
Definition: GLState.cc:1504
ACG::glVertex
void glVertex(const Vec2i &_v)
Wrapper: glVertex for Vec2i.
Definition: gl.hh:97