diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt
index eb9fba44b4e5a79d3354e42788c6aaf3def7dd4f..2c56e9b75c9551f9b2e5d9bbc867b66b94357e0b 100644
--- a/Geo/CMakeLists.txt
+++ b/Geo/CMakeLists.txt
@@ -11,7 +11,6 @@ set(SRC
     GEdgeLoop.cpp GEdgeCompound.cpp GFaceCompound.cpp
   GRegionCompound.cpp GRbf.cpp
     gmshVertex.cpp gmshEdge.cpp gmshFace.cpp gmshRegion.cpp
-    gmshEdgeDiscretize.cpp
    gmshSurface.cpp
     OCCVertex.cpp OCCEdge.cpp OCCFace.cpp OCCRegion.cpp
     discreteEdge.cpp discreteFace.cpp discreteRegion.cpp
diff --git a/Geo/MLine.cpp b/Geo/MLine.cpp
index c0859e53588ff2467dca0f8b6c3902f83b905b9e..1299cb4dc62ef89bb876730e5997d2bb6174f09f 100644
--- a/Geo/MLine.cpp
+++ b/Geo/MLine.cpp
@@ -10,6 +10,7 @@
 #include "GaussLegendre1D.h"
 #include "Context.h"
 #include "qualityMeasures.h"
+#include "decasteljau.h"
 
 const JacobianBasis* MLine::getJacobianFuncSpace(int order) const
 {
@@ -79,3 +80,62 @@ void MLineN::getEdgeRep(bool curved, int num, double *x, double *y, double *z, S
   }
   else MLine::getEdgeRep(false, num, x, y, z, n);
 }
+
+void MLine::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  ts.clear();
+  ts.push_back(-1);
+  ts.push_back(1);
+  dpts.clear();
+  dpts.push_back(getVertex(0)->point());
+  dpts.push_back(getVertex(1)->point());
+}
+
+void MLine3::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  SPoint3 p0 = getVertex(0)->point();
+  SPoint3 p2 = getVertex(1)->point();
+  SPoint3 p1 = getVertex(2)->point() * 2 - (p0  + p2) * 0.5;
+  decasteljau(tol, p0, p1, p2, dpts, ts);
+  for (size_t i = 0; i < ts.size(); ++i)
+    ts[i] = -1 + 2 * ts[i];
+}
+
+void MLineN::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
+{
+  int order = getPolynomialOrder();
+  if (order == 3) {
+    SPoint3 p0 = getVertex(0)->point();
+    SPoint3 p3 = getVertex(1)->point();
+    SPoint3 p1 = p0 * (-5./6) + p3 * (1./3) + getVertex(2)->point() * 3. - getVertex(3)->point() * 1.5;
+    SPoint3 p2 = p0 * (1./3) + p3 * (-5./6) - getVertex(2)->point() * 1.5 + getVertex(3)->point() * 3.;
+    decasteljau(tol, p0, p1, p2, p3, dpts, ts);
+    for (size_t i = 0; i < ts.size(); ++i)
+      ts[i] = -1 + 2 * ts[i];
+    return;
+  }
+  fullMatrix<double> lagNodes(order + 1, 3), bezNodes( order + 1, 3);
+  for (int i = 0; i < order + 1; ++i) {
+    MVertex *v = getVertex(i);
+    lagNodes(i, 0) = v->x();
+    lagNodes(i, 1) = v->y();
+    lagNodes(i, 2) = v->z();
+  }
+  const bezierBasis *bez = BasisFactory::getBezierBasis(TYPE_LIN, order);
+  bez->matrixLag2Bez.mult(lagNodes, bezNodes);
+  std::vector<SPoint3> pts(bezNodes.size1());
+  pts[0][0] = bezNodes(0, 0);
+  pts[0][1] = bezNodes(0, 1);
+  pts[0][2] = bezNodes(0, 2);
+  pts[order][0] = bezNodes(1, 0);
+  pts[order][1] = bezNodes(1, 1);
+  pts[order][2] = bezNodes(1, 2);
+  for (int i = 0; i < order - 1; ++i) {
+    pts[i + 1][0] = bezNodes(i + 2, 0);
+    pts[i + 1][1] = bezNodes(i + 2, 1);
+    pts[i + 1][2] = bezNodes(i + 2, 2);
+  }
+  decasteljau(tol, pts, dpts, ts);
+    for (size_t i = 0; i < ts.size(); ++i)
+      ts[i] = -1 + 2 * ts[i];
+}
diff --git a/Geo/MLine.h b/Geo/MLine.h
index 98d6d240a7ac0dd22df33a965ff39a4a48f91b14..378a4d62ef3e762ef6ea2d83656ad0eb2883d371 100644
--- a/Geo/MLine.h
+++ b/Geo/MLine.h
@@ -96,6 +96,7 @@ class MLine : public MElement {
     return SPoint3(0, 0, 0);
   }
   virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts);
+  virtual void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
 };
 
 /*
@@ -149,6 +150,7 @@ class MLine3 : public MLine {
   {
     num < 2 ? MLine::getNode(num, u, v, w) : MElement::getNode(num, u, v, w);
   }
+  virtual void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
 };
 
 /*
@@ -208,6 +210,7 @@ class MLineN : public MLine {
   {
     num < 2 ? MLine::getNode(num, u, v, w) : MElement::getNode(num, u, v, w);
   }
+  virtual void discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts);
 };
 
 struct compareMLinePtr {
diff --git a/Geo/gmshEdge.cpp b/Geo/gmshEdge.cpp
index 8bd39eaf55677799351d061b3696d7b03385e5c7..8d4a2fa398e2f3a15daec307842a49262433b21e 100644
--- a/Geo/gmshEdge.cpp
+++ b/Geo/gmshEdge.cpp
@@ -12,6 +12,7 @@
 #include "GeoInterpolation.h"
 #include "GmshMessage.h"
 #include "Context.h"
+#include "decasteljau.h"
 
 gmshEdge::gmshEdge(GModel *m, Curve *edge, GVertex *v1, GVertex *v2)
   : GEdge(m, edge->Num, v1, v2), c(edge)
@@ -406,3 +407,127 @@ void gmshEdge::writeGEO(FILE *fp)
   if(meshAttributes.reverseMesh)
     fprintf(fp, "Reverse Line {%d};\n", tag());
 }
+
+static inline SPoint3 curveGetPoint(Curve *c, int i)
+{
+  Vertex *v;
+  List_Read(c->Control_Points, i , &v);
+  return SPoint3(v->Pos.X, v->Pos.Y, v->Pos.Z);
+}
+
+void gmshEdge::discretize(double tol, std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  switch(c->Typ) {
+    case MSH_SEGM_LINE :
+      {
+        int NPt = List_Nbr(c->Control_Points);
+        pts.resize(NPt);
+        ts.resize(NPt);
+        for (int i = 0; i < NPt; ++i) {
+          pts[i]= curveGetPoint(c, i);
+          ts[i] = i / (double) (NPt - 1);
+        }
+        return;
+      }
+    case MSH_SEGM_BEZIER :
+      {
+        int NbCurves = (List_Nbr(c->Control_Points) - 1) / 3;
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          SPoint3 pt[4];
+          for(int i = 0; i < 4; i++) {
+            pt[i] = curveGetPoint(c, iCurve * 3 + i);
+          }
+          std::vector<double> lts;
+          std::vector<SPoint3> lpts;
+          decasteljau(tol, pt[0], pt[1], pt[2], pt[3], lpts, lts);
+          for (size_t i = (iCurve == 0 ? 0 : 1); i < lpts.size(); ++i) {
+            pts.push_back(lpts[i]);
+            ts.push_back(t1 + lts[i] * (t2 - t1));
+          }
+        }
+        break;
+      }
+    case MSH_SEGM_BSPLN:
+      {
+        bool periodic = (c->end == c->beg);
+        int NbControlPoints = List_Nbr(c->Control_Points);
+        int NbCurves = NbControlPoints + (periodic ? -1 : 1);
+        SPoint3 pt[4];
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          for(int i = 0; i < 4; i++) {
+            int k;
+            if (periodic) {
+              k = (iCurve - 1 + i) % (NbControlPoints - 1);
+              if (k < 0)
+                k += NbControlPoints - 1;
+            }
+            else {
+              k = std::max(0, std::min(iCurve - 2 + i, NbControlPoints -1));
+            }
+            pt[i] = curveGetPoint(c, k);
+          }
+          SPoint3 bpt[4] = {
+            (pt[0] + pt[1] * 4 + pt[2]) * (1./6.),
+            (pt[1] * 2 + pt[2]) * (1./3.),
+            (pt[1] + pt[2] * 2) * (1./3.),
+            (pt[1] + pt[2] * 4 + pt[3]) * (1./6.)
+          };
+          std::vector<double> lts;
+          std::vector<SPoint3> lpts;
+          decasteljau(tol, bpt[0], bpt[1], bpt[2], bpt[3], lpts, lts);
+          for (size_t i = (iCurve == 0 ? 0 : 1); i < lpts.size(); ++i) {
+            pts.push_back(lpts[i]);
+            ts.push_back(t1 + lts[i] * (t2 - t1));
+          }
+        }
+        break;
+      }
+    case MSH_SEGM_SPLN:
+      {
+        int NbCurves = List_Nbr(c->Control_Points) - 1;
+        SPoint3 pt[4];
+        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
+          double t1 = (iCurve) / (double)(NbCurves);
+          double t2 = (iCurve+1) / (double)(NbCurves);
+          pt[1] = curveGetPoint(c, iCurve);
+          pt[2] = curveGetPoint(c, iCurve + 1);
+          if(iCurve == 0) {
+            if(c->beg == c->end)
+              pt[0] = curveGetPoint(c, NbCurves - 1);
+            else
+              pt[0] = SPoint3(pt[1] * 2 - pt[2]);
+          }
+          else
+            pt[0] = curveGetPoint(c, iCurve - 1);
+          if(iCurve == NbCurves - 1) {
+            if(c->beg == c->end)
+              pt[3] = curveGetPoint(c, 1);
+            else
+              pt[3] = SPoint3(2 * pt[2] - pt[1]);
+          }
+          else
+            pt[3] = curveGetPoint(c, iCurve + 2);
+          SPoint3 bpt[4] = {
+            pt[1],
+            (pt[1] * 6 + pt[2] - pt[0]) * (1./6.),
+            (pt[2] * 6 - pt[3] + pt[1]) * (1./6.),
+            pt[2]
+          };
+          std::vector<double> lts;
+          std::vector<SPoint3> lpts;
+          decasteljau(tol, bpt[0], bpt[1], bpt[2], bpt[3], lpts, lts);
+          for (size_t i = (iCurve == 0 ? 0 : 1); i < lpts.size(); ++i) {
+            pts.push_back(lpts[i]);
+            ts.push_back(t1 + lts[i] * (t2 - t1));
+          }
+        }
+        break;
+      }
+    default :
+      Msg::Fatal("not implemented");
+  }
+}
diff --git a/Geo/gmshEdgeDiscretize.cpp b/Geo/gmshEdgeDiscretize.cpp
deleted file mode 100644
index 440ebe4f7c3ef7dc58b9ae85265b048c2a265720..0000000000000000000000000000000000000000
--- a/Geo/gmshEdgeDiscretize.cpp
+++ /dev/null
@@ -1,195 +0,0 @@
-#include <cstdio>
-#include <cmath>
-#include <vector>
-#include "SPoint3.h"
-#include "SVector3.h"
-#include "GEdge.h"
-#include "gmshEdge.h"
-#include "Geo.h"
-
-class discreteList {
-  std::vector<std::pair<SPoint3, double> > _pts;
-  std::vector<int> _next;
-  public:
-  int insertPoint(int pos, const SPoint3 &pt, double t) {
-    _pts.push_back(std::make_pair(pt, t));
-    _next.push_back(_next[pos + 1]);
-    _next[pos + 1] = _pts.size() - 1;
-    return _pts.size() - 1;
-  }
-  void sort(std::vector<SPoint3> &spts, std::vector<double> &ts) {
-    spts.clear();
-    spts.reserve(_pts.size());
-    ts.clear();
-    ts.reserve(_pts.size());
-    for (int p = _next[0]; p != -1; p = _next[p + 1]) {
-      spts.push_back(_pts[p].first);
-      ts.push_back(_pts[p].second);
-    }
-  }
-  discreteList() {
-    _next.push_back(-1);
-  }
-};
-
-static void decasteljau(double tol, discreteList &discrete, int pos, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, const SPoint3 &p3, double t0, double t3)
-{
-  SVector3 d30 = p3 - p0;
-  SVector3 d13 = p1 - p3;
-  SVector3 d23 = p2 - p3;
-  SVector3 d130 = crossprod(d13, d30);
-  SVector3 d230 = crossprod(d23, d30);
-  double d = std::max(dot(d130, d130), dot(d230, d230));
-  double l2 = dot(d30, d30);
-
-  if(d < tol * tol * l2) {
-    return;
-  }
-
-  SPoint3 p01((p0 + p1) * 0.5);
-  SPoint3 p12((p1 + p2) * 0.5);
-  SPoint3 p23((p2 + p3) * 0.5);
-  SPoint3 p012((p01 + p12) * 0.5);
-  SPoint3 p123((p12 + p23) * 0.5);
-  SPoint3 p0123((p012 + p123) * 0.5);
-  double t0123 = 0.5 * (t0 + t3);
-  int newpos = discrete.insertPoint(pos, p0123, t0123);
-
-  decasteljau(tol, discrete, pos, p0, p01, p012, p0123, t0, t0123);
-  decasteljau(tol, discrete, newpos, p0123, p123, p23, p3, t0123, t3);
-}
-
-static int discretizeBezier(double tol, discreteList &discrete, int pos, const SPoint3 pt[4], double t0, double t3, bool insertFirstPoint)
-{
-  if (insertFirstPoint)
-    pos = discrete.insertPoint(pos, pt[0], t0);
-  int newp = discrete.insertPoint(pos, pt[3], t3);
-  decasteljau(tol, discrete, pos, pt[0], pt[1], pt[2], pt[3], t0, t3);
-  return newp;
-}
-
-static int discretizeBSpline(double tol, discreteList &discrete, int pos, const SPoint3 pt[4], double t0, double t3, bool insertFirstPoint)
-{
-  SPoint3 bpt[4] = {
-    SPoint3((pt[0] + 4 * pt[1]  + pt[2]) * (1./6.)),
-    SPoint3((2 * pt[1] + pt[2]) * (1./3.)),
-    SPoint3((pt[1] + 2 * pt[2]) * (1./3.)),
-    SPoint3((pt[1] + 4 * pt[2] + pt[3]) * (1./6.))
-  };
-  return discretizeBezier(tol, discrete, pos, bpt, t0, t3, insertFirstPoint);
-}
-
-static int discretizeCatmullRom(double tol, discreteList &discrete, int pos, const SPoint3 pt[4], double t0, double t3, bool insertFirstPoint)
-{
-  SPoint3 bpt[4] = {
-    pt[1],
-    SPoint3(( 6 * pt[1] + pt[2] - pt[0]) * (1./6.)),
-    SPoint3(( 6 * pt[2] - pt[3] + pt[1]) * (1./6.)),
-    pt[2]
-  };
-  return discretizeBezier(tol, discrete, pos, bpt, t0, t3, insertFirstPoint);
-}
-
-static inline SPoint3 curveGetPoint(Curve *c, int i)
-{
-  Vertex *v;
-  List_Read(c->Control_Points, i , &v);
-  return SPoint3(v->Pos.X, v->Pos.Y, v->Pos.Z);
-}
-
-static void discretizeCurve(Curve *c, double tol, std::vector<SPoint3> &pts, std::vector<double> &ts)
-{
-  discreteList discrete;
-  switch(c->Typ) {
-    case MSH_SEGM_LINE :
-      {
-        int NPt = List_Nbr(c->Control_Points);
-        pts.resize(NPt);
-        ts.resize(NPt);
-        for (int i = 0; i < NPt; ++i) {
-          pts[i]= curveGetPoint(c, i);
-          ts[i] = i / (double) (NPt - 1);
-        }
-        return;
-      }
-    case MSH_SEGM_BEZIER :
-      {
-        int back = -1;
-        int NbCurves = (List_Nbr(c->Control_Points) - 1) / 3;
-        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
-          double t1 = (iCurve) / (double)(NbCurves);
-          double t2 = (iCurve+1) / (double)(NbCurves);
-          SPoint3 pt[4];
-          for(int i = 0; i < 4; i++) {
-            pt[i] = curveGetPoint(c, iCurve * 3 + i);
-          }
-          back = discretizeBezier(tol, discrete, back, pt, t1, t2, iCurve == 0);
-        }
-        break;
-      }
-    case MSH_SEGM_BSPLN:
-      {
-        int back = -1;
-        bool periodic = (c->end == c->beg);
-        int NbControlPoints = List_Nbr(c->Control_Points);
-        int NbCurves = NbControlPoints + (periodic ? -1 : 1);
-        SPoint3 pt[4];
-        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
-          double t1 = (iCurve) / (double)(NbCurves);
-          double t2 = (iCurve+1) / (double)(NbCurves);
-          for(int i = 0; i < 4; i++) {
-            int k;
-            if (periodic) {
-              k = (iCurve - 1 + i) % (NbControlPoints - 1);
-              if (k < 0)
-                k += NbControlPoints - 1;
-            }
-            else {
-              k = std::max(0, std::min(iCurve - 2 + i, NbControlPoints -1));
-            }
-            pt[i] = curveGetPoint(c, k);
-          }
-          back = discretizeBSpline(tol, discrete, back, pt, t1, t2, iCurve == 0);
-        }
-        break;
-      }
-    case MSH_SEGM_SPLN:
-      {
-        int NbCurves = List_Nbr(c->Control_Points) - 1;
-        SPoint3 pt[4];
-        int back = -1;
-        for (int iCurve = 0; iCurve < NbCurves; ++iCurve) {
-          double t1 = (iCurve) / (double)(NbCurves);
-          double t2 = (iCurve+1) / (double)(NbCurves);
-          pt[1] = curveGetPoint(c, iCurve);
-          pt[2] = curveGetPoint(c, iCurve + 1);
-          if(iCurve == 0) {
-            if(c->beg == c->end)
-              pt[0] = curveGetPoint(c, NbCurves - 1);
-            else
-              pt[0] = SPoint3(pt[1] * 2 - pt[2]);
-          }
-          else
-            pt[0] = curveGetPoint(c, iCurve - 1);
-          if(iCurve == NbCurves - 1) {
-            if(c->beg == c->end)
-              pt[3] = curveGetPoint(c, 1);
-            else
-              pt[3] = SPoint3(2 * pt[2] - pt[1]);
-          }
-          else
-            pt[3] = curveGetPoint(c, iCurve + 2);
-          back = discretizeCatmullRom(tol, discrete, back, pt, t1, t2, iCurve == 0);
-        }
-        break;
-      }
-    default :
-      Msg::Fatal("not implemented");
-  }
-  discrete.sort(pts, ts);
-}
-
-void gmshEdge::discretize(double tol, std::vector<SPoint3> &dpts, std::vector<double> &ts)
-{
-  discretizeCurve(c, tol, dpts, ts);
-}
diff --git a/Numeric/CMakeLists.txt b/Numeric/CMakeLists.txt
index ae0f52d7217b3b82eaedfd4c9d920379bf992e94..8abf9bc3f3749692942d81cd77b6232bae92901b 100644
--- a/Numeric/CMakeLists.txt
+++ b/Numeric/CMakeLists.txt
@@ -30,6 +30,7 @@ set(SRC
   GaussJacobi1D.cpp
   HilbertCurve.cpp
  robustPredicates.cpp
+ decasteljau.cpp
   mathEvaluator.cpp
   Iso.cpp
 )
diff --git a/Numeric/decasteljau.cpp b/Numeric/decasteljau.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..15e9c0120ccc533e9c2174212340787886561a46
--- /dev/null
+++ b/Numeric/decasteljau.cpp
@@ -0,0 +1,116 @@
+#include "decasteljau.h"
+#include "SPoint3.h"
+#include "SVector3.h"
+
+class discreteList {
+  std::vector<std::pair<SPoint3, double> > _pts;
+  std::vector<int> _next;
+  public:
+  int insertPoint(int pos, const SPoint3 &pt, double t) {
+    _pts.push_back(std::make_pair(pt, t));
+    _next.push_back(_next[pos + 1]);
+    _next[pos + 1] = _pts.size() - 1;
+    return _pts.size() - 1;
+  }
+  void sort(std::vector<SPoint3> &spts, std::vector<double> &ts) {
+    spts.clear();
+    spts.reserve(_pts.size());
+    ts.clear();
+    ts.reserve(_pts.size());
+    for (int p = _next[0]; p != -1; p = _next[p + 1]) {
+      spts.push_back(_pts[p].first);
+      ts.push_back(_pts[p].second);
+    }
+  }
+  discreteList() {
+    _next.push_back(-1);
+  }
+};
+
+static double sqDistPointSegment(const SPoint3 &p, const SPoint3 &s0, const SPoint3 &s1)
+{
+  SVector3 d(s1 - s0);
+  SVector3 d0(p - s0);
+  SVector3 d1(p - s1);
+  double dn2 = crossprod(d, d0).normSq();
+  double dt2 = std::max(0., std::max(-dot(d, d0), dot(d, d1)));
+  dt2 *= dt2;
+  return (dt2 + dn2) / d.normSq();
+}
+
+static void decasteljau(double tol, discreteList &discrete, int pos, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, double t0, double t2)
+{
+  if(sqDistPointSegment(p1, p0, p2) < tol * tol)
+    return;
+  SPoint3 p01((p0 + p1) * 0.5);
+  SPoint3 p12((p1 + p2) * 0.5);
+  SPoint3 p012((p01 + p12) * 0.5);
+  double t012 = 0.5 * (t0 + t2);
+  int newpos = discrete.insertPoint(pos, p012, t012);
+  decasteljau(tol, discrete, pos, p0, p01, p012, t0, t012);
+  decasteljau(tol, discrete, newpos, p012, p12, p2, t012, t2);
+}
+
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  discreteList discrete;
+  discrete.insertPoint(-1, p0, 0);
+  discrete.insertPoint(0, p2, 1);
+  decasteljau(tol, discrete, 0, p0, p1, p2, 0., 1);
+  discrete.sort(pts, ts);
+}
+
+static void decasteljau(double tol, discreteList &discrete, int pos, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, const SPoint3 &p3, double t0, double t3)
+{
+  if (std::max(sqDistPointSegment(p1, p0, p3), sqDistPointSegment(p2, p0, p3)) < tol * tol)
+    return;
+  SPoint3 p01((p0 + p1) * 0.5);
+  SPoint3 p12((p1 + p2) * 0.5);
+  SPoint3 p23((p2 + p3) * 0.5);
+  SPoint3 p012((p01 + p12) * 0.5);
+  SPoint3 p123((p12 + p23) * 0.5);
+  SPoint3 p0123((p012 + p123) * 0.5);
+  double t0123 = 0.5 * (t0 + t3);
+  int newpos = discrete.insertPoint(pos, p0123, t0123);
+  decasteljau(tol, discrete, pos, p0, p01, p012, p0123, t0, t0123);
+  decasteljau(tol, discrete, newpos, p0123, p123, p23, p3, t0123, t3);
+}
+
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, const SPoint3 &p3, std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  discreteList discrete;
+  discrete.insertPoint(-1, p0, 0);
+  discrete.insertPoint(0, p3, 1);
+  decasteljau(tol, discrete, 0, p0, p1, p2, p3, 0., 1);
+  discrete.sort(pts, ts);
+}
+
+static void decasteljau(double tol, discreteList &discrete, int pos, const std::vector<SPoint3> &pts, double t0, double te)
+{
+  int order = pts.size() - 1;
+  double dmax2 = 0;
+  for (int i = 1; i < order ; ++i)
+    dmax2 = std::max(dmax2, sqDistPointSegment(pts[i], pts[0], pts[order]));
+  if(dmax2 < tol * tol)
+    return;
+  std::vector<SPoint3> sub0(pts.size());
+  std::vector<SPoint3> sub1(pts);
+  for (int l = 0; l < order + 1; ++l) {
+    sub0[l] = sub1[0];
+    for (int i = 0; i < order - l; ++i)
+      sub1[i] = (sub1[i] + sub1[i + 1]) * 0.5;
+  }
+  double tmid = 0.5 * (t0 + te);
+  int newpos = discrete.insertPoint(pos, sub1[0], tmid);
+  decasteljau(tol, discrete, pos, sub0, t0, tmid);
+  decasteljau(tol, discrete, newpos, sub1, tmid, te);
+}
+
+void decasteljau(double tol, const std::vector<SPoint3> &controlPoints, std::vector<SPoint3> &pts, std::vector<double> &ts)
+{
+  discreteList discrete;
+  discrete.insertPoint(-1, controlPoints[0], 0);
+  discrete.insertPoint(0, controlPoints.back(), 1);
+  decasteljau(tol, discrete, 0, controlPoints, 0., 1);
+  discrete.sort(pts, ts);
+}
diff --git a/Numeric/decasteljau.h b/Numeric/decasteljau.h
new file mode 100644
index 0000000000000000000000000000000000000000..7daa3251cf3007935319bf7a24532069857e8ef3
--- /dev/null
+++ b/Numeric/decasteljau.h
@@ -0,0 +1,9 @@
+#ifndef _DECASTELJAU_H_
+#define _DECASTELJAU_H_
+#include <vector>
+class SPoint3;
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, std::vector<SPoint3> &pts, std::vector<double> &ts);
+void decasteljau(double tol, const SPoint3 &p0, const SPoint3 &p1, const SPoint3 &p2, const SPoint3 &p3, std::vector<SPoint3> &pts, std::vector<double> &ts);
+void decasteljau(double tol, const std::vector<SPoint3> &controlPoints, std::vector<SPoint3> &pts, std::vector<double> &ts);
+double sqDistPointSegment(const SPoint3 &p, const SPoint3 &s0, const SPoint3 &s1);
+#endif
diff --git a/wrappers/gmshpy/gmshGeo.i b/wrappers/gmshpy/gmshGeo.i
index 49d6ad1e9f250088c7445ab95226b27d789266e3..67e3432a0c0db5030052b50d753090f8d7ce47db 100644
--- a/wrappers/gmshpy/gmshGeo.i
+++ b/wrappers/gmshpy/gmshGeo.i
@@ -83,6 +83,7 @@ namespace std {
 %include "discreteEdge.h"
 %include "discreteVertex.h"
 %include "discreteRegion.h"
+%include "SPoint3.h"
 %include "MElement.h"
 %include "MVertex.h"
 %include "MTriangle.h"
@@ -94,7 +95,6 @@ namespace std {
 %include "MFace.h"
 %include "MPoint.h"
 %include "SVector3.h"
-%include "SPoint3.h"
 %include "SPoint2.h"
 %include "SBoundingBox3d.h"
 %include "Curvature.h"
@@ -141,3 +141,10 @@ namespace std {
 
 }
 
+%extend MElement {
+  SPoint3 pnt(double xi0, double xi1, double xi2) {
+    SPoint3 p;
+    $self->pnt(xi0, xi1, xi2, p);
+    return p;
+  }
+}