diff --git a/Mesh/HighOrder.cpp b/Mesh/HighOrder.cpp
index ab6ad3ff14128cff78ba48df59ef9756ea8b5dc3..4b49f6d9b65564848dda13b6865d357c5eac1f31 100644
--- a/Mesh/HighOrder.cpp
+++ b/Mesh/HighOrder.cpp
@@ -1326,10 +1326,13 @@ void SetOrderN(GModel *m, int order, bool linear, bool incomplete)
   else Msg::StatusBar(2, true, "Meshing order %d, curvilinear OFF...", order);
   double t1 = Cpu();
 
+  
 
   // first, make sure to remove any existsing second order vertices/elements
   SetOrder1(m);    
 
+  //  m->writeMSH("BEFORE.msh");
+
   highOrderSmoother *displ2D = 0; 
   highOrderSmoother *displ3D = 0; 
   if(CTX::instance()->mesh.smoothInternalEdges){
@@ -1357,6 +1360,9 @@ void SetOrderN(GModel *m, int order, bool linear, bool incomplete)
   std::vector<MElement*> bad;
   double worst;
   //  printJacobians(m, "smoothness_b.pos");
+
+  //  m->writeMSH("RAW.msh");
+
   if (displ2D){
     checkHighOrderTriangles("Before optimization", m, bad, worst);
     for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it)
@@ -1384,10 +1390,14 @@ void SetOrderN(GModel *m, int order, bool linear, bool incomplete)
   
   double t2 = Cpu();
 
+  //  m->writeMSH("SMOOTHED.msh");
+
   if (!linear){
     hot.ensureMinimumDistorsion(0.1);
     checkHighOrderTriangles("final mesh", m, bad, worst);
   }
 
+  //  m->writeMSH("CORRECTED.msh");
+
   Msg::StatusBar(2, true, "Done meshing order %d (%g s)", order, t2 - t1);
 }
diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp
index e4bed315d482f46779fc01566c1a8891dac5e425..b17f53269c6ebb1bc7c2166ee4ecab5a896a1052 100644
--- a/Mesh/qualityMeasures.cpp
+++ b/Mesh/qualityMeasures.cpp
@@ -210,73 +210,164 @@ double mesh_functional_distorsion(MElement *t, double u, double v)
   return det;
 }
 
-double mesh_functional_distorsion_p2(MTriangle *t)
+static double MINQ (double a, double b, double c){
+  if (a == 0) return std::min(a+b+c,c);
+  double xmin = -b/(2*a);
+  if (xmin < 0 || xmin > 1)return std::min(c,a+b+c);
+  return std::min(c,std::min(a+b+c,a * xmin * xmin + b * xmin + c));
+}
+
+
+double mesh_functional_distorsion_p2_bezier_refined(MTriangle *t)
 {
-  double d1 =mesh_functional_distorsion(t,0.0,0.0);
-  double d2 =mesh_functional_distorsion(t,1.0,0.0);
-  double d3 =mesh_functional_distorsion(t,0.0,1.0);
-  double d4 =mesh_functional_distorsion(t,0.5,0.0);
-  double d5 =mesh_functional_distorsion(t,0.5,0.5);
-  double d6 =mesh_functional_distorsion(t,0.0,0.5);
-  double d[6] = {d1,d2,d3,4*d4-d1-d2,4*d5-d2-d3,4*d6-d1-d3};
-  
-  return *std::min_element(d,d+6);
+  double J1 =mesh_functional_distorsion(t,0.0,0.0);
+  double J2 =mesh_functional_distorsion(t,1.0,0.0);
+  double J3 =mesh_functional_distorsion(t,0.0,1.0);
+  double J4 =mesh_functional_distorsion(t,0.5,0.0);
+  double J5 =mesh_functional_distorsion(t,0.5,0.5);
+  double J6 =mesh_functional_distorsion(t,0.0,0.5);
+
+  double J36 =mesh_functional_distorsion(t,0.0,.75);
+  double J35 =mesh_functional_distorsion(t,0.25,.75);
+  double J56 =mesh_functional_distorsion(t,0.25,.5);
+
+  double J16 =mesh_functional_distorsion(t,0.0,.25);
+  double J14 =mesh_functional_distorsion(t,0.25,.0);
+  double J46 =mesh_functional_distorsion(t,0.25,.25);
+
+
+  double J45 =mesh_functional_distorsion(t,0.5,.25);
+  double J52 =mesh_functional_distorsion(t,0.75,.25);
+  double J24 =mesh_functional_distorsion(t,0.75,.0);
+
+  double d[15] = {
+    J1,J6,J4,2*J16-0.5*(J1+J6),2*J14-0.5*(J1+J4),2*J46-0.5*(J6+J4),
+    J3,J5,2*J36-0.5*(J3+J6),2*J35-0.5*(J3+J5),2*J56-0.5*(J5+J6),
+    J2,2*J45-0.5*(J4+J5),2*J52-0.5*(J5+J2),2*J24-0.5*(J2+J4)};
+  return  *std::min_element(d,d+15);  
 }
 
-double qmDistorsionOfMapping (MTriangle *e)
+double mesh_functional_distorsion_p2_exact(MTriangle *t)
 {
-  //  return 1.0;
-  if (e->getPolynomialOrder() == 1) return 1.0;
-  if (e->getPolynomialOrder() == 2) return mesh_functional_distorsion_p2(e);
-
-  IntPt *pts;
-  int npts;
-  e->getIntegrationPoints(e->getPolynomialOrder(),&npts, &pts);
-  double dmin;
-  for (int i = 0 ; i < npts; i++){
-    const double u = pts[i].pt[0];
-    const double v = pts[i].pt[1];
-    const double di  = mesh_functional_distorsion (e, u, v);
-    //    printf("di = %g\n",di);
-    dmin = (i == 0)? di : std::min(dmin, di);
+  double J1 =mesh_functional_distorsion(t,0.0,0.0);
+  double J2 =mesh_functional_distorsion(t,1.0,0.0);
+  double J3 =mesh_functional_distorsion(t,0.0,1.0);
+  double J4 =mesh_functional_distorsion(t,0.5,0.0);
+  double J5 =mesh_functional_distorsion(t,0.5,0.5);
+  double J6 =mesh_functional_distorsion(t,0.0,0.5);
+
+  const double a = J1;
+  const double b = -3*J1-J2+4*J4;
+  const double c = -3*J1-J3+4*J6;
+  const double d = 4*(J1-J4+J5-J6);
+  const double e = 2*(J1+J2-2*J4);
+  const double f = 2*(J1+J3-2*J6);
+
+  double js[3] = {
+    MINQ (2*(J1+J2-2*J4), -3*J1-J2+4*J4, J1),
+    MINQ (2*(J1+J3-2*J6), -3*J1-J3+4*J6, J1),
+    MINQ (2*(J3+J2-2*J5), -3*J2-J3+4*J5, J2)
+  };
+  double min_interm =  *std::min_element(js,js+3);
+
+  double mat[2][2] = {{2*e,d},{d,2*f}};
+  double x[2], rhs[2] = {-b,-c};
+
+  if (!sys2x2(mat,rhs,x))return min_interm;
+
+  const double ximin = x[0];
+  const double etamin  = x[1];
+
+  if (ximin> 0 && etamin > 0 && 1-ximin-etamin>0){
+    const double m4 = a+b*ximin+c*etamin+d*ximin*etamin+
+      e*ximin*ximin + f*etamin*etamin;      
+    /*
+    if (m4 < min_interm && (m4 < .9 || m4 > 1.1)){
+      printf("m4  = %g xi = %g eta  = %g min_interm = %g min_edges = %g %g %g\n",m4,ximin,etamin,min_interm, MINQ (e,b,a), MINQ (f,c,a), MINQ (-d+e+f,b-c+d-2*f,a+c+f));
+      FILE *f = fopen ("t.pos","w");
+      fprintf(f,"ST2(%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0){%g,%g,%g,%g,%g,%g}\n",
+	      t->getVertex(0)->x(),t->getVertex(0)->y(),
+	      t->getVertex(1)->x(),t->getVertex(1)->y(),
+	      t->getVertex(2)->x(),t->getVertex(2)->y(),
+	      t->getVertex(3)->x(),t->getVertex(3)->y(),
+	      t->getVertex(4)->x(),t->getVertex(4)->y(),
+	      t->getVertex(5)->x(),t->getVertex(5)->y(),
+	    J1,J2,J3,J4,J5,J6);
+      fclose(f);
+      getchar();
+    }
+    */
+    return std::min(m4, min_interm);
   }
-  const fullMatrix<double>& points = e->getFunctionSpace()->points;
+  return min_interm;
+}
 
-  for (int i = 0; i < e->getNumPrimaryVertices(); i++) {
-    const double u = points(i, 0);
-    const double v = points(i, 1);
-    const double di  = mesh_functional_distorsion (e, u, v);
-    dmin = std::min(dmin, di);
+double mesh_functional_distorsion_pN(MElement *t)
+{
+  const JacobianBasis *jac = t->getJacobianFuncSpace();
+  //  jac->monomials.print("coucou");
+  fullVector<double>Ji(jac->points.size1());
+  for (int i=0;i<jac->points.size1();i++){
+    const double u = jac->points(i,0);
+    const double v = jac->points(i,1);
+    Ji(i) = mesh_functional_distorsion(t,u,v);    
   }
-  return dmin;
+ 
+  fullVector<double> Bi( jac->matrixLag2Bez.size1() );
+  jac->matrixLag2Bez.mult(Ji,Bi);
+ 
+  return *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
 }
 
-double qmDistorsionOfMapping (MQuadrangle *e)
+
+double qmDistorsionOfMapping (MTriangle *e)
 {
   //  return 1.0;
   if (e->getPolynomialOrder() == 1) return 1.0;
-  //  if (e->getPolynomialOrder() == 2) return mesh_functional_distorsion_p2(e);
-
-  IntPt *pts;
-  int npts;
-  e->getIntegrationPoints(e->getPolynomialOrder(),&npts, &pts);
-  double dmin;
-  for (int i = 0 ; i < npts; i++){
-    const double u = pts[i].pt[0];
-    const double v = pts[i].pt[1];
-    const double di  = mesh_functional_distorsion (e, u, v);
-    dmin = (i == 0)? di : std::min(dmin, di);
+  else if  (e->getPolynomialOrder() == 2) {
+    //    const double exact = mesh_functional_distorsion_p2_exact(e);
+    const double bezier= mesh_functional_distorsion_pN(e);
+    if (bezier < .1){
+      const double bezier_refined= mesh_functional_distorsion_p2_bezier_refined(e);
+      return bezier_refined;
+    }
+    /*
+    if (exact < .99 || exact > 1.01){
+      FILE *f = fopen ("statistics.dat","a");
+      fprintf(f,"%12.5E %12.5E %12.5E\n",exact,bezier,bezier_refined);
+      fclose(f);
+
+      if (exact > 0 && bezier < 0){
+	f = fopen ("t.pos","w");
+	double J1 =mesh_functional_distorsion(e,0.0,0.0);
+	double J2 =mesh_functional_distorsion(e,1.0,0.0);
+	double J3 =mesh_functional_distorsion(e,0.0,1.0);
+	double J4 =mesh_functional_distorsion(e,0.5,0.0);
+	double J5 =mesh_functional_distorsion(e,0.5,0.5);
+	double J6 =mesh_functional_distorsion(e,0.0,0.5);
+	fprintf(f,"ST2(%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0,%g,%g,0){%g,%g,%g,%g,%g,%g}\n",
+		e->getVertex(0)->x(),e->getVertex(0)->y(),
+		e->getVertex(1)->x(),e->getVertex(1)->y(),
+		e->getVertex(2)->x(),e->getVertex(2)->y(),
+		e->getVertex(3)->x(),e->getVertex(3)->y(),
+		e->getVertex(4)->x(),e->getVertex(4)->y(),
+		e->getVertex(5)->x(),e->getVertex(5)->y(),
+		J1,J2,J3,J4,J5,J6);
+	fclose(f);
+	getchar();
+      }
+    }
+  */
+    return bezier;
   }
-  const fullMatrix<double>& points = e->getFunctionSpace()->points;
+  else return  mesh_functional_distorsion_pN(e);
+}
 
-  for (int i = 0; i < e->getNumPrimaryVertices(); i++) {
-    const double u = points(i, 0);
-    const double v = points(i, 1);
-    const double di  = mesh_functional_distorsion (e, u, v);
-    dmin = std::min(dmin, di);
-  }
-  //  printf("%g\n",dmin);
-  return dmin;
+double qmDistorsionOfMapping (MQuadrangle *e)
+{
+  //  return 1.0;
+  if (e->getPolynomialOrder() == 1) return 1.0;
+  else return mesh_functional_distorsion_pN(e);
 }
 
 
@@ -284,49 +375,30 @@ static double mesh_functional_distorsion(MTetrahedron *t, double u, double v, do
 {
   // compute uncurved element jacobian d_u x and d_v x
   double mat[3][3];  
-  t->getPrimaryJacobian(u, v, w, mat);
-  
+  t->getPrimaryJacobian(u, v, w, mat);  
   const double det1 = det3x3(mat);
-
-   //const double det1 = t->getJacobian(u,v,w,mat);
-  // const double det1 = det3x3(mat);
   t->getJacobian(u, v, w, mat);
   const double detN = det3x3(mat);
-  // const double detN = det3x3(mat);
-
-  //  printf("%g %g %g = %g %g\n",u,v,w,det1,detN);
-
   if (det1 == 0 || detN == 0) return 0;
-  double dist = std::min(detN / det1, det1 / detN); 
+  double dist = det1 / detN; 
   return dist;
 }
 
-double qmDistorsionOfMapping(MTetrahedron *e)
+double qmDistorsionOfMapping(MTetrahedron *t)
 {
-  if (e->getPolynomialOrder() == 1) return 1.0;
-  IntPt *pts;
-  int npts;
-  e->getIntegrationPoints(e->getPolynomialOrder(), &npts, &pts);
-  double dmin;
-  for (int i = 0; i < npts; i++){
-    const double u = pts[i].pt[0];
-    const double v = pts[i].pt[1];
-    const double w = pts[i].pt[2];
-    const double di  = mesh_functional_distorsion(e, u, v, w);
-    dmin = (i == 0) ? di : std::min(dmin, di);
+  const JacobianBasis *jac = t->getJacobianFuncSpace();
+  fullVector<double>Ji(jac->points.size1());
+  for (int i=0;i<jac->points.size1();i++){
+    const double u = jac->points(i,0);
+    const double v = jac->points(i,1);
+    const double w = jac->points(i,2);
+    Ji(i) = mesh_functional_distorsion(t,u,v,w);    
   }
-  
-  const fullMatrix<double>& points = e->getFunctionSpace()->points;
-
-  for (int i = 0; i < e->getNumPrimaryVertices(); i++) {
-    const double u = points(i, 0);
-    const double v = points(i, 1);
-    const double w = points(i, 2);
-    const double di  = mesh_functional_distorsion(e, u, v, w);
-    dmin = std::min(dmin, di);
-  }
-
-  return dmin;
+ 
+  fullVector<double> Bi( jac->matrixLag2Bez.size1() );
+  jac->matrixLag2Bez.mult(Ji,Bi);
+ 
+  return *std::min_element(Bi.getDataPtr(),Bi.getDataPtr()+Bi.size());
 }
 
 double qmTriangleAngles (MTriangle *e) {
diff --git a/benchmarks/boolean/wikipedia.py b/benchmarks/boolean/wikipedia.py
index 50a436c5ee0cf684807054827b899508ba641a20..e39a9ef6e7c167646821bacdaafd21e143748669 100644
--- a/benchmarks/boolean/wikipedia.py
+++ b/benchmarks/boolean/wikipedia.py
@@ -32,6 +32,7 @@ myModel.setAsCurrent();
 
 myModel.mesh(3);
 myModel.save("wikipedia.msh");
+myModel.save("wikipedia.brep");
 
 #FlGui.instance();
 #FlGui.run();