From 7cdba047dc627c41115b10abac09e89b3d354b2a Mon Sep 17 00:00:00 2001
From: Thomas Toulorge <thomas.toulorge@mines-paristech.fr>
Date: Thu, 9 Mar 2017 15:08:48 +0000
Subject: [PATCH] Improved boundary layer detection for fast high-order curving

---
 Fltk/highOrderToolsWindow.cpp                 |   3 +-
 .../OptHomFastCurving.cpp                     | 107 +++++++++++++-----
 .../OptHomFastCurving.h                       |  13 ++-
 3 files changed, 86 insertions(+), 37 deletions(-)

diff --git a/Fltk/highOrderToolsWindow.cpp b/Fltk/highOrderToolsWindow.cpp
index 9e035fb266..3a49732803 100644
--- a/Fltk/highOrderToolsWindow.cpp
+++ b/Fltk/highOrderToolsWindow.cpp
@@ -124,7 +124,7 @@ static void chooseopti_cb(Fl_Widget *w, void *data)
     o->choice[0]->deactivate();
     o->choice[3]->deactivate();
     o->value[1]->deactivate();
-    o->value[2]->activate();
+    o->value[2]->deactivate();
     o->value[3]->deactivate();
     o->value[4]->deactivate();
     o->value[5]->deactivate();
@@ -197,7 +197,6 @@ static void highordertools_runopti_cb(Fl_Widget *w, void *data)
     FastCurvingParameters p;
     p.onlyVisible = onlyVisible;
     p.dim = dim;
-    p.maxNumLayers = (int) o->value[2]->value();
     HighOrderMeshFastCurving(GModel::current(), p);
     break;
   }
diff --git a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp
index 4d057c9d00..afbe2d0f4b 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp
+++ b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp
@@ -27,27 +27,28 @@
 //
 // Contributors: Thomas Toulorge, Jonathan Lambrechts
 
-#include <stdio.h>
+#include <cstdio>
 #include <sstream>
 #include <fstream>
-#include <iterator>
-#include <string.h>
-#include "GmshConfig.h"
+#include <string>
+#include <cmath>
 #include "OptHomFastCurving.h"
+#include "GmshConfig.h"
 #include "GModel.h"
 #include "Gmsh.h"
+#include "MLine.h"
 #include "MTriangle.h"
 #include "MQuadrangle.h"
 #include "MTetrahedron.h"
 #include "MHexahedron.h"
 #include "MPrism.h"
-#include "MLine.h"
+#include "MEdge.h"
+#include "MFace.h"
 #include "OS.h"
-#include <stack>
 #include "SVector3.h"
 #include "BasisFactory.h"
-#include "Field.h"
 #include "MetaEl.h"
+#include "qualityMeasuresJacobian.h"
 
 
 
@@ -205,15 +206,72 @@ void getOppositeEdge(MElement *el, const MEdge &elBaseEd, MEdge &elTopEd,
 }
 
 
+void getColumnQuad(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p,
+                   MEdge &elBaseEd,  std::vector<MElement*> &blob)
+{
+  const double maxDP = std::cos(p.maxAngle);
+
+  MElement *el = 0;
+
+  for (int iLayer = 0; iLayer < p.maxNumLayers; iLayer++) {
+    std::vector<MElement*> newElts = ed2el[elBaseEd];
+    el = (newElts[0] == el) ? newElts[1] : newElts[0];
+    if (el->getType() != TYPE_QUA) break;
+    MEdge elTopEd;
+    double edLenMin, edLenMax;
+    getOppositeEdge(el, elBaseEd, elTopEd, edLenMin, edLenMax);
+
+    if (edLenMin > edLenMax*p.maxRho) break;
+    const double dp = dot(elBaseEd.normal(), elTopEd.normal());
+    if (std::abs(dp) < maxDP) break;
+
+    blob.push_back(el);
+    elBaseEd = elTopEd;
+  }
+}
 
-bool getColumn2D(MEdgeVecMEltMap &ed2el,
-                 int maxNumLayers, const MEdge &baseEd,
-                 std::vector<MVertex*> &baseVert,
+
+void getColumnTri(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p,
+                   MEdge &elBaseEd, std::vector<MElement*> &blob)
+{
+  const double maxDP = std::cos(p.maxAngle);
+
+  MElement *el0 = 0, *el1 = 0;
+
+  for (int iLayer = 0; iLayer < p.maxNumLayers; iLayer++) {
+    std::vector<MElement*> newElts0 = ed2el[elBaseEd];
+    el0 = (newElts0[0] == el1) ? newElts0[1] : newElts0[0];
+    if (el0->getType() != TYPE_TRI) break;
+    MEdge elMidEd;
+    double edLenMin0, edLenMax0;
+    getOppositeEdge(el0, elBaseEd, elMidEd, edLenMin0, edLenMax0);
+
+    std::vector<MElement*> newElts1 = ed2el[elMidEd];
+    el1 = (newElts1[0] == el0) ? newElts1[1] : newElts1[0];
+    if (el1->getType() != TYPE_TRI) break;
+    MEdge elTopEd;
+    double edLenMin1, edLenMax1;
+    getOppositeEdge(el1, elMidEd, elTopEd, edLenMin1, edLenMax1);
+
+    const double edLenMin = std::min(edLenMin0, edLenMin1);
+    const double edLenMax = std::max(edLenMax0, edLenMax1);
+    if (edLenMin > edLenMax*p.maxRho) break;
+    const double dp = dot(elBaseEd.normal(), elTopEd.normal());
+    if (std::abs(dp) < maxDP) break;
+
+    blob.push_back(el0);
+    blob.push_back(el1);
+    elBaseEd = elTopEd;
+  }
+}
+
+
+
+bool getColumn2D(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p,
+                 const MEdge &baseEd, std::vector<MVertex*> &baseVert,
                  std::vector<MVertex*> &topPrimVert,
                  std::vector<MElement*> &blob)
 {
-  static const double tol = 2.;
-
   // Get first element and base vertices
   std::vector<MElement*> firstElts = ed2el[baseEd];
   if (firstElts.size() != 1) {
@@ -225,18 +283,10 @@ bool getColumn2D(MEdgeVecMEltMap &ed2el,
   const int iFirstElEd = getElementEdge(baseEd, el);
   el->getEdgeVertices(iFirstElEd, baseVert);
   MEdge elBaseEd(baseVert[0], baseVert[1]);
-  MEdge elTopEd;
 
   // Sweep column upwards by choosing largest edges in each element
-  for (int iLayer = 0; iLayer < maxNumLayers; iLayer++) {
-    double edLenMin, edLenMax;
-    getOppositeEdge(el, elBaseEd, elTopEd, edLenMin, edLenMax);
-    if (edLenMax < edLenMin*tol) break;
-    blob.push_back(el);
-    std::vector<MElement*> newElts = ed2el[elTopEd];
-    el = (newElts[0] == el) ? newElts[1] : newElts[0];
-    elBaseEd = elTopEd;
-  }
+  if (el->getType() == TYPE_TRI) getColumnTri(ed2el, p, elBaseEd, blob);
+  else getColumnQuad(ed2el, p, elBaseEd, blob);
 
   // TODO: improve by taking all vertices?
   topPrimVert.resize(2);
@@ -248,9 +298,8 @@ bool getColumn2D(MEdgeVecMEltMap &ed2el,
 
 
 // TODO: Implement 3D
-bool getColumn3D(MFaceVecMEltMap &face2el,
-                 int maxNumLayers, const MFace &baseFace,
-                 std::vector<MVertex*> &baseVert,
+bool getColumn3D(MFaceVecMEltMap &face2el, const FastCurvingParameters &p,
+                 const MFace &baseFace, std::vector<MVertex*> &baseVert,
                  std::vector<MVertex*> &topPrimVert,
                  std::vector<MElement*> &blob)
 {
@@ -303,7 +352,7 @@ private:
 
 
 void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el,
-                      GEntity *bndEnt, FastCurvingParameters &p)
+                      GEntity *bndEnt, const FastCurvingParameters &p)
 {
   // Build list of bnd. elements to consider
   std::list<MElement*> bndEl;
@@ -338,8 +387,7 @@ void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el,
       MVertex *vb1 = (*itBE)->getVertex(1);
       metaElType = TYPE_QUA;
       MEdge baseEd(vb0, vb1);
-      foundCol = getColumn2D(ed2el, p.maxNumLayers, baseEd, baseVert,
-                             topPrimVert, blob);
+      foundCol = getColumn2D(ed2el, p, baseEd, baseVert, topPrimVert, blob);
     }
     else {                                                                                  // 2D boundary
       MVertex *vb0 = (*itBE)->getVertex(0);
@@ -355,8 +403,7 @@ void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el,
         metaElType = TYPE_PRI;
       }
       MFace baseFace(vb0, vb1, vb2, vb3);
-      foundCol = getColumn3D(face2el, p.maxNumLayers, baseFace, baseVert,
-                             topPrimVert, blob);
+      foundCol = getColumn3D(face2el, p, baseFace, baseVert, topPrimVert, blob);
     }
     if (!foundCol) continue;                                                               // Skip bnd. el. if top vertices not found
     int order = blob[0]->getPolynomialOrder();
diff --git a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h
index 7fd62f20be..f34571fc6f 100644
--- a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h
+++ b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.h
@@ -33,12 +33,15 @@
 class GModel;
 
 struct FastCurvingParameters {
-  int dim ;           // Which dimension to curve
-  bool onlyVisible ;  // Apply curving to visible entities ONLY
-  int maxNumLayers;   // Maximum number of element layers to consider when trying to detect BL
+  int dim ;                       // Spatial dimension of the mesh to curve
+  bool onlyVisible ;              // Apply curving to visible entities ONLY?
+  int maxNumLayers;               // Maximum number of layers of elements to curve in BL
+  double maxRho;                  // Maximum ratio min/max edge/face size for elements to curve in BL
+  double maxAngle;                // Maximum angle between layers of elements to curve in BL
 
-  FastCurvingParameters ()
-    : dim(3) , onlyVisible(true), maxNumLayers(6)
+  FastCurvingParameters () :
+    dim(3) , onlyVisible(true), maxNumLayers(100), maxRho(0.5),
+    maxAngle(3.1415926535897932*10./180.)
   {
   }
 };
-- 
GitLab