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
85 void InfoMeshObjectPlugin::pluginsInitialized() {
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
112 DataType InfoMeshObjectPlugin::supportedDataTypes() {
113 return DataType(DATA_POLY_MESH | DATA_TRIANGLE_MESH);
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
714 InfoMeshObjectPlugin::
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
720 ACG::SceneGraph::PickTarget target = ACG::SceneGraph::PICK_FACE;
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
729 target = ACG::SceneGraph::PICK_ANYTHING;
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
761 target = ACG::SceneGraph::PICK_FACE;
762 if (info_->pickMode->currentIndex() == 1 )
763 target = ACG::SceneGraph::PICK_EDGE;
764 else if (info_->pickMode->currentIndex() == 2 )
765 target = ACG::SceneGraph::PICK_VERTEX;
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() ) {
887 for ( PluginFunctions::ObjectIterator o_it = PluginFunctions::ObjectIterator(PluginFunctions::TARGET_OBJECTS); o_it != PluginFunctions::objectsEnd(); ++o_it ) {
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
PluginFunctions::scenegraphPick
bool scenegraphPick(ACG::SceneGraph::PickTarget _pickTarget, const QPoint &_mousePos, size_t &_nodeIdx, size_t &_targetIdx, ACG::Vec3d *_hitPointPtr=0)
Execute picking operation on scenegraph.
Definition: PluginFunctions.cc:480
BaseObject::getObjectinfo
virtual QString getObjectinfo()
Get all Info for the Object as a string.
Definition: BaseObject.cc:244
LOGERR
Definition: LoggingInterface.hh:96
InfoMeshObjectPlugin::supportedDataTypes
DataType supportedDataTypes()
Get data type for information requests.
Definition: MeshObjectInfoPlugin.cc:112
DATA_TRIANGLE_MESH
#define DATA_TRIANGLE_MESH
Definition: TriangleMesh.hh:60
ACG::SceneGraph::PICK_EDGE
picks edges (may not be implemented for all nodes)
Definition: PickTarget.hh:80
DATA_POLY_MESH
#define DATA_POLY_MESH
Definition: PolyMesh.hh:59
UPDATE_ALL
const UpdateType UPDATE_ALL(UpdateTypeSet(1))
Identifier for all updates.
PluginFunctions::polyMesh
PolyMesh * polyMesh(BaseObjectData *_object)
Get a poly mesh from an object.
Definition: PluginFunctionsPolyMesh.cc:128
PolyMeshObject
Type for a Meshobject containing a poly mesh.
Definition: PolyMesh.hh:65
ACG::SceneGraph::PICK_FACE
picks faces (should be implemented for all nodes)
Definition: PickTarget.hh:78
InfoMeshObjectPlugin::pluginsInitialized
void pluginsInitialized()
initialize the plugin
Definition: MeshObjectInfoPlugin.cc:85
InfoMeshObjectPlugin::getEdgeLengths
void getEdgeLengths(MeshT *_mesh, double &min, double &max, double &mean)
Get edge lengths.
Definition: MeshObjectInfoPlugin.cc:796
BaseObject
Definition: BaseObject.hh:82
PluginFunctions::getObject
bool getObject(const int _identifier, BaseObject *&_object)
Get the object which has the given identifier.
Definition: PluginFunctions.cc:296
OpenMesh::TriMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:73
OpenMesh::VectorT
Definition: Vector11T.hh:83
BaseObject::target
bool target()
Definition: BaseObject.cc:273
PluginFunctions::triMesh
TriMesh * triMesh(BaseObjectData *_object)
Get a triangle mesh from an object.
Definition: PluginFunctionsTriangleMesh.cc:134
InfoBar
Definition: infoBar.hh:47
DataType
Predefined datatypes.
Definition: DataTypes.hh:83
OpenMesh::sane_aarg
T sane_aarg(T _aarg)
Trigonometry/angles - related.
Definition: MathDefs.hh:122
OpenMesh::PolyMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:94
BaseObject::id
int id() const
Definition: BaseObject.cc:190
MeshObject::mesh
MeshT * mesh()
return a pointer to the mesh
Definition: MeshObjectT_impl.hh:350
ACG::Geometry::aspectRatio
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
BaseObject::dataType
bool dataType(DataType _type) const
Definition: BaseObject.cc:221
PluginFunctions::objectsEnd
DLLEXPORT ObjectIterator objectsEnd()
Return Iterator to Object End.
Definition: PluginFunctionsIterator.cc:177
ACG::SceneGraph::PickTarget
PickTarget
What target to use for picking.
Definition: PickTarget.hh:73
InfoMeshObjectPlugin::getClosestVertexFromEdge
int getClosestVertexFromEdge(MeshT *_mesh, int _edge_idx, ACG::Vec3d &_hitPoint)
Get closest vertex index from an edge.
Definition: MeshObjectInfoPlugin.cc:696
ValenceHistogramDialog
Definition: ValenceHistogramDialog.hh:51
InfoMeshObjectPlugin::updateData
void updateData(int _identifier, const UpdateType &_type, const bool deleted)
Slot that updates the visualization.
Definition: MeshObjectInfoPlugin.cc:857
ACG::SceneGraph::PICK_ANYTHING
pick any of the prior targets (should be implemented for all nodes)
Definition: PickTarget.hh:84
InfoDialog
Definition: infoDialog.hh:46
PluginFunctions::ObjectIterator
Core Data Iterator.
Definition: PluginFunctions.hh:441
ACG::SceneGraph::PICK_VERTEX
picks verices (may not be implemented for all nodes)
Definition: PickTarget.hh:82
BaseObject::name
QString name() const
return the name of the object. The name defaults to NONAME if unset.
Definition: BaseObject.cc:730
PluginFunctions::targetCount
int targetCount()
Get the number of target objects.
Definition: PluginFunctions.cc:1008
TriMeshObject
Type for a MeshObject containing a triangle mesh.
Definition: TriangleMesh.hh:67
BaseObjectData
Definition: BaseObjectData.hh:102
UpdateType
Update type class.
Definition: UpdateType.hh:60
PluginFunctions::TARGET_OBJECTS
const QStringList TARGET_OBJECTS("target")
Iterable object range.
InfoMeshObjectPlugin::getClosestVertexInFace
int getClosestVertexInFace(MeshT *_mesh, int _face_idx, ACG::Vec3d &_hitPoint)
Get closest vertex index from a face.
Definition: MeshObjectInfoPlugin.cc:610
OpenMesh::VectorT::length
auto length() const -> decltype(std::declval< VectorT< S, DIM >>().norm())
compute squared euclidean norm
Definition: Vector11T.hh:423
InfoMeshObjectPlugin::getClosestEdgeInFace
int getClosestEdgeInFace(MeshT *_mesh, int _face_idx, const ACG::Vec3d &_hitPoint)
Get closest edge index from a face.
Definition: MeshObjectInfoPlugin.cc:649
InfoMeshObjectPlugin::slotInformationRequested
void slotInformationRequested(const QPoint _clickedPoint, DataType _type)
Show information dialog on clicked object.
Definition: MeshObjectInfoPlugin.cc:715
PluginFunctions::getPickedObject
bool getPickedObject(const size_t _node_idx, BaseObjectData *&_object)
Get the picked mesh.
Definition: PluginFunctions.cc:261
ACG::Vec3d
VectorT< double, 3 > Vec3d
Definition: VectorT.hh:121
LOGINFO
Definition: LoggingInterface.hh:94