1 /****************************************************************************
2 * MeshLab                                                           o o     *
3 * An extendible mesh processor                                    o     o   *
4 *                                                                _   O  _   *
5 * Copyright(C) 2005, 2009                                          \/)\/    *
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 /*  A class implementing Meshlab's Edit interface that is for picking points in 3D
25  *
26  *
27  * @author Oscar Barney
28  */
29 
30 #include <GL/glew.h>
31 
32 #include "editpickpoints.h"
33 #include <meshlab/mainwindow.h>
34 
35 #include <wrap/gl/picking.h>
36 #include <wrap/gl/pick.h>
37 #include <wrap/qt/gl_label.h>
38 #include <wrap/qt/trackball.h>
39 
40 
41 
42 #include <math.h>
43 
44 using namespace vcg;
45 
46 #define PI 3.14159265
47 
48 
EditPickPointsPlugin()49 EditPickPointsPlugin::EditPickPointsPlugin()
50 {
51 	// initialize to false so we don't end up collecting some weird point in the beginning
52 	registerPoint = false;
53 	moveSelectPoint = false;
54 
55 	pickPointsDialog = 0;
56 	currentModel = 0;
57 
58 	overrideCursorShape = 0;
59 }
60 
61 //Constants
62 
63 
Info()64 const QString EditPickPointsPlugin::Info()
65 {
66 	return tr("Pick and save 3D points on the mesh");
67 }
68 
69 //called
Decorate(MeshModel & mm,GLArea * gla,QPainter * painter)70 void EditPickPointsPlugin::Decorate(MeshModel &mm, GLArea *gla, QPainter *painter)
71 {
72 	//qDebug() << "Decorate " << mm.fileName.c_str() << " ..." << mm.cm.fn;
73 
74 	if (gla != glArea || mm.cm.fn < 1)
75 	{
76 		//qDebug() << "GLarea is different or no faces!!! ";
77 		return;
78 	}
79 
80 
81 	//make sure we picking points on the right meshes!
82 	if (&mm != currentModel) {
83 		//now that were are ending tell the dialog to save any points it has to metadata
84 		pickPointsDialog->savePointsToMetaData();
85 
86 		//set the new mesh model
87 		pickPointsDialog->setCurrentMeshModel(&mm, gla);
88 		currentModel = &mm;
89 	}
90 
91 	//We have to calculate the position here because it doesnt work in the mouseEvent functions for some reason
92 	Point3m pickedPoint;
93 
94 	if (moveSelectPoint)
95 	{
96 		/* qDebug("Found point for move %i %i -> %f %f %f",
97 				currentMousePosition.x(),
98 				currentMousePosition.y(),
99 				pickedPoint[0], pickedPoint[1], pickedPoint[2]); */
100 
101 				//let the dialog know that this was the pointed picked in case it wants the information
102 		bool picked = Pick<Point3m>(currentMousePosition.x(), currentMousePosition.y(), pickedPoint);
103 		pickPointsDialog->selectOrMoveThisPoint(pickedPoint);
104 
105 		moveSelectPoint = false;
106 	}
107 	else
108 	{
109 		if (registerPoint)
110 		{
111 			 /*qDebug("Found point for add %i %i -> %f %f %f",
112 					currentMousePosition.x(),
113 					currentMousePosition.y(),
114 					pickedPoint[0], pickedPoint[1], pickedPoint[2]); */
115 
116 
117 					//find the normal of the face we just clicked
118 			bool picked = Pick<Point3m>(currentMousePosition.x(), currentMousePosition.y(), pickedPoint);
119 			std::vector<CFaceO*> face;
120 			int result = GLPickTri<CMeshO>::PickVisibleFace(currentMousePosition.x(), currentMousePosition.y(), mm.cm, face);
121 
122 			if ((result == 0) || (face[0] == NULL)) {
123 				qDebug() << "find nearest face failed!";
124 			}
125 			else
126 			{
127 				CFaceO::NormalType faceNormal = face[0]->N();
128 				//qDebug() << "found face normal: " << faceNormal[0] << faceNormal[1] << faceNormal[2];
129 
130 				//if we didn't find a face then don't add the point because the user was probably
131 				//clicking on another mesh opened inside the glarea
132 				pickPointsDialog->addMoveSelectPoint(pickedPoint, faceNormal);
133 			}
134 
135 			registerPoint = false;
136 		}
137 	}
138 
139 	drawPickedPoints(pickPointsDialog->getPickedPointTreeWidgetItemVector(), mm.cm.bbox, painter);
140 }
141 
StartEdit(MeshModel & mm,GLArea * gla,MLSceneGLSharedDataContext *)142 bool EditPickPointsPlugin::StartEdit(MeshModel & mm, GLArea * gla, MLSceneGLSharedDataContext* /*cont*/)
143 {
144 	//qDebug() << "StartEdit Pick Points: " << mm.fileName.c_str() << " ..." << mm.cm.fn;
145 
146 	//if there are no faces then we can't do anything with this plugin
147 	if (mm.cm.fn < 1)
148 	{
149 		if (NULL != pickPointsDialog)
150 		{
151 			pickPointsDialog->hide();
152 		}
153 
154 		//show message
155 		QMessageBox::warning(gla->window(), "Edit Pick Points",
156 			"Sorry, this mesh has no faces on which picked points can sit.",
157 			QMessageBox::Ok, QMessageBox::Ok);
158 		return false;
159 	}
160 
161 	//get the cursor
162 	QCursor *cursor = QApplication::overrideCursor();
163 	if (cursor) overrideCursorShape = cursor->shape();
164 	else overrideCursorShape = Qt::ArrowCursor;
165 
166 	//set this so redraw can use it
167 	glArea = gla;
168 
169 	//Create GUI window if we don't already have one
170 	if (pickPointsDialog == 0)
171 	{
172 		pickPointsDialog = new PickPointsDialog(this, gla->window());
173 	}
174 
175 	currentModel = &mm;
176 
177 	//set the current mesh
178 	pickPointsDialog->setCurrentMeshModel(&mm, gla);
179 
180 	//show the dialog
181 	pickPointsDialog->show();
182 	return true;
183 }
184 
EndEdit(MeshModel & mm,GLArea *,MLSceneGLSharedDataContext *)185 void EditPickPointsPlugin::EndEdit(MeshModel & mm, GLArea * /*gla*/, MLSceneGLSharedDataContext* /*cont*/)
186 {
187 	//qDebug() << "EndEdit Pick Points: " << mm.fileName.c_str() << " ..." << mm.cm.fn;
188 
189 	// some cleaning at the end.
190 
191 	if ((mm.cm.fn > 0) && (pickPointsDialog != NULL))
192 	{
193 		//now that were are ending tell the dialog to save any points it has to metadata
194 		pickPointsDialog->savePointsToMetaData();
195 
196 		//remove the dialog from the screen
197 		pickPointsDialog->hide();
198 
199 		QApplication::setOverrideCursor(QCursor((Qt::CursorShape)overrideCursorShape));
200 
201 		this->glArea = 0;
202 	}
203 }
204 
mousePressEvent(QMouseEvent * event,MeshModel & mm,GLArea * gla)205 void EditPickPointsPlugin::mousePressEvent(QMouseEvent *event, MeshModel &mm, GLArea *gla)
206 {
207 	//qDebug() << "mouse press Pick Points: " << mm.fileName.c_str() << " ...";
208 
209 	//if there are no faces then we can't do anything with this plugin
210 	if (mm.cm.fn < 1) return;
211 
212 	if (Qt::RightButton == event->button() &&
213 		pickPointsDialog->getMode() != PickPointsDialog::ADD_POINT) {
214 
215 		currentMousePosition =  QPoint(QT2VCG_X(gla, event), QT2VCG_Y(gla, event));
216 
217 		pickPointsDialog->recordNextPointForUndo();
218 
219 		//set flag that we need to add a new point
220 		moveSelectPoint = true;
221 	}
222 }
223 
mouseMoveEvent(QMouseEvent * event,MeshModel & mm,GLArea * gla)224 void EditPickPointsPlugin::mouseMoveEvent(QMouseEvent *event, MeshModel &mm, GLArea *gla)
225 {
226 	//qDebug() << "mousemove pick Points: " << mm.fileName.c_str() << " ...";
227 
228 	//if there are no faces then we can't do anything with this plugin
229 	if (mm.cm.fn < 1) return;
230 
231 	if (Qt::RightButton == event->button() &&
232 		pickPointsDialog->getMode() != PickPointsDialog::ADD_POINT) {
233 
234 		//qDebug() << "mouse move left button and move mode: ";
235 
236 		currentMousePosition = QPoint(QT2VCG_X(gla, event), QT2VCG_Y(gla, event)); //event->pos();
237 
238 		//set flag that we need to add a new point
239 		registerPoint = true;
240 	}
241 }
242 
mouseReleaseEvent(QMouseEvent * event,MeshModel & mm,GLArea * gla)243 void EditPickPointsPlugin::mouseReleaseEvent(QMouseEvent *event, MeshModel &mm, GLArea * gla)
244 {
245 	//qDebug() << "mouseRelease Pick Points: " << mm.fileName.c_str() << " ...";
246 
247 	//if there are no faces then we can't do anything with this plugin
248 	if (mm.cm.fn < 1) return;
249 
250 	//only add points for the left button
251 	if (Qt::RightButton == event->button()) {
252 		currentMousePosition = QPoint(QT2VCG_X(gla, event), QT2VCG_Y(gla, event));//event->pos();
253 
254 		//set flag that we need to add a new point
255 		registerPoint = true;
256 	}
257 }
258 
drawPickedPoints(std::vector<PickedPointTreeWidgetItem * > & pointVector,Box3m & boundingBox,QPainter * painter)259 void EditPickPointsPlugin::drawPickedPoints(
260 	std::vector<PickedPointTreeWidgetItem*> &pointVector, Box3m &boundingBox, QPainter *painter)
261 {
262 	assert(glArea);
263 	Point3m size = boundingBox.Dim();
264 	//how we scale the object indicating the normal at each selected point
265 	Scalarm scaleFactor = (size[0] + size[1] + size[2]) / 90.0;
266 
267 	//qDebug() << "scaleFactor: " << scaleFactor;
268 
269 	glPushAttrib(GL_ALL_ATTRIB_BITS);
270 
271 	// enable color tracking
272 	glEnable(GL_COLOR_MATERIAL);
273 
274 	//draw the things that we always want to show, like the names
275 	glDepthFunc(GL_ALWAYS);
276 	glDisable(GL_DEPTH_TEST);
277 	glDepthMask(GL_FALSE);
278 
279 	//set point attributes
280 	glPointSize(4.5);
281 	bool showNormal = pickPointsDialog->showNormal();
282 	bool showPin = pickPointsDialog->drawNormalAsPin();
283 
284 	for (int i = 0; i < pointVector.size(); ++i)
285 	{
286 		PickedPointTreeWidgetItem * item = pointVector[i];
287 		//if the point has been set (it may not be if a template has been loaded)
288 		if (item->isActive()) {
289 			Point3m point = item->getPoint();
290 			glColor(vcg::Color4b(vcg::Color4b::Blue));
291 			glLabel::render(painter, point, QString(item->getName()));
292 
293 			//draw the dot if we arnt showing the normal or showing the normal as a line
294 			if (!showNormal || !showPin)
295 			{
296 				if (item->isSelected()) glColor(vcg::Color4b(Color4b::Green));
297 
298 				glBegin(GL_POINTS);
299 				glVertex(point);
300 				glEnd();
301 			}
302 		}
303 	}
304 
305 
306 	//now draw the things that we want drawn if they are not ocluded
307 	//we can see in bright red
308 	glDepthFunc(GL_LESS);
309 	glEnable(GL_DEPTH_TEST);
310 	glDepthMask(GL_TRUE);
311 
312 	glEnable(GL_BLEND);
313 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
314 
315 	glMatrixMode(GL_MODELVIEW);
316 
317 	Point3m yaxis(Scalarm(0), Scalarm(1), Scalarm(0));
318 
319 	for (int i = 0; i < pointVector.size(); ++i)
320 	{
321 		PickedPointTreeWidgetItem * item = pointVector[i];
322 		//if the point has been set (it may not be if a template has been loaded)
323 		if (item->isActive()) {
324 			Point3m point = item->getPoint();
325 
326 			if (showNormal)
327 			{
328 				Point3m normal = item->getNormal();
329 
330 				if (showPin)
331 				{
332 					//dot product
333 					Scalarm angle = (Angle(normal, yaxis) * 180.0 / PI);
334 
335 					//cross product
336 					Point3m axis = yaxis^normal;
337 					//qDebug() << "angle: " << angle << " x" << axis[0] << " y" << axis[1] << " z" << axis[2];
338 
339 					//bluegreen and a little clear
340 					glColor4f(0.0f, 1.0f, 0.0f, 0.7f);
341 					//glColor(Color4b::Green);
342 
343 					glPushMatrix();
344 
345 					//move the pin to where it needs to be
346 					glTranslatef(point[0], point[1], point[2]);
347 					glRotatef(angle, axis[0], axis[1], axis[2]);
348 					glScalef(0.2*scaleFactor, 1.5*scaleFactor, 0.2*scaleFactor);
349 
350 					glBegin(GL_TRIANGLES);
351 
352 					//front
353 					glNormal3f(0, -1, 1);
354 					glVertex3f(0, 0, 0);
355 					glVertex3f(1, 1, 1);
356 					glVertex3f(-1, 1, 1);
357 
358 					//right
359 					glNormal3f(1, -1, 0);
360 					glVertex3f(0, 0, 0);
361 					glVertex3f(1, 1, -1);
362 					glVertex3f(1, 1, 1);
363 
364 					//left
365 					glNormal3f(-1, -1, 0);
366 					glVertex3f(0, 0, 0);
367 					glVertex3f(-1, 1, 1);
368 					glVertex3f(-1, 1, -1);
369 
370 					//back
371 					glNormal3f(0, -1, -1);
372 					glVertex3f(0, 0, 0);
373 					glVertex3f(-1, 1, -1);
374 					glVertex3f(1, 1, -1);
375 
376 					//top
377 
378 					//if it is selected color it green
379 					if (item->isSelected())	glColor4f(0.0f, 0.0f, 1.0f, 0.7f);
380 
381 
382 					glNormal3f(0, 1, 0);
383 					glVertex3f(1, 1, 1);
384 					glVertex3f(1, 1, -1);
385 					glVertex3f(-1, 1, -1);
386 
387 					glNormal3f(0, 1, 0);
388 					glVertex3f(1, 1, 1);
389 					glVertex3f(-1, 1, -1);
390 					glVertex3f(-1, 1, 1);
391 
392 					//change back
393 					if (item->isSelected())	glColor4f(0.0f, 1.0f, 0.0f, 0.7f);
394 
395 					glEnd();
396 					glPopMatrix();
397 				}
398 				else
399 				{
400 					glColor(vcg::Color4b(vcg::Color4b::Green));
401 
402 					glBegin(GL_LINES);
403 					glVertex(point);
404 					glVertex(point + (normal*scaleFactor));
405 					glEnd();
406 				}
407 			}
408 			glColor(vcg::Color4b(vcg::Color4b::Red));
409 			//glArea->renderText(point[0], point[1], point[2], QString(item->getName()) );
410 		}
411 	}
412 	glDisable(GL_BLEND);
413 	glDisable(GL_COLOR_MATERIAL);
414 	glDisable(GL_DEPTH_TEST);
415 	glPopAttrib();
416 
417 }
418