Developer Documentation
Loading...
Searching...
No Matches
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
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
virtual QString getObjectinfo()
Get all Info for the Object as a string.
QString name() const
return the name of the object. The name defaults to NONAME if unset.
bool dataType(DataType _type) const
bool target()
int id() const
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
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.
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
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)
PolyConnectivity::ConstFaceVertexRange vertices() const
Returns a range of vertices incident to the face (PolyConnectivity::fv_range())
PolyConnectivity::ConstFaceHalfedgeRange halfedges() const
Returns a range of halfedges of the face (PolyConnectivity::fh_range())
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...