MeshObjectInfoPlugin.cc 32.5 KB
Newer Older
1
2
3
/*===========================================================================*\
*                                                                            *
*                              OpenFlipper                                   *
Martin Schultz's avatar
Martin Schultz committed
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
*                                                                            *
\*===========================================================================*/

Jan Möbius's avatar
Jan Möbius committed
42

43
44
45

//=============================================================================
//
46
//  CLASS InfoMeshObjectPlugin - IMPLEMENTATION
47
48
49
50
51
52
53
54
55
56
57
58
59
//
//=============================================================================


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


#include "MeshObjectInfoPlugin.hh"

#include <MeshTools/MeshInfoT.hh>

#include <Math_Tools/Math_Tools.hh>

60
61
#include "ValenceHistogramDialog.hh"

62

63
64
//== IMPLEMENTATION ==========================================================

65
66
67

InfoMeshObjectPlugin::InfoMeshObjectPlugin() :
        info_(0),
68
69
70
        infoBar_(0),
        lastPickedObject_(0),
        lastPickedObjectId_(-1)
71
72
73
{
}

Jan Möbius's avatar
Jan Möbius committed
74
75
InfoMeshObjectPlugin::~InfoMeshObjectPlugin() {

76
  //Info bar and dialog will be deleted by core widget
Jan Möbius's avatar
Jan Möbius committed
77
78
}

79

80
void InfoMeshObjectPlugin::initializePlugin() {
81

82
83
84
}

/// initialize the plugin
85
void InfoMeshObjectPlugin::pluginsInitialized() {
86
87
88
89

  //set the slot descriptions
  setDescriptions();

90
  if ( OpenFlipper::Options::gui()) {
91
92
93
94
95
96
97

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

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

98
99
100
    connect(info_->valenceHistograms_pb, SIGNAL( clicked() ),
            this, SLOT( slotShowHistogram() ));

101
102
103
    // Set default pick mode in dialog box
    info_->pickMode->setCurrentIndex(0); // PICK_FACES

104
105
106
    emit addWidgetToStatusbar(infoBar_);
    infoBar_->hideCounts();
  }
107
108
109
110
111
  
}

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

112
DataType InfoMeshObjectPlugin::supportedDataTypes() {
113
114
115
116
117
118
    return DataType(DATA_POLY_MESH | DATA_TRIANGLE_MESH);
}

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

template< class MeshT >
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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;
  }
147
148
149
150
151
152
153
154
155
156
157
158
159

  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
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
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183

  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();

184
185
186
187
188
189
190
191
    // 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();

192
193
194
195
196
197
    //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
OM3  
Jan Möbius committed
198
199
    if ( fv_it.is_valid() ){
      adjacentVertices = QString::number( fv_it->idx() );
200
201
202
      ++fv_it;
    }

Jan Möbius's avatar
OM3  
Jan Möbius committed
203
204
    while( fv_it.is_valid() ){
      adjacentVertices += "; " + QString::number( fv_it->idx() );
205
206
207
208
209
210
211
212
213
214
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
      ++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();

256
257
258
259
260
261
262
263
    // 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();

264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
    // 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();

293
294
295
296
    // Edge Length
    info_->edgeLengthLabel->hide();
    info_->edgeLength->hide();

297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
    // 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
OM3  
Jan Möbius committed
322
323
    if ( ve_it.is_valid() ){
      adjacentEdges = QString::number( ve_it->idx() );
324
325
326
      ++ve_it;
    }

Jan Möbius's avatar
OM3  
Jan Möbius committed
327
328
    while( ve_it.is_valid() ){
      adjacentEdges += "; " + QString::number( ve_it->idx() );
329
330
331
332
333
334
335
336
337
338
339
340
341
      ++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' ) );


342
  // Components
343
344
  int compo_count = MeshInfo::componentCount(_mesh);
  info_->components->setText( locale.toString(compo_count));
345
  // Boundaries
346
347
  int boundary_count = MeshInfo::boundaryCount(_mesh);
  info_->boundaries->setText( locale.toString(boundary_count) );
348
  // Genus
349
350
351
352
353
  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);
354
355
356
357
358
359
  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)" );
360
361
362
363
364
365
366

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

  float maxX = FLT_MIN;
  float minX = FLT_MAX;
Jan Möbius's avatar
Jan Möbius committed
367
  //float sumX = 0.0;
368
369
  float maxY = FLT_MIN;
  float minY = FLT_MAX;
Jan Möbius's avatar
Jan Möbius committed
370
  //float sumY = 0.0;
371
372
  float maxZ = FLT_MIN;
  float minZ = FLT_MAX;
Jan Möbius's avatar
Jan Möbius committed
373
  //float sumZ = 0.0;
374
375
376
377
378
379
380
381
382
  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
OM3  
Jan Möbius committed
383
    typename MeshT::Point p = _mesh->point( *v_it );
384
385
    if (p[0] < minX) minX = p[0];
    if (p[0] > maxX) maxX = p[0];
Jan Möbius's avatar
Jan Möbius committed
386
    //sumX += p[0];
387
388
    if (p[1] < minY) minY = p[1];
    if (p[1] > maxY) maxY = p[1];
Jan Möbius's avatar
Jan Möbius committed
389
    //sumY += p[1];
390
391
    if (p[2] < minZ) minZ = p[2];
    if (p[2] > maxZ) maxZ = p[2];
Jan Möbius's avatar
Jan Möbius committed
392
    //sumZ += p[2];
393
394
395
396
397
398
399



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

Jan Möbius's avatar
OM3  
Jan Möbius committed
400
    for (vv_it=_mesh->vv_iter( *v_it ); vv_it.is_valid(); ++vv_it){
401
402
      valence++;

Jan Möbius's avatar
OM3  
Jan Möbius committed
403
      typename MeshT::Point p2 = _mesh->point( *vv_it );
404
405
406
407
408
409
410
411
412
413
414
415
      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;
  }

416
417
418
  //=============================
  // Vertex valence
  //=============================
419
420
421
422
  info_->valenceMin->setText( QString::number(minV) );
  info_->valenceMean->setText( QString::number( sumV / (float)_mesh->n_vertices(),'f' ) );
  info_->valenceMax->setText( QString::number(maxV) );

423
424
425
426
427
428
429
430
431
432
433
434
435
  //=============================
  // edge length
  //=============================
  if (_mesh->n_edges() >0 ) {
    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') );
  } else {
    info_->edgeMin->setText( "-" );
    info_->edgeMean->setText( "-" );
    info_->edgeMax->setText( "-" );
  }

436

437
438
439
440
441
442
  //=============================
  // Triangle information
  //=============================
  if (_mesh->n_faces() > 0 ) {
    typename MeshT::FaceIter f_it;
    typename MeshT::FaceIter f_end = _mesh->faces_end();
443

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

458
459
460
    //iterate over all faces
    for (f_it = _mesh->faces_begin(); f_it != f_end; ++f_it){
      typename MeshT::ConstFaceVertexIter cfv_it = _mesh->cfv_iter(*f_it);
461

462
463
464
465
466
      const typename MeshT::Point v0 = _mesh->point( *cfv_it );
      ++cfv_it;
      const typename MeshT::Point v1 = _mesh->point( *cfv_it );
      ++cfv_it;
      const typename MeshT::Point v2 = _mesh->point( *cfv_it );
467

468
      const float aspect = ACG::Geometry::aspectRatio(v0, v1, v2);
469

470
471
472
      if (aspect < minA) minA = aspect;
      if (aspect > maxA) maxA = aspect;
      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
479
480
      if (angle < minI) minI = angle;
      if (angle > maxI) maxI = angle;
      //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
485
486
      if (angle < minI) minI = angle;
      if (angle > maxI) maxI = angle;
      //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
491
492
      if (angle < minI) minI = angle;
      if (angle > maxI) maxI = angle;
      //sumI += angle;
493

494
495
496
      //compute dihedral angles
      typename MeshT::FaceFaceIter ff_it;
      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
505
506
507
508
509
510
511
512
513
        if (angle < minD) minD = angle;
        if (angle > maxD) maxD = angle;
        sumD += angle;
        numD ++;
      }

      const unsigned int valence = _mesh->valence(*f_it);
      minFValence = std::min(minFValence, valence);
      maxFValence = std::max(maxFValence, valence);
      sumFValence += valence;
514
    }
515

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


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

525
526
527
    info_->faceValenceMin->setText(tr("%1").arg(minFValence));
    info_->faceValenceMax->setText(tr("%1").arg(maxFValence));
    info_->faceValenceMean->setText(tr("%1").arg( static_cast<float>(sumFValence) / _mesh->n_faces()));
528
529
530
531
532
533
534
535
536
537

    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( "-" );
    }
538
  } else {
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553

    // No triangles, no info
    info_->aspectMin->setText( "-" );
    info_->aspectMean->setText( "-" );
    info_->aspectMax->setText( "-" );


    info_->angleMin->setText( "-" );
    info_->angleMean->setText( "-" );
    info_->angleMax->setText( "-"  );

    info_->faceValenceMin->setText("-");
    info_->faceValenceMax->setText("-");
    info_->faceValenceMean->setText("-");

554
555
556
557
558
    info_->dihedralMin->setText( "-" );
    info_->dihedralMean->setText( "-" );
    info_->dihedralMax->setText( "-" );
  }

559

560
561
562
  //Calculate Bounding Box(min,max,cog)
  ACG::Vec3d min;
  ACG::Vec3d max;
563
  MeshInfo::getBoundingBox(_mesh, min, max);
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580

  //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
581
  ACG::Vec3d cog = MeshInfo::cog(_mesh);
582
583
584
585
586
587
588
589
590
591
592
593

  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
594

595
596
597
598
599
600
601
  info_->show();
}

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

/** \brief Find closest vertex to selection
 *
Jan Möbius's avatar
Jan Möbius committed
602
 * @param _mesh     Reference to the mesh
603
 * @param _face_idx Index of the face that has been clicked on
Jan Möbius's avatar
Jan Möbius committed
604
605
606
 * @param _hitPoint The point that is used as the reference
 *
 * @return index of the closest vertex of the face to the hitpoint
607
608
609
 */

template <class MeshT>
610
int InfoMeshObjectPlugin::getClosestVertexInFace(MeshT* _mesh, int _face_idx, ACG::Vec3d& _hitPoint) {
611
612
613
614
615
616
617
618
619

    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
OM3  
Jan Möbius committed
620
    for (fv_it = _mesh->fv_iter(_mesh->face_handle(_face_idx)); fv_it.is_valid(); ++fv_it){
621

Jan Möbius's avatar
OM3  
Jan Möbius committed
622
      p = _mesh->point( *fv_it );
623
624
625

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

      if (temp_dist < dist) {
          dist = temp_dist;
Jan Möbius's avatar
OM3  
Jan Möbius committed
630
          closest_v_idx = fv_it->idx();
631
632
633
634
635
636
637
638
639
640
      }

    }
    return closest_v_idx;
}

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

/** \brief Find closest edge to selection
 *
Jan Möbius's avatar
Jan Möbius committed
641
 * @param _mesh     Reference to the mesh
642
 * @param _face_idx Index of the face that has been clicked on
Jan Möbius's avatar
Jan Möbius committed
643
 * @param _hitPoint The point which will be tested
Jan Möbius's avatar
Jan Möbius committed
644
645
 *
 * @return index of the closest edge in the face to the hitpoint
646
647
648
 */

template <class MeshT>
Jan Möbius's avatar
Jan Möbius committed
649
int InfoMeshObjectPlugin::getClosestEdgeInFace(MeshT* _mesh, int _face_idx, const ACG::Vec3d& _hitPoint) {
650
651
652
653
654

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

Jan Möbius's avatar
Jan Möbius committed
655
656
    ACG::Vec3d vp1, vp2, h;
    double dist = DBL_MAX;
657
658
    int closest_e_handle = 0;

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

Jan Möbius's avatar
OM3  
Jan Möbius committed
661
662
      v1 = _mesh->from_vertex_handle(*fh_it);
      v2 = _mesh->to_vertex_handle(*fh_it);
663
664
665
666
667
668
669

      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
670
      const ACG::Vec3d e = (vp2 - vp1).normalized();
Jan Möbius's avatar
Jan Möbius committed
671
      const ACG::Vec3d g = _hitPoint - vp1;
Jan Möbius's avatar
Jan Möbius committed
672
      const double x = g | e;
673

Jan Möbius's avatar
Jan Möbius committed
674
      const double temp_dist = (_hitPoint - (vp1 + x * e)).length();
675
676
677
678
679
680
681
682
683
684
685

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

    return closest_e_handle;
}

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

686
687
/** \brief Find closest vertex on the edge (endpoint)
 *
Jan Möbius's avatar
Jan Möbius committed
688
689
690
691
692
 * @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
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
 */

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();

}

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

713
void
714
InfoMeshObjectPlugin::
715
716
717
718
719
  slotInformationRequested(const QPoint _clickedPoint, DataType _type) {

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

720
721
    ACG::SceneGraph::PickTarget target = ACG::SceneGraph::PICK_FACE;

722
    size_t         node_idx, target_idx;
723
    ACG::Vec3d     hit_point;
724

725
726
    if (info_->isHidden())
    {
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
      //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);
      }
759
760
    }

761
762
763
764
765
    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;
766

767
    if (PluginFunctions::scenegraphPick(target, _clickedPoint, node_idx, target_idx, &hit_point)) {
768
769
770
771
772
773
      BaseObjectData* object;

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

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

774
775
776
         lastPickedObject_ = object;
         lastPickedObjectId_ = object->id();

777
778
779
780
         if ( object->dataType(DATA_TRIANGLE_MESH) )
           printMeshInfo( PluginFunctions::triMesh(object) , object->id(), target_idx, hit_point );

         if ( object->dataType(DATA_POLY_MESH) )
781
           printMeshInfo( PluginFunctions::polyMesh(object) , object->id(), target_idx, hit_point );
782
783
784
785
      } else {
          lastPickedObject_ = 0;
          return;
      }
786
    }
787
788
789
790
    else
    {
      emit log( LOGERR , tr("Unable to pick object.") );
    }
791
792
793
794
795
}

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

template< class MeshT >
796
void InfoMeshObjectPlugin::getEdgeLengths(MeshT* _mesh, double &min, double &max, double &mean)
797
798
799
800
801
802
803
804
805
{
  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
OM3  
Jan Möbius committed
806
807
    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 ();
808
809
810
811
812
813
814
815
816
817
    if (len < min) min = len;
    if (len > max) max = len;
    mean += len;
  }

  mean /= _mesh->n_edges();
}

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

818
bool InfoMeshObjectPlugin::getEdgeLengths(int _id, double &min, double &max, double &mean)
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
{
  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;
}

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

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

859
  if ( !infoBar_ ) {
860
861
     return;
   }
862

863
864
  BaseObjectData* object;
  PluginFunctions::getObject(_identifier,object);
865

866
867
868
869
870
  if (_identifier == lastPickedObjectId_ && _deleted) {
      lastPickedObject_ = 0;
      lastPickedObjectId_ = -1;
  }

Jan Möbius's avatar
Jan Möbius committed
871
872
873
874
875
876
  // Last object that is target has been removed.
  if ( _deleted && object && object->target() && (PluginFunctions::targetCount() == 1) ) {
    infoBar_->hideCounts();
    return;
  }

877
878
879
   // 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() ) ) {
880

Jan Möbius's avatar
Jan Möbius committed
881
882


883
884
885
886
887
888
889
890
891
892
893
     // 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;
         }
       }
     }
894

895
896
     // We only need to update something, if the updated object is the target object
     if (object && object->target() ) {
897

898
       if (object->dataType(DATA_TRIANGLE_MESH)){
899

900
         TriMesh* mesh = PluginFunctions::triMesh(object);
901

902
903
904
         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()) ) );
905

906
         infoBar_->showCounts();
907

908
909
         return;
       }
910

911
       if (object->dataType(DATA_POLY_MESH)){
912

913
         PolyMesh* mesh = PluginFunctions::polyMesh(object);
914

915
916
917
         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()) ) );
918

919
920
921
         infoBar_->showCounts();
         return;
       }
922

923
     }
924

925
     infoBar_->hideCounts();
926

927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
   } 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);
946

947
948
949
950
}

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

951
void InfoMeshObjectPlugin::slotObjectSelectionChanged( int _identifier ){
952
953
954
955
956
957
958
  updateData(_identifier,UPDATE_ALL,false);
}

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

void InfoMeshObjectPlugin::objectDeleted( int _identifier ){
  updateData(_identifier,UPDATE_ALL,true);
959
960
}

961

962
963
//------------------------------------------------------------------------------

964
void InfoMeshObjectPlugin::slotAllCleared(){
965
966
  if ( infoBar_ )
    infoBar_->hideCounts();
967

968
969
}

970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
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();
}

993
994