Developer Documentation
MeshObjectInfoPlugin.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43 * *
44 * $Revision$ *
45 * $LastChangedBy$ *
46 * $Date$ *
47 * *
48 \*===========================================================================*/
49 
50 //=============================================================================
51 //
52 // CLASS InfoMeshObjectPlugin - IMPLEMENTATION
53 //
54 //=============================================================================
55 
56 
57 //== INCLUDES =================================================================
58 
59 
60 #include "MeshObjectInfoPlugin.hh"
61 
62 #include <MeshTools/MeshInfoT.hh>
63 
64 #include <Math_Tools/Math_Tools.hh>
65 
66 #include "ValenceHistogramDialog.hh"
67 
68 #if QT_VERSION >= 0x050000
69 #else
70 #include <QtGui>
71 #endif
72 
73 //== IMPLEMENTATION ==========================================================
74 
75 
76 InfoMeshObjectPlugin::InfoMeshObjectPlugin() :
77  info_(0),
78  infoBar_(0),
79  lastPickedObject_(0),
80  lastPickedObjectId_(-1)
81 {
82 }
83 
84 InfoMeshObjectPlugin::~InfoMeshObjectPlugin() {
85 
86  //Info bar and dialog will be deleted by core widget
87 }
88 
89 
90 void InfoMeshObjectPlugin::initializePlugin() {
91 
92 }
93 
96 
97  //set the slot descriptions
98  setDescriptions();
99 
100  if ( OpenFlipper::Options::gui()) {
101 
102  // Create info bar
103  infoBar_ = new InfoBar();
104 
105  // Create info dialog
106  info_ = new InfoDialog();
107 
108  connect(info_->valenceHistograms_pb, SIGNAL( clicked() ),
109  this, SLOT( slotShowHistogram() ));
110 
111  // Set default pick mode in dialog box
112  info_->pickMode->setCurrentIndex(0); // PICK_FACES
113 
114  emit addWidgetToStatusbar(infoBar_);
115  infoBar_->hideCounts();
116  }
117 
118 }
119 
120 //-----------------------------------------------------------------------------
121 
124 }
125 
126 //-----------------------------------------------------------------------------
127 
128 template< class MeshT >
129 void InfoMeshObjectPlugin::printMeshInfo( MeshT* _mesh , int _id, unsigned int _index, ACG::Vec3d& _hitPoint ) {
130 
131  bool face = false;
132  bool edge = false;
133  bool vertex = false;
134 
135  int closestVertexIndex = -1;
136  int closestEdgeIndex = -1;
137 
138  switch (info_->pickMode->currentIndex() ) {
139  case 0 : //Face
140  closestVertexIndex = getClosestVertexInFace(_mesh, _index, _hitPoint);
141  closestEdgeIndex = getClosestEdgeInFace (_mesh, _index, _hitPoint);
142  face = true;
143  break;
144  case 1 : //Edge
145  closestVertexIndex = getClosestVertexFromEdge(_mesh, _index, _hitPoint);
146  closestEdgeIndex = _index;
147  edge = true;
148  break;
149  case 2 : //Vertex
150  closestVertexIndex = _index;
151  vertex = true;
152  break;
153  default:
154  emit log(LOGERR,"Error: unknown picking mode in printMeshInfo");
155  return;
156  }
157 
158  QLocale locale;
159 
160  QString name;
161 
162  // name
163  BaseObject* obj = 0;
164  if ( PluginFunctions::getObject(_id, obj) )
165  info_->generalBox->setTitle( tr("General object information for %1").arg( obj->name() ) );
166 
167  // ID
168  info_->id->setText( locale.toString(_id) );
169  // Vertices
170  info_->vertices->setText( locale.toString( qulonglong(_mesh->n_vertices() ) ) );
171  // Faces
172  info_->faces->setText( locale.toString( qulonglong( _mesh->n_faces() ) ) );
173  // Edges
174  info_->edges->setText( locale.toString( qulonglong( _mesh->n_edges() ) ) );
175 
176  if ( face ) {
177 
178  // Picked Face
179  info_->closestFaceLabel->setText( tr("Picked Face:") );
180  info_->closestFaceLabel->show();
181  info_->faceHandle->setText( locale.toString( _index ) );
182  info_->faceHandle->show();
183 
184  // Closest Vertex
185  info_->closestVertexLabel->setText( tr("Closest Vertex:") );
186  info_->vertexHandle->setText( locale.toString( closestVertexIndex ) );
187 
188  // Closest Edge
189  info_->closestEdgeLabel->setText( tr("Closest Edge:") );
190  info_->edgeHandle->setText( locale.toString( closestEdgeIndex ) );
191  info_->closestEdgeLabel->show();
192  info_->edgeHandle->show();
193 
194  // Closest Edge Length
195  info_->edgeLengthLabel->setText( tr("Closest Edge Length:") );
196  info_->edgeLengthLabel->show();
197  const typename MeshT::Point from = _mesh->point(_mesh->from_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
198  const typename MeshT::Point to = _mesh->point(_mesh->to_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
199  info_->edgeLength->setText( locale.toString( (to - from).norm() ) );
200  info_->edgeLength->show();
201 
202  //adjacent vertex handles
203  typename MeshT::FaceHandle fh = _mesh->face_handle(_index);
204 
205  typename MeshT::FaceVertexIter fv_it = _mesh->fv_iter(fh);
206  QString adjacentVertices;
207 
208  if ( fv_it.is_valid() ){
209  adjacentVertices = QString::number( fv_it->idx() );
210  ++fv_it;
211  }
212 
213  while( fv_it.is_valid() ){
214  adjacentVertices += "; " + QString::number( fv_it->idx() );
215  ++fv_it;
216  }
217 
218  info_->adjVertexHandles->setText( adjacentVertices );
219  info_->adjVertexHandles->show();
220  info_->adjacentVertexLabel->show();
221 
222  //normal
223  info_->normalLabel->setText(tr("Normal of picked face:"));
224  info_->normalX->setText( QString::number( _mesh->normal(fh)[0],'f' ) );
225  info_->normalY->setText( QString::number( _mesh->normal(fh)[1],'f' ) );
226  info_->normalZ->setText( QString::number( _mesh->normal(fh)[2],'f' ) );
227  info_->normalLabel->show();
228  info_->normalLeft->show();
229  info_->normalX->show();
230  info_->normalY->show();
231  info_->normalZ->show();
232  info_->normalRight->show();
233 
234  // closest vertex coordinates
235  info_->closestVertexPosLabel->setText(tr("Closest Vertex on the mesh:"));
236 
237  } else if (edge) {
238 
239  // Adjacent Faces
240  info_->closestFaceLabel->setText( tr("Adjacent Faces:") );
241  info_->closestFaceLabel->show();
242  typename MeshT::HalfedgeHandle he1 = _mesh->halfedge_handle(_mesh->edge_handle(_index),0);
243  typename MeshT::HalfedgeHandle he2 = _mesh->halfedge_handle(_mesh->edge_handle(_index),1);
244 
245  int fh1 = _mesh->face_handle(he1).idx();
246  int fh2 = _mesh->face_handle(he2).idx();
247 
248  info_->faceHandle->setText( locale.toString( fh1 ) + ";" + locale.toString( fh2 ) );
249  info_->faceHandle->show();
250 
251  // Adjacent vertices
252  info_->adjVertexHandles->setText(QString::number( _mesh->from_vertex_handle(he1).idx() ) + ";" + QString::number( _mesh->to_vertex_handle(he1).idx() ));
253  info_->adjVertexHandles->show();
254  info_->adjacentVertexLabel->show();
255 
256  // Closest Vertex
257  info_->closestVertexLabel->setText( tr("Closest Vertex:") );
258  info_->vertexHandle->setText( locale.toString( closestVertexIndex ) );
259 
260  // Picked Edge
261  info_->closestEdgeLabel->setText( tr("Picked Edge:") );
262  info_->edgeHandle->setText( locale.toString( closestEdgeIndex ) );
263  info_->closestEdgeLabel->show();
264  info_->edgeHandle->show();
265 
266  // Edge Length
267  info_->edgeLengthLabel->setText( tr("Edge Length:") );
268  info_->edgeLengthLabel->show();
269  const typename MeshT::Point from = _mesh->point(_mesh->from_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
270  const typename MeshT::Point to = _mesh->point(_mesh->to_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
271  info_->edgeLength->setText( locale.toString( (to - from).norm() ) );
272  info_->edgeLength->show();
273 
274  // Normal
275  info_->normalLabel->hide();
276  info_->normalLeft->hide();
277  info_->normalX->hide();
278  info_->normalY->hide();
279  info_->normalZ->hide();
280  info_->normalRight->hide();
281 
282  // closest vertex coordinates
283  info_->closestVertexPosLabel->setText(tr("Closest Vertex on the mesh:"));
284 
285  } else if (vertex) {
286 
287  // Faces
288  info_->closestFaceLabel->hide();
289  info_->faceHandle->hide();
290 
291  // Adjacent vertices
292  info_->adjVertexHandles->hide();
293  info_->adjacentVertexLabel->hide();
294 
295  // Closest Vertex
296  info_->closestVertexLabel->setText( tr("Picked Vertex:") );
297  info_->vertexHandle->setText( locale.toString( closestVertexIndex ) );
298 
299  // Closest Edge
300  info_->closestEdgeLabel->hide();
301  info_->edgeHandle->hide();
302 
303  // Edge Length
304  info_->edgeLengthLabel->hide();
305  info_->edgeLength->hide();
306 
307  // Normal
308  typename MeshT::VertexHandle vh = _mesh->vertex_handle(_index);
309  info_->normalLabel->setText(tr("Normal of picked vertex:"));
310  info_->normalX->setText( QString::number( _mesh->normal(vh)[0],'f' ) );
311  info_->normalY->setText( QString::number( _mesh->normal(vh)[1],'f' ) );
312  info_->normalZ->setText( QString::number( _mesh->normal(vh)[2],'f' ) );
313  info_->normalLabel->show();
314  info_->normalLeft->show();
315  info_->normalX->show();
316  info_->normalY->show();
317  info_->normalZ->show();
318  info_->normalRight->show();
319 
320  // closest vertex coordinates
321  info_->closestVertexPosLabel->setText(tr("Picked Vertex on the mesh:"));
322 
323  // Adjacent Edges
324  info_->closestFaceLabel->setText( tr("Adjacent Edges:") );
325  info_->closestFaceLabel->show();
326 
327  //adjacent vertex handles
328 
329  typename MeshT::VertexEdgeIter ve_it = _mesh->ve_iter(vh);
330  QString adjacentEdges;
331 
332  if ( ve_it.is_valid() ){
333  adjacentEdges = QString::number( ve_it->idx() );
334  ++ve_it;
335  }
336 
337  while( ve_it.is_valid() ){
338  adjacentEdges += "; " + QString::number( ve_it->idx() );
339  ++ve_it;
340  }
341 
342  info_->faceHandle->setText( adjacentEdges );
343  info_->faceHandle->show();
344  }
345 
346  // closest vertex coordinates
347  info_->vertexX->setText( QString::number( _mesh->point( _mesh->vertex_handle(closestVertexIndex) )[0],'f' ) );
348  info_->vertexY->setText( QString::number( _mesh->point( _mesh->vertex_handle(closestVertexIndex) )[1],'f' ) );
349  info_->vertexZ->setText( QString::number( _mesh->point( _mesh->vertex_handle(closestVertexIndex) )[2],'f' ) );
350 
351 
352  // Components
353  int compo_count = MeshInfo::componentCount(_mesh);
354  info_->components->setText( locale.toString(compo_count));
355  // Boundaries
356  int boundary_count = MeshInfo::boundaryCount(_mesh);
357  info_->boundaries->setText( locale.toString(boundary_count) );
358  // Genus
359  int chi = _mesh->n_vertices();
360  chi -= _mesh->n_edges();
361  chi += _mesh->n_faces(); // chi = Euler characteristic
362  // chi + n_holes = 2(n_components - genus) => genus = n_components - (chi + n_holes)/2;
363  float genus = compo_count - 0.5*(chi + boundary_count);
364  if(compo_count == 1 && boundary_count == 0)
365  info_->genus->setText( QString::number(genus) );
366  else if(compo_count != 1)
367  info_->genus->setText( "(multiple components)" );
368  else
369  info_->genus->setText( "(not manifold)" );
370 
371  // Coordinates
372  typename MeshT::VertexIter v_it;
373  typename MeshT::VertexIter v_end = _mesh->vertices_end();
374 
375  float maxX = FLT_MIN;
376  float minX = FLT_MAX;
377  //float sumX = 0.0;
378  float maxY = FLT_MIN;
379  float minY = FLT_MAX;
380  //float sumY = 0.0;
381  float maxZ = FLT_MIN;
382  float minZ = FLT_MAX;
383  //float sumZ = 0.0;
384  int minV = 999;
385  int maxV = 0;
386  int sumV = 0;
387  float maxE = FLT_MIN;
388  float minE = FLT_MAX;
389  float sumE = 0.0;
390 
391  //iterate over all vertices
392  for (v_it = _mesh->vertices_begin(); v_it != v_end; ++v_it){
393  typename MeshT::Point p = _mesh->point( *v_it );
394  if (p[0] < minX) minX = p[0];
395  if (p[0] > maxX) maxX = p[0];
396  //sumX += p[0];
397  if (p[1] < minY) minY = p[1];
398  if (p[1] > maxY) maxY = p[1];
399  //sumY += p[1];
400  if (p[2] < minZ) minZ = p[2];
401  if (p[2] > maxZ) maxZ = p[2];
402  //sumZ += p[2];
403 
404 
405 
406  //check valence + edge length
407  int valence = 0;
408  typename MeshT::VertexVertexIter vv_it;
409 
410  for (vv_it=_mesh->vv_iter( *v_it ); vv_it.is_valid(); ++vv_it){
411  valence++;
412 
413  typename MeshT::Point p2 = _mesh->point( *vv_it );
414  typename MeshT::Scalar len = (p2 - p).norm();
415 
416  if (len < minE) minE = len;
417  if (len > maxE) maxE = len;
418  sumE += len;
419  }
420 
421  if (valence < minV) minV = valence;
422  if (valence > maxV) maxV = valence;
423  sumV += valence;
424  }
425 
426 
427  //valence
428  info_->valenceMin->setText( QString::number(minV) );
429  info_->valenceMean->setText( QString::number( sumV / (float)_mesh->n_vertices(),'f' ) );
430  info_->valenceMax->setText( QString::number(maxV) );
431 
432  //edge length
433  info_->edgeMin->setText( QString::number(minE,'f') );
434  info_->edgeMean->setText( QString::number( sumE / (_mesh->n_edges()*2),'f' ) );
435  info_->edgeMax->setText( QString::number(maxE,'f') );
436 
437  //get aspect ratio
438 
439  typename MeshT::FaceIter f_it;
440  typename MeshT::FaceIter f_end = _mesh->faces_end();
441 
442  float maxA = FLT_MIN;
443  float minA = FLT_MAX;
444  float sumA = 0.0;
445  float maxI = FLT_MIN;
446  float minI = FLT_MAX;
447  //float sumI = 0.0;
448  float maxD = FLT_MIN;
449  float minD = FLT_MAX;
450  float sumD = 0.0;
451  int numD = 0;
452  unsigned int maxFValence = std::numeric_limits<unsigned int>::min();
453  unsigned int minFValence = std::numeric_limits<unsigned int>::max();
454  size_t sumFValence = 0;
455 
456  //iterate over all faces
457  for (f_it = _mesh->faces_begin(); f_it != f_end; ++f_it){
458  typename MeshT::ConstFaceVertexIter cfv_it = _mesh->cfv_iter(*f_it);
459 
460  const typename MeshT::Point v0 = _mesh->point( *cfv_it );
461  ++cfv_it;
462  const typename MeshT::Point v1 = _mesh->point( *cfv_it );
463  ++cfv_it;
464  const typename MeshT::Point v2 = _mesh->point( *cfv_it );
465 
466  const float aspect = ACG::Geometry::aspectRatio(v0, v1, v2);
467 
468  if (aspect < minA) minA = aspect;
469  if (aspect > maxA) maxA = aspect;
470  sumA += aspect;
471 
472  //inner triangle angles
473 
474  double angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v2 - v0) | MathTools::sane_normalized(v1 - v0) )));
475 
476  if (angle < minI) minI = angle;
477  if (angle > maxI) maxI = angle;
478  //sumI += angle;
479 
480  angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v2 - v1) | MathTools::sane_normalized(v0 - v1) )));
481 
482  if (angle < minI) minI = angle;
483  if (angle > maxI) maxI = angle;
484  //sumI += angle;
485 
486  angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v1 - v2) | MathTools::sane_normalized(v0 - v2) )));
487 
488  if (angle < minI) minI = angle;
489  if (angle > maxI) maxI = angle;
490  //sumI += angle;
491 
492  //compute dihedral angles
493  typename MeshT::FaceFaceIter ff_it;
494  const typename MeshT::Normal n1 = _mesh->normal(*f_it);
495 
496  for (ff_it = _mesh->ff_iter(*f_it); ff_it.is_valid(); ++ff_it){
497 
498  const typename MeshT::Normal n2 = _mesh->normal(*ff_it);
499 
500  angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(n1) | MathTools::sane_normalized(n2) )));
501 
502  if (angle < minD) minD = angle;
503  if (angle > maxD) maxD = angle;
504  sumD += angle;
505  numD ++;
506  }
507 
508  const unsigned int valence = _mesh->valence(*f_it);
509  minFValence = std::min(minFValence, valence);
510  maxFValence = std::max(maxFValence, valence);
511  sumFValence += valence;
512  }
513 
514  info_->aspectMin->setText( QString::number(minA,'f') );
515  info_->aspectMean->setText( QString::number( sumA / _mesh->n_faces(),'f' ) );
516  info_->aspectMax->setText( QString::number(maxA,'f') );
517 
518  info_->angleMin->setText( QString::number(minI,'f') );
519  info_->angleMean->setText( "-" );
520  info_->angleMax->setText( QString::number(maxI,'f') );
521 
522  info_->faceValenceMin->setText(trUtf8("%1").arg(minFValence));
523  info_->faceValenceMax->setText(trUtf8("%1").arg(maxFValence));
524  info_->faceValenceMean->setText(trUtf8("%1").arg(
525  static_cast<float>(sumFValence) / _mesh->n_faces()));
526 
527  // Only one face or no face -> don't output angles
528  if ( _mesh->n_faces() > 1 ) {
529  info_->dihedralMin->setText( QString::number(minD,'f') );
530  info_->dihedralMean->setText( QString::number( sumD / numD,'f' ) );
531  info_->dihedralMax->setText( QString::number(maxD,'f') );
532  } else {
533  info_->dihedralMin->setText( "-" );
534  info_->dihedralMean->setText( "-" );
535  info_->dihedralMax->setText( "-" );
536  }
537 
538  //Calculate Bounding Box(min,max,cog)
539  ACG::Vec3d min;
540  ACG::Vec3d max;
541  MeshInfo::getBoundingBox(_mesh, min, max);
542 
543  //Bounding Box Size
544  ACG::Vec3d diff = max-min;
545 
546  info_->bbMinX->setText( QString::number(min[0],'f') );
547  info_->bbMinY->setText( QString::number(min[1],'f') );
548  info_->bbMinZ->setText( QString::number(min[2],'f') );
549 
550  info_->bbMaxX->setText( QString::number(max[0],'f') );
551  info_->bbMaxY->setText( QString::number(max[1],'f') );
552  info_->bbMaxZ->setText( QString::number(max[2],'f') );
553 
554  info_->bbSizeX->setText( QString::number(diff[0],'f') );
555  info_->bbSizeY->setText( QString::number(diff[1],'f') );
556  info_->bbSizeZ->setText( QString::number(diff[2],'f') );
557 
558  //COG
559  ACG::Vec3d cog = MeshInfo::cog(_mesh);
560 
561  info_->cogX->setText( QString::number(cog[0],'f') );
562  info_->cogY->setText( QString::number(cog[1],'f') );
563  info_->cogZ->setText( QString::number(cog[2],'f') );
564 
565  //hitpoint
566  info_->pointX->setText( QString::number( _hitPoint[0],'f' ) );
567  info_->pointY->setText( QString::number( _hitPoint[1],'f' ) );
568  info_->pointZ->setText( QString::number( _hitPoint[2],'f' ) );
569 
570  info_->setWindowFlags(info_->windowFlags() | Qt::WindowStaysOnTopHint);
571 
572 
573  info_->show();
574 }
575 
576 //----------------------------------------------------------------------------------------------
577 
587 template <class MeshT>
588 int InfoMeshObjectPlugin::getClosestVertexInFace(MeshT* _mesh, int _face_idx, ACG::Vec3d& _hitPoint) {
589 
590  typename MeshT::FaceVertexIter fv_it;
591 
592  int closest_v_idx = 0;
593  double dist = DBL_MAX;
594 
595  ACG::Vec3d vTemp = ACG::Vec3d(0.0, 0.0, 0.0);
596  typename MeshT::Point p;
597 
598  for (fv_it = _mesh->fv_iter(_mesh->face_handle(_face_idx)); fv_it.is_valid(); ++fv_it){
599 
600  p = _mesh->point( *fv_it );
601 
602  // Find closest vertex to selection
603  vTemp = ACG::Vec3d(p[0], p[1], p[2]);
604  const double temp_dist = (vTemp - _hitPoint).length();
605 
606  if (temp_dist < dist) {
607  dist = temp_dist;
608  closest_v_idx = fv_it->idx();
609  }
610 
611  }
612  return closest_v_idx;
613 }
614 
615 //-------------------------------------------------------------------------------------------
616 
626 template <class MeshT>
627 int InfoMeshObjectPlugin::getClosestEdgeInFace(MeshT* _mesh, int _face_idx, const ACG::Vec3d& _hitPoint) {
628 
629  typename MeshT::ConstFaceHalfedgeIter fh_it;
630  typename MeshT::VertexHandle v1, v2;
631  typename MeshT::Point p1, p2;
632 
633  ACG::Vec3d vp1, vp2, h;
634  double dist = DBL_MAX;
635  int closest_e_handle = 0;
636 
637  for (fh_it = _mesh->fh_iter(_mesh->face_handle(_face_idx)); fh_it.is_valid(); ++fh_it){
638 
639  v1 = _mesh->from_vertex_handle(*fh_it);
640  v2 = _mesh->to_vertex_handle(*fh_it);
641 
642  p1 = _mesh->point(v1);
643  p2 = _mesh->point(v2);
644 
645  vp1 = ACG::Vec3d(p1[0], p1[1], p1[2]);
646  vp2 = ACG::Vec3d(p2[0], p2[1], p2[2]);
647 
648  const ACG::Vec3d e = (vp2 - vp1).normalized();
649  const ACG::Vec3d g = _hitPoint - vp1;
650  const double x = g | e;
651 
652  const double temp_dist = (_hitPoint - (vp1 + x * e)).length();
653 
654  if (temp_dist < dist) {
655  dist = temp_dist;
656  }
657  }
658 
659  return closest_e_handle;
660 }
661 
662 //----------------------------------------------------------------------------------------------
663 
673 template <class MeshT>
674 int InfoMeshObjectPlugin::getClosestVertexFromEdge(MeshT* _mesh, int _edge_idx, ACG::Vec3d& _hitPoint) {
675 
676  ACG::Vec3d toVertex = _mesh->point( _mesh->to_vertex_handle( _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 )) );
677  ACG::Vec3d fromVertex = _mesh->point( _mesh->from_vertex_handle( _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 )) );
678 
679  double distTo = (_hitPoint - toVertex ).norm();
680  double distFrom = (_hitPoint - fromVertex).norm();
681 
682  if ( distTo > distFrom )
683  return _mesh->from_vertex_handle( _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 ) ).idx();
684  else
685  return _mesh->to_vertex_handle( _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 ) ).idx();
686 
687 }
688 
689 //----------------------------------------------------------------------------------------------
690 
691 void
693  slotInformationRequested(const QPoint _clickedPoint, DataType _type) {
694 
695  // Only respond on mesh objects
696  if((_type != DATA_TRIANGLE_MESH) && (_type != DATA_POLY_MESH)) return;
697 
699 
700  unsigned int node_idx, target_idx;
701  ACG::Vec3d hit_point;
702 
703  if (info_->isHidden())
704  {
705  //user couldn't select the pick mode,
706  //so we have to do this
708  if (!PluginFunctions::scenegraphPick(target, _clickedPoint, node_idx, target_idx, &hit_point))
709  return;
710 
711  BaseObjectData* object;
712  if (!PluginFunctions::getPickedObject(node_idx, object) )
713  return;
714 
715  //object is picked, now we can decide, what the user wants to pick
716  //priority: face > edge > vertex
717  if ( object->dataType(DATA_TRIANGLE_MESH) )
718  {
719  TriMesh* mesh = PluginFunctions::triMesh(object);
720  if (mesh->n_faces() != 0)
721  info_->pickMode->setCurrentIndex(0);
722  else if (mesh->n_edges() != 0)
723  info_->pickMode->setCurrentIndex(1);
724  else
725  info_->pickMode->setCurrentIndex(2);
726  }
727  else if ( object->dataType(DATA_POLY_MESH) )
728  {
729  PolyMesh* mesh = PluginFunctions::polyMesh(object);
730  if (mesh->n_faces() != 0)
731  info_->pickMode->setCurrentIndex(0);
732  else if (mesh->n_edges() != 0)
733  info_->pickMode->setCurrentIndex(1);
734  else
735  info_->pickMode->setCurrentIndex(2);
736  }
737  }
738 
740  if (info_->pickMode->currentIndex() == 1 )
742  else if (info_->pickMode->currentIndex() == 2 )
744 
745  if (PluginFunctions::scenegraphPick(target, _clickedPoint, node_idx, target_idx, &hit_point)) {
746  BaseObjectData* object;
747 
748  if ( PluginFunctions::getPickedObject(node_idx, object) ) {
749 
750  emit log( LOGINFO , object->getObjectinfo() );
751 
752  lastPickedObject_ = object;
753  lastPickedObjectId_ = object->id();
754 
755  if ( object->dataType(DATA_TRIANGLE_MESH) )
756  printMeshInfo( PluginFunctions::triMesh(object) , object->id(), target_idx, hit_point );
757 
758  if ( object->dataType(DATA_POLY_MESH) )
759  printMeshInfo( PluginFunctions::polyMesh(object) , object->id(), target_idx, hit_point );
760  } else {
761  lastPickedObject_ = 0;
762  return;
763  }
764  }
765  else
766  {
767  emit log( LOGERR , tr("Unable to pick object.") );
768  }
769 }
770 
771 //------------------------------------------------------------------------------
772 
773 template< class MeshT >
774 void InfoMeshObjectPlugin::getEdgeLengths(MeshT* _mesh, double &min, double &max, double &mean)
775 {
776  typename MeshT::ConstEdgeIter e_it(_mesh->edges_sbegin()),
777  e_end(_mesh->edges_end());
778 
779  min = FLT_MAX;
780  max = FLT_MIN;
781  mean = 0.0;
782  for (; e_it!=e_end; ++e_it)
783  {
784  typename MeshT::Scalar len = (_mesh->point(_mesh->to_vertex_handle(_mesh->halfedge_handle(*e_it, 0))) -
785  _mesh->point(_mesh->to_vertex_handle(_mesh->halfedge_handle(*e_it, 1)))).norm ();
786  if (len < min) min = len;
787  if (len > max) max = len;
788  mean += len;
789  }
790 
791  mean /= _mesh->n_edges();
792 }
793 
794 //------------------------------------------------------------------------------
795 
796 bool InfoMeshObjectPlugin::getEdgeLengths(int _id, double &min, double &max, double &mean)
797 {
798  BaseObjectData* object;
799  if ( ! PluginFunctions::getObject(_id,object) )
800  return false;
801 
802  if ( object == 0){
803  emit log(LOGERR, tr("Unable to get object"));
804  return false;
805  }
806 
807  if ( object->dataType(DATA_TRIANGLE_MESH) ) {
808  TriMesh* mesh = PluginFunctions::triMesh(object);
809 
810  if ( mesh == 0 ) {
811  emit log(LOGERR,tr("Unable to get mesh"));
812  return false;
813  }
814 
815  getEdgeLengths (mesh, min, max, mean);
816  return true;
817 
818  } else {
819  PolyMesh* mesh = PluginFunctions::polyMesh(object);
820 
821  if ( mesh == 0 ) {
822  emit log(LOGERR,tr("Unable to get mesh"));
823  return false;
824  }
825 
826  getEdgeLengths (mesh, min, max, mean);
827  return true;
828  }
829 
830  return false;
831 }
832 
833 //------------------------------------------------------------------------------
834 
835 void InfoMeshObjectPlugin::updateData( int _identifier , const UpdateType& _type, const bool _deleted){
836 
837  if ( !infoBar_ ) {
838  return;
839  }
840 
841  BaseObjectData* object;
842  PluginFunctions::getObject(_identifier,object);
843 
844  if (_identifier == lastPickedObjectId_ && _deleted) {
845  lastPickedObject_ = 0;
846  lastPickedObjectId_ = -1;
847  }
848 
849  // Last object that is target has been removed.
850  if ( _deleted && object && object->target() && (PluginFunctions::targetCount() == 1) ) {
851  infoBar_->hideCounts();
852  return;
853  }
854 
855  // We only show the information in the status bar if one target mesh is selected or
856  // If 2 targets where selected, where one is deleted which was target
857  if ( PluginFunctions::targetCount() == 1 || ( _deleted && (PluginFunctions::targetCount() == 2) && object && object->target() ) ) {
858 
859 
860 
861  // The object that caused the update is not a target anymore.
862  // Therefore we need to get the remaining target by iteration.
863  // If something was deleted, we might see this object here, so make sure, to not take the one with the same id as the deleted one
864  if ( object && !object->target() ) {
866  if ( !_deleted || ( o_it->id() != _identifier ) ) {
867  object = *o_it;
868  break;
869  }
870  }
871  }
872 
873  // We only need to update something, if the updated object is the target object
874  if (object && object->target() ) {
875 
876  if (object->dataType(DATA_TRIANGLE_MESH)){
877 
878  TriMesh* mesh = PluginFunctions::triMesh(object);
879 
880  infoBar_->vertices->setText( QLocale::system().toString( qulonglong(mesh->n_vertices()) ) );
881  infoBar_->edges->setText( QLocale::system().toString( qulonglong(mesh->n_edges()) ) );
882  infoBar_->faces->setText( QLocale::system().toString( qulonglong(mesh->n_faces()) ) );
883 
884  infoBar_->showCounts();
885 
886  return;
887  }
888 
889  if (object->dataType(DATA_POLY_MESH)){
890 
891  PolyMesh* mesh = PluginFunctions::polyMesh(object);
892 
893  infoBar_->vertices->setText( QLocale::system().toString( qulonglong(mesh->n_vertices()) ) );
894  infoBar_->edges->setText( QLocale::system().toString( qulonglong(mesh->n_edges()) ) );
895  infoBar_->faces->setText( QLocale::system().toString( qulonglong(mesh->n_faces()) ) );
896 
897  infoBar_->showCounts();
898  return;
899  }
900 
901  }
902 
903  infoBar_->hideCounts();
904 
905  } else {
906  // Display only count information
907  if ( (PluginFunctions::targetCount() > 1) && object ) {
908  if ( _deleted && object->target() ) {
909  infoBar_->showTargetCount( PluginFunctions::targetCount() - 1);
910  } else {
911  infoBar_->showTargetCount( PluginFunctions::targetCount() );
912  }
913  } else
914  infoBar_->hideCounts();
915  }
916 
917 }
918 
919 //------------------------------------------------------------------------------
920 
921 void InfoMeshObjectPlugin::slotObjectUpdated( int _identifier , const UpdateType& _type){
922 
923  updateData(_identifier,_type,false);
924 
925 }
926 
927 //------------------------------------------------------------------------------
928 
929 void InfoMeshObjectPlugin::slotObjectSelectionChanged( int _identifier ){
930  updateData(_identifier,UPDATE_ALL,false);
931 }
932 
933 //------------------------------------------------------------------------------
934 
935 void InfoMeshObjectPlugin::objectDeleted( int _identifier ){
936  updateData(_identifier,UPDATE_ALL,true);
937 }
938 
939 
940 //------------------------------------------------------------------------------
941 
942 void InfoMeshObjectPlugin::slotAllCleared(){
943  if ( infoBar_ )
944  infoBar_->hideCounts();
945 
946 }
947 
948 void InfoMeshObjectPlugin::slotShowHistogram() {
949  if (!lastPickedObject_) return;
950 
951  ValenceHistogramDialog *dialog = 0;
952  {
953  TriMeshObject *tmo = dynamic_cast<TriMeshObject*>(lastPickedObject_);
954  if (tmo) {
955  dialog = new ValenceHistogramDialog(*tmo->mesh(), info_);
956  }
957  }
958 
959  if (!dialog) {
960  PolyMeshObject *pmo = dynamic_cast<PolyMeshObject*>(lastPickedObject_);
961  if (pmo) {
962  dialog = new ValenceHistogramDialog(*pmo->mesh(), info_);
963  }
964  }
965 
966  dialog->setAttribute(Qt::WA_DeleteOnClose, true);
967  dialog->show();
968  dialog->raise();
969 }
970 
971 #if QT_VERSION < 0x050000
972  Q_EXPORT_PLUGIN2( InfoMeshObjectPlugin , InfoMeshObjectPlugin );
973 #endif
974 
975 
int getClosestVertexFromEdge(MeshT *_mesh, int _edge_idx, ACG::Vec3d &_hitPoint)
Get closest vertex index from an edge.
auto length() const -> decltype(std::declval< VectorT< S, DIM >>().norm())
compute squared euclidean norm
Definition: Vector11T.hh:417
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, unsigned int &_nodeIdx, unsigned int &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
void slotInformationRequested(const QPoint _clickedPoint, DataType _type)
Show information dialog on clicked object.
Predefined datatypes.
Definition: DataTypes.hh:96
Add normals to mesh item (vertices/faces)
Definition: Attributes.hh:87
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:73
Plugin to visualize information about objects in the scene.
Scalar aspectRatio(const VectorT< Scalar, N > &_v0, const VectorT< Scalar, N > &_v1, const VectorT< Scalar, N > &_v2)
return aspect ratio (length/height) of triangle
Definition: Algorithms.cc:1266
bool getObject(int _identifier, BSplineCurveObject *&_object)
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
bool dataType(DataType _type) const
Definition: BaseObject.cc:232
const QStringList TARGET_OBJECTS("target")
Iterable object range.
int id() const
Definition: BaseObject.cc:201
bool getPickedObject(const unsigned int _node_idx, BaseObjectData *&_object)
Get the picked mesh.
MeshT * mesh()
return a pointer to the mesh
Definition: MeshObjectT.cc:351
Update type class.
Definition: UpdateType.hh:70
PickTarget
What target to use for picking.
Definition: BaseNode.hh:99
T sane_aarg(T _aarg)
Trigonometry/angles - related.
Definition: MathDefs.hh:127
bool target()
Definition: BaseObject.cc:284
int getClosestVertexInFace(MeshT *_mesh, int _face_idx, ACG::Vec3d &_hitPoint)
Get closest vertex index from a face.
picks verices (may not be implemented for all nodes)
Definition: BaseNode.hh:108
int targetCount()
Get the number of target objects.
QString name() const
return the name of the object. The name defaults to NONAME if unset.
Definition: BaseObject.cc:741
void getEdgeLengths(MeshT *_mesh, double &min, double &max, double &mean)
Get edge lengths.
picks edges (may not be implemented for all nodes)
Definition: BaseNode.hh:106
DataType supportedDataTypes()
Get data type for information requests.
int getClosestEdgeInFace(MeshT *_mesh, int _face_idx, const ACG::Vec3d &_hitPoint)
Get closest edge index from a face.
void pluginsInitialized()
initialize the plugin
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:70
virtual QString getObjectinfo()
Get all Info for the Object as a string.
Definition: BaseObject.cc:255
pick any of the prior targets (should be implemented for all nodes)
Definition: BaseNode.hh:110
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
void updateData(int _identifier, const UpdateType &_type, const bool deleted)
Slot that updates the visualization.
#define DATA_POLY_MESH
Definition: PolyMesh.hh:65
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:127
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:66
picks faces (should be implemented for all nodes)
Definition: BaseNode.hh:104
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.