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