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