From 1e71ca7510e48c646d63c32f2d79110677cdd6ff Mon Sep 17 00:00:00 2001
From: Thomas Toulorge <thomas.toulorge@mines-paristech.fr>
Date: Mon, 7 Apr 2014 16:56:18 +0000
Subject: [PATCH] Added interpolation on current mesh for high-order mesh
 creation

---
 Mesh/HighOrder.cpp | 182 +++++++++++++++++++++++----------------------
 1 file changed, 92 insertions(+), 90 deletions(-)

diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp
index 626300d2cd..e7d8f378b8 100644
--- a/Mesh/HighOrder.cpp
+++ b/Mesh/HighOrder.cpp
@@ -125,9 +125,8 @@ static bool computeEquidistantParameters(GFace *gf, double u0, double uN,
 
 // --------- Creation of high-order edge vertices -----------
 
-static bool getEdgeVerticesonGeo(GEdge *ge, const MEdge &edge, std::vector<MVertex*> &ve, int nPts = 1)
+static bool getEdgeVerticesonGeo(GEdge *ge, MVertex *v0, MVertex *v1, std::vector<MVertex*> &ve, int nPts = 1)
 {
-    MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1);
     double u0 = 0., u1 = 0., US[100];
     bool reparamOK = reparamMeshVertexOnEdge(v0, ge, u0);
     if(ge->periodic(0) && ge->getEndVertex()->getNumMeshVertices() > 0 &&
@@ -170,9 +169,8 @@ static bool getEdgeVerticesonGeo(GEdge *ge, const MEdge &edge, std::vector<MVert
     return true;
 }
 
-static bool getEdgeVerticesonGeo(GFace *gf, const MEdge &edge, std::vector<MVertex*> &ve, int nPts = 1)
+static bool getEdgeVerticesonGeo(GFace *gf, MVertex *v0, MVertex *v1, std::vector<MVertex*> &ve, int nPts = 1)
 {
-      MVertex *v0 = edge.getVertex(0), *v1 = edge.getVertex(1);
       SPoint2 p0, p1;
       double US[100], VS[100];
       bool reparamOK = reparamMeshEdgeOnFace(v0, v1, gf, p0, p1);
@@ -186,7 +184,9 @@ static bool getEdgeVerticesonGeo(GFace *gf, const MEdge &edge, std::vector<MVert
           VS[nPts+1] =  p1[1];
           for(int j = 0; j < nPts; j++){
             const double t = (double)(j + 1) / (nPts + 1);
-            SPoint3 pc = edge.interpolate(t);
+            SPoint3 pc(t*v1->x()+(1.-t)*v0->x(),
+                       t*v1->y()+(1.-t)*v0->y(),
+                       t*v1->z()+(1.-t)*v0->z());
             SPoint2 guess = p0 * (1.-t) + p1 * t;
             GPoint gp = gf->closestPoint(pc, guess);
             if(gp.succeeded()){
@@ -213,17 +213,31 @@ static bool getEdgeVerticesonGeo(GFace *gf, const MEdge &edge, std::vector<MVert
       return true;
 }
 
-static void interpVerticesInExistingEdge(GEntity *ge, const MEdge &edge,
+static void interpVerticesInExistingEdge(GEntity *ge, const MElement *edgeEl,
                                          std::vector<MVertex*> &veEdge, int nPts)
 {
-  for(int j = 0; j < nPts; j++) {
-    const double t = (double)(j + 1)/(nPts + 1);
-    SPoint3 pc = edge.interpolate(t);
-    MVertex *v = new MVertex(pc.x(), pc.y(), pc.z(), ge);
+  fullMatrix<double> points;
+  points = edgeEl->getFunctionSpace(nPts+1)->points;
+  for(int k = 2; k < nPts+2; k++) {
+    SPoint3 pos;
+    edgeEl->pnt(points(k, 0), 0., 0., pos);
+    MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), ge);
     veEdge.push_back(v);
   }
 }
 
+inline static bool getMinMaxVert(MVertex *v0, MVertex *v1, MVertex *&vMin, MVertex *&vMax)
+{
+  const bool increasing = (v0->getNum() < v1->getNum());
+  if (increasing) {
+    vMin = v0; vMax = v1;
+  }
+  else {
+    vMin = v1; vMax = v0;
+  }
+  return increasing;
+}
+
 // Get new interior vertices for a 1D element
 static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve,
                             std::vector<MVertex*> &newHOVert, edgeContainer &edgeVertices,
@@ -233,14 +247,18 @@ static void getEdgeVertices(GEdge *ge, MElement *ele, std::vector<MVertex*> &ve,
      ge->geomType() == GEntity::BoundaryLayerCurve)
     linear = true;
 
-  MEdge edge = ele->getEdge(0);
-  std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
+  std::vector<MVertex*> veOld;
+  ele->getVertices(veOld);
+  MVertex *vMin, *vMax;
+  const bool increasing = getMinMaxVert(veOld[0], veOld[1], vMin, vMax);
+  std::pair<MVertex*, MVertex*> p(vMin, vMax);
   std::vector<MVertex*> veEdge;
-  bool gotVertOnGeo = linear ? false : getEdgeVerticesonGeo(ge, edge, veEdge, nPts);    // Get vertices on geometry if asked
+  bool gotVertOnGeo = linear ? false :
+                      getEdgeVerticesonGeo(ge, veOld[0], veOld[1], veEdge, nPts);       // Get vertices on geometry if asked
   if (!gotVertOnGeo)                                                                    // If not on geometry, create from mesh interpolation
-    interpVerticesInExistingEdge(ge, edge, veEdge, nPts);
+    interpVerticesInExistingEdge(ge, ele, veEdge, nPts);
   newHOVert.insert(newHOVert.end(), veEdge.begin(), veEdge.end());
-  if(edge.getVertex(0) == edge.getMinVertex())                                          // Add newly created vertices to list
+  if(increasing)                                          // Add newly created vertices to list
     edgeVertices[p].insert(edgeVertices[p].end(), veEdge.begin(), veEdge.end());
   else
     edgeVertices[p].insert(edgeVertices[p].end(), veEdge.rbegin(), veEdge.rend());
@@ -257,21 +275,27 @@ static void getEdgeVertices(GFace *gf, MElement *ele, std::vector<MVertex*> &ve,
     linear = true;
 
   for(int i = 0; i < ele->getNumEdges(); i++) {
-    MEdge edge = ele->getEdge(i);
-    std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
+    std::vector<MVertex*> veOld;
+    ele->getEdgeVertices(i,veOld);
+    MVertex *vMin, *vMax;
+    const bool increasing = getMinMaxVert(veOld[0], veOld[1], vMin, vMax);
+    std::pair<MVertex*, MVertex*> p(vMin, vMax);
     std::vector<MVertex*> veEdge;
     if(edgeVertices.count(p)) {                                                             // Vertices already exist
-      if(edge.getVertex(0) == edge.getMinVertex())
+      if(increasing)
         veEdge.assign(edgeVertices[p].begin(), edgeVertices[p].end());
       else
         veEdge.assign(edgeVertices[p].rbegin(), edgeVertices[p].rend());
     }
     else {                                                                                  // Vertices do not exist, create them
-      bool gotVertOnGeo = linear ? false : getEdgeVerticesonGeo(gf, edge, veEdge, nPts);    // Get vertices on geometry if asked
-      if (!gotVertOnGeo)                                                                    // If not on geometry, create from mesh interpolation
-        interpVerticesInExistingEdge(gf, edge, veEdge, nPts);
+      bool gotVertOnGeo = linear ? false :
+                          getEdgeVerticesonGeo(gf, veOld[0], veOld[1], veEdge, nPts);       // Get vertices on geometry if asked
+      if (!gotVertOnGeo) {                                                                   // If not on geometry, create from mesh interpolation
+        const MLineN edgeEl(veOld, ele->getPolynomialOrder());
+        interpVerticesInExistingEdge(gf, &edgeEl, veEdge, nPts);
+      }
       newHOVert.insert(newHOVert.end(), veEdge.begin(), veEdge.end());
-      if(edge.getVertex(0) == edge.getMinVertex())                                          // Add newly created vertices to list
+      if(increasing)                                                                        // Add newly created vertices to list
         edgeVertices[p].insert(edgeVertices[p].end(), veEdge.begin(), veEdge.end());
       else
         edgeVertices[p].insert(edgeVertices[p].end(), veEdge.rbegin(), veEdge.rend());
@@ -286,19 +310,23 @@ static void getEdgeVertices(GRegion *gr, MElement *ele, std::vector<MVertex*> &v
                             bool linear, int nPts = 1)
 {
   for(int i = 0; i < ele->getNumEdges(); i++) {
-    MEdge edge = ele->getEdge(i);
-    std::pair<MVertex*, MVertex*> p(edge.getMinVertex(), edge.getMaxVertex());
+    std::vector<MVertex*> veOld;
+    ele->getEdgeVertices(i,veOld);
+    MVertex *vMin, *vMax;
+    const bool increasing = getMinMaxVert(veOld[0], veOld[1], vMin, vMax);
+    std::pair<MVertex*, MVertex*> p(vMin, vMax);
     std::vector<MVertex*> veEdge;
     if(edgeVertices.count(p)) {                                                             // Vertices already exist
-      if(edge.getVertex(0) == edge.getMinVertex())
+      if(increasing)
         veEdge.assign(edgeVertices[p].begin(), edgeVertices[p].end());
       else
         veEdge.assign(edgeVertices[p].rbegin(), edgeVertices[p].rend());
     }
     else {                                                                                  // Vertices do not exist, create them
-      interpVerticesInExistingEdge(gr, edge, veEdge, nPts);
+      const MLineN edgeEl(veOld, ele->getPolynomialOrder());
+      interpVerticesInExistingEdge(gr, &edgeEl, veEdge, nPts);
       newHOVert.insert(newHOVert.end(), veEdge.begin(), veEdge.end());
-      if(edge.getVertex(0) == edge.getMinVertex())                                          // Add newly created vertices to list
+      if(increasing)                                                                        // Add newly created vertices to list
         edgeVertices[p].insert(edgeVertices[p].end(), veEdge.begin(), veEdge.end());
       else
         edgeVertices[p].insert(edgeVertices[p].end(), veEdge.rbegin(), veEdge.rend());
@@ -413,43 +441,6 @@ static void reorientQuadPoints(std::vector<MVertex*> &vtcs, int orientation,
   }
 }
 
-static int getNewFacePointsInFace(int numPrimaryFacePoints, int nPts, fullMatrix<double> &points)
-{
-  int start = 0;
-
-  int tag = 0;
-  switch(numPrimaryFacePoints) {
-    case 3:
-      if (nPts < 2) break;
-
-      tag = ElementType::getTag(TYPE_TRI, nPts+1);
-      if (!tag) {
-        Msg::Error("getFaceVertices not implemented for order %i", nPts +1);
-        break;
-      }
-      points = BasisFactory::getNodalBasis(tag)->points;
-      start = 3 * (1 + nPts);
-      break;
-
-    case 4:
-      if (nPts < 1) break;
-
-      tag = ElementType::getTag(TYPE_QUA, nPts+1);
-      if (!tag) {
-        Msg::Error("getFaceVertices not implemented for order %i", nPts +1);
-        break;
-      }
-      points = BasisFactory::getNodalBasis(tag)->points;
-      start = 4 * (1 + nPts);
-      break;
-
-    default:
-      Msg::Error("getFaceVertices not implemented for %d-node faces", numPrimaryFacePoints);
-      break;
-  }
-  return start;
-}
-
 static int getNewFacePointsInVolume(MElement *incomplete, int nPts, fullMatrix<double> &points)
 {
 
@@ -531,15 +522,16 @@ static int getNewFacePointsInVolume(MElement *incomplete, int nPts, fullMatrix<d
   return startFace;
 }
 
-static void getFaceVerticesOnGeo(GFace *gf, MElement *incomplete, const MFace &face,
-                            std::vector<MVertex*> &vf, int nPts = 1)
+static void getFaceVerticesOnGeo(GFace *gf, MElement *incomplete, const MElement *faceEl,
+                                 std::vector<MVertex*> &vf, int nPts = 1)
 {
   SPoint2 pts[1000];
   bool reparamOK = true;
   for(int k = 0; k < incomplete->getNumVertices(); k++)
     reparamOK &= reparamMeshVertexOnFace(incomplete->getVertex(k), gf, pts[k]);
   fullMatrix<double> points;
-  int start = getNewFacePointsInFace(face.getNumVertices(), nPts, points);
+  int start = (faceEl->getType() == 3) ? 3 * (1 + nPts) : 4 * (1 + nPts);
+  points = faceEl->getFunctionSpace(nPts+1)->points;
   for(int k = start; k < points.size1(); k++) {
     MVertex *v;
     const double t1 = points(k, 0);
@@ -581,28 +573,20 @@ static void getFaceVerticesOnGeo(GFace *gf, MElement *incomplete, const MFace &f
   }
 }
 
-static void interpVerticesInExistingFace(GEntity *ge, const MFace &face,
+static void interpVerticesInExistingFace(GEntity *ge, const MElement *faceEl,
                                          std::vector<MVertex*> &veFace, int nPts)
 {
   fullMatrix<double> points;
-  int start = getNewFacePointsInFace(face.getNumVertices(), nPts, points);
-  for(int k = start; k < points.size1(); k++){
-    const double t1 = points(k, 0);
-    const double t2 = points(k, 1);
-    SPoint3 pc = face.interpolate(t1, t2);
-    MVertex *v = new MVertex(pc.x(), pc.y(), pc.z(), ge);
+  int start = (faceEl->getType() == 3) ? 3 * (1 + nPts) : 4 * (1 + nPts);
+  points = faceEl->getFunctionSpace(nPts+1)->points;
+  for (int k = start; k < points.size1(); k++) {
+    double t1 = points(k, 0);
+    double t2 = points(k, 1);
+    SPoint3 pos;
+    faceEl->pnt(t1, t2, 0, pos);
+    MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), ge);
     veFace.push_back(v);
   }
-//  MElement *interpEl = getStraightInterpEl(face);
-//  for (int k = start; k < points.size1(); k++) {
-//    double t1 = points(k, 0);
-//    double t2 = points(k, 1);
-//    SPoint3 pos;
-//    interpEl->pnt(t1, t2, 0, pos);
-//    MVertex* v = new MVertex(pos.x(), pos.y(), pos.z(), gf);
-//    vf.push_back(v);
-//  }
-//  delete interpEl;
 }
 
 
@@ -636,9 +620,9 @@ static void getFaceVertices(GFace *gf, MElement *incomplete, MElement *ele,
   MFace face = ele->getFace(0);
   std::vector<MVertex*> veFace;
   if (!linear)                                                                      // Get vertices on geometry if asked...
-    getFaceVerticesOnGeo(gf, incomplete, face, veFace, nPts);
+    getFaceVerticesOnGeo(gf, incomplete, ele, veFace, nPts);
   else                                                                              // ... otherwise, create from mesh interpolation
-    interpVerticesInExistingFace(gf, face, veFace, nPts);
+    interpVerticesInExistingFace(gf, ele, veFace, nPts);
   newHOVert.insert(newHOVert.end(), veFace.begin(), veFace.end());
   faceVertices[face].insert(faceVertices[face].end(), veFace.begin(), veFace.end());
   vf.insert(vf.end(), veFace.begin(), veFace.end());
@@ -673,8 +657,17 @@ static void getFaceVertices(GRegion *gr, MElement *incomplete, MElement *ele,
       veFace.assign(vtcs.begin(), vtcs.end());
     }
     else {                                                                                // Vertices do not exist, create them by interpolation
-      if (linear)                                                                         // Interpolate on existing mesh
-        interpVerticesInExistingFace(gr, face, veFace, nPts);
+      if (linear) {                                                                       // Interpolate on existing mesh
+        std::vector<MVertex*> vfOld;
+        ele->getFaceVertices(i,vfOld);
+        MElement *faceEl;
+        if (face.getNumVertices() == 3)
+          faceEl = new MTriangleN(vfOld, ele->getPolynomialOrder());
+        else
+          faceEl = new MQuadrangleN(vfOld, ele->getPolynomialOrder());
+        interpVerticesInExistingFace(gr, faceEl, veFace, nPts);
+        delete faceEl;
+      }
       else {
         if (incomplete) {                                                                 // Interpolate in incomplete 3D element if given
           for(int k = index; k < index + numVert; k++){
@@ -730,7 +723,15 @@ static void getFaceVertices(GRegion *gr, MElement *incomplete, MElement *ele,
 //              veFace.push_back(v);
 //            }
 //          }
-          interpVerticesInExistingFace(gr, face, veFace, nPts);
+          std::vector<MVertex*> vfOld;
+          ele->getFaceVertices(i,vfOld);
+          MElement *faceEl;
+          if (face.getNumVertices() == 3)
+            faceEl = new MTriangleN(vfOld, nPts+1);
+          else
+            faceEl = new MQuadrangleN(vfOld, nPts+1);
+          interpVerticesInExistingFace(gr, faceEl, veFace, nPts);
+          delete faceEl;
         }
       }
       newHOVert.insert(newHOVert.end(), veFace.begin(), veFace.end());
@@ -833,13 +834,14 @@ static void getVolumeVertices(GRegion *gr, MElement *incomplete, MElement *ele,
 {
   fullMatrix<double> points;
   int startInter = getNewVolumePoints(incomplete, nPts, points);
+  const MElement *interpEl = linear ? ele : incomplete;
   for(int k = startInter; k < points.size1(); k++){
     MVertex *v;
     const double t1 = points(k, 0);
     const double t2 = points(k, 1);
     const double t3 = points(k, 2);
     SPoint3 pos;
-    incomplete->pnt(t1, t2, t3, pos);
+    interpEl->pnt(t1, t2, t3, pos);
     v = new MVertex(pos.x(), pos.y(), pos.z(), gr);
     newHOVert.push_back(v);
     vr.push_back(v);
-- 
GitLab