MeshObjectInfoPlugin.cc 32.2 KB
Newer Older
1 2 3
/*===========================================================================*\
*                                                                            *
*                              OpenFlipper                                   *
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
 *           Department of Computer Graphics and Multimedia                  *
 *                          All rights reserved.                             *
 *                            www.openflipper.org                            *
 *                                                                           *
 *---------------------------------------------------------------------------*
 * This file is part of OpenFlipper.                                         *
 *---------------------------------------------------------------------------*
 *                                                                           *
 * Redistribution and use in source and binary forms, with or without        *
 * modification, are permitted provided that the following conditions        *
 * are met:                                                                  *
 *                                                                           *
 * 1. Redistributions of source code must retain the above copyright notice, *
 *    this list of conditions and the following disclaimer.                  *
 *                                                                           *
 * 2. Redistributions in binary form must reproduce the above copyright      *
 *    notice, this list of conditions and the following disclaimer in the    *
 *    documentation and/or other materials provided with the distribution.   *
 *                                                                           *
 * 3. Neither the name of the copyright holder nor the names of its          *
 *    contributors may be used to endorse or promote products derived from   *
 *    this software without specific prior written permission.               *
 *                                                                           *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
39 40 41 42 43
*                                                                            *
\*===========================================================================*/

/*===========================================================================*\
*                                                                            *
Jan Möbius's avatar
Jan Möbius committed
44 45 46
*   $Revision$                                                       *
*   $LastChangedBy$                                                *
*   $Date$                     *
47 48 49 50 51
*                                                                            *
\*===========================================================================*/

//=============================================================================
//
52
//  CLASS InfoMeshObjectPlugin - IMPLEMENTATION
53 54 55 56 57 58 59 60 61 62 63 64 65
//
//=============================================================================


//== INCLUDES =================================================================


#include "MeshObjectInfoPlugin.hh"

#include <MeshTools/MeshInfoT.hh>

#include <Math_Tools/Math_Tools.hh>

66 67
#include "ValenceHistogramDialog.hh"

68
#if QT_VERSION >= 0x050000
69 70 71 72
#else
#include <QtGui>
#endif

73 74
//== IMPLEMENTATION ==========================================================

75 76 77

InfoMeshObjectPlugin::InfoMeshObjectPlugin() :
        info_(0),
78 79 80
        infoBar_(0),
        lastPickedObject_(0),
        lastPickedObjectId_(-1)
81 82 83
{
}

84 85
InfoMeshObjectPlugin::~InfoMeshObjectPlugin() {

86
  //Info bar and dialog will be deleted by core widget
87 88
}

89

90
void InfoMeshObjectPlugin::initializePlugin() {
91

92 93 94
}

/// initialize the plugin
95
void InfoMeshObjectPlugin::pluginsInitialized() {
96 97 98 99

  //set the slot descriptions
  setDescriptions();

100
  if ( OpenFlipper::Options::gui()) {
101 102 103 104 105 106 107

    // Create info bar
    infoBar_ = new InfoBar();

    // Create info dialog
    info_ = new InfoDialog();

108 109 110
    connect(info_->valenceHistograms_pb, SIGNAL( clicked() ),
            this, SLOT( slotShowHistogram() ));

111 112 113
    // Set default pick mode in dialog box
    info_->pickMode->setCurrentIndex(0); // PICK_FACES

114 115 116
    emit addWidgetToStatusbar(infoBar_);
    infoBar_->hideCounts();
  }
117 118 119 120 121
  
}

//-----------------------------------------------------------------------------

122
DataType InfoMeshObjectPlugin::supportedDataTypes() {
123 124 125 126 127 128
    return DataType(DATA_POLY_MESH | DATA_TRIANGLE_MESH);
}

//-----------------------------------------------------------------------------

template< class MeshT >
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
void InfoMeshObjectPlugin::printMeshInfo( MeshT* _mesh , int _id, unsigned int _index, ACG::Vec3d& _hitPoint ) {

  bool face   = false;
  bool edge   = false;
  bool vertex = false;

  int closestVertexIndex = -1;
  int closestEdgeIndex   = -1;

  switch (info_->pickMode->currentIndex() ) {
    case 0 : //Face
      closestVertexIndex = getClosestVertexInFace(_mesh, _index, _hitPoint);
      closestEdgeIndex   = getClosestEdgeInFace  (_mesh, _index, _hitPoint);
      face = true;
      break;
    case 1 : //Edge
      closestVertexIndex = getClosestVertexFromEdge(_mesh, _index, _hitPoint);
      closestEdgeIndex   = _index;
      edge = true;
      break;
    case 2 : //Vertex
      closestVertexIndex = _index;
      vertex = true;
      break;
    default:
      emit log(LOGERR,"Error: unknown picking mode in printMeshInfo");
      return;
  }
157 158 159 160 161 162 163 164 165 166 167 168 169

  QLocale locale;

  QString name;

  // name
  BaseObject* obj = 0;
  if ( PluginFunctions::getObject(_id, obj) )
    info_->generalBox->setTitle( tr("General object information for %1").arg( obj->name() ) );

  // ID
  info_->id->setText( locale.toString(_id) );
  // 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 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193

  if ( face ) {

    // Picked Face
    info_->closestFaceLabel->setText( tr("Picked Face:") );
    info_->closestFaceLabel->show();
    info_->faceHandle->setText( locale.toString( _index ) );
    info_->faceHandle->show();

    // Closest Vertex
    info_->closestVertexLabel->setText( tr("Closest Vertex:") );
    info_->vertexHandle->setText( locale.toString( closestVertexIndex ) );

    // Closest Edge
    info_->closestEdgeLabel->setText( tr("Closest Edge:") );
    info_->edgeHandle->setText( locale.toString( closestEdgeIndex ) );
    info_->closestEdgeLabel->show();
    info_->edgeHandle->show();

194 195 196 197 198 199 200 201
    // Closest Edge Length
    info_->edgeLengthLabel->setText( tr("Closest Edge Length:") );
    info_->edgeLengthLabel->show();
    const typename MeshT::Point from = _mesh->point(_mesh->from_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
    const typename MeshT::Point to   = _mesh->point(_mesh->to_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
    info_->edgeLength->setText( locale.toString( (to - from).norm() ) );
    info_->edgeLength->show();

202 203 204 205 206 207
    //adjacent vertex handles
    typename MeshT::FaceHandle fh = _mesh->face_handle(_index);

    typename MeshT::FaceVertexIter fv_it = _mesh->fv_iter(fh);
    QString adjacentVertices;

Jan Möbius's avatar
Jan Möbius committed
208 209
    if ( fv_it.is_valid() ){
      adjacentVertices = QString::number( fv_it->idx() );
210 211 212
      ++fv_it;
    }

Jan Möbius's avatar
Jan Möbius committed
213 214
    while( fv_it.is_valid() ){
      adjacentVertices += "; " + QString::number( fv_it->idx() );
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
      ++fv_it;
    }

    info_->adjVertexHandles->setText( adjacentVertices );
    info_->adjVertexHandles->show();
    info_->adjacentVertexLabel->show();

    //normal
    info_->normalLabel->setText(tr("Normal of picked face:"));
    info_->normalX->setText( QString::number( _mesh->normal(fh)[0],'f' ) );
    info_->normalY->setText( QString::number( _mesh->normal(fh)[1],'f' ) );
    info_->normalZ->setText( QString::number( _mesh->normal(fh)[2],'f' ) );
    info_->normalLabel->show();
    info_->normalLeft->show();
    info_->normalX->show();
    info_->normalY->show();
    info_->normalZ->show();
    info_->normalRight->show();

    // closest vertex coordinates
    info_->closestVertexPosLabel->setText(tr("Closest Vertex on the mesh:"));

  } else if (edge) {

    // Adjacent Faces
    info_->closestFaceLabel->setText( tr("Adjacent Faces:") );
    info_->closestFaceLabel->show();
    typename MeshT::HalfedgeHandle he1 = _mesh->halfedge_handle(_mesh->edge_handle(_index),0);
    typename MeshT::HalfedgeHandle he2 = _mesh->halfedge_handle(_mesh->edge_handle(_index),1);

    int fh1 = _mesh->face_handle(he1).idx();
    int fh2 = _mesh->face_handle(he2).idx();

    info_->faceHandle->setText( locale.toString( fh1 ) + ";" + locale.toString( fh2 ) );
    info_->faceHandle->show();

    // Adjacent vertices
    info_->adjVertexHandles->setText(QString::number( _mesh->from_vertex_handle(he1).idx() ) + ";" + QString::number( _mesh->to_vertex_handle(he1).idx() ));
    info_->adjVertexHandles->show();
    info_->adjacentVertexLabel->show();

    // Closest Vertex
    info_->closestVertexLabel->setText( tr("Closest Vertex:") );
    info_->vertexHandle->setText( locale.toString( closestVertexIndex ) );

    // Picked Edge
    info_->closestEdgeLabel->setText( tr("Picked Edge:") );
    info_->edgeHandle->setText( locale.toString( closestEdgeIndex ) );
    info_->closestEdgeLabel->show();
    info_->edgeHandle->show();

266 267 268 269 270 271 272 273
    // Edge Length
    info_->edgeLengthLabel->setText( tr("Edge Length:") );
    info_->edgeLengthLabel->show();
    const typename MeshT::Point from = _mesh->point(_mesh->from_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
    const typename MeshT::Point to   = _mesh->point(_mesh->to_vertex_handle( _mesh->halfedge_handle( _mesh->edge_handle(closestEdgeIndex),0 ) ));
    info_->edgeLength->setText( locale.toString( (to - from).norm() ) );
    info_->edgeLength->show();

274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302
    // Normal
    info_->normalLabel->hide();
    info_->normalLeft->hide();
    info_->normalX->hide();
    info_->normalY->hide();
    info_->normalZ->hide();
    info_->normalRight->hide();

    // closest vertex coordinates
    info_->closestVertexPosLabel->setText(tr("Closest Vertex on the mesh:"));

  } else if (vertex) {

    // Faces
    info_->closestFaceLabel->hide();
    info_->faceHandle->hide();

    // Adjacent vertices
    info_->adjVertexHandles->hide();
    info_->adjacentVertexLabel->hide();

    // Closest Vertex
    info_->closestVertexLabel->setText( tr("Picked Vertex:") );
    info_->vertexHandle->setText( locale.toString( closestVertexIndex ) );

    // Closest Edge
    info_->closestEdgeLabel->hide();
    info_->edgeHandle->hide();

303 304 305 306
    // Edge Length
    info_->edgeLengthLabel->hide();
    info_->edgeLength->hide();

307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
    // Normal
    typename MeshT::VertexHandle vh = _mesh->vertex_handle(_index);
    info_->normalLabel->setText(tr("Normal of picked vertex:"));
    info_->normalX->setText( QString::number( _mesh->normal(vh)[0],'f' ) );
    info_->normalY->setText( QString::number( _mesh->normal(vh)[1],'f' ) );
    info_->normalZ->setText( QString::number( _mesh->normal(vh)[2],'f' ) );
    info_->normalLabel->show();
    info_->normalLeft->show();
    info_->normalX->show();
    info_->normalY->show();
    info_->normalZ->show();
    info_->normalRight->show();

    // closest vertex coordinates
    info_->closestVertexPosLabel->setText(tr("Picked Vertex on the mesh:"));

    // Adjacent Edges
    info_->closestFaceLabel->setText( tr("Adjacent Edges:") );
    info_->closestFaceLabel->show();

    //adjacent vertex handles

    typename MeshT::VertexEdgeIter ve_it = _mesh->ve_iter(vh);
    QString adjacentEdges;

Jan Möbius's avatar
Jan Möbius committed
332 333
    if ( ve_it.is_valid() ){
      adjacentEdges = QString::number( ve_it->idx() );
334 335 336
      ++ve_it;
    }

Jan Möbius's avatar
Jan Möbius committed
337 338
    while( ve_it.is_valid() ){
      adjacentEdges += "; " + QString::number( ve_it->idx() );
339 340 341 342 343 344 345 346 347 348 349 350 351
      ++ve_it;
    }

    info_->faceHandle->setText( adjacentEdges );
    info_->faceHandle->show();
  }

  // closest vertex coordinates
  info_->vertexX->setText( QString::number( _mesh->point( _mesh->vertex_handle(closestVertexIndex) )[0],'f' ) );
  info_->vertexY->setText( QString::number( _mesh->point( _mesh->vertex_handle(closestVertexIndex) )[1],'f' ) );
  info_->vertexZ->setText( QString::number( _mesh->point( _mesh->vertex_handle(closestVertexIndex) )[2],'f' ) );


352
  // Components
353 354
  int compo_count = MeshInfo::componentCount(_mesh);
  info_->components->setText( locale.toString(compo_count));
355
  // Boundaries
356 357
  int boundary_count = MeshInfo::boundaryCount(_mesh);
  info_->boundaries->setText( locale.toString(boundary_count) );
358
  // Genus
359 360 361 362 363
  int chi = _mesh->n_vertices();
  chi -= _mesh->n_edges();
  chi += _mesh->n_faces(); // chi = Euler characteristic
  // chi + n_holes = 2(n_components - genus) => genus = n_components - (chi + n_holes)/2;
  float genus = compo_count - 0.5*(chi + boundary_count);
364 365 366 367 368 369
  if(compo_count == 1 && boundary_count == 0)
    info_->genus->setText( QString::number(genus) );
  else if(compo_count != 1)
    info_->genus->setText( "(multiple components)" );
  else
    info_->genus->setText( "(not manifold)" );
370 371 372 373 374 375 376

  // Coordinates
  typename MeshT::VertexIter v_it;
  typename MeshT::VertexIter v_end = _mesh->vertices_end();

  float maxX = FLT_MIN;
  float minX = FLT_MAX;
377
  //float sumX = 0.0;
378 379
  float maxY = FLT_MIN;
  float minY = FLT_MAX;
380
  //float sumY = 0.0;
381 382
  float maxZ = FLT_MIN;
  float minZ = FLT_MAX;
383
  //float sumZ = 0.0;
384 385 386 387 388 389 390 391 392
  int minV = 999;
  int maxV = 0;
  int sumV = 0;
  float maxE = FLT_MIN;
  float minE = FLT_MAX;
  float sumE = 0.0;

  //iterate over all vertices
  for (v_it = _mesh->vertices_begin(); v_it != v_end; ++v_it){
Jan Möbius's avatar
Jan Möbius committed
393
    typename MeshT::Point p = _mesh->point( *v_it );
394 395
    if (p[0] < minX) minX = p[0];
    if (p[0] > maxX) maxX = p[0];
396
    //sumX += p[0];
397 398
    if (p[1] < minY) minY = p[1];
    if (p[1] > maxY) maxY = p[1];
399
    //sumY += p[1];
400 401
    if (p[2] < minZ) minZ = p[2];
    if (p[2] > maxZ) maxZ = p[2];
402
    //sumZ += p[2];
403 404 405 406 407 408 409



    //check valence + edge length
    int valence = 0;
    typename MeshT::VertexVertexIter vv_it;

Jan Möbius's avatar
Jan Möbius committed
410
    for (vv_it=_mesh->vv_iter( *v_it ); vv_it.is_valid(); ++vv_it){
411 412
      valence++;

Jan Möbius's avatar
Jan Möbius committed
413
      typename MeshT::Point p2 = _mesh->point( *vv_it );
414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
      typename MeshT::Scalar len = (p2 - p).norm();

      if (len < minE) minE = len;
      if (len > maxE) maxE = len;
      sumE += len;
    }

    if (valence < minV) minV = valence;
    if (valence > maxV) maxV = valence;
    sumV += valence;
  }

  
  //valence
  info_->valenceMin->setText( QString::number(minV) );
  info_->valenceMean->setText( QString::number( sumV / (float)_mesh->n_vertices(),'f' ) );
  info_->valenceMax->setText( QString::number(maxV) );

  //edge length
  info_->edgeMin->setText( QString::number(minE,'f') );
  info_->edgeMean->setText( QString::number( sumE / (_mesh->n_edges()*2),'f' )  );
  info_->edgeMax->setText( QString::number(maxE,'f') );

  //get aspect ratio

  typename MeshT::FaceIter f_it;
  typename MeshT::FaceIter f_end = _mesh->faces_end();

  float maxA = FLT_MIN;
  float minA = FLT_MAX;
  float sumA = 0.0;
  float maxI = FLT_MIN;
  float minI = FLT_MAX;
447
  //float sumI = 0.0;
448 449 450 451
  float maxD = FLT_MIN;
  float minD = FLT_MAX;
  float sumD = 0.0;
  int numD = 0;
452 453
  unsigned int maxFValence = std::numeric_limits<unsigned int>::min();
  unsigned int minFValence = std::numeric_limits<unsigned int>::max();
454
  size_t sumFValence = 0;
455 456 457

  //iterate over all faces
  for (f_it = _mesh->faces_begin(); f_it != f_end; ++f_it){
Jan Möbius's avatar
Jan Möbius committed
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 469 470 471 472 473 474 475 476 477

    if (aspect < minA) minA = aspect;
    if (aspect > maxA) maxA = aspect;
    sumA += aspect;

    //inner triangle angles

    double angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v2 - v0) | MathTools::sane_normalized(v1 - v0) )));

    if (angle < minI) minI = angle;
    if (angle > maxI) maxI = angle;
478
    //sumI += angle;
479 480 481 482 483

    angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v2 - v1) | MathTools::sane_normalized(v0 - v1) )));

    if (angle < minI) minI = angle;
    if (angle > maxI) maxI = angle;
484
    //sumI += angle;
485 486 487 488 489

    angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v1 - v2) | MathTools::sane_normalized(v0 - v2) )));

    if (angle < minI) minI = angle;
    if (angle > maxI) maxI = angle;
490
    //sumI += angle;
491 492 493

    //compute dihedral angles
    typename MeshT::FaceFaceIter ff_it;
494
    const typename MeshT::Normal n1 = _mesh->normal(*f_it);
495

Jan Möbius's avatar
Jan Möbius committed
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 501 502 503 504 505 506

      angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(n1) | MathTools::sane_normalized(n2) )));

      if (angle < minD) minD = angle;
      if (angle > maxD) maxD = angle;
      sumD += angle;
      numD ++;
    }
507 508

    const unsigned int valence = _mesh->valence(*f_it);
509 510 511
    minFValence = std::min(minFValence, valence);
    maxFValence = std::max(maxFValence, valence);
    sumFValence += valence;
512 513 514 515 516 517 518 519 520 521
  }

  info_->aspectMin->setText( QString::number(minA,'f') );
  info_->aspectMean->setText( QString::number( sumA / _mesh->n_faces(),'f' ) );
  info_->aspectMax->setText( QString::number(maxA,'f') );

  info_->angleMin->setText( QString::number(minI,'f') );
  info_->angleMean->setText( "-" );
  info_->angleMax->setText( QString::number(maxI,'f')  );

522 523
  info_->faceValenceMin->setText(trUtf8("%1").arg(minFValence));
  info_->faceValenceMax->setText(trUtf8("%1").arg(maxFValence));
524 525
  info_->faceValenceMean->setText(trUtf8("%1").arg(
          static_cast<float>(sumFValence) / _mesh->n_faces()));
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
  
  // Only one face or no face -> don't output angles 
  if ( _mesh->n_faces() > 1 ) {
    info_->dihedralMin->setText( QString::number(minD,'f') );
    info_->dihedralMean->setText( QString::number( sumD / numD,'f' ) );
    info_->dihedralMax->setText( QString::number(maxD,'f') );
  } else {
    info_->dihedralMin->setText( "-" );
    info_->dihedralMean->setText( "-" );
    info_->dihedralMax->setText( "-" );
  }

  //Calculate Bounding Box(min,max,cog)
  ACG::Vec3d min;
  ACG::Vec3d max;
541
  MeshInfo::getBoundingBox(_mesh, min, max);
542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558

  //Bounding Box Size
  ACG::Vec3d diff = max-min;

  info_->bbMinX->setText( QString::number(min[0],'f') );
  info_->bbMinY->setText( QString::number(min[1],'f') );
  info_->bbMinZ->setText( QString::number(min[2],'f') );

  info_->bbMaxX->setText( QString::number(max[0],'f') );
  info_->bbMaxY->setText( QString::number(max[1],'f') );
  info_->bbMaxZ->setText( QString::number(max[2],'f') );

  info_->bbSizeX->setText( QString::number(diff[0],'f') );
  info_->bbSizeY->setText( QString::number(diff[1],'f') );
  info_->bbSizeZ->setText( QString::number(diff[2],'f') );

  //COG
559
  ACG::Vec3d cog = MeshInfo::cog(_mesh);
560 561 562 563 564 565 566 567 568 569 570 571

  info_->cogX->setText( QString::number(cog[0],'f') );
  info_->cogY->setText( QString::number(cog[1],'f') );
  info_->cogZ->setText( QString::number(cog[2],'f') );

  //hitpoint
  info_->pointX->setText( QString::number( _hitPoint[0],'f' ) );
  info_->pointY->setText( QString::number( _hitPoint[1],'f' ) );
  info_->pointZ->setText( QString::number( _hitPoint[2],'f' ) );

  info_->setWindowFlags(info_->windowFlags() | Qt::WindowStaysOnTopHint);

Matthias Möller's avatar
Matthias Möller committed
572

573 574 575 576 577 578 579
  info_->show();
}

//----------------------------------------------------------------------------------------------

/** \brief Find closest vertex to selection
 *
580
 * @param _mesh     Reference to the mesh
581
 * @param _face_idx Index of the face that has been clicked on
582 583 584
 * @param _hitPoint The point that is used as the reference
 *
 * @return index of the closest vertex of the face to the hitpoint
585 586 587
 */

template <class MeshT>
588
int InfoMeshObjectPlugin::getClosestVertexInFace(MeshT* _mesh, int _face_idx, ACG::Vec3d& _hitPoint) {
589 590 591 592 593 594 595 596 597

    typename MeshT::FaceVertexIter fv_it;

    int closest_v_idx = 0;
    double dist = DBL_MAX;

    ACG::Vec3d vTemp = ACG::Vec3d(0.0, 0.0, 0.0);
    typename MeshT::Point p;

Jan Möbius's avatar
Jan Möbius committed
598
    for (fv_it = _mesh->fv_iter(_mesh->face_handle(_face_idx)); fv_it.is_valid(); ++fv_it){
599

Jan Möbius's avatar
Jan Möbius committed
600
      p = _mesh->point( *fv_it );
601 602 603

      // Find closest vertex to selection
      vTemp = ACG::Vec3d(p[0], p[1], p[2]);
Jan Möbius's avatar
Jan Möbius committed
604
      const double temp_dist = (vTemp - _hitPoint).length();
605 606 607

      if (temp_dist < dist) {
          dist = temp_dist;
Jan Möbius's avatar
Jan Möbius committed
608
          closest_v_idx = fv_it->idx();
609 610 611 612 613 614 615 616 617 618
      }

    }
    return closest_v_idx;
}

//-------------------------------------------------------------------------------------------

/** \brief Find closest edge to selection
 *
619
 * @param _mesh     Reference to the mesh
620
 * @param _face_idx Index of the face that has been clicked on
621
 * @param _hitPoint The point which will be tested
622 623
 *
 * @return index of the closest edge in the face to the hitpoint
624 625 626
 */

template <class MeshT>
627
int InfoMeshObjectPlugin::getClosestEdgeInFace(MeshT* _mesh, int _face_idx, const ACG::Vec3d& _hitPoint) {
628 629 630 631 632

    typename MeshT::ConstFaceHalfedgeIter fh_it;
    typename MeshT::VertexHandle v1, v2;
    typename MeshT::Point p1, p2;

Jan Möbius's avatar
Jan Möbius committed
633 634
    ACG::Vec3d vp1, vp2, h;
    double dist = DBL_MAX;
635 636
    int closest_e_handle = 0;

Jan Möbius's avatar
Jan Möbius committed
637
    for (fh_it = _mesh->fh_iter(_mesh->face_handle(_face_idx)); fh_it.is_valid(); ++fh_it){
638

Jan Möbius's avatar
Jan Möbius committed
639 640
      v1 = _mesh->from_vertex_handle(*fh_it);
      v2 = _mesh->to_vertex_handle(*fh_it);
641 642 643 644 645 646 647

      p1 = _mesh->point(v1);
      p2 = _mesh->point(v2);

      vp1 = ACG::Vec3d(p1[0], p1[1], p1[2]);
      vp2 = ACG::Vec3d(p2[0], p2[1], p2[2]);

Jan Möbius's avatar
Jan Möbius committed
648
      const ACG::Vec3d e = (vp2 - vp1).normalized();
Jan Möbius's avatar
Jan Möbius committed
649
      const ACG::Vec3d g = _hitPoint - vp1;
Jan Möbius's avatar
Jan Möbius committed
650
      const double x = g | e;
651

Jan Möbius's avatar
Jan Möbius committed
652
      const double temp_dist = (_hitPoint - (vp1 + x * e)).length();
653 654 655 656 657 658 659 660 661 662 663

      if (temp_dist < dist) {
          dist = temp_dist;
      }
    }

    return closest_e_handle;
}

//----------------------------------------------------------------------------------------------

664 665
/** \brief Find closest vertex on the edge (endpoint)
 *
666 667 668 669 670
 * @param _mesh     Reference to the mesh
 * @param _edge_idx Index of the edge that has been clicked on
 * @param _hitPoint The point which will be tested
 *
 * @return index of the closest vertex on the edge
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
 */

template <class MeshT>
int InfoMeshObjectPlugin::getClosestVertexFromEdge(MeshT* _mesh, int _edge_idx, ACG::Vec3d& _hitPoint) {

    ACG::Vec3d toVertex   = _mesh->point( _mesh->to_vertex_handle(   _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 )) );
    ACG::Vec3d fromVertex = _mesh->point( _mesh->from_vertex_handle( _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 )) );

    double distTo   = (_hitPoint - toVertex  ).norm();
    double distFrom = (_hitPoint - fromVertex).norm();

    if ( distTo > distFrom )
      return _mesh->from_vertex_handle( _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 ) ).idx();
    else
      return _mesh->to_vertex_handle(   _mesh->halfedge_handle(_mesh->edge_handle(_edge_idx),0 ) ).idx();

}

//----------------------------------------------------------------------------------------------

691
void
692
InfoMeshObjectPlugin::
693 694 695 696 697
  slotInformationRequested(const QPoint _clickedPoint, DataType _type) {

    // Only respond on mesh objects
    if((_type != DATA_TRIANGLE_MESH) && (_type != DATA_POLY_MESH)) return;

698 699 700 701
    ACG::SceneGraph::PickTarget target = ACG::SceneGraph::PICK_FACE;

    unsigned int   node_idx, target_idx;
    ACG::Vec3d     hit_point;
702

703 704
    if (info_->isHidden())
    {
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736
      //user couldn't select the pick mode,
      //so we have to do this
      target = ACG::SceneGraph::PICK_ANYTHING;
      if (!PluginFunctions::scenegraphPick(target, _clickedPoint, node_idx, target_idx, &hit_point))
        return;

      BaseObjectData* object;
      if (!PluginFunctions::getPickedObject(node_idx, object) )
        return;

      //object is picked, now we can decide, what the user wants to pick
      //priority: face > edge > vertex
      if ( object->dataType(DATA_TRIANGLE_MESH) )
      {
        TriMesh* mesh = PluginFunctions::triMesh(object);
        if (mesh->n_faces() != 0)
          info_->pickMode->setCurrentIndex(0);
        else if (mesh->n_edges() != 0)
          info_->pickMode->setCurrentIndex(1);
        else
          info_->pickMode->setCurrentIndex(2);
      }
      else if ( object->dataType(DATA_POLY_MESH) )
      {
        PolyMesh* mesh = PluginFunctions::polyMesh(object);
        if (mesh->n_faces() != 0)
          info_->pickMode->setCurrentIndex(0);
        else if (mesh->n_edges() != 0)
          info_->pickMode->setCurrentIndex(1);
        else
          info_->pickMode->setCurrentIndex(2);
      }
737 738
    }

739 740 741 742 743
    target = ACG::SceneGraph::PICK_FACE;
    if (info_->pickMode->currentIndex() == 1 )
      target = ACG::SceneGraph::PICK_EDGE;
    else if (info_->pickMode->currentIndex() == 2 )
      target = ACG::SceneGraph::PICK_VERTEX;
744

745
    if (PluginFunctions::scenegraphPick(target, _clickedPoint, node_idx, target_idx, &hit_point)) {
746 747 748 749 750 751
      BaseObjectData* object;

      if ( PluginFunctions::getPickedObject(node_idx, object) ) {

         emit log( LOGINFO , object->getObjectinfo() );

752 753 754
         lastPickedObject_ = object;
         lastPickedObjectId_ = object->id();

755 756 757 758
         if ( object->dataType(DATA_TRIANGLE_MESH) )
           printMeshInfo( PluginFunctions::triMesh(object) , object->id(), target_idx, hit_point );

         if ( object->dataType(DATA_POLY_MESH) )
759
           printMeshInfo( PluginFunctions::polyMesh(object) , object->id(), target_idx, hit_point );
760 761 762 763
      } else {
          lastPickedObject_ = 0;
          return;
      }
764
    }
765 766 767 768
    else
    {
      emit log( LOGERR , tr("Unable to pick object.") );
    }
769 770 771 772 773
}

//------------------------------------------------------------------------------

template< class MeshT >
774
void InfoMeshObjectPlugin::getEdgeLengths(MeshT* _mesh, double &min, double &max, double &mean)
775 776 777 778 779 780 781 782 783
{
  typename MeshT::ConstEdgeIter e_it(_mesh->edges_sbegin()),
                                e_end(_mesh->edges_end());

  min = FLT_MAX;
  max = FLT_MIN;
  mean = 0.0;
  for (; e_it!=e_end; ++e_it)
  {
Jan Möbius's avatar
Jan Möbius committed
784 785
    typename MeshT::Scalar len = (_mesh->point(_mesh->to_vertex_handle(_mesh->halfedge_handle(*e_it, 0))) -
                                  _mesh->point(_mesh->to_vertex_handle(_mesh->halfedge_handle(*e_it, 1)))).norm ();
786 787 788 789 790 791 792 793 794 795
    if (len < min) min = len;
    if (len > max) max = len;
    mean += len;
  }

  mean /= _mesh->n_edges();
}

//------------------------------------------------------------------------------

796
bool InfoMeshObjectPlugin::getEdgeLengths(int _id, double &min, double &max, double &mean)
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834
{
  BaseObjectData* object;
  if ( ! PluginFunctions::getObject(_id,object) )
    return false;

  if ( object == 0){
    emit log(LOGERR, tr("Unable to get object"));
    return false;
  }

  if ( object->dataType(DATA_TRIANGLE_MESH) ) {
    TriMesh* mesh = PluginFunctions::triMesh(object);

    if ( mesh == 0 ) {
      emit log(LOGERR,tr("Unable to get mesh"));
      return false;
    }

    getEdgeLengths (mesh, min, max, mean);
    return true;

  } else {
    PolyMesh* mesh = PluginFunctions::polyMesh(object);

    if ( mesh == 0 ) {
      emit log(LOGERR,tr("Unable to get mesh"));
      return false;
    }

    getEdgeLengths (mesh, min, max, mean);
    return true;
  }

  return false;
}

//------------------------------------------------------------------------------

835
void InfoMeshObjectPlugin::updateData( int _identifier , const UpdateType& _type, const bool _deleted){
836

837
  if ( !infoBar_ ) {
838 839
     return;
   }
840

841 842
  BaseObjectData* object;
  PluginFunctions::getObject(_identifier,object);
843

844 845 846 847 848
  if (_identifier == lastPickedObjectId_ && _deleted) {
      lastPickedObject_ = 0;
      lastPickedObjectId_ = -1;
  }

849 850 851 852 853 854
  // Last object that is target has been removed.
  if ( _deleted && object && object->target() && (PluginFunctions::targetCount() == 1) ) {
    infoBar_->hideCounts();
    return;
  }

855 856 857
   // We only show the information in the status bar if one target mesh is selected or
   // If 2 targets where selected, where one is deleted which was target
   if ( PluginFunctions::targetCount() == 1 || ( _deleted && (PluginFunctions::targetCount() == 2) && object && object->target() ) ) {
858

859 860


861 862 863 864 865 866 867 868 869 870 871
     // The object that caused the update is not a target anymore.
     // Therefore we need to get the remaining target by iteration.
     // 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
     if ( object && !object->target() ) {
       for ( PluginFunctions::ObjectIterator o_it = PluginFunctions::ObjectIterator(PluginFunctions::TARGET_OBJECTS);  o_it != PluginFunctions::objectsEnd(); ++o_it ) {
         if ( !_deleted || ( o_it->id() != _identifier ) ) {
           object = *o_it;
           break;
         }
       }
     }
872

873 874
     // We only need to update something, if the updated object is the target object
     if (object && object->target() ) {
875

876
       if (object->dataType(DATA_TRIANGLE_MESH)){
877

878
         TriMesh* mesh = PluginFunctions::triMesh(object);
879

880 881 882
         infoBar_->vertices->setText( QLocale::system().toString( qulonglong(mesh->n_vertices()) ) );
         infoBar_->edges->setText( QLocale::system().toString( qulonglong(mesh->n_edges()) ) );
         infoBar_->faces->setText( QLocale::system().toString( qulonglong(mesh->n_faces()) ) );
883

884
         infoBar_->showCounts();
885

886 887
         return;
       }
888

889
       if (object->dataType(DATA_POLY_MESH)){
890

891
         PolyMesh* mesh = PluginFunctions::polyMesh(object);
892

893 894 895
         infoBar_->vertices->setText( QLocale::system().toString( qulonglong(mesh->n_vertices()) ) );
         infoBar_->edges->setText( QLocale::system().toString( qulonglong(mesh->n_edges()) ) );
         infoBar_->faces->setText( QLocale::system().toString( qulonglong(mesh->n_faces()) ) );
896

897 898 899
         infoBar_->showCounts();
         return;
       }
900

901
     }
902

903
     infoBar_->hideCounts();
904

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
   } else {
     // Display only count information
     if ( (PluginFunctions::targetCount() > 1) && object ) {
       if ( _deleted && object->target() ) {
         infoBar_->showTargetCount( PluginFunctions::targetCount() - 1);
       } else {
         infoBar_->showTargetCount( PluginFunctions::targetCount() );
       }
     } else
       infoBar_->hideCounts();
   }

}

//------------------------------------------------------------------------------

void InfoMeshObjectPlugin::slotObjectUpdated( int _identifier , const UpdateType& _type){

  updateData(_identifier,_type,false);
924

925 926 927 928
}

//------------------------------------------------------------------------------

929
void InfoMeshObjectPlugin::slotObjectSelectionChanged( int _identifier ){
930 931 932 933 934 935 936
  updateData(_identifier,UPDATE_ALL,false);
}

//------------------------------------------------------------------------------

void InfoMeshObjectPlugin::objectDeleted( int _identifier ){
  updateData(_identifier,UPDATE_ALL,true);
937 938
}

939

940 941
//------------------------------------------------------------------------------

942
void InfoMeshObjectPlugin::slotAllCleared(){
943 944
  if ( infoBar_ )
    infoBar_->hideCounts();
945

946 947
}

948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970
void InfoMeshObjectPlugin::slotShowHistogram() {
    if (!lastPickedObject_) return;

    ValenceHistogramDialog *dialog = 0;
    {
        TriMeshObject *tmo = dynamic_cast<TriMeshObject*>(lastPickedObject_);
        if (tmo) {
            dialog = new ValenceHistogramDialog(*tmo->mesh(), info_);
        }
    }

    if (!dialog) {
        PolyMeshObject *pmo = dynamic_cast<PolyMeshObject*>(lastPickedObject_);
        if (pmo) {
            dialog = new ValenceHistogramDialog(*pmo->mesh(), info_);
        }
    }

    dialog->setAttribute(Qt::WA_DeleteOnClose, true);
    dialog->show();
    dialog->raise();
}

971 972 973
#if QT_VERSION < 0x050000
  Q_EXPORT_PLUGIN2( InfoMeshObjectPlugin , InfoMeshObjectPlugin );
#endif
974 975