diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 99071e73f4127a506788f77faf7e6097c3711cd4..0cf95e81bd168c9a460dbb6aedd30c30ee71bd3c 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.478 2006-11-25 20:08:39 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.479 2006-11-25 23:06:06 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -30,6 +30,7 @@
 #include "GeoExtractContour.h"
 #include "Generator.h"
 #include "SecondOrder.h"
+#include "OptimizeMesh.h"
 #include "Draw.h"
 #include "SelectBuffer.h"
 #include "Views.h"
@@ -3810,8 +3811,7 @@ void mesh_optimize_cb(CALLBACK_ARGS)
     return;
   }
   CTX.threads_lock = 1;
-  Msg(GERROR, "Mesh optimize has yet to be reinterfaced");
-  //Optimize_Netgen();
+  OptimizeMesh();
   CTX.threads_lock = 0;
   CTX.mesh.changed = ENT_LINE | ENT_SURFACE | ENT_VOLUME;
   Draw();
diff --git a/Fltk/Makefile b/Fltk/Makefile
index 7097bda09da689ce466fbd06d4c553f405487b28..cfa5160079b5e7ee978a9a74d7a5978a9791a504 100644
--- a/Fltk/Makefile
+++ b/Fltk/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.114 2006-11-25 20:08:39 geuzaine Exp $
+# $Id: Makefile,v 1.115 2006-11-25 23:06:06 geuzaine Exp $
 #
 # Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 #
@@ -120,8 +120,9 @@ Callbacks.o: Callbacks.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../Common/GmshUI.h ../Geo/Geo.h ../Common/GmshDefines.h \
   ../Geo/ExtrudeParams.h ../Geo/GeoStringInterface.h ../Geo/Geo.h \
   ../Geo/GeoExtractContour.h ../Mesh/Generator.h ../Mesh/SecondOrder.h \
-  ../Graphics/Draw.h ../Common/Views.h ../Common/ColorTable.h \
-  ../Common/VertexArray.h ../Common/SmoothNormals.h ../Numeric/Numeric.h \
+  ../Mesh/OptimizeMesh.h ../Graphics/Draw.h ../Common/Views.h \
+  ../Common/ColorTable.h ../Common/VertexArray.h \
+  ../Common/SmoothNormals.h ../Numeric/Numeric.h \
   ../Common/AdaptiveViews.h ../Common/GmshMatrix.h \
   ../Graphics/SelectBuffer.h ../Geo/GVertex.h ../Geo/GEntity.h \
   ../Geo/Range.h ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h \
diff --git a/Geo/Geo.cpp b/Geo/Geo.cpp
index c65ccffa3d40ee60926ad50a61363ed45da9a546..643b61dcaea2e7091b76ba47a31498ccdc78d27b 100644
--- a/Geo/Geo.cpp
+++ b/Geo/Geo.cpp
@@ -1,4 +1,4 @@
-// $Id: Geo.cpp,v 1.62 2006-11-25 20:08:39 geuzaine Exp $
+// $Id: Geo.cpp,v 1.63 2006-11-25 23:06:06 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -22,6 +22,7 @@
 #include "Gmsh.h"
 #include "Numeric.h"
 #include "Geo.h"
+#include "GeoUtils.h"
 #include "GeoInterpolation.h"
 #include "Context.h"
 
@@ -656,6 +657,213 @@ Surface *Create_Surface(int Num, int Typ)
   return (pS);
 }
 
+void CreateNurbsSurfaceSupport(int Num, int Order1, int Order2,
+                               List_T * List, List_T * ku, List_T * kv)
+{
+  // This routine has been heavily modified to fit the new interfaces,
+  // but has not been tested since then. It's probably full of bugs
+  // now.
+  List_T *ListOfDouble_L;
+  List_T *ListCP = List_Create(2, 2, sizeof(int));
+
+  for(int j = 0; j < List_Nbr(List); j++) {
+    List_Read(List, j, &ListOfDouble_L);
+    for(int i = 0; i < List_Nbr(ListOfDouble_L); i++) {
+      double d;
+      List_Read(ListOfDouble_L, i, &d);
+      int N = (int)d;
+      List_Add(ListCP, &N);
+    }
+  }
+  List_Read(List, 0, &ListOfDouble_L);
+  int Nu = List_Nbr(List);
+  int Nv = List_Nbr(ListOfDouble_L);
+
+  Surface *s = Create_Surface(Num, MSH_SURF_NURBS);
+  s->Support = NULL;
+  s->Control_Points = List_Create(4, 1, sizeof(Vertex *));
+  s->OrderU = Order1;
+  s->OrderV = Order2;
+  s->Nu = Nu;
+  s->Nv = Nv;
+  for(int i = 0; i < List_Nbr(ListCP); i++) {
+    int j;
+    List_Read(ListCP, i, &j);
+    Vertex *v = FindPoint(j);
+    if(v){
+      List_Add(s->Control_Points, &v);
+    }
+    else{
+      Msg(GERROR, "Unknown control point %d in nurbs surface", j);
+    }
+  }
+
+  s->ku = (float *)malloc(List_Nbr(ku) * sizeof(float));
+  s->kv = (float *)malloc(List_Nbr(kv) * sizeof(float));
+
+  double kumin = 0., kumax = 1.;
+  double kvmin = 0., kvmax = 1.;
+
+  for(int i = 0; i < List_Nbr(ku); i++) {
+    double d;
+    List_Read(ku, i, &d);
+    float f = (float)((d - kumin) / (kumax - kumin));
+    s->ku[i] = f;
+  }
+  for(int i = 0; i < List_Nbr(kv); i++) {
+    double d;
+    List_Read(kv, i, &d);
+    float f = (float)((d - kvmin) / (kvmax - kvmin));
+    s->kv[i] = f;
+  }
+
+  List_Delete(ListCP);
+
+  End_Surface(s);
+  Tree_Add(THEM->Surfaces, &s);
+}
+
+void CreateNurbsSurface(int Num, int Order1, int Order2, List_T * List,
+                        List_T * ku, List_T * kv)
+{
+  // This routine has been heavily modified to fit the new interfaces,
+  // but has not been tested since then. It's probably full of bugs
+  // now.
+
+  List_T *ListOfDouble_L, *Listint, *ListCP;
+  int Loop[4];
+
+  ListCP = List_Create(2, 2, sizeof(int));
+
+  double kumin, kumax;
+  List_Read(ku, 0, &kumin);
+  List_Read(ku, List_Nbr(ku) - 1, &kumax);
+  double kvmin, kvmax;
+  List_Read(kv, 0, &kvmin);
+  List_Read(kv, List_Nbr(kv) - 1, &kvmax);
+  for(int j = 0; j < List_Nbr(List); j++) {
+    List_Read(List, j, &ListOfDouble_L);
+    for(int i = 0; i < List_Nbr(ListOfDouble_L); i++) {
+      double d;
+      List_Read(ListOfDouble_L, i, &d);
+      int N = (int)d;
+      List_Add(ListCP, &N);
+    }
+  }
+
+  // 1st and 3rd gen
+  List_Read(List, 0, &ListOfDouble_L);
+  Listint = ListOfDouble2ListOfInt(ListOfDouble_L);
+  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[0])) {
+  }
+  else {
+    Loop[0] = NEWREG();
+    Curve *c = Create_Curve(Loop[0], MSH_SEGM_NURBS, Order1, Listint, NULL, 
+			    -1, -1, kumin, kumax);
+    Tree_Add(THEM->Curves, &c);
+    CreateReversedCurve(c);
+    c->k = (float *)malloc(4 * List_Nbr(ku) * sizeof(float));
+    for(int i = 0; i < List_Nbr(ku); i++) {
+      double d;
+      List_Read(ku, i, &d);
+      c->k[i] = (float)d /*((d-kumin)/(kumax-kumin)) */ ;
+    }
+  }
+  List_Delete(Listint);
+
+  List_Read(List, List_Nbr(List) - 1, &ListOfDouble_L);
+  Listint = ListOfDouble2ListOfInt(ListOfDouble_L);
+  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[2])) {
+  }
+  else {
+    Loop[2] = NEWREG();
+    Curve *c = Create_Curve(Loop[2], MSH_SEGM_NURBS, Order1, Listint, NULL, 
+			    -1, -1, kumin, kumax);
+    Tree_Add(THEM->Curves, &c);
+    CreateReversedCurve(c);
+    c->k = (float *)malloc(4 * List_Nbr(ku) * sizeof(float));
+    for(int i = 0; i < List_Nbr(ku); i++) {
+      double d;
+      List_Read(ku, i, &d);
+      c->k[i] = (float)d /*((d-kumin)/(kumax-kumin)) */ ;
+    }
+  }
+  List_Delete(Listint);
+
+  // 2nd and 4th gen
+  List_T *List1 = List_Create(List_Nbr(List), 1, sizeof(double));
+  List_T *List2 = List_Create(List_Nbr(List), 1, sizeof(double));
+  for(int i = 0; i < List_Nbr(List); i++) {
+    List_Read(List, i, &ListOfDouble_L);
+    List_Add(List1, List_Pointer(ListOfDouble_L, 0));
+    List_Add(List2, List_Pointer(ListOfDouble_L, List_Nbr(ListOfDouble_L) - 1));
+  }
+
+  Listint = ListOfDouble2ListOfInt(List1);
+  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[1])) {
+  }
+  else {
+    Loop[1] = NEWREG();
+    Curve *c = Create_Curve(Loop[1], MSH_SEGM_NURBS, Order2, Listint, NULL, 
+			    -1, -1, kumin, kumax);
+    Tree_Add(THEM->Curves, &c);
+    CreateReversedCurve(c);
+    c->k = (float *)malloc(4 * List_Nbr(kv) * sizeof(float));
+    for(int i = 0; i < List_Nbr(kv); i++) {
+      double d;
+      List_Read(kv, i, &d);
+      c->k[i] = (float)d /*((d-kvmin)/(kvmax-kvmin)) */ ;
+    }
+  }
+  List_Delete(Listint);
+
+  Listint = ListOfDouble2ListOfInt(List2);
+  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[3])) {
+  }
+  else {
+    Loop[3] = NEWREG();
+    Curve *c = Create_Curve(Loop[3], MSH_SEGM_NURBS, Order2, Listint, NULL,
+			    -1, -1, kumin, kumax);
+    Tree_Add(THEM->Curves, &c);
+    CreateReversedCurve(c);
+    c->k = (float *)malloc(4 * List_Nbr(kv) * sizeof(float));
+    for(int i = 0; i < List_Nbr(kv); i++) {
+      double d;
+      List_Read(kv, i, &d);
+      c->k[i] = (float)d /*((d-kvmin)/(kvmax-kvmin)) */ ;
+    }
+  }
+  List_Delete(Listint);
+  List_Delete(List1);
+  List_Delete(List2);
+
+  Listint = List_Create(10, 10, sizeof(int));
+  int l0 = -Loop[0];
+  List_Add(Listint, &l0);
+  List_Add(Listint, &Loop[1]);
+  List_Add(Listint, &Loop[2]);
+  int l3 = -Loop[3];
+  List_Add(Listint, &l3);
+
+  int topnew = NEWREG();
+  CreateNurbsSurfaceSupport(topnew, Order1, Order2, List, ku, kv);
+
+  int il = NEWREG();
+  SurfaceLoop *l = Create_SurfaceLoop(il, Listint);
+  Tree_Add(THEM->SurfaceLoops, &l);
+  List_Reset(Listint);
+  List_Add(Listint, &il);
+
+  Surface *s = Create_Surface(NEWREG(), MSH_SURF_TRIMMED);
+  setSurfaceGeneratrices(s, Listint);
+  s->Support = s;
+  End_Surface(s);
+  Tree_Add(THEM->Surfaces, &s);
+
+  List_Delete(Listint);
+  List_Delete(ListCP);
+}
+
 void Free_Surface(void *a, void *b)
 {
   Surface *pS = *(Surface **) a;
diff --git a/Geo/Geo.h b/Geo/Geo.h
index 34399abb5864a74fa662913fa8682aa9277f65c6..4dde96800c498ffd3e8bb48d011b0b138cc7666b 100644
--- a/Geo/Geo.h
+++ b/Geo/Geo.h
@@ -213,6 +213,9 @@ typedef struct{
 }Curve;
 
 class Mesh{
+private:
+  void alloc_all();
+  void free_all();
 public:
   Tree_T *Points;
   Tree_T *Curves;
@@ -225,8 +228,6 @@ public:
   int MaxSurfaceLoopNum, MaxVolumeNum, MaxPhysicalNum;
   Mesh(){ alloc_all(); }
   ~Mesh(){ free_all(); }
-  void alloc_all();
-  void free_all();
   void destroy(){ free_all(); alloc_all(); }
 };
 
@@ -261,6 +262,10 @@ Volume        *Create_Volume(int Num, int Typ);
 EdgeLoop      *Create_EdgeLoop(int Num, List_T * intlist);
 SurfaceLoop   *Create_SurfaceLoop(int Num, List_T * intlist);
 
+void CreateNurbsSurface (int Num, int Order1, int Order2, List_T *, List_T *, List_T *);
+void CreateNurbsSurfaceSupport (int Num, int Order2, int Order1, 
+                                List_T * List, List_T *, List_T *);
+
 void Free_Vertex (void *a, void *b);
 void Free_PhysicalGroup(void *a, void *b);
 void Free_Surface(void *a, void *b);
diff --git a/Geo/GeoInterpolation.cpp b/Geo/GeoInterpolation.cpp
index ab53ed1f2a2f41b992678792f8b348da4a276830..88c652180eed0d9a0258597d0ecea995b2916edd 100644
--- a/Geo/GeoInterpolation.cpp
+++ b/Geo/GeoInterpolation.cpp
@@ -1,4 +1,4 @@
-// $Id: GeoInterpolation.cpp,v 1.3 2006-11-25 18:03:49 geuzaine Exp $
+// $Id: GeoInterpolation.cpp,v 1.4 2006-11-25 23:06:06 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -791,214 +791,3 @@ Vertex InterpolateNurbsSurface(Surface * s, double u, double v)
   }
   return sp;
 }
-
-
-// Surface creation helpers
-
-void CreateNurbsSurfaceSupport(int Num, int Order1, int Order2,
-                               List_T * List, List_T * ku, List_T * kv)
-{
-  // This routine has been heavily modified to fit the new interfaces,
-  // but has not been tested since then. It's probably full of bugs
-  // now.
-  List_T *ListOfDouble_L;
-  List_T *ListCP = List_Create(2, 2, sizeof(int));
-
-  for(int j = 0; j < List_Nbr(List); j++) {
-    List_Read(List, j, &ListOfDouble_L);
-    for(int i = 0; i < List_Nbr(ListOfDouble_L); i++) {
-      double d;
-      List_Read(ListOfDouble_L, i, &d);
-      int N = (int)d;
-      List_Add(ListCP, &N);
-    }
-  }
-  List_Read(List, 0, &ListOfDouble_L);
-  int Nu = List_Nbr(List);
-  int Nv = List_Nbr(ListOfDouble_L);
-
-  Surface *s = Create_Surface(Num, MSH_SURF_NURBS);
-  s->Support = NULL;
-  s->Control_Points = List_Create(4, 1, sizeof(Vertex *));
-  s->OrderU = Order1;
-  s->OrderV = Order2;
-  s->Nu = Nu;
-  s->Nv = Nv;
-  for(int i = 0; i < List_Nbr(ListCP); i++) {
-    int j;
-    List_Read(ListCP, i, &j);
-    Vertex *v = FindPoint(j);
-    if(v){
-      List_Add(s->Control_Points, &v);
-    }
-    else{
-      Msg(GERROR, "Unknown control point %d in nurbs surface", j);
-    }
-  }
-
-  s->ku = (float *)malloc(List_Nbr(ku) * sizeof(float));
-  s->kv = (float *)malloc(List_Nbr(kv) * sizeof(float));
-
-  double kumin = 0., kumax = 1.;
-  double kvmin = 0., kvmax = 1.;
-
-  for(int i = 0; i < List_Nbr(ku); i++) {
-    double d;
-    List_Read(ku, i, &d);
-    float f = (float)((d - kumin) / (kumax - kumin));
-    s->ku[i] = f;
-  }
-  for(int i = 0; i < List_Nbr(kv); i++) {
-    double d;
-    List_Read(kv, i, &d);
-    float f = (float)((d - kvmin) / (kvmax - kvmin));
-    s->kv[i] = f;
-  }
-
-  List_Delete(ListCP);
-
-  End_Surface(s);
-  Tree_Add(THEM->Surfaces, &s);
-}
-
-void CreateNurbsSurface(int Num, int Order1, int Order2, List_T * List,
-                        List_T * ku, List_T * kv)
-{
-  // This routine has been heavily modified to fit the new interfaces,
-  // but has not been tested since then. It's probably full of bugs
-  // now.
-
-  List_T *ListOfDouble_L, *Listint, *ListCP;
-  int Loop[4];
-
-  ListCP = List_Create(2, 2, sizeof(int));
-
-  double kumin, kumax;
-  List_Read(ku, 0, &kumin);
-  List_Read(ku, List_Nbr(ku) - 1, &kumax);
-  double kvmin, kvmax;
-  List_Read(kv, 0, &kvmin);
-  List_Read(kv, List_Nbr(kv) - 1, &kvmax);
-  for(int j = 0; j < List_Nbr(List); j++) {
-    List_Read(List, j, &ListOfDouble_L);
-    for(int i = 0; i < List_Nbr(ListOfDouble_L); i++) {
-      double d;
-      List_Read(ListOfDouble_L, i, &d);
-      int N = (int)d;
-      List_Add(ListCP, &N);
-    }
-  }
-
-  // 1st and 3rd gen
-  List_Read(List, 0, &ListOfDouble_L);
-  Listint = ListOfDouble2ListOfInt(ListOfDouble_L);
-  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[0])) {
-  }
-  else {
-    Loop[0] = NEWREG();
-    Curve *c = Create_Curve(Loop[0], MSH_SEGM_NURBS, Order1, Listint, NULL, 
-			    -1, -1, kumin, kumax);
-    Tree_Add(THEM->Curves, &c);
-    CreateReversedCurve(c);
-    c->k = (float *)malloc(4 * List_Nbr(ku) * sizeof(float));
-    for(int i = 0; i < List_Nbr(ku); i++) {
-      double d;
-      List_Read(ku, i, &d);
-      c->k[i] = (float)d /*((d-kumin)/(kumax-kumin)) */ ;
-    }
-  }
-  List_Delete(Listint);
-
-  List_Read(List, List_Nbr(List) - 1, &ListOfDouble_L);
-  Listint = ListOfDouble2ListOfInt(ListOfDouble_L);
-  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[2])) {
-  }
-  else {
-    Loop[2] = NEWREG();
-    Curve *c = Create_Curve(Loop[2], MSH_SEGM_NURBS, Order1, Listint, NULL, 
-			    -1, -1, kumin, kumax);
-    Tree_Add(THEM->Curves, &c);
-    CreateReversedCurve(c);
-    c->k = (float *)malloc(4 * List_Nbr(ku) * sizeof(float));
-    for(int i = 0; i < List_Nbr(ku); i++) {
-      double d;
-      List_Read(ku, i, &d);
-      c->k[i] = (float)d /*((d-kumin)/(kumax-kumin)) */ ;
-    }
-  }
-  List_Delete(Listint);
-
-  // 2nd and 4th gen
-  List_T *List1 = List_Create(List_Nbr(List), 1, sizeof(double));
-  List_T *List2 = List_Create(List_Nbr(List), 1, sizeof(double));
-  for(int i = 0; i < List_Nbr(List); i++) {
-    List_Read(List, i, &ListOfDouble_L);
-    List_Add(List1, List_Pointer(ListOfDouble_L, 0));
-    List_Add(List2, List_Pointer(ListOfDouble_L, List_Nbr(ListOfDouble_L) - 1));
-  }
-
-  Listint = ListOfDouble2ListOfInt(List1);
-  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[1])) {
-  }
-  else {
-    Loop[1] = NEWREG();
-    Curve *c = Create_Curve(Loop[1], MSH_SEGM_NURBS, Order2, Listint, NULL, 
-			    -1, -1, kumin, kumax);
-    Tree_Add(THEM->Curves, &c);
-    CreateReversedCurve(c);
-    c->k = (float *)malloc(4 * List_Nbr(kv) * sizeof(float));
-    for(int i = 0; i < List_Nbr(kv); i++) {
-      double d;
-      List_Read(kv, i, &d);
-      c->k[i] = (float)d /*((d-kvmin)/(kvmax-kvmin)) */ ;
-    }
-  }
-  List_Delete(Listint);
-
-  Listint = ListOfDouble2ListOfInt(List2);
-  if(recognize_seg(MSH_SEGM_NURBS, Listint, &Loop[3])) {
-  }
-  else {
-    Loop[3] = NEWREG();
-    Curve *c = Create_Curve(Loop[3], MSH_SEGM_NURBS, Order2, Listint, NULL,
-			    -1, -1, kumin, kumax);
-    Tree_Add(THEM->Curves, &c);
-    CreateReversedCurve(c);
-    c->k = (float *)malloc(4 * List_Nbr(kv) * sizeof(float));
-    for(int i = 0; i < List_Nbr(kv); i++) {
-      double d;
-      List_Read(kv, i, &d);
-      c->k[i] = (float)d /*((d-kvmin)/(kvmax-kvmin)) */ ;
-    }
-  }
-  List_Delete(Listint);
-  List_Delete(List1);
-  List_Delete(List2);
-
-  Listint = List_Create(10, 10, sizeof(int));
-  int l0 = -Loop[0];
-  List_Add(Listint, &l0);
-  List_Add(Listint, &Loop[1]);
-  List_Add(Listint, &Loop[2]);
-  int l3 = -Loop[3];
-  List_Add(Listint, &l3);
-
-  int topnew = NEWREG();
-  CreateNurbsSurfaceSupport(topnew, Order1, Order2, List, ku, kv);
-
-  int il = NEWREG();
-  SurfaceLoop *l = Create_SurfaceLoop(il, Listint);
-  Tree_Add(THEM->SurfaceLoops, &l);
-  List_Reset(Listint);
-  List_Add(Listint, &il);
-
-  Surface *s = Create_Surface(NEWREG(), MSH_SURF_TRIMMED);
-  setSurfaceGeneratrices(s, Listint);
-  s->Support = s;
-  End_Surface(s);
-  Tree_Add(THEM->Surfaces, &s);
-
-  List_Delete(Listint);
-  List_Delete(ListCP);
-}
-
diff --git a/Geo/GeoInterpolation.h b/Geo/GeoInterpolation.h
index a155eb95c7274e418d6b0c292219aa4ac6d8bc53..9b88643fc58b5ac1b12b1234631c664b3d50e7ad 100644
--- a/Geo/GeoInterpolation.h
+++ b/Geo/GeoInterpolation.h
@@ -53,10 +53,4 @@ Vertex InterpolateUBS (Curve * Curve, double u, int derivee);
 Vertex InterpolateNurbs (Curve * Curve, double u, int derivee);
 Vertex InterpolateNurbsSurface (Surface * s, double u, double v);
 
-void CreateNurbsSurface (int Num, int Order1, int Order2, List_T *, List_T *, List_T *);
-void CreateNurbsSurfaceSupport (int Num, int Order2, int Order1, 
-                                List_T * List, List_T *, List_T *);
-
 #endif
-
-
diff --git a/Geo/Makefile b/Geo/Makefile
index d7cf8727db41c1d4b9f22eeaddd000475bb3f587..f8ff8d4a6b672fbe8ab3c69a62e9b7f25d35010e 100644
--- a/Geo/Makefile
+++ b/Geo/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.116 2006-11-25 18:03:49 geuzaine Exp $
+# $Id: Makefile,v 1.117 2006-11-25 23:06:06 geuzaine Exp $
 #
 # Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 #
@@ -209,7 +209,7 @@ ExtrudeParams.o: ExtrudeParams.cpp ../Common/Gmsh.h ../Common/Message.h \
 Geo.o: Geo.cpp ../Common/Gmsh.h ../Common/Message.h ../DataStr/Malloc.h \
   ../DataStr/List.h ../DataStr/Tree.h ../DataStr/avl.h ../DataStr/Tools.h \
   ../DataStr/List.h ../DataStr/Tree.h ../Numeric/Numeric.h Geo.h \
-  ../Common/GmshDefines.h ExtrudeParams.h GeoInterpolation.h \
+  ../Common/GmshDefines.h ExtrudeParams.h GeoUtils.h GeoInterpolation.h \
   ../Common/Context.h
 GeoStringInterface.o: GeoStringInterface.cpp ../Common/Gmsh.h \
   ../Common/Message.h ../DataStr/Malloc.h ../DataStr/List.h \
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index 3b98dedbf4c0d9958c2c31bb9d775820ddeba6e7..dd5416148bd02e277ca1fef6b59570f55a0f5513 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -1,4 +1,4 @@
-// $Id: Generator.cpp,v 1.102 2006-11-25 20:08:39 geuzaine Exp $
+// $Id: Generator.cpp,v 1.103 2006-11-25 23:06:08 geuzaine Exp $
 //
 // Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 //
@@ -31,6 +31,7 @@
 #include "GModel.h"
 #include "BackgroundMesh.h"
 #include "SecondOrder.h"
+#include "OptimizeMesh.h"
 
 extern Context_T CTX;
 extern GModel *GMODEL;
@@ -281,9 +282,8 @@ void GenerateMesh(int ask)
 
   // Optimize quality
   if(GMODEL->getMeshStatus() == 3 && CTX.mesh.optimize)
-    Msg(GERROR, "Mesh optimize has yet to be reinterfaced");
-  //Optimize_Netgen();
-
+    OptimizeMesh();
+  
   // Create second order elements
   if(GMODEL->getMeshStatus() && CTX.mesh.order == 2) 
     Degre2(CTX.mesh.second_order_linear, CTX.mesh.second_order_incomplete);
diff --git a/Mesh/Makefile b/Mesh/Makefile
index d8790a9ee0d1d618ad382d5d81231db93da75d55..15d4f255b14ba936c49a163a6f77107551b3d685 100644
--- a/Mesh/Makefile
+++ b/Mesh/Makefile
@@ -1,4 +1,4 @@
-# $Id: Makefile,v 1.143 2006-11-25 21:56:46 geuzaine Exp $
+# $Id: Makefile,v 1.144 2006-11-25 23:06:08 geuzaine Exp $
 #
 # Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
 #
@@ -30,15 +30,16 @@ INCLUDE = -I../Numeric -I../Common -I../DataStr -I../Geo -I../Mesh\
           -I../contrib/Metis
 CFLAGS  =  ${OPTIM} ${FLAGS} ${INCLUDE} 
 
-SRC = DivideAndConquer.cpp \
+SRC = Generator.cpp \
+        meshGEdge.cpp \
+        meshGFace.cpp \
+          meshGFaceTransfinite.cpp \
+        meshGRegion.cpp \
+          meshGRegionDelaunayInsertion.cpp \
+      DivideAndConquer.cpp \
       BackgroundMesh.cpp \
       BDS.cpp \
-      Generator.cpp \
-      meshGEdge.cpp \
-      meshGFace.cpp \
-      meshGFaceTransfinite.cpp \
-      meshGRegionDelaunayInsertion.cpp \
-      meshGRegion.cpp \
+      OptimizeMesh.cpp \
       SecondOrder.cpp
 
 OBJ = ${SRC:.cpp=.o}
@@ -64,33 +65,6 @@ depend:
 	rm -f Makefile.new
 
 # DO NOT DELETE THIS LINE
-DivideAndConquer.o: DivideAndConquer.cpp ../Common/Gmsh.h \
-  ../Common/Message.h ../DataStr/Malloc.h ../DataStr/List.h \
-  ../DataStr/Tree.h ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h \
-  ../DataStr/Tree.h ../Numeric/Numeric.h DivideAndConquer.h \
-  ../Common/Context.h
-BackgroundMesh.o: BackgroundMesh.cpp ../Common/Gmsh.h ../Common/Message.h \
-  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
-  ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h ../DataStr/Tree.h \
-  ../Common/Views.h ../Common/ColorTable.h ../Common/VertexArray.h \
-  ../Common/SmoothNormals.h ../Numeric/Numeric.h \
-  ../Common/AdaptiveViews.h ../Common/GmshMatrix.h BackgroundMesh.h \
-  ../Common/Context.h ../Common/OctreePost.h ../Common/Octree.h \
-  ../Common/OctreeInternals.h
-BDS.o: BDS.cpp ../Numeric/Numeric.h ../Common/GmshMatrix.h BDS.h \
-  ../Geo/GFace.h ../Geo/GPoint.h ../Geo/GEntity.h ../Geo/Range.h \
-  ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
-  ../Common/GmshDefines.h ../Geo/GEdgeLoop.h ../Geo/GEdge.h \
-  ../Geo/GEntity.h ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/MVertex.h \
-  ../Geo/SPoint3.h ../Geo/GPoint.h ../Geo/SPoint2.h ../Geo/SVector3.h \
-  ../Geo/SPoint3.h ../Geo/SPoint3.h ../Geo/SPoint2.h ../Geo/MElement.h \
-  ../Geo/MVertex.h ../Geo/MEdge.h ../Geo/MVertex.h ../Geo/SVector3.h \
-  ../Common/Hash.h ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
-  ../Common/Context.h ../DataStr/List.h ../Geo/ExtrudeParams.h \
-  ../Geo/MElement.h ../Geo/SPoint2.h ../Geo/SVector3.h ../Geo/Pair.h \
-  ../Geo/ExtrudeParams.h ../Common/Views.h ../Common/ColorTable.h \
-  ../Common/VertexArray.h ../Common/SmoothNormals.h \
-  ../Common/AdaptiveViews.h ../Common/GmshMatrix.h ../Common/Message.h
 Generator.o: Generator.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
   ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h ../DataStr/Tree.h \
@@ -110,7 +84,7 @@ Generator.o: Generator.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/MElement.h ../Geo/SPoint2.h \
   ../Geo/SVector3.h ../Geo/Pair.h ../Geo/ExtrudeParams.h ../Geo/GRegion.h \
   ../Geo/GEntity.h ../Geo/MElement.h ../Geo/ExtrudeParams.h \
-  ../Geo/SBoundingBox3d.h BackgroundMesh.h SecondOrder.h
+  ../Geo/SBoundingBox3d.h BackgroundMesh.h SecondOrder.h OptimizeMesh.h
 meshGEdge.o: meshGEdge.cpp ../Common/Gmsh.h ../Common/Message.h \
   ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
   ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h ../DataStr/Tree.h \
@@ -154,6 +128,23 @@ meshGFaceTransfinite.o: meshGFaceTransfinite.cpp meshGFace.h \
   ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/MElement.h ../Geo/SPoint2.h \
   ../Geo/SVector3.h ../Geo/Pair.h ../Geo/ExtrudeParams.h \
   ../Common/Message.h
+meshGRegion.o: meshGRegion.cpp meshGRegion.h ../Geo/GModel.h \
+  ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
+  ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Common/GmshDefines.h \
+  ../Geo/MVertex.h ../Geo/SPoint3.h ../Geo/GPoint.h ../Geo/SPoint2.h \
+  ../Geo/GEdge.h ../Geo/GEntity.h ../Geo/GVertex.h ../Geo/SVector3.h \
+  ../Geo/SPoint3.h ../Geo/SPoint3.h ../Geo/SPoint2.h ../Geo/MElement.h \
+  ../Geo/MVertex.h ../Geo/MEdge.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Common/Hash.h ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Numeric/Numeric.h ../Common/Context.h ../DataStr/List.h \
+  ../Geo/ExtrudeParams.h ../Geo/GFace.h ../Geo/GPoint.h ../Geo/GEntity.h \
+  ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/MElement.h ../Geo/SPoint2.h \
+  ../Geo/SVector3.h ../Geo/Pair.h ../Geo/ExtrudeParams.h ../Geo/GRegion.h \
+  ../Geo/GEntity.h ../Geo/MElement.h ../Geo/ExtrudeParams.h \
+  ../Geo/SBoundingBox3d.h ../Common/SmoothNormals.h BDS.h \
+  ../Common/Views.h ../Common/ColorTable.h ../Common/VertexArray.h \
+  ../Common/SmoothNormals.h ../Common/AdaptiveViews.h \
+  ../Common/GmshMatrix.h ../Common/Message.h
 meshGRegionDelaunayInsertion.o: meshGRegionDelaunayInsertion.cpp \
   meshGRegionDelaunayInsertion.h ../Geo/MElement.h \
   ../Common/GmshDefines.h ../Geo/MVertex.h ../Geo/SPoint3.h \
@@ -163,8 +154,35 @@ meshGRegionDelaunayInsertion.o: meshGRegionDelaunayInsertion.cpp \
   ../Geo/GRegion.h ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
   ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Geo/MElement.h \
   ../Geo/ExtrudeParams.h ../Common/Message.h
-meshGRegion.o: meshGRegion.cpp meshGRegion.h ../Geo/GModel.h \
-  ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
+DivideAndConquer.o: DivideAndConquer.cpp ../Common/Gmsh.h \
+  ../Common/Message.h ../DataStr/Malloc.h ../DataStr/List.h \
+  ../DataStr/Tree.h ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h \
+  ../DataStr/Tree.h ../Numeric/Numeric.h DivideAndConquer.h \
+  ../Common/Context.h
+BackgroundMesh.o: BackgroundMesh.cpp ../Common/Gmsh.h ../Common/Message.h \
+  ../DataStr/Malloc.h ../DataStr/List.h ../DataStr/Tree.h \
+  ../DataStr/avl.h ../DataStr/Tools.h ../DataStr/List.h ../DataStr/Tree.h \
+  ../Common/Views.h ../Common/ColorTable.h ../Common/VertexArray.h \
+  ../Common/SmoothNormals.h ../Numeric/Numeric.h \
+  ../Common/AdaptiveViews.h ../Common/GmshMatrix.h BackgroundMesh.h \
+  ../Common/Context.h ../Common/OctreePost.h ../Common/Octree.h \
+  ../Common/OctreeInternals.h
+BDS.o: BDS.cpp ../Numeric/Numeric.h ../Common/GmshMatrix.h BDS.h \
+  ../Geo/GFace.h ../Geo/GPoint.h ../Geo/GEntity.h ../Geo/Range.h \
+  ../Geo/SPoint3.h ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h \
+  ../Common/GmshDefines.h ../Geo/GEdgeLoop.h ../Geo/GEdge.h \
+  ../Geo/GEntity.h ../Geo/GVertex.h ../Geo/GEntity.h ../Geo/MVertex.h \
+  ../Geo/SPoint3.h ../Geo/GPoint.h ../Geo/SPoint2.h ../Geo/SVector3.h \
+  ../Geo/SPoint3.h ../Geo/SPoint3.h ../Geo/SPoint2.h ../Geo/MElement.h \
+  ../Geo/MVertex.h ../Geo/MEdge.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Common/Hash.h ../Geo/MFace.h ../Geo/MVertex.h ../Geo/SVector3.h \
+  ../Common/Context.h ../DataStr/List.h ../Geo/ExtrudeParams.h \
+  ../Geo/MElement.h ../Geo/SPoint2.h ../Geo/SVector3.h ../Geo/Pair.h \
+  ../Geo/ExtrudeParams.h ../Common/Views.h ../Common/ColorTable.h \
+  ../Common/VertexArray.h ../Common/SmoothNormals.h \
+  ../Common/AdaptiveViews.h ../Common/GmshMatrix.h ../Common/Message.h
+OptimizeMesh.o: OptimizeMesh.cpp ../Geo/GModel.h ../Geo/GVertex.h \
+  ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
   ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Common/GmshDefines.h \
   ../Geo/MVertex.h ../Geo/SPoint3.h ../Geo/GPoint.h ../Geo/SPoint2.h \
   ../Geo/GEdge.h ../Geo/GEntity.h ../Geo/GVertex.h ../Geo/SVector3.h \
@@ -176,10 +194,8 @@ meshGRegion.o: meshGRegion.cpp meshGRegion.h ../Geo/GModel.h \
   ../Geo/GEdgeLoop.h ../Geo/GEdge.h ../Geo/MElement.h ../Geo/SPoint2.h \
   ../Geo/SVector3.h ../Geo/Pair.h ../Geo/ExtrudeParams.h ../Geo/GRegion.h \
   ../Geo/GEntity.h ../Geo/MElement.h ../Geo/ExtrudeParams.h \
-  ../Geo/SBoundingBox3d.h ../Common/SmoothNormals.h BDS.h \
-  ../Common/Views.h ../Common/ColorTable.h ../Common/VertexArray.h \
-  ../Common/SmoothNormals.h ../Common/AdaptiveViews.h \
-  ../Common/GmshMatrix.h ../Common/Message.h
+  ../Geo/SBoundingBox3d.h ../Common/SmoothNormals.h ../Common/Message.h \
+  ../Common/OS.h
 SecondOrder.o: SecondOrder.cpp ../Geo/GModel.h ../Geo/GVertex.h \
   ../Geo/GEntity.h ../Geo/Range.h ../Geo/SPoint3.h \
   ../Geo/SBoundingBox3d.h ../Geo/SPoint3.h ../Common/GmshDefines.h \
diff --git a/Mesh/OptimizeMesh.cpp b/Mesh/OptimizeMesh.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e8b8092b54685009c831ef1fe58db7adfa5e07c0
--- /dev/null
+++ b/Mesh/OptimizeMesh.cpp
@@ -0,0 +1,40 @@
+// $Id: OptimizeMesh.cpp,v 1.1 2006-11-25 23:06:08 geuzaine Exp $
+//
+// Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+// 
+// Please report all bugs and problems to <gmsh@geuz.org>.
+
+#include "GModel.h"
+#include "GRegion.h"
+#include "Message.h"
+#include "OS.h"
+
+extern GModel *GMODEL;
+
+void OptimizeMesh()
+{
+  Msg(STATUS1, "Optimizing order...");
+  double t1 = Cpu();
+
+  Msg(GERROR, "Mesh optimize needs to be reinterfaced");
+
+
+  double t2 = Cpu();
+  Msg(INFO, "Mesh optimize complete (%g s)", t2 - t1);
+  Msg(STATUS1, "Mesh");
+}
diff --git a/Mesh/OptimizeMesh.h b/Mesh/OptimizeMesh.h
new file mode 100644
index 0000000000000000000000000000000000000000..2b6488fb214af4e5d12db4ec54619a7e2771e11b
--- /dev/null
+++ b/Mesh/OptimizeMesh.h
@@ -0,0 +1,25 @@
+#ifndef _OPTIMIZE_MESH_H_
+#define _OPTIMIZE_MESH_H_
+
+// Copyright (C) 1997-2006 C. Geuzaine, J.-F. Remacle
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+// 
+// Please report all bugs and problems to <gmsh@geuz.org>.
+
+void OptimizeMesh();
+
+#endif