/*===========================================================================*\ * * * OpenFlipper * * Copyright (C) 2001-2009 by Computer Graphics Group, RWTH Aachen * * www.openflipper.org * * * *---------------------------------------------------------------------------* * This file is part of OpenFlipper. * * * * OpenFlipper is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version with the * * following exceptions: * * * * If other files instantiate templates or use macros * * or inline functions from this file, or you compile this file and * * link it with other files to produce an executable, this file does * * not by itself cause the resulting executable to be covered by the * * GNU Lesser General Public License. This exception does not however * * invalidate any other reasons why the executable file might be * * covered by the GNU Lesser General Public License. * * * * OpenFlipper is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU LesserGeneral Public * * License along with OpenFlipper. If not, * * see . * * * \*===========================================================================*/ /*===========================================================================*\ * * * $Revision$ * * $Author$ * * $Date$ * * * \*===========================================================================*/ //============================================================================= // // CLASS InfoPlugin - IMPLEMENTATION // //============================================================================= //== INCLUDES ================================================================= #include #include "InfoPlugin.hh" #include #include #include #include #include #include #include #include #include #include //== IMPLEMENTATION ========================================================== /// initialize the plugin void InfoPlugin::pluginsInitialized() { //set the slot descriptions setDescriptions(); // Initialize hit point hit_point_ = ACG::Vec3d(0.0, 0.0, 0.0); } //----------------------------------------------------------------------------- template< class MeshT > void InfoPlugin::printMeshInfo( MeshT* _mesh , int _id, unsigned int _face ) { QLocale locale; if (info_ == 0){ info_ = new InfoDialog(); } int closest_v_idx = getClosestVertex(_mesh, _face); int closest_e_idx = getClosestEdge(_mesh, _face); // ID info_->id->setText( tr("Object ID: ") + locale.toString(_id) ); // Vertices info_->vertices->setText( tr("Vertices: ") + locale.toString( _mesh->n_vertices() ) ); // Faces info_->faces->setText( tr("Faces: ") + locale.toString( _mesh->n_faces() ) ); // Edges info_->edges->setText( tr("Edges: ") + locale.toString( _mesh->n_edges() ) ); // Closest Vertex info_->closestv->setText( tr("Closest vertex: ") + locale.toString( closest_v_idx ) ); // Closest Edge info_->closeste->setText( tr("Closest edge: ") + locale.toString( closest_e_idx ) ); // Picked Vertex info_->pickedFace->setText( tr("Picked face: ") + locale.toString( _face ) ); // Components info_->components->setText( tr("Components: ") + locale.toString(MeshInfo::componentCount(_mesh))); // Boundaries info_->boundaries->setText( tr("Boundaries: ") + locale.toString(MeshInfo::boundaryCount(_mesh)) ); // Genus int genus = 1 - (_mesh->n_vertices() - _mesh->n_edges() + _mesh->n_faces() ) / 2; info_->genus->setText( tr("Genus: ") + QString::number(genus) ); info_->table->clear(); info_->table->setColumnCount ( 3 ); info_->table->setRowCount ( 8 ); QStringList headerdata; headerdata << tr("Min") << tr("Mean") << tr("Max"); info_->table->setHorizontalHeaderLabels(headerdata); headerdata.clear(); headerdata << tr("X Coordinate") << tr("Y Coordinate") << tr("Z Coordinate") << tr("Vertex Valence") << tr("Edge Length") << tr("Aspect Ratio"); headerdata << tr("Inner Face Angles") << tr("Dihedral Angles"); info_->table->setVerticalHeaderLabels(headerdata); //set tooltips info_->table->verticalHeaderItem(0)->setToolTip(tr("minimum, maximum and arithmetic mean of the vertex x-coordinates")); info_->table->verticalHeaderItem(1)->setToolTip(tr("minimum, maximum and arithmetic mean of the vertex y-coordinates")); info_->table->verticalHeaderItem(2)->setToolTip(tr("minimum, maximum and arithmetic mean of the vertex z-coordinates")); info_->table->verticalHeaderItem(3)->setToolTip(tr("minimum, maximum and arithmetic mean of the vertex valences")); info_->table->verticalHeaderItem(4)->setToolTip(tr("minimum, maximum and arithmetic mean of the edge lengthes")); info_->table->verticalHeaderItem(5)->setToolTip(tr("minimum, maximum and arithmetic mean of the aspect ratio." " i.e. the ratio between longest and shortest edge in a triangle.")); info_->table->verticalHeaderItem(6)->setToolTip(tr("minimum, maximum and arithmetic mean of the inner angles in a face.")); info_->table->verticalHeaderItem(7)->setToolTip(tr("minimum, maximum and arithmetic mean of the dihedral angles" " i.e. the angles between neighboring faces.")); // Coordinates typename MeshT::VertexIter v_it; typename MeshT::VertexIter v_end = _mesh->vertices_end(); float maxX = FLT_MIN; float minX = FLT_MAX; float sumX = 0.0; float maxY = FLT_MIN; float minY = FLT_MAX; float sumY = 0.0; float maxZ = FLT_MIN; float minZ = FLT_MAX; float sumZ = 0.0; int minV = 999; int maxV = 0; int sumV = 0; float maxE = FLT_MIN; float minE = FLT_MAX; float sumE = 0.0; //iterate over all vertices for (v_it = _mesh->vertices_begin(); v_it != v_end; ++v_it){ typename MeshT::Point p = _mesh->point( v_it.handle() ); if (p[0] < minX) minX = p[0]; if (p[0] > maxX) maxX = p[0]; sumX += p[0]; if (p[1] < minY) minY = p[1]; if (p[1] > maxY) maxY = p[1]; sumY += p[1]; if (p[2] < minZ) minZ = p[2]; if (p[2] > maxZ) maxZ = p[2]; sumZ += p[2]; //check valence + edge length int valence = 0; typename MeshT::VertexVertexIter vv_it; for (vv_it=_mesh->vv_iter( v_it ); vv_it; ++vv_it){ valence++; typename MeshT::Point p2 = _mesh->point( vv_it.handle() ); typename MeshT::Scalar len = (p2 - p).norm(); if (len < minE) minE = len; if (len > maxE) maxE = len; sumE += len; } if (valence < minV) minV = valence; if (valence > maxV) maxV = valence; sumV += valence; } int row=0; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minX,'f') ) ); info_->table->setItem(row,1, new QTableWidgetItem( QString::number( sumX / _mesh->n_vertices(),'f' )) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxX,'f') ) ); row++; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minY,'f') ) ); info_->table->setItem(row,1, new QTableWidgetItem( QString::number( sumY / _mesh->n_vertices(),'f' )) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxY,'f') ) ); row++; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minZ,'f') ) ); info_->table->setItem(row,1, new QTableWidgetItem( QString::number( sumZ / _mesh->n_vertices(),'f' )) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxZ,'f') ) ); row++; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minV) ) ); info_->table->setItem(row,1, new QTableWidgetItem( QString::number( sumV / (float)_mesh->n_vertices(),'f' )) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxV) ) ); row++; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minE,'f') ) ); info_->table->setItem(row,1, new QTableWidgetItem( QString::number( sumE / (_mesh->n_edges()*2),'f' )) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxE,'f') ) ); //get aspect ratio typename MeshT::FaceIter f_it; typename MeshT::FaceIter f_end = _mesh->faces_end(); float maxA = FLT_MIN; float minA = FLT_MAX; float sumA = 0.0; float maxI = FLT_MIN; float minI = FLT_MAX; float sumI = 0.0; float maxD = FLT_MIN; float minD = FLT_MAX; float sumD = 0.0; //iterate over all faces for (f_it = _mesh->faces_begin(); f_it != f_end; ++f_it){ typename MeshT::ConstFaceVertexIter cfv_it = _mesh->cfv_iter(f_it); typename MeshT::Point v0 = _mesh->point( cfv_it.handle() ); ++cfv_it; typename MeshT::Point v1 = _mesh->point( cfv_it.handle() ); ++cfv_it; typename MeshT::Point v2 = _mesh->point( cfv_it.handle() ); float aspect = ACG::Geometry::aspectRatio(v0, v1, v2); if (aspect < minA) minA = aspect; if (aspect > maxA) maxA = aspect; sumA += aspect; //inner triangle angles double angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v2 - v0) | MathTools::sane_normalized(v1 - v0) ))); if (angle < minI) minI = angle; if (angle > maxI) maxI = angle; sumI += angle; angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v2 - v1) | MathTools::sane_normalized(v0 - v1) ))); if (angle < minI) minI = angle; if (angle > maxI) maxI = angle; sumI += angle; angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(v1 - v2) | MathTools::sane_normalized(v0 - v2) ))); if (angle < minI) minI = angle; if (angle > maxI) maxI = angle; sumI += angle; //compute dihedral angles typename MeshT::FaceFaceIter ff_it; typename MeshT::Normal n1 = _mesh->normal(f_it); for (ff_it = _mesh->ff_iter(f_it); ff_it; ++ff_it){ typename MeshT::Normal n2 = _mesh->normal(ff_it); angle = OpenMesh::rad_to_deg(acos(OpenMesh::sane_aarg( MathTools::sane_normalized(n1) | MathTools::sane_normalized(n2) ))); if (angle < minD) minD = angle; if (angle > maxD) maxD = angle; sumD += angle; } } row++; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minA,'f') ) ); info_->table->setItem(row,1, new QTableWidgetItem( QString::number( sumA / _mesh->n_faces(),'f' )) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxA,'f') ) ); row++; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minI,'f') ) ); info_->table->setItem(row,1, new QTableWidgetItem( "-" ) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxI,'f') ) ); row++; info_->table->setItem(row,0, new QTableWidgetItem( QString::number(minD,'f') ) ); info_->table->setItem(row,1, new QTableWidgetItem( QString::number( sumD / (_mesh->n_faces()*3),'f' )) ); info_->table->setItem(row,2, new QTableWidgetItem( QString::number(maxD,'f') ) ); info_->table->resizeColumnsToContents(); info_->table3->clear(); info_->table3->setColumnCount ( 3 ); headerdata.clear(); headerdata << "X" << "Y" << "Z"; info_->table3->setHorizontalHeaderLabels(headerdata); typename MeshT::FaceHandle fh = _mesh->face_handle(_face); headerdata.clear(); headerdata << tr("Bounding Box (Minimum)") << tr("Bounding Box (Maximum)") << tr("BoundingBox (Size)") << tr("Center of Gravity"); headerdata << tr("Picked Face Normal (Handle %1 )" ).arg(fh.idx()); typename MeshT::FaceVertexIter fv_it = _mesh->fv_iter(fh); int vertexCount = 0; while( fv_it ){ headerdata << tr("Adjacent Vertex (Handle %1 )").arg(fv_it.handle().idx()); ++fv_it; vertexCount++; } info_->table3->setRowCount ( 5 + vertexCount ); info_->table3->setVerticalHeaderLabels(headerdata); //set tooltips info_->table3->verticalHeaderItem(0)->setToolTip(tr("minimum corner coordinates of the bounding box")); info_->table3->verticalHeaderItem(1)->setToolTip(tr("maximum corner coordinates of the bounding box")); info_->table3->verticalHeaderItem(2)->setToolTip(tr("diagonal size of the bounding box")); info_->table3->verticalHeaderItem(3)->setToolTip(tr("coordinates of the center of gravity")); info_->table3->verticalHeaderItem(4)->setToolTip(tr("direction of the face normal that was picked")); for (int i=0; i < vertexCount; i++) info_->table3->verticalHeaderItem(5 + i)->setToolTip(tr("Coordinates of a vertex which is adjacent to the picked face")); //Calculate Bounding Box(min,max,cog) ACG::Vec3d min; ACG::Vec3d max; MeshInfo::getBoundingBox(*_mesh, min, max); //Bounding Box Size ACG::Vec3d diff = max-min; row=0; info_->table3->setItem(row,0, new QTableWidgetItem( QString::number(min[0],'f') ) ); info_->table3->setItem(row,1, new QTableWidgetItem( QString::number(min[1],'f') ) ); info_->table3->setItem(row,2, new QTableWidgetItem( QString::number(min[2],'f') ) ); row++; info_->table3->setItem(row,0, new QTableWidgetItem( QString::number(max[0],'f') ) ); info_->table3->setItem(row,1, new QTableWidgetItem( QString::number(max[1],'f') ) ); info_->table3->setItem(row,2, new QTableWidgetItem( QString::number(max[2],'f') ) ); row++; info_->table3->setItem(row,0, new QTableWidgetItem( QString::number(diff[0],'f') ) ); info_->table3->setItem(row,1, new QTableWidgetItem( QString::number(diff[1],'f') ) ); info_->table3->setItem(row,2, new QTableWidgetItem( QString::number(diff[2],'f') ) ); //COG ACG::Vec3d cog = MeshInfo::cog(*_mesh); row++; info_->table3->setItem(row,0, new QTableWidgetItem( QString::number(cog[0],'f') ) ); info_->table3->setItem(row,1, new QTableWidgetItem( QString::number(cog[1],'f') ) ); info_->table3->setItem(row,2, new QTableWidgetItem( QString::number(cog[2],'f') ) ); //face-normal row++; info_->table3->setItem(row,0, new QTableWidgetItem( QString::number( _mesh->normal(fh)[0],'f' ) ) ); info_->table3->setItem(row,1, new QTableWidgetItem( QString::number( _mesh->normal(fh)[1],'f' ) ) ); info_->table3->setItem(row,2, new QTableWidgetItem( QString::number( _mesh->normal(fh)[2],'f' ) ) ); fv_it = _mesh->fv_iter(fh); while( fv_it ) { row++; info_->table3->setItem(row,0, new QTableWidgetItem( QString::number( _mesh->point(fv_it)[0],'f' ) ) ); info_->table3->setItem(row,1, new QTableWidgetItem( QString::number( _mesh->point(fv_it)[1],'f' ) ) ); info_->table3->setItem(row,2, new QTableWidgetItem( QString::number( _mesh->point(fv_it)[2],'f' ) ) ); ++fv_it; } info_->table3->resizeColumnsToContents(); info_->setWindowFlags(info_->windowFlags() | Qt::WindowStaysOnTopHint); info_->show(); } //---------------------------------------------------------------------------------------------- /** \brief Find closest vertex to selection * * @param _mesh Refernce to the mesh * @param _face_idx Index of the face that has been clicked on */ template int InfoPlugin::getClosestVertex(MeshT* _mesh, int _face_idx) { typename MeshT::FaceVertexIter fv_it; int closest_v_idx = 0; double dist = DBL_MAX; double temp_dist = 0.0; ACG::Vec3d vTemp = ACG::Vec3d(0.0, 0.0, 0.0); typename MeshT::Point p; for (fv_it = _mesh->fv_iter(_mesh->face_handle(_face_idx)); fv_it; ++fv_it){ p = _mesh->point( fv_it.handle() ); // Find closest vertex to selection vTemp = ACG::Vec3d(p[0], p[1], p[2]); temp_dist = (vTemp - hit_point_).length(); if (temp_dist < dist) { dist = temp_dist; closest_v_idx = fv_it.handle().idx(); } } return closest_v_idx; } //------------------------------------------------------------------------------------------- /** \brief Find closest edge to selection * * @param _mesh Reference to the mesh * @param _face_idx Index of the face that has been clicked on */ template int InfoPlugin::getClosestEdge(MeshT* _mesh, int _face_idx) { typename MeshT::ConstFaceHalfedgeIter fh_it; typename MeshT::VertexHandle v1, v2; typename MeshT::Point p1, p2; ACG::Vec3d vp1, vp2, click, e, g, h; double x, temp_dist, dist = DBL_MAX; int closest_e_handle = 0; click = ACG::Vec3d(hit_point_[0], hit_point_[1], hit_point_[2]); for (fh_it = _mesh->fh_iter(_mesh->face_handle(_face_idx)); fh_it; ++fh_it){ v1 = _mesh->from_vertex_handle(fh_it); v2 = _mesh->to_vertex_handle(fh_it); p1 = _mesh->point(v1); p2 = _mesh->point(v2); vp1 = ACG::Vec3d(p1[0], p1[1], p1[2]); vp2 = ACG::Vec3d(p2[0], p2[1], p2[2]); e = vp2 - vp1; e.normalize(); g = click - vp1; x = g | e; temp_dist = (click - (vp1 + x * e)).length(); if (temp_dist < dist) { dist = temp_dist; closest_e_handle = _mesh->edge_handle(fh_it.handle()).idx(); } } return closest_e_handle; } //---------------------------------------------------------------------------------------------- void InfoPlugin:: slotMouseEventIdentify( QMouseEvent* _event ) { if (_event->type() == QEvent::MouseButtonPress) { unsigned int node_idx, target_idx; ACG::Vec3d hit_point; if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) { BaseObjectData* object; // BaseObject* obj = dynamic_cast< BaseObject* > (object); if ( PluginFunctions::getPickedObject(node_idx, object) ) { emit log( LOGINFO , object->getObjectinfo() ); // Set hit point hit_point_ = ACG::Vec3d(hit_point[0], hit_point[1], hit_point[2]); if ( object->picked(node_idx) && object->dataType(DATA_TRIANGLE_MESH) ) printMeshInfo( PluginFunctions::triMesh(object) , object->id(), target_idx ); if ( object->picked(node_idx) && object->dataType(DATA_POLY_MESH) ) printMeshInfo( PluginFunctions::polyMesh(object) , object->id(), target_idx ); } else return; } } } //------------------------------------------------------------------------------ template< class MeshT > void InfoPlugin::getEdgeLengths(MeshT* _mesh, double &min, double &max, double &mean) { typename MeshT::ConstEdgeIter e_it(_mesh->edges_sbegin()), e_end(_mesh->edges_end()); min = FLT_MIN; max = FLT_MAX; mean = 0.0; for (; e_it!=e_end; ++e_it) { typename MeshT::Scalar len = (_mesh->point(_mesh->to_vertex_handle(_mesh->halfedge_handle(e_it, 0))) - _mesh->point(_mesh->to_vertex_handle(_mesh->halfedge_handle(e_it, 1)))).norm (); if (len < min) min = len; if (len > max) max = len; mean += len; } mean /= _mesh->n_edges(); } //------------------------------------------------------------------------------ bool InfoPlugin::getEdgeLengths(int _id, double &min, double &max, double &mean) { BaseObjectData* object; if ( ! PluginFunctions::getObject(_id,object) ) return false; if ( object == 0){ emit log(LOGERR, tr("Unable to get object")); return false; } if ( object->dataType(DATA_TRIANGLE_MESH) ) { TriMesh* mesh = PluginFunctions::triMesh(object); if ( mesh == 0 ) { emit log(LOGERR,tr("Unable to get mesh")); return false; } getEdgeLengths (mesh, min, max, mean); return true; } else { PolyMesh* mesh = PluginFunctions::polyMesh(object); if ( mesh == 0 ) { emit log(LOGERR,tr("Unable to get mesh")); return false; } getEdgeLengths (mesh, min, max, mean); return true; } return false; } //------------------------------------------------------------------------------ Q_EXPORT_PLUGIN2( InfoPlugin , InfoPlugin );