diff --git a/Geo/GEdgeLoop.cpp b/Geo/GEdgeLoop.cpp
index a6a0498312de1560caf1d11b31b2758cd59aa685..096ecef238410b86bfe9ab28ac798f6afa500a82 100644
--- a/Geo/GEdgeLoop.cpp
+++ b/Geo/GEdgeLoop.cpp
@@ -111,7 +111,7 @@ GEdgeLoop::GEdgeLoop(const std::list<GEdge*> &cwire)
     if(ges.getSign() == 0){ // oops
       Msg::Error("Something wrong in edge loop of size=%d, no sign !", wire.size());
       for (std::list<GEdge* >::iterator it = wire.begin(); it != wire.end(); it++){
-	printf("GEdge=%d begin=%g end =%d \n", (*it)->tag(), (*it)->getBeginVertex()->tag(), (*it)->getEndVertex()->tag()  );
+	printf("GEdge=%d begin=%d end =%d \n", (*it)->tag(), (*it)->getBeginVertex()->tag(), (*it)->getEndVertex()->tag()  );
       }
       break;
     }
diff --git a/Geo/GFace.cpp b/Geo/GFace.cpp
index bd895b65bad6d027214d870f8524af710b771eae..c53b3f4ce755602087c7323b887ed1df726489a4 100644
--- a/Geo/GFace.cpp
+++ b/Geo/GFace.cpp
@@ -854,8 +854,11 @@ GPoint GFace::closestPoint(const SPoint3 & queryPoint, const double initialGuess
 
 bool GFace::containsParam(const SPoint2 &pt) const
 {
+  
   Range<double> uu = parBounds(0);
   Range<double> vv = parBounds(1);
+  //printf("p =%g %g uu.low=%g uu.high=%g vv.low=%g vv.high=%g\n", pt.x(), pt.y(), uu.low(), uu.high(), vv.low(), vv.high());
+
   if((pt.x() >= uu.low() && pt.x() <= uu.high()) &&
      (pt.y() >= vv.low() && pt.y() <= vv.high()))
     return true;
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index 12f4ea05c9f6b4e4237dd7af113ff44cc650e9b1..72a71cba2a2f4e753b7ce2855c07660fe8e9ef3a 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -30,6 +30,8 @@
 #include "qualityMeasures.h"
 #include "Field.h"
 #include "OS.h"
+#include "Octree.h"
+#include "MElementOctree.h"
 #include "HighOrder.h"
 #include "meshGEdge.h"
 #include "meshPartitionOptions.h"
@@ -400,42 +402,9 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
     if (isMeshed) return true;
   }
 
-  // build face normal
-   std::list<GEdge*>::iterator ite = edges.begin();
-   std::list<int>::iterator itd = dir.begin();
-  // SVector3 tan1, tan2;
-  // for (int i=0; i<2; i++){
-  //   MVertex *v1 = (*ite)->lines[0]->getVertex(0);
-  //   MVertex *v2 = (*ite)->lines[0]->getVertex(1);
-  //   SPoint2 p1, p2;
-  //   if (*itd > 0.0){
-  //     //printf("v1=%g %g v2=%g %g \n", v1->x(), v1->y(), v2->x(), v2->y());
-  //     reparamMeshVertexOnFace(v1, gf, p1);
-  //     reparamMeshVertexOnFace(v2, gf, p2);
-  //     //printf("orient OK p1=%g %g p2=%g %g \n", p1.x(), p1.y(), p2.x(), p2.y());
-  //   }
-  //   else{
-  //     //printf("v1=%g %g v2=%g %g \n", v1->x(), v1->y(), v2->x(), v2->y());
-  //     reparamMeshVertexOnFace(v2, gf, p1);
-  //     reparamMeshVertexOnFace(v1, gf, p2);
-  //     //printf("orient -1 p1=%g %g p2=%g %g \n", p1.x(), p1.y(), p2.x(), p2.y());
-  //   }
-  //   //printf("edge=%d tan=%g %g \n", (*ite)->tag(), p2.x()-p1.x(),p2.y()-p1.y()); 
-  //   if (i==0) tan1 = SVector3(p2.x()-p1.x(),p2.y()-p1.y(),0.0);
-  //   else tan2 = SVector3(p2.x()-p1.x(),p2.y()-p1.y(),0.0);
-  //   ite++; itd++;
-  // }
-  // tan1.normalize(); tan2.normalize();
-  // SVector3 next = crossprod(tan1,tan2);
-  // next.normalize();
-  // printf("next =%g %g %g \n", next.x(), next.y(), next.z());
-  SVector3 next(0., 0., 1.0); 
-
   // build a set with all points of the boundaries
   std::set<MVertex*> all_vertices;
-  std::map<SPoint2, SVector3> pt2Normal;
-  ite = edges.begin();
-  itd = dir.begin();
+  std::list<GEdge*>::iterator ite = edges.begin();
   while(ite != edges.end()){
     if((*ite)->isSeam(gf)) return false;
     if(!(*ite)->isMeshDegenerated()){
@@ -444,40 +413,11 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
 	MVertex *v2 = (*ite)->lines[i]->getVertex(1);
         all_vertices.insert(v1);
         all_vertices.insert(v2);
-	
-	SPoint2 p1, p2;
-	if (*itd > 0.0){
-	  reparamMeshVertexOnFace(v1, gf, p1);
-	  reparamMeshVertexOnFace(v2, gf, p2);
-	}
-	else{
-	  reparamMeshVertexOnFace(v2, gf, p1);
-	  reparamMeshVertexOnFace(v1, gf, p2);
-	}
-	SVector3 tan(p2.x()-p1.x(),p2.y()-p1.y(),0.0);
-	tan.normalize();
-	SVector3 ne = crossprod(tan, next); 
-	ne.normalize();
-	std::map<SPoint2, SVector3>::iterator it = pt2Normal.find(p1);
-	if (it == pt2Normal.end())
-	  pt2Normal.insert(std::make_pair(p1,ne));
-	else{
-	  SVector3 n1 =  it->second;
-	  it->second = n1+ne;
-	}
-	std::map<SPoint2, SVector3>::iterator it2 = pt2Normal.find(p2);
-	if (it2 == pt2Normal.end())
-	  pt2Normal.insert(std::make_pair(p2,ne));
-	else{
-	  SVector3 n1 =  it2->second;
-	  it2->second = n1+ne;
-	}
-
       }
     }
     else
       printf("edge %d degenerated mesh \n", (*ite)->tag());
-    ++ite;   ++itd;
+    ++ite;   
   }
 
   std::list<GEdge*> emb_edges = gf->embeddedEdges();
@@ -550,9 +490,8 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
   // use a divide & conquer type algorithm to create a triangulation.
   // We add to the triangulation a box with 4 points that encloses the
   // domain.
-  std::map<SPoint2, SVector3> pt2NormalNEW;
+  DocRecord doc(points.size() + 4);
   {
-    DocRecord doc(points.size() + 4);
     for(unsigned int i = 0; i < points.size(); i++){
       double XX = CTX::instance()->mesh.randFactor * LC2D * (double)rand() / 
         (double)RAND_MAX;
@@ -563,14 +502,6 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
       doc.points[i].data = points[i];
       doc.points[i].adjacent = NULL;
 
-      SPoint2 p(points[i]->u, points[i]->v);
-      SPoint2 pNEW(points[i]->u+XX, points[i]->v+YY);
-      std::map<SPoint2, SVector3>::iterator it = pt2Normal.find(p);
-      if (it != pt2Normal.end() ){
-	pt2NormalNEW.insert(std::make_pair(pNEW,it->second));
-      }
-      else
-	Msg::Error("no point found \n");
     }
     
     // increase the size of the bounding box
@@ -626,32 +557,23 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
     ite = edges.begin();
     while(ite != edges.end()){
       if(!(*ite)->isMeshDegenerated())
-        recoverEdge
-          (m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
+        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
       ++ite;
     }
     ite = emb_edges.begin();
     while(ite != emb_edges.end()){
       if(!(*ite)->isMeshDegenerated())
-        recoverEdge
-          (m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
+        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 1);
       ++ite;
     }
     
     Msg::Debug("Recovering %d mesh Edges", edgesToRecover.size());
-
-    if (Msg::GetVerbosity() == 10){
-      doc.Voronoi();
-      doc.makePosView("voronoi.pos", gf);
-      doc.printMedialAxis(pt2NormalNEW, "skeleton.pos", gf);
-    }
-    
+   
     // effectively recover the medge
     ite = edges.begin();
     while(ite != edges.end()){
       if(!(*ite)->isMeshDegenerated()){
-        recoverEdge
-          (m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2);
+        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2);
       }
       ++ite;
     }
@@ -733,8 +655,7 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
     ite = emb_edges.begin();
     while(ite != emb_edges.end()){
       if(!(*ite)->isMeshDegenerated())
-        recoverEdge
-          (m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2);
+        recoverEdge(m, *ite, recoverMapInv, &edgesToRecover, &edgesNotRecovered, 2);
       ++ite;
     }
 
@@ -802,6 +723,38 @@ static bool meshGenerator(GFace *gf, int RECUR_ITER,
     outputScalarField(m->triangles, name, 1);
   }
 
+  {
+    std::list<BDS_Face*>::iterator itt = m->triangles.begin();
+    while (itt != m->triangles.end()){
+      BDS_Face *t = *itt;
+      if(!t->deleted){
+        BDS_Point *n[4];
+        t->getNodes(n);
+        MVertex *v1 = recoverMap[n[0]];
+        MVertex *v2 = recoverMap[n[1]];
+        MVertex *v3 = recoverMap[n[2]];
+        if(!n[3]){
+          if(v1 != v2 && v1 != v3 && v2 != v3)
+            gf->triangles.push_back(new MTriangle(v1, v2, v3));
+        }
+        else{
+          MVertex *v4 = recoverMap[n[3]];
+          gf->quadrangles.push_back(new MQuadrangle(v1, v2, v3, v4));
+        }
+      }
+      ++itt;
+    }
+  }
+  Octree * _octree = buildMElementOctree(gf->model());
+  if (Msg::GetVerbosity() == 10){
+    doc.Voronoi();
+    doc.makePosView("voronoi.pos", gf);
+    doc.printMedialAxis(_octree, "skeleton.pos", gf);
+  }
+  Octree_Delete(_octree);
+  gf->triangles.clear();
+  gf->quadrangles.clear();
+
   int nb_swap;
   //outputScalarField(m->triangles, "beforeswop.pos",1);
   Msg::Debug("Delaunizing the initial mesh");
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 7cfb9069bb12c61682a9f45741b3aa43b6618e2c..856cc49d954fb7b68e0d29e40c1bf573546db91a 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -273,7 +273,7 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
     char opts[128];
     buildTetgenStructure(gr, in, numberedV);
     if (Msg::GetVerbosity() == 10)
-      sprintf(opts, "peVv");
+      sprintf(opts, "peVvS0s");
     else
       sprintf(opts, "pe%c",  (Msg::GetVerbosity() < 3) ? 'Q': (Msg::GetVerbosity() > 6)? 'V': '\0');
     try{
@@ -326,7 +326,8 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
   gr->set(faces);
 
   // now do insertion of points
-  insertVerticesInRegion(gr);
+  //insertVerticesInRegion(gr);
+
 
 #endif
 }
diff --git a/Numeric/DivideAndConquer.cpp b/Numeric/DivideAndConquer.cpp
index b313a24d5afe742ca249aa9f6a4fe9a11977eeba..8fbccdf9ff2d4f31957520d6cfb8f586439a9dcc 100644
--- a/Numeric/DivideAndConquer.cpp
+++ b/Numeric/DivideAndConquer.cpp
@@ -576,7 +576,7 @@ void DocRecord::makePosView(std::string fileName, GFace *gf)
       double pc[2] = {(double)points[i].where.h, (double)points[i].where.v};
       if (!onHull(i)){
 	GPoint p0(pc[0], pc[1], 0.0);
-	if (gf) p0 = gf->point(pc[0], pc[1]);
+	//if (gf) p0 = gf->point(pc[0], pc[1]);
         fprintf(f,"SP(%g,%g,%g)  {%g};\n",p0.x(),p0.y(),p0.z(),(double)i);
         voronoiCell (i,pts);
         for (unsigned int j = 0; j < pts.size(); j++){
@@ -584,10 +584,10 @@ void DocRecord::makePosView(std::string fileName, GFace *gf)
 	  SPoint2 pp2 = pts[(j+1)%pts.size()];
 	  GPoint p1(pp1.x(), pp1.y(), 0.0);
 	  GPoint p2(pp2.x(), pp2.y(), 0.0);
-	  if (gf) {
-	     p1 = gf->point(p1.x(), p1.y());
-	     p2 = gf->point(p2.x(), p2.y());
-	  }
+	  // if (gf) {
+	  //    p1 = gf->point(p1.x(), p1.y());
+	  //    p2 = gf->point(p2.x(), p2.y());
+	  // }
           fprintf(f,"SL(%g,%g,%g,%g,%g,%g)  {%g,%g};\n",
                   p1.x(),p1.y(),p1.z(),p2.x(),p2.y(),p2.z(),
                   (double)i,(double)i);
@@ -602,8 +602,7 @@ void DocRecord::makePosView(std::string fileName, GFace *gf)
   fclose(f);
 }
 
-void DocRecord::printMedialAxis(std::map<SPoint2, SVector3> &pt2Normal, 
-				std::string fileName, GFace *gf)
+void DocRecord::printMedialAxis(Octree *_octree, std::string fileName, GFace *gf)
 {
   
   FILE *f = fopen(fileName.c_str(),"w");
@@ -613,10 +612,6 @@ void DocRecord::printMedialAxis(std::map<SPoint2, SVector3> &pt2Normal,
       std::vector<SPoint2> pts;
       SPoint2 pc((double)points[i].where.h, (double)points[i].where.v);
       if (!onHull(i)){
-       	std::map<SPoint2, SVector3>::const_iterator it = pt2Normal.find(pc);
-	if (it == pt2Normal.end()) printf("pt not found \n");
-	SVector3 n = it->second;
-	//fprintf(f,"VP(%g,%g,%g)  {%g,%g,%g};\n",pc.x(),pc.y(), 0.0, n.x(), n.y(), n.z());
 	GPoint p0(pc[0], pc[1], 0.0);
 	if (gf) p0 = gf->point(pc[0], pc[1]);
         fprintf(f,"SP(%g,%g,%g)  {%g};\n",p0.x(),p0.y(),p0.z(),(double)i);
@@ -632,12 +627,16 @@ void DocRecord::printMedialAxis(std::map<SPoint2, SVector3> &pt2Normal,
 	     p1 = gf->point(p1.x(), p1.y());
 	     p2 = gf->point(p2.x(), p2.y());
 	  }
-	  if (dot(v1,n) > 0.0  && dot(v2,n) > 0.0){
+	  double P1[3] = {p1.x(), p1.y(), p1.z()};
+	  double P2[3] = {p2.x(), p2.y(), p2.z()};
+	  MElement *m1 = (MElement*)Octree_Search(P1, _octree);
+	  MElement *m2 = (MElement*)Octree_Search(P2, _octree);
+	  if (m1 && m2){
 	    fprintf(f,"SL(%g,%g,%g,%g,%g,%g)  {%g,%g};\n",
 		    p1.x(),p1.y(),p1.z(),
 		    p2.x(),p2.y(),p2.z(),
 		    (double)i,(double)i);
-	  }
+	 }
         }
        }
     }
diff --git a/Numeric/DivideAndConquer.h b/Numeric/DivideAndConquer.h
index 87eeee10fab48a1d5ae1295a3641d6f259fd6dd0..843b2a0e22ef424e2265c0e49bb889121d623f32 100644
--- a/Numeric/DivideAndConquer.h
+++ b/Numeric/DivideAndConquer.h
@@ -10,6 +10,7 @@
 #include "fullMatrix.h"
 #include "SPoint2.h"
 #include "simpleFunction.h"
+#include "Octree.h"
 
 class binding;
 class GFace;
@@ -95,7 +96,7 @@ class DocRecord{
   int hullSize() {return _hullSize;}
   int onHull(PointNumero i) { return std::binary_search(_hull, _hull+_hullSize, i); }
   void makePosView(std::string, GFace *gf=NULL);
-  void printMedialAxis(std::map<SPoint2, SVector3> &pt2Normal, std::string, GFace *gf=NULL);
+  void printMedialAxis(Octree *_octree, std::string, GFace *gf=NULL);
   double Lloyd (int);
   void voronoiCell (PointNumero pt, std::vector<SPoint2> &pts) const;
   static void registerBindings(binding *b);
diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp
index d38bd96e3781fb526266271136958fc9da8445ad..73d61795855e0cf268c6e69adeefb14671f872e1 100644
--- a/Numeric/Numeric.cpp
+++ b/Numeric/Numeric.cpp
@@ -901,46 +901,258 @@ void signedDistancesPointsTriangle(std::vector<double>&distances,
   }                                        
 }
 
-void signedDistancesPointsLine (std::vector<double>&distances,
-                                std::vector<SPoint3>&closePts,
-                                const std::vector<SPoint3> &pts,
-                                const SPoint3 &p1,
-                                const SPoint3 &p2){
-
+void signedDistancePointLine(const SPoint3 &p1,const SPoint3 &p2,const SPoint3 &p, double &d, SPoint3 &closePt){
   SVector3 t1 = p2 - p1;
   const double n2t1 = dot(t1, t1);
+  SVector3 pp1 = p - p1;
+  const double t12 = dot(pp1, t1) / n2t1;
+  d = 1.e10;
+  bool found = false;
+  if (t12 >= 0 && t12 <= 1.){
+    d =  std::min(fabs(d), p.distance(p1 + (p2 - p1) * t12)); 
+    closePt = p1 + (p2 - p1) * t12;
+    found = true;
+  }
+  if (p.distance(p1) < fabs(d)){
+    closePt = p1;
+    d =  std::min(fabs(d), p.distance(p1));
+  }
+  if (p.distance(p2) < fabs(d)){
+    closePt = p2;
+    d =  std::min(fabs(d), p.distance(p2));
+  }
+}
+
+void signedDistancesPointsLine (std::vector<double>&distances,
+				std::vector<SPoint3>&closePts,
+				const std::vector<SPoint3> &pts,
+				const SPoint3 &p1,
+				const SPoint3 &p2){
 
-  const unsigned pts_size=pts.size();
   distances.clear();
-  distances.resize(pts_size);
+  distances.resize(pts.size());
   closePts.clear();
-  closePts.resize(pts_size);
+  closePts.resize(pts.size());
 
   double d;
-  for (unsigned int i = 0; i <pts_size;++i){
-    const SPoint3 &p = pts[i];
-    SVector3 pp1 = p - p1;
-    const double t12 = dot(pp1, t1) / n2t1;
-    d = 1.e10;
-    bool found = false;
+  for (unsigned int i = 0; i < pts.size();i++){
     SPoint3 closePt;
-    if (t12 >= 0 && t12 <= 1.){
-      d =  std::min(fabs(d), p.distance(p1 + (p2 - p1) * t12));  
-      closePt = p1 + (p2 - p1) * t12;
-      found = true;
-    }
+    const SPoint3 &p = pts[i];
+    signedDistancePointLine(p1,p2,p,d,closePt);
+    distances[i] = d;
+    closePts[i] = closePt;
+  }
+}
+
+void changeReferential(const int direction,const SPoint3 &p,const SPoint3 &closePt,const SPoint3 &p1,const SPoint3 &p2,double* xp,double* yp,double* otherp,double* x,double* y,double* other){
+  if (direction==1){
+    const SPoint3 &d1=SPoint3(1.0,0.0,0.0);
+    const SPoint3 &d=SPoint3(p2.x()-p1.x(),p2.y()-p1.y(),p2.z()-p1.z());
+    double norm=sqrt( d.x()*d.x()+d.y()*d.y()+d.z()*d.z() );
+    const SPoint3 &dn=SPoint3(d.x()/norm,d.y()/norm,d.z()/norm);
+    const SPoint3 &d3=SPoint3(d1.y()*dn.z()-d1.z()*dn.y(),d1.z()*dn.x()-d1.x()*dn.z(),d1.x()*dn.y()-d1.y()*dn.x());
+    norm=sqrt( d3.x()*d3.x()+d3.y()*d3.y()+d3.z()*d3.z() );
+    const SPoint3 &d3n=SPoint3(d3.x()/norm,d3.y()/norm,d3.z()/norm);
+    const SPoint3 &d2=SPoint3(d3n.y()*d1.z()-d3n.z()*d1.y(),d3n.z()*d1.x()-d3n.x()*d1.z(),d3n.x()*d1.y()-d3n.y()*d1.x());
+    norm=sqrt( d2.x()*d2.x()+d2.y()*d2.y()+d2.z()*d2.z() );
+    const SPoint3 &d2n=SPoint3(d2.x()/norm,d2.y()/norm,d2.z()/norm);
+    *xp=p.x()*d1.x()+p.y()*d1.y()+p.z()*d1.z();
+    *yp=p.x()*d3n.x()+p.y()*d3n.y()+p.z()*d3n.z();
+    *otherp=p.x()*d2n.x()+p.y()*d2n.y()+p.z()*d2n.z();
+    *x=closePt.x()*d1.x()+closePt.y()*d1.y()+closePt.z()*d1.z();
+    *y=closePt.x()*d3n.x()+closePt.y()*d3n.y()+closePt.z()*d3n.z();
+    *other=closePt.x()*d2n.x()+closePt.y()*d2n.y()+closePt.z()*d2n.z();
+  }else{
+    const SPoint3 &d2=SPoint3(0.0,1.0,0.0);
+    const SPoint3 &d=SPoint3(p2.x()-p1.x(),p2.y()-p1.y(),p2.z()-p1.z());
+    double norm=sqrt( d.x()*d.x()+d.y()*d.y()+d.z()*d.z() );
+    const SPoint3 &dn=SPoint3(d.x()/norm,d.y()/norm,d.z()/norm);
+    const SPoint3 &d3=SPoint3(dn.y()*d2.z()-dn.z()*d2.y(),dn.z()*d2.x()-dn.x()*d2.z(),dn.x()*d2.y()-dn.y()*d2.x());
+    norm=sqrt( d3.x()*d3.x()+d3.y()*d3.y()+d3.z()*d3.z() );
+    const SPoint3 &d3n=SPoint3(d3.x()/norm,d3.y()/norm,d3.z()/norm);
+    const SPoint3 &d1=SPoint3(d2.y()*d3n.z()-d2.z()*d3n.y(),d2.z()*d3n.x()-d2.x()*d3n.z(),d2.x()*d3n.y()-d2.y()*d3n.x());
+    norm=sqrt( d1.x()*d1.x()+d1.y()*d1.y()+d1.z()*d1.z() );
+    const SPoint3 &d1n=SPoint3(d1.x()/norm,d1.y()/norm,d1.z()/norm);
+    *xp=p.x()*d2.x()+p.y()*d2.y()+p.z()*d2.z();
+    *yp=p.x()*d3n.x()+p.y()*d3n.y()+p.z()*d3n.z();
+    *otherp=p.x()*d1n.x()+p.y()*d1n.y()+p.z()*d1n.z();
+    *x=closePt.x()*d2.x()+closePt.y()*d2.y()+closePt.z()*d2.z();
+    *y=closePt.x()*d3n.x()+closePt.y()*d3n.y()+closePt.z()*d3n.z();
+    *other=closePt.x()*d1n.x()+closePt.y()*d1n.y()+closePt.z()*d1n.z();
+  }
+}
 
-    if (p.distance(p1) < fabs(d)){
-      closePt = p1;
-      d =  std::min(fabs(d), p.distance(p1));
+int computeDistanceRatio(const double &y, const double &yp,const double &x,const double &xp, double *distance, const double &r1, const double &r2){
+  double b;
+  double a;
+  if (y==yp){
+    b=-y;
+    a=0.0;
+  }else{
+    if (x==xp){
+      b=-x;
+      a==0.0;
+    }else{
+      b=(xp*y-x*yp)/(yp-y);
+      if (yp==0.0){
+        a=-(b+x)/y;
+      }else{
+        a=-(b+xp)/yp;
+      }
+    }
+  }
+  double ae;
+  double be;
+  double ce;
+  double da=r1*r1;
+  double db=r2*r2;
+  if (y==yp){
+    ae=1.0/da;
+    be=-(2*x)/da;
+    ce=(x*x/da)-1.0;
+  }else{
+    if (x==xp){
+      ae = 1.0/db;
+      be = -(2.0*y)/db;
+      ce = (y*y/db)-1.0;
+    }else{
+      if (fabs(a)<0.00001){
+        ae = 1.0/db;
+        be = -(2.0*y)/db;
+        ce = (y*y/db)-1.0;
+      }else{
+        double a2=a*a;
+        ae=(1.0/da)+(1.0/(db*a2));
+        be=(2.0*y)/(db*a)+(2.0*b)/(a2*db)-((2.0*x)/da);
+        ce=(x*x)/da+(b*b)/(db*a2)+(2.0*b*y)/(a*db)+(y*y/db)-1.0;
+      }
+    }
+  }
+  double rho=be*be-4*ae*ce;
+  double x1,x2,y1,y2,propdist;
+  if (rho<0) {
+    return 1;
+  }else{
+    x1=-(be+sqrt(rho))/(2.0*ae);
+    x2=(-be+sqrt(rho))/(2.0*ae);
+    if (y==yp){
+      y1=-b;
+      y2=-b;
+    }else{
+      if (x==xp){
+	y1=x1;
+        y2=x2;
+	x1=-b;
+        x2=-b;
+      }else{
+        if (fabs(a)<0.00001){
+          y1=x1;
+          y2=x2;
+          x1=-b;
+          x2=-b;
+        }else{
+          y1=-(b+x1)/a;
+          y2=-(b+x2)/a;
+	}
+      }
     }
-    if (p.distance(p2) < fabs(d)){
-      closePt = p2;
-      d =  std::min(fabs(d), p.distance(p2));
+    if (x1==x2){
+      propdist=(y1-y)/(yp-y);
+      if(propdist<0.0){
+	propdist=(y2-y)/(yp-y);
+      }
+    }else{
+      if (xp!=x){
+        propdist=(x1-x)/(xp-x);
+	if (propdist<0.0){
+	  propdist=(x2-x)/(xp-x);
+	}
+      }else{
+	if (yp!=y){
+	  propdist=(y1-y)/(yp-y);
+	  if(propdist<0.0){
+	    propdist=(y2-y)/(yp-y);
+	  }
+	}else{
+	  propdist=0.01;
+	}
+      }
     }
+    *distance=propdist;
+    return 0;
+  }
+}
+
+void signedDistancesPointsEllipseLine (std::vector<double>&distances,
+				std::vector<double> &distancesE,
+				std::vector<int>&isInYarn,
+				std::vector<SPoint3>&closePts,
+				const std::vector<SPoint3> &pts,
+				const SPoint3 &p1,
+				const SPoint3 &p2){
+  
+  distances.clear();
+  distances.resize(pts.size());
+  distancesE.clear();
+  distancesE.resize(pts.size());
+  isInYarn.clear();
+  isInYarn.resize(pts.size());
+  closePts.clear();
+  closePts.resize(pts.size());
+  double d;
+  for (unsigned int i = 0; i < pts.size();i++){
+    SPoint3 closePt;
+    const SPoint3 &p = pts[i];
+    signedDistancePointLine(p1,p2,p,d,closePt);
     
     distances[i] = d;
     closePts[i] = closePt;
+    int direction;
+    double distancesMin;
+    if (!(p.x()==closePt.x() && p.y()==closePt.y() && p.z()==closePt.z())){
+      double xp,yp,x,y,otherp,other,propdist;
+      if (p1.x()==p2.x()){
+        direction=1;
+        if (fabs(closePt.x()-0.0)<0.00000001) isInYarn[i]=1;
+        if (fabs(closePt.x()-2.2)<0.00000001) isInYarn[i]=4;
+        if (fabs(closePt.x()-4.4)<0.00000001) isInYarn[i]=2;
+        if (fabs(closePt.x()-6.6)<0.00000001) isInYarn[i]=5;
+        if (fabs(closePt.x()-8.8)<0.00000001) isInYarn[i]=3;
+	if (fabs(closePt.x()-11.0)<0.00000001) isInYarn[i]=1;
+      }else{
+        if (p1.y()==p2.y()){
+          direction=2;
+	  if (fabs(closePt.y()-0.0)<0.00000001) isInYarn[i]=6;
+	  if (fabs(closePt.y()-2.2)<0.00000001) isInYarn[i]=7;
+	  if (fabs(closePt.y()-4.4)<0.00000001) isInYarn[i]=8;
+	  if (fabs(closePt.y()-6.6)<0.00000001) isInYarn[i]=9;
+	  if (fabs(closePt.y()-8.8)<0.00000001) isInYarn[i]=10;
+	  if (fabs(closePt.y()-11.0)<0.00000001) isInYarn[i]=6;
+        }else{
+	  printf("WTF %lf %lf\n",closePt.x(),closePt.y());
+        }
+      }
+      changeReferential(direction,p,closePt,p1,p2,&xp,&yp,&otherp,&x,&y,&other);
+      int result;
+      if (fabs(other-otherp)>0.01){
+	result=1;
+      }else{
+        result=computeDistanceRatio(y,yp,x,xp,&propdist,1.1,0.0875);
+      }
+      if (result==1){
+          distancesE[i] = 1.e10;
+          isInYarn[i]=0;
+      }else{
+        if (propdist<1.0){
+          isInYarn[i]=0;
+          distancesE[i]=(1.0/propdist)-1.0;
+        }else{
+	  distancesE[i]=(1.0-(1.0/propdist))/3.0;
+        }
+      }
+    }else{
+        isInYarn[i]=0;
+        distancesE[i]=1000000.0;
+    }
   }
-
 }
diff --git a/Numeric/Numeric.h b/Numeric/Numeric.h
index 7a5d38018eb5eea4bade98efc6f8274f4937c5c4..8748b0da5ef716d715fbaac5751059924d3c058a 100644
--- a/Numeric/Numeric.h
+++ b/Numeric/Numeric.h
@@ -90,9 +90,21 @@ void signedDistancesPointsTriangle(std::vector<double> &distances,
                                    const SPoint3 &p1,
                                    const SPoint3 &p2,
                                    const SPoint3 &p3);
-void signedDistancesPointsLine(std::vector<double> &distances,
-                               std::vector<SPoint3> &closePts,
-                               const std::vector<SPoint3> &pts,
-                               const SPoint3 &p1,
-                               const SPoint3 &p2);
+void signedDistancePointLine(const SPoint3 &p1,const SPoint3 &p2,const SPoint3 &p, double &distance, SPoint3 &closePt);
+void signedDistancesPointsLine (std::vector<double>&distances,
+                                std::vector<SPoint3>&closePts,
+                                const std::vector<SPoint3> &pts,
+                                const SPoint3 &p1,
+                                const SPoint3 &p2);
+
+void changeReferential(const int direction,const SPoint3 &p,const SPoint3 &closePt,const SPoint3 &p1,const SPoint3 &p2,double* xp,double* yp,double* otherp,double* x,double* y,double* other);
+int computeDistanceRatio(const double &y, const double &yp,const double &x,const double &xp, double *distance, const double &r1, const double &r2);
+
+void signedDistancesPointsEllipseLine (std::vector<double>&distances,
+                                std::vector<double>&distancesE,
+                                std::vector<int>&isInYarn,
+                                std::vector<SPoint3>&closePts,
+                                const std::vector<SPoint3> &pts,
+                                const SPoint3 &p1,
+                                const SPoint3 &p2);
 #endif
diff --git a/Plugin/Distance.cpp b/Plugin/Distance.cpp
index 9bc823c5787b9162696bef129a1b6ba46b3e8a43..e7a84a7732c8b3f54382283f66bf67581a924e61 100644
--- a/Plugin/Distance.cpp
+++ b/Plugin/Distance.cpp
@@ -24,12 +24,12 @@
 
 
 StringXNumber DistanceOptions_Number[] = {
-  {GMSH_FULLRC, "Point", NULL, 0.},
-  {GMSH_FULLRC, "Line", NULL, 0.},
-  {GMSH_FULLRC, "Surface", NULL, 0.},
+  {GMSH_FULLRC, "PhysPoint", NULL, 0.},
+  {GMSH_FULLRC, "PhysLine", NULL, 0.},
+  {GMSH_FULLRC, "PhysSurface", NULL, 0.},
   {GMSH_FULLRC, "Computation", NULL, -1},
-  {GMSH_FULLRC, "Min Scale", NULL, -1},
-  {GMSH_FULLRC, "Max Scale", NULL, -1},
+  {GMSH_FULLRC, "MinScale", NULL, -1},
+  {GMSH_FULLRC, "MaxScale", NULL, -1},
   {GMSH_FULLRC, "Orthogonal", NULL, -1}
 };
 
@@ -171,10 +171,23 @@ PView *GMSH_DistancePlugin::execute(PView *v)
     
   std::vector<GEntity*> _entities;
   GModel::current()->getEntities(_entities);
+  GEntity* ge = _entities[_entities.size()-1];
+  int integrationPointTetra[2];
+  if (type==-100){
+    integrationPointTetra[0]=1;
+    integrationPointTetra[1]=4;
+  }else{
+    integrationPointTetra[0]=0;
+    integrationPointTetra[1]=0;
+  }
 
-  int totNumNodes = 0;
-  for (unsigned int i = 0; i < _entities.size() ; i++)
-    totNumNodes += _entities[i]->mesh_vertices.size();
+  int numnodes = 0;
+  for(unsigned int i = 0; i < _entities.size()-1; i++)
+    numnodes += _entities[i]->mesh_vertices.size();
+  int totNodes=numnodes + _entities[_entities.size()-1]->mesh_vertices.size();
+  printf("%d\n",totNodes);
+  int order=ge->getMeshElement(0)->getPolynomialOrder();
+  int totNumNodes = totNodes+ge->getNumMeshElements()*integrationPointTetra[order-1];
 
   if (totNumNodes ==0) {
     Msg::Error("This plugin needs a mesh !");
@@ -192,7 +205,48 @@ PView *GMSH_DistancePlugin::execute(PView *v)
   distances.reserve(totNumNodes);
   pt2Vertex.reserve(totNumNodes);
 
-  for (int i = 0; i < totNumNodes; i++) distances.push_back(1.e22);
+    std::map<MVertex*,double> _distanceE_map;
+    std::map<MVertex*,int> _isInYarn_map;
+    std::vector<int> index;
+    std::vector<double> distancesE;
+    std::vector<int> isInYarn;
+    std::vector<SPoint3> closePts;
+    std::vector<double> distances2;
+    std::vector<double> distancesE2;
+    std::vector<int> isInYarn2;
+    std::vector<SPoint3> closePts2;
+
+  if (type==-100){
+    index.clear();
+    distancesE.clear();
+    closePts.clear();
+    isInYarn.clear();
+    isInYarn.reserve(totNumNodes);
+    closePts.reserve(totNumNodes);
+    distancesE.reserve(totNumNodes);
+    index.reserve(totNumNodes);
+    distances2.clear();
+    distancesE2.clear();
+    closePts2.clear();
+    isInYarn2.clear();
+    distances2.reserve(totNumNodes);
+    isInYarn2.reserve(totNumNodes);
+    closePts2.reserve(totNumNodes);
+    distancesE2.reserve(totNumNodes);
+  }
+
+  for (int i = 0; i < totNumNodes; i++) {
+    distances.push_back(1.e22);
+    if (type==-100){
+      distancesE.push_back(1.e22);
+      isInYarn.push_back(0);
+      closePts.push_back(SPoint3(0.,0.,0.));
+      distances2.push_back(1.e22);
+      distancesE2.push_back(1.e22);
+      isInYarn2.push_back(0);
+      closePts2.push_back(SPoint3(0.,0.,0.));
+    }
+  }
 
   int k = 0;
   for(unsigned int i = 0; i < _entities.size(); i++){
@@ -202,11 +256,43 @@ PView *GMSH_DistancePlugin::execute(PView *v)
       MVertex *v = ge->mesh_vertices[j];
       pts.push_back(SPoint3(v->x(), v->y(),v->z()));
       _distance_map.insert(std::make_pair(v, 0.0));
+      if (type==-100){
+        index.push_back(v->getIndex());
+        _isInYarn_map.insert(std::make_pair(v, 0));
+        _distanceE_map.insert(std::make_pair(v, 0.0));
+      }
       pt2Vertex[k] = v;
       k++;
     }
   }
-  
+
+  if (type==-100){
+  double jac[3][3];
+  for (unsigned int i = 0; i < ge->getNumMeshElements(); i++){ 
+    MElement *e = ge->getMeshElement(i);
+    IntPt *ptsi;
+    int nptsi;
+    double uvw[4][3];
+    e->getIntegrationPoints(e->getPolynomialOrder(),&nptsi, &ptsi);
+    for(int j = 0; j < 4; j++) {
+      double xyz[3] = {e->getVertex(j)->x(),
+                       e->getVertex(j)->y(),
+                       e->getVertex(j)->z()};
+      e->xyz2uvw(xyz, uvw[j]);
+    }
+
+    for(int ip = 0; ip < nptsi; ip++){
+      const double u = ptsi[ip].pt[0];
+      const double v = ptsi[ip].pt[1];
+      const double w = ptsi[ip].pt[2];
+      const double weight = ptsi[ip].weight;
+      const double detJ = e->getJacobian(u, v, w, jac);
+      SPoint3 p; 
+      e->pnt(u, v, w, p);
+      pts.push_back(p);
+    }
+  }
+  }
   // Compute geometrical distance to mesh boundaries
   //------------------------------------------------------
   if (type < 0.0 ){
@@ -230,37 +316,155 @@ PView *GMSH_DistancePlugin::execute(PView *v)
 	for(unsigned int k = 0; k < g2->getNumMeshElements(); k++){ 
 	  std::vector<double> iDistances;
 	  std::vector<SPoint3> iClosePts;
+          std::vector<double> iDistancesE;
+          std::vector<int> iIsInYarn;
 	  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);
+	  if((e->getNumVertices() == 2 and order==1) or (e->getNumVertices() == 3 and order==2)){
+            if (type==-100){
+//              if ( !((p1.x()==p2.x()) & (p1.y()==p2.y()) & (p1.z()==p2.z())) ){
+                signedDistancesPointsEllipseLine(iDistances, iDistancesE, iIsInYarn, iClosePts, pts, p1,p2);
+//              }
+            }else{
+	      signedDistancesPointsLine(iDistances, iClosePts, pts, p1,p2);
+            }
 	  }
-	  else if(e->getNumVertices() == 3){
+	  else if(e->getNumVertices() == 3 and order==1){
 	    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]);
-	      MVertex *v = pt2Vertex[kk];
-	      _distance_map[v] = distances[kk];
+            if (type==-100){
+            if( !((p1.x()==p2.x()) & (p1.y()==p2.y()) & (p1.z()==p2.z()))){
+//              printf("%d %d %d %lf %lf %lf %lf\n",kk,isInYarn[kk],iIsInYarn[kk],distances[kk],iDistances[kk],distancesE[kk],iDistancesE[kk]);
+              if (iIsInYarn[kk]>0){
+	        if (isInYarn[kk]==0){
+                  distances[kk] = iDistances[kk];
+	          distancesE[kk]= iDistancesE[kk];
+                  isInYarn[kk] = iIsInYarn[kk];
+                  closePts[kk]= SPoint3(iClosePts[kk].x(),iClosePts[kk].y(),iClosePts[kk].z());
+	        }else{
+	          if (isInYarn[kk]!=iIsInYarn[kk]){
+	            if (isInYarn2[kk]==0){
+		      distances2[kk] = iDistances[kk];
+	              distancesE2[kk]= iDistancesE[kk];
+                      isInYarn2[kk] = iIsInYarn[kk];
+                      closePts2[kk]= SPoint3(iClosePts[kk].x(),iClosePts[kk].y(),iClosePts[kk].z());
+	            }else{
+		      if (isInYarn2[kk]==iIsInYarn[kk]){
+		        if (iDistancesE[kk] < distancesE2[kk]){
+		          distances2[kk] = iDistances[kk];
+		          distancesE2[kk]= iDistancesE[kk];
+                          closePts2[kk]= SPoint3(iClosePts[kk].x(),iClosePts[kk].y(),iClosePts[kk].z());
+		        }
+		      }
+	            }
+	          }else{
+	            if (iDistancesE[kk] < distancesE[kk]){ 
+	 	      distances[kk] = iDistances[kk];
+		      distancesE[kk]= iDistancesE[kk];
+		      closePts[kk]= SPoint3(iClosePts[kk].x(),iClosePts[kk].y(),iClosePts[kk].z());
+                    }
+	          }
+	        }
+	      }else{
+	        if (isInYarn[kk]==0){
+	           if (iDistancesE[kk] < distancesE[kk]){
+                      distances[kk] = iDistances[kk];
+                      distancesE[kk]= iDistancesE[kk];
+                      closePts[kk]= SPoint3(iClosePts[kk].x(),iClosePts[kk].y(),iClosePts[kk].z());
+                   }
+	        }
+	      }
+            }
+            }else{
+	      if (std::abs(iDistances[kk]) < distances[kk]){
+	        distances[kk] = std::abs(iDistances[kk]);
+	        MVertex *v = pt2Vertex[kk];
+	        _distance_map[v] = distances[kk];
+              }
 	    }
 	  }
 	}
       }
     }
+    if (type==-100){
+      for (unsigned int kk = 0; kk< pts.size(); kk++) {
+        if (isInYarn2[kk]>0){
+          if (distancesE2[kk]>distancesE[kk]){
+            distances[kk]=distances2[kk];
+	    distancesE[kk]=distancesE2[kk];
+	    isInYarn[kk]=isInYarn2[kk];
+	    closePts[kk]=closePts2[kk];
+          }
+        }
+        if (kk<totNodes){
+          MVertex *v = pt2Vertex[kk];
+	  _distance_map[v] = distancesE[kk];
+          _distanceE_map[v] = distances[kk];
+          _isInYarn_map[v] = isInYarn[kk];
+        }
+      }
+    }
     if (!existEntity){
       if (id_pt != 0) Msg::Error("The Physical Point does not exist !");
       if (id_line != 0) Msg::Error("The Physical Line does not exist !");
       if (id_face != 0) Msg::Error("The Physical Surface does not exist !");
       return view;
     }
+  printView(_entities, _distance_map);
+  if (type==-100){
+
+  Msg::Info("Writing integrationPointInYarn.pos");
+  FILE* f5 = fopen("integrationPointInYarn.pos","w");
+  FILE* f6 = fopen("integrationPointInYarn.bin","wb");
+  FILE* f7 = fopen("integrationPointInYarn.txt","w");
+  int j=0;
+  fprintf(f5,"View \"integrationPointInYarn\"{\n");
+  for (std::vector<int>::iterator it = isInYarn.begin(); it !=isInYarn.end(); it++) {
+     if (j>=totNodes){
+      int iPIY=*it;
+      fwrite(&iPIY,sizeof(int),1,f6);
+      fprintf(f7,"%d %lf %lf %lf\n",iPIY,pts[j].x(),  pts[j].y(),  pts[j].z());
+      fprintf(f5,"SP(%g,%g,%g){%d};\n",
+            pts[j].x(),  pts[j].y(),  pts[j].z(),
+            *it);
+    }
+    j++;
+  }
+  fclose(f6);
+  fclose(f7);
+  fprintf(f5,"};\n");
+  fclose(f5);
 
-    printView(_entities, _distance_map);
+  Msg::Info("Writing isInYarn.pos");
+  FILE * f4 = fopen("isInYarn.pos","w");
+  fprintf(f4,"View \"isInYarn\"{\n");
+  for(unsigned int i = 0; i < ge->getNumMeshElements(); i++){ 
+    MElement *e = ge->getMeshElement(i);
+    fprintf(f4,"SS(");
+    std::vector<int> inYarn;
+    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*, int>::iterator it = _isInYarn_map.find(v);
+      inYarn.push_back(it->second);
+    }
+    fprintf(f4,"){");
+    for (int i=0; i<inYarn.size(); i++){
+      if (i) fprintf(f4,",%d", inYarn[i]);
+      else fprintf(f4,"%d", inYarn[i]);
+    }
+    fprintf(f4,"};\n");
+  }
+  fprintf(f4,"};\n");
+  fclose(f4);
+  }
     
   }
   
@@ -359,12 +563,9 @@ PView *GMSH_DistancePlugin::execute(PView *v)
   //compute also orthogonal vector to distance field
   // A Uortho = -C DIST 
   //------------------------------------------------
-  if (ortho > 0 && _maxDim != 2){
-     Msg::Error("The orthogonal field is only implemented for a 2D distance field !");
-  }
-  else if (ortho > 0 && _maxDim == 2){
+  if (ortho > 0){
 #if defined(HAVE_SOLVER)
-
+  
 #ifdef HAVE_TAUCS
   linearSystemCSRTaucs<double> *lsys2 = new linearSystemCSRTaucs<double>;
 #else
@@ -477,4 +678,3 @@ PView *GMSH_DistancePlugin::execute(PView *v)
   
   return view;
 }
-