From 4cbdd579cdd0f601dc2d491163368c14bfd3dd7d Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sat, 18 Sep 2010 11:18:27 +0000
Subject: [PATCH] * new option to select recombination algo (using
 subdivisionAlgo==3 is a bad idea) * new option to recombine all tri meshes,
 whatever the specific setting for a given surface * libmatch -> libblossom
 (there's a libMatch.dylib in the default MacOS install)

---
 CMakeLists.txt                  | 10 ++++------
 Common/Context.h                |  1 +
 Common/DefaultOptions.h         |  4 ++++
 Common/Options.cpp              | 32 +++++++++++++++++++++++++++++++-
 Common/Options.h                |  2 ++
 Fltk/optionWindow.cpp           | 33 +++++++++++++++++++++++++--------
 Geo/Geo.cpp                     |  1 +
 Mesh/Generator.cpp              |  6 +++---
 Mesh/meshGEdge.cpp              |  2 +-
 Mesh/meshGFace.cpp              |  6 ++++--
 Mesh/meshGFaceOptimize.cpp      |  5 ++---
 Mesh/meshGFaceTransfinite.cpp   |  4 ++--
 Mesh/meshGRegionTransfinite.cpp |  5 ++++-
 benchmarks/2d/recombine.geo     |  1 -
 14 files changed, 84 insertions(+), 28 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 58386f088c..6c6c4703b2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -702,17 +702,15 @@ if(ENABLE_ACIS)
 endif(ENABLE_ACIS)
 
 if(ENABLE_MATCH)
-  find_library(MATCH_LIB match PATH_SUFFIXES)
+  find_library(MATCH_LIB blossom PATH_SUFFIXES)
   find_library(CONCORDE_LIB concorde PATH_SUFFIXES)
   if(MATCH_LIB AND CONCORDE_LIB)
     find_path(CONCORDE_INC "concorde.h" PATH_SUFFIXES)
     find_path(MATCH_INC "match.h" PATH_SUFFIXES)
     if(MATCH_INC AND CONCORDE_INC)	     
-         set_config_option(HAVE_MATCH "Match")
-         list(APPEND EXTERNAL_LIBRARIES ${MATCH_LIB})
-         list(APPEND EXTERNAL_LIBRARIES ${CONCORDE_LIB})
-         list(APPEND EXTERNAL_INCLUDES ${MATCH_INC})
-         list(APPEND EXTERNAL_INCLUDES ${CONCORDE_INC})
+      set_config_option(HAVE_MATCH "Match")
+      list(APPEND EXTERNAL_LIBRARIES ${MATCH_LIB} ${CONCORDE_LIB})
+      list(APPEND EXTERNAL_INCLUDES ${MATCH_INC} ${CONCORDE_INC})
     endif(MATCH_INC AND CONCORDE_INC)
   endif(MATCH_LIB AND CONCORDE_LIB)
 endif(ENABLE_MATCH)
diff --git a/Common/Context.h b/Common/Context.h
index 6999f63533..662170ef44 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -29,6 +29,7 @@ struct contextMeshOptions {
   int lcFromPoints, lcFromCurvature, lcExtendFromBoundary;
   int dual, voronoi, drawSkinOnly, colorCarousel, labelSampling;
   int fileFormat, nbSmoothing, algo2d, algo3d, algoSubdivide;
+  int algoRecombine, recombineAll;
   int order, secondOrderLinear, secondOrderIncomplete;
   int secondOrderExperimental, meshOnlyVisible;
   int smoothInternalEdges, minCircPoints, minCurvPoints;
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index dde2fc4b5b..1c7470f07e 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1215,6 +1215,10 @@ StringXNumber MeshOptions_Number[] = {
   { F|O, "RandomFactor" , opt_mesh_rand_factor , 1.e-9 ,
     "Random factor used in the 2D meshing algorithm (should be increased if "
     "RandomFactor * size(triangle)/size(model) approaches machine accuracy)" },
+  { F|O, "RecombinationAlgorithm" , opt_mesh_algo_recombine , 0 ,
+    "Mesh recombination algorithm (0=standard, 1=blossom)" }, 
+  { F|O, "RecombineAll" , opt_mesh_recombine_all , 0 ,
+    "Apply recombination algorithm to all surfaces, ignoring per-surface spec" }, 
   { F|O, "RefineSteps" , opt_mesh_refine_steps , 10 ,
     "Number of refinement steps in the MeshAdapt-based 2D algorithms" }, 
   { F|O, "Remove4Triangles" , opt_mesh_remove_4_triangles , 0 ,
diff --git a/Common/Options.cpp b/Common/Options.cpp
index a70eec2f55..0778cdac46 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -5604,12 +5604,42 @@ double opt_mesh_algo2d(OPT_ARGS_NUM)
   return CTX::instance()->mesh.algo2d;
 }
 
+double opt_mesh_algo_recombine(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET){
+    CTX::instance()->mesh.algoRecombine = (int)val;
+    if(CTX::instance()->mesh.algoRecombine < 0 && 
+       CTX::instance()->mesh.algoRecombine > 1)
+      CTX::instance()->mesh.algoRecombine = 0;
+  }
+#if defined(HAVE_FLTK)
+  if(FlGui::available() && (action & GMSH_GUI)) {
+    FlGui::instance()->options->mesh.choice[1]->value
+      (CTX::instance()->mesh.algoRecombine);
+  }
+#endif
+  return CTX::instance()->mesh.algoRecombine;
+}
+
+double opt_mesh_recombine_all(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET){
+    CTX::instance()->mesh.recombineAll = (int)val;
+  }
+#if defined(HAVE_FLTK)
+  if(FlGui::available() && (action & GMSH_GUI))
+    FlGui::instance()->options->mesh.butt[21]->value
+      (CTX::instance()->mesh.recombineAll);
+#endif
+  return CTX::instance()->mesh.recombineAll;
+}
+
 double opt_mesh_algo_subdivide(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET){
     CTX::instance()->mesh.algoSubdivide = (int)val;
     if(CTX::instance()->mesh.algoSubdivide < 0 && 
-       CTX::instance()->mesh.algoSubdivide > 3)
+       CTX::instance()->mesh.algoSubdivide > 2)
       CTX::instance()->mesh.algoSubdivide = 0;
   }
 #if defined(HAVE_FLTK)
diff --git a/Common/Options.h b/Common/Options.h
index 1ac5159857..b0afa9e771 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -524,6 +524,8 @@ double opt_mesh_bdf_field_format(OPT_ARGS_NUM);
 double opt_mesh_nb_smoothing(OPT_ARGS_NUM);
 double opt_mesh_algo2d(OPT_ARGS_NUM);
 double opt_mesh_algo3d(OPT_ARGS_NUM);
+double opt_mesh_algo_recombine(OPT_ARGS_NUM);
+double opt_mesh_recombine_all(OPT_ARGS_NUM);
 double opt_mesh_algo_subdivide(OPT_ARGS_NUM);
 double opt_mesh_mesh_only_visible(OPT_ARGS_NUM);
 double opt_mesh_min_circ_points(OPT_ARGS_NUM);
diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp
index 54d8c022d2..c8fb6db7fc 100644
--- a/Fltk/optionWindow.cpp
+++ b/Fltk/optionWindow.cpp
@@ -451,6 +451,8 @@ static void mesh_options_ok_cb(Fl_Widget *w, void *data)
   opt_mesh_algo3d(0, GMSH_SET,
                   (o->mesh.choice[3]->value() == 0) ? ALGO_3D_DELAUNAY : 
                   ALGO_3D_FRONTAL);
+  opt_mesh_algo_recombine(0, GMSH_SET, o->mesh.choice[1]->value());
+  opt_mesh_recombine_all(0, GMSH_SET, o->mesh.butt[21]->value());
   opt_mesh_algo_subdivide(0, GMSH_SET, o->mesh.choice[5]->value());
   opt_mesh_color_carousel(0, GMSH_SET, o->mesh.choice[4]->value());
   opt_mesh_quality_type(0, GMSH_SET, o->mesh.choice[6]->value());
@@ -1972,11 +1974,15 @@ optionWindow::optionWindow(int deltaFontSize)
         {"Frontal", 0, 0, 0},
         {0}
       };
+      static Fl_Menu_Item menu_recombination_algo[] = {
+        {"Standard", 0, 0, 0},
+        {"Blossom", 0, 0, 0},
+        {0}
+      };
       static Fl_Menu_Item menu_subdivision_algo[] = {
         {"None", 0, 0, 0},
         {"All Quads", 0, 0, 0},
         {"All Hexas", 0, 0, 0},
-        {"All Quads (Blossom)", 0, 0, 0},
         {0}
       };
 
@@ -1992,14 +1998,25 @@ optionWindow::optionWindow(int deltaFontSize)
       mesh.choice[3]->align(FL_ALIGN_RIGHT);
       mesh.choice[3]->callback(mesh_options_ok_cb);
 
+      mesh.choice[1] = new Fl_Choice
+        (L + 2 * WB, 2 * WB + 3 * BH, IW, BH, "Recombination algorithm");
+      mesh.choice[1]->menu(menu_recombination_algo);
+      mesh.choice[1]->align(FL_ALIGN_RIGHT);
+      mesh.choice[1]->callback(mesh_options_ok_cb);
+
+      mesh.butt[21] = new Fl_Check_Button
+        (L + 2 * WB, 2 * WB + 4 * BH, BW, BH, "Recombine all triangular meshes");
+      mesh.butt[21]->type(FL_TOGGLE_BUTTON);
+      mesh.butt[21]->callback(mesh_options_ok_cb);
+
       mesh.choice[5] = new Fl_Choice
-        (L + 2 * WB, 2 * WB + 3 * BH, IW, BH, "Subdivision algorithm");
+        (L + 2 * WB, 2 * WB + 5 * BH, IW, BH, "Subdivision algorithm");
       mesh.choice[5]->menu(menu_subdivision_algo);
       mesh.choice[5]->align(FL_ALIGN_RIGHT);
       mesh.choice[5]->callback(mesh_options_ok_cb);
 
       mesh.value[0] = new Fl_Value_Input
-        (L + 2 * WB, 2 * WB + 4 * BH, IW, BH, "Smoothing steps");
+        (L + 2 * WB, 2 * WB + 6 * BH, IW, BH, "Smoothing steps");
       mesh.value[0]->minimum(0);
       mesh.value[0]->maximum(100);
       mesh.value[0]->step(1);
@@ -2007,7 +2024,7 @@ optionWindow::optionWindow(int deltaFontSize)
       mesh.value[0]->callback(mesh_options_ok_cb);
 
       mesh.value[2] = new Fl_Value_Input
-        (L + 2 * WB, 2 * WB + 5 * BH, IW, BH, "Element size factor");
+        (L + 2 * WB, 2 * WB + 7 * BH, IW, BH, "Element size factor");
       mesh.value[2]->minimum(0.001);
       mesh.value[2]->maximum(1000);
       mesh.value[2]->step(0.01);
@@ -2015,17 +2032,17 @@ optionWindow::optionWindow(int deltaFontSize)
       mesh.value[2]->callback(mesh_options_ok_cb);
 
       mesh.value[25] = new Fl_Value_Input
-        (L + 2 * WB, 2 * WB + 6 * BH, IW, BH, "Minimum element size");
+        (L + 2 * WB, 2 * WB + 8 * BH, IW, BH, "Minimum element size");
       mesh.value[25]->align(FL_ALIGN_RIGHT);
       mesh.value[25]->callback(mesh_options_ok_cb);
 
       mesh.value[26] = new Fl_Value_Input
-        (L + 2 * WB, 2 * WB + 7 * BH, IW, BH, "Maximum element size");
+        (L + 2 * WB, 2 * WB + 9 * BH, IW, BH, "Maximum element size");
       mesh.value[26]->align(FL_ALIGN_RIGHT);
       mesh.value[26]->callback(mesh_options_ok_cb);
 
       mesh.value[3] = new Fl_Value_Input
-        (L + 2 * WB, 2 * WB + 8 * BH, IW, BH, "Element order");
+        (L + 2 * WB, 2 * WB + 10 * BH, IW, BH, "Element order");
       mesh.value[3]->minimum(1);
       mesh.value[3]->maximum(2);
       mesh.value[3]->step(1);
@@ -2033,7 +2050,7 @@ optionWindow::optionWindow(int deltaFontSize)
       mesh.value[3]->callback(mesh_options_ok_cb);
 
       mesh.butt[4] = new Fl_Check_Button
-        (L + 2 * WB, 2 * WB + 9 * BH, BW, BH, "Use incomplete high order elements");
+        (L + 2 * WB, 2 * WB + 11 * BH, BW, BH, "Use incomplete high order elements");
       mesh.butt[4]->type(FL_TOGGLE_BUTTON);
       mesh.butt[4]->callback(mesh_options_ok_cb);
 
diff --git a/Geo/Geo.cpp b/Geo/Geo.cpp
index 53d33fd68c..d383b533d6 100644
--- a/Geo/Geo.cpp
+++ b/Geo/Geo.cpp
@@ -591,6 +591,7 @@ Surface *Create_Surface(int Num, int Typ)
   pS->Typ = Typ;
   pS->Method = MESH_UNSTRUCTURED;
   pS->Recombine = 0;
+  pS->RecombineAngle = 45;
   pS->Recombine_Dir = -1;
   pS->TypeOfMapping = 1;
   pS->TransfiniteSmoothing = -1;
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index f8fba46418..3bebd69de2 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -474,10 +474,10 @@ static void Mesh2D(GModel *m)
         GFaceCompound *gfc = (GFaceCompound*) gf;
         if(gfc->getNbSplit() != 0) continue;
       }
-      int recombine = gf->meshAttributes.recombine;
+      int rec = (CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine);
       Msg::Info("Lloyd optimization for face %d", gf->tag());
-      gf->lloyd(25, recombine);
-      if(recombine) recombineIntoQuads(gf);
+      gf->lloyd(25, rec);
+      if(rec) recombineIntoQuads(gf);
     }
   }
 
diff --git a/Mesh/meshGEdge.cpp b/Mesh/meshGEdge.cpp
index 655e1e6f40..d8144024d3 100644
--- a/Mesh/meshGEdge.cpp
+++ b/Mesh/meshGEdge.cpp
@@ -384,7 +384,7 @@ void meshGEdge::operator() (GEdge *ge)
     N = std::max(ge->minimumMeshSegments() + 1, (int)(a + 1.));
   }
   
-  if(CTX::instance()->mesh.algoSubdivide == 3 && N%2 == 0)N++;
+  if(CTX::instance()->mesh.algoRecombine == 1 && N%2 == 0) N++;
 
   //  printFandPrimitive(ge->tag(),Points);
 
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 44c8a4ffed..edbec3bfd0 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -898,7 +898,8 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
   // delete the mesh
   delete m;
 
-  if(gf->meshAttributes.recombine && !CTX::instance()->mesh.optimizeLloyd)
+  if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) && 
+     !CTX::instance()->mesh.optimizeLloyd)
     recombineIntoQuads(gf);
 
   computeElementShapes(gf, gf->meshStatistics.worst_element_shape,
@@ -1468,7 +1469,8 @@ static bool meshGeneratorPeriodic(GFace *gf, bool debug = true)
   // delete the mesh  
   delete m;
 
- if(gf->meshAttributes.recombine && !CTX::instance()->mesh.optimizeLloyd)
+ if((CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine) && 
+    !CTX::instance()->mesh.optimizeLloyd)
     recombineIntoQuads(gf);
  
   computeElementShapes(gf, gf->meshStatistics.worst_element_shape,
diff --git a/Mesh/meshGFaceOptimize.cpp b/Mesh/meshGFaceOptimize.cpp
index e4b602c2ac..e2a7d50156 100644
--- a/Mesh/meshGFaceOptimize.cpp
+++ b/Mesh/meshGFaceOptimize.cpp
@@ -1337,10 +1337,9 @@ static int _recombineIntoQuads(GFace *gf, int recur_level, bool cubicGraph = 1)
   std::set<MElement*> touched;
 
   
-  if(CTX::instance()->mesh.algoSubdivide == 3){
+  if(CTX::instance()->mesh.algoRecombine == 1){
 #ifdef HAVE_MATCH
     int ncount = gf->triangles.size();
-    //    printf("%d %d ----------------\n",CTX::instance()->mesh.algoSubdivide, ncount);
     if (ncount % 2 == 0) {
       int ecount =  cubicGraph ? pairs.size() + makeGraphPeriodic.size() : pairs.size();
       printf("%d internal %d closed\n",pairs.size(), makeGraphPeriodic.size());
@@ -1552,7 +1551,7 @@ void recombineIntoQuads(GFace *gf)
   gf->model()->writeMSH("raw.msh");
   for(int i = 0; i < CTX::instance()->mesh.nbSmoothing; i++) 
     laplaceSmoothing(gf);
-  if(success && CTX::instance()->mesh.algoSubdivide == 3){    
+  if(success && CTX::instance()->mesh.algoRecombine == 1){    
     gf->model()->writeMSH("smoothed.msh");
     int COUNT = 0;
     char NAME[256];
diff --git a/Mesh/meshGFaceTransfinite.cpp b/Mesh/meshGFaceTransfinite.cpp
index e94cfb20bb..ce00a080ec 100644
--- a/Mesh/meshGFaceTransfinite.cpp
+++ b/Mesh/meshGFaceTransfinite.cpp
@@ -420,7 +420,7 @@ int MeshTransfiniteSurface(GFace *gf)
         MVertex *v2 = tab[i + 1][j];
         MVertex *v3 = tab[i + 1][j + 1];
         MVertex *v4 = tab[i][j + 1];
-        if(gf->meshAttributes.recombine)
+        if(CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine)
           gf->quadrangles.push_back(new MQuadrangle(v1, v2, v3, v4));
         else if(gf->meshAttributes.transfiniteArrangement == 1 ||
                 (gf->meshAttributes.transfiniteArrangement == 0 && 
@@ -449,7 +449,7 @@ int MeshTransfiniteSurface(GFace *gf)
         MVertex *v2 = tab[i + 1][j];
         MVertex *v3 = tab[i + 1][j + 1];
         MVertex *v4 = tab[i][j + 1];
-        if(gf->meshAttributes.recombine)
+        if(CTX::instance()->mesh.recombineAll || gf->meshAttributes.recombine)
           gf->quadrangles.push_back(new MQuadrangle(v1, v2, v3, v4));
         else if(gf->meshAttributes.transfiniteArrangement == 1 ||
                 (gf->meshAttributes.transfiniteArrangement == 0 && 
diff --git a/Mesh/meshGRegionTransfinite.cpp b/Mesh/meshGRegionTransfinite.cpp
index 54c06268e0..7bcf689c31 100644
--- a/Mesh/meshGRegionTransfinite.cpp
+++ b/Mesh/meshGRegionTransfinite.cpp
@@ -220,7 +220,10 @@ class GOrientedTransfiniteFace {
   // returns the index of the face in the reference hexahedron
   int index() const { return _index; }
   // returns true if the face is recombined
-  int recombined() const { return _gf->meshAttributes.recombine; }
+  int recombined() const 
+  { 
+    return CTX::instance()->mesh.recombineAll || _gf->meshAttributes.recombine; 
+  }
   // returns the number or points in the transfinite mesh in both
   // parameter directions
   int getNumU(){ return (_permutation % 2) ? _HH + 1: _LL + 1; }
diff --git a/benchmarks/2d/recombine.geo b/benchmarks/2d/recombine.geo
index b0cddc8b8e..083f744b62 100644
--- a/benchmarks/2d/recombine.geo
+++ b/benchmarks/2d/recombine.geo
@@ -10,4 +10,3 @@ Line(4) = {4,1} ;
 Line Loop(5) = {4,1,-2,3} ;
 Plane Surface(6) = {5} ;
 Recombine Surface{6};
-Mesh.SubdivisionAlgorithm = 3;
-- 
GitLab