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

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@18122 383ad7c9-94d9-4d36-a494-682f7c89f535
parents
include (plugin)
openflipper_plugin ( INSTALLDATA Icons )
#include <QtGui>
#include <QFileInfo>
#include "ComponentsPlugin.hh"
#include <iostream>
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
#include <OpenFlipper/common/GlobalOptions.hh>
#include <MeshTools/MeshInfoT.hh>
const char *SPLIT_COMPONENTS = "SplitComponents";
const char *BIGGEST_COMPONENT = "ComponentsPluginBiggestComponent";
//------------------------------------------------------------------------------
/** \brief Constructor
*
*/
ComponentsPlugin::ComponentsPlugin() {}
/*******************************************************************************
BaseInterface implementation
*******************************************************************************/
/** \brief Initialize the plugin
*
*/
void ComponentsPlugin::initializePlugin() {
}
//------------------------------------------------------------------------------
/** \brief Second initialization phase
*
*/
void ComponentsPlugin::pluginsInitialized()
{
setDescriptions();
emit addPickMode( SPLIT_COMPONENTS );
emit addPickMode( BIGGEST_COMPONENT );
// Add a scissor Toolbar
QToolBar* toolbar = new QToolBar("Components Toolbar");
//Split components
splitAction_ = new QAction(tr("&Split into components"), this);
splitAction_->setCheckable( true );
splitAction_->setStatusTip(tr("Clicked objects are splitted into components"));
splitAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"components_split_components.png") );
connect(splitAction_, SIGNAL(triggered()), this, SLOT(slotSplitComponentsButton()) );
toolbar->addAction(splitAction_);
biggestAction_ = new QAction(tr("&Get biggest component"), this);
biggestAction_->setCheckable( true );
biggestAction_->setStatusTip(tr("Get the biggest component of the clicked object and delete the other components."));
biggestAction_->setIcon(QIcon(OpenFlipper::Options::iconDirStr()+OpenFlipper::Options::dirSeparator()+"components_biggest_component.png") );
connect(biggestAction_, SIGNAL(triggered()), this, SLOT(slotBiggestComponentButton()) );
toolbar->addAction(biggestAction_);
emit addToolbar( toolbar );
}
/*******************************************************************************
PickingInterface implementation
*******************************************************************************/
/** \brief the pickMode changed
*
* @param _mode the new pickMode
*/
void ComponentsPlugin::slotPickModeChanged( const std::string& _mode){
splitAction_->setChecked( _mode == SPLIT_COMPONENTS );
biggestAction_->setChecked( _mode == BIGGEST_COMPONENT );
}
/*******************************************************************************
MouseInterface implementation
*******************************************************************************/
/** \brief a mouse event occured
*
* @param _event the event that occured
*/
void ComponentsPlugin::slotMouseEvent( QMouseEvent* _event )
{
if( PluginFunctions::pickMode() == SPLIT_COMPONENTS )
splitComponents( _event );
if (PluginFunctions::pickMode() == BIGGEST_COMPONENT)
biggestComponent( _event );
}
/*******************************************************************************
ComponentsPlugin Implementation
*******************************************************************************/
/** \brief Split into Components Button was hit
*
*/
void ComponentsPlugin::slotSplitComponentsButton( )
{
PluginFunctions::actionMode( Viewer::PickingMode );
PluginFunctions::pickMode( SPLIT_COMPONENTS );
}
//------------------------------------------------------------------------------
/** \brief Split components (triggered by pickMode)
*
* @param _event the mouse event that occured
*/
void ComponentsPlugin::splitComponents(QMouseEvent * _event)
{
if (_event->type() == QEvent::MouseButtonPress )
{
unsigned int node_idx, target_idx;
ACG::Vec3d* sourcePoint3D = 0;
if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE,
_event->pos(),
node_idx,
target_idx,
sourcePoint3D))
{
BaseObjectData *obj;
PluginFunctions::getPickedObject(node_idx, obj);
splitComponents( obj->id() );
}
}
}
void ComponentsPlugin::slotBiggestComponentButton()
{
PluginFunctions::actionMode( Viewer::PickingMode );
PluginFunctions::pickMode( BIGGEST_COMPONENT );
}
void ComponentsPlugin::biggestComponent(QMouseEvent* _event)
{
if (_event->type() == QEvent::MouseButtonPress )
{
unsigned int node_idx, target_idx;
ACG::Vec3d* sourcePoint3D = 0;
if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE,
_event->pos(),
node_idx,
target_idx,
sourcePoint3D))
{
BaseObjectData *obj;
PluginFunctions::getPickedObject(node_idx, obj);
if (!obj)
{
emit log(LOGERR,tr("Unable to pick Object."));
return;
}
biggestComponent(obj->id());
emit createBackup(obj->id(),"GetBiggestComponents",UPDATE_ALL);
emit updatedObject( obj->id() , UPDATE_ALL );
}
}
}
Q_EXPORT_PLUGIN2( componentsplugin, ComponentsPlugin );
/*===========================================================================*\
* *
* 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 <http://www.gnu.org/licenses/>. *
* *
\*===========================================================================*/
/*===========================================================================*\
* *
* $Revision: 15115 $ *
* $Author: moebius $ *
* $Date: 2012-07-26 14:40:06 +0200 (Thu, 26 Jul 2012) $ *
* *
\*===========================================================================*/
#ifndef COMPONENTSPLUGIN_HH
#define COMPONENTSPLUGIN_HH
#include <QObject>
#include <OpenFlipper/BasePlugin/BaseInterface.hh>
#include <OpenFlipper/BasePlugin/MouseInterface.hh>
#include <OpenFlipper/BasePlugin/PickingInterface.hh>
#include <OpenFlipper/BasePlugin/BackupInterface.hh>
#include <OpenFlipper/BasePlugin/LoadSaveInterface.hh>
#include <OpenFlipper/BasePlugin/LoggingInterface.hh>
#include <OpenFlipper/BasePlugin/ScriptInterface.hh>
#include <OpenFlipper/BasePlugin/ToolbarInterface.hh>
#include <OpenFlipper/common/Types.hh>
#include <ObjectTypes/PolyMesh/PolyMesh.hh>
#include <ObjectTypes/TriangleMesh/TriangleMesh.hh>
class ComponentsPlugin : public QObject, BaseInterface, MouseInterface, PickingInterface, LoggingInterface, BackupInterface, LoadSaveInterface, ToolbarInterface,ScriptInterface
{
Q_OBJECT
Q_INTERFACES( BaseInterface )
Q_INTERFACES( MouseInterface )
Q_INTERFACES( PickingInterface )
Q_INTERFACES( LoggingInterface )
Q_INTERFACES( BackupInterface )
Q_INTERFACES( LoadSaveInterface )
Q_INTERFACES( ToolbarInterface )
Q_INTERFACES( ScriptInterface )
signals:
// BaseInterface
void updateView();
void updatedObject(int _identifier, const UpdateType _type);
void setSlotDescription(QString _slotName, QString _slotDescription,
QStringList _parameters, QStringList _descriptions);
// LoadSaveInterface
void addEmptyObject( DataType _type, int& _id);
void copyObject( int _oldId, int& _newId);
// ToolBarInterface
void addToolbar(QToolBar* _toolbar);
void getToolBar( QString _name, QToolBar*& _toolbar);
// PickingInterface
void addPickMode( const std::string _mode );
//ScriptInterface
void scriptInfo( QString _functionName );
// LoggingInterface
void log( Logtype _type, QString _message );
void log( QString _message );
// BackupInterface
void createBackup( int _objectid, QString _name, UpdateType _type);
// LoadSaveInterface
void deleteObject( int _id );
private slots:
// BaseInterface
void initializePlugin();
void pluginsInitialized();
// PickingInterface
void slotPickModeChanged( const std::string& _mode);
// MouseInterface:
void slotMouseEvent( QMouseEvent* _event );
public:
ComponentsPlugin();
~ComponentsPlugin() { }
void exit() {}
QString name() { return (QString("Components")); };
QString description( ) { return (QString("Handle mesh components")); };
//===========================================================================
/** @name GUI Related
* @{ */
//===========================================================================
private slots:
/// Split into Components Button was hit
void slotSplitComponentsButton();
void slotBiggestComponentButton();
/// Split Components of picked object
void splitComponents(QMouseEvent* _event);
void biggestComponent(QMouseEvent* _event);
private :
//toolbar
QAction* splitAction_;
QAction* biggestAction_;
/** @} */
//===========================================================================
/** @name Template Functions
* @{ */
//===========================================================================
/// Split mesh into components
template< class MeshT >
void splitComponent( MeshT* _mesh, MeshT* _copy);
template< class MeshT >
void selectBiggestComponent( MeshT* _mesh);
template< class MeshT >
void isolateBiggestComponent( MeshT* _mesh);
/** @} */
//===========================================================================
/** @name Scripting Functions
* @{ */
//===========================================================================
public slots:
/// Split a mesh into components
IdList splitComponents( int _objectId );
void biggestComponent(int _objId);
public slots:
QString version() { return QString("1.0"); };
/** @} */
private:
/// set scripting slot descriptions
void setDescriptions();
};
#if defined(INCLUDE_TEMPLATES) && !defined(COMPONENTSPLUGIN_CC)
#define COMPONENTSPLUGIN_TEMPLATES
#include "ComponentsPluginT.cc"
#endif
//=============================================================================
#endif //CUTPLUGIN_HH
//=============================================================================
#define COMPONENTSPLUGIN_CC
#include "ComponentsPlugin.hh"
#include <iostream>
#include <queue>
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
//------------------------------------------------------------------------------
/** \brief Split mesh into components
*
* This function will split an arbitrary component out of a mesh.
* It takes a copy of the original mesh.
*
* @param _mesh the original mesh
* @param _copy original mesh copy with identical topology and geometry
* the copy will contain one component of the original mesh.
*/
template< class MeshT >
void
ComponentsPlugin::splitComponent( MeshT* _mesh, MeshT* _copy){
//init properties
OpenMesh::FPropHandleT< bool > visited;
if ( !_mesh->get_property_handle(visited,"visited") )
_mesh->add_property(visited, "visited");
typename MeshT::FaceIter f_it;
typename MeshT::FaceIter f_end = _mesh->faces_end();
//init property for all faces
for (f_it = _mesh->faces_begin(); f_it != f_end; ++f_it)
_mesh->property(visited, *f_it) = false;
typename MeshT::FaceHandle fh;
//Take the first face in the mesh as we only split one component apart
fh = *(_mesh->faces_begin());
_mesh->property(visited, fh) = true;
//if none was found -> finished
if (!fh.is_valid() ) return;
std::vector< typename MeshT::FaceHandle > handles;
handles.push_back( fh );
//grow from face and collect faces in this component
while( handles.size() > 0 ){
typename MeshT::FaceHandle current = handles.back();
handles.pop_back();
typename MeshT::FaceFaceIter ff_it;
for (ff_it=_mesh->ff_iter( current ); ff_it.is_valid(); ++ff_it)
if ( ! _mesh->property(visited, *ff_it) ){
_mesh->property(visited, *ff_it) = true;
handles.push_back( *ff_it );
}
}
//delete the found component from the original mesh and keep it in the copy
for (typename MeshT::FaceIter f_it = _mesh->faces_begin(); f_it != f_end; ++f_it)
// -1 means not the component
if ( _mesh->property(visited, *f_it) )
_mesh->delete_face( *f_it );
else
_copy->delete_face( *f_it );
//remove garbage from the components
_copy->garbage_collection();
_mesh->garbage_collection();
_mesh->remove_property(visited);
}
template< class MeshT >
void
ComponentsPlugin::selectBiggestComponent( MeshT* _mesh){
OpenMesh::FPropHandleT< bool > visited;
if ( !_mesh->get_property_handle(visited,"visited") )
_mesh->add_property(visited, "visited");
std::vector<typename MeshT::FaceHandle> facesInBiggest;
for (typename MeshT::FaceIter fIter = _mesh->faces_begin(); fIter != _mesh->faces_end(); ++fIter)
{
if (_mesh->property(visited,*fIter))
continue;
//It is a vertex, which is not visited => new component
std::vector<typename MeshT::FaceHandle> componentFaces;
componentFaces.push_back(*fIter);
for(std::size_t i = 0; i < componentFaces.size(); ++i )
{
//add all not visited neightbours
for (typename MeshT::FaceFaceIter ffIter = _mesh->ff_begin(componentFaces[i]); ffIter.is_valid() ;++ffIter)
{
if (!ffIter->is_valid())
std::cout << "handleId: " << *ffIter << std::endl;
if (ffIter->is_valid() && !_mesh->property(visited,*ffIter) )
{
_mesh->property(visited,*ffIter) = true;
componentFaces.push_back(*ffIter);
}
}
}
//all faces are found, so compare the components
if (facesInBiggest.size() < componentFaces.size())
{
std::swap(facesInBiggest,componentFaces);
}
}
_mesh->remove_property(visited);
//select all faces in the biggest component;
for (typename std::vector<typename MeshT::FaceHandle>::iterator iter = facesInBiggest.begin(); iter != facesInBiggest.end(); ++iter)
{
_mesh->status(*iter).set_selected(true);
}
}
template< class MeshT >
void
ComponentsPlugin::isolateBiggestComponent( MeshT* _mesh)
{
for (typename MeshT::FaceIter fIter = _mesh->faces_begin(); fIter != _mesh->faces_end(); ++fIter)
{
if (!_mesh->status(*fIter).selected())
{
//delete face and isolated vertices
_mesh->delete_face(*fIter,true);
}
else
{
_mesh->status(*fIter).set_selected(false);
}
}
_mesh->garbage_collection();
}
#include "ComponentsPlugin.hh"
#include <OpenFlipper/BasePlugin/PluginFunctions.hh>
#include <MeshTools/MeshInfoT.hh>
//------------------------------------------------------------------------------
/** \brief Set Descriptions for all scripting slots
*
*/
void ComponentsPlugin::setDescriptions(){
emit setSlotDescription("splitComponents(int)","Split the mesh into connected components. The original mesh is deleted.",
QStringList("objectId"), QStringList("Id of an object"));
emit setSlotDescription("biggestComponent(int)","Get the biggest component and delete the smaller ones.",
QStringList("objectId"),QStringList("Id of an object"));
}
//------------------------------------------------------------------------------
/** \brief splits the object into components
*
* i.e. creates (#components) new meshes and deletes the old mesh
*
* @param _objectId id of the target object
*/
IdList ComponentsPlugin::splitComponents( int _objectId ) {
// get object
BaseObjectData *obj;
PluginFunctions::getObject(_objectId, obj);
if (obj == 0){
emit log(LOGERR,"Unable to get object");
return IdList();
}
QFileInfo fi(obj->name());
if ( obj->dataType(DATA_TRIANGLE_MESH) ) {
TriMesh* mesh = PluginFunctions::triMesh(obj);
if ( mesh == 0 ) {
emit log(LOGERR,"Unable to get mesh");
return IdList();
}
int components = MeshInfo::componentCount( mesh );
//create empty meshes
std::vector< TriMesh* > newMeshes;
IdList newIDs;
newIDs.push_back( _objectId );
if (components == 1){
return newIDs;
}
QString currentName = obj->name();
QString extension = currentName.section('.', -1);
currentName = currentName.section('.',0,-2);
// Update name of original object
obj->setName(currentName+"_component_"+QString::number(0)+"."+extension);
for(int i=0; i < components-1; i++){
// Copy original Object
int id;
emit copyObject(obj->id(), id);
if (id == -1){
emit log(LOGERR, "Unable to generate a copy of object " + QString::number(obj->id()) );
return IdList();
}
// Get the target Object which will contain one component and is the copy of the original
BaseObjectData *curObj;
PluginFunctions::getObject(id, curObj);
curObj->setName(currentName+"_component_"+QString::number(i+1)+"."+extension);
TriMesh* curMesh = PluginFunctions::triMesh(curObj);
if ( curMesh == 0 ) {
emit log(LOGERR,"Unable to get mesh");
return IdList();
}
// Takes one component out of mesh, deletes it from mesh and adds it to curMesh
splitComponent( mesh, curMesh);
newIDs.push_back(id);
}
emit updatedObject(_objectId,UPDATE_ALL);