Skip to content
Snippets Groups Projects
Select Git revision
  • master default protected
  • test
  • feature_picking
3 results

MeshObjectSelectionPlugin.cc

Blame
  • MeshObjectSelectionPlugin.cc 101.68 KiB
    /*===========================================================================*\
     *                                                                           *
     *                              OpenFlipper                                  *
     *           Copyright (c) 2001-2015, RWTH-Aachen University                 *
     *           Department of Computer Graphics and Multimedia                  *
     *                          All rights reserved.                             *
     *                            www.openflipper.org                            *
     *                                                                           *
     *---------------------------------------------------------------------------*
     * This file is part of OpenFlipper.                                         *
     *---------------------------------------------------------------------------*
     *                                                                           *
     * Redistribution and use in source and binary forms, with or without        *
     * modification, are permitted provided that the following conditions        *
     * are met:                                                                  *
     *                                                                           *
     * 1. Redistributions of source code must retain the above copyright notice, *
     *    this list of conditions and the following disclaimer.                  *
     *                                                                           *
     * 2. Redistributions in binary form must reproduce the above copyright      *
     *    notice, this list of conditions and the following disclaimer in the    *
     *    documentation and/or other materials provided with the distribution.   *
     *                                                                           *
     * 3. Neither the name of the copyright holder nor the names of its          *
     *    contributors may be used to endorse or promote products derived from   *
     *    this software without specific prior written permission.               *
     *                                                                           *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       *
     * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
     * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A           *
     * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
     * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,  *
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,       *
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR        *
     * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF    *
     * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING      *
     * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS        *
     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.              *
     *                                                                           *
    \*===========================================================================*/
    
    #include "MeshObjectSelectionPlugin.hh"
    #include "widgets/ParameterWidget.hh"
    
    #include <MeshTools/MeshSelectionT.hh>
    
    
    //#include <QDesktopWidget>
    #include <QColorDialog>
    #include <QInputDialog>
    #include <QHBoxLayout>
    #include <QLabel>
    
    // Primitive type icons
    #define VERTEX_TYPE         "selection_vertex.png"
    #define EDGE_TYPE           "selection_edge.png"
    #define HEDGE_TYPE          "selection_halfedge.png"
    #define FACE_TYPE           "selection_face.png"
    // =======================================
    // Define operations
    // =======================================
    // General:
    #define G_CLEAR_HANDLE  "Clear Handle Region"
    #define G_CLEAR_MODEL   "Clear Modeling Region"
    #define G_CONVERT       "Convert Selection"
    // Vertices:
    #define V_SELECT_ALL    "Select All Vertices"
    #define V_CLEAR         "Clear Vertex Selection"
    #define V_INVERT        "Invert Vertex Selection"
    #define V_BOUNDARY      "Select Boundary Vertices"
    #define V_SHRINK        "Shrink Vertex Selection"
    #define V_GROW          "Grow Vertex Selection"
    #define V_DELETE        "Delete selected Vertices"
    #define V_COLORIZE      "Colorize selected Vertices"
    #define V_COPYSELECTION "Create mesh from Vertex Selection"
    #define V_HANDLE        "Set to Handle Region"
    #define V_MODELING      "Set to Modeling Region"
    #define V_LOAD_FLIPPER  "Load Flipper Selection"
    // Edges
    #define E_SELECT_ALL    "Select All Edges"
    #define E_CLEAR         "Clear Edge Selection"
    #define E_INVERT        "Invert Edge Selection"
    #define E_DELETE        "Delete selected Edges"
    #define E_BOUNDARY      "Select Boundary Edges"
    #define E_COLORIZE      "Colorize selected Edges"
    #define E_COPYSELECTION "Create mesh from Edge Selection"
    #define E_TRACE_PATH    "Trace Edge Path"
    
    // Halfedges
    #define HE_SELECT_ALL   "Select All Halfedges"
    #define HE_CLEAR        "Clear Halfedge Selection"
    #define HE_INVERT       "Invert Halfedge Selection"
    #define HE_BOUNDARY     "Select Boundary Halfedges"
    #define HE_COLORIZE     "Colorize selected Halfedges"
    // Faces
    #define F_SELECT_ALL    "Select All Faces"
    #define F_CLEAR         "Clear Face Selection"
    #define F_INVERT        "Invert Face Selection"
    #define F_DELETE        "Delete selected Faces"
    #define F_BOUNDARY      "Select Boundary Faces"
    #define F_SHRINK        "Shrink Face Selection"
    #define F_GROW          "Grow Face Selection"
    #define F_COLORIZE      "Colorize selected Faces"
    #define F_COPYSELECTION "Create mesh from Face Selection"
    
    //Colorize
    #define C_SELECTIONCOLOR "Selection Color"
    #define C_FEATURECOLOR "Feature Color"
    #define C_HANDLECOLOR "Handle Color"
    #define C_AREACOLOR "Area Color"
    
    /// Default constructor
    MeshObjectSelectionPlugin::MeshObjectSelectionPlugin() :
    vertexType_(0),
    edgeType_(0),
    halfedgeType_(0),
    faceType_(0),
    allSupportedTypes_(0u),
    conversionDialog_(0),
    parameterWidget_(nullptr),
    colorButtonSelection_(0),
    colorButtonArea_(0),
    colorButtonHandle_(0),
    colorButtonFeature_(0),
    dihedral_angle_threshold_(0.0),
    max_angle_( 2*M_PI)
    {
    }
          
    MeshObjectSelectionPlugin::~MeshObjectSelectionPlugin() {
        
        delete conversionDialog_;
        delete parameterWidget_;
    }
    
    void MeshObjectSelectionPlugin::initializePlugin() {
    
        // Tell core about all scriptable slots
        updateSlotDescriptions();
        
        // Create conversion dialog
        if(!OpenFlipper::Options::nogui()) {
            conversionDialog_ = new ConversionDialog(0);
            conversionDialog_->hide();
            connect(conversionDialog_->convertButton, SIGNAL(clicked()), this, SLOT(conversionRequested()));
            // Fill in combo boxes
            conversionDialog_->convertFromBox->addItems(
                QString("Vertex Selection;Edge Selection;Halfedge Selection;Face Selection;" \
                        "Feature Vertices;Feature Edges;Feature Faces;Handle Region;Modeling Region").split(";"));
            conversionDialog_->convertToBox->addItems(
                QString("Vertex Selection;Edge Selection;Halfedge Selection;Face Selection;" \
                        "Feature Vertices;Feature Edges;Feature Faces;Handle Region;Modeling Region").split(";"));
    
            parameterWidget_ = new ParameterWidget(nullptr);
    
        }
    }
    
    void MeshObjectSelectionPlugin::pluginsInitialized() {
        // Create new selection environment for mesh objects
        // and register mesh types tri- and polymeshes for
        // the environment.
        
        QString iconPath = OpenFlipper::Options::iconDirStr() + OpenFlipper::Options::dirSeparator();
        
        emit addSelectionEnvironment("Mesh Object Selections", "Select mesh object primitives such as vertices, (half-)edges and faces.",
                                     iconPath + "selections.png", environmentHandle_);
    
        // Register mesh object types
        emit registerType(environmentHandle_, DATA_POLY_MESH);
        emit registerType(environmentHandle_, DATA_TRIANGLE_MESH);
        
        // Register mesh primitive types
        emit addPrimitiveType(environmentHandle_, "Select Vertices",     iconPath + VERTEX_TYPE, vertexType_);
        emit addPrimitiveType(environmentHandle_, "Select Edges",        iconPath + EDGE_TYPE,   edgeType_);
        emit addPrimitiveType(environmentHandle_, "Select Halfedges",    iconPath + HEDGE_TYPE,  halfedgeType_);
        emit addPrimitiveType(environmentHandle_, "Select Faces",        iconPath + FACE_TYPE,   faceType_);
        
        // Combine all supported types
        allSupportedTypes_ = (vertexType_ | edgeType_ | halfedgeType_ | faceType_);
        
        // Determine, which selection modes are requested
        emit showToggleSelectionMode(environmentHandle_, true, allSupportedTypes_);
        emit showSphereSelectionMode(environmentHandle_, true, allSupportedTypes_);
    
        emit showLassoSelectionMode(environmentHandle_, true, allSupportedTypes_);
        emit showVolumeLassoSelectionMode(environmentHandle_, true, allSupportedTypes_);
    
        emit showFloodFillSelectionMode(environmentHandle_, true, allSupportedTypes_);
        emit showComponentsSelectionMode(environmentHandle_, true, allSupportedTypes_);
        emit showClosestBoundarySelectionMode(environmentHandle_, true, allSupportedTypes_);
        
        // Define general operations
        QStringList generalOperations;
        generalOperations.append(G_CLEAR_HANDLE);
        generalOperations.append(G_CLEAR_MODEL);
        generalOperations.append(G_CONVERT);
        
        // Define vertex operations
        QStringList vertexOperations;
        vertexOperations.append(V_SELECT_ALL);
        vertexOperations.append(V_CLEAR);
        vertexOperations.append(V_INVERT);
        vertexOperations.append(V_BOUNDARY);
        vertexOperations.append(V_SHRINK);
        vertexOperations.append(V_GROW);
        vertexOperations.append(V_DELETE);
        vertexOperations.append(V_COLORIZE);
        vertexOperations.append(V_COPYSELECTION);
        vertexOperations.append(V_HANDLE);
        vertexOperations.append(V_MODELING);
        vertexOperations.append(V_LOAD_FLIPPER);
        
        // Define edge operations
        QStringList edgeOperations;
        edgeOperations.append(E_SELECT_ALL);
        edgeOperations.append(E_CLEAR);
        edgeOperations.append(E_INVERT);
        edgeOperations.append(E_DELETE);
        edgeOperations.append(E_BOUNDARY);
        edgeOperations.append(E_COLORIZE);
        edgeOperations.append(E_COPYSELECTION);
        edgeOperations.append(E_TRACE_PATH);
        
        // Define halfedge operations
        QStringList hedgeOperations;
        hedgeOperations.append(HE_SELECT_ALL);
        hedgeOperations.append(HE_CLEAR);
        hedgeOperations.append(HE_INVERT);
        hedgeOperations.append(HE_BOUNDARY);
        hedgeOperations.append(HE_COLORIZE);
        
        // Define face operations
        QStringList faceOperations;
        faceOperations.append(F_SELECT_ALL);
        faceOperations.append(F_CLEAR);
        faceOperations.append(F_INVERT);
        faceOperations.append(F_DELETE);
        faceOperations.append(F_BOUNDARY);
        faceOperations.append(F_SHRINK);
        faceOperations.append(F_GROW);
        faceOperations.append(F_COLORIZE);
        faceOperations.append(F_COPYSELECTION);
        
        // Define colorize operations
        QStringList colorOperations;
        colorOperations.append(C_SELECTIONCOLOR);
        colorOperations.append(C_FEATURECOLOR);
        colorOperations.append(C_AREACOLOR);
        colorOperations.append(C_HANDLECOLOR);
    
        emit addSelectionOperations(environmentHandle_, generalOperations, "Selection Operations");
        emit addSelectionOperations(environmentHandle_, vertexOperations,  "Vertex Operations",   vertexType_);
        emit addSelectionOperations(environmentHandle_, edgeOperations,    "Edge Operations",     edgeType_);
        emit addSelectionOperations(environmentHandle_, hedgeOperations,   "Halfedge Operations", halfedgeType_);
        emit addSelectionOperations(environmentHandle_, faceOperations,    "Face Operations",     faceType_);
        emit addSelectionOperations(environmentHandle_, colorOperations, "Highlight Operations");
    
        if(!OpenFlipper::Options::nogui())
          emit addSelectionParameters(environmentHandle_, parameterWidget_, "Selection Parameters");
        
        // Register key shortcuts:
        
        // Select (a)ll
        emit registerKeyShortcut(Qt::Key_A, Qt::ControlModifier);
        // (C)lear selection (Only current selection)
        emit registerKeyShortcut(Qt::Key_C,      Qt::NoModifier);
        // (C)lear all selections
        emit registerKeyShortcut(Qt::Key_C,      Qt::ShiftModifier);
        // (I)nvert selection
        emit registerKeyShortcut(Qt::Key_I,      Qt::NoModifier);
        // Delete selected entities
        emit registerKeyShortcut(Qt::Key_Delete, Qt::NoModifier);
        // Select a vertex by ID
        emit registerKeyShortcut(Qt::Key_V,      Qt::NoModifier);
        // Select a halfedge by ID
        emit registerKeyShortcut(Qt::Key_H,      Qt::NoModifier);
        // Select a edge by ID
        emit registerKeyShortcut(Qt::Key_E,      Qt::NoModifier);
        // Select a face by ID
        emit registerKeyShortcut(Qt::Key_F,      Qt::NoModifier);
    
        // load default Color values
        std::string statusStr = OpenFlipperQSettings().value("SelectionMeshObject/StatusColor",QString()).toString().toStdString();
        std::string handleStr = OpenFlipperQSettings().value("SelectionMeshObject/HandleColor",QString()).toString().toStdString();
        std::string featureStr = OpenFlipperQSettings().value("SelectionMeshObject/FeatureColor",QString()).toString().toStdString();
        std::string areaStr = OpenFlipperQSettings().value("SelectionMeshObject/AreaColor",QString()).toString().toStdString();
        if (statusStr.empty() || handleStr.empty() || featureStr.empty() || areaStr.empty())
        {
          setDefaultColorValues();
        }
        else
        {
          std::stringstream sstream;
    
          sstream.str(statusStr);
          sstream >> statusColor_;
    
          sstream.str("");
          sstream.clear();
          sstream.str(handleStr);
          sstream >> handleColor_;
    
          sstream.str("");
          sstream.clear();
          sstream.str(featureStr);
          sstream >> featureColor_;
    
          sstream.str("");
          sstream.clear();
          sstream.str(areaStr);
          sstream >> areaColor_;
          updateColorValues(); //update GUI
        }
    
    }
    
    void MeshObjectSelectionPlugin::updateSlotDescriptions() {
        
        emit setSlotDescription("selectVertices(int,IdList)", tr("Select the specified vertices"),
                                QString("objectId,vertexList").split(","), QString("Id of object,List of vertices").split(","));
        emit setSlotDescription("unselectVertices(int,IdList)", tr("Unselect the specified vertices"),
                                QString("objectId,vertexList").split(","), QString("Id of object,List of vertices").split(","));
        emit setSlotDescription("selectAllVertices(int)", tr("Select all vertices of an object"),
                                QStringList("objectId"), QStringList("Id of object"));
        emit setSlotDescription("clearVertexSelection(int)", tr("Clear vertex selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("invertVertexSelection(int)", tr("Invert vertex selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("selectBoundaryVertices(int)", tr("Select all boundary vertices of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("selectClosestBoundaryVertices(int,int)", tr("Select boundary vertices closest to a specific vertex"),
                                QString("objectId,vertexId").split(","), QString("Id of an object,Id of closest vertex").split(","));
        emit setSlotDescription("shrinkVertexSelection(int)", tr("Shrink vertex selection by outer selection ring"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("growVertexSelection(int)", tr("Grow vertex selection by an-ring of selection"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("deleteVertexSelection(int)", tr("Delete selected vertices"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("createMeshFromVertexSelection(int)", tr("Take vertex selection and create a new mesh from it"),
                                QString("objectId").split(","), QString("Id of an object where the selection should be used to create a new mesh").split(","));
    
        emit setSlotDescription("selectVerticesByValue(int,QString,bool,double)", tr("Select vertices based on the value of their component"),
                                    QString("objectId,component,greater,value").split(","),
                                    QString("Id of an object where the selection should be used to create a new mesh,component specification: \"x\" or \"y\" or \"z\" ,true: select vertex if component greater than value; false: select if component less than value ,value to test").split(","));
    
        emit setSlotDescription("colorizeVertexSelection(int,int,int,int)", tr("Colorize the selected vertices"),
                                QString("objectId,r,g,b").split(","), QString("Id of an object,Red,Green,Blue").split(","));
        emit setSlotDescription("selectHandleVertices(int,IdList)", tr("Add specified vertices to handle area"),
                                QString("objectId,vertexList").split(","), QString("Id of an object,List of vertices").split(","));
        emit setSlotDescription("unselectHandleVertices(int,IdList)", tr("Remove specified vertices from handle area"),
                                QString("objectId,vertexList").split(","), QString("Id of an object,List of vertices").split(","));
        emit setSlotDescription("clearHandleVertices(int)", tr("Clear handle area"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("setAllHandleVertices(int)", tr("Add all vertices of an object to handle area"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("selectModelingVertices(int,IdList)", tr("Add specified vertices to modeling area"),
                                QString("objectId,vertexList").split(","), QString("Id of an object,List of vertices").split(","));
        emit setSlotDescription("unselectModelingVertices(int,IdList)", tr("Remove specified vertices to modeling area"),
                                QString("objectId,vertexList").split(","), QString("Id of an object,List of vertices").split(","));
        emit setSlotDescription("clearModelingVertices(int)", tr("Clear modeling area"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("setAllModelingVertices(int)", tr("Add al vertices of an object to modeling area"),
                                QStringList("objectId"), QStringList("Id of an object"));
        
        emit setSlotDescription("loadSelection(int,QString)", tr("Load selection from selection file"),
                                QString("objectId,filename").split(","), QString("Id of an object,Selection file").split(","));
    
        emit setSlotDescription("loadFlipperModelingSelection(int,QString)", tr("Load selection from Flipper selection file"),
                                QString("objectId,filename").split(","), QString("Id of an object,Flipper selection file").split(","));
        emit setSlotDescription("saveFlipperModelingSelection(int,QString)", tr("Save selection into Flipper selection file"),
                                QString("objectId,filename").split(","), QString("Id of an object,Flipper selection file").split(","));
        
        emit setSlotDescription("selectEdges(int,IdList)", tr("Select the specified edges"),
                                QString("objectId,edgeList").split(","), QString("Id of an object,List of edges").split(","));
        emit setSlotDescription("unselectEdges(int,IdList)", tr("Unselect the specified edges"),
                                QString("objectId,edgeList").split(","), QString("Id of an object,List of edges").split(","));
        emit setSlotDescription("selectAllEdges(int)", tr("Select all edges of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("invertEdgeSelection(int)", tr("Invert edge selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("clearEdgeSelection(int)", tr("Clear edge selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("selectBoundaryEdges(int)", tr("Select all boundary edges of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        
        emit setSlotDescription("colorizeEdgeSelection(int,int,int,int)", tr("Colorize the selected edges"),
                                QString("objectId,r,g,b").split(","), QString("Id of an object,Red,Green,Blue").split(","));
        emit setSlotDescription("createMeshFromEdgeSelection(int)", tr("Take edge selection and create a new mesh from it"),
                                QString("objectId").split(","), QString("Id of an object where the selection should be used to create a new mesh").split(","));
        
        emit setSlotDescription("selectHalfedges(int,IdList)", tr("Select the specified halfedges"),
                                QString("objectId,halfedgeList").split(","), QString("Id of an object,List of halfedges").split(","));
        emit setSlotDescription("unselectHalfedges(int,IdList)", tr("Unselect the specified halfedges"),
                                QString("objectId,halfedgeList").split(","), QString("Id of an object,List of halfedges").split(","));
        emit setSlotDescription("selectAllHalfedges(int)", tr("Select all halfedges of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("invertHalfedgeSelection(int)", tr("Invert halfedge selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("clearHalfedgeSelection(int)", tr("Clear halfedge selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("selectBoundaryHalfedges(int)", tr("Select all boundary halfedges of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        
        emit setSlotDescription("colorizeHalfedgeSelection(int,int,int,int)", tr("Colorize the selected halfedges"),
                                QString("objectId,r,g,b").split(","), QString("Id of an object,Red,Green,Blue").split(","));
                                
        emit setSlotDescription("selectFaces(int,IdList)", tr("Select the specified faces"),
                                QString("objectId,faceList").split(","), QString("Id of an object,List of faces").split(","));
        emit setSlotDescription("unselectFaces(int,IdList)", tr("Unselect the specified faces"),
                                QString("objectId,faceList").split(","), QString("Id of an object,List of faces").split(","));
        emit setSlotDescription("selectAllFaces(int)", tr("Select all vertices of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("clearFaceSelection(int)", tr("Clear face selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("invertFaceSelection(int)", tr("Invert face selection of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("selectBoundaryFaces(int)", tr("Select all boundary faces of an object"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("shrinkFaceSelection(int)", tr("Shrink face selection by outer face ring of selection"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("growFaceSelection(int)", tr("Grow face selection by an-ring of faces around selection"),
                                QStringList("objectId"), QStringList("Id of an object"));
        emit setSlotDescription("colorizeFaceSelection(int,int,int,int)", tr("Colorize the selected faces"),
                                QString("objectId,r,g,b").split(","), QString("Id of an object,Red,Green,Blue").split(","));
    
        emit setSlotDescription("createMeshFromFaceSelection(int)", tr("Take face selection and create a new mesh from it"),
                                QString("objectId").split(","), QString("Id of an object where the selection should be used to create a new mesh").split(","));
    
    
        QString conversionStrings = tr(" Possible strings:\n"
            "- Vertex/Edge/Halfedge/Face Selection\n"
            "- Model/Handle Region\n"
            "- Feature Vertices/Edges/Faces");
    
        emit setSlotDescription("convertSelection(int,QString,QString,bool)", tr("Convert the selection on given object. Conversion must be given as strings.")+conversionStrings ,
                                QString("objectId,from,to,deselect").split(","), QString("Id of an object,string of selection which will be converted,resulting selection or area,deselect selection after conversion").split(","));
    
        emit setSlotDescription("conversion(QString,QString,bool)", tr("Convert selection on all target Objects.")+conversionStrings,
                                QString("from,to,deselect").split(","), QString("string of selection which will be converted,resulting selection region or feature,deselect selection after conversion").split(","));
    
        emit setSlotDescription("convertEdgesToVertexPairs(int,IdList)", tr("Convert edge ids to vertex pair ids. Returns vertex Idlist."),
                                QString("objectId, edgeIds").split(","), QString("Id of an object, Ids of edges").split(","));
        emit setSlotDescription("convertHalfedgesToVertexPairs(int,IdList)", tr("Convert halfedge ids to vertex pair ids. Returns vertex Idlist."),
                                QString("objectId, halfedgeIds").split(","), QString("Id of an object, Ids of halfedges").split(","));
    
        emit setSlotDescription("convertVertexPairsToHalfedges(int,IdList)", tr("Convert vertex pair ids to halfedge ids. Returns halfedge Idlist."),
                                QString("objectId, vertexIds").split(","), QString("Id of an object, Ids of paired vertices").split(","));
        emit setSlotDescription("convertVertexPairsToEdges(int,IdList)", tr("Convert vertex pair ids to edge ids. Returns edge Idlist."),
                                QString("objectId, vertexIds").split(","), QString("Id of an object, Ids of paired vertices").split(","));
    }
    
    void MeshObjectSelectionPlugin::slotSelectionOperation(QString _operation) {
        
        SelectionInterface::PrimitiveType type = 0u;
        emit getActivePrimitiveType(type);
        
        if((type & allSupportedTypes_) == 0)
            return;
        
        // Test if operation should be applied to target objects only
        bool targetsOnly = false;
        emit targetObjectsOnly(targetsOnly);
        PluginFunctions::IteratorRestriction restriction =
                (targetsOnly ? PluginFunctions::TARGET_OBJECTS : PluginFunctions::ALL_OBJECTS);
        
        if(_operation == G_CLEAR_HANDLE) {
            // Clear handle region
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    clearHandleVertices(o_it->id());
            }
        } else if(_operation == G_CLEAR_MODEL) {
            // Clear modeling region
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    clearModelingVertices(o_it->id());
            }
        } else if(_operation == G_CONVERT) {
            // Convert vertex selection
            if(!OpenFlipper::Options::nogui())
                conversionDialog_->show();
        } else if(_operation == V_SELECT_ALL) {
            // Select all vertices
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectAllVertices(o_it->id());
            }
        } else if(_operation == V_CLEAR) {
            // Clear vertex selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    clearVertexSelection(o_it->id());
            }
        } else if(_operation == V_INVERT) {
            // Invert vertex selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    invertVertexSelection(o_it->id());
            }
        } else if(_operation == V_BOUNDARY) {
            // Select boundary vertices
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectBoundaryVertices(o_it->id());
            }
        } else if(_operation == V_SHRINK) {
            // Shrink vertex selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    shrinkVertexSelection(o_it->id());
            }
        } else if(_operation == V_GROW) {
            // Grow vertex selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    growVertexSelection(o_it->id());
            }
        } else if(_operation == V_DELETE) {
            // Delete vertex selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()){
                  deleteVertexSelection(o_it->id());
                  emit updatedObject(o_it->id(), UPDATE_GEOMETRY);
                  emit createBackup(o_it->id(), "Delete Vertices", UPDATE_GEOMETRY);
                }
            }
        } else if(_operation == V_COLORIZE) {
            // Colorize vertex selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    setColorForSelection(o_it->id(), vertexType_);
                }
            }
        } else if(_operation == V_COPYSELECTION) {
            // Copy vertex selection
            std::vector<int> objects;
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              if (o_it->visible()) {
                objects.push_back(o_it->id());
              }
            }
    
            for ( unsigned int i = 0 ; i < objects.size() ; ++i)
              createMeshFromSelection(objects[i],vertexType_);
    
        } else if(_operation == V_HANDLE) {
            // Set vertex selection to be handle region
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    std::vector<int> ids = getVertexSelection(o_it->id());
                    selectHandleVertices(o_it->id(), ids);
                    clearVertexSelection(o_it->id());
                }
            }
        } else if(_operation == V_MODELING) {
            // Set vertex selection to be modeling
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    std::vector<int> ids = getVertexSelection(o_it->id());
                    selectModelingVertices(o_it->id(), ids);
                    clearVertexSelection(o_it->id());
                }
            }
        } else if(_operation == V_LOAD_FLIPPER) {
            // Load Flipper selection file
            QString fileName = QFileDialog::getOpenFileName(0,
                    tr("Open Flipper Selection File"), OpenFlipper::Options::dataDirStr(),
                    tr("Flipper Selection Files (*.sel)"));
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    loadFlipperModelingSelection(o_it->id(), fileName);
                }
            }
        } else if(_operation == E_SELECT_ALL) {
            // Select all edges
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectAllEdges(o_it->id());
            }
        } else if(_operation == E_CLEAR) {
            // Clear edge selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    clearEdgeSelection(o_it->id());
            }
        } else if(_operation == E_INVERT) {
            // Invert edge selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    invertEdgeSelection(o_it->id());
            }
        } else if(_operation == E_DELETE) {
            // Delete edge selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    deleteEdgeSelection(o_it->id());
            }
        } else if(_operation == E_BOUNDARY) {
            // Select boundary edges
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectBoundaryEdges(o_it->id());
            }
        } else if(_operation == E_COLORIZE) {
            // Colorize edge selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    setColorForSelection(o_it->id(), edgeType_);
                }
            }
        } else if(_operation == E_COPYSELECTION) {
          // Copy edge selection
          std::vector<int> objects;
          for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL));
              o_it != PluginFunctions::objectsEnd(); ++o_it) {
            if (o_it->visible()) {
              objects.push_back(o_it->id());
            }
          }
    
          for ( unsigned int i = 0 ; i < objects.size() ; ++i)
            createMeshFromSelection(objects[i],edgeType_);
    
        } else if (_operation == E_TRACE_PATH) {
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    traceEdgePath(o_it->id(), .9);
                }
            }
        } else if(_operation == HE_SELECT_ALL) {
            // Select all edges
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectAllHalfedges(o_it->id());
            }
        } else if(_operation == HE_CLEAR) {
            // Clear edge selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    clearHalfedgeSelection(o_it->id());
            }
        } else if(_operation == HE_INVERT) {
            // Invert edge selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    invertHalfedgeSelection(o_it->id());
            }
        } else if(_operation == HE_BOUNDARY) {
            // Select boundary edges
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectBoundaryHalfedges(o_it->id());
            }
        } else if(_operation == HE_COLORIZE) {
            // Colorize halfedge selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    setColorForSelection(o_it->id(), halfedgeType_);
                }
            }
        } else if(_operation == F_SELECT_ALL) {
            // Select all faces
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectAllFaces(o_it->id());
            }
        } else if(_operation == F_CLEAR) {
            // Clear face selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    clearFaceSelection(o_it->id());
            }
        } else if(_operation == F_INVERT) {
            // Invert face selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    invertFaceSelection(o_it->id());
            }
        } else if(_operation == F_DELETE) {
            // Delete face selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    deleteFaceSelection(o_it->id());
            }
        } else if(_operation == F_BOUNDARY) {
            // Select boundary faces
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    selectBoundaryFaces(o_it->id());
            }
        } else if(_operation == F_SHRINK) {
            // Shrink face selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    shrinkFaceSelection(o_it->id());
            }
        } else if(_operation == F_GROW) {
            // Grow face selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible())
                    growFaceSelection(o_it->id());
            }
        } else if(_operation == F_COLORIZE) {
            // Colorize face selection
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    setColorForSelection(o_it->id(), faceType_);
                }
            }
        } else if(_operation == F_COPYSELECTION) {
          // Copy face selection
          std::vector<int> objects;
          for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_ALL));
              o_it != PluginFunctions::objectsEnd(); ++o_it) {
            if (o_it->visible()) {
              objects.push_back(o_it->id());
            }
          }
    
          for ( unsigned int i = 0 ; i < objects.size() ; ++i)
            createMeshFromSelection(objects[i],faceType_);
        } else if(_operation == C_SELECTIONCOLOR) {
          QColor newColor = QColorDialog::getColor(QColor::fromRgbF(statusColor_[0],statusColor_[1],statusColor_[2],statusColor_[3]), 0, "Pick Color", QColorDialog::ShowAlphaChannel);
          if (newColor.isValid())
          {
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_POLY_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              PolyMeshObject* poly = 0;
              PluginFunctions::getObject(o_it->id(),poly);
              poly->setSelectionColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              TriMeshObject* tri = 0;
              PluginFunctions::getObject(o_it->id(),tri);
              tri->setSelectionColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            emit updateView();
          }
    
        }else if(_operation == C_FEATURECOLOR) {
          QColor newColor = QColorDialog::getColor(QColor::fromRgbF(featureColor_[0],featureColor_[1],featureColor_[2],featureColor_[3]), 0, "Pick Color", QColorDialog::ShowAlphaChannel);
          if (newColor.isValid())
          {
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_POLY_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              PolyMeshObject* poly = 0;
              PluginFunctions::getObject(o_it->id(),poly);
              poly->setFeatureColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              TriMeshObject* tri = 0;
              PluginFunctions::getObject(o_it->id(),tri);
              tri->setFeatureColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            emit updateView();
          }
    
        }else if(_operation == C_HANDLECOLOR) {
          QColor newColor = QColorDialog::getColor(QColor::fromRgbF(handleColor_[0],handleColor_[1],handleColor_[2],handleColor_[3]), 0, "Pick Color", QColorDialog::ShowAlphaChannel);
          if (newColor.isValid())
          {
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_POLY_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              PolyMeshObject* poly = 0;
              PluginFunctions::getObject(o_it->id(),poly);
              poly->setHandleColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              TriMeshObject* tri = 0;
              PluginFunctions::getObject(o_it->id(),tri);
              tri->setHandleColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            emit updateView();
          }
    
        }else if(_operation == C_AREACOLOR) {
          QColor newColor = QColorDialog::getColor(QColor::fromRgbF(areaColor_[0],areaColor_[1],areaColor_[2],areaColor_[3]), 0, "Pick Color", QColorDialog::ShowAlphaChannel);
          if (newColor.isValid())
          {
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_POLY_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              PolyMeshObject* poly = 0;
              PluginFunctions::getObject(o_it->id(),poly);
              poly->setAreaColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH));
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
              TriMeshObject* tri = 0;
              PluginFunctions::getObject(o_it->id(),tri);
              tri->setAreaColor(ACG::Vec4f(newColor.redF(),newColor.greenF(),newColor.blueF(),newColor.alphaF()));
            }
            emit updateView();
          }
    
        }
    }
    
    void MeshObjectSelectionPlugin::setColorForSelection(const int _objectId, const PrimitiveType _primitiveTypes) {
        
        QColor c = QColorDialog::getColor(Qt::red, 0, tr("Choose color"),QColorDialog::ShowAlphaChannel);
        
        if(c.isValid()) {
            if(_primitiveTypes & vertexType_) {
                // Vertex colorization
                colorizeVertexSelection(_objectId, c.red(), c.green(), c.blue(), c.alpha());
            } else if (_primitiveTypes & edgeType_) {
                // Edge colorization
                colorizeEdgeSelection(_objectId, c.red(), c.green(), c.blue(), c.alpha());
            } else if (_primitiveTypes & halfedgeType_) {
                // Edge colorization
                colorizeHalfedgeSelection(_objectId, c.red(), c.green(), c.blue(), c.alpha());
            } else if (_primitiveTypes & faceType_) {
                // Edge colorization
                colorizeFaceSelection(_objectId, c.red(), c.green(), c.blue(), c.alpha());
            }
        }
    }
    
    void MeshObjectSelectionPlugin::conversionRequested() {
        
        conversionDialog_->hide();
        
        QString from = conversionDialog_->convertFromBox->currentText();
        QString to = conversionDialog_->convertToBox->currentText();
        
        if(from == to) return;
        
        bool deselect = true;
        if(!OpenFlipper::Options::nogui()) {
            deselect = conversionDialog_->deselect->isChecked();
        }
        
        conversion(from, to, deselect);
    }
    
    void MeshObjectSelectionPlugin::convertSelection(const int& _objectId ,const QString& _from, const QString& _to, bool _deselect) {
      BaseObject* object = 0;
    
      PluginFunctions::getObject(_objectId,object);
    
      if ( object == 0 ) {
        emit log(LOGERR,"Object not found in convertSelection");
        return;
      }
    
      if(_from == "Vertex Selection") {
        if (_to == "Edge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToEdgeSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToEdgeSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Halfedge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToHalfedgeSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToHalfedgeSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Face Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToFaceSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToFaceSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Feature Vertices") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexSelectionToFeatureVertices(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexSelectionToFeatureVertices(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Handle Region") {
          selectHandleVertices(_objectId, getVertexSelection(_objectId));
        } else if (_to == "Modeling Region") {
          selectModelingVertices(_objectId, getVertexSelection(_objectId));
        }
    
        if(_deselect) {
          clearVertexSelection(_objectId);
        }
    
      } else if (_from == "Edge Selection") {
        if(_to == "Vertex Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertEdgeToVertexSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertEdgeToVertexSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Halfedge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertEdgeToHalfedgeSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertEdgeToHalfedgeSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Face Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertEdgeToFaceSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertEdgeToFaceSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Feature Edges") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertEdgeSelectionToFeatureEdges(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertEdgeSelectionToFeatureEdges(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Handle Region") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            TriMesh* mesh = PluginFunctions::triMesh(_objectId);
            std::vector<int> ids;
            for(auto e_it : mesh->edges()) {
              if(mesh->status(e_it).selected()) {
                ids.push_back(e_it.h0().to().idx());
                ids.push_back(e_it.h1().to().idx());
              }
            }
            selectHandleVertices(_objectId, ids);
          } else if(object->dataType() == DATA_POLY_MESH) {
            PolyMesh* mesh = PluginFunctions::polyMesh(_objectId);
            std::vector<int> ids;
            for(auto e_it : mesh->edges()) {
              if(mesh->status(e_it).selected()) {
                ids.push_back(e_it.h0().to().idx());
                ids.push_back(e_it.h1().to().idx());
              }
            }
            selectHandleVertices(_objectId, ids);
          }
        } else if (_to == "Modeling Region") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            TriMesh* mesh = PluginFunctions::triMesh(_objectId);
            std::vector<int> ids;
            for(auto e_it : mesh->edges()) {
              if(mesh->status(e_it).selected()) {
                ids.push_back(e_it.h0().to().idx());
                ids.push_back(e_it.h1().to().idx());
              }
            }
            selectModelingVertices(_objectId, ids);
          } else if(object->dataType() == DATA_POLY_MESH) {
            PolyMesh* mesh = PluginFunctions::polyMesh(_objectId);
            std::vector<int> ids;
            for(auto e_it : mesh->edges()) {
              if(mesh->status(e_it).selected()) {
                ids.push_back(e_it.h0().to().idx());
                ids.push_back(e_it.h1().to().idx());
              }
            }
            selectModelingVertices(_objectId, ids);
          }
        }
    
        if(_deselect) {
          clearEdgeSelection(_objectId);
        }
      } else if (_from == "Halfedge Selection") {
        if(_to == "Vertex Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertHalfedgeToVertexSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertHalfedgeToVertexSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Edge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertHalfedgeToEdgeSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertHalfedgeToEdgeSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Face Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertHalfedgeToFaceSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertHalfedgeToFaceSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Handle Region") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            TriMesh* mesh = PluginFunctions::triMesh(_objectId);
            std::vector<int> ids;
            for(auto h_it : mesh->halfedges()) {
              if(mesh->status(h_it).selected()) {
                ids.push_back(h_it.to().idx());
                ids.push_back(h_it.from().idx());
              }
            }
            selectHandleVertices(_objectId, ids);
          } else if(object->dataType() == DATA_POLY_MESH) {
            PolyMesh* mesh = PluginFunctions::polyMesh(_objectId);
            std::vector<int> ids;
            for(auto h_it : mesh->halfedges()) {
              if(mesh->status(h_it).selected()) {
                ids.push_back(h_it.to().idx());
                ids.push_back(h_it.from().idx());
              }
            }
            selectHandleVertices(_objectId, ids);
          }
        } else if (_to == "Modeling Region") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            TriMesh* mesh = PluginFunctions::triMesh(_objectId);
            std::vector<int> ids;
            for(auto h_it : mesh->halfedges()) {
              if(mesh->status(h_it).selected()) {
                ids.push_back(h_it.to().idx());
                ids.push_back(h_it.from().idx());
              }
            }
            selectModelingVertices(_objectId, ids);
          } else if(object->dataType() == DATA_POLY_MESH) {
            PolyMesh* mesh = PluginFunctions::polyMesh(_objectId);
            std::vector<int> ids;
            for(auto h_it : mesh->halfedges()) {
              if(mesh->status(h_it).selected()) {
                ids.push_back(h_it.to().idx());
                ids.push_back(h_it.from().idx());
              }
            }
            selectModelingVertices(_objectId, ids);
          }
        }
    
        if(_deselect) {
          clearHalfedgeSelection(_objectId);
        }
      } else if (_from == "Face Selection") {
        if(_to == "Vertex Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertFaceToVertexSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertFaceToVertexSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Edge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertFaceToEdgeSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertFaceToEdgeSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Feature Faces") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertFaceSelectionToFeatureFaces(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertFaceSelectionToFeatureFaces(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Halfedge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertFaceToHalfedgeSelection(PluginFunctions::triMesh(_objectId));
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertFaceToHalfedgeSelection(PluginFunctions::polyMesh(_objectId));
        } else if (_to == "Handle Region") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            TriMesh* mesh = PluginFunctions::triMesh(_objectId);
            std::vector<int> ids;
            for(auto f_it : mesh->faces()) {
              if(mesh->status(f_it).selected()) {
                for(auto fv_it : f_it.vertices()) {
                  ids.push_back(fv_it.idx());
                }
              }
            }
            selectHandleVertices(_objectId, ids);
          } else if(object->dataType() == DATA_POLY_MESH) {
            PolyMesh* mesh = PluginFunctions::polyMesh(_objectId);
            std::vector<int> ids;
            for(auto f_it : mesh->faces()) {
              if(mesh->status(f_it).selected()) {
                for(auto fv_it : f_it.vertices()) {
                  ids.push_back(fv_it.idx());
                }
              }
            }
            selectHandleVertices(_objectId, ids);
          }
        } else if (_to == "Modeling Region") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            TriMesh* mesh = PluginFunctions::triMesh(_objectId);
            std::vector<int> ids;
            for(auto f_it : mesh->faces()) {
              if(mesh->status(f_it).selected()) {
                for(auto fv_it : f_it.vertices()) {
                  ids.push_back(fv_it.idx());
                }
              }
            }
            selectModelingVertices(_objectId, ids);
          } else if(object->dataType() == DATA_POLY_MESH) {
            PolyMesh* mesh = PluginFunctions::polyMesh(_objectId);
            std::vector<int> ids;
            for(auto f_it : mesh->faces()) {
              if(mesh->status(f_it).selected()) {
                for(auto fv_it : f_it.vertices()) {
                  ids.push_back(fv_it.idx());
                }
              }
            }
            selectModelingVertices(_objectId, ids);
          }
        }
    
        if(_deselect) {
          clearFaceSelection(_objectId);
        }
      } else if (_from == "Feature Vertices") {
    
        if (_to == "Vertex Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            MeshSelection::convertFeatureVerticesToVertexSelection(PluginFunctions::triMesh(_objectId));
            if (_deselect) {
              MeshSelection::clearFeatureVertices(PluginFunctions::triMesh(_objectId));
            }
          } else if(object->dataType() == DATA_POLY_MESH) {
            MeshSelection::convertFeatureVerticesToVertexSelection(PluginFunctions::polyMesh(_objectId));
            if (_deselect) {
              MeshSelection::clearFeatureVertices(PluginFunctions::polyMesh(_objectId));
            }
          }
        }
      } else if (_from == "Feature Edges") {
    
        if (_to == "Edge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            MeshSelection::convertFeatureEdgesToEdgeSelection(PluginFunctions::triMesh(_objectId));
            if (_deselect) {
              MeshSelection::clearFeatureEdges(PluginFunctions::triMesh(_objectId));
            }
          } else if(object->dataType() == DATA_POLY_MESH) {
            MeshSelection::convertFeatureEdgesToEdgeSelection(PluginFunctions::polyMesh(_objectId));
            if (_deselect) {
              MeshSelection::clearFeatureEdges(PluginFunctions::polyMesh(_objectId));
            }
          }
        }
      } else if (_from == "Feature Faces") {
    
        if (_to == "Face Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH) {
            MeshSelection::convertFeatureFacesToFaceSelection(PluginFunctions::triMesh(_objectId));
            if (_deselect) {
              MeshSelection::clearFeatureFaces(PluginFunctions::triMesh(_objectId));
            }
          } else if(object->dataType() == DATA_POLY_MESH) {
            MeshSelection::convertFeatureFacesToFaceSelection(PluginFunctions::polyMesh(_objectId));
            if (_deselect) {
              MeshSelection::clearFeatureFaces(PluginFunctions::polyMesh(_objectId));
            }
          }
        }
      } else if (_from == "Handle Region") {
        std::vector<int> ids = getHandleVertices(_objectId);
        if(_to == "Vertex Selection") {
          selectVertices(_objectId, ids);
        } else if (_to == "Edge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToEdgeSelection(PluginFunctions::triMesh(_objectId), ids);
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToEdgeSelection(PluginFunctions::polyMesh(_objectId), ids);
        } else if (_to == "Halfedge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToHalfedgeSelection(PluginFunctions::triMesh(_objectId), ids);
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToHalfedgeSelection(PluginFunctions::polyMesh(_objectId), ids);
        } else if (_to == "Face Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToFaceSelection(PluginFunctions::triMesh(_objectId), ids);
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToFaceSelection(PluginFunctions::polyMesh(_objectId), ids);
        } else if (_to == "Modeling Region") {
          selectModelingVertices(_objectId, ids);
        }
    
        if(_deselect) {
          clearHandleVertices(_objectId);
        }
    
      } else if (_from == "Modeling Region") {
        std::vector<int> ids = getModelingVertices(_objectId);
        if(_to == "Vertex Selection") {
          selectVertices(_objectId, ids);
        } else if (_to == "Edge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToEdgeSelection(PluginFunctions::triMesh(_objectId), ids);
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToEdgeSelection(PluginFunctions::polyMesh(_objectId), ids);
        } else if (_to == "Halfedge Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToHalfedgeSelection(PluginFunctions::triMesh(_objectId), ids);
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToHalfedgeSelection(PluginFunctions::polyMesh(_objectId), ids);
        } else if (_to == "Face Selection") {
          if(object->dataType() == DATA_TRIANGLE_MESH)
            MeshSelection::convertVertexToFaceSelection(PluginFunctions::triMesh(_objectId), ids);
          else if(object->dataType() == DATA_POLY_MESH)
            MeshSelection::convertVertexToFaceSelection(PluginFunctions::polyMesh(_objectId), ids);
        } else if (_to == "Handle Region") {
          selectHandleVertices(_objectId, ids);
        }
    
        if(_deselect) {
          clearModelingVertices(_objectId);
        }
      }
    
      emit updatedObject(_objectId, UPDATE_SELECTION);
    
    }
    
    
    void MeshObjectSelectionPlugin::conversion(const QString& _from, const QString& _to, bool _deselect) {
    
      for (PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH));
             o_it != PluginFunctions::objectsEnd(); ++o_it) {
    
            convertSelection(o_it->id(),_from,_to,_deselect);
            emit createBackup(o_it->id(), "Selection Conversion", UPDATE_SELECTION);
        }
    }
    
    void MeshObjectSelectionPlugin::slotToggleSelection(QMouseEvent* _event, SelectionInterface::PrimitiveType _currentType, bool _deselect) {
        
        // Return if none of the currently active types is handled by this plugin
        if((_currentType & allSupportedTypes_) == 0) return;
        
        size_t node_idx, target_idx;
        ACG::Vec3d hit_point;
    
        // First of all, pick anything to find all possible objects
        if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING,
            _event->pos(), node_idx, target_idx, &hit_point)) {
    
            BaseObjectData* object(0);
            PluginFunctions::getPickedObject(node_idx, object);
            if(!object) return;
        
            if (object->dataType() == DATA_TRIANGLE_MESH) {
                // Pick triangle meshes
                if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
    
                    if (object->dataType(DATA_TRIANGLE_MESH)) {
                        toggleMeshSelection(object->id(), PluginFunctions::triMesh(object), target_idx, hit_point, _currentType);
                    }
                } else {
                  // Pick point cloud
                  TriMesh* mesh = PluginFunctions::triMesh(object);
    
                  if (mesh->n_vertices() && !mesh->n_faces()) {
                    if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_VERTEX, _event->pos(), node_idx, target_idx, &hit_point)) {
    
                      TriMesh::VertexHandle vh = mesh->vertex_handle(target_idx);
                      mesh->status(vh).set_selected(!mesh->status(vh).selected());
    
                      if (mesh->status(vh).selected())
                        emit scriptInfo("selectVertices(ObjectId(" + QString::number(object->id()) + ") , [" + QString::number(vh.idx()) + "])");
                      else
                        emit scriptInfo("unselectVertices(ObjectId(" + QString::number(object->id()) + ") , [" + QString::number(vh.idx()) + "])");
                      emit updatedObject(object->id(), UPDATE_SELECTION_VERTICES);
                    }
                  }
                }
            } else if (object->dataType() == DATA_POLY_MESH) {
                // Pick poly meshes
                if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
    
                    if (object->dataType(DATA_POLY_MESH)) {
                        toggleMeshSelection(object->id(), PluginFunctions::polyMesh(object), target_idx, hit_point, _currentType);
                    }
                }
            }
            emit updatedObject(object->id(), UPDATE_SELECTION);
            emit createBackup(object->id(), "Toggle Selection", UPDATE_SELECTION);
        }
    }
    
    void MeshObjectSelectionPlugin::slotLassoSelection(QMouseEvent* _event, PrimitiveType _currentType, bool _deselect) {
        
        // Return if none of the currently active types is handled by this plugin
        if((_currentType & allSupportedTypes_) == 0) return;
       
        if(_event->type() == QEvent::MouseButtonPress) {
     
            // Add picked point
            lasso_2Dpoints_.push_back(_event->pos());
            
            return;
    
        } else if(_event->type() == QEvent::MouseButtonDblClick) {
            
            // Finish surface lasso selection
            if (lasso_2Dpoints_.size() > 2) {
    
                QRegion region(lasso_2Dpoints_);
                
                lassoSelect(region, _currentType, _deselect);
            }
            
            // Clear points
            lasso_2Dpoints_.clear();
        }
    }
    
    void MeshObjectSelectionPlugin::slotVolumeLassoSelection(QMouseEvent* _event, PrimitiveType _currentType, bool _deselect) {
        
        // Return if none of the currently active types is handled by this plugin
        if((_currentType & allSupportedTypes_) == 0) return;
        
        if(_event->type() == QEvent::MouseButtonPress) {
    
            // Add point on viewing plane to selection polygon
            volumeLassoPoints_.append(_event->pos());
            
            return;
    
        } else if(_event->type() == QEvent::MouseButtonDblClick) {
    
            ACG::GLState &state = PluginFunctions::viewerProperties().glState();
            bool updateGL = state.updateGL();
            state.set_updateGL (false);
    
            QPolygon p(volumeLassoPoints_);
            QRegion region = QRegion(p);
    
            SelectVolumeAction action(region, this, _currentType, _deselect, state);
            ACG::SceneGraph::traverse (PluginFunctions::getRootNode(), action);
    
            state.set_updateGL(updateGL);
    
            // Clear lasso points
            volumeLassoPoints_.clear();
        }
    }
    
    void MeshObjectSelectionPlugin::slotSphereSelection(QMouseEvent* _event, double _radius, PrimitiveType _currentType, bool _deselect) {
        
        // Return if none of the currently active types is handled by this plugin
        if((_currentType & allSupportedTypes_) == 0) return;
        
        size_t 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 = 0;
    
            if (PluginFunctions::getPickedObject(node_idx, object)) {
    
                if (object->picked(node_idx) && object->dataType(DATA_TRIANGLE_MESH)) {
                    paintSphereSelection(PluginFunctions::triMesh(object), object->id(), target_idx, hit_point, _radius, _currentType, _deselect);
                } else if (object->picked(node_idx) && object->dataType(DATA_POLY_MESH)) {
                    paintSphereSelection(PluginFunctions::polyMesh(object), object->id(), target_idx, hit_point, _radius, _currentType, _deselect);
                }
    
                emit updatedObject(object->id(), UPDATE_SELECTION);
                if ( _event->type() == QEvent::MouseButtonRelease )
                  emit  createBackup(object->id(), "Sphere Selection", UPDATE_SELECTION);
            }
        }
    }
    
    void MeshObjectSelectionPlugin::slotClosestBoundarySelection(QMouseEvent* _event, PrimitiveType _currentType, bool _deselect) {
        
        // Return if none of the currently active types is handled by this plugin
        if((_currentType & allSupportedTypes_) == 0) return;
    
        size_t 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 = 0;
    
            if(PluginFunctions::getPickedObject(node_idx, object)) {
    
                if(object->dataType(DATA_TRIANGLE_MESH)) {
    
                    TriMesh* m = PluginFunctions::triMesh(object);
                    TriMesh::VertexHandle vh = *(m->fv_iter(m->face_handle(target_idx)));
    
                    closestBoundarySelection(m, vh.idx(), _currentType, _deselect);
    
                    emit updatedObject(object->id(), UPDATE_SELECTION);
                    emit  createBackup(object->id(), "Boundary Selection", UPDATE_SELECTION);
    
                } else if(object->dataType(DATA_POLY_MESH)) {
    
                    PolyMesh* m = PluginFunctions::polyMesh(object);
                    PolyMesh::VertexHandle vh = *(m->fv_iter(m->face_handle(target_idx)));
    
                    closestBoundarySelection(m, vh.idx(), _currentType, _deselect);
    
                    emit updatedObject(object->id(), UPDATE_SELECTION);
                    emit  createBackup(object->id(), "Boundary Selection", UPDATE_SELECTION);
                }
                
                emit updateView();
            }
        }
    }
    
    void MeshObjectSelectionPlugin::slotFloodFillSelection(QMouseEvent* _event, PrimitiveType _currentType, bool _deselect) {
        
        // Return if none of the currently active types is handled by this plugin
        if((_currentType & allSupportedTypes_) == 0) return;
        
        size_t node_idx, target_idx;
        ACG::Vec3d hit_point;
    
        if(!OpenFlipper::Options::nogui())
          max_angle_ = parameterWidget_->maxAngle->value();
    
        // pick Anything to find all possible objects
        if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING,
                                            _event->pos(), node_idx, target_idx, &hit_point)) {
    
            BaseObjectData* object = 0;
            
            if(PluginFunctions::getPickedObject(node_idx, object)) {
    
                // TRIANGLE MESHES
                if(object->dataType() == DATA_TRIANGLE_MESH) {
    
                    if(PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) {
    
                        if(PluginFunctions::getPickedObject(node_idx, object)) {
    
                            if(object->dataType(DATA_TRIANGLE_MESH)) {
                                floodFillSelection(
                                        PluginFunctions::triMesh(object),
                                        object->id(), target_idx, max_angle_,
                                        _currentType, _deselect);
                                emit updatedObject(object->id(), UPDATE_SELECTION);
                                emit  createBackup(object->id(), "FloodFill Selection", UPDATE_SELECTION);
                            }
                        }
                    }
    
                // POLY MESHES
                } else if(object->dataType() == DATA_POLY_MESH) {
    
                    if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(), node_idx, target_idx, &hit_point)) {
    
                        if(PluginFunctions::getPickedObject(node_idx, object) ) {
    
                            if(object->dataType(DATA_POLY_MESH)) {
                                floodFillSelection(
                                        PluginFunctions::polyMesh(object),
                                        object->id(), target_idx, max_angle_,
                                        _currentType, _deselect);
                                emit updatedObject(object->id(), UPDATE_SELECTION);
                                emit  createBackup(object->id(), "FloodFill Selection", UPDATE_SELECTION);
                            }
                        }
                    }
                }
                else {
                    emit log(LOGERR,tr("floodFillSelection: Unsupported dataType"));
                }
            }
        }
    }
    
    void MeshObjectSelectionPlugin::slotComponentsSelection(QMouseEvent* _event, SelectionInterface::PrimitiveType _currentType, bool _deselect) {
    
        // Return if none of the currently active types is handled by this plugin
        if((_currentType & allSupportedTypes_) == 0) return;
    
        size_t node_idx, target_idx;
        ACG::Vec3d hit_point;
    
        // First of all, pick anything to find all possible objects
        if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_ANYTHING,
            _event->pos(), node_idx, target_idx, &hit_point)) {
    
            BaseObjectData* object(0);
            PluginFunctions::getPickedObject(node_idx, object);
            if(!object) return;
    
            if (object->dataType() == DATA_TRIANGLE_MESH) {
                // Pick triangle meshes
                if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
    
                    if (object->dataType(DATA_TRIANGLE_MESH)) {
                        componentsMeshSelection(PluginFunctions::triMesh(object),
                                object->id(), target_idx, hit_point, _currentType);
                    }
                }
            } else if (object->dataType() == DATA_POLY_MESH) {
                // Pick poly meshes
                if (PluginFunctions::scenegraphPick(ACG::SceneGraph::PICK_FACE, _event->pos(),node_idx, target_idx, &hit_point)) {
    
                    if (object->dataType(DATA_POLY_MESH)) {
                        componentsMeshSelection(PluginFunctions::polyMesh(object),
                                object->id(), target_idx, hit_point, _currentType);
                    }
                }
            }
            emit updatedObject(object->id(), UPDATE_SELECTION);
            emit createBackup(object->id(), "Connected Components Selection", UPDATE_SELECTION);
        }
    }
    
    void MeshObjectSelectionPlugin::slotIndexSelection(int _key)
    {
    
      bool targetsOnly = false;
      emit targetObjectsOnly(targetsOnly);
      PluginFunctions::IteratorRestriction restriction =
              (targetsOnly ? PluginFunctions::TARGET_OBJECTS : PluginFunctions::ALL_OBJECTS);
    
      int visible_objects = 0;
      for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH));
           o_it != PluginFunctions::objectsEnd(); ++o_it)
      {
        if (o_it->visible()) {
          ++visible_objects;
        }
      }
    
      bool fly = visible_objects == 1; // only fly to selection if a single object is processed
    
      int idx;
      switch (_key)
      {
        case Qt::Key_V:
          idx = QInputDialog::getInt(nullptr, tr("Vertex to mark"), tr("Vertex idx:"), -1);
          break;
        case Qt::Key_H:
          idx = QInputDialog::getInt(nullptr, tr("Halfedge to mark"), tr("Halfedge idx:"), -1);
          break;
        case Qt::Key_E:
          idx = QInputDialog::getInt(nullptr, tr("Edge to mark"), tr("Edge idx:"), -1);
          break;
        case Qt::Key_F:
          idx = QInputDialog::getInt(nullptr, tr("Face to mark"), tr("Face idx:"), -1);
          break;
        default:
          idx = -1;
      }
    
      if (idx < 0)
        return;
    
      for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH));
           o_it != PluginFunctions::objectsEnd(); ++o_it) {
        bool selected_something = false;
        if (o_it->visible()) {
          if(_key == Qt::Key_V)
            selected_something = selectVertex(o_it->id(), idx, fly);
          if(_key == Qt::Key_H)
            selected_something = selectHalfedge(o_it->id(), idx, fly);
          if(_key == Qt::Key_E)
            selected_something = selectEdge(o_it->id(), idx, fly);
          if(_key == Qt::Key_F)
            selected_something = selectFace(o_it->id(), idx, fly);
        }
        if (selected_something)
        {
          emit updatedObject(o_it->id(), UPDATE_SELECTION);
          emit  createBackup(o_it->id(), "Select Element", UPDATE_SELECTION);
        }
      }
    }
    
    void MeshObjectSelectionPlugin::loadSelection(int _objId, const QString& _filename) {
    
        // Load ini file
        INIFile file;
    
        if(!file.connect(_filename, false)) {
            emit log(LOGERR, QString("Could not read file '%1'!").arg(_filename));
            return;
        }
    
        // Load selection from file
        loadIniFile(file, _objId);
    }
    
    void MeshObjectSelectionPlugin::loadIniFile(INIFile& _ini, int _id) {
    
        BaseObjectData* object = 0;
        if (!PluginFunctions::getObject(_id,object)) {
            emit log(LOGERR,tr("Cannot find object for id ") + QString::number(_id) + tr(" in saveFile") );
            return;
        }
    
        std::vector<int> ids;
        bool invert = false;
    
        bool updated_selection = false;
        bool updated_modeling_regions = false;
    
        QString sectionName = object->name();
    
        if (_ini.get_entry(ids, sectionName ,"ModelingRegion")) {
            invert = false;
            _ini.get_entry(invert, sectionName, "InvertModeling");
    
            if (invert) {
                setAllModelingVertices(object->id());
                unselectModelingVertices(object->id() , ids);
            } else {
                clearModelingVertices(object->id());
                selectModelingVertices(object->id(), ids);
            }
    
            if(object->dataType(DATA_TRIANGLE_MESH)) {
                update_regions(PluginFunctions::triMesh(object));
            }
    
            if(object->dataType(DATA_POLY_MESH)) {
                update_regions(PluginFunctions::polyMesh(object));
            }
    
            updated_modeling_regions = true;
        }
    
        if(_ini.get_entry(ids, sectionName, "HandleRegion")) {
            invert = false;
            _ini.get_entry(invert, sectionName, "InvertHandle");
    
            if(invert) {
                setAllHandleVertices(object->id());
                unselectHandleVertices(object->id(), ids);
            } else {
                clearHandleVertices(object->id());
                selectHandleVertices(object->id(), ids);
            }
    
            if (object->dataType(DATA_TRIANGLE_MESH)) {
                update_regions(PluginFunctions::triMesh(object));
            }
    
            if(object->dataType(DATA_POLY_MESH)) {
                update_regions(PluginFunctions::polyMesh(object));
            }
            
            updated_modeling_regions = true;
        }
    
        if(_ini.get_entry(ids, sectionName, "VertexSelection")) {
            invert = false;
            _ini.get_entry(invert, sectionName, "InvertVertexSelection");
    
            if(invert) {
                selectAllVertices(object->id());
                unselectVertices(object->id(),ids);
            } else {
                clearVertexSelection(object->id());
                selectVertices(object->id(),ids);
            }
    
            updated_selection = true;
        }
    
        if(_ini.get_entry(ids, sectionName, "EdgeSelection")) {
            invert = false;
            _ini.get_entry(invert, sectionName, "InvertEdgeSelection");
    
            ids = convertVertexPairsToEdges(_id, ids);
    
            if(invert) {
                selectAllEdges(object->id());
                unselectEdges(object->id(),ids);
            } else {
                clearEdgeSelection(object->id());
                selectEdges(object->id(),ids);
            }
    
            updated_selection = true;
        }
    
        if(_ini.get_entry(ids, sectionName, "FaceSelection")) {
            invert = false;
            _ini.get_entry(invert, sectionName, "InvertFaceSelection");
    
            if(invert) {
                selectAllFaces(object->id());
                unselectFaces(object->id(),ids);
            } else {
                clearFaceSelection(object->id());
                selectFaces(object->id(),ids);
            }
    
            updated_selection = true;
        }
    
        if(updated_modeling_regions) {
    
            emit updatedObject(object->id(), UPDATE_ALL);
            emit updateView();
    
        } else if(updated_selection) {
    
            emit updatedObject(object->id(), UPDATE_SELECTION);
            emit updateView();
        }
    
        if ( updated_modeling_regions || updated_selection )
          emit  createBackup(object->id(), "Load Selection", UPDATE_SELECTION);
    }
    
    void MeshObjectSelectionPlugin::saveIniFile(INIFile& _ini, int _id) {
        
        BaseObjectData* object = 0;
        if ( !PluginFunctions::getObject(_id,object) ) {
            emit log(LOGERR,tr("Cannot find object for id ") + QString::number(_id) + tr(" in saveFile") );
            return;
        }
    
        // The objects section should already exist
        QString sectionName = object->name();
        if(!_ini.section_exists(sectionName)) {
            emit log(LOGERR,tr("Cannot find object section id ") + QString::number(_id) + tr(" in saveFile") );
            return;
        }
    
        _ini.add_entry(sectionName, "VertexSelection", getVertexSelection(object->id()));
        _ini.add_entry(sectionName, "EdgeSelection", convertEdgesToVertexPairs(_id, getEdgeSelection(object->id())));
    
        if(object->dataType(DATA_POLY_MESH ) || object->dataType( DATA_TRIANGLE_MESH)) {
            _ini.add_entry(sectionName, "FaceSelection", getFaceSelection(object->id()));
            _ini.add_entry(sectionName, "HandleRegion", getHandleVertices(object->id()));
            _ini.add_entry(sectionName, "ModelingRegion", getModelingVertices(object->id()));
        }
    }
    
    void MeshObjectSelectionPlugin::slotLoadSelection(const INIFile& _file) {
        
        // Iterate over all mesh objects in the scene and save
        // the selections for all supported entity types
        for (PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); 
             o_it != PluginFunctions::objectsEnd(); ++o_it) {
            
            // Read section for each object
            // Append object name to section identifier
            QString section = QString("MeshObjectSelection") + "//" + o_it->name();
            if(!_file.section_exists(section)) {
                continue;
            }
            
            std::vector<int> ids;
            // Load vertex selection:
            _file.get_entry(ids, section, "VertexSelection");
            selectVertices(o_it->id(), ids);
            ids.clear();
            // Load edge selection:
            _file.get_entry(ids, section, "EdgeSelection");
            selectEdges(o_it->id(), convertVertexPairsToEdges(o_it->id(), ids));
            ids.clear();
            // Load halfedge selection:
            _file.get_entry(ids, section, "HalfedgeSelection");
            selectHalfedges(o_it->id(), convertVertexPairsToHalfedges(o_it->id(), ids));
            ids.clear();
            // Load face selection:
            _file.get_entry(ids, section, "FaceSelection");
            selectFaces(o_it->id(), ids);
            ids.clear();
            // Load handle region:
            _file.get_entry(ids, section, "HandleRegion");
            selectHandleVertices(o_it->id(), ids);
            ids.clear();
            // Load modeling region:
            _file.get_entry(ids, section, "ModelingRegion");
            selectModelingVertices(o_it->id(), ids);
            ids.clear();
            
            emit updatedObject(o_it->id(), UPDATE_SELECTION);
            emit  createBackup(o_it->id(), "Load Selection", UPDATE_SELECTION);
        }
    }
    
    void MeshObjectSelectionPlugin::slotSaveSelection(INIFile& _file) {
        
        // Iterate over all mesh objects in the scene and save
        // the selections for all supported entity types
        for (PluginFunctions::ObjectIterator o_it(PluginFunctions::ALL_OBJECTS, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); 
             o_it != PluginFunctions::objectsEnd(); ++o_it) {
            
            // Create section for each object
            // Append object name to section identifier
            QString section = QString("MeshObjectSelection") + "//" + o_it->name();
    
            // Store vertex selection:
            _file.add_entry(section, "VertexSelection", getVertexSelection(o_it->id()));
            // Store edge selection:
            _file.add_entry(section, "EdgeSelection", convertEdgesToVertexPairs(o_it->id(), getEdgeSelection(o_it->id())));
            // Store halfedge selection:
            _file.add_entry(section, "HalfedgeSelection", convertHalfedgesToVertexPairs(o_it->id(), getHalfedgeSelection(o_it->id())));
            // Store face selection:
            _file.add_entry(section, "FaceSelection", getFaceSelection(o_it->id()));
            // Store handle region:
            _file.add_entry(section, "HandleRegion", getHandleVertices(o_it->id()));
            // Store modeling region:
            _file.add_entry(section, "ModelingRegion", getModelingVertices(o_it->id()));
        }
    }
    
    void MeshObjectSelectionPlugin::slotKeyShortcutEvent(int _key, Qt::KeyboardModifiers _modifiers) {
    
        if (((_key == Qt::Key_V) || (_key == Qt::Key_H) || (_key == Qt::Key_E) || (_key == Qt::Key_F)) && _modifiers == Qt::NoModifier)
            slotIndexSelection(_key);
    
        SelectionInterface::PrimitiveType type = 0u;
        emit getActivePrimitiveType(type);
    
        if((type & allSupportedTypes_) == 0)
        {
            // No supported type is active
            return;
        }
        
        bool targetsOnly = false;
        emit targetObjectsOnly(targetsOnly);
        PluginFunctions::IteratorRestriction restriction =
                (targetsOnly ? PluginFunctions::TARGET_OBJECTS : PluginFunctions::ALL_OBJECTS);
        
        if(_key == Qt::Key_A && _modifiers == Qt::ControlModifier) {
            
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    
                    if(type & vertexType_)
                        selectAllVertices(o_it->id());
                    if(type & edgeType_)
                        selectAllEdges(o_it->id());
                    if(type & halfedgeType_)
                        selectAllHalfedges(o_it->id());
                    if(type & faceType_)
                        selectAllFaces(o_it->id());
                }
                emit updatedObject(o_it->id(), UPDATE_SELECTION);
                emit  createBackup(o_it->id(), "Select All", UPDATE_SELECTION);
            }
        } else if (_key == Qt::Key_C && ( _modifiers == Qt::NoModifier ||  _modifiers == Qt::ShiftModifier) ) {
    
          for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH));
              o_it != PluginFunctions::objectsEnd(); ++o_it) {
            if (o_it->visible()) {
    
              if ( _modifiers == Qt::NoModifier  ) {
                if( type & vertexType_ )
                  clearVertexSelection(o_it->id());
                if(type & edgeType_)
                  clearEdgeSelection(o_it->id());
                if(type & halfedgeType_)
                  clearHalfedgeSelection(o_it->id());
                if(type & faceType_)
                  clearFaceSelection(o_it->id());
              } else { // Shift -> Clear All
                clearVertexSelection(o_it->id());
                clearEdgeSelection(o_it->id());
                clearHalfedgeSelection(o_it->id());
                clearFaceSelection(o_it->id());
              }
    
              emit updatedObject(o_it->id(), UPDATE_SELECTION);
              emit  createBackup(o_it->id(), "Clear Selection", UPDATE_SELECTION);
            }
    
          }
    
        } else if(_key == Qt::Key_I && _modifiers == Qt::NoModifier) {
            
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    
                    if(type & vertexType_)
                        invertVertexSelection(o_it->id());
                    if(type & edgeType_)
                        invertEdgeSelection(o_it->id());
                    if(type & halfedgeType_)
                        invertHalfedgeSelection(o_it->id());
                    if(type & faceType_)
                        invertFaceSelection(o_it->id());
                }
                emit updatedObject(o_it->id(), UPDATE_SELECTION);
                emit  createBackup(o_it->id(), "Invert Selection", UPDATE_SELECTION);
            }
        } else if (_key == Qt::Key_Delete && _modifiers == Qt::NoModifier) {
            
            for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH)); 
                o_it != PluginFunctions::objectsEnd(); ++o_it) {
                if (o_it->visible()) {
                    // Delete all selected primitives
                    if(type & vertexType_)
                        deleteVertexSelection(o_it->id());
                    if(type & edgeType_)
                        deleteEdgeSelection(o_it->id());
                    if(type & faceType_)
                        deleteFaceSelection(o_it->id());
                }
                emit updatedObject(o_it->id(), UPDATE_TOPOLOGY);
                emit  createBackup(o_it->id(), "Delete Selection", UPDATE_TOPOLOGY);
            }
        }
    }
    
    void MeshObjectSelectionPlugin::slotMouseWheelEvent(QWheelEvent* event, std::string const& mode) {
    
      // Get currently active primitive type
      SelectionInterface::PrimitiveType type = 0u;
      emit getActivePrimitiveType(type);
    
      // Only handle supported primitive types
      if((type & allSupportedTypes_) == 0) {
        // No supported type is active
        return;
      }
    
      // Decide, if all or only target objects should be handled
      bool targetsOnly = false;
      emit targetObjectsOnly(targetsOnly);
      PluginFunctions::IteratorRestriction restriction =
          (targetsOnly ? PluginFunctions::TARGET_OBJECTS : PluginFunctions::ALL_OBJECTS);
    
      if(event->modifiers() == Qt::ShiftModifier) {
    
        if (event->angleDelta().y() > 0) {
          for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH));
              o_it != PluginFunctions::objectsEnd(); ++o_it) {
            if (o_it->visible()) {
    
              if(type & vertexType_)
                growVertexSelection(o_it->id());
              if(type & faceType_)
                growFaceSelection(o_it->id());
            }
            emit updatedObject(o_it->id(), UPDATE_SELECTION);
            emit createBackup(o_it->id(), "Grow Selection", UPDATE_SELECTION);
          }
        } else {
    
          for (PluginFunctions::ObjectIterator o_it(restriction, DataType(DATA_TRIANGLE_MESH | DATA_POLY_MESH));
              o_it != PluginFunctions::objectsEnd(); ++o_it) {
            if (o_it->visible()) {
    
              if(type & vertexType_)
                shrinkVertexSelection(o_it->id());
              if(type & faceType_)
                shrinkFaceSelection(o_it->id());
            }
            emit updatedObject(o_it->id(), UPDATE_SELECTION);
            emit createBackup(o_it->id(), "Shrink Selection", UPDATE_SELECTION);
          }
        }
      }
    }
    
    void MeshObjectSelectionPlugin::lassoSelect(QRegion&      _region,
                                                PrimitiveType _primitiveType,
                                                bool          _deselection) {
    
        // <object id, primitive id>
        QList <QPair<size_t, size_t> > list;
        
        if(_primitiveType & vertexType_) {
            PluginFunctions::scenegraphRegionPick(ACG::SceneGraph::PICK_FRONT_VERTEX, _region, list);
            
            std::set<int> alreadySelectedObjects;
            
            for(int i = 0; i < list.size(); ++i) {
                
                if(alreadySelectedObjects.count(list[i].first) != 0)
                    continue;
                
                BaseObjectData* bod = 0;
                PluginFunctions::getPickedObject(list[i].first, bod);
                
                if(bod && (bod->dataType() == DATA_TRIANGLE_MESH || bod->dataType() == DATA_POLY_MESH)) {
                    IdList elements;
                    for(int j = 0; j < list.size(); ++j) {
                        if(list[j].first == list[i].first) {
                            
                            elements.push_back(list[j].second);
                        }
                    }
                    if (!_deselection)
                      selectVertices(bod->id(), elements);
                    else
                      unselectVertices(bod->id(), elements);
                    alreadySelectedObjects.insert(list[i].first);
                    emit updatedObject(bod->id(), UPDATE_SELECTION);
                    emit  createBackup(bod->id(), "Lasso Selection", UPDATE_SELECTION);
                }
            }
        }
        if(_primitiveType & edgeType_) {
            PluginFunctions::scenegraphRegionPick(ACG::SceneGraph::PICK_FRONT_EDGE, _region, list);
            
            std::set<int> alreadySelectedObjects;
            
            for(int i = 0; i < list.size(); ++i) {
                
                if(alreadySelectedObjects.count(list[i].first) != 0)
                    continue;
                
                BaseObjectData* bod = 0;
                PluginFunctions::getPickedObject(list[i].first, bod);
                
                if(bod && (bod->dataType() == DATA_TRIANGLE_MESH || bod->dataType() == DATA_POLY_MESH)) {
                    IdList elements;
                    for(int j = 0; j < list.size(); ++j) {
                        if(list[j].first == list[i].first) {
                            
                            elements.push_back(list[j].second);
                        }
                    }
                    if (!_deselection)
                      selectEdges(bod->id(), elements, dihedral_angle_threshold_);
                    else
                      unselectEdges(bod->id(), elements);
                    alreadySelectedObjects.insert(list[i].first);
                    emit updatedObject(bod->id(), UPDATE_SELECTION);
                    emit  createBackup(bod->id(), "Lasso Selection", UPDATE_SELECTION);
                }
            }
        }
        if(_primitiveType & halfedgeType_) {
            PluginFunctions::scenegraphRegionPick(ACG::SceneGraph::PICK_FRONT_EDGE, _region, list);
            
            std::set<int> alreadySelectedObjects;
            
            for(int i = 0; i < list.size(); ++i) {
                
                if(alreadySelectedObjects.count(list[i].first) != 0)
                    continue;
                
                BaseObjectData* bod = 0;
                PluginFunctions::getPickedObject(list[i].first, bod);
                
                if(bod && (bod->dataType() == DATA_TRIANGLE_MESH || bod->dataType() == DATA_POLY_MESH)) {
                    IdList elements;
                    for(int j = 0; j < list.size(); ++j) {
                        if(list[j].first == list[i].first) {
                            
                            elements.push_back(list[j].second);
                        }
                    }
                    IdList oldEdgeSelection = getEdgeSelection(bod->id());
                    clearEdgeSelection(bod->id());
    
                    if (!_deselection)
                    {
                      //on selection: select picked edges, convert to halfedge selection
                      update_dihedral_angle_threshold_from_ui();
                      selectEdges(bod->id(), elements, dihedral_angle_threshold_);
                    }
                    else
                    {
                      //on deselection: get current Halfedge Selection, unselect edge, convert back
                      if(bod->dataType() == DATA_TRIANGLE_MESH)
                        MeshSelection::convertHalfedgeToEdgeSelection(PluginFunctions::triMesh(bod));
                      else if(bod->dataType() == DATA_POLY_MESH)
                        MeshSelection::convertHalfedgeToEdgeSelection(PluginFunctions::polyMesh(bod));
    
                      clearHalfedgeSelection(bod->id());
                      unselectEdges(bod->id(), elements);
                    }
                    
    
                    if(bod->dataType() == DATA_TRIANGLE_MESH)
                        MeshSelection::convertEdgeToHalfedgeSelection(PluginFunctions::triMesh(bod));
                    else if(bod->dataType() == DATA_POLY_MESH)
                        MeshSelection::convertEdgeToHalfedgeSelection(PluginFunctions::polyMesh(bod));
                    
                    clearEdgeSelection(bod->id());
                    selectEdges(bod->id(), oldEdgeSelection);
                    
                    alreadySelectedObjects.insert(list[i].first);
                    emit updatedObject(bod->id(), UPDATE_SELECTION);
                    emit  createBackup(bod->id(), "Lasso Selection", UPDATE_SELECTION);
                }
            }
        }
        if(_primitiveType & faceType_) {
            PluginFunctions::scenegraphRegionPick(ACG::SceneGraph::PICK_FACE, _region, list);
            
            std::set<int> alreadySelectedObjects;
            
            for(int i = 0; i < list.size(); ++i) {
                
                if(alreadySelectedObjects.count(list[i].first) != 0)
                    continue;
                
                BaseObjectData* bod = 0;
                PluginFunctions::getPickedObject(list[i].first, bod);
                
                if(bod && (bod->dataType() == DATA_TRIANGLE_MESH || bod->dataType() == DATA_POLY_MESH)) {
                    IdList elements;
                    for(int j = 0; j < list.size(); ++j) {
                        if(list[j].first == list[i].first) {
                            
                            elements.push_back(list[j].second);
                        }
                    }
                    if (!_deselection)
                      selectFaces(bod->id(), elements);
                    else
                      unselectFaces(bod->id(), elements);
                    alreadySelectedObjects.insert(list[i].first);
                    emit updatedObject(bod->id(), UPDATE_SELECTION);
                    emit  createBackup(bod->id(), "Lasso Selection", UPDATE_SELECTION);
                }
            }
        }
    }
    
    /// Traverse the scenegraph and call the selection function for all mesh nodes
    bool SelectVolumeAction::operator()(BaseNode* _node) {
        
        BaseObjectData* object = 0;
        if(PluginFunctions::getPickedObject(_node->id(), object)) {
            
            bool selected = false;
            if (object->dataType(DATA_TRIANGLE_MESH)) {
    
                TriMesh* m = PluginFunctions::triMesh(object);
                selected = plugin_->volumeSelection(m, object->id(), state_, &region_, type_, deselection_);
    
            } else if(object->dataType(DATA_POLY_MESH)) {
    
                PolyMesh* m = PluginFunctions::polyMesh(object);
                selected = plugin_->volumeSelection(m, object->id(), state_, &region_, type_, deselection_);
            }
    
            if (selected){
                emit plugin_->updatedObject(object->id(), UPDATE_SELECTION);
                emit plugin_->createBackup( object->id(), "Lasso Selection", UPDATE_SELECTION);
            }
        }
        return true;
    }
    
    /// Create a mesh containing the selection of the given mesh
    int MeshObjectSelectionPlugin::createMeshFromSelection(int _objectId, PrimitiveType _primitiveType)
    {
    
      // get object
      BaseObjectData *obj = 0;
      PluginFunctions::getObject(_objectId, obj);
    
      if (obj == 0) {
        emit log(LOGERR, tr("Unable to get object"));
        return -1;
      }
    
      if (obj->dataType(DATA_TRIANGLE_MESH)) {
        TriMesh* mesh = PluginFunctions::triMesh(obj);
    
        if (mesh == 0) {
          emit log(LOGERR, tr("Unable to get mesh"));
          return -1;
        }
    
        //add an empty mesh
        int id = -1;
        emit addEmptyObject(DATA_TRIANGLE_MESH, id);
    
        if (id == -1) {
          emit log(LOGERR, tr("Unable to add empty object"));
          return -1;
        }
    
        BaseObjectData *newObj;
        PluginFunctions::getObject(id, newObj);
    
        TriMesh* newMesh = PluginFunctions::triMesh(newObj);
    
        if (newMesh == 0) {
          emit log(LOGERR, tr("Unable to get mesh"));
          return -1;
        }
    
        //fill the empty mesh with the selection
        createMeshFromSelection(*mesh, *newMesh,_primitiveType);
    
        emit updatedObject(id, UPDATE_ALL);
    
        return id;
    
      } else if (obj->dataType(DATA_POLY_MESH)) {
        PolyMesh* mesh = PluginFunctions::polyMesh(obj);
    
        if (mesh == 0) {
          emit log(LOGERR, tr("Unable to get mesh"));
          return -1;
        }
    
        //add an empty mesh
        int id;
        emit addEmptyObject(DATA_POLY_MESH, id);
    
        if (id == -1) {
          emit log(LOGERR, tr("Unable to add empty object"));
          return -1;
        }
    
        BaseObjectData *newObj;
        PluginFunctions::getObject(id, newObj);
    
        PolyMesh* newMesh = PluginFunctions::polyMesh(newObj);
    
        if (newMesh == 0) {
          emit log(LOGERR, tr("Unable to get mesh"));
          return -1;
        }
    
        //fill the empty mesh with the selection
        createMeshFromSelection(*mesh, *newMesh,_primitiveType);
    
        emit updatedObject(id, UPDATE_ALL);
    
        return id;
      } else {
        emit log(LOGERR, tr("DataType not supported"));
        return -1;
      }
    }
    
    void MeshObjectSelectionPlugin::updateColorValues()
    {
      // apply color values to the gui
      if (OpenFlipper::Options::gui())
      {
        colorButtonSelection_->setColor(QColor::fromRgbF(statusColor_[0],statusColor_[1],statusColor_[2],statusColor_[3]));
        colorButtonHandle_->setColor(QColor::fromRgbF(handleColor_[0], handleColor_[1], handleColor_[2], handleColor_[3]));
        colorButtonArea_->setColor(QColor::fromRgbF(areaColor_[0],areaColor_[1],areaColor_[2],areaColor_[3]));
        colorButtonFeature_->setColor(QColor::fromRgbF(featureColor_[0],featureColor_[1],featureColor_[2],featureColor_[3]));
      }
    
      // save new color values
      std::stringstream sstream;
      sstream << statusColor_;
      OpenFlipperQSettings().setValue("SelectionMeshObject/StatusColor",QString(sstream.str().c_str()));
      sstream.str("");
      sstream.clear();
    
      sstream << handleColor_;
      OpenFlipperQSettings().setValue("SelectionMeshObject/HandleColor",QString(sstream.str().c_str()));
      sstream.str("");
      sstream.clear();
    
      sstream << areaColor_;
      OpenFlipperQSettings().setValue("SelectionMeshObject/AreaColor",QString(sstream.str().c_str()));
      sstream.str("");
      sstream.clear();
    
      sstream << featureColor_;
      OpenFlipperQSettings().setValue("SelectionMeshObject/FeatureColor",QString(sstream.str().c_str()));
    }
    
    
    void MeshObjectSelectionPlugin::setDefaultColorValues()
    {
      statusColor_ = ACG::Vec4f(1.0f,0.0f,0.0f,1.0f);
      areaColor_ = ACG::Vec4f(0.4f, 0.4f, 1.0f, 1.0f);
      handleColor_ = ACG::Vec4f(0.2f, 1.0f, 0.2f, 1.0f);
      featureColor_ = ACG::Vec4f(1.0f, 0.2f, 1.0f, 1.0f);
    
      updateColorValues();
    }
    
    bool MeshObjectSelectionPlugin::initializeOptionsWidget(QWidget*& _widget)
    {
      _widget = new QWidget();
      QVBoxLayout* vLayout = new QVBoxLayout();
      QHBoxLayout* hLayout = new QHBoxLayout();
    
      hLayout->addWidget(new QLabel("Select default colors for newly created objects. Does not affect already created objects."));
      vLayout->addLayout(hLayout);
    
      hLayout = new QHBoxLayout();
      colorButtonSelection_ = new QtColorChooserButton();
      hLayout->addWidget(new QLabel("Selection Color: "));
      hLayout->addWidget(colorButtonSelection_);
      vLayout->addLayout(hLayout);
    
      hLayout = new QHBoxLayout();
      colorButtonHandle_ = new QtColorChooserButton();
      hLayout->addWidget(new QLabel("Handle Color: "));
      hLayout->addWidget(colorButtonHandle_);
      vLayout->addLayout(hLayout);
    
      hLayout = new QHBoxLayout();
      colorButtonFeature_ = new QtColorChooserButton();
      hLayout->addWidget(new QLabel("Feature Color: "));
      hLayout->addWidget(colorButtonFeature_);
      vLayout->addLayout(hLayout);
    
      hLayout = new QHBoxLayout();
      colorButtonArea_= new QtColorChooserButton();
      hLayout->addWidget(new QLabel("Area Color: "));
      hLayout->addWidget(colorButtonArea_);
      vLayout->addLayout(hLayout);
    
      hLayout = new QHBoxLayout();
      QPushButton* restoreDefault = new QPushButton();
      connect(restoreDefault, SIGNAL(clicked()), this, SLOT(setDefaultColorValues()));
      restoreDefault->setText("Restore Default");
      hLayout->addWidget(restoreDefault);
      hLayout->addStretch();
      vLayout->addLayout(hLayout);
    
      _widget->setLayout(vLayout);
    
      return true;
    }
    
    void MeshObjectSelectionPlugin::applyOptions()
    {
      statusColor_ = ACG::Vec4f(colorButtonSelection_->color().redF(),colorButtonSelection_->color().greenF(),colorButtonSelection_->color().blueF(),1.f);
      areaColor_ = ACG::Vec4f(colorButtonArea_->color().redF(),colorButtonArea_->color().greenF(),colorButtonArea_->color().blueF(),1.f);
      handleColor_ = ACG::Vec4f(colorButtonHandle_->color().redF(),colorButtonHandle_->color().greenF(),colorButtonHandle_->color().blueF(),1.f);
      featureColor_ = ACG::Vec4f(colorButtonFeature_->color().redF(),colorButtonFeature_->color().greenF(),colorButtonFeature_->color().blueF(),1.f);
    
      updateColorValues();
    }
    
    void MeshObjectSelectionPlugin::addedEmptyObject(int _id )
    {
      if (OpenFlipper::Options::nogui())
        return;
    
      PolyMeshObject* polyObj = 0;
      TriMeshObject* triObj = 0;
    
      triObj = PluginFunctions::triMeshObject(_id);
      polyObj = PluginFunctions::polyMeshObject(_id);
    
      if (triObj)
      {
        triObj->setSelectionColor(statusColor_);
        triObj->setHandleColor(handleColor_);
        triObj->setAreaColor(areaColor_);
        triObj->setFeatureColor(featureColor_);
      }else if (polyObj)
      {
        polyObj->setSelectionColor(statusColor_);
        polyObj->setHandleColor(handleColor_);
        polyObj->setAreaColor(areaColor_);
        polyObj->setFeatureColor(featureColor_);
      }
    
    }
    
    void MeshObjectSelectionPlugin::set_dihedral_angle_threshold(const double _a)
    {
      dihedral_angle_threshold_ = OpenMesh::deg_to_rad(_a);
    }
    
    double MeshObjectSelectionPlugin::get_dihedral_angle_threshold()
    {
      return dihedral_angle_threshold_;
    }
    
    void MeshObjectSelectionPlugin::set_max_angle(const double _a)
    {
      max_angle_ = _a;
    }
    
    double MeshObjectSelectionPlugin::get_max_angle()
    {
      return max_angle_;
    }
    
    void MeshObjectSelectionPlugin::update_dihedral_angle_threshold_from_ui()
    {  
      set_dihedral_angle_threshold( parameterWidget_->minDihedralAngle->value());
    }