1 /****************************************************************************
2  * MeshLab                                                           o o     *
3  * A versatile mesh processing toolbox                             o     o   *
4  *                                                                _   O  _   *
5  * Copyright(C) 2008                                                \/)\/    *
6  * Visual Computing Lab                                            /\/|      *
7  * ISTI - Italian National Research Council                           |      *
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 /****************************************************************************
24   History
25 $Log: edit_topo.cpp,v $
26 ****************************************************************************/
27 #include "edit_topo.h"
28 
29 #include <vcg/complex/algorithms/point_sampling.h>
30 #include <vcg/complex/algorithms/create/resampler.h>
31 #include <vcg/simplex/face/distance.h>
32 
33 using namespace std;
34 using namespace vcg;
35 //
36 // --- "Edit plugin" specific methods ---
37 //
38 
39 
40 
41 //
42 //	Edit plugin constructor
43 //
edit_topo()44 edit_topo::edit_topo()
45 {
46 	edit_topodialogobj=0;
47 	reDraw = false;
48 	click = false;
49 	first_model_generated=false;
50 
51 	nameVtxCount = 0;
52 	stack.clear();
53 	Estack.clear();
54 
55 	drag_click=false;
56 	drag_stack.clear();
57 
58 	lastPoint.V = Point3f(0,0,0);
59 	lastPoint.vName = "--";
60 
61 	connectStart.V = Point3f(0,0,0);
62 	connectStart.vName = "--";
63 	connectEnd.V = Point3f(0,0,0);
64 	connectEnd.vName = "--";
65 }
66 
67 //
68 //	Edit plugin destructor
69 //
~edit_topo()70 edit_topo::~edit_topo()
71 {
72 	stack.clear();
73 	Estack.clear();
74 	Fstack.clear();
75 
76 
77 	if (edit_topodialogobj != 0)
78 	{
79 		delete edit_topodialogobj;
80 		edit_topodialogobj = 0;
81 	}
82 
83 }
84 
Info()85 const QString edit_topo::Info()
86 {
87   return tr("Allow to re-top a model");
88 }
89 
90 /************************************************************************************/
91 //
92 // -- Edit topology Methods:
93 //		Those methods are used by the plugin to edit
94 //		the new topology defined by the user
95 //
96 //		All of the methods here are directly used to build
97 //		the base topology mesh as defined by the user
98 //
99 
100 //
101 //	Adds a vertex to the new topo vertices list
102 //		The new vertex will be selected from one of the existing mesh
103 //
editAddVertex(MeshModel & m)104 void edit_topo::editAddVertex(MeshModel &m)
105 {
106 	CVertexO * temp_vert=0;
107 	if (getVertexAtMouse(m, temp_vert))
108 	{
109 		if(temp_vert->P() != lastPoint.V)
110 		{
111 			Vtx temp;
112 			temp.V = temp_vert->P();
113 			temp.vName = QString("V%1").arg(nameVtxCount++);
114 
115 			bool contained = false;
116 			for(int i=0; i<stack.count(); i++)
117 			{
118 				Vtx at = stack.at(i);
119 				if(at.V==temp.V)
120 					contained = true;
121 			}
122 			if(!contained)
123 			{
124 				stack.push_back(temp);
125 				lastPoint = temp;
126 				edit_topodialogobj->updateVtxTable(stack);
127 			}
128 			else nameVtxCount--;
129 		}
130 	}
131 }
132 
133 //
134 //	Adds a vertex to the new topo vertices list
135 //		The new vertex is freely selected over the existing mesh
136 //
editAddVertexFree()137 void edit_topo::editAddVertexFree()
138 {
139 	Point3f temp_vert;
140 	if (Pick(mousePos.x(), mouseRealY, temp_vert))
141 	{
142 		if(temp_vert != lastPoint.V)
143 		{
144 			Vtx temp;
145 			temp.V = temp_vert;
146 			temp.vName = QString("V%1").arg(nameVtxCount++);
147 
148 			bool contained = false;
149 			for(int i=0; i<stack.count(); i++)
150 			{
151 				Vtx at = stack.at(i);
152 				if(at.V==temp.V)
153 					contained = true;
154 			}
155 
156 			if(!contained)
157 			{
158 				stack.push_back(temp);
159 				lastPoint = temp;
160 				edit_topodialogobj->updateVtxTable(stack);
161 			}
162 			else nameVtxCount--;
163 		}
164 	}
165 }
166 
167 //
168 //	Removes a vertex from the new topo vertices list
169 //		The operation will affect also Edges and Faces lists
170 //
editDeleteVertex()171 void edit_topo::editDeleteVertex()
172 {
173 	Vtx vtx;
174 	if(getVisibleVertexNearestToMouse(stack, vtx))
175 	{
176 		// Remove vertex from Vert list
177 		for(int i=0; i<stack.count(); i++)
178 			if(stack.at(i) == vtx)
179 			{
180 				stack.removeAt(i);
181 				edit_topodialogobj->updateVtxTable(stack);
182 			}
183 
184 		int EtoDel = 0;
185 		int FtoDel = 0;
186 
187 		// And delete all the edges and faces where this vertex is present
188 		for(int e=0; e<Estack.count(); e++)
189 			if(Estack.at(e).containsVtx(vtx))
190 				EtoDel++;
191 		for(int e=0; e<Fstack.count(); e++)
192 			if(Fstack.at(e).containsVtx(vtx))
193 				FtoDel++;
194 
195 		for(int i=0; i<EtoDel; i++)
196 		{	bool del = false;
197 			for(int e=0; e<Estack.count(); e++)
198 				if((Estack.at(e).containsVtx(vtx))&&(!del))
199 				{
200 					Estack.removeAt(e);
201 					edit_topodialogobj->updateEdgTable(Estack);
202 					del = true;
203 				}}
204 
205 		for(int i=0; i<FtoDel; i++)
206 		{	bool del = false;
207 			for(int f=0; f<Fstack.count(); f++)
208 				if((Fstack.at(f).containsVtx(vtx))&&(!del))
209 				{
210 					Fstack.removeAt(f);
211 					edit_topodialogobj->updateFceTable(Fstack);
212 					del = true;
213 				}}
214 			if(stack.count()==0)
215 				nameVtxCount = 0;
216 		}
217 }
218 
219 //
220 //	Connects two vertices and creates a new edge
221 //		The operation will also create a new face in the faces list
222 //		if the selected edge is connected to other two edges
223 //
editConnectVertex()224 void edit_topo::editConnectVertex()
225 {
226 	if(connectStart.V==Point3f(0,0,0))
227 	{
228 		Vtx vtx;
229 		// First click
230 		if(getVisibleVertexNearestToMouse(stack, vtx))
231 		{
232 			connectStart.V = vtx.V;
233 			connectStart.vName = vtx.vName;
234 		}
235 	}
236 	else
237 	{
238 		Vtx vtx;
239 		// Second click (insert the edge in the Ed. list)
240 		if(getVisibleVertexNearestToMouse(stack, vtx))
241 		if(vtx.V != connectStart.V)
242 		{
243 			connectEnd.V = vtx.V;
244 			connectEnd.vName = vtx.vName;
245 			Edg added;
246 			added.v[0] = connectStart;
247 			added.v[1] = connectEnd;
248 
249 			if(!Estack.contains(added))
250 			{
251 				Estack.push_back(added);
252 				edit_topodialogobj->updateEdgTable(Estack);
253 
254 				QList<Edg> endStack;
255 				QList<Edg> staStack;
256 				Edg _3rd;
257 
258 				//--> Check if the "just now" selected edge is connected to others. Then, create a new face
259 				for(int i=0; i<Estack.count(); i++)
260 				{
261 					Edg ed = Estack.at(i);
262 					if(ed != added)
263 					{
264 						if((ed.v[0] == connectEnd)||(ed.v[1] == connectEnd))
265 							endStack.push_back(ed);
266 						if((ed.v[0] == connectStart)||(ed.v[1] == connectStart))
267 							staStack.push_back(ed);
268 					}
269 				}
270 				for(int i=0; i<endStack.count(); i++)
271 				{
272 					Vtx nextEnd;
273 					Edg edgEnd = endStack.at(i);
274 
275 					if(edgEnd.v[0] == connectEnd)
276 						nextEnd = edgEnd.v[1];
277 					if(edgEnd.v[1] == connectEnd)
278 						nextEnd = edgEnd.v[0];
279 
280 					for(int j=0; j<staStack.count(); j++)
281 					{
282 						Vtx nextSta;
283 						Edg edgSta = staStack.at(j);
284 
285 						if(edgSta.v[0] == connectStart)
286 							nextSta = edgSta.v[1];
287 						if(edgSta.v[1] == connectStart)
288 							nextSta = edgSta.v[0];
289 
290 						if(nextSta == nextEnd)
291 						{
292 							Fce toAdd;
293 							toAdd.e[0] = added;
294 							toAdd.e[1] = edgSta;
295 							toAdd.e[2] = edgEnd;
296 							toAdd.selected = true;
297 
298 							if(!Fstack.contains(toAdd))
299 							{
300 								Fstack.push_back(toAdd);
301 
302 								QList<QString> vNames;
303 								for(int n=0; n<3; n++)
304 									for(int m=0; m<2; m++)
305 										if(!vNames.contains(toAdd.e[n].v[m].vName))
306 											vNames.push_back(toAdd.e[n].v[m].vName);
307 								edit_topodialogobj->updateFceTable(Fstack);
308 							}
309 						}
310 					}
311 				}
312 
313 				connectStart.V = Point3f(0,0,0);
314 				connectStart.vName = "00";
315 			}
316 			connectEnd.V = Point3f(0,0,0);
317 			connectEnd.vName = "00";
318 		}
319 	}
320 }
321 
322 
323 //
324 //	Selects or deselects the face selected by the user
325 //
editSelectFace()326 void edit_topo::editSelectFace()
327 {
328 	Fce nearest;
329 	bool got = false;
330 	double tx,ty,tz;
331 	int at = 0;
332 	for(int f=0; f<Fstack.count(); f++)
333 	{
334 		Fce fc = Fstack.at(f);
335 
336 		QList<Vtx> allv;
337 		for(int e=0; e<3; e++)
338 			for(int v=0; v<2; v++)
339 				if(!allv.contains(fc.e[e].v[v]))
340 					allv.push_back(fc.e[e].v[v]);
341 
342 		gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
343 		QPointF p0 = QPointF(tx, ty);
344 		gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
345 		QPointF p1 = QPointF(tx, ty);
346 		gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
347 		QPointF p2 = QPointF(tx, ty);
348 
349 		QPoint p = QPoint(mousePos.x(), mouseRealY);
350 
351 		if(pointInTriangle(p, p0, p1, p2))
352 		{
353 			nearest = fc;
354 			got = true;
355 			at = f;
356 		}
357 	}
358 	if(got)
359 	{
360 		Fstack.removeAt(at);
361 		nearest.selected=!nearest.selected;
362 		Fstack.push_back(nearest);
363 	}
364 }
365 
366 //
367 //	Removes an edge from the edge's list
368 //		The operation will also remove each face using that
369 //		edge (if present), but will not remove any vertex
370 //
editDeconnectEdge()371 void edit_topo::editDeconnectEdge()
372 {
373 	Edg minE;
374 	// Remove the edge from his stack, and also from the faces stack
375 	if(getVisibleEdgeNearestToMouse(Estack, minE))
376 	{
377 		for(int at=0; at<Estack.count(); at++)
378 			if(Estack.at(at)==minE)
379 				Estack.removeAt(at);
380 
381 		int toDel = 0;
382 		for(int f=0; f<Fstack.count(); f++)
383 			if(Fstack.at(f).containsEdg(minE))
384 				toDel++;
385 
386 		for(int i=0; i<toDel; i++)
387 		{	bool del = false;
388 			for(int f=0; f<Fstack.count(); f++)
389 				if((Fstack.at(f).containsEdg(minE))&&(!del))
390 				{
391 					Fstack.removeAt(f);
392 					del = true;
393 				}}
394 			edit_topodialogobj->updateVtxTable(stack);
395 			edit_topodialogobj->updateFceTable(Fstack);
396 			edit_topodialogobj->updateEdgTable(Estack);
397 		}
398 }
399 
400 
401 //
402 //	Manage the drag&drop process used to move a vertex to a new
403 //		position as selected with mouse
404 //		The method will delete old vertex and insert a new vertex,
405 //		and also adjourn each edge/face that is using it
406 //
editDragAndDropVertex()407 void edit_topo::editDragAndDropVertex()
408 {
409 	drag_stack.clear();
410 	if(!drag_click)
411 	{
412 		// First click: select vertex
413 		drag_click = true;
414 
415 		Vtx vtx;
416 		if(getVisibleVertexNearestToMouse(stack, vtx))
417 		{
418 			drag_vtx = vtx;
419 
420 			for(int f=0; f<Fstack.count(); f++)
421 			{
422 				Fce fc = Fstack.at(f);
423 				if(fc.containsVtx(vtx))
424 					drag_stack.push_back(fc);
425 			}
426 		}
427 		else
428 			drag_click = false;
429 	}
430 	else
431 	{
432 		// second click: new vertex position
433 		drag_click = false;
434 
435 		// Get new vertex coords
436 		Point3f temp_vert;
437 		if (Pick(mousePos.x(), mouseRealY, temp_vert))
438 		{
439 			// remove the old vertex
440 			Vtx newV;
441 			newV.V = temp_vert;
442 			newV.vName = drag_vtx.vName;
443 			for(int v=0; v<stack.count(); v++)
444 				if(stack.at(v)==drag_vtx)
445 					stack.removeAt(v);
446 
447 			// add the new vertex
448 			stack.push_back(newV);
449 
450 			// count the number of edges involved
451 			int edgToRemove=0;
452 			for(int e=0; e<Estack.count(); e++)
453 				if(Estack.at(e).containsVtx(drag_vtx))
454 					edgToRemove++;
455 
456 			// edit each edge
457 			for(int i=0; i<edgToRemove; i++)
458 				for(int e=0; e<Estack.count(); e++)
459 					if(Estack.at(e).containsVtx(drag_vtx))
460 					{
461 						Edg newE = Estack.at(e);
462 						if(newE.v[0].V==drag_vtx.V)
463 							newE.v[0]=newV;
464 						if(newE.v[1].V==drag_vtx.V)
465 							newE.v[1]=newV;
466 						Estack.removeAt(e);
467 						Estack.push_back(newE);
468 					}
469 
470 			// count faces number
471 			int fceToRemove=0;
472 			for(int f=0; f<Fstack.count(); f++)
473 				if(Fstack.at(f).containsVtx(drag_vtx))
474 					fceToRemove++;
475 
476 			// update faces with new vertex and edges
477 			for(int i=0; i<fceToRemove; i++)
478 				for(int f=0; f<Fstack.count(); f++)
479 					if(Fstack.at(f).containsVtx(drag_vtx))
480 					{
481 						Fce newF = Fstack.at(f);
482 						for(int e=0; e<3; e++)
483 							for(int v=0; v<2; v++)
484 								if(newF.e[e].v[v].V == drag_vtx.V)
485 									newF.e[e].v[v] = newV;
486 						Fstack.removeAt(f);
487 						Fstack.push_back(newF);
488 					}
489 
490 			edit_topodialogobj->updateVtxTable(stack);
491 			edit_topodialogobj->updateFceTable(Fstack);
492 			edit_topodialogobj->updateEdgTable(Estack);
493 
494 		/* Uncomment this if you want the mesh to be auto-recreated
495 			if(first_model_generated)
496 				on_mesh_create();*/
497 		}
498 	}
499 }
500 
501 
502 //
503 //	Split an edge on its mid point
504 //		The process will remove the original edge and add two new
505 //		faces. This will also add a new vertex and create (eventually)
506 //		two new faces.
507 //
editEdgeSplit()508 void edit_topo::editEdgeSplit()
509 {
510 	Edg minE;
511 	if(getVisibleEdgeNearestToMouse(Estack, minE))
512 	{
513 		Vtx newVtx;
514 		Point3f new3f;
515 
516 		double tx,ty,tz;
517 		gluProject(minE.v[0].V.X(),minE.v[0].V.Y(),minE.v[0].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
518 		QPointF p0 = QPointF(tx, ty);
519 		gluProject(minE.v[1].V.X(),minE.v[1].V.Y(),minE.v[1].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
520 		QPointF p1 = QPointF(tx, ty);
521 
522 		QPointF Qmid = (p1 + p0)/2;
523 
524 		if(Pick(Qmid.x(), Qmid.y(), new3f))
525 		{
526 			newVtx.V = new3f;
527 			newVtx.vName = QString("V%1").arg(nameVtxCount++);
528 
529 			int fCount = 0;
530 			for(int f=0; f<Fstack.count(); f++)
531 				if(Fstack.at(f).containsEdg(minE))
532 					fCount++;
533 
534 			for(int i=0; i<fCount; i++)
535 			{
536 				bool found=false;
537 				for(int f=0; ((f<Fstack.count())&&(!found)); f++)
538 				{
539 					Fce fc = Fstack.at(f);
540 					if(fc.containsEdg(minE))
541 					{
542 						Fce newF1 = fc;
543 						Fce newF2 = fc;
544 
545 						Vtx oldV1 = minE.v[0];
546 						Vtx oldV2 = minE.v[1];
547 
548 						// Edit new face 01 and 02
549 						for(int e=0; e<3; e++)
550 							for(int v=0; v<2; v++)
551 							{
552 								if(newF1.e[e].v[v]==oldV1)
553 									newF1.e[e].v[v]=newVtx;
554 								if(newF2.e[e].v[v]==oldV2)
555 									newF2.e[e].v[v]=newVtx;
556 							}
557 
558 						Edg newEdgMid;
559 						QList<Vtx> allv;
560 						for(int e=0; e<3; e++)
561 							for(int v=0; v<2; v++)
562 								if(!allv.contains(fc.e[e].v[v]))
563 									allv.push_back(fc.e[e].v[v]);
564 
565 						Vtx oldVtx;
566 						for(int i=0; i<3; i++)
567 							if((allv.at(i)!=oldV1)&&(allv.at(i)!=oldV2))
568 								oldVtx=allv.at(i);
569 
570 						newEdgMid.v[0]=oldVtx;
571 						newEdgMid.v[1]=newVtx;
572 
573 						Estack.push_back(newEdgMid);
574 						Fstack.removeAt(f);
575 						Fstack.push_back(newF1);
576 						Fstack.push_back(newF2);
577 
578 						found = true;
579 					}
580 				}
581 			}
582 
583 			Edg newEdg1 = minE;
584 			Edg newEdg2 = minE;
585 
586 			newEdg1.v[0] = newVtx;
587 			newEdg2.v[1] = newVtx;
588 
589 			for(int e=0; e<Estack.count(); e++)
590 				if(Estack.at(e)==minE)
591 					Estack.removeAt(e);
592 
593 			Estack.push_back(newEdg1);
594 			Estack.push_back(newEdg2);
595 
596 			stack.push_back(newVtx);
597 
598 			edit_topodialogobj->updateVtxTable(stack);
599 			edit_topodialogobj->updateFceTable(Fstack);
600 			edit_topodialogobj->updateEdgTable(Estack);
601 		}
602 	}
603 }
604 
605 //
606 //	Collapse an edge over its mid point
607 //		This will also remove faces using the old edge
608 //
editEdgeCollapse()609 void edit_topo::editEdgeCollapse()
610 {
611 	Edg toColl;
612 	if(getVisibleEdgeNearestToMouse(Estack, toColl))
613 	{
614 		Vtx oldVtx1 = toColl.v[0];
615 		Vtx oldVtx2 = toColl.v[1];
616 
617 		Vtx newVtx;
618 		Point3f new3f;
619 
620 		double tx,ty,tz;
621 		gluProject(oldVtx1.V.X(),oldVtx1.V.Y(),oldVtx1.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
622 		QPointF p0 = QPointF(tx, ty);
623 		gluProject(oldVtx2.V.X(),oldVtx2.V.Y(),oldVtx2.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
624 		QPointF p1 = QPointF(tx, ty);
625 
626 		QPointF Qmid = (p1 + p0)/2;
627 
628 		if(Pick(Qmid.x(), Qmid.y(), new3f))
629 		{
630 			newVtx.V = new3f;
631 			newVtx.vName = QString("V%1").arg(nameVtxCount++);
632 
633 			// Remove faces containing the coll edge
634 			int times = 0;
635 			for(int f=0; f<Fstack.count(); f++)
636 				if(Fstack.at(f).containsEdg(toColl))
637 					times++;
638 
639 			for(int i=0; i<times; i++)
640 				for(int f=0; f<Fstack.count(); f++)
641 					if(Fstack.at(f).containsEdg(toColl))
642 						Fstack.removeAt(f);
643 
644 			// Update faces stack with the new vertex
645 			times = 0;
646 			for(int f=0; f<Fstack.count(); f++)
647 				if(Fstack.at(f).containsVtx(oldVtx1)||Fstack.at(f).containsVtx(oldVtx2))
648 					times++;
649 
650 			for(int i=0; i<times; i++)
651 				for(int f=0; f<Fstack.count(); f++)
652 					if(Fstack.at(f).containsVtx(oldVtx1)||Fstack.at(f).containsVtx(oldVtx2))
653 					{
654 						Fce fc = Fstack.at(f);
655 						for(int e=0; e<3; e++)
656 							for(int v=0; v<2; v++)
657 								if((fc.e[e].v[v]==oldVtx1)||(fc.e[e].v[v]==oldVtx2))
658 									fc.e[e].v[v] = newVtx;
659 
660 						Fstack.removeAt(f);
661 						Fstack.push_back(fc);
662 					}
663 
664 			// Update edges stack
665 			times = 0;
666 			for(int e=0; e<Estack.count(); e++)
667 				if(Estack.at(e).containsVtx(oldVtx1)||Estack.at(e).containsVtx(oldVtx2))
668 					times++;
669 
670 			for(int i=0; i<times; i++)
671 				for(int e=0; e<Estack.count(); e++)
672 					if(Estack.at(e).containsVtx(oldVtx1)||Estack.at(e).containsVtx(oldVtx2))
673 					{
674 						Edg ed = Estack.at(e);
675 						for(int v=0; v<2; v++)
676 							if((ed.v[v]==oldVtx1)||(ed.v[v]==oldVtx2))
677 								ed.v[v]=newVtx;
678 						Estack.removeAt(e);
679 						if(!Estack.contains(ed))
680 							if(ed.v[0]!=ed.v[1])
681 								Estack.push_back(ed);
682 					}
683 
684 			// Update vtx stack;
685 			for(int i=0; i<2; i++)
686 				for(int v=0; v<stack.count(); v++)
687 					if((stack.at(v)==oldVtx1)||(stack.at(v)==oldVtx2))
688 						stack.removeAt(v);
689 			stack.push_back(newVtx);
690 
691 			edit_topodialogobj->updateVtxTable(stack);
692 			edit_topodialogobj->updateFceTable(Fstack);
693 			edit_topodialogobj->updateEdgTable(Estack);
694 		}
695 	}
696 }
697 
698 
699 
700 
701 /************************************************************************************/
702 //
703 // -- Decoration Plugin methods
704 //			Those methods are used by the plugin to draw decorations
705 //			on each plugin's user states
706 //
707 //			Each method declared here is used only in decorations functions,
708 //			so, each method here will be called by the Decorate() func
709 
710 
711 //
712 //	Standard decoration mode
713 //		Draws points and edges as defined by the user.
714 //		And, also, vertices labels
715 //
editDecoStandard(MeshModel & m)716 void edit_topo::editDecoStandard(MeshModel &m)
717 {
718 	if(stack.count()!=0)
719 		drawPoint(m, 3.0f, Color4b::Red, stack);
720 
721 	if(stack.count()!=0)
722 		drawLabel(stack);
723 
724 	if(Estack.count()!=0)
725 	{
726 		for(int i=0; i<Estack.count(); i++)
727 		{
728 			Edg e = Estack.at(i);
729 			Vtx p1 = e.v[0];
730 			Vtx p2 = e.v[1];
731 
732 			drawLine(Color4b::Blue, Color4b::Black, p1.V, p2.V);
733 		}
734 	}
735 }
736 
737 //
738 //	Only vertices deco mode
739 //		Draws only vertices and labels, but not edges
740 //
editDecoOnlyVertex(MeshModel & m)741 void edit_topo::editDecoOnlyVertex(MeshModel &m)
742 {
743 	if(stack.count()!=0)
744 		drawPoint(m, 3.0f, Color4b::Red, stack);
745 
746 	if(stack.count()!=0)
747 		drawLabel(stack);
748 }
749 
750 //
751 //	Drag and drop mode decorations
752 //		Before click: standard vertex selection pointer (yellow)
753 //		After select: draw each new edge with yellow lines
754 //
editDecoDragAndDropVertex(MeshModel & m)755 void edit_topo::editDecoDragAndDropVertex(MeshModel &m)
756 {
757 	if(drag_click)
758 	{
759 		Point3f pmouse;
760 		if(Pick(mousePos.x(), mouseRealY, pmouse))
761 		{
762 			for(int i=0; i<drag_stack.count(); i++)
763 			{
764 				Fce fc = drag_stack.at(i);
765 
766 				QList<Vtx> allv;
767 				for(int e=0; e<3; e++)
768 					for(int v=0; v<2; v++)
769 						if(!allv.contains(fc.e[e].v[v]))
770 							allv.push_back(fc.e[e].v[v]);
771 
772 				QVector<Vtx> v = allv.toVector();
773 
774 				for(int i=0; i<3; i++)
775 					if(v[i] == drag_vtx)
776 						v[i].V = pmouse;
777 
778 				drawLine(Color4b::Yellow, Color4b::Yellow, v[0].V, v[1].V);
779 				drawLine(Color4b::Yellow, Color4b::Yellow, v[1].V, v[2].V);
780 				drawLine(Color4b::Yellow, Color4b::Yellow, v[2].V, v[0].V);
781 			}
782 		}
783 	}
784 	else
785 	{
786 		Vtx vtx;
787 		if(getVisibleVertexNearestToMouse(stack, vtx))
788 			drawPoint(m, 4.0f, Color4b::Yellow, vtx.V);
789 
790 	}
791 }
792 
793 //
794 //	Face selection decoration mode
795 //		Draws each face (no vertices, no labels) in blue,
796 //		and the face nearest to the mouse in yellow (and, so,
797 //		face will be selectable)
798 //
799 //	This method will also draw the "auto" elaborated vertices
800 //	as defined by the edit topo algorithm
801 //
editDecoFaceSelect(MeshModel & m)802 void edit_topo::editDecoFaceSelect(MeshModel &m)
803 {
804 	// Draw auto-generated new mesh vertices
805 	if(out.count()!=0)
806 	{
807 		for(int i=0; i<out.count(); i++)
808 			drawPoint(m, 2.0f, Color4b::Yellow, out.at(i));
809 	}
810 
811 	// Draw selected faces in blue, non selected in black, and mouse nearest in yellow
812 	if(Fstack.count()!=0)
813 	{
814 		bool got = false;
815 		Fce nearest;
816 		for(int i=0; i<Fstack.count(); i++)
817 		{
818 			Fce f = Fstack.at(i);
819 
820 			QList<Vtx> allv;
821 			for(int e=0; e<3; e++)
822 				for(int v=0; v<2; v++)
823 					if(!allv.contains(f.e[e].v[v]))
824 						allv.push_back(f.e[e].v[v]);
825 
826 			if(f.selected)
827 			{
828 				drawLine(Color4b::Blue, Color4b::Black, allv.at(0).V, allv.at(1).V);
829 				drawLine(Color4b::Blue, Color4b::Black, allv.at(1).V, allv.at(2).V);
830 				drawLine(Color4b::Blue, Color4b::Black, allv.at(2).V, allv.at(0).V);
831 
832 				Point3f mid = (allv.at(0).V + allv.at(1).V + allv.at(2).V) / 3;
833 				if(isVertexVisible(allv.at(0).V)&&isVertexVisible(allv.at(1).V)&&isVertexVisible(allv.at(2).V))
834 					drawPoint(m, 5.0f, Color4b::Green, mid);
835 			}
836 			else
837 			{
838 				drawLine(Color4b::DarkRed, Color4b::Black, allv.at(0).V, allv.at(1).V);
839 				drawLine(Color4b::DarkRed, Color4b::Black, allv.at(1).V, allv.at(2).V);
840 				drawLine(Color4b::DarkRed, Color4b::Black, allv.at(2).V, allv.at(0).V);
841 			}
842 		}
843 
844 		double tx,ty,tz;
845 		for(int f=0; f<Fstack.count(); f++)
846 		{
847 			Fce fc = Fstack.at(f);
848 
849 			QList<Vtx> allv;
850 			for(int e=0; e<3; e++)
851 				for(int v=0; v<2; v++)
852 					if(!allv.contains(fc.e[e].v[v]))
853 						allv.push_back(fc.e[e].v[v]);
854 
855 			gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
856 			QPointF p0 = QPointF(tx, ty);
857 			gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
858 			QPointF p1 = QPointF(tx, ty);
859 			gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
860 			QPointF p2 = QPointF(tx, ty);
861 
862 			QPoint p = QPoint(mousePos.x(), mouseRealY);
863 
864 			if(pointInTriangle(p, p0, p1, p2))
865 			{
866 				nearest = fc;
867 				got = true;
868 			}
869 		}
870 		if(got)
871 		{
872 			QList<Vtx> allv;
873 			for(int e=0; e<3; e++)
874 				for(int v=0; v<2; v++)
875 					if(!allv.contains(nearest.e[e].v[v]))
876 						allv.push_back(nearest.e[e].v[v]);
877 
878 			drawLine(Color4b::Yellow, Color4b::Red, allv.at(0).V, allv.at(1).V);
879 			drawLine(Color4b::Yellow, Color4b::Red, allv.at(1).V, allv.at(2).V);
880 			drawLine(Color4b::Yellow, Color4b::Red, allv.at(2).V, allv.at(0).V);
881 		}
882 	}
883 }
884 
885 //
886 //	Vertex selection decoration
887 //		Draws in yellow the selectable vertex (the selectable vertex is the nearest to the mouse)
888 //
editDecoVertexSelect(MeshModel & m)889 void edit_topo::editDecoVertexSelect(MeshModel &m)
890 {
891 	Point3f p = Point3f(0,0,0);
892 
893 	glPushMatrix();
894 	glMultMatrix(m.cm.Tr);
895 
896 	CVertexO * temp_vert=0;
897 	if (getVertexAtMouse(m, temp_vert))
898 	{
899 		cursorPoint = temp_vert->P();
900 		drawPoint(m, 4.0f, Color4b::Yellow, cursorPoint);
901 	}
902 }
903 
904 //
905 //	Vertex deletion decoration
906 //		Draws in yellow the deletable vertex (the deletable vertex is the nearest to the mouse)
907 //
editDecoDeleteVertexSelect(MeshModel & m)908 void edit_topo::editDecoDeleteVertexSelect(MeshModel &m)
909 {
910 	Vtx vtx;
911 	if(getVisibleVertexNearestToMouse(stack, vtx))
912 		drawPoint(m, 4.0f, Color4b::Green, vtx.V);
913 }
914 
915 //
916 //	Edge deletion decoration
917 //		Draws in yellow the deletable edge
918 //
editDecoDeleteVertexConnect(MeshModel & m)919 void edit_topo::editDecoDeleteVertexConnect(MeshModel &m)
920 {
921 	if(connectStart.V==Point3f(0,0,0) && connectEnd.V==Point3f(0,0,0))
922 	{
923 		Vtx vtx;
924 		if(getVisibleVertexNearestToMouse(stack, vtx))
925 			drawPoint(m, 4.0f, Color4b::Green, vtx.V);
926 	}
927 
928 	if(connectStart.V!=Point3f(0,0,0) && connectEnd.V==Point3f(0,0,0))
929 	{
930 		drawPoint(m, 4.0f, Color4b::LightBlue, connectStart.V);
931 
932 		Vtx vtx;
933 		if(getVisibleVertexNearestToMouse(stack, vtx))
934 		{
935 			drawPoint(m, 4.0f, Color4b::Green, vtx.V);
936 			drawLine(Color4b::Blue, Color4b::Green, connectStart.V, vtx.V);
937 		}
938 	}
939 }
940 
941 //
942 //	Edge deletion decoration
943 //
editDecoDeleteVertexDeconnect(MeshModel &)944 void edit_topo::editDecoDeleteVertexDeconnect(MeshModel &)
945 {
946 	Edg minE;
947 	if(getVisibleEdgeNearestToMouse(Estack, minE))
948 		drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V);
949 }
950 
951 //
952 //	Split selection decoration
953 //		Draws in yellow the splittable edge
954 //
editDecoSplit(MeshModel &)955 void edit_topo::editDecoSplit(MeshModel &)
956 {
957 	Edg minE;
958 	if(getVisibleEdgeNearestToMouse(Estack, minE))
959 		drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V);
960 }
961 
962 //
963 //	Collapse selection decoration
964 //		Draws in yellow the collapse able edge
965 //
editDecoCollapse(MeshModel &)966 void edit_topo::editDecoCollapse(MeshModel &)
967 {
968 	Edg minE;
969 	if(getVisibleEdgeNearestToMouse(Estack, minE))
970 		drawLine(Color4b::Yellow, Color4b::Green, minE.v[0].V, minE.v[1].V);
971 }
972 
973 //
974 //	Main decoration method
975 //
Decorate(MeshModel & m,GLArea *)976 void edit_topo::Decorate(MeshModel &m, GLArea *)
977 {
978 	updateMatrixes();
979 	// onClick
980 	if(click)
981 	{
982 		click=false;
983 
984 		//---
985 		// Existing vertex selection mode (yellow pointer)
986 		//---
987 		if(edit_topodialogobj->utensil==U_VTX_SEL)
988 			editAddVertex(m);
989 
990 		//---
991 		// Free vertex selection (no pointer)
992 		//---
993 		if(edit_topodialogobj->utensil==U_VTX_SEL_FREE)
994 			editAddVertexFree();
995 
996 		//---
997 		// Remove selected vertex mode (Yellow pointer)
998 		//---
999 		if(edit_topodialogobj->utensil==U_VTX_DEL)
1000 			editDeleteVertex();
1001 
1002 		//---
1003 		// Edge mode (vertex connection)
1004 		//---
1005 		if(edit_topodialogobj->utensil==U_VTX_CONNECT)
1006 			editConnectVertex();
1007 
1008 		//---
1009 		// Face Select/Deselect
1010 		//---
1011 		if(edit_topodialogobj->utensil==U_FCE_SEL)
1012 			editSelectFace();
1013 
1014 		//---
1015 		// edge deselection mode
1016 		//---
1017 		if(edit_topodialogobj->utensil==U_VTX_DE_CONNECT)
1018 			editDeconnectEdge();
1019 
1020 		//---
1021 		// Vertex moove mode
1022 		//---
1023 		if(edit_topodialogobj->utensil==U_DND)
1024 			editDragAndDropVertex();
1025 
1026 		//---
1027 		// edge split mode
1028 		//---
1029 		if(edit_topodialogobj->utensil==U_EDG_SPLIT)
1030 			editEdgeSplit();
1031 
1032 		//---
1033 		// edge collapse mode
1034 		//---
1035 		if(edit_topodialogobj->utensil==U_EDG_COLLAPSE)
1036 			editEdgeCollapse();
1037 	}// end if click
1038 
1039 
1040 	/*** Decorations ***/
1041 
1042 
1043 	//---
1044 	// Even if there's something selected: show edges
1045 	//---
1046 	if((edit_topodialogobj->utensil==U_VTX_CONNECT)||(edit_topodialogobj->utensil==U_VTX_DE_CONNECT)
1047 			||(edit_topodialogobj->utensil==U_DND)||(edit_topodialogobj->utensil==U_EDG_SPLIT)
1048 			||(edit_topodialogobj->utensil==U_EDG_COLLAPSE))
1049 		editDecoStandard(m);
1050 
1051 	//---
1052 	// First step: show only vertices
1053 	//---
1054 	if((edit_topodialogobj->utensil==U_VTX_SEL_FREE)||(edit_topodialogobj->utensil==U_VTX_DEL)
1055 		||(edit_topodialogobj->utensil==U_VTX_SEL))
1056 		editDecoOnlyVertex(m);
1057 
1058 	//---
1059 	// Drag and drop vertices mode
1060 	//---
1061 	if(edit_topodialogobj->utensil==U_DND)
1062 		editDecoDragAndDropVertex(m);
1063 
1064 	//---
1065 	// Face selection mode
1066 	//---
1067 	if(edit_topodialogobj->utensil==U_FCE_SEL)
1068 		editDecoFaceSelect(m);
1069 
1070 	//---
1071 	// Yellow pointer (vertex selection)
1072 	//---
1073 	if(edit_topodialogobj->utensil==U_VTX_SEL)
1074 		editDecoVertexSelect(m);
1075 
1076 	//---
1077 	// Vertex de-selection (Yellow pointeR)
1078 	//---
1079 	if((edit_topodialogobj->utensil==U_VTX_DEL)&&(stack.count()!=0))
1080 		editDecoDeleteVertexSelect(m);
1081 
1082 	//---
1083 	// edge mode (vtx connection)
1084 	//---
1085 	if(edit_topodialogobj->utensil==U_VTX_CONNECT)
1086 		editDecoDeleteVertexConnect(m);
1087 
1088 	//---
1089 	// edge deselection mode
1090 	//---
1091 	if(edit_topodialogobj->utensil==U_VTX_DE_CONNECT)
1092 		editDecoDeleteVertexDeconnect(m);
1093 
1094 	//---
1095 	// edge split mode
1096 	//---
1097 	if(edit_topodialogobj->utensil==U_EDG_SPLIT)
1098 		editDecoSplit(m);
1099 
1100 	//---
1101 	// edge collapse mode
1102 	//---
1103 	if(edit_topodialogobj->utensil==U_EDG_COLLAPSE)
1104 		editDecoCollapse(m);
1105 }
1106 
1107 //
1108 //	Plugin init
1109 //
StartEdit(MeshModel & m,GLArea * gla)1110 bool edit_topo::StartEdit(MeshModel &m, GLArea *gla)
1111 {
1112 	parentGla = gla;
1113 	gla->setCursor(QCursor(QPixmap(":/images/cursor_paint.png"),1,1));
1114 
1115 	// Init uniform grid
1116 	float dist = m.cm.bbox.Diag();
1117 
1118 	// Init data masks
1119 	m.updateDataMask(MeshModel::MM_FACEMARK);
1120 	tri::UpdateNormals<CMeshO>::PerFaceNormalized(m.cm);
1121 	tri::UpdateFlags<CMeshO>::FaceProjection(m.cm);
1122 
1123 	// Init retopology model builder object
1124 	rm.init(&m, dist);
1125 
1126 	// Init miminum visible distance param (used only for labels rendering)
1127 	_md = 0.03;
1128 
1129 	// Init ui
1130 	if (edit_topodialogobj == 0)
1131 	{
1132 		edit_topodialogobj = new edit_topodialog(gla->window());
1133 		dock = new QDockWidget(gla->window());
1134 		dock->setAllowedAreas(Qt::NoDockWidgetArea);
1135 		dock->setWidget(edit_topodialogobj);
1136 		QPoint p = gla->window()->mapToGlobal(QPoint(0,0));
1137 		dock->setGeometry(-5+p.x()+gla->window()->width()-edit_topodialogobj->width(),p.y(),edit_topodialogobj->width(),edit_topodialogobj->height());
1138 		dock->setFloating(true);
1139 	}
1140 	dock->setVisible(true);
1141 	dock->layout()->update();
1142 
1143 	gla->update();
1144 	gla->setMouseTracking(true);
1145 
1146 	// Connect slots
1147 	connect(edit_topodialogobj, SIGNAL( mesh_create() ),
1148           this, SLOT( on_mesh_create() ) );
1149 
1150 	connect(edit_topodialogobj, SIGNAL( update_request() ),
1151           this, SLOT( on_update_request() ) );
1152 	return true;
1153 }
1154 
1155 //
1156 //	End edit
1157 //
EndEdit(MeshModel &,GLArea *)1158 void edit_topo::EndEdit(MeshModel &, GLArea *)
1159 {
1160 	stack.clear();
1161 	Estack.clear();
1162 	Fstack.clear();
1163 
1164 	reDraw = false;
1165 	click = false;
1166 	first_model_generated=false;
1167 
1168 	nameVtxCount = 0;
1169 
1170 	drag_click=false;
1171 	drag_stack.clear();
1172 
1173 	lastPoint.V = Point3f(0,0,0);
1174 	lastPoint.vName = "--";
1175 
1176 	connectStart.V = Point3f(0,0,0);
1177 	connectStart.vName = "--";
1178 	connectEnd.V = Point3f(0,0,0);
1179 	connectEnd.vName = "--";
1180 
1181 	if (edit_topodialogobj != 0)
1182 	{
1183 		delete edit_topodialogobj;
1184 		delete dock;
1185 		edit_topodialogobj = 0;
1186 		dock = 0;
1187 	 }
1188 }
1189 
1190 
1191 /************************************************************************************/
1192 //
1193 // --- Slot implementation methods ---
1194 //		Those two methods are invoked by the gui
1195 //
1196 
1197 //
1198 //	"Create new mesh" click
1199 //		This method calls the retopology algoritm, and creates
1200 //		the new mesh using the user defined new topology
1201 //
on_mesh_create()1202 void edit_topo::on_mesh_create()
1203 {
1204 	out.clear();
1205 
1206 	if(first_model_generated)
1207 		parentGla->meshDoc->meshList.pop_back();
1208 
1209 
1210         MeshModel *mm= parentGla->meshDoc->addNewMesh("");
1211         //parentGla->meshDoc->meshList.push_back(mm);
1212 	first_model_generated = true;
1213 
1214 
1215 	MeshModel *m = parentGla->meshDoc->meshList.back();	// destination = new mesh
1216 	MeshModel *currentMesh  = parentGla->meshDoc->mm();	// source = current	mesh
1217 
1218 	// if debug value is true, the algorithm will respond with all the
1219 	// auto generated vertices.
1220 	// The isDEBUG value is forced by the "Draw auto-filled vertices" gui checkbox
1221 	if(edit_topodialogobj->isDEBUG())
1222 	{
1223 		rm.Lout.clear();
1224     	int iter = edit_topodialogobj->getIterations();
1225 		float dist = edit_topodialogobj->dist()/100;
1226 
1227 		// Retopology algorithm call
1228 		rm.createRefinedMesh(*m, /* *currentMesh,*/ dist, iter, Fstack, stack, edit_topodialogobj, true);
1229 		out = rm.Lout;
1230 	}
1231 	else
1232 	{
1233 		int iter = edit_topodialogobj->getIterations();
1234 		float dist = edit_topodialogobj->dist()/100;
1235 
1236 		// Retopology algorithm call
1237 		rm.createRefinedMesh(*m, /* *currentMesh, */ dist, iter, Fstack, stack, edit_topodialogobj, false);
1238 	}
1239 
1240 	m->cm.Tr = currentMesh->cm.Tr;
1241 	parentGla->update();
1242 }
1243 
1244 
1245 //
1246 //	General update requested by some gui functions
1247 //
on_update_request()1248 void edit_topo::on_update_request()
1249 {
1250 	parentGla->update();
1251 }
1252 
1253 
1254 
1255 
1256 
1257 /************************************************************************************/
1258 //
1259 // --- Plugin events methods ---
1260 //
mousePressEvent(QMouseEvent * event,MeshModel & m,GLArea * gla)1261 void edit_topo::mousePressEvent(QMouseEvent * event, MeshModel &m, GLArea * gla)
1262 {
1263 	mousePos=event->pos();
1264 	click=false;
1265 	gla->update();
1266 }
1267 
mouseMoveEvent(QMouseEvent * event,MeshModel & m,GLArea * gla)1268 void edit_topo::mouseMoveEvent(QMouseEvent * event, MeshModel &m, GLArea * gla)
1269 {
1270 	mousePos=event->pos();
1271 	mouseRealY = gla->curSiz.height() - mousePos.y();
1272 	reDraw=true;
1273 	gla->update();
1274 }
1275 
mouseReleaseEvent(QMouseEvent * event,MeshModel &,GLArea * gla)1276 void edit_topo::mouseReleaseEvent(QMouseEvent * event, MeshModel &, GLArea * gla)
1277 {
1278 	if(event->button() == Qt::LeftButton)
1279 	{
1280 		click=true;
1281 		reDraw=true;
1282 	}
1283 	else if(event->button() == Qt::RightButton)
1284 	{
1285 		connectStart.V=Point3f(0,0,0);
1286 
1287 		drag_stack.clear();
1288 		drag_click = false;
1289 	}
1290 	gla->update();
1291 	mousePos=event->pos();
1292 }
1293 
1294 
1295 /************************************************************************************/
1296 //
1297 // --- New topology mesh methods ---
1298 //			Those methods are used by the edit plugin
1299 //			to elaborate topology related operations
1300 //
1301 
1302 
1303 //
1304 //	Get nearest 2d point of the given array
1305 //	Returns: array index
getNearest(QPointF center,QPointF * points,int num)1306 int edit_topo::getNearest(QPointF center, QPointF *points,int num) {
1307 	int nearestInd=0;
1308 	float dist=fabsf(center.x()-points[0].x())*fabsf(center.x()-points[0].x())+fabsf(center.y()-points[0].y())*fabsf(center.y()-points[0].y());
1309 	for (int lauf=1; lauf<num; lauf++)
1310 	{
1311 		float temp=fabsf(center.x()-points[lauf].x())*fabsf(center.x()-points[lauf].x())+
1312 				fabsf(center.y()-points[lauf].y())*fabsf(center.y()-points[lauf].y());
1313 		if (temp<dist)
1314 		{
1315 				nearestInd=lauf;
1316 				dist=temp;
1317 		}
1318 	}
1319 	return nearestInd;
1320 }
1321 
1322 //
1323 //	Get nearest 3d face over the meshmodel
1324 //	Returns: true if found, and facepointer
getFaceAtMouse(MeshModel & m,CMeshO::FacePointer & val)1325 bool edit_topo::getFaceAtMouse(MeshModel &m, CMeshO::FacePointer& val)
1326 {
1327 	QPoint mid=QPoint(mousePos.x(), mouseRealY);
1328 	return (GLPickTri<CMeshO>::PickNearestFace(mid.x(), mid.y(), m.cm, val,2,2));
1329 }
1330 
1331 //
1332 //	Get existing nearest 3d vertex on the given mesh model
1333 //	Returns: true if found, and vertexpointer value
getVertexAtMouse(MeshModel & m,CMeshO::VertexPointer & value)1334 bool edit_topo::getVertexAtMouse(MeshModel &m,CMeshO::VertexPointer& value)
1335 {
1336 	CFaceO * temp=0;
1337 
1338 	QPoint mid=QPoint(mousePos.x(), mouseRealY);
1339 	double tx,ty,tz;
1340 	if (getFaceAtMouse(m,temp))
1341 	{
1342 		QPointF point[3];
1343 		for (int lauf=0; lauf<3; lauf++)
1344 		{
1345 			gluProject(temp->V(lauf)->P()[0],temp->V(lauf)->P()[1],temp->V(lauf)->P()[2],mvmatrix,projmatrix,viewport,&tx,&ty,&tz);
1346 			point[lauf]=QPointF(tx,ty);
1347 		}
1348 		value=temp->V(getNearest(mid,point,3));
1349 		return true;
1350 	}
1351 	return false;
1352 }
1353 
1354 
1355 //
1356 //	Check if the given vertex is visible on the current user view
1357 //			This method is used for rendering vertices labels, and
1358 //			rendering edges/faces
1359 //	Returns: true if visible
isVertexVisible(Point3f v)1360 bool edit_topo::isVertexVisible(Point3f v)
1361 {
1362 	float   pix;
1363 	double tx,ty,tz;
1364 
1365 	gluProject(v.X(),v.Y(),v.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1366 	glReadPixels(tx,ty,1,1,GL_DEPTH_COMPONENT,GL_FLOAT,&pix);
1367 
1368 	float ff = fabs(tz - pix);
1369 
1370 	return ((ff < 0.003));
1371 }
1372 
1373 //
1374 //	Get visible vertex nearest to mouse position (from a given vertices list)
1375 //	Returns: true if visible
getVisibleVertexNearestToMouse(QList<Vtx> list,Vtx & out)1376 bool edit_topo::getVisibleVertexNearestToMouse(QList<Vtx> list, Vtx &out)
1377 {
1378 	bool found = false;
1379 	double minDist = 100000;
1380 	int minIdx = -1;
1381 	Point3f t;
1382 
1383 	QList<Vtx> visib;
1384 
1385 	for(int i=0; i<list.count(); i++)
1386 		if(isVertexVisible(list.at(i).V))
1387 			visib.push_back(list.at(i));
1388 
1389 	QPoint mPos = QPoint(mousePos.x(), mouseRealY);
1390 	for(int i=0; i<visib.count(); i++)
1391 	{
1392 		Point3f p = visib.at(i).V;
1393 		double tx,ty,tz;
1394 		gluProject(p.X(),p.Y(),p.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1395 
1396 		QPoint qp = QPoint(tx, ty);
1397 
1398 		// faster distance
1399 		//double dx = fabs((double)(qp.x() - mPos.x()));
1400 		//double dy = fabs((double)(qp.y() - mPos.y()));
1401 		//double dist = (dy > dx) ? 0.41*dx+0.941246*dy : 0.41*dy+0.941246*dx;
1402 
1403 		double dist = sqrt((double)(math::Sqr(qp.x() - mPos.x()) + math::Sqr(qp.y() - mPos.y())));
1404 
1405 		if(dist<minDist)
1406 		{
1407 			minDist = dist;
1408 			minIdx = i;
1409 			found = true;
1410 		}
1411 	}
1412 
1413 	if(found)
1414 	{
1415 		for(int j=0; j<list.count(); j++)
1416 			if(list.at(j).vName==visib.at(minIdx).vName)
1417 			{
1418 				out = list.at(j);
1419 				return true;
1420 			}
1421 	}
1422 	return false;
1423 }
1424 
1425 //
1426 //	Get visible edge nearest to mouse (from a given edges list)
1427 //	Returns: true if found
getVisibleEdgeNearestToMouse(QList<Edg> listE,Edg & ret)1428 bool edit_topo::getVisibleEdgeNearestToMouse(QList<Edg> listE, Edg &ret)
1429 {
1430 	Fce nearest;
1431 	bool got = false;
1432 	double tx,ty,tz;
1433 	int at = 0;
1434 	for(int f=0; f<Fstack.count(); f++)
1435 	{
1436 		Fce fc = Fstack.at(f);
1437 
1438 		QList<Vtx> allv;
1439 		for(int e=0; e<3; e++)
1440 			for(int v=0; v<2; v++)
1441 				if(!allv.contains(fc.e[e].v[v]))
1442 					allv.push_back(fc.e[e].v[v]);
1443 
1444 		gluProject(allv.at(0).V.X(),allv.at(0).V.Y(),allv.at(0).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1445 		QPointF p0 = QPointF(tx, ty);
1446 		gluProject(allv.at(1).V.X(),allv.at(1).V.Y(),allv.at(1).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1447 		QPointF p1 = QPointF(tx, ty);
1448 		gluProject(allv.at(2).V.X(),allv.at(2).V.Y(),allv.at(2).V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1449 		QPointF p2 = QPointF(tx, ty);
1450 
1451 		QPoint p = QPoint(mousePos.x(), mouseRealY);
1452 
1453 		if(pointInTriangle(p, p0, p1, p2))
1454 		{
1455 			nearest = fc;
1456 			got = true;
1457 			at = f;
1458 		}
1459 	}
1460 
1461 	if(got)
1462 	{
1463 		Edg minE;
1464 		float bestD = -1;
1465 		bool found = false;
1466 		double tx,ty,tz;
1467 
1468 		for(int i=0; i<3; i++)
1469 		{
1470 			Edg e = nearest.e[i];
1471 			gluProject(e.v[0].V.X(),e.v[0].V.Y(),e.v[0].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1472 			QPointF p0 = QPointF(tx, ty);
1473 			gluProject(e.v[1].V.X(),e.v[1].V.Y(),e.v[1].V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1474 			QPointF p1 = QPointF(tx, ty);
1475 
1476 			float dist = distancePointSegment(QPointF(mousePos.x(),mouseRealY), p1, p0);
1477 			if((dist < bestD)||(bestD==-1))
1478 			{
1479 				bestD = dist;
1480 				minE = e;
1481 				found = true;
1482 			}
1483 		}
1484 
1485 		ret = minE;
1486 		return found;
1487 	}
1488 	return false;
1489 }
1490 
1491 //
1492 //	Checks if the given point is in the given triangle
1493 //
pointInTriangle(const QPointF & p,const QPointF & a,const QPointF & b,const QPointF & c)1494 bool edit_topo::pointInTriangle(const QPointF &p, const QPointF &a, const QPointF &b, const QPointF &c)
1495 {
1496 	float fab=(p.y()-a.y())*(b.x()-a.x()) - (p.x()-a.x())*(b.y()-a.y());
1497 	float fbc=(p.y()-c.y())*(a.x()-c.x()) - (p.x()-c.x())*(a.y()-c.y());
1498 	float fca=(p.y()-b.y())*(c.x()-b.x()) - (p.x()-b.x())*(c.y()-b.y());
1499 
1500 	return (fab*fbc>0 && fbc*fca>0);
1501 }
1502 
1503 //
1504 //	2d distance p-seg
1505 //
distancePointSegment(QPointF p,QPointF segmentP1,QPointF segmentP2)1506 float edit_topo::distancePointSegment(QPointF p, QPointF segmentP1,QPointF segmentP2)
1507 {
1508 	float x0, y0, x1, x2, y1, y2, m, q;
1509 
1510 	x1 = segmentP1.x();
1511 	y1 = segmentP1.y();
1512 
1513 	x2 = segmentP2.x();
1514 	y2 = segmentP2.y();
1515 
1516 	m = (y2-y1)/(x2-x1);
1517 	q = y1 - m*x1;
1518 
1519 	x0 = p.x();
1520 	y0 = p.y();
1521 
1522 	return fabs((y0 - m*x0 -q) / (sqrt(1 + m*m)));
1523 }
1524 
1525 //
1526 //	2d distance p-p
1527 //
distancePointPoint(QPointF P1,QPointF P2)1528 float edit_topo::distancePointPoint(QPointF P1, QPointF P2)
1529 {
1530 	return sqrt(pow((P1.x()-P2.x()),2)+pow((P1.y()-P2.y()),2));
1531 }
1532 
1533 /************************************************************************************/
1534 //
1535 // --- Plugin rendering methods ---
1536 //		Those methods are used by the plugin to draw labels
1537 //		vertices, edges, faces, ... in opengl
1538 
1539 //
1540 //	Draws user selected vertices labels
1541 //
drawLabel(QList<Vtx> list)1542 void edit_topo::drawLabel(QList<Vtx> list)
1543 {
1544 
1545 	QVector<Vtx> v = list.toVector();
1546 	int pCount = list.count();
1547 
1548 	for(int i=0; i<pCount; i++)
1549 		drawLabel(list.at(i));
1550 }
1551 
1552 //
1553 //	Draws user selected vertex label
1554 //
drawLabel(Vtx v)1555 void edit_topo::drawLabel(Vtx v)
1556 {
1557 	if(isVertexVisible(v.V)&&(edit_topodialogobj->drawLabels()))
1558 	{
1559 		double tx,ty,tz;
1560 		gluProject(v.V.X(),v.V.Y(),v.V.Z(), mvmatrix,projmatrix,viewport, &tx,&ty,&tz);
1561 		int x,y;
1562 		x = tx+5;
1563 		y=(parentGla->curSiz.height() - 5 - ty);
1564 
1565 		// new style
1566 		QString text = v.vName;
1567 		QFont font;
1568 		font.setFamily("Helvetica");
1569 		font.setPixelSize(10);
1570 		QFontMetrics fm(font);
1571 		QRect brec=fm.boundingRect(text);
1572 		glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT );
1573 		glDisable(GL_LIGHTING);
1574 		glDisable(GL_TEXTURE_2D);
1575 		glEnable(GL_BLEND);
1576 		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1577 
1578 		glMatrixMode(GL_PROJECTION);
1579 		glPushMatrix();
1580 		glLoadIdentity();
1581 		gluOrtho2D(0,parentGla->width(),parentGla->height(),0);
1582 		glMatrixMode(GL_MODELVIEW);
1583 		glPushMatrix();
1584 		glLoadIdentity();
1585 		glColor4f(0,0,0,0.6f);
1586 		glBegin(GL_QUADS);
1587 		glVertex2f(x+brec.left(),y+brec.bottom());
1588 		glVertex2f(x+brec.right(),y+brec.bottom());
1589 		glVertex2f(x+brec.right(),y+brec.top());
1590 		glVertex2f(x+brec.left(),y+brec.top());
1591 		glEnd();
1592 		int offset=2;
1593 		glColor4f(0,0,0,0.3f);
1594 		glBegin(GL_QUADS);
1595 			glVertex2f(x+brec.left()-offset,y+brec.bottom()+offset);
1596 			glVertex2f(x+brec.right()+offset,y+brec.bottom()+offset);
1597 			glVertex2f(x+brec.right()+offset,y+brec.top()-offset);
1598 			glVertex2f(x+brec.left()-offset,y+brec.top()-offset);
1599 		glEnd();
1600 		glColor3f(1,1,1);
1601 		parentGla->renderText(x,y, text,QFont());
1602 		glMatrixMode(GL_PROJECTION);
1603 		glPopMatrix();
1604 		glMatrixMode(GL_MODELVIEW);
1605 		glPopMatrix();
1606 		glPopAttrib();
1607 	}
1608 }
1609 
1610 //
1611 //	Draws a point
1612 //
drawPoint(MeshModel & m,float pSize,Color4b colorFront,Point3f p)1613 void edit_topo::drawPoint(MeshModel &m, float pSize, Color4b colorFront, Point3f p)
1614 {
1615 	glPushMatrix();
1616 	glMultMatrix(m.cm.Tr);
1617 	glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LINE_BIT | GL_DEPTH_BUFFER_BIT);
1618 	glDepthFunc(GL_ALWAYS);
1619 	glDisable(GL_DEPTH_TEST);
1620 	glDepthMask(GL_FALSE);
1621 	glDisable(GL_LIGHTING);
1622 
1623 	glColor(colorFront);
1624 
1625 	glPointSize(pSize);
1626 
1627 	glBegin(GL_POINTS);
1628 		glVertex(p);
1629 		glVertex(p);
1630 	glEnd();
1631 /*
1632 	glDepthMask(GL_TRUE);
1633 	glEnable(GL_DEPTH_TEST);
1634 	glDepthFunc(GL_LESS);
1635 	glColor(colorBack);
1636 
1637 	glPointSize(0.3);
1638 
1639 	glBegin(GL_POINT);
1640 		glVertex(cursorPoint);
1641 		glVertex(cursorPoint);
1642 	glEnd();
1643 */
1644 	glPopAttrib();
1645 	glPopMatrix();
1646 }
1647 
1648 //
1649 //	Draws all vertices
1650 //
drawPoint(MeshModel & m,float pSize,Color4b colorFront,QList<Vtx> list)1651 void edit_topo::drawPoint(MeshModel &m, float pSize, Color4b colorFront, QList<Vtx> list)
1652 {
1653 	glPushMatrix();
1654 	glMultMatrix(m.cm.Tr);
1655 	glPushAttrib(GL_ENABLE_BIT | GL_CURRENT_BIT | GL_LINE_BIT | GL_DEPTH_BUFFER_BIT);
1656 	glLineWidth(2.0f);
1657 	glDepthFunc(GL_ALWAYS);
1658 	glDisable(GL_DEPTH_TEST);
1659 	glDepthMask(GL_FALSE);
1660 
1661 	glDisable(GL_LIGHTING);
1662 	glColor(colorFront);
1663 
1664 	glPointSize(pSize);
1665 
1666 	QVector<Vtx> v = list.toVector();
1667 	int pCount = list.count();
1668 
1669 	glBegin(GL_POINTS);
1670 		for(int i=0; i<pCount; i++)
1671 			glVertex(v[i].V);
1672 	glEnd();
1673 
1674 	glDepthMask(GL_TRUE);
1675 	glEnable(GL_DEPTH_TEST);
1676 	glDepthFunc(GL_LESS);
1677 	glColor(Color4b::White);
1678 
1679 	glPointSize(1.3f);
1680 
1681 	glBegin(GL_POINTS);
1682 		for(int i=0; i<pCount; i++)
1683 			glVertex(v[i].V);
1684 	glEnd();
1685 
1686 	glPopAttrib();
1687 	glPopMatrix();
1688 }
1689 
1690 //
1691 //	Creates recursively the dotted line points
1692 //
vectSub(int part,Point3f p1,Point3f p2)1693 QVector<Point3f> vectSub(int part, Point3f p1, Point3f p2)
1694 {
1695 	if(part==2)
1696 	{
1697 		QVector<Point3f> toRet(3);
1698 		toRet[0]=p1;
1699 		toRet[1]=(p1+p2)/2;
1700 		toRet[2]=p2;
1701 		return toRet;
1702 	}
1703 	else
1704 	{
1705 		QVector<Point3f> L;
1706 		QVector<Point3f> R;
1707 
1708 		int np=(int)(part/2);
1709 
1710 		L = vectSub(np, p1, (p1+p2)/2);
1711 		R = vectSub(np, (p1+p2)/2, p2);
1712 
1713 		QVector<Point3f> toRet;
1714 		for(int i=0; i<L.size(); i++)
1715 			if(!toRet.contains(L.at(i)))
1716 				toRet.push_back(L.at(i));
1717 		for(int i=0; i<R.size(); i++)
1718 			if(!toRet.contains(R.at(i)))
1719 				toRet.push_back(R.at(i));
1720 
1721 		return toRet;
1722 	}
1723 }
1724 
1725 //
1726 //	Draws a line (used for edges and faces)
1727 //
drawLine(Color4b colorFront,Color4b colorBack,Point3f p1,Point3f p2)1728 void edit_topo::drawLine(Color4b colorFront, Color4b colorBack, Point3f p1, Point3f p2)
1729 {
1730 	// Drawing of the current line
1731 	if(isVertexVisible(p1)&&isVertexVisible(p2))
1732 	{
1733 		glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT);
1734 		glDisable(GL_LIGHTING);
1735 		glDisable(GL_TEXTURE_2D);
1736 		glDepthMask(false);
1737 		glLineWidth(2.5f);
1738 		glPointSize(1.4f);
1739 
1740 		glEnable(GL_BLEND);
1741 		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
1742 		glEnable(GL_LINE_SMOOTH);
1743 		glEnable(GL_POINT_SMOOTH);
1744 		glColor(colorFront);
1745 		glBegin(GL_LINES);
1746 			glVertex(p1);
1747 			glVertex(p2);
1748 		glEnd();
1749 		glBegin(GL_POINTS);
1750 			glVertex(p1);
1751 			glVertex(p2);
1752 		glEnd();
1753 
1754 		// Fill the intermed. points to draw a dotted line
1755 		QVector<Point3f> trattP;
1756 		int part = 32;
1757 		float dist = (p1-p2).Norm();
1758 		if(dist>10) part*=2;
1759 		if(dist>50) part*=2;
1760 		if(dist>100) part*=2;
1761 		if(dist>400) part*=2;
1762 
1763 		Point3f pp1, pp2;
1764 		trattP = vectSub(part, p1, p2);
1765 
1766 		for(int i=0; i<(trattP.size()-1); i+=2)
1767 		{
1768 			pp1 = trattP[i];
1769 			pp2 = trattP[i+1];
1770 
1771 			glDisable(GL_DEPTH_TEST);
1772 
1773 			glLineWidth(0.5f);
1774 			glPointSize(0.3f);
1775 			glBegin(GL_LINES);
1776 				glVertex(pp1);
1777 				glVertex(pp2);
1778 			glEnd();
1779 			glBegin(GL_POINTS);
1780 				glVertex(pp1);
1781 				glVertex(pp2);
1782 			glEnd();
1783 		}
1784 		glPopAttrib();
1785 	}
1786 	else if(edit_topodialogobj->drawEdges())
1787 	{
1788 		glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_LINE_BIT | GL_POINT_BIT | GL_CURRENT_BIT | GL_LIGHTING_BIT | GL_COLOR_BUFFER_BIT);
1789 		glDisable(GL_LIGHTING);
1790 		glDisable(GL_TEXTURE_2D);
1791 		glDepthMask(false);
1792 		glLineWidth(1.5f);
1793 		glPointSize(0.4f);
1794 
1795 		// Fill the intermed. points to draw a dotted line
1796 		QVector<Point3f> trattP;
1797 		int part = 8;
1798 		float dist = (p1-p2).Norm();
1799 		if(dist>10) part*=2;
1800 		if(dist>50) part*=2;
1801 		if(dist>100) part*=2;
1802 		if(dist>400) part*=2;
1803 
1804 		Point3f pp1, pp2;
1805 		trattP = vectSub(part, p1, p2);
1806 
1807 		glColor(colorBack);
1808 		glDisable(GL_DEPTH_TEST);
1809 
1810 		for(int i=0; i<(trattP.size()-1); i+=2)
1811 		{
1812 			pp1 = trattP[i];
1813 			pp2 = trattP[i+1];
1814 
1815 			glBegin(GL_LINES);
1816 				glVertex(pp1);
1817 				glVertex(pp2);
1818 			glEnd();
1819 			glBegin(GL_POINTS);
1820 				glVertex(pp1);
1821 				glVertex(pp2);
1822 			glEnd();
1823 		}
1824 		glPopAttrib();
1825 	}
1826 }
1827 
1828 //
1829 //	Draws a triangle
1830 //
drawFace(CMeshO::FacePointer fp)1831 void edit_topo::drawFace(CMeshO::FacePointer fp)
1832 {
1833     glPointSize(3.0f);
1834 
1835 	glBegin(GL_POINTS); //GL_LINE_LOOP);
1836 		glVertex(fp->P(0));
1837 		glVertex(fp->P(1));
1838 		glVertex(fp->P(2));
1839 	glEnd();
1840 }
1841