Skip to content
Snippets Groups Projects
Select Git revision
  • 4d69aaee512c078e7a6a6a02cbcb48a69fd38762
  • master default
  • cgnsUnstructured
  • partitioning
  • poppler
  • HighOrderBLCurving
  • gmsh_3_0_4
  • gmsh_3_0_3
  • gmsh_3_0_2
  • gmsh_3_0_1
  • gmsh_3_0_0
  • gmsh_2_16_0
  • gmsh_2_15_0
  • gmsh_2_14_1
  • gmsh_2_14_0
  • gmsh_2_13_2
  • gmsh_2_13_1
  • gmsh_2_12_0
  • gmsh_2_11_0
  • gmsh_2_10_1
  • gmsh_2_10_0
  • gmsh_2_9_3
  • gmsh_2_9_2
  • gmsh_2_9_1
  • gmsh_2_9_0
  • gmsh_2_8_6
26 results

GUI.cpp

Blame
  • Forked from gmsh / gmsh
    Source project has a limited visibility.
    GUI_Classifier.cpp 19.41 KiB
    // Gmsh - Copyright (C) 1997-2008 C. Geuzaine, J.-F. Remacle
    //
    // See the LICENSE.txt file for license information. Please report all
    // bugs and problems to <gmsh@geuz.org>.
    
    #include "GUI_Classifier.h"
    #include "Numeric.h"
    #include "Draw.h"
    #include "Options.h"
    #include "Context.h"
    #include "SelectBuffer.h"
    #include "GUI_Projection.h"
    #include "GUI_Extras.h"
    #include "Message.h"
    #include "meshGFaceDelaunayInsertion.h"
    #include "meshGFaceOptimize.h"
    #include "discreteEdge.h"
    #include "discreteFace.h"
    
    extern Context_T CTX;
    
    void buildListOfEdgeAngle ( e2t_cont adj,std::vector<edge_angle> &edges_detected,std::vector<edge_angle> &edges_lonly);
    
    void NoElementsSelectedMode (classificationEditor *e)
    {
      e->_buttons[CLASSBUTTON_DEL]->deactivate();
      e->_buttons[CLASSBUTTON_ADD]->deactivate();
      e->_buttons[CLASSBUTTON_CLEAR]->deactivate();
      //  e->_buttons[CLASSBUTTON_OK]->deactivate();
      e->_togbuttons[CLASSTOGBUTTON_CLOS]->deactivate();
      e->_inputs[CLASSVALUE_ANGLE]->deactivate();
    
      e->_buttons[CLASSBUTTON_SELECT]->activate(); 
      e->_togbuttons[CLASSTOGBUTTON_HIDE]->activate(); 
    
    }
    
    void ElementsSelectedMode (classificationEditor *e)
    {
    
      e->_buttons[CLASSBUTTON_DEL]->activate();
      e->_buttons[CLASSBUTTON_ADD]->activate();
      e->_buttons[CLASSBUTTON_CLEAR]->activate();
      e->_togbuttons[CLASSTOGBUTTON_CLOS]->activate();
      e->_inputs[CLASSVALUE_ANGLE]->activate();
      //  e->_buttons[CLASSBUTTON_OK]->activate();
    
      e->_buttons[CLASSBUTTON_SELECT]->deactivate(); 
      e->_togbuttons[CLASSTOGBUTTON_HIDE]->deactivate(); 
    }
    
    
    
    int maxEdgeNum ()
    {
      GModel::eiter it =  GModel::current()->firstEdge();
      GModel::eiter ite = GModel::current()->lastEdge();
      int MAXX = 0;
      while (it != ite)
        {
          MAXX = std::max (MAXX, (*it)->tag());
          ++it;
        }
      return MAXX;
    }
    
    int maxFaceNum ()
    {
      GModel::fiter it =  GModel::current()->firstFace();
      GModel::fiter ite = GModel::current()->lastFace();
      int MAXX = 0;
      while (it != ite)
        {
          MAXX = std::max (MAXX, (*it)->tag());
          ++it;
        }
      return MAXX;
    }
    
    
    struct compareMLinePtr 
    {
      bool operator () ( MLine *l1 , MLine *l2) const
      {
        static Less_Edge le;
        return le(l1->getEdge(0),l2->getEdge(0)); 
      }
    };
    
     
    void recurClassify ( MTri3 *t , 
                         GFace *gf,
                         std::map<MLine*, GEdge*, compareMLinePtr> &lines,
                         std::map<MTriangle*, GFace*> &reverse)
    {
      if (!t->isDeleted())
        {
          gf->triangles.push_back(t->tri());
          reverse[t->tri()] = gf;
    
          t->setDeleted ( true );
          
          for (int i=0;i<3;i++)
            {
              MTri3 *tn = t->getNeigh(i);
              if (tn)
                {
                  edgeXface exf ( t, i);
                  MLine ml (exf.v[0],exf.v[1]);       
                  std::map<MLine*, GEdge*, compareMLinePtr>::iterator it = lines.find(&ml);
                  if (it==lines.end())
                    recurClassify (tn, gf,lines, reverse);
                }
            }  
        }
    }
    
    
    GEdge * getNewModelEdge (GFace *gf1, GFace *gf2, std::map< std::pair <int, int> , GEdge* > &newEdges)
    {
      int t1 = gf1 ? gf1->tag() : -1;
      int t2 = gf2 ? gf2->tag() : -1;
      int i1 = std::min(t1,t2);
      int i2 = std::max(t1,t2);
    
      if (i1 == i2) return 0;
    
      std::map< std::pair <int, int> , GEdge* >::iterator it = newEdges.find(std::make_pair<int,int>(i1,i2));
      if (it == newEdges.end())
        {
          discreteEdge *temporary = new discreteEdge(GModel::current(), maxEdgeNum() + 1);
          GModel::current()->add (temporary);
          newEdges[std::make_pair<int,int>(i1,i2)] = temporary;
          
          return temporary;
        }
      else
        return it->second;  
    }
    
    
    void recurClassifyEdges ( MTri3 *t , 
                              std::map<MTriangle*, GFace*> &reverse,
                              std::map<MLine*, GEdge*, compareMLinePtr> &lines,
                              std::set<MLine*> &touched,
                              std::map< std::pair <int, int> , GEdge* > &newEdges)
    {
      if (!t->isDeleted())
        {
          t->setDeleted ( true );
          
          GFace *gf1 = reverse[t->tri()];
          for (int i=0;i<3;i++)
            {
              GFace *gf2 = 0;
              MTri3 *tn = t->getNeigh(i);
              if (tn)
                gf2 = reverse[tn->tri()];
    
              edgeXface exf ( t, i);
              MLine ml (exf.v[0],exf.v[1]);   
              std::map<MLine*, GEdge*, compareMLinePtr>::iterator it = lines.find(&ml);
              if (it != lines.end())
                {
                  if (touched.find(it->first) == touched.end())
                    {
                      GEdge *ge =  getNewModelEdge (gf1, gf2, newEdges);
                      if (ge) ge->lines.push_back(it->first);
                      touched.insert(it->first);
                    }
                }
              if (tn)
                recurClassifyEdges (tn, reverse,lines, touched,newEdges);
            }  
        }
    }
    
    
    
    void class_color_cb(Fl_Widget* w, void* data)
    {
      classificationEditor *e = (classificationEditor*)data;
      std::map<MLine*, GEdge*, compareMLinePtr> lines;
      {
        GModel::eiter it =  GModel::current()->firstEdge();
        GModel::eiter ite = GModel::current()->lastEdge();
        for( ;it!=ite;++it)
          {
            for (unsigned int i=0;i<(*it)->lines.size();i++)lines[(*it)->lines[i] ] = *it;
          }
      }
    
    
      std::list<MTri3*> tris;
      {
        std::set<GFace*>::iterator it = e->_faces.begin();
        while (it != e->_faces.end())
          {
            GFace *gf = *it;
            for (unsigned int i=0;i<gf->triangles.size();i++)
              {
                tris.push_back (new MTri3 ( gf->triangles [i] , 0 ) );
              }
            gf->triangles.clear();
            ++it;
          }
      }
    
    
      connectTriangles (tris);
    
      {
        std::map<MTriangle*,GFace*> reverse;
    
        // color all triangles
        std::list<MTri3*> ::iterator it = tris.begin();
        while (it != tris.end())
          {
            if (!(*it)->isDeleted())
              {
                discreteFace *temporary = new discreteFace(GModel::current(), maxFaceNum() + 1);
                recurClassify(*it, temporary, lines, reverse);
                GModel::current()->add(temporary);
              }
            ++it;
          }
    
        // color some lines
        it = tris.begin();
        while (it != tris.end())
          {
            (*it)->setDeleted(false);
            ++it;
          }
    
        it = tris.begin();
    
        std::map< std::pair <int, int> , GEdge* > newEdges;
        std::set< MLine* > touched;
        recurClassifyEdges ( *it , reverse , lines, touched,newEdges);
        GModel::current()->remove(e->saved);
    
        while (it != tris.end())
          {
            delete *it;
            ++it;
          }
      }
    
      CTX.mesh.changed = ENT_ALL;
      Draw();  
      Msg::StatusBar(3, false, "");
    
    }
    
    void updateedges_cb(Fl_Widget* w, void* data)
    {
      classificationEditor *e = (classificationEditor*)data;
     
      //  printf("%d edges detected\n",e->edges_detected.size());
    
      for (unsigned int i=0;i<e->temporary->lines.size();i++)
        {
          delete e->temporary->lines[i];
        }
      e->temporary->lines.clear();
    
      for (unsigned int i=0 ; i<e->edges_detected.size();i++)
        {
          edge_angle ea =  e->edges_detected[i];
          //      printf("angle = %g\n",ea.angle);
          if ( ea.angle  <= e -> _inputs[CLASSVALUE_ANGLE] ->value() / 180 * M_PI) 
            break;
          e->temporary->lines.push_back(new MLine(ea.v1, ea.v2));            
        } 
    
      if (e->_togbuttons[CLASSTOGBUTTON_CLOS]->value())
        {
          for (unsigned int i=0 ; i<e->edges_lonly.size();i++)
            {
              edge_angle ea =  e->edges_lonly[i];
              e->temporary->lines.push_back(new MLine(ea.v1, ea.v2));            
            } 
        }
      
    
      CTX.mesh.changed = ENT_ALL;
      Draw();   
    }
    
    edge_angle::  edge_angle ( MVertex *_v1, MVertex *_v2, MTriangle *t1, MTriangle *t2)
      : v1(_v1), v2(_v2)
    {
      if (!t2) angle = 0;
      else
        {
          double c1[3];
          double c2[3];
          double c3[3];
          {
            MVertex *p1 = t1->getVertex(0);
            MVertex *p2 = t1->getVertex(1);
            MVertex *p3 = t1->getVertex(2);
            double a[3] = { p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z() };
            double b[3] = { p1->x() - p3->x(), p1->y() - p3->y(), p1->z() - p3->z() };
            c1[2] = a[0] * b[1] - a[1] * b[0];
            c1[1] = -a[0] * b[2] + a[2] * b[0];
            c1[0] = a[1] * b[2] - a[2] * b[1];
          }
          {
            MVertex *p1 = t2->getVertex(0);
            MVertex *p2 = t2->getVertex(1);
            MVertex *p3 = t2->getVertex(2);
            double a[3] = { p1->x() - p2->x(), p1->y() - p2->y(), p1->z() - p2->z() };
            double b[3] = { p1->x() - p3->x(), p1->y() - p3->y(), p1->z() - p3->z() };
            c2[2] = a[0] * b[1] - a[1] * b[0];
            c2[1] = -a[0] * b[2] + a[2] * b[0];
            c2[0] = a[1] * b[2] - a[2] * b[1];
          }
          norme(c1);
          norme(c2);
          prodve(c1,c2,c3);
          double cosa ; prosca(c1,c2,&cosa);
          double sina = norme (c3);
          angle = atan2(sina,cosa);
        }
      
    }
    void buildListOfEdgeAngle ( e2t_cont adj,std::vector<edge_angle> &edges_detected,std::vector<edge_angle> &edges_lonly)
    {
      e2t_cont::iterator it = adj.begin();
      for ( ; it!=adj.end();++it )
        {
          if ( it->second.second ) edges_detected.push_back ( edge_angle ( it->first.getVertex (0) ,it->first.getVertex (1) , 
                                                                           it->second.first,it->second.second) );
          else edges_lonly.push_back ( edge_angle ( it->first.getVertex (0) ,it->first.getVertex (1) , 
                                                    it->second.first,it->second.second) );  
        }
      std::sort ( edges_detected .begin() ,  edges_detected .end() );
    }
    
    
    classificationEditor::classificationEditor() 
    {
    
      op[0]=opt_mesh_lines(0, GMSH_GET, 0.);
      op[1]=opt_mesh_surfaces_edges(0, GMSH_GET, 0.);
      op[2]=opt_mesh_surfaces_faces(0, GMSH_GET, 0.);
      op[3]=opt_mesh_line_width(0, GMSH_SET | GMSH_GET,0.);
    
      opt_mesh_lines(0, GMSH_SET | GMSH_GUI, 1);
      opt_mesh_surfaces_edges(0, GMSH_SET | GMSH_GUI, 0);
      opt_mesh_surfaces_faces(0, GMSH_SET | GMSH_GUI, 1);
      opt_mesh_line_width(0, GMSH_SET | GMSH_GUI, 1.5);
    
    
      // construct GUI in terms of standard sizes
      const int BH = 2 * GetFontSize() + 1, BB = 12 * GetFontSize(), WB = 7;
      const int width = (int)(3.5 * BB), height = 10 * BH;
    
      _window = new Dialog_Window(width, height, CTX.non_modal_windows, "Classify");
      
      new Fl_Tabs(WB, WB, width - 2 * WB, height - 2 * WB);
      {
        Fl_Group *o = new Fl_Group(WB, WB + BH, width - 2 * WB, height - 2 * WB - BH, "Edge Detection");
        edge_detec = o;
        //    o->hide();
        // create all widgets (we construct this once, we never deallocate!)
        
        _buttons[CLASSBUTTON_OK] = 
          new Fl_Button       (4*WB+2*BB, 7*WB+6*BH, BB, BH, "OK");
        _buttons[CLASSBUTTON_OK]->callback(class_ok_cb, this);
        
        _buttons[CLASSBUTTON_SELECT] = 
          new Fl_Button       (2*WB, 2*WB+1*BH, BB, BH, "Select Elements");
        _buttons[CLASSBUTTON_SELECT]->callback(class_select_cb, this);
        
        _togbuttons[CLASSTOGBUTTON_HIDE] = 
          new Fl_Toggle_Button(3*WB+BB, 2*WB+1*BH, BB, BH, "Hide Unselected");
        _togbuttons[CLASSTOGBUTTON_HIDE]->callback(class_hide_cb,this);
    
        _togbuttons[CLASSTOGBUTTON_CLOS] = 
          new Fl_Toggle_Button(2*WB, 4*WB+3*BH, BB, BH, "Include Closure");
        _togbuttons[CLASSTOGBUTTON_CLOS]->callback(updateedges_cb,this);
        
        _inputs[CLASSVALUE_ANGLE] = 
          new Fl_Value_Input(3*WB+BB, 4*WB+3*BH, BB, BH, "Treshold Angle");
        _inputs[CLASSVALUE_ANGLE]->value(40);
        _inputs [CLASSVALUE_ANGLE]->maximum(90);
        _inputs[CLASSVALUE_ANGLE]->minimum(0);
        _inputs[CLASSVALUE_ANGLE]->align(FL_ALIGN_RIGHT);
        _inputs[CLASSVALUE_ANGLE]->step(1);
        _inputs[CLASSVALUE_ANGLE]->when(FL_WHEN_RELEASE);  
        _inputs[CLASSVALUE_ANGLE]->callback(updateedges_cb,this);
    
        _buttons[CLASSBUTTON_DEL] = 
          new Fl_Button       (2*WB, 5*WB+4*BH, BB, BH, "Delete Edge");
        _buttons[CLASSBUTTON_DEL]->callback(class_deleteedge_cb, this);    
        _buttons[CLASSBUTTON_DEL]->deactivate();
    
        _buttons[CLASSBUTTON_ADD] = 
          new Fl_Button       (2*WB, 6*WB+5*BH, BB, BH, "Save Selection");
        _buttons[CLASSBUTTON_ADD]->callback(class_save_cb, this);    
        _buttons[CLASSBUTTON_ADD]->deactivate();
    
        _buttons[CLASSBUTTON_CLEAR] = 
          new Fl_Button       (2*WB, 7*WB+6*BH, BB, BH, "Clear Selection");
        _buttons[CLASSBUTTON_CLEAR]->callback(class_clear_cb, this);    
        _buttons[CLASSBUTTON_CLEAR]->deactivate();
        o->end();
      }
      {
        Fl_Group *o = new Fl_Group(WB, WB + BH, width - 2 * WB, height - 2 * WB - BH, "Face Colouring");
        face_color = o;
        o->deactivate();
        o->hide();
        _buttons[CLASSBUTTON_SELFAC] = 
          new Fl_Button       (2*WB, 2*WB+1*BH, BB, BH, "Select Model Face");
        _buttons[CLASSBUTTON_SELFAC]->callback(class_selectgface_cb, this);
        _buttons[CLASSBUTTON_COLOR] = 
          new Fl_Button       (2*WB, 3*WB+2*BH, BB, BH, "Classify Mesh Faces");
        _buttons[CLASSBUTTON_COLOR]->callback(class_color_cb, this);
        o->end();
      }
      {
        Fl_Group *o = new Fl_Group(WB, WB + BH, width - 2 * WB, height - 2 * WB - BH, "Reverse Engineer Surfaces");
        reverse_eng = o;
        o->hide();
        o->deactivate();
        o->end();
      }
      NoElementsSelectedMode (this);
    
      // allocate detected edges
      // temporary for the selection
      // saved for the ones that have been saved by the user
      // and that will be used for next step
    
      temporary = new discreteEdge(GModel::current(), maxEdgeNum() + 1);
      GModel::current()->add(temporary);
      saved = new discreteEdge(GModel::current(), maxEdgeNum() + 1);
      GModel::current()->add(saved);
      
      _window->end();
      _window->hotspot(_window);
      _window->size_range(width, (int)(0.85 * height));    
    }
    
    
    void class_hide_cb(Fl_Widget *w, void *data)
    {
      CTX.hide_unselected = !CTX.hide_unselected;
      CTX.mesh.changed = ENT_ALL;
      Draw();
    }
    
    void class_select_cb(Fl_Widget *w, void *data)
    {
      classificationEditor *e = (classificationEditor*)data;
      std::vector<GVertex*> vertices;
      std::vector<GEdge*> edges;
      std::vector<GFace*> faces;
      std::vector<GRegion*> regions;
      std::vector<MElement*> elements;
      std::vector<MTriangle*> &ele(e->getElements());
    
      CTX.pick_elements = 1;
    
      while(1) {
        CTX.mesh.changed = ENT_ALL;
        Draw();
    
        Msg::StatusBar(3, false, "Select Elements\n"
            "[Press 'e' to end selection or 'q' to abort]");
        
        char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
        if(ib == 'l') {
          if(CTX.pick_elements){
            for(unsigned int i = 0; i < elements.size(); i++){
              if(elements[i]->getNumEdges() == 3 && elements[i]->getVisibility() != 2){
                elements[i]->setVisibility(2); ele.push_back((MTriangle*)elements[i]);
              }
            }
          }
        }
        if(ib == 'r') {
          for(unsigned int i = 0; i < elements.size(); i++)
            elements[i]->setVisibility(1);
        }
        // ok, we compute edges !
        if(ib == 'e') {
          ZeroHighlight();
          e2t_cont adj;
          buildEdgeToTriangle (ele , adj );      
          buildListOfEdgeAngle ( adj,e->edges_detected,e->edges_lonly);
          ElementsSelectedMode (e);
          break;
        }
        // do nothing
        if(ib == 'q') {
          ZeroHighlight();
          ele.clear();
          break;
        }
      }
      
      updateedges_cb(0, data);
    
      CTX.mesh.changed = ENT_ALL;
      CTX.pick_elements = 0;
      Draw();  
      Msg::StatusBar(3, false, "");
    }
    
    
    void class_selectgface_cb(Fl_Widget *w, void *data)
    {
      classificationEditor *e = (classificationEditor*)data;
      std::vector<GVertex*> vertices;
      std::vector<GEdge*> edges;
      std::vector<GFace*> faces;
      std::vector<GFace*> temp;
      std::vector<GRegion*> regions;
      std::vector<MElement*> elements;
    
      opt_geometry_surfaces(0, GMSH_SET | GMSH_GUI, 1);
    
      while(1) {
        CTX.mesh.changed = ENT_ALL;
        Draw();
    
        Msg::StatusBar(3, false, "Select Model Face\n"
            "[Press 'e' to end selection or 'q' to abort]");
        
        char ib = SelectEntity(ENT_SURFACE, vertices, edges, faces, regions, elements);
        if(ib == 'l') {
          for(unsigned int i = 0; i < faces.size(); i++){
            HighlightEntity(faces[i]);      
            temp.push_back(faces[i]);
          }
        }
        // ok store the list of gfaces !
        if(ib == 'e') {
          ZeroHighlight();
          for(unsigned int i = 0; i < temp.size(); i++){
            e->_faces.insert (temp[i]);
          }
          break;
        }
        // do nothing
        if(ib == 'q') {
          ZeroHighlight();
          break;
        }
      } 
      CTX.mesh.changed = ENT_ALL;
      Draw();  
      Msg::StatusBar(3, false, "");
    }
    
    
    void class_deleteedge_cb(Fl_Widget *w, void *data)
    {
      classificationEditor *e = (classificationEditor*)data;
      std::vector<GVertex*> vertices;
      std::vector<GEdge*> edges;
      std::vector<GFace*> faces;
      std::vector<GRegion*> regions;
      std::vector<MElement*> elements;
      std::vector<MLine*> ele;
      
      CTX.pick_elements = 1;
      
      while(1) {
        CTX.mesh.changed = ENT_ALL;
        Draw();
    
        Msg::StatusBar(3, false, "Select Elements\n"
            "[Press 'e' to end selection or 'q' to abort]");
        
        char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
        if(ib == 'l') {
          if(CTX.pick_elements){
            for(unsigned int i = 0; i < elements.size(); i++){
              if(elements[i]->getNumEdges() == 1 && elements[i]->getVisibility() != 2){
                elements[i]->setVisibility(2); ele.push_back((MLine*)elements[i]);
              }
            }
          }
        }
        if(ib == 'r') {
          for(unsigned int i = 0; i < elements.size(); i++)
            elements[i]->setVisibility(1);
        }
        // ok, we compute edges !
        if(ib == 'e') {
          ZeroHighlight();      
          break;
        }
        // do nothing
        if(ib == 'q') {
          ZeroHighlight();
          ele.clear();
          break;
        }
      }
    
    
      std::sort (ele.begin(),ele.end());
      //  look in all temporary edges if a deleted one is present and delete it !
      std::vector<MLine*> temp = e->temporary->lines;
      e->temporary->lines.clear();
           
      for(unsigned int i=0;i<temp.size();i++)
        {      
          std::vector<MLine*>::iterator it = std::find (ele.begin(),ele.end(),temp[i]);
          if (it != ele.end())
            {
              delete temp[i];
            }
          else e->temporary->lines.push_back(temp[i]);
        }
      
      CTX.mesh.changed = ENT_ALL;
      CTX.pick_elements = 0;
      Draw();  
      Msg::StatusBar(3, false, "");
    }
    
    
    void class_save_cb(Fl_Widget *w, void *data)
    {
      classificationEditor *e = (classificationEditor*)data;
    
      e->saved->lines.insert (e->saved->lines.end(), e->temporary->lines.begin(), e->temporary->lines.end());
      e->temporary->lines.clear();
      e->_elements.clear();
      e->edges_detected.clear();
    
      CTX.mesh.changed = ENT_ALL;
      CTX.pick_elements = 0;
      NoElementsSelectedMode (e);
      Draw();  
      Msg::StatusBar(3, false, "");
    }
    
    void class_clear_cb(Fl_Widget *w, void *data)
    {
      classificationEditor *e = (classificationEditor*)data;
    
      for (unsigned int i=0;i<e->temporary->lines.size();i++)
        {      
          delete e->temporary->lines[i];
        }
      e->temporary->lines.clear();
    
      CTX.mesh.changed = ENT_ALL;
      CTX.pick_elements = 0;
      NoElementsSelectedMode (e);
      Draw();  
      Msg::StatusBar(3, false, "");
    }
    
    void class_ok_cb(Fl_Widget *w, void *data)
    {
      classificationEditor *e = (classificationEditor*)data;
      e->edge_detec->deactivate();
      e->edge_detec->hide();
      e->face_color->activate();
      e->face_color->show();
      class_save_cb(w,data);
      opt_mesh_lines(0, GMSH_SET | GMSH_GUI, e->op[0]);
      opt_mesh_surfaces_edges(0, GMSH_SET | GMSH_GUI, e->op[1]);
      opt_mesh_surfaces_faces(0, GMSH_SET | GMSH_GUI, e->op[2]);
      opt_mesh_line_width(0, GMSH_SET | GMSH_GUI, e->op[3]);
    
      Msg::StatusBar(3, false, "");
    }
    
    void class_okcolor_cb(Fl_Widget *w, void *data)
    {
      classificationEditor *e = (classificationEditor*)data;
      e->edge_detec->deactivate();
      e->edge_detec->show();
      e->face_color->deactivate();
      e->face_color->hide();
      //  class_save_cb(w,data);
      Msg::StatusBar(3, false, "");
    }
    
    
    
    void mesh_classify_cb(Fl_Widget* w, void* data)
    {
      // create the (static) editor
      static classificationEditor *editor = 0;
      if(!editor){
        editor = new classificationEditor();
      }
      editor->show();
    }