Commit e79c16a9 authored by Jan Möbius's avatar Jan Möbius
Browse files

Started cleanup and more documentation

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@15716 383ad7c9-94d9-4d36-a494-682f7c89f535
parent b420c28e
/*===========================================================================*\
* *
* OpenFlipper *
* Copyright (C) 2001-2011 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 <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision: 15713 $ *
* $LastChangedBy: moebius $ *
* $Date: 2012-10-25 12:58:58 +0200 (Do, 25 Okt 2012) $ *
* *
\*===========================================================================*/
#include "MeshRepairPlugin.hh"
#include "MeshFixingT.hh"
//-----------------------------------------------------------------------------
void MeshRepairPlugin::fixNonManifoldVertices(int _objectId)
{
TriMesh* triMesh = 0;
PolyMesh* polyMesh = 0;
PluginFunctions::getMesh(_objectId, triMesh);
PluginFunctions::getMesh(_objectId, polyMesh);
if (triMesh)
fixNonManifoldVertices(triMesh);
else if (polyMesh)
fixNonManifoldVertices(polyMesh);
else
{
emit log(LOGERR, tr("Unsupported Object Type."));
return;
}
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup(_objectId, "fixTopology", UPDATE_ALL);
emit scriptInfo("fixTopology(" + QString::number(_objectId) + ")");
}
//-----------------------------------------------------------------------------
void
MeshRepairPlugin::fixMesh(int _objectId, double _epsilon) {
// get the target mesh
TriMesh* triMesh = 0;
PluginFunctions::getMesh(_objectId,triMesh);
if (triMesh) {
MeshFixing<TriMesh> fixer(*triMesh,_epsilon);
if ( !fixer.fix() )
emit log(LOGERR, "Fixmesh encountered Problems! Object: " + QString::number(_objectId) + ".");
// Recompute normals
triMesh->update_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup(_objectId, "Fixed mesh", UPDATE_ALL);
emit scriptInfo( "fixMesh(" + QString::number(_objectId) + ", " + QString::number(_epsilon) + ")" );
} else
emit log( LOGERR,tr("Unsupported Object Type for mesh fixing!") );
}
//-----------------------------------------------------------------------------
......@@ -295,7 +295,7 @@ int MeshFixing<MeshT>::neighbor(unsigned int _f, unsigned int _v0, unsigned int
return neighborFace;
}
/**
/** Tries to ensure that all faces in one component have the same orientation.
*
*/
template<class MeshT>
......@@ -304,7 +304,6 @@ void MeshFixing<MeshT>::fix_orientation()
// We need faces to work on!
if (faces_.empty()) return;
int fh = 0;
std::vector<int> todo;
......
......@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>432</width>
<height>852</height>
<height>830</height>
</rect>
</property>
<property name="windowTitle">
......@@ -588,20 +588,6 @@ There is no automatic algorithm to fix these foldovers here. So you will have to
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>Fix Mesh:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="fixTopologyButton">
<property name="text">
<string>Fix Topology</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
......@@ -693,13 +679,26 @@ There is no automatic algorithm to fix these foldovers here. So you will have to
<item>
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>General</string>
<string>General Operations</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QPushButton" name="fixNonManifoldVerticesButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Remove non-manifold vertices by duplicating them&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Fix non-manifold vertices</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="QPushButton" name="fixMeshButton">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This button will try to fix triangle meshes. &lt;/p&gt;&lt;p&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;Degenerated faces will be removed and all vertices which are closer than the given distance will be collapsed. Non-manifold configurations at vertices will be removed and all faces of each component will be updated to have the same orientation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Fix Triangle Mesh</string>
</property>
......
......@@ -52,7 +52,6 @@
#include <MeshTools/MeshSelectionT.hh>
#include <ACG/Geometry/Algorithms.hh>
#include <Math_Tools/Math_Tools.hh>
#include "MeshFixingT.hh"
//-----------------------------------------------------------------------------
......@@ -89,16 +88,26 @@ initializePlugin()
//Face operations
connect(tool_->triangleAspectButton,SIGNAL(clicked()),this,SLOT(slotDetectTriangleAspect()));
connect(tool_->flipOrientation,SIGNAL(clicked()),this,SLOT(slotFlipOrientation()));
connect(tool_->fixTopologyButton,SIGNAL(clicked()),this,SLOT(slotFixTopology()));
// General Operations
connect(tool_->fixMeshButton,SIGNAL(clicked()),this,SLOT(slotFixMesh()));
//==================
//Normal operations
//==================
connect(tool_->computeNormals,SIGNAL(clicked()),this,SLOT(slotUpdateNormals()));
connect(tool_->computeVertexNormals,SIGNAL(clicked()),this,SLOT(slotUpdateVertexNormals()));
connect(tool_->computeFaceNormals,SIGNAL(clicked()),this,SLOT(slotUpdateFaceNormals()));
connect(tool_->computeHalfedgeNormals,SIGNAL(clicked()),this,SLOT(slotUpdateHalfedgeNormals()));
// General Operations
connect(tool_->fixMeshButton,SIGNAL(clicked()),this,SLOT(slotFixMesh()));
//==================
// General
//==================
connect(tool_->fixNonManifoldVerticesButton,SIGNAL(clicked()),this,SLOT(slotFixNonManifoldVertices()));
toolIcon_ = new QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"meshrepair-toolbox.png");
tool_->repairCollapseEButton->setIcon(*toolIcon_);
......@@ -274,10 +283,10 @@ void MeshRepairPlugin::slotSnapBoundary()
//-----------------------------------------------------------------------------
void MeshRepairPlugin::slotFixTopology()
void MeshRepairPlugin::slotFixNonManifoldVertices()
{
for ( PluginFunctions::ObjectIterator o_it(PluginFunctions::TARGET_OBJECTS,DataType( DATA_TRIANGLE_MESH | DATA_POLY_MESH ) ); o_it != PluginFunctions::objectsEnd(); ++o_it)
fixTopology(o_it->id());
fixNonManifoldVertices(o_it->id());
emit updateView();
}
......@@ -289,29 +298,15 @@ void MeshRepairPlugin::slotFixTopology()
*/
void MeshRepairPlugin::pluginsInitialized() {
emit setSlotDescription("updateFaceNormals(int)",tr("Recompute Face normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
// TODO: Check and update
emit setSlotDescription("updateHalfedgeNormals(int)",tr("Recompute Halfedge normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
emit setSlotDescription("updateVertexNormals(int)",tr("Recompute Vertex normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
emit setSlotDescription("updateNormals(int)",tr("Recompute Face and Vertex normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
emit setSlotDescription("flipOrientation(int)",tr("Flips the normals of all faces by changing the vertex order in each face"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
emit setSlotDescription("fixMesh(int,double)",tr("Fixes a mesh."),
QString(tr("objectId,distance")).split(","),
QString(tr("ID of an object;Vertices with distance lower than epsilon will be treated as one")).split(";"));
emit setSlotDescription("removeSelectedEdges(int)",tr("Remove the selected edges"),
QStringList(tr("objectId")),
......@@ -344,10 +339,48 @@ void MeshRepairPlugin::pluginsInitialized() {
emit setSlotDescription("detectSkinnyTriangleByAngle(int,double,bool)",tr("Select or remove skinny triangles. Whether a triangle is skinny is determined by a minimum angle threshold."),
QString(tr("objectId,angle,remove")).split(","),
QString(tr("ID of an object;Minimum angle threshold")).split(";"));
emit setSlotDescription("snapBoundary(int,double)",tr("Snaps selected and boundary vertices if the distance is less than the given max. distance."),
QString(tr("objectId,epsilon")).split(","),
QString(tr("ID of an object;Max Distance")).split(";"));
// ===============================
// Normal Fixing
// ===============================
emit setSlotDescription("updateFaceNormals(int)",tr("Recompute Face normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
emit setSlotDescription("updateHalfedgeNormals(int)",tr("Recompute Halfedge normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
emit setSlotDescription("updateVertexNormals(int)",tr("Recompute Vertex normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
emit setSlotDescription("updateNormals(int)",tr("Recompute Face and Vertex normals"),
QStringList(tr("objectId")),
QStringList(tr("ID of an object")));
// ===============================
// General Mesh fixing
// ===============================
emit setSlotDescription("(int)",tr("Fixes non manifold vertices."),
QString(tr("objectId")).split(","),
QString(tr("ID of an object;Non manifold vertices are splitted.")).split(";"));
emit setSlotDescription("fixMesh(int,double)",tr("Fixes a mesh."),
QString(tr("objectId,distance")).split(","),
QString(tr("ID of an object;Vertices with distance lower than epsilon will be treated as one.")).split(";"));
}
......@@ -379,27 +412,7 @@ void MeshRepairPlugin::snapBoundary(int _objectId, double _eps)
}
void MeshRepairPlugin::fixTopology(int _objectId)
{
TriMesh* triMesh = 0;
PolyMesh* polyMesh = 0;
PluginFunctions::getMesh(_objectId, triMesh);
PluginFunctions::getMesh(_objectId, polyMesh);
if (triMesh)
fixTopology(triMesh);
else if (polyMesh)
fixTopology(polyMesh);
else
{
emit log(LOGERR, tr("Unsupported Object Type."));
return;
}
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup(_objectId, "fixTopology", UPDATE_ALL);
emit scriptInfo("fixTopology(" + QString::number(_objectId) + ")");
}
void MeshRepairPlugin::removeSelectedVal3Vertices(int _objectId) {
......@@ -630,119 +643,8 @@ void MeshRepairPlugin::detectFoldover(int _objectId, float _angle) {
+ " with angle greater than " + QString::number(_angle) + ".");
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::updateFaceNormals(int _objectId) {
BaseObjectData* object = 0;
PluginFunctions::getObject(_objectId,object);
if ( object == 0) {
emit log(LOGERR,tr("updateFaceNormals: Unable to get object %1. ").arg(_objectId) );
return;
}
if ( object->dataType(DATA_TRIANGLE_MESH) ) {
TriMesh* mesh = PluginFunctions::triMesh(object);
mesh->update_face_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup( _objectId, "Updated Face Normals", UPDATE_ALL);
emit scriptInfo( "updateFaceNormals(" + QString::number(_objectId) + ")" );
} else if ( object->dataType(DATA_POLY_MESH) ) {
PolyMesh* mesh = PluginFunctions::polyMesh(object);
mesh->update_face_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup( _objectId, "Updated Face Normals", UPDATE_ALL);
emit scriptInfo( "updateFaceNormals(" + QString::number(_objectId) + ")" );
} else
emit log(LOGERR,tr("updateFaceNormals: MeshRepair only works on triangle and poly meshes!") );
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::updateHalfedgeNormals(int _objectId) {
BaseObjectData* object = 0;
PluginFunctions::getObject(_objectId,object);
if ( object == 0) {
emit log(LOGERR,tr("updateFaceNormals: Unable to get object %1. ").arg(_objectId) );
return;
}
if ( object->dataType(DATA_TRIANGLE_MESH) ) {
TriMesh* mesh = PluginFunctions::triMesh(object);
mesh->request_halfedge_normals();
mesh->update_halfedge_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup( _objectId, "Updated Face Normals", UPDATE_ALL);
emit scriptInfo( "updateFaceNormals(" + QString::number(_objectId) + ")" );
} else if ( object->dataType(DATA_POLY_MESH) ) {
PolyMesh* mesh = PluginFunctions::polyMesh(object);
mesh->request_halfedge_normals();
mesh->update_halfedge_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup( _objectId, "Updated Face Normals", UPDATE_ALL);
emit scriptInfo( "updateFaceNormals(" + QString::number(_objectId) + ")" );
} else
emit log(LOGERR,tr("updateFaceNormals: MeshRepair only works on triangle and poly meshes!") );
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::updateVertexNormals(int _objectId){
BaseObjectData* object = 0;
PluginFunctions::getObject(_objectId,object);
if ( object == 0) {
emit log(LOGERR,tr("updateVertexNormals: Unable to get object %1. ").arg(_objectId) );
return;
}
if ( object->dataType(DATA_TRIANGLE_MESH) ) {
TriMesh* mesh = PluginFunctions::triMesh(object);
mesh->update_vertex_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup( _objectId, "Updated Vertex Normals", UPDATE_ALL);
emit scriptInfo( "updateVertexNormals(" + QString::number(_objectId) + ")" );
} else if ( object->dataType(DATA_POLY_MESH) ) {
PolyMesh* mesh = PluginFunctions::polyMesh(object);
mesh->update_vertex_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup( _objectId, "Updated Vertex Normals", UPDATE_ALL);
emit scriptInfo( "updateVertexNormals(" + QString::number(_objectId) + ")" );
} else
emit log(LOGERR,tr("updateVertexNormals: MeshRepair only works on triangle and poly meshes!") );
}
//-----------------------------------------------------------------------------
void MeshRepairPlugin::updateNormals(int _objectId) {
BaseObjectData* object = 0;
PluginFunctions::getObject(_objectId,object);
if ( object == 0) {
emit log(LOGERR,tr("updateNormals: Unable to get object %1. ").arg(_objectId) );
return;
}
if ( object->dataType(DATA_TRIANGLE_MESH) ) {
TriMesh* mesh = PluginFunctions::triMesh(object);
mesh->update_normals();
emit scriptInfo( "updateNormals(" + QString::number(_objectId) + ")" );
} else if ( object->dataType(DATA_POLY_MESH) ) {
PolyMesh* mesh = PluginFunctions::polyMesh(object);
mesh->update_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup( _objectId, "Updated All Normals", UPDATE_ALL);
emit scriptInfo( "updateNormals(" + QString::number(_objectId) + ")" );
} else
emit log(LOGERR,tr("updateNormals: MeshRepair only works on triangle and poly meshes!") );
}
//-----------------------------------------------------------------------------
void
......@@ -960,32 +862,6 @@ void MeshRepairPlugin::detectFlatValence3Vertices(int _objectId, double _angle)
}
void
MeshRepairPlugin::fixMesh(int _objectId, double _epsilon) {
// get the target mesh
TriMesh* triMesh = 0;
PluginFunctions::getMesh(_objectId,triMesh);
if (triMesh) {
MeshFixing<TriMesh> fixer(*triMesh,_epsilon);
if ( !fixer.fix() )
emit log(LOGERR, "Fixmesh encountered Problems! Object: " + QString::number(_objectId) + ".");
// Recompute normals
triMesh->update_normals();
emit updatedObject(_objectId, UPDATE_ALL);
emit createBackup(_objectId, "Fixed mesh", UPDATE_ALL);
emit scriptInfo( "fixMesh(" + QString::number(_objectId) + ", " + QString::number(_epsilon) + ")" );
} else
emit log( LOGERR,tr("Unsupported Object Type for mesh fixing!") );
}
//-----------------------------------------------------------------------------
Q_EXPORT_PLUGIN2( meshrepairplugin , MeshRepairPlugin );
......@@ -169,9 +169,14 @@ private slots:
void slotSnapBoundary();
/// Button slot
void slotFixTopology();
void slotFixNonManifoldVertices();
//===========================================================================
/** @name Scripting functions
* @{ */
//===========================================================================
//Scripting functions:
public slots:
/// Remove all selected valence 3 vertices
......@@ -189,23 +194,12 @@ public slots:
/// Detect triangle with aspect of _aspect and select candidates
void detectTriangleAspect(int _objectId, float _aspect);
/// Recomputes the face normals of an object
void updateFaceNormals(int _objectId);
/// Recomputes the halfedge normals of an object
void updateHalfedgeNormals(int _objectId);
/// Recomputes the vertex normals of an object
void updateVertexNormals(int _objectId);
/// Recomputes the face and vertex normals of an object
void updateNormals(int _objectId);
/// Flips the normals of all faces by changing the vertex order
void flipOrientation(int _objectId);
/// Fix a mesh
void fixMesh(int _objectId, double _epsilon);
/// Selects all edges of an object which are shorter than the given length
void selectEdgesShorterThan(int _objectId,double _length);
......@@ -218,7 +212,52 @@ public slots:
void snapBoundary(int _objectId, double _eps);
void fixTopology(int _objectId);
// ==================================================
// Normal recomputations
// ==================================================
/// Recomputes the face normals of an object
void updateFaceNormals(int _objectId);
/// Recomputes the halfedge normals of an object
void updateHalfedgeNormals(int _objectId);
/// Recomputes the vertex normals of an object
void updateVertexNormals(int _objectId);
/// Recomputes the face and vertex normals of an object
void updateNormals(int _objectId);
// ==================================================
// General
// ==================================================
/** \brief remove non-manifold vertices by duplicating them
*
* @param _objectId Id of the mesh to fix
*/
void fixNonManifoldVertices(int _objectId);
/** \brief Fix a mesh
*
* Degenerated faces will be removed and all vertices which are closer than the given distance
* will be collapsed. Non-manifold configurations at vertices will be removed and all faces of
* each component will be updated to have the same orientation.
*
* @param _objectId Id of the object to fix
* @param _epsilon Snapping distance
*/
void fixMesh(int _objectId, double _epsilon);
/** @} */
private:
/** \brief select edges based on length
......@@ -258,12 +297,20 @@ private:
template<typename MeshT>
static bool sort_less_pair_second(const std::pair<typename MeshT::VertexHandle,double> &lhs,const std::pair<typename MeshT::VertexHandle,double> &rhs);
/** \brief fixes the orientation and non-manifold problems in a mesh.
* @param _mesh target mesh
/** \brief Removes non-manifold vertices by duplicating them
*
* @param _mesh target mesh
*/
template<typename MeshT>
void fixTopology(MeshT *_mesh);
void fixNonManifoldVertices(MeshT *_mesh);
// Checked from here
public slots:
QString version() {
......
......@@ -243,6 +243,7 @@ void MeshRepairPlugin::snapBoundary(MeshT *_mesh, double _eps)
}
}
vertexDistMap.erase(v_oldIter);
//todo: delete vertex before proceed. Now, they will be deleted at the end resulting worse snap
}
_mesh->delete_isolated_vertices();
......@@ -252,8 +253,9 @@ void MeshRepairPlugin::snapBoundary(MeshT *_mesh, double _eps)
}
//-----------------------------------------------------------------------------
template<typename MeshT>
void MeshRepairPlugin::fixTopology(MeshT *_mesh)
void MeshRepairPlugin::fixNonManifoldVertices(MeshT *_mesh)