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