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