From 17451aa23eda6682b226bd1e746d098b4a04db82 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sat, 20 Mar 2010 10:11:10 +0000
Subject: [PATCH] move distance computation to Plugin(Distance)

---
 Common/CommandLine.cpp   |   5 -
 Common/Context.h         |   2 +-
 Common/CreateFile.cpp    |   6 -
 Common/DefaultOptions.h  |   2 -
 Common/Options.cpp       |   6 -
 Common/Options.h         |   1 -
 Geo/GModelIO_Mesh.cpp    | 329 -------------------------------------
 Plugin/CMakeLists.txt    |   1 +
 Plugin/Distance.cpp      | 343 +++++++++++++++++++++++++++++++++++++++
 Plugin/Distance.h        |  33 ++++
 Plugin/Plugin.h          |   6 +-
 Plugin/PluginManager.cpp |   3 +
 12 files changed, 385 insertions(+), 352 deletions(-)
 create mode 100644 Plugin/Distance.cpp
 create mode 100644 Plugin/Distance.h

diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index 8b96247668..75e58c9525 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -66,7 +66,6 @@ void PrintUsage(const char *name)
   Msg::Direct("                          bdf, p3d, cgns, med, fea)");
   Msg::Direct("  -bin                  Use binary format when available");  
   Msg::Direct("  -parametric           Save vertices with their parametric coordinates");  
-  Msg::Direct("  -distance             Save distance of vertices to the boundaries");  
   Msg::Direct("  -numsubedges          Set the number of subdivisions when displaying high order elements");  
   Msg::Direct("  -algo string          Select mesh algorithm (meshadapt, del2d, front2d, del3d, front3d)");
   Msg::Direct("  -smooth int           Set number of mesh smoothing steps");
@@ -496,10 +495,6 @@ void GetOptions(int argc, char *argv[])
         i++;
         CTX::instance()->mesh.saveParametric = 1;
       }
-      else if(!strcmp(argv[i] + 1, "distance")) {
-        i++;
-        CTX::instance()->mesh.saveDistance = 1;
-      }
       else if(!strcmp(argv[i] + 1, "algo")) {
         i++;
         if(argv[i]) {
diff --git a/Common/Context.h b/Common/Context.h
index 9d22f18bd4..0658b032cb 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -30,7 +30,7 @@ struct contextMeshOptions {
   int order, secondOrderLinear, secondOrderIncomplete;
   int secondOrderExperimental, meshOnlyVisible;
   int smoothInternalEdges, minCircPoints, minCurvPoints;
-  int saveAll, saveGroupsOfNodes, binary, bdfFieldFormat, saveParametric, saveDistance;
+  int saveAll, saveGroupsOfNodes, binary, bdfFieldFormat, saveParametric;
   int smoothNormals, reverseAllNormals, zoneDefinition, clip;
   int saveElementTagType;  
 };
diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp
index c43b878361..6160fbc619 100644
--- a/Common/CreateFile.cpp
+++ b/Common/CreateFile.cpp
@@ -183,12 +183,6 @@ void CreateOutputFile(std::string fileName, int format)
          CTX::instance()->mesh.binary, CTX::instance()->mesh.saveAll,
          CTX::instance()->mesh.saveParametric, CTX::instance()->mesh.scalingFactor);
     }
-    if (CTX::instance()->mesh.saveDistance){
-      GModel::current()->writeDistanceMSH
-	(fileName, CTX::instance()->mesh.mshFileVersion,
-	 CTX::instance()->mesh.binary, CTX::instance()->mesh.saveAll,
-	 CTX::instance()->mesh.saveParametric, CTX::instance()->mesh.scalingFactor);
-    }
     break;
 
   case FORMAT_STL:
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 41d2d2c6ac..fe3e73d1b0 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1208,8 +1208,6 @@ StringXNumber MeshOptions_Number[] = {
     "physical or partition ids (1=elementary, 2=physical, 3=partition)" },
   { F|O, "SaveParametric" , opt_mesh_save_parametric , 0. , 
     "Save parametric coordinates of nodes" },
-  { F|O, "SaveDistance" , opt_mesh_save_distance , 0. , 
-    "Save distance of nodes to boundaries" },
   { F|O, "SaveGroupsOfNodes" , opt_mesh_save_groups_of_nodes , 0. , 
     "Save groups of nodes for each physical line and surface (UNV mesh "
     "format only)" },
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 2cf5913fe1..f1077ee938 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -5695,12 +5695,6 @@ double opt_mesh_save_parametric(OPT_ARGS_NUM)
     CTX::instance()->mesh.saveParametric = val ? 1 : 0;
   return CTX::instance()->mesh.saveParametric;
 }
-double opt_mesh_save_distance(OPT_ARGS_NUM)
-{
-  if(action & GMSH_SET)
-    CTX::instance()->mesh.saveDistance = val ? 1 : 0;
-  return CTX::instance()->mesh.saveDistance;
-}
 
 double opt_mesh_save_groups_of_nodes(OPT_ARGS_NUM)
 {
diff --git a/Common/Options.h b/Common/Options.h
index 9ac991aafb..5a7cbc189f 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -531,7 +531,6 @@ double opt_mesh_draw_skin_only(OPT_ARGS_NUM);
 double opt_mesh_save_all(OPT_ARGS_NUM);
 double opt_mesh_save_element_tag_type(OPT_ARGS_NUM);
 double opt_mesh_save_parametric(OPT_ARGS_NUM);
-double opt_mesh_save_distance(OPT_ARGS_NUM);
 double opt_mesh_save_groups_of_nodes(OPT_ARGS_NUM);
 double opt_mesh_color_carousel(OPT_ARGS_NUM);
 double opt_mesh_zone_definition(OPT_ARGS_NUM);
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index ea0ffc427f..ccb4f58a45 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -28,21 +28,6 @@
 #include "discreteEdge.h"
 #include "discreteFace.h"
 #include "discreteRegion.h"
-#include "MElement.h"
-#include "GEdgeCompound.h"
-#include "GFaceCompound.h"
-#include "simpleFunction.h"
-#include "distanceTerm.h"
-#include "Context.h"
-#include "Numeric.h"
-#include "dofManager.h"
-#include "linearSystemGMM.h"
-#include "linearSystemCSR.h"
-#include "linearSystemFull.h"
-
-#if defined(HAVE_ANN)
-#include "ANN/ANN.h"
-#endif
 
 void GModel::_storePhysicalTagsInEntities(int dim,
                                           std::map<int, std::map<int, std::string> > &map)
@@ -858,320 +843,6 @@ int GModel::writePartitionedMSH(const std::string &baseName, bool binary,
   return 1;
 }
 
-int GModel::writeDistanceMSH(const std::string &name, double version, bool binary,
-			     bool saveAll, bool saveParametric, double scalingFactor)
-{
- 
-  std::vector<GEntity*> entities;
-  getEntities(entities);
-
-  int numnodes = 0;
-  for(unsigned int i = 0; i < entities.size()-1; i++)
-    numnodes += entities[i]->mesh_vertices.size();
-  int totNumNodes = numnodes + entities[entities.size()-1]->mesh_vertices.size();
-
-  std::map<MVertex*,double* > distance_map; 
-  std::map<MVertex*,double > distance_map2;
-  std::vector<SPoint3> pts;
-  std::vector<double> distances;
-  pts.clear(); 
-  distances.clear();
-  distances.reserve(totNumNodes);
-  pts.reserve(totNumNodes);
-  for (int i = 0; i< totNumNodes; i++)   distances.push_back(1.e22);
-
-  int k=0;
-  int maxDim = 0;
-  for(unsigned int i = 0; i < entities.size(); i++){
-    GEntity* ge = entities[i]; 
-    maxDim = std::max(maxDim, ge->dim());
-    for(unsigned int j = 0; j < ge->mesh_vertices.size(); j++){
-      MVertex *v = ge->mesh_vertices[j];
-      pts.push_back(SPoint3(v->x(), v->y(),v->z()));
-      distance_map.insert(std::make_pair(v, &(distances[k])));
-      distance_map2.insert(std::make_pair(v, 0.0));
-      k++;
-    }
-  }
-
-  //Compute geometrical distance to mesh boundaries
-  //-------------------------------------------------
-
-  for(unsigned int i = 0; i < entities.size(); i++){
-    if(entities[i]->dim() == (maxDim-1)) {
-      GEntity* g2 = entities[i];
-      for(unsigned int k = 0; k < g2->getNumMeshElements(); k++){ 
-	std::vector<double> iDistances;
-	std::vector<SPoint3> iClosePts;
-	MElement *e = g2->getMeshElement(k);
-	MVertex *v1 = e->getVertex(0);
-	MVertex *v2 = e->getVertex(1);
-	SPoint3 p1 (v1->x(),v1->y(),v1->z());
-	SPoint3 p2 (v2->x(),v2->y(),v2->z());
-	if( e->getNumVertices() == 2){
-	  signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);
-	}
-	else if( e->getNumVertices() == 3){
-	  MVertex *v3 = e->getVertex(2);
-	  SPoint3 p3 (v3->x(),v3->y(),v3->z());
-	  signedDistancesPointsTriangle(iDistances, iClosePts, pts, p1,p2,p3);
-	}
-	for (unsigned int kk = 0; kk< pts.size(); kk++) {
-	  if (std::abs(iDistances[kk]) < distances[kk] ) 
-	    distances[kk] = std::abs(iDistances[kk]);
-	}
-      }
-    }
-  }
-
-//   std::map<int, std::vector<GEntity*> > groups[4];
-//   getPhysicalGroups(groups);
-//   std::map<int, std::vector<GEntity*> >::const_iterator it = groups[1].find(100);//Physical Line(100)={...}
-//   if(it == groups[1].end()) return 0;
-//   const std::vector<GEntity *> &physEntities = it->second;
-//   for(unsigned int i = 0; i < physEntities.size(); i++){
-//     GEntity* g2 = physEntities[i];
-//     for(unsigned int i = 0; i < g2->getNumMeshElements(); i++){ 
-//       std::vector<double> iDistances;
-//       std::vector<SPoint3> iClosePts;
-//       MElement *e = g2->getMeshElement(i);
-//       MVertex *v1 = e->getVertex(0);
-//       MVertex *v2 = e->getVertex(1);
-//       SPoint3 p1 (v1->x(),v1->y(),v1->z());
-//       SPoint3 p2 (v2->x(),v2->y(),v2->z());
-//       signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);     
-//       for (int k = 0; k< pts.size(); k++) {
-// 	if (std::abs(iDistances[k]) < distances[k] ) 
-// 	  distances[k] = std::abs(iDistances[k]);
-//       }
-//     }
-//   }
-
-
-  //Compute PDE for distance function
-  //-------------------------------------------------
-  
-#ifdef HAVE_TAUCS
-  linearSystemCSRTaucs<double> *lsys = new linearSystemCSRTaucs<double>;
-#else
-  linearSystemCSRGmm<double> *lsys = new linearSystemCSRGmm<double>;
-  lsys->setNoisy(1);
-  lsys->setGmres(1);
-  lsys->setPrec(5.e-8);
-#endif
-
-  dofManager<double> myAssembler(lsys);
-
-  SBoundingBox3d bbox;
-  for(unsigned int i = 0; i < entities.size(); i++){
-    if(entities[i]->dim() < maxDim) {
-      GEntity *ge = entities[i];
-      for(unsigned int j = 0; j < ge->mesh_vertices.size(); j++){
-	MVertex *v = ge->mesh_vertices[j];
-	myAssembler.fixVertex(v, 0, 1, 0.0);
-	bbox += SPoint3(v->x(),v->y(),v->z());
-      }
-    }
-  }
-
-  for(unsigned int ii = 0; ii < entities.size(); ii++){
-    if(entities[ii]->dim() == maxDim) {
-      GEntity *ge = entities[ii];
-      for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i){
-	MElement *t = ge->getMeshElement(i);
-	for (int k = 0; k < t->getNumVertices(); k++){
-	    myAssembler.numberVertex(t->getVertex(k), 0, 1);
-	}
-      }    
-    }  
-  }
-
-  double L = norm(SVector3(bbox.max(), bbox.min())); 
-  double mu = L/28;
-  printf("L=%g \n", L);
-
-  simpleFunction<double> DIFF(mu * mu), MONE(1.0);
-  distanceTerm distance(this, 1, &DIFF, &MONE);
-  
-  for(unsigned int ii = 0; ii < entities.size(); ii++){
-    if(entities[ii]->dim() == maxDim) {
-      GEntity *ge = entities[ii];
-      for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i){
-	SElement se(ge->getMeshElement(i));
-	distance.addToMatrix(myAssembler, &se);
-      }
-      groupOfElements g((GFace*)ge);
-      distance.addToRightHandSide(myAssembler, g);
-    }
-  }
-
-   Msg::Info("Distance Computation: Assembly done");
-   lsys->systemSolve();
-   Msg::Info("Distance Computation: System solved");
- 
-   for(std::map<MVertex*,double >::iterator itv = distance_map2.begin(); itv !=distance_map2.end() ; ++itv){
-    MVertex *v = itv->first;
-    double value =  std::min(0.9999, myAssembler.getDofValue(v, 0, 1));
-    double dist = -mu * log(1. - value);
-    itv->second = dist;
-   }
-
-  lsys->clear();
-
-  //Writing pos files
-  //----------------------
-
-  Msg::Info("Writing distance-GEOM.pos");
-  FILE * f2 = fopen("distance-GEOM.pos","w");
-  fprintf(f2,"View \"distance GEOM\"{\n");
-  int j = 0;
-  for(std::vector<double>::iterator it = distances.begin(); it != distances.end(); it++) {
-    fprintf(f2,"SP(%g,%g,%g){%g};\n",
-	    pts[j].x(),  pts[j].y(),  pts[j].z(),
-	    *it);  
-    j++;
-  }
-  fprintf(f2,"};\n");
-  fclose(f2);
-
-  Msg::Info("Writing distance-bgm.pos");
-  FILE * f3 = fopen("distance-bgm.pos","w");
-  fprintf(f3,"View \"distance\"{\n");
-  for(unsigned int ii = 0; ii < entities.size(); ii++){
-    if(entities[ii]->dim() == maxDim) {
-      for(unsigned int i = 0; i < entities[ii]->getNumMeshElements(); i++){ 
-	MElement *e = entities[ii]->getMeshElement(i);
-	if (maxDim == 3) fprintf(f3,"SS(");
-	else if (maxDim == 2) fprintf(f3,"ST(");
-	std::vector<double> dist;
-	for(int j = 0; j < e->getNumVertices(); j++) {
-	  MVertex *v =  e->getVertex(j);
-	  if(j) fprintf(f3,",%g,%g,%g",v->x(),v->y(), v->z());
-	  else fprintf(f3,"%g,%g,%g", v->x(),v->y(), v->z());
-	  std::map<MVertex*, double*>::iterator it = distance_map.find(v);
-	  dist.push_back(*(it->second));
-	}
-	fprintf(f3,"){");
-	for (unsigned int i = 0; i < dist.size(); i++){
-	  if (i) fprintf(f3,",%g", dist[i]);
-	  else fprintf(f3,"%g", dist[i]);
-	}   
-	fprintf(f3,"};\n");
-      }
-    }
-  }
-  fprintf(f3,"};\n");
-  fclose(f3);
-
-  Msg::Info("Writing distance-bgm2.pos");
-  FILE * f4 = fopen("distance-bgm2.pos","w");
-  fprintf(f4,"View \"distance\"{\n");
-  //GEntity* ge = entities[entities.size()-1];
-  for(unsigned int ii = 0; ii < entities.size(); ii++){
-    if(entities[ii]->dim() == maxDim) {
-      for(unsigned int i = 0; i < entities[ii]->getNumMeshElements(); i++){ 
-	MElement *e = entities[ii]->getMeshElement(i);
-	if (maxDim == 3) fprintf(f4,"SS(");
-	else if (maxDim == 2) fprintf(f4,"ST(");
-	std::vector<double> dist;
-	for(int j = 0; j < e->getNumVertices(); j++) {
-	  MVertex *v =  e->getVertex(j);
-	  if(j) fprintf(f4,",%g,%g,%g",v->x(),v->y(), v->z());
-	  else fprintf(f4,"%g,%g,%g", v->x(),v->y(), v->z());
-	  std::map<MVertex*, double>::iterator it = distance_map2.find(v);
-	  dist.push_back(it->second);
-	}
-	fprintf(f4,"){");
-	for (unsigned int i = 0; i < dist.size(); i++){
-	  if (i) fprintf(f4,",%g", dist[i]);
-	  else fprintf(f4,"%g", dist[i]);
-	}   
-	fprintf(f4,"};\n");
-      }
-    }
-  }
-  fprintf(f4,"};\n");
-  fclose(f4);
-
-      
-// #if defined(HAVE_ANN)
-//   Msg::Info("Computing Distance function to the boundaries with ANN");
-//   std::map<MVertex*,double > distance; 
-
-//  // add all points from boundaries into kdtree
-//   ANNpointArray kdnodes = annAllocPts(numnodes, 4);
-//   k = 0;
-//   for(unsigned int i = 0; i < entities.size()-1; i++)
-//     for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++){
-//       MVertex *v =  entities[i]->mesh_vertices[j];
-//       distance.insert(std::make_pair(v, 0.0));
-//       kdnodes[k][0] = v->x();
-//       kdnodes[k][1] = v->y();
-//       kdnodes[k][2] = v->z();
-//       k++;
-//     }  
-//   ANNkd_tree *kdtree = new ANNkd_tree(kdnodes, numnodes, 3);
-
-//   // compute the distances with the kdtree
-//   ANNidxArray index = new ANNidx[1];
-//   ANNdistArray dist = new ANNdist[1];
-//   GEntity* ga = entities[entities.size()-1];
-//   for(unsigned int j = 0; j < ga->mesh_vertices.size(); j++){
-//     MVertex *v = ga->mesh_vertices[j];
-//     double xyz[3] = {v->x(), v->y(), v->z()};
-//     kdtree->annkSearch(xyz, 1, index, dist);
-//     double d = sqrt(dist[0]);
-//     distance.insert(std::make_pair(v, d));
-//   }
-//   delete [] index;
-//   delete [] dist;
-//   delete kdtree;
-//   annDeallocPts(kdnodes);
-
-//   //write distance in msh file
-//   Msg::Info("Writing distance-ANN.pos");
-//   FILE * f = fopen("distance-ANN.pos","w");
-//   fprintf(f,"View \"distance ANN\"{\n");
-//   for(std::map<MVertex*, double>::iterator it = distance.begin(); it != distance.end(); it++) {
-//     fprintf(f,"SP(%g,%g,%g){%g};\n",
-// 	    it->first->x(), it->first->y(), it->first->z(),
-// 	    it->second);     
-//   }
-//   fprintf(f,"};\n");
-//   fclose(f);
-
-// #endif
-
-//   Msg::Info("Writing distance-bgm.pos");
-//   FILE * f2 = fopen("distance-bgm.pos","w");
-//   fprintf(f2,"View \"distance\"{\n");
-//   GEntity* ge = entities[entities.size()-1];
-//   for(unsigned int i = 0; i < ge->getNumMeshElements(); i++){ 
-//     MElement *e = ge->getMeshElement(i);
-//     fprintf(f2,"ST(");//TO DO CHANGE this
-//     std::vector<double> dist;
-//     for(int j = 0; j < e->getNumVertices(); j++) {
-//       MVertex *v =  e->getVertex(j);
-//       if(j) fprintf(f2,",%g,%g,%g",v->x(),v->y(), v->z());
-//       else fprintf(f2,"%g,%g,%g", v->x(),v->y(), v->z());
-//       std::map<MVertex*, double>::iterator it = distance.find(v);
-//       dist.push_back(it->second);
-//     }
-//     fprintf(f2,"){");
-//     for (int i=0; i<dist.size(); i++){
-//       if (i) fprintf(f2,",%g", dist[i]);
-//       else fprintf(f2,"%g", dist[i]);
-//     }   
-//     fprintf(f2,"};\n");
-//   }
-//   fprintf(f2,"};\n");
-//   fclose(f2);
-
-
-  return 1;
-
-}
-
 int GModel::writePOS(const std::string &name, bool printElementary, 
                      bool printElementNumber, bool printGamma, bool printEta, 
                      bool printRho, bool printDisto, bool saveAll,
diff --git a/Plugin/CMakeLists.txt b/Plugin/CMakeLists.txt
index 797ca59a77..12b32aa25e 100644
--- a/Plugin/CMakeLists.txt
+++ b/Plugin/CMakeLists.txt
@@ -23,6 +23,7 @@ set(SRC
   Probe.cpp
   HarmonicToTime.cpp ModulusPhase.cpp
   HomologyComputation.cpp
+  Distance.cpp
 )
 
 file(GLOB HDR RELATIVE ${CMAKE_SOURCE_DIR}/Plugin *.h) 
diff --git a/Plugin/Distance.cpp b/Plugin/Distance.cpp
new file mode 100644
index 0000000000..d4121bb6d6
--- /dev/null
+++ b/Plugin/Distance.cpp
@@ -0,0 +1,343 @@
+// Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+//
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
+
+#include <stdlib.h>
+#include "Gmsh.h"
+#include "GmshConfig.h"
+#include "GModel.h"
+#include "Distance.h"
+#include "simpleFunction.h"
+#include "distanceTerm.h"
+#include "Context.h"
+#include "Numeric.h"
+#include "dofManager.h"
+#include "linearSystemGMM.h"
+#include "linearSystemCSR.h"
+#include "linearSystemFull.h"
+
+#if defined(HAVE_ANN)
+#include "ANN/ANN.h"
+#endif
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterDistancePlugin()
+  {
+    return new GMSH_DistancePlugin();
+  }
+}
+
+std::string GMSH_DistancePlugin::getHelp() const
+{
+  return "Plugin(Distance) computes distances to boundaries in "
+    "a mesh.\n\n"
+    "Plugin(Distance) creates a bunch of files.";
+}
+
+PView *GMSH_DistancePlugin::execute(PView *v)
+{
+  std::vector<GEntity*> entities;
+  GModel::current()->getEntities(entities);
+
+  int numnodes = 0;
+  for(unsigned int i = 0; i < entities.size() - 1; i++)
+    numnodes += entities[i]->mesh_vertices.size();
+  int totNumNodes = numnodes + entities[entities.size() - 1]->mesh_vertices.size();
+
+  std::map<MVertex*,double* > distance_map; 
+  std::map<MVertex*,double > distance_map2;
+  std::vector<SPoint3> pts;
+  std::vector<double> distances;
+  pts.clear(); 
+  distances.clear();
+  distances.reserve(totNumNodes);
+  pts.reserve(totNumNodes);
+  for (int i = 0; i < totNumNodes; i++) distances.push_back(1.e22);
+
+  int k = 0;
+  int maxDim = 0;
+  for(unsigned int i = 0; i < entities.size(); i++){
+    GEntity* ge = entities[i]; 
+    maxDim = std::max(maxDim, ge->dim());
+    for(unsigned int j = 0; j < ge->mesh_vertices.size(); j++){
+      MVertex *v = ge->mesh_vertices[j];
+      pts.push_back(SPoint3(v->x(), v->y(),v->z()));
+      distance_map.insert(std::make_pair(v, &(distances[k])));
+      distance_map2.insert(std::make_pair(v, 0.0));
+      k++;
+    }
+  }
+
+  // Compute geometrical distance to mesh boundaries
+
+  for(unsigned int i = 0; i < entities.size(); i++){
+    if(entities[i]->dim() == (maxDim - 1)) {
+      GEntity* g2 = entities[i];
+      for(unsigned int k = 0; k < g2->getNumMeshElements(); k++){ 
+	std::vector<double> iDistances;
+	std::vector<SPoint3> iClosePts;
+	MElement *e = g2->getMeshElement(k);
+	MVertex *v1 = e->getVertex(0);
+	MVertex *v2 = e->getVertex(1);
+	SPoint3 p1(v1->x(), v1->y(), v1->z());
+	SPoint3 p2(v2->x(), v2->y(), v2->z());
+	if(e->getNumVertices() == 2){
+	  signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);
+	}
+	else if(e->getNumVertices() == 3){
+	  MVertex *v3 = e->getVertex(2);
+	  SPoint3 p3 (v3->x(),v3->y(),v3->z());
+	  signedDistancesPointsTriangle(iDistances, iClosePts, pts, p1, p2, p3);
+	}
+	for (unsigned int kk = 0; kk< pts.size(); kk++) {
+	  if (std::abs(iDistances[kk]) < distances[kk])
+	    distances[kk] = std::abs(iDistances[kk]);
+	}
+      }
+    }
+  }
+
+//   std::map<int, std::vector<GEntity*> > groups[4];
+//   getPhysicalGroups(groups);
+//   std::map<int, std::vector<GEntity*> >::const_iterator it = groups[1].find(100);
+//   if(it == groups[1].end()) return 0;
+//   const std::vector<GEntity *> &physEntities = it->second;
+//   for(unsigned int i = 0; i < physEntities.size(); i++){
+//     GEntity* g2 = physEntities[i];
+//     for(unsigned int i = 0; i < g2->getNumMeshElements(); i++){ 
+//       std::vector<double> iDistances;
+//       std::vector<SPoint3> iClosePts;
+//       MElement *e = g2->getMeshElement(i);
+//       MVertex *v1 = e->getVertex(0);
+//       MVertex *v2 = e->getVertex(1);
+//       SPoint3 p1 (v1->x(),v1->y(),v1->z());
+//       SPoint3 p2 (v2->x(),v2->y(),v2->z());
+//       signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);     
+//       for (int k = 0; k< pts.size(); k++) {
+// 	if (std::abs(iDistances[k]) < distances[k] ) 
+// 	  distances[k] = std::abs(iDistances[k]);
+//       }
+//     }
+//   }
+
+
+  // Compute PDE for distance function
+  
+#ifdef HAVE_TAUCS
+  linearSystemCSRTaucs<double> *lsys = new linearSystemCSRTaucs<double>;
+#else
+  linearSystemCSRGmm<double> *lsys = new linearSystemCSRGmm<double>;
+  lsys->setNoisy(1);
+  lsys->setGmres(1);
+  lsys->setPrec(5.e-8);
+#endif
+
+  dofManager<double> myAssembler(lsys);
+
+  SBoundingBox3d bbox;
+  for(unsigned int i = 0; i < entities.size(); i++){
+    if(entities[i]->dim() < maxDim) {
+      GEntity *ge = entities[i];
+      for(unsigned int j = 0; j < ge->mesh_vertices.size(); j++){
+	MVertex *v = ge->mesh_vertices[j];
+	myAssembler.fixVertex(v, 0, 1, 0.0);
+	bbox += SPoint3(v->x(),v->y(),v->z());
+      }
+    }
+  }
+
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      GEntity *ge = entities[ii];
+      for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i){
+	MElement *t = ge->getMeshElement(i);
+	for(int k = 0; k < t->getNumVertices(); k++){
+          myAssembler.numberVertex(t->getVertex(k), 0, 1);
+	}
+      }    
+    }  
+  }
+
+  double L = norm(SVector3(bbox.max(), bbox.min())); 
+  double mu = L/28;
+  printf("L=%g \n", L);
+
+  simpleFunction<double> DIFF(mu * mu), MONE(1.0);
+  distanceTerm distance(GModel::current(), 1, &DIFF, &MONE);
+  
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      GEntity *ge = entities[ii];
+      for(unsigned int i = 0; i < ge->getNumMeshElements(); ++i){
+	SElement se(ge->getMeshElement(i));
+	distance.addToMatrix(myAssembler, &se);
+      }
+      groupOfElements g((GFace*)ge);
+      distance.addToRightHandSide(myAssembler, g);
+    }
+  }
+
+  Msg::Info("Distance Computation: Assembly done");
+  lsys->systemSolve();
+  Msg::Info("Distance Computation: System solved");
+  
+  for(std::map<MVertex*,double >::iterator itv = distance_map2.begin(); 
+      itv !=distance_map2.end() ; ++itv){
+    MVertex *v = itv->first;
+    double value = std::min(0.9999, myAssembler.getDofValue(v, 0, 1));
+    double dist = -mu * log(1. - value);
+    itv->second = dist;
+  }
+
+  lsys->clear();
+  
+  //Writing pos files
+
+  Msg::Info("Writing distance-GEOM.pos");
+  FILE * f2 = fopen("distance-GEOM.pos","w");
+  fprintf(f2,"View \"distance GEOM\"{\n");
+  int j = 0;
+  for(std::vector<double>::iterator it = distances.begin(); it != distances.end(); it++){
+    fprintf(f2,"SP(%g,%g,%g){%g};\n", pts[j].x(), pts[j].y(), pts[j].z(), *it);
+    j++;
+  }
+  fprintf(f2,"};\n");
+  fclose(f2);
+
+  Msg::Info("Writing distance-bgm.pos");
+  FILE * f3 = fopen("distance-bgm.pos","w");
+  fprintf(f3,"View \"distance\"{\n");
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      for(unsigned int i = 0; i < entities[ii]->getNumMeshElements(); i++){ 
+	MElement *e = entities[ii]->getMeshElement(i);
+	if (maxDim == 3) fprintf(f3,"SS(");
+	else if (maxDim == 2) fprintf(f3,"ST(");
+	std::vector<double> dist;
+	for(int j = 0; j < e->getNumVertices(); j++) {
+	  MVertex *v =  e->getVertex(j);
+	  if(j) fprintf(f3,",%g,%g,%g",v->x(),v->y(), v->z());
+	  else fprintf(f3,"%g,%g,%g", v->x(),v->y(), v->z());
+	  std::map<MVertex*, double*>::iterator it = distance_map.find(v);
+	  dist.push_back(*(it->second));
+	}
+	fprintf(f3,"){");
+	for (unsigned int i = 0; i < dist.size(); i++){
+	  if (i) fprintf(f3,",%g", dist[i]);
+	  else fprintf(f3,"%g", dist[i]);
+	}   
+	fprintf(f3,"};\n");
+      }
+    }
+  }
+  fprintf(f3,"};\n");
+  fclose(f3);
+
+  Msg::Info("Writing distance-bgm2.pos");
+  FILE * f4 = fopen("distance-bgm2.pos","w");
+  fprintf(f4,"View \"distance\"{\n");
+  for(unsigned int ii = 0; ii < entities.size(); ii++){
+    if(entities[ii]->dim() == maxDim) {
+      for(unsigned int i = 0; i < entities[ii]->getNumMeshElements(); i++){ 
+	MElement *e = entities[ii]->getMeshElement(i);
+	if (maxDim == 3) fprintf(f4,"SS(");
+	else if (maxDim == 2) fprintf(f4,"ST(");
+	std::vector<double> dist;
+	for(int j = 0; j < e->getNumVertices(); j++) {
+	  MVertex *v =  e->getVertex(j);
+	  if(j) fprintf(f4,",%g,%g,%g",v->x(),v->y(), v->z());
+	  else fprintf(f4,"%g,%g,%g", v->x(),v->y(), v->z());
+	  std::map<MVertex*, double>::iterator it = distance_map2.find(v);
+	  dist.push_back(it->second);
+	}
+	fprintf(f4,"){");
+	for (unsigned int i = 0; i < dist.size(); i++){
+	  if (i) fprintf(f4,",%g", dist[i]);
+	  else fprintf(f4,"%g", dist[i]);
+	}   
+	fprintf(f4,"};\n");
+      }
+    }
+  }
+  fprintf(f4,"};\n");
+  fclose(f4);
+
+// #if defined(HAVE_ANN)
+//   Msg::Info("Computing Distance function to the boundaries with ANN");
+//   std::map<MVertex*,double > distance; 
+
+//  // add all points from boundaries into kdtree
+//   ANNpointArray kdnodes = annAllocPts(numnodes, 4);
+//   k = 0;
+//   for(unsigned int i = 0; i < entities.size()-1; i++)
+//     for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++){
+//       MVertex *v =  entities[i]->mesh_vertices[j];
+//       distance.insert(std::make_pair(v, 0.0));
+//       kdnodes[k][0] = v->x();
+//       kdnodes[k][1] = v->y();
+//       kdnodes[k][2] = v->z();
+//       k++;
+//     }  
+//   ANNkd_tree *kdtree = new ANNkd_tree(kdnodes, numnodes, 3);
+
+//   // compute the distances with the kdtree
+//   ANNidxArray index = new ANNidx[1];
+//   ANNdistArray dist = new ANNdist[1];
+//   GEntity* ga = entities[entities.size()-1];
+//   for(unsigned int j = 0; j < ga->mesh_vertices.size(); j++){
+//     MVertex *v = ga->mesh_vertices[j];
+//     double xyz[3] = {v->x(), v->y(), v->z()};
+//     kdtree->annkSearch(xyz, 1, index, dist);
+//     double d = sqrt(dist[0]);
+//     distance.insert(std::make_pair(v, d));
+//   }
+//   delete [] index;
+//   delete [] dist;
+//   delete kdtree;
+//   annDeallocPts(kdnodes);
+
+//   //write distance in msh file
+//   Msg::Info("Writing distance-ANN.pos");
+//   FILE * f = fopen("distance-ANN.pos","w");
+//   fprintf(f,"View \"distance ANN\"{\n");
+//   for(std::map<MVertex*, double>::iterator it = distance.begin(); it != distance.end(); it++) {
+//     fprintf(f,"SP(%g,%g,%g){%g};\n",
+// 	    it->first->x(), it->first->y(), it->first->z(),
+// 	    it->second);     
+//   }
+//   fprintf(f,"};\n");
+//   fclose(f);
+
+// #endif
+
+//   Msg::Info("Writing distance-bgm.pos");
+//   FILE * f2 = fopen("distance-bgm.pos","w");
+//   fprintf(f2,"View \"distance\"{\n");
+//   GEntity* ge = entities[entities.size()-1];
+//   for(unsigned int i = 0; i < ge->getNumMeshElements(); i++){ 
+//     MElement *e = ge->getMeshElement(i);
+//     fprintf(f2,"ST(");//TO DO CHANGE this
+//     std::vector<double> dist;
+//     for(int j = 0; j < e->getNumVertices(); j++) {
+//       MVertex *v =  e->getVertex(j);
+//       if(j) fprintf(f2,",%g,%g,%g",v->x(),v->y(), v->z());
+//       else fprintf(f2,"%g,%g,%g", v->x(),v->y(), v->z());
+//       std::map<MVertex*, double>::iterator it = distance.find(v);
+//       dist.push_back(it->second);
+//     }
+//     fprintf(f2,"){");
+//     for (int i=0; i<dist.size(); i++){
+//       if (i) fprintf(f2,",%g", dist[i]);
+//       else fprintf(f2,"%g", dist[i]);
+//     }   
+//     fprintf(f2,"};\n");
+//   }
+//   fprintf(f2,"};\n");
+//   fclose(f2);
+
+  return 0;
+}
diff --git a/Plugin/Distance.h b/Plugin/Distance.h
new file mode 100644
index 0000000000..35cd24d1d9
--- /dev/null
+++ b/Plugin/Distance.h
@@ -0,0 +1,33 @@
+// Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+//
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
+
+#ifndef _DISTANCE_H_
+#define _DISTANCE_H_
+
+#include <string>
+#include "Plugin.h"
+
+extern "C"
+{
+  GMSH_Plugin *GMSH_RegisterDistancePlugin();
+}
+
+class GMSH_DistancePlugin : public GMSH_PostPlugin
+{
+ public:
+  GMSH_DistancePlugin(){}
+  std::string getName() const { return "Distance"; }
+  std::string getShortHelp() const
+  {
+    return "Compute distance to boundaries";
+  }
+  std::string getHelp() const;
+  std::string getAuthor() const { return "E. Marchandise"; }
+  PView *execute(PView *);
+};
+
+#endif
diff --git a/Plugin/Plugin.h b/Plugin/Plugin.h
index 455c1e204f..7ccf9d7339 100644
--- a/Plugin/Plugin.h
+++ b/Plugin/Plugin.h
@@ -80,6 +80,8 @@ class GMSH_PostPlugin : public GMSH_Plugin
 {
  public:
   inline GMSH_PLUGIN_TYPE getType() const { return GMSH_Plugin::GMSH_POST_PLUGIN; }
+  virtual int getNbOptions() const { return 0; }
+  virtual StringXNumber *getOption(int iopt) { return 0; };
   virtual int getNbOptionsStr() const { return 0; }
   virtual StringXString *getOptionStr(int iopt) { return NULL; }
   // run the plugin
@@ -107,10 +109,10 @@ class GMSH_PostPlugin : public GMSH_Plugin
 class GMSH_SolverPlugin : public GMSH_Plugin
 {
  public:
-  virtual int getNbOptionsStr() const { return 0; }
-  virtual StringXString *getOptionStr(int iopt) { return 0; }
   virtual int getNbOptions() const { return 0; }
   virtual StringXNumber *getOption(int iopt) { return 0; };
+  virtual int getNbOptionsStr() const { return 0; }
+  virtual StringXString *getOptionStr(int iopt) { return 0; }
   inline GMSH_PLUGIN_TYPE getType() const { return GMSH_Plugin::GMSH_SOLVER_PLUGIN; }
   virtual void run() {} // do nothing
   // popup dialog box
diff --git a/Plugin/PluginManager.cpp b/Plugin/PluginManager.cpp
index 17c2e423cd..2848acc40a 100644
--- a/Plugin/PluginManager.cpp
+++ b/Plugin/PluginManager.cpp
@@ -43,6 +43,7 @@
 #include "Probe.h"
 #include "GSHHS.h"
 #include "HomologyComputation.h"
+#include "Distance.h"
 
 // for testing purposes only :-)
 #undef HAVE_DLOPEN
@@ -214,6 +215,8 @@ void PluginManager::registerDefaultPlugins()
     allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
                       ("Homology", GMSH_RegisterHomologyComputationPlugin()));
 #endif
+    allPlugins.insert(std::pair<std::string, GMSH_Plugin*>
+                      ("Distance", GMSH_RegisterDistancePlugin()));
   }
 
 #if defined(HAVE_FLTK)
-- 
GitLab