1 /****************************************************************************
2 * Rgb Triangulations Plugin *
3 * *
4 * Author: Daniele Panozzo (daniele.panozzo@gmail.com) *
5 * Copyright(C) 2007 *
6 * DISI - Department of Computer Science *
7 * University of Genova *
8 * *
9 * All rights reserved. *
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20 * for more details. *
21 ****************************************************************************/
22
23 #include <QtGui>
24
25 #include <math.h>
26 #include <stdlib.h>
27 #include <meshlab/glarea.h>
28 #include "rgbt.h"
29 #include <stdio.h>
30 #include <wrap/gl/pick.h>
31 #include <limits>
32 #include <vcg/space/color4.h>
33
34 #include "rgbPrimitives.h"
35 #include "controlPoint.h"
36 #include "subDialog.h"
37
38 #include<vcg/complex/algorithms/update/topology.h>
39 #include<vcg/complex/algorithms/update/bounding.h>
40
41 namespace rgbt
42 {
43
44 using namespace vcg;
45
RgbTPlugin()46 RgbTPlugin::RgbTPlugin()
47 {
48 m = 0;
49 rgbInfo = 0;
50 widgetRgbT=0;
51 to = 0;
52 isDragging = false;
53 //qDebug() << "RgbTPlugin"<< endl;
54 ie = 0;
55 rgbie = 0;
56 }
57
58 /** the destructor is never called */
~RgbTPlugin()59 RgbTPlugin::~RgbTPlugin()
60 {
61 //qDebug() << "~RgbTPlugin"<< endl;
62 }
63
Info()64 const QString RgbTPlugin::Info()
65 {
66 return tr("Selective Mesh Refinement with Rgb Triangulations");
67 }
68
StartEdit(MeshModel & m,GLArea * parent)69 bool RgbTPlugin::StartEdit(MeshModel &m, GLArea * parent)
70 {
71 // select the type of subdivison surface
72 SubDialog sd;
73 int r = sd.exec();
74 if (r == QDialog::Accepted)
75 RgbPrimitives::stype = RgbPrimitives::LOOP;
76 else
77 RgbPrimitives::stype = RgbPrimitives::MODBUTFLY;
78 // -----
79
80
81 this->m = &m;
82 current_gla = parent;
83
84 if (widgetRgbT==0)
85 {
86 widgetRgbT = new WidgetRgbT(parent->window(),this);
87 paint_dock = new QDockWidget(parent->window());
88 paint_dock->setAllowedAreas(Qt::NoDockWidgetArea);
89 paint_dock->setWidget(widgetRgbT);
90 QPoint p=parent->window()->mapToGlobal(QPoint(0, 0));
91 paint_dock->setGeometry(-5+p.x()+parent->window()->width()-widgetRgbT->width(), p.y(), widgetRgbT->width(),
92 widgetRgbT->height());
93 paint_dock->setFloating(true);
94 }
95 paint_dock->setVisible(true);
96 paint_dock->layout()->update();
97
98 parent->setCursor(QCursor(QPixmap(":/images/sel_rect.png"),1,1));
99
100 m.updateDataMask(MeshModel::MM_FACEFACETOPO);
101 m.updateDataMask(MeshModel::MM_VERTFACETOPO); // It update also the FV relation
102 m.updateDataMask(MeshModel::MM_FACECOLOR);
103
104 #ifdef RGBCOLOR
105 parent->getCurrentRenderMode().colorMode=vcg::GLW::CMPerFace;
106 #endif
107 parent->getCurrentRenderMode().lighting=true;
108 parent->getCurrentRenderMode().drawMode = vcg::GLW::DMFlatWire;
109 //parent->mm()->ioMask|=MeshModel::IOM_FACECOLOR;
110
111 if (rgbInfo) delete rgbInfo;
112 rgbInfo = new RgbInfo(m.cm.vert.size(),m.cm.face.size());
113
114 if (to) delete to;
115 to = new TopologicalOpC(m.cm,&(rgbInfo->vert),&(rgbInfo->face));
116
117 if (ie) delete ie;
118 ie = new InteractiveEdit();
119
120 if (rgbie) delete rgbie;
121 rgbie = new RgbInteractiveEdit(m.cm,*rgbInfo,*to);
122
123 for (unsigned int i = 0; i < m.cm.face.size(); ++i)
124 {
125 if (!m.cm.face[i].IsD())
126 {
127 RgbTriangleC t = RgbTriangleC(m.cm,*rgbInfo,i);
128 t.setFaceColor(FaceInfo::FACE_GREEN);
129 t.setFaceLevel(0);
130 }
131 }
132 int x = 0;
133 for (unsigned int i = 0; i < m.cm.vert.size(); ++i)
134 {
135
136 if (!m.cm.vert[i].IsD())
137 {
138 RgbVertexC v = RgbVertexC(m.cm,*rgbInfo,i);
139 v.setLevel(0);
140
141 if (!RgbPrimitives::isVertexInternal(v))
142 {
143 v.setIsBorder(true);
144 x++;
145 }
146
147 }
148
149 }
150
151 ModButterfly::init(m.cm,*rgbInfo);
152
153 ControlPoint::init(m.cm,*rgbInfo);
154
155 parent->update();
156
157 updateSelectedFaces(m);
158 return false;
159 }
160
161 // this is called only when we change editor or we want to close it.
EndEdit(MeshModel &,GLArea *)162 void RgbTPlugin::EndEdit(MeshModel &/*m*/, GLArea * /*parent*/)
163 {
164 //qDebug() <<"RgbTPlugin::ENDEDIT"<<endl;
165
166 if (widgetRgbT!=0)
167 {
168 delete widgetRgbT;
169 delete paint_dock;
170 widgetRgbT=0;
171 paint_dock=0;
172 }
173 }
174
mousePressEvent(QMouseEvent * event,MeshModel & m,GLArea * gla)175 void RgbTPlugin::mousePressEvent(QMouseEvent *event, MeshModel &m, GLArea * gla)
176 {
177 cur=event->pos();
178 isDragging = true;
179 selMode = SMClear;
180 if(event->modifiers()==Qt::ControlModifier) selMode=SMAdd;
181 if(event->modifiers()==Qt::ShiftModifier) selMode=SMSub;
182
183 if (widgetRgbT->tool == TOOL_BRUSH || widgetRgbT->tool == TOOL_ERASER)
184 {
185 // Interactive Editing
186 ie->has_track=gla->isTrackBallVisible();
187 gla->showTrackBall(false);
188
189 ie->first = true;
190 ie->isDragging = true;
191 ie->pressed = 1;
192
193 ie->visited_vertexes.clear();
194 ie->start=event->pos();
195 ie->cur=ie->start;
196 ie->prev=ie->start;
197 ie->inverse_y=gla->curSiz.height()-cur.y();
198 ie->curr_mouse=event->button();
199 ie->current_gla=gla;
200
201 ie->pen.painttype=PEN;
202 ie->pen.paintutensil=SELECT;
203 ie->pen.backface= 0;
204 ie->pen.invisible= 0;
205 ie->pen.radius= widgetRgbT->sRadius->value()*0.5;
206 ie->curSel.clear();
207 }
208 }
209
mouseMoveEvent(QMouseEvent * event,MeshModel &,GLArea * gla)210 void RgbTPlugin::mouseMoveEvent(QMouseEvent * event, MeshModel &/*m*/, GLArea *gla)
211 {
212 isDragging = true;
213 cur=event->pos();
214
215 if (widgetRgbT->tool == TOOL_BRUSH || (widgetRgbT->tool == TOOL_ERASER))
216 {
217 if (!ie->isDragging)
218 {
219 ie->prev=ie->cur; /** to prevent losses when two mouseEvents occur befor one decorate */
220 }
221 ie->cur=event->pos();
222 ie->isDragging = true;
223 //gla->update();
224 }
225
226 gla->update();
227 }
228
mouseReleaseEvent(QMouseEvent * event,MeshModel &,GLArea * gla)229 void RgbTPlugin::mouseReleaseEvent(QMouseEvent *event, MeshModel &/*m*/, GLArea *gla)
230 {
231 if (widgetRgbT->tool == TOOL_BRUSH || (widgetRgbT->tool == TOOL_ERASER))
232 {
233 gla->showTrackBall(ie->has_track);
234 ie->visited_vertexes.clear();
235 gla->update();
236 ie->prev=ie->cur;
237 ie->cur=event->pos();
238 ie->pressed=2;
239 ie->isDragging=false;
240 }
241 }
242
DrawXORRect(GLArea * gla,bool doubleDraw)243 void RgbTPlugin::DrawXORRect(GLArea * gla, bool doubleDraw)
244 {
245 glMatrixMode(GL_PROJECTION);
246 glPushMatrix();
247 glLoadIdentity();
248 glOrtho(0,gla->curSiz.width(),gla->curSiz.height(),0,-1,1);
249 glMatrixMode(GL_MODELVIEW);
250 glPushMatrix();
251 glLoadIdentity();
252 glPushAttrib(GL_ENABLE_BIT);
253 glDisable(GL_DEPTH_TEST);
254 glDisable(GL_LIGHTING);
255 glDisable(GL_TEXTURE_2D);
256 glEnable(GL_COLOR_LOGIC_OP);
257 glLogicOp(GL_XOR);
258 glColor3f(1,1,1);
259 if(doubleDraw)
260 {
261 glBegin(GL_LINE_LOOP);
262 glVertex2f(startp.x(),startp.y());
263 glVertex2f(prevp.x(),startp.y());
264 glVertex2f(prevp.x(),prevp.y());
265 glVertex2f(startp.x(),prevp.y());
266 glEnd();
267 }
268 glBegin(GL_LINE_LOOP);
269 glVertex2f(startp.x(),startp.y());
270 glVertex2f(cur.x(),startp.y());
271 glVertex2f(cur.x(),cur.y());
272 glVertex2f(startp.x(),cur.y());
273 glEnd();
274 glDisable(GL_LOGIC_OP);
275
276 // Closing 2D
277 glPopAttrib();
278 glPopMatrix(); // restore modelview
279 glMatrixMode(GL_PROJECTION);
280 glPopMatrix();
281 glMatrixMode(GL_MODELVIEW);
282
283 }
284
285 /** only in decorare it is possible to obtain the correct zbuffer values and the other opengl stuff */
Decorate(MeshModel & m,GLArea * gla)286 void RgbTPlugin::Decorate(MeshModel &m, GLArea * gla)
287 {
288 if (!widgetRgbT)
289 return; // it is possible that the widget is not altready build when decorate il called
290 QPoint mid=QPoint(cur.x(),gla->curSiz.height()-cur.y());
291 CMeshO::FaceIterator it;
292
293 switch (widgetRgbT->tool)
294 {
295 case TOOL_SELECTIONSINGLE:
296 if (!isDragging) return;
297 CFaceO * fp;
298 if (getFaceAtMouse(m,mid,fp))
299 {
300 switch (selMode)
301 {
302 case SMAdd:
303 if (!fp->IsS())
304 {
305 selectedFaces.push_back(fp);
306 fp->SetS();
307 }
308
309 break;
310 case SMSub:
311 if (fp->IsS())
312 {
313 selectedFaces.remove(fp);
314 fp->ClearS();
315 }
316
317 break;
318 case SMClear:
319 for (it = m.cm.face.begin(); it != m.cm.face.end(); ++it)
320 {
321 it->ClearS();
322 }
323 selectedFaces.clear();
324 fp->SetS();
325 selectedFaces.push_back(fp);
326 break;
327 default:
328 break;
329 }
330 }
331
332 break;
333
334 case TOOL_BRUSH:
335 case TOOL_ERASER:
336
337 ie->updateMatrixes();
338 QPoint mid=QPoint(cur.x(),gla->curSiz.height()- cur.y());
339 if (ie->first)
340 {
341 ie->first=false;
342 if (ie->pixels!=0)
343 {
344 free(ie->pixels);
345 }
346 ie->pixels=(GLfloat *)malloc(sizeof(GLfloat)*gla->curSiz.width()*gla->curSiz.height());
347 glReadPixels(0,0,gla->curSiz.width(),gla->curSiz.height(),GL_DEPTH_COMPONENT,GL_FLOAT,ie->pixels);
348 }
349 if(ie->isDragging)
350 {
351 ie->isDragging=false;
352
353 ie->DrawXORCircle(gla,false);
354
355 vector<Vert_Data>::iterator vpo;
356 vector<Vert_Data> newSel;
357
358 vector<CMeshO::FacePointer> faceSel;
359
360 if (ie->first)
361 ie->curSel.clear();
362
363 ie->pen.backface = false;
364 ie->pen.invisible = false;
365
366 ie->getInternFaces(m,&ie->curSel,&newSel,&faceSel,gla,ie->pen,ie->cur,ie->prev,ie->pixels,ie->mvmatrix,ie->projmatrix,ie->viewport);
367
368 // Faces
369 if (widgetRgbT->tool == TOOL_BRUSH)
370 {
371 vector<CMeshO::FacePointer>::iterator fpo;
372 typedef std::pair<int,int> intpair;
373 list<intpair> lp;
374 list<intpair>::iterator lpit;
375
376 //std::cout << "FACES << ";
377 for(fpo=faceSel.begin();fpo!=faceSel.end();++fpo)
378 {
379 for (int i = 0; i<3; i++)
380 {
381 int v1 = (*fpo)->V(i%3)-&(m.cm.vert[0]);
382 int v2 = (*fpo)->V((i+1)%3)-&(m.cm.vert[0]);
383 lp.push_back(intpair(v1,v2));
384 }
385 //std::cout << (*fpo)->Index() << " - ";
386 }
387 //std::cout << ">> " << std::endl;
388 for (lpit = lp.begin(); lpit != lp.end(); ++lpit)
389 {
390 int wlevel = widgetRgbT->sBrushLevel->value();
391 double wlength = widgetRgbT->sBrushLength->value();
392 int* plevel = widgetRgbT->cLevelEnabled->isChecked() ? &wlevel : 0;
393 double* plength = widgetRgbT->cLengthEnabled->isChecked() ? &wlength : 0;
394 rgbie->processEdge((*lpit).first,(*lpit).second,plevel,plength);
395 }
396
397 }
398
399 if (widgetRgbT->tool == TOOL_ERASER)
400 {
401 // Vert
402 list<int> li;
403 list<int>::iterator liit;
404
405 //std::cout << "VERT << ";
406 for(vpo=newSel.begin();vpo!=newSel.end();++vpo)
407 {
408 int i = (vpo->v) - &(m.cm.vert[0]);
409 li.push_back(i);
410 //std::cout << i << "(" << vpo->distance << ") - ";
411 }
412 for (liit = li.begin(); liit != li.end(); ++liit)
413 {
414 int wlevel = widgetRgbT->sBrushLevel->value();
415 double wlength = widgetRgbT->sBrushLength->value();
416 int* plevel = widgetRgbT->cLevelEnabled->isChecked() ? &wlevel : 0;
417 double* plength = widgetRgbT->cLengthEnabled->isChecked() ? &wlength : 0;
418 rgbie->processVertex(*liit,plevel,plength);
419 }
420
421 //std::cout << ">> " << std::endl;
422 }
423
424 ie->pressed=0;
425
426 }
427 ie->isDragging = false;
428 }
429 }
430
getFaceAtMouse(MeshModel & m,QPoint & mid,CMeshO::FacePointer & val)431 bool RgbTPlugin::getFaceAtMouse(MeshModel &m,QPoint &mid ,CMeshO::FacePointer& val)
432 {
433 return (GLPickTri<CMeshO>::PickNearestFace(mid.x(), mid.y(), m.cm, val,2,2));
434 }
435
getFacesAtMouse(MeshModel & m,QPoint & mid,vector<CMeshO::FacePointer> & val)436 bool RgbTPlugin::getFacesAtMouse(MeshModel &m,QPoint &mid ,vector<CMeshO::FacePointer> & val)
437 {
438 val.clear();
439 GLPickTri<CMeshO>::PickFace(mid.x(), mid.y(), m.cm, val,2,2);
440 return (val.size()>0);
441 }
442
updateSelectedFaces(MeshModel & m)443 void RgbTPlugin::updateSelectedFaces(MeshModel &m)
444 {
445 selectedFaces.clear();
446 CMeshO::FaceIterator it;
447 for (it = m.cm.face.begin(); it != m.cm.face.end(); ++it)
448 {
449 if (it->IsS())
450 selectedFaces.push_back(&*it);
451 }
452
453 }
454
455 // Public Slots
456
edgeSplit()457 void RgbTPlugin::edgeSplit()
458 {
459 if (selectedFaces.size() == 2)
460 {
461 std::list<CMeshO::FacePointer>::iterator it = selectedFaces.begin();
462 CMeshO::FacePointer f0 = *it;
463 (*it)->ClearS();
464 ++it;
465 (*it)->ClearS();
466 CMeshO::FacePointer f1 = *it;
467
468 typedef EdgeFIType EdgeFIType;
469 EdgeFIType e;
470 if (commonEdge(f0,f1,&e))
471 {
472 RgbTriangleC t = RgbTriangleC(m->cm,*rgbInfo,e.fp->Index());
473 RgbPrimitives::recursiveEdgeSplit(t,e.i,*to);
474 }
475 }
476 else if (selectedFaces.size() == 1)
477 {
478 std::list<CMeshO::FacePointer>::iterator it = selectedFaces.begin();
479 CMeshO::FacePointer f = *it;
480 (*it)->ClearS();
481
482 RgbTriangleC t = RgbTriangleC(&m->cm,rgbInfo,f->Index());
483
484 for(int i = 0; i < 3; i++)
485 {
486 PointType p;
487 PointType p1, p2;
488 p1 = (t.V(i).vert().P());
489 p2 = (t.V((i+1)%3).vert().P());
490
491 for (int i2 = 0; i2 < 3; ++i2)
492 {
493 p[i2] = (p1[i2] + p2[i2]) / 2;
494 }
495
496 if (t.getEdgeIsBorder(i))
497 {
498 RgbPrimitives::recursiveEdgeSplit(t,i,*to);
499 }
500
501 }
502
503 }
504
505 selectedFaces.clear();
506 current_gla->update();
507 }
508
vertexRemoval()509 void RgbTPlugin::vertexRemoval()
510 {
511 if (selectedFaces.size() > 2)
512 {
513 std::list<FacePointer>::iterator it = selectedFaces.begin();
514 std::list<FacePointer>::iterator end = selectedFaces.end();
515 vector<FacePointer> sf;
516 while(it != end)
517 {
518 sf.push_back(*it);
519 ++it;
520 }
521
522 EdgeFIType e;
523 if (commonVertex(sf,&e))
524 {
525 RgbTriangleC t = RgbTriangleC(m->cm,*rgbInfo,e.fp->Index());
526 RgbPrimitives::vertexRemoval(t,e.i,*to);
527 }
528 }
529 else if (selectedFaces.size() == 1)
530 {
531 std::list<CMeshO::FacePointer>::iterator it = selectedFaces.begin();
532 CMeshO::FacePointer f = *it;
533 (*it)->ClearS();
534
535 RgbTriangleC t = RgbTriangleC(&m->cm,rgbInfo,f->Index());
536
537 for(int i = 0; i < 3; i++)
538 {
539 if (t.getVertexIsBorder(i))
540 {
541 if (RgbPrimitives::vertexRemoval_Possible(t,i))
542 {
543 RgbPrimitives::vertexRemoval(t,i,*to);
544 break;
545 }
546
547 }
548
549 }
550
551 }
552 selectedFaces.clear();
553 current_gla->update();
554 }
555
pickEdgeLenght(double & d)556 bool RgbTPlugin::pickEdgeLenght(double& d)
557 {
558 if (selectedFaces.size() == 2)
559 {
560 std::list<CMeshO::FacePointer>::iterator it = selectedFaces.begin();
561 CMeshO::FacePointer f0 = *it;
562 ++it;
563 CMeshO::FacePointer f1 = *it;
564
565 typedef EdgeFIType EdgeFIType;
566 EdgeFIType e;
567 if (commonEdge(f0,f1,&e))
568 {
569 Point3f v1 = e.fp->V(e.i)->P();
570 Point3f v2 = e.fp->V((e.i+1)%3)->P();
571
572 d = (v2 - v1).Norm();
573
574 return true;
575 }
576
577 return false;
578 }
579 else
580 return false;
581 }
582
commonEdge(CMeshO::FacePointer fp1,CMeshO::FacePointer fp2,EdgeFIType * edge)583 bool RgbTPlugin::commonEdge(CMeshO::FacePointer fp1, CMeshO::FacePointer fp2, EdgeFIType* edge)
584 {
585 assert(fp1);
586 assert(fp2);
587
588 for (int i = 0; i < 3; ++i) {
589 if (fp1->FFp(i) == fp2)
590 {
591 if (edge)
592 *edge = EdgeFIType(fp1,i);
593 return true;
594 }
595 }
596 return false;
597 }
598
commonVertex(vector<FacePointer> fc,EdgeFIType * vert)599 bool RgbTPlugin::commonVertex(vector<FacePointer> fc, EdgeFIType* vert)
600 {
601 if (fc.size() < 2)
602 return false;
603
604 FacePointer f = fc[0];
605
606 for (int i = 0; i < 3; ++i)
607 {
608 VertexPointer v = f->V(i);
609 vector<FacePointer>::iterator it = fc.begin();
610 vector<FacePointer>::iterator end = fc.end();
611 ++it; // skip the first
612 bool isCommon = true;
613 for (; it != end; ++it)
614 {
615 bool isInTriangle = false;
616 for (int j = 0; j < 3; ++j)
617 {
618
619 if ((*it)->V(j) == v)
620 isInTriangle = true;
621 }
622 if (!isInTriangle)
623 isCommon = false;
624
625 }
626
627 if (isCommon)
628 {
629 if(vert)
630 {
631 vert->fp = f;
632 vert->i = i;
633 }
634 return true;
635 }
636 }
637
638 return false;
639 }
640
641 }
642
643