From b76bf5090ad9afacfaa101bd3cdcea0e3de3ccc2 Mon Sep 17 00:00:00 2001
From: Emilie Marchandise <emilie.marchandise@uclouvain.be>
Date: Tue, 29 Nov 2011 16:40:11 +0000
Subject: [PATCH] added a new gLevelset for distance to STL (nice for
 adaptation with mmg3d around stl triangulations)

---
 Geo/gmshLevelset.cpp | 285 +++++++++++++++++++++++++------------------
 Geo/gmshLevelset.h   |   7 +-
 Numeric/cartesian.h  |  91 +++++++++++---
 3 files changed, 246 insertions(+), 137 deletions(-)

diff --git a/Geo/gmshLevelset.cpp b/Geo/gmshLevelset.cpp
index ad27fa8550..fcf96ed742 100644
--- a/Geo/gmshLevelset.cpp
+++ b/Geo/gmshLevelset.cpp
@@ -106,6 +106,61 @@ void removeParentCellsWithChildren(cartesianBox<double> *box)
   removeParentCellsWithChildren(box->getChildBox());
 }
 
+void computeLevelset(GModel *gm, cartesianBox<double> &box)
+{
+  // tolerance for desambiguation
+  const double tol = box.getLC() * 1.e-12;
+  std::vector<SPoint3> nodes;
+  std::vector<int> indices;
+  for (cartesianBox<double>::valIter it = box.nodalValuesBegin(); 
+       it != box.nodalValuesEnd(); ++it){
+    nodes.push_back(box.getNodeCoordinates(it->first));
+    indices.push_back(it->first);
+  }
+  Msg::Info("  %d nodes in the grid at level %d", (int)nodes.size(), box.getLevel());
+  std::vector<double> dist, localdist;
+  std::vector<SPoint3> dummy;
+  for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++){
+   if((*fit)->geomType() == GEntity::DiscreteSurface){
+      for(unsigned int k = 0; k < (*fit)->getNumMeshElements(); k++){ 
+	  std::vector<double> iDistances;
+	  std::vector<SPoint3> iClosePts;
+          std::vector<double> iDistancesE;
+	  MElement *e = (*fit)->getMeshElement(k);
+	  if(e->getType() == TYPE_TRI){
+	    MVertex *v1 = e->getVertex(0);
+	    MVertex *v2 = e->getVertex(1);
+	    MVertex *v3 = e->getVertex(2);
+	    SPoint3 p1(v1->x(),v1->y(),v1->z());
+	    SPoint3 p2(v2->x(),v2->y(),v2->z());
+	    SPoint3 p3(v3->x(),v3->y(),v3->z());
+	    signedDistancesPointsTriangle(localdist, dummy, nodes, p1, p2, p3);
+	  }
+	  if(dist.empty()) 
+	    dist = localdist;
+	  else{ 
+	    for (unsigned int j = 0; j < localdist.size(); j++){
+	      dist[j] = (fabs(dist[j]) < fabs(localdist[j])) ? dist[j] : localdist[j];
+	    }
+	  }
+      }
+    }
+    else{
+      printf(" CAD surface \n");
+      //look in utils_api_demos maincartesian
+      // for (GModel::fiter fit = _model->firstFace(); fit != _model->lastFace(); fit++){
+      // for (int i = 0; i < (*fit)->stl_triangles.size(); i += 3){
+    }
+  }
+
+  for (unsigned int j = 0; j < dist.size(); j++)
+    box.setNodalValue(indices[j], dist[j]);
+
+  if(box.getChildBox()) computeLevelset(gm, *box.getChildBox());
+}
+
+
+
 
 inline double det3(double d11, double d12, double d13, double d21, double d22, double d23, double d31, double d32, double d33) {
   return d11 * (d22 * d33 - d23 * d32) - d21 * (d12 * d33 - d13 * d32) + d31 * (d12 * d23 - d13 * d22);
@@ -588,77 +643,71 @@ double gLevelsetMathEval::operator() (const double x, const double y, const doub
     return 1.;
 }
 
-gLevelsetDistGeom::gLevelsetDistGeom(std::string name, int tag) : gLevelsetPrimitive(tag) {
-  //_model = new GModel();
-  //_model->load(name);
- 
+gLevelsetDistGeom::gLevelsetDistGeom(std::string geomBox, std::string name, int tag) : gLevelsetPrimitive(tag) {
+  
+  GModel *gmg = new GModel();
+  gmg->load(geomBox+std::string(".msh"));
   GModel *gm = new GModel();
   gm->load(name);
-
-  double lx = 0.1, ly = 0.1, lz = 0.1;
-  double rmax = 0.05;
+  
+  double lx = 0.5, ly = 0.5, lz = 0.5;
   int levels = 3;
   int refineCurvedSurfaces = 0;
 
+  double rmax = 0.1;
   double sampling = std::min(rmax, std::min(lx, std::min(ly, lz)));
-  double rtube = std::max(lx, std::max(ly, lz)) * 2.;
+  double rtube = std::max(lx, std::max(ly, lz))*2; //0.5; // * 2.;
 
+  Msg::Info("Filling coarse point cloud on surfaces");
   std::vector<SPoint3> points;
   std::vector<SPoint3> refinePoints;
+  for(GModel::viter vit = gmg->firstVertex(); vit != gmg->lastVertex(); vit++){
+    for(unsigned int k = 0; k < (*vit)->getNumMeshVertices(); k++){ 
+      MVertex  *v = (*vit)->getMeshVertex(k);
+       SPoint3 p(v->x(), v->y(), v->z());
+      points.push_back(p);
+    }
+  }
+  for (GModel::eiter eit = gmg->firstEdge(); eit != gmg->lastEdge(); eit++){
+    for(unsigned int k = 0; k < (*eit)->getNumMeshVertices(); k++){ 
+      MVertex  *ve = (*eit)->getMeshVertex(k);
+      SPoint3 pe(ve->x(), ve->y(), ve->z());
+      points.push_back(pe);
+    }
+  }
 
-  Msg::Info("Filling coarse point cloud on surfaces");
-
+  //FOR DISCRETE GEOMETRIES
+  for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++){
+    for(unsigned int k = 0; k < (*fit)->getNumMeshVertices(); k++){ 
+      MVertex  *vf = (*fit)->getMeshVertex(k);
+      SPoint3 pf(vf->x(), vf->y(), vf->z());
+      points.push_back(pf);
+    }
+    for(unsigned int k = 0; k < (*fit)->getNumMeshElements(); k++){ 
+      MElement *e =  (*fit)->getMeshElement(k);
+      if (e->getType() == TYPE_TRI){
+	MVertex *v1 = e->getVertex(0);
+	MVertex *v2 = e->getVertex(1);
+	MVertex *v3 = e->getVertex(2);
+	SPoint3 cg( (v1->x()+v2->x()+v3->x())/3.,
+		    (v1->y()+v2->y()+v3->y())/3.,
+		    (v1->z()+v2->z()+v3->z())/3.);
+	refinePoints.push_back(cg);
+      }
+    }
+  }
   //FOR CAD
-  for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++)
-     (*fit)->fillPointCloud(sampling, &points);
-
-  //FOR STL
-  // for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++){
-  //   for(unsigned int k = 0; k < (*fit)->getNumMeshElements(); k++){ 
-  //     MElement *e = (*fit)->getMeshElement(k);
-  //     if(e->getType() == TYPE_TRI){
-  // 	MVertex *v1 = e->getVertex(0);
-  // 	MVertex *v2 = e->getVertex(1);
-  // 	MVertex *v3 = e->getVertex(2);
-  // 	SPoint3 p1(v1->x(), v1->y(), v1->z());
-  // 	SPoint3 p2(v2->x(), v2->y(), v2->z());
-  // 	SPoint3 p3(v3->x(), v3->y(), v3->z());
-  // 	points.push_back(p1);
-  // 	points.push_back(p2);
-  // 	points.push_back(p3);
-  // 	// std::vector<SPoint3>::iterator it1 = std::find(points.begin(), points.end(), p1);
-  // 	// if(it1 != points.end())  points.push_back(p1);
-  // 	// std::vector<SPoint3>::iterator it2 = std::find(points.begin(), points.end(), p2);
-  // 	// if(it2 != points.end())  points.push_back(p2);
-  // 	// std::vector<SPoint3>::iterator it3 = std::find(points.begin(), points.end(),p3);
-  // 	// if(it3 != points.end())  points.push_back(p3);
-  //     }
-  //   }
-  // }
- Msg::Info("  %d points in the surface cloud", (int)points.size());
- if (points.size() == 0) {Msg::Fatal("No points on surfaces \n"); };
+  //for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++)
+  //   (*fit)->fillPointCloud(sampling, &points);
 
-
-  // if(levels > 1){
-  //   double s = sampling / pow(2., levels - 1);
-  //   Msg::Info("Filling refined point cloud on curves and curved surfaces");
-  //   for (GModel::eiter eit = gm->firstEdge(); eit != gm->lastEdge(); eit++)
-  //     fillPointCloud(*eit, s, refinePoints);
-
-  //   // FIXME: refine this by computing e.g. "mean" curvature
-  //   if(refineCurvedSurfaces){
-  //     for (GModel::fiter fit = gm->firstFace(); fit != gm->lastFace(); fit++)
-  //       if((*fit)->geomType() != GEntity::Plane)
-  //         (*fit)->fillPointCloud(2 * s, &refinePoints);
-  //   }
-  //   Msg::Info("  %d points in the refined cloud", (int)refinePoints.size());
-  // }
+  Msg::Info("  %d points in the surface cloud", (int)points.size());
+  if (points.size() == 0) {Msg::Fatal("No points on surfaces \n"); };
 
   SBoundingBox3d bb;
   for(unsigned int i = 0; i < points.size(); i++) bb += points[i]; 
   for(unsigned int i = 0; i < refinePoints.size(); i++) bb += refinePoints[i]; 
-  bb.scale(1.21, 1.21, 1.21);
-  SVector3 range = bb.max() - bb.min();   
+  //bb.scale(1.01, 1.01, 1.01);
+  SVector3 range = bb.max() - bb.min(); 
   int NX = range.x() / lx; 
   int NY = range.y() / ly; 
   int NZ = range.z() / lz; 
@@ -671,85 +720,89 @@ gLevelsetDistGeom::gLevelsetDistGeom(std::string name, int tag) : gLevelsetPrimi
             bb.max().x(), bb.max().y(), bb.max().z());
   Msg::Info("  Nx=%d Ny=%d Nz=%d", NX, NY, NZ);
   
-  cartesianBox<double> box(bb.min().x(), bb.min().y(), bb.min().z(), 
-                           SVector3(range.x(), 0, 0),
-                           SVector3(0, range.y(), 0),
-                           SVector3(0, 0, range.z()),
-                           NX, NY, NZ, levels);
-
-  Msg::Info("Inserting active cells in the cartesian grid");
-  Msg::Info("  level %d", box.getLevel());
-  for (unsigned int i = 0; i < points.size(); i++)
-    insertActiveCells(points[i].x(), points[i].y(), points[i].z(), rmax, box);
-
-  cartesianBox<double> *parent = &box, *child;
+  _box = new cartesianBox<double>(bb.min().x(), bb.min().y(), bb.min().z(), 
+				 SVector3(range.x(), 0, 0),
+				 SVector3(0, range.y(), 0),
+				 SVector3(0, 0, range.z()),
+				 NX, NY, NZ, levels);
+  Msg::Info("Inserting the active cells in the cartesian grid");
+  for (int i = 0; i < NX; i++)
+    for (int j = 0; j < NY; j++)
+      for (int k = 0; k < NZ; k++)
+        _box->insertActiveCell(_box->getCellIndex(i, j, k));
+
+  cartesianBox<double> *parent = _box, *child;
   while((child = parent->getChildBox())){
-    Msg::Info("  level %d", child->getLevel());
+    Msg::Info("  level %d ", child->getLevel());
     for(unsigned int i = 0; i < refinePoints.size(); i++)
       insertActiveCells(refinePoints[i].x(), refinePoints[i].y(), refinePoints[i].z(), 
-                        rtube / pow(2., (levels - child->getLevel())), *child);
+                         rtube / pow(2., (levels - child->getLevel())), *child);
     parent = child;
   }
 
-  // remove child cells that do not entirely fill parent cell or for
-  // which there is no parent neighbor; then remove parent cells that
-  // have children
-  Msg::Info("Removing cells to match X-FEM mesh topology constraints");
-  removeBadChildCells(&box);
-  removeParentCellsWithChildren(&box);
+  Msg::Info("Removing cells to match mesh topology constraints");
+  removeBadChildCells(_box);
+  removeParentCellsWithChildren(_box);
 
-  // we generate duplicate nodes at this point so we can easily access
-  // cell values at each level; we will clean up by renumbering after
-  // filtering
   Msg::Info("Initializing nodal values in the cartesian grid");
-  box.createNodalValues();
+  _box->createNodalValues();
 
   Msg::Info("Computing levelset on the cartesian grid");  
-  //computeLevelset(gm, box);
+  computeLevelset(gm, *_box);
 
+  double dist = _box->getValueContainingPoint(0, 0, 0);
   Msg::Info("Renumbering mesh vertices across levels");
-  box.renumberNodes();
+  _box->renumberNodes();
   
-  bool decomposeInSimplex = false;
-  box.writeMSH("yeah.msh", decomposeInSimplex);
-  exit(1);
+  double dist2 = _box->getValueContainingPoint(0, 0, 0);
+  printf("dist =%g dist2=%g \n", dist, dist2);
+  _box->writeMSH("yeah.msh", false);
 
+  delete gm;
+  delete gmg;
+ 
 }
 
 double gLevelsetDistGeom::operator() (const double x, const double y, const double z) const {
 
-  std::vector<SPoint3> nodes;
-  nodes.push_back(SPoint3(x,y,z));
-  double dist = 1.e22;
- 
-  for (GModel::fiter fit = _model->firstFace(); fit != _model->lastFace(); fit++){
-    if((*fit)->geomType() == GEntity::DiscreteSurface){
-      for(unsigned int k = 0; k < (*fit)->getNumMeshElements(); k++){ 
-	  std::vector<double> iDistances;
-	  std::vector<SPoint3> iClosePts;
-          std::vector<double> iDistancesE;
-	  MElement *e = (*fit)->getMeshElement(k);
-	  if(e->getType() == TYPE_TRI){
-	    MVertex *v1 = e->getVertex(0);
-	    MVertex *v2 = e->getVertex(1);
-	    MVertex *v3 = e->getVertex(2);
-	    SPoint3 p1(v1->x(), v1->y(), v1->z());
-	    SPoint3 p2(v2->x(), v2->y(), v2->z());
-	    SPoint3 p3(v3->x(),v3->y(),v3->z());
-	    signedDistancesPointsTriangle(iDistances, iClosePts, nodes, p1, p2, p3);
-	  }
-	  if (fabs(iDistances[0]) < fabs(dist)) dist = iDistances[0];
-      }
-    }
-    else{
-      printf(" CAD surface \n");
-      //look in utils_api_demos maincartesian
-      // for (GModel::fiter fit = _model->firstFace(); fit != _model->lastFace(); fit++){
-      // for (int i = 0; i < (*fit)->stl_triangles.size(); i += 3){
-    }
-  }
-  double ana =  sqrt((y*y)+(z*z))-0.5;
-  printf("xyz = %g %g %g dist = %g (%g)\n",x, y, z, -dist, ana );
+  double dist = _box->getValueContainingPoint(x,y,z);
+
+  //double ana =  sqrt((y*y)+(z*z))-0.5;
+  //printf("xyz = %g %g %g dist = %g (%g)\n",x, y, z, -dist, ana );
+  //exit(1);
+
+  // std::vector<SPoint3> nodes;
+  // nodes.push_back(SPoint3(x,y,z));
+  
+  // for (GModel::fiter fit = _model->firstFace(); fit != _model->lastFace(); fit++){
+  //   if((*fit)->geomType() == GEntity::DiscreteSurface){
+  //     for(unsigned int k = 0; k < (*fit)->getNumMeshElements(); k++){ 
+  // 	  std::vector<double> iDistances;
+  // 	  std::vector<SPoint3> iClosePts;
+  //         std::vector<double> iDistancesE;
+  // 	  MElement *e = (*fit)->getMeshElement(k);
+  // 	  if(e->getType() == TYPE_TRI){
+  // 	    MVertex *v1 = e->getVertex(0);
+  // 	    MVertex *v2 = e->getVertex(1);
+  // 	    MVertex *v3 = e->getVertex(2);
+  // 	    SPoint3 p1(v1->x(), v1->y(), v1->z());
+  // 	    SPoint3 p2(v2->x(), v2->y(), v2->z());
+  // 	    SPoint3 p3(v3->x(),v3->y(),v3->z());
+  // 	    signedDistancesPointsTriangle(iDistances, iClosePts, nodes, p1, p2, p3);
+  // 	  }
+  // 	  if (fabs(iDistances[0]) < fabs(dist)) dist = iDistances[0];
+  //     }
+  //   }
+  //   else{
+  //     printf(" CAD surface \n");
+  //     //look in utils_api_demos maincartesian
+  //     // for (GModel::fiter fit = _model->firstFace(); fit != _model->lastFace(); fit++){
+  //     // for (int i = 0; i < (*fit)->stl_triangles.size(); i += 3){
+  //   }
+  // }
+
+  // double ana =  sqrt((y*y)+(z*z))-0.5;
+  // printf("xyz = %g %g %g dist = %g (%g)\n",x, y, z, -dist, ana );
   //exit(1);
 
   return dist;
diff --git a/Geo/gmshLevelset.h b/Geo/gmshLevelset.h
index cb3d339157..a126c1486e 100644
--- a/Geo/gmshLevelset.h
+++ b/Geo/gmshLevelset.h
@@ -19,6 +19,7 @@
 #include "MVertex.h"
 #include "GmshConfig.h"
 #include "mathEvaluator.h"
+#include "cartesian.h"
 
 #if defined(HAVE_POST)
 #include "PView.h"
@@ -257,10 +258,10 @@ public:
 
 class gLevelsetDistGeom: public gLevelsetPrimitive
 {
-  GModel *_model;
+  cartesianBox<double> *_box;
 public:
-  gLevelsetDistGeom(std::string f, int tag=1);
-  ~gLevelsetDistGeom(){ if (_model) delete _model; }
+  gLevelsetDistGeom(std::string g, std::string f, int tag=1);
+  ~gLevelsetDistGeom(){if (_box) delete _box; }
   double operator () (const double x, const double y, const double z) const;
   int type() const { return UNKNOWN; }
 };
diff --git a/Numeric/cartesian.h b/Numeric/cartesian.h
index 131002ebf0..9eeb00bac5 100644
--- a/Numeric/cartesian.h
+++ b/Numeric/cartesian.h
@@ -13,6 +13,8 @@
 #include "SVector3.h"
 #include "SPoint3.h"
 #include "GmshMessage.h"
+#include "MHexahedron.h"
+#include "MVertex.h"
 
 // A cartesian grid that encompasses an oriented 3-D box, with values
 // stored at vertices:
@@ -171,25 +173,78 @@ class cartesianBox {
           }
         }
   }
-  /* double getValueContainingPoint(double x, double y, double z) const */
-  /* { */
-  /*   double val; */
-  /*   int t = getCellContainingPoint(x, y,z); */
-  /*   std::vector<scalar> values; */
-  /*   getNodalValuesForCell(t, values); */
-  /*   printf("values size =%d \n", values.size()); */
+  double getValueContainingPoint(double x, double y, double z) 
+  {
+
+    SVector3 DP (x - _X, y - _Y, z - _Z);
+    double xa = dot(DP, _xiAxis);
+    double ya = dot(DP, _etaAxis);
+    double za = dot(DP, _zetaAxis);
+
+    int t = getCellContainingPoint(x, y,z);
+    int i, j, k;
+    getCellIJK(t, i, j, k);
+
+    //printf("xyz = %g %g %g \n",x, y, z);
+    //printf("ijk =%d %d %d \n", i, j, k);
 
-  /*   SVector3 DP (x - _X, y - _Y, z - _Z); */
-  /*   double xi = dot(DP, _xiAxis); */
-  /*   double eta = dot(DP, _etaAxis); */
-  /*   double zeta = dot(DP, _zetaAxis);  */
-   
-  /*   double xi_e = xi-values[0]; */
-  /*   double eta_e = xi-_dxi/2; */
-  /*   double zeta_e = xi-_dxi/2; */
-     
-  /*   return val; */
-  /* } */
+    valIter it1 = _nodalValues.find(getNodeIndex(i, j, k));
+    valIter it2 = _nodalValues.find(getNodeIndex(i + 1, j, k));
+    valIter it3 = _nodalValues.find(getNodeIndex(i + 1, j + 1, k));
+    valIter it4 = _nodalValues.find(getNodeIndex(i, j + 1, k));
+    valIter it5 = _nodalValues.find(getNodeIndex(i, j, k + 1));
+    valIter it6 = _nodalValues.find(getNodeIndex(i + 1, j, k + 1));
+    valIter it7 = _nodalValues.find(getNodeIndex(i + 1, j + 1, k + 1));
+    valIter it8 = _nodalValues.find(getNodeIndex(i, j + 1, k + 1));
+
+    if(it1 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+    if(it2 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+    if(it3 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+    if(it4 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+    if(it5 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+    if(it6 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+    if(it7 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+    if(it8 == _nodalValues.end()) return _childBox->getValueContainingPoint(x,y,z);
+
+    double vals[8];
+    vals[0]  = it1->second.first;
+    vals[1]  = it2->second.first;
+    vals[2]  = it3->second.first;
+    vals[3]  = it4->second.first;
+    vals[4]  = it5->second.first;
+    vals[5]  = it6->second.first;
+    vals[6]  = it7->second.first;
+    vals[7]  = it8->second.first;
+    //for (int i= 0; i< 8; i++) printf("vals %d = %g \n", i, vals[i]);
+
+    SPoint3 p1 = getNodeCoordinates(it1->first);
+    SPoint3 p2 = getNodeCoordinates(it2->first);
+    SPoint3 p3 = getNodeCoordinates(it3->first);
+    SPoint3 p4 = getNodeCoordinates(it4->first);
+    SPoint3 p5 = getNodeCoordinates(it5->first);
+    SPoint3 p6 = getNodeCoordinates(it6->first);
+    SPoint3 p7 = getNodeCoordinates(it7->first);
+    SPoint3 p8 = getNodeCoordinates(it8->first);
+
+    MVertex *v1 = new MVertex(p1.x(), p1.y(), p1.z());
+    MVertex *v2 = new MVertex(p2.x(), p2.y(), p2.z());
+    MVertex *v3 = new MVertex(p3.x(), p3.y(), p3.z());
+    MVertex *v4 = new MVertex(p4.x(), p4.y(), p4.z());
+    MVertex *v5 = new MVertex(p5.x(), p5.y(), p5.z());
+    MVertex *v6 = new MVertex(p6.x(), p6.y(), p6.z());
+    MVertex *v7 = new MVertex(p7.x(), p7.y(), p7.z());
+    MVertex *v8 = new MVertex(p8.x(), p8.y(), p8.z());
+
+    MHexahedron *newElem = new MHexahedron(v1, v2, v3, v4, v5, v6, v7, v8);
+    double uvw[3];
+    double xyz[3] = {x,y,z};
+    newElem->xyz2uvw(xyz, uvw);
+    //printf("uvw =%g %g %g \n", uvw[0],uvw[1],uvw[2]);
+    double val = newElem->interpolate(vals, uvw[0], uvw[1], uvw[2]);
+
+    delete newElem;
+    return val;
+  }
   int getCellContainingPoint(double x, double y, double z) const
   {
     // P = P_0 + xi * _vdx + eta * _vdy + zeta *vdz
-- 
GitLab