From 98a4cb20a1acc04182633cbca299df7090b98984 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Wed, 1 Nov 2006 22:19:27 +0000
Subject: [PATCH] more work on mesh editing

---
 Common/Context.h          |  1 +
 Common/Options.cpp        |  7 +---
 Common/VertexArray.cpp    |  9 ++---
 Fltk/Callbacks.cpp        | 40 ++++++-------------
 Fltk/Opengl.cpp           |  9 ++---
 Fltk/Opengl_Window.cpp    |  6 +--
 Geo/GModel.cpp            | 83 ++++++++++++++++++++++++++++++++++++++-
 Geo/GModel.h              |  3 +-
 Graphics/Mesh.cpp         | 10 ++---
 Graphics/SelectBuffer.cpp | 14 +++----
 Graphics/SelectBuffer.h   |  9 ++---
 11 files changed, 125 insertions(+), 66 deletions(-)

diff --git a/Common/Context.h b/Common/Context.h
index d6e791b8ae..f5a3dfeb0a 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -134,6 +134,7 @@ public :
   int forced_bbox; // dynamic variable tracking if the bbox is currently imposed
 
   int enable_mouse_selection; // enable selection using the mouse
+  int pick_elements; // allow individual element picking
 
   int expert_mode; // to disable some warnings for beginners
   int printing; // dynamic: equal to 1 while gmsh is printing
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 8e78bd5988..e23d4f30a0 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.312 2006-09-24 05:59:13 geuzaine Exp $
+// $Id: Options.cpp,v 1.313 2006-11-01 22:19:26 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -134,6 +134,7 @@ void Init_Options(int num)
   CTX.printing = 0;
   CTX.mesh_timer[0] = CTX.mesh_timer[1] = CTX.mesh_timer[2] = 0.;
   CTX.draw_rotation_center = 0;
+  CTX.pick_elements = 0;
   CTX.mesh.draw = 1;
   CTX.post.draw = 1;
   CTX.post.list = NULL;
@@ -2783,10 +2784,6 @@ double opt_general_mouse_selection(OPT_ARGS_NUM)
       if(!CTX.batch) Msg(STATUS2N, "Mouse selection ON (with mesh hover)");
       WID->g_status_butt[9]->color(FL_GREEN);
       break;
-    case 3:
-      if(!CTX.batch) Msg(STATUS2N, "Mouse selection ON (with element hover)");
-      WID->g_status_butt[9]->color(FL_YELLOW);
-      break;
     case 0:
     default:
       if(!CTX.batch) Msg(STATUS2N, "Mouse selection OFF");
diff --git a/Common/VertexArray.cpp b/Common/VertexArray.cpp
index 733fd3ca85..9e746bd1f8 100644
--- a/Common/VertexArray.cpp
+++ b/Common/VertexArray.cpp
@@ -1,4 +1,4 @@
-// $Id: VertexArray.cpp,v 1.15 2006-08-24 01:14:55 geuzaine Exp $
+// $Id: VertexArray.cpp,v 1.16 2006-11-01 22:19:26 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -60,8 +60,7 @@ void VertexArray::add(float x, float y, float z, float n0, float n1, float n2,
   _colors.push_back(b);
   _colors.push_back(a);
 
-  if(ele && CTX.enable_mouse_selection > 2)
-    _elements.push_back(ele);
+  if(ele && CTX.pick_elements) _elements.push_back(ele);
 }
 
 void VertexArray::add(float x, float y, float z, unsigned int col, MElement *ele)
@@ -79,11 +78,9 @@ void VertexArray::add(float x, float y, float z, unsigned int col, MElement *ele
   _colors.push_back(b);
   _colors.push_back(a);
 
-  if(ele && CTX.enable_mouse_selection > 2)
-    _elements.push_back(ele);
+  if(ele && CTX.pick_elements) _elements.push_back(ele);
 }
 
-
 class AlphaElement {
 public:
   AlphaElement(float *vp, char *np, unsigned char *cp) : v(vp), n(np), c(cp) {}
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 89a9836c15..e2145a86eb 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.464 2006-10-31 20:50:35 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.465 2006-11-01 22:19:26 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -479,11 +479,6 @@ void status_xyz1p_cb(CALLBACK_ARGS)
       // mouse hover and select for geometry and mesh
       opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 2);
     }
-    else if(Fl::event_state(FL_META)){
-      // mouse hover and select for geometry and mesh, and mouse
-      // select for individual mesh elements
-      opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 3);
-    }
     else if(CTX.enable_mouse_selection){
       // mouse does nothing
       opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 0);
@@ -491,7 +486,7 @@ void status_xyz1p_cb(CALLBACK_ARGS)
     }
     else{
       // mouse hover and select for geometry, but mouse select only
-      // for mesh (default)
+      // for mesh (default, for performance reasons)
       opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 1);
     }
   }
@@ -3529,20 +3524,11 @@ void mesh_delete_cb(CALLBACK_ARGS)
 void mesh_delete_parts_cb(CALLBACK_ARGS)
 {
   char *str = (char*)data;
-  int meshSelection;
 
-  if(!strcmp(str, "elements")){
-    opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 3);
-    meshSelection = 2;
-  }
-  else if(!strcmp(str, "surfaces")){
-    opt_general_mouse_selection(0, GMSH_SET | GMSH_GUI, 2);
-    meshSelection = 1;
-  }
-  else{
-    Msg(GERROR, "Unknown mesh edit action");
-    return;
-  }
+  if(!strcmp(str, "elements"))
+    CTX.pick_elements = 1;
+  else
+    CTX.pick_elements = 0;
   CTX.mesh.changed = ENT_ALL;
 
   std::vector<GVertex*> vertices;
@@ -3552,7 +3538,7 @@ void mesh_delete_parts_cb(CALLBACK_ARGS)
   std::vector<MElement*> elements, ele;
 
   while(1) {
-    CTX.mesh.changed = ENT_ALL;
+    if(CTX.pick_elements) CTX.mesh.changed = ENT_ALL;
     Draw();
 
     if(ele.size() || fac.size())
@@ -3562,10 +3548,9 @@ void mesh_delete_parts_cb(CALLBACK_ARGS)
       Msg(ONSCREEN, "Select %s\n"
 	  "[Press 'e' to end selection or 'q' to abort]", str);
 
-    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, 
-			   elements, meshSelection);
+    char ib = SelectEntity(ENT_ALL, vertices, edges, faces, regions, elements);
     if(ib == 'l') {
-      if(meshSelection == 2){
+      if(CTX.pick_elements){
 	for(unsigned int i = 0; i < elements.size(); i++){
 	  if(elements[i]->getVisibility() != 2){
 	    elements[i]->setVisibility(2);
@@ -3583,7 +3568,7 @@ void mesh_delete_parts_cb(CALLBACK_ARGS)
       }
     }
     if(ib == 'r') {
-      if(meshSelection == 2){
+      if(CTX.pick_elements){
 	for(unsigned int i = 0; i < elements.size(); i++)
 	  elements[i]->setVisibility(1);
       }
@@ -3593,7 +3578,7 @@ void mesh_delete_parts_cb(CALLBACK_ARGS)
       }
     }
     if(ib == 'u') {
-      if(meshSelection == 2){
+      if(CTX.pick_elements){
 	if(ele.size()){
 	  ele[ele.size() - 1]->setVisibility(1);
 	  ele.pop_back();
@@ -3607,7 +3592,7 @@ void mesh_delete_parts_cb(CALLBACK_ARGS)
       }
     }
     if(ib == 'e') {
-      if(meshSelection == 2){
+      if(CTX.pick_elements){
 	for(unsigned int i = 0; i < ele.size(); i++)
 	  if(ele[i]->getVisibility() == 2) ele[i]->setVisibility(0);
       }
@@ -3627,6 +3612,7 @@ void mesh_delete_parts_cb(CALLBACK_ARGS)
     }
   }
 
+  CTX.pick_elements = 0;
   CTX.mesh.changed = ENT_ALL;
   Draw();  
   Msg(ONSCREEN, "");
diff --git a/Fltk/Opengl.cpp b/Fltk/Opengl.cpp
index d1f5f20b39..a690878377 100644
--- a/Fltk/Opengl.cpp
+++ b/Fltk/Opengl.cpp
@@ -1,4 +1,4 @@
-// $Id: Opengl.cpp,v 1.68 2006-10-31 20:20:21 geuzaine Exp $
+// $Id: Opengl.cpp,v 1.69 2006-11-01 22:19:26 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -194,8 +194,7 @@ char SelectEntity(int type,
 		  std::vector<GEdge*> &edges,
 		  std::vector<GFace*> &faces,
 		  std::vector<GRegion*> &regions,
-		  std::vector<MElement*> &elements,
-		  int meshSelection)
+		  std::vector<MElement*> &elements)
 {
   if(!WID) return 'q';
 
@@ -240,13 +239,13 @@ char SelectEntity(int type,
 	WID->g_opengl_window->SelectionMode = false;
 	return 'c';
       }
-      else if(ProcessSelectionBuffer(WID->selection, multi,
+      else if(ProcessSelectionBuffer(WID->selection, multi, true,
 				     WID->try_selection_xywh[0],
 				     WID->try_selection_xywh[1], 
 				     WID->try_selection_xywh[2],
 				     WID->try_selection_xywh[3], 
 				     vertices, edges, faces, regions,
-				     elements, meshSelection)){
+				     elements)){
 	WID->selection = ENT_NONE;
 	WID->g_opengl_window->SelectionMode = false;
 	if(add)
diff --git a/Fltk/Opengl_Window.cpp b/Fltk/Opengl_Window.cpp
index 35a4e5970b..8758caac57 100644
--- a/Fltk/Opengl_Window.cpp
+++ b/Fltk/Opengl_Window.cpp
@@ -1,4 +1,4 @@
-// $Id: Opengl_Window.cpp,v 1.73 2006-10-31 20:20:21 geuzaine Exp $
+// $Id: Opengl_Window.cpp,v 1.74 2006-11-01 22:19:26 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -379,11 +379,11 @@ int Opengl_Window::handle(int event)
 	std::vector<GFace*> faces;
 	std::vector<GRegion*> regions;
 	std::vector<MElement*> elements;
-	int meshSelection = CTX.enable_mouse_selection > 1 ? 1 : 0;
 	bool something = ProcessSelectionBuffer(WID->selection, false,
+						CTX.enable_mouse_selection > 1,
 						(int)curr.win[0], (int)curr.win[1], 5, 5, 
 						vertices, edges, faces, regions,
-						elements, meshSelection);
+						elements);
 	if((WID->selection == ENT_ALL && something) ||
 	   (WID->selection == ENT_POINT && vertices.size()) ||
 	   (WID->selection == ENT_LINE && edges.size()) || 
diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index 909dbd7588..1f4d58a47e 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1,4 +1,4 @@
-// $Id: GModel.cpp,v 1.17 2006-10-31 20:20:21 geuzaine Exp $
+// $Id: GModel.cpp,v 1.18 2006-11-01 22:19:26 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -81,9 +81,88 @@ GVertex * GModel::vertexByTag(int n) const
     return 0;
 }
 
+template<class T>
+static bool removeElement(MElement *e, std::vector<T*> &vec)
+{
+  typename std::vector<T*>::iterator it = std::find(vec.begin(), vec.end(), e);
+  if(it == vec.end()) return false;
+  vec.erase(it);
+  delete e; 
+  return true; 
+}
+
+bool GModel::remove(MElement *e)
+{
+  switch(e->getDim()){
+  case 3:
+    for(riter it = firstRegion(); it != lastRegion(); ++it){
+      if(removeElement(e, (*it)->tetrahedra)) return true;
+      if(removeElement(e, (*it)->hexahedra)) return true;
+      if(removeElement(e, (*it)->prisms)) return true;
+      if(removeElement(e, (*it)->pyramids)) return true;
+    }
+    break;
+  case 2:
+    for(fiter it = firstFace(); it != lastFace(); ++it){
+      if(removeElement(e, (*it)->triangles)) return true;
+      if(removeElement(e, (*it)->quadrangles)) return true;
+    }
+    break;
+  case 1:
+    for(eiter it = firstEdge(); it != lastEdge(); ++it){
+      if(removeElement(e, (*it)->lines)) return true;
+    }
+    break;
+  }
+  return false;
+}
+
 void GModel::removeInvisible()
 {
-  printf("deleting all invisible entities/elements\n");
+  // FIXME: should make this faster
+  std::vector<MElement*> ele;
+  for(riter it = firstRegion(); it != lastRegion(); ++it){
+    for(unsigned int i = 0; i < (*it)->tetrahedra.size(); i++)
+      if(!(*it)->tetrahedra[i]->getVisibility()) ele.push_back((*it)->tetrahedra[i]);
+    for(unsigned int i = 0; i < (*it)->hexahedra.size(); i++)
+      if(!(*it)->hexahedra[i]->getVisibility()) ele.push_back((*it)->hexahedra[i]);
+    for(unsigned int i = 0; i < (*it)->prisms.size(); i++)
+      if(!(*it)->prisms[i]->getVisibility()) ele.push_back((*it)->prisms[i]);
+    for(unsigned int i = 0; i < (*it)->pyramids.size(); i++)
+      if(!(*it)->pyramids[i]->getVisibility()) ele.push_back((*it)->pyramids[i]);
+  }
+  for(fiter it = firstFace(); it != lastFace(); ++it){
+    for(unsigned int i = 0; i < (*it)->triangles.size(); i++)
+      if(!(*it)->triangles[i]->getVisibility()) ele.push_back((*it)->triangles[i]);
+    for(unsigned int i = 0; i < (*it)->quadrangles.size(); i++)
+      if(!(*it)->quadrangles[i]->getVisibility()) ele.push_back((*it)->quadrangles[i]);
+  }
+  for(eiter it = firstEdge(); it != lastEdge(); ++it){
+    for(unsigned int i = 0; i < (*it)->lines.size(); i++)
+      if(!(*it)->lines[i]->getVisibility()) ele.push_back((*it)->lines[i]);
+  }
+  for(unsigned int i = 0; i < ele.size(); i++)
+    remove(ele[i]);
+
+  std::vector<GRegion*> r;
+  for(riter it = firstRegion(); it != lastRegion(); ++it)
+    if(!(*it)->getVisibility()) r.push_back(*it);
+  for(unsigned int i = 0; i < r.size(); i++){ remove(r[i]); delete r[i]; }
+
+  std::vector<GFace*> f;
+  for(fiter it = firstFace(); it != lastFace(); ++it)
+    if(!(*it)->getVisibility()) f.push_back(*it);
+  for(unsigned int i = 0; i < f.size(); i++){ remove(f[i]); delete f[i]; }
+
+  std::vector<GEdge*> e;
+  for(eiter it = firstEdge(); it != lastEdge(); ++it)
+    if(!(*it)->getVisibility()) e.push_back(*it);
+  for(unsigned int i = 0; i < e.size(); i++){ remove(e[i]); delete e[i]; }
+
+  std::vector<GVertex*> v;
+  for(viter it = firstVertex(); it != lastVertex(); ++it)
+    if(!(*it)->getVisibility()) v.push_back(*it);
+  for(unsigned int i = 0; i < v.size(); i++){ remove(v[i]); delete v[i]; }
 }
 
 int GModel::renumberMeshVertices()
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 6bd08c30dc..a4e1acc013 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -90,6 +90,7 @@ class GModel
   void remove(GFace *f) { faces.erase(std::find(firstFace(), lastFace(), f)); }
   void remove(GEdge *e) { edges.erase(std::find(firstEdge(), lastEdge(), e)); }
   void remove(GVertex *v) { vertices.erase(std::find(firstVertex(), lastVertex(), v)); }
+  bool remove(MElement *e);
 
   // Deletes all invisble stuff (entities and elements)
   void removeInvisible();
@@ -154,7 +155,7 @@ class GModel
   // Export flat Gmsh geo model (only implemented for gmshModel at the moment)
   virtual int writeGEO(const std::string &name){ return 0; }
 
-  // FIXME: this will be removed (and rewritten)
+  // A container for smooth normals
   smooth_normals *normals;
 };
 
diff --git a/Graphics/Mesh.cpp b/Graphics/Mesh.cpp
index c5710a4c0a..654bb21cfa 100644
--- a/Graphics/Mesh.cpp
+++ b/Graphics/Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: Mesh.cpp,v 1.185 2006-10-31 20:20:22 geuzaine Exp $
+// $Id: Mesh.cpp,v 1.186 2006-11-01 22:19:26 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -442,7 +442,7 @@ static void drawArrays(GEntity *e, VertexArray *va, GLint type, bool useNormalAr
 
   // If we want to be enable picking of individual elements we need to
   // draw each one separately
-  if(CTX.render_mode == GMSH_SELECT && CTX.enable_mouse_selection > 2) {
+  if(CTX.render_mode == GMSH_SELECT && CTX.pick_elements) {
     if(va->getNumElementPointers() == va->getNumVertices()){
       for(int i = 0; i < va->getNumVertices(); i += va->getType()){
 	glPushName(va->getType());
@@ -475,7 +475,7 @@ static void drawArrays(GEntity *e, VertexArray *va, GLint type, bool useNormalAr
     glDisableClientState(GL_COLOR_ARRAY);
     glColor4ubv((GLubyte *) & color);
   }
-  else if(CTX.enable_mouse_selection > 2){
+  else if(CTX.pick_elements){
     glEnableClientState(GL_COLOR_ARRAY);
   }
   else if(!e->getSelection() && (CTX.mesh.color_carousel == 0 || 
@@ -617,7 +617,7 @@ class initMeshGFace {
 
     // mouse selection of individual elements is complicated if we
     // don't draw everything per element
-    if(CTX.enable_mouse_selection > 2) useEdges = false;
+    if(CTX.pick_elements) useEdges = false;
 
     // Further optimizations are possible when useEdges is true:
     // 1) store the unique vertices in the vertex array and use
@@ -731,7 +731,7 @@ class initMeshGRegion {
     
     // mouse selection of individual elements is complicated if we
     // don't draw everything per element
-    if(CTX.enable_mouse_selection > 2) useEdges = false;
+    if(CTX.pick_elements) useEdges = false;
 
     if(useEdges){
       Msg(DEBUG, "Using edges to draw volume %d", r->tag());
diff --git a/Graphics/SelectBuffer.cpp b/Graphics/SelectBuffer.cpp
index 8313750c1a..85b793e3fa 100644
--- a/Graphics/SelectBuffer.cpp
+++ b/Graphics/SelectBuffer.cpp
@@ -1,4 +1,4 @@
-// $Id: SelectBuffer.cpp,v 1.5 2006-10-31 20:20:22 geuzaine Exp $
+// $Id: SelectBuffer.cpp,v 1.6 2006-11-01 22:19:27 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -46,14 +46,14 @@ class hitDepthLessThan{
   }
 };
 
-bool ProcessSelectionBuffer(int entityType, bool multipleSelection, 
+bool ProcessSelectionBuffer(int entityType,
+			    bool multipleSelection, bool meshSelection,
 			    int x, int y, int w, int h,
 			    std::vector<GVertex*> &vertices,
 			    std::vector<GEdge*> &edges,
 			    std::vector<GFace*> &faces,
 			    std::vector<GRegion*> &regions,
-			    std::vector<MElement*> &elements,
-			    int meshSelection)
+			    std::vector<MElement*> &elements)
 {
   vertices.clear();
   edges.clear();
@@ -63,9 +63,9 @@ bool ProcessSelectionBuffer(int entityType, bool multipleSelection,
 
   // In our case the selection buffer size is equal to between 5 and 7
   // times the maximum number of possible hits
-  int size = 
-    7 * (GMODEL->numVertex() + GMODEL->numEdge() + GMODEL->numFace() + 
-	 GMODEL->numRegion() + (meshSelection > 1 ? 3 * GMODEL->numElement() : 0)) ;
+  int eles = (meshSelection && CTX.pick_elements) ? 3 * GMODEL->numElement() : 0;
+  int size = 7 * (GMODEL->numVertex() + GMODEL->numEdge() + GMODEL->numFace() + 
+		  GMODEL->numRegion() + eles) ;
 
   GLuint *selectionBuffer = new GLuint[size];
   glSelectBuffer(size, selectionBuffer);
diff --git a/Graphics/SelectBuffer.h b/Graphics/SelectBuffer.h
index b591bdb621..c2bbebd555 100644
--- a/Graphics/SelectBuffer.h
+++ b/Graphics/SelectBuffer.h
@@ -35,21 +35,20 @@
 #include "GFace.h"
 #include "GRegion.h"
 
-bool ProcessSelectionBuffer(int entityType, bool multipleSelection,
+bool ProcessSelectionBuffer(int entityType, 
+			    bool multipleSelection, bool meshSelection,
 			    int x, int y, int w, int h, 
 			    std::vector<GVertex*> &vertices,
 			    std::vector<GEdge*> &edges,
 			    std::vector<GFace*> &faces,
 			    std::vector<GRegion*> &regions,
-			    std::vector<MElement*> &elements,
-			    int meshSelection);
+			    std::vector<MElement*> &elements);
 char SelectEntity(int entityType,
 		  std::vector<GVertex*> &vertices,
 		  std::vector<GEdge*> &edges,
 		  std::vector<GFace*> &faces,
 		  std::vector<GRegion*> &regions,
-		  std::vector<MElement*> &elements,
-		  int meshSelection=1);
+		  std::vector<MElement*> &elements);
 
 void HighlightEntity(GEntity *e, bool permanent=false);
 void HighlightEntity(GVertex *v, GEdge *e, GFace *f, GRegion *r, bool permanent=false);
-- 
GitLab