diff --git a/Common/ShapeFunctions.h b/Common/ShapeFunctions.h
new file mode 100644
index 0000000000000000000000000000000000000000..6f41b9400519cb4f0994504154c21a97c04bfccc
--- /dev/null
+++ b/Common/ShapeFunctions.h
@@ -0,0 +1,943 @@
+#ifndef _SHAPE_FUNCTIONS_H_
+#define _SHAPE_FUNCTIONS_H_
+
+// Copyright (C) 1997-2008 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 "Numeric.h"
+#include "Message.h"
+
+#define ONE  (1. + 1.e-6)
+#define ZERO (-1.e-6)
+
+class element{
+protected:
+  double *_x, *_y, *_z;
+public:
+  element(double *x, double *y, double *z) : _x(x), _y(y), _z(z) {}
+  virtual ~element(){}
+  virtual int getDimension() = 0;
+  virtual int getNumNodes() = 0;
+  virtual void getNode(int num, double &u, double &v, double &w) = 0;
+  virtual int getNumEdges() = 0;
+  virtual void getEdge(int num, int &start, int &end) = 0;
+  virtual int getNumGaussPoints() = 0;
+  virtual void getGaussPoint(int num, double &u, double &v, double &w, double &weight) = 0; 
+  virtual void getShapeFunction(int num, double u, double v, double w, double &s) = 0;
+  virtual void getGradShapeFunction(int num, double u, double v, double w, double s[3]) = 0;
+  double getJacobian(double u, double v, double w, double jac[3][3])
+  {
+    jac[0][0] = jac[0][1] = jac[0][2] = 0.;
+    jac[1][0] = jac[1][1] = jac[1][2] = 0.;
+    jac[2][0] = jac[2][1] = jac[2][2] = 0.;
+    double s[3];
+    switch(getDimension()){
+    case 3 :
+      for(int i = 0; i < getNumNodes(); i++) {
+        getGradShapeFunction(i, u, v, w, s);
+        jac[0][0] += _x[i] * s[0]; jac[0][1] += _y[i] * s[0]; jac[0][2] += _z[i] * s[0];
+        jac[1][0] += _x[i] * s[1]; jac[1][1] += _y[i] * s[1]; jac[1][2] += _z[i] * s[1];
+        jac[2][0] += _x[i] * s[2]; jac[2][1] += _y[i] * s[2]; jac[2][2] += _z[i] * s[2];
+      }
+      return fabs(
+        jac[0][0] * jac[1][1] * jac[2][2] + jac[0][2] * jac[1][0] * jac[2][1] +
+        jac[0][1] * jac[1][2] * jac[2][0] - jac[0][2] * jac[1][1] * jac[2][0] -
+        jac[0][0] * jac[1][2] * jac[2][1] - jac[0][1] * jac[1][0] * jac[2][2]);
+    case 2 :
+      for(int i = 0; i < getNumNodes(); i++) {
+        getGradShapeFunction(i, u, v, w, s);
+        jac[0][0] += _x[i] * s[0]; jac[0][1] += _y[i] * s[0]; jac[0][2] += _z[i] * s[0];
+        jac[1][0] += _x[i] * s[1]; jac[1][1] += _y[i] * s[1]; jac[1][2] += _z[i] * s[1];
+      }
+      {
+        double a[3], b[3], c[3];
+        a[0]= _x[1] - _x[0]; a[1]= _y[1] - _y[0]; a[2]= _z[1] - _z[0];
+        b[0]= _x[2] - _x[0]; b[1]= _y[2] - _y[0]; b[2]= _z[2] - _z[0];
+        prodve(a, b, c);
+        jac[2][0] = c[0]; jac[2][1] = c[1]; jac[2][2] = c[2]; 
+      }
+      return sqrt(SQR(jac[0][0] * jac[1][1] - jac[0][1] * jac[1][0]) +
+                  SQR(jac[0][2] * jac[1][0] - jac[0][0] * jac[1][2]) +
+                  SQR(jac[0][1] * jac[1][2] - jac[0][2] * jac[1][1]));
+    case 1:
+      for(int i = 0; i < getNumNodes(); i++) {
+        getGradShapeFunction(i, u, v, w, s);
+        jac[0][0] += _x[i] * s[0]; jac[0][1] += _y[i] * s[0]; jac[0][2] += _z[i] * s[0];
+      }
+      {
+        double a[3], b[3], c[3];
+        a[0]= _x[1] - _x[0]; a[1]= _y[1] - _y[0]; a[2]= _z[1] - _z[0];  
+        if((fabs(a[0]) >= fabs(a[1]) && fabs(a[0]) >= fabs(a[2])) ||
+           (fabs(a[1]) >= fabs(a[0]) && fabs(a[1]) >= fabs(a[2]))) {
+          b[0] = a[1]; b[1] = -a[0]; b[2] = 0.;
+        }
+        else {
+          b[0] = 0.; b[1] = a[2]; b[2] = -a[1];
+        }
+        prodve(a, b, c);
+        jac[1][0] = b[0]; jac[1][1] = b[1]; jac[1][2] = b[2]; 
+        jac[2][0] = c[0]; jac[2][1] = c[1]; jac[2][2] = c[2]; 
+      }
+      return sqrt(SQR(jac[0][0])+SQR(jac[0][1])+SQR(jac[0][2]));
+    default:
+      return 1.;
+    }
+  }
+  double interpolate(double val[], double u, double v, double w, int stride=1)
+  {
+    double sum = 0;
+    int j = 0;
+    for(int i = 0; i < getNumNodes(); i++){
+      double s;
+      getShapeFunction(i, u, v, w, s);
+      sum += val[j] * s;
+      j += stride;
+    }
+    return sum;
+  }
+  void interpolateGrad(double val[], double u, double v, double w, double f[3], int stride=1,
+                       double invjac[3][3]=NULL)
+  {
+    double dfdu[3] = {0., 0., 0.};
+    int j = 0;
+    for(int i = 0; i < getNumNodes(); i++){
+      double s[3];
+      getGradShapeFunction(i, u, v, w, s);
+      dfdu[0] += val[j] * s[0];
+      dfdu[1] += val[j] * s[1];
+      dfdu[2] += val[j] * s[2];
+      j += stride;
+    }
+    if(invjac){
+      matvec(invjac, dfdu, f);
+    }
+    else{
+      double jac[3][3], inv[3][3];
+      getJacobian(u, v, w, jac);
+      inv3x3(jac, inv);
+      matvec(inv, dfdu, f);
+    }
+  }
+  void interpolateCurl(double val[], double u, double v, double w, double f[3], int stride=3)
+  {
+    double fx[3], fy[3], fz[3], jac[3][3], inv[3][3];
+    getJacobian(u, v, w, jac);
+    inv3x3(jac, inv);
+    interpolateGrad(&val[0], u, v, w, fx, stride, inv);
+    interpolateGrad(&val[1], u, v, w, fy, stride, inv);
+    interpolateGrad(&val[2], u, v, w, fz, stride, inv);
+    f[0] = fz[1] - fy[2];
+    f[1] = -(fz[0] - fx[2]);
+    f[2] = fy[0] - fx[1];
+  }
+  double interpolateDiv(double val[], double u, double v, double w, int stride=3)
+  {
+    double fx[3], fy[3], fz[3], jac[3][3], inv[3][3];
+    getJacobian(u, v, w, jac);
+    inv3x3(jac, inv);
+    interpolateGrad(&val[0], u, v, w, fx, stride, inv);
+    interpolateGrad(&val[1], u, v, w, fy, stride, inv);
+    interpolateGrad(&val[2], u, v, w, fz, stride, inv);
+    return fx[0] + fy[1] + fz[2];
+  }
+  double integrate(double val[], int stride=1)
+  {
+    double sum = 0;
+    for(int i = 0; i < getNumGaussPoints(); i++){
+      double u, v, w, weight, jac[3][3];
+      getGaussPoint(i, u, v, w, weight);
+      double det = getJacobian(u, v, w, jac);
+      double d = interpolate(val, u, v, w, stride);
+      sum += d * weight * det;
+    }
+    return sum;
+  }
+  double integrateLevelsetPositive(double val[])
+  {
+    // FIXME: explain + generalize this
+    double ones[8] = {1., 1., 1., 1., 1., 1., 1., 1.};
+    double area = integrate(ones);
+    double sum = 0, sumabs = 0.;
+    for(int i = 0; i < getNumNodes(); i++){
+      sum += val[i];
+      sumabs += fabs(val[i]);           
+    }
+    double res = 0.;
+    if(sumabs)
+      res = area * (1 + sum/sumabs) * 0.5 ;
+    return res;
+  }
+  virtual double integrateCirculation(double val[])
+  {
+    Msg::Error("integrateCirculation not available for this element");
+    return 0.;
+  }
+  virtual double integrateFlux(double val[])
+  {
+    Msg::Error("integrateFlux not available for this element");
+    return 0.;
+  }
+  virtual void xyz2uvw(double xyz[3], double uvw[3])
+  {
+    // general newton routine for the nonlinear case (more efficient
+    // routines are implemented for simplices, where the basis
+    // functions are linear)
+    uvw[0] = uvw[1] = uvw[2] = 0.0;
+
+    int iter = 1, maxiter = 20;
+    double error = 1., tol = 1.e-6;
+    
+    while (error > tol && iter < maxiter){
+      double jac[3][3];
+      if(!getJacobian(uvw[0], uvw[1], uvw[2], jac)) break;
+        
+      double xn = 0., yn = 0., zn = 0.;
+      for (int i = 0; i < getNumNodes(); i++) {
+        double s;
+        getShapeFunction(i, uvw[0], uvw[1], uvw[2], s);
+        xn += _x[i] * s;
+        yn += _y[i] * s;
+        zn += _z[i] * s;
+      }
+      double inv[3][3];
+      inv3x3(jac, inv);
+      
+      double un = uvw[0] +
+        inv[0][0] * (xyz[0] - xn) + inv[1][0] * (xyz[1] - yn) + inv[2][0] * (xyz[2] - zn);
+      double vn = uvw[1] +
+        inv[0][1] * (xyz[0] - xn) + inv[1][1] * (xyz[1] - yn) + inv[2][1] * (xyz[2] - zn) ;
+      double wn = uvw[2] +
+        inv[0][2] * (xyz[0] - xn) + inv[1][2] * (xyz[1] - yn) + inv[2][2] * (xyz[2] - zn) ;
+      
+      error = sqrt(SQR(un - uvw[0]) + SQR(vn - uvw[1]) + SQR(wn - uvw[2]));
+      uvw[0] = un;
+      uvw[1] = vn;
+      uvw[2] = wn;
+      iter++ ;
+    }
+    //if(error > tol) Msg::Warning("Newton did not converge in xyz2uvw") ;
+  }
+  virtual int isInside(double u, double v, double w) = 0;
+  double maxEdgeLength()
+  {
+    double max = 0.;
+    for(int i = 0; i < getNumEdges(); i++){
+      int n1, n2;
+      getEdge(i, n1, n2);
+      double d = sqrt(SQR(_x[n1]-_x[n2]) + SQR(_y[n1]-_y[n2]) + SQR(_z[n1]-_z[n2]));
+      if(d > max) max = d;
+    }
+    return max;
+  }
+};
+
+class point : public element{
+public:
+  point(double *x, double *y, double *z) : element(x, y, z) {}
+  inline int getDimension(){ return 0; }
+  inline int getNumNodes(){ return 1; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    u = v = w = 0.;
+  }
+  inline int getNumEdges(){ return 0; }
+  void getEdge(int num, int &start, int &end)
+  {
+    start = end = 0;
+  }
+  inline int getNumGaussPoints(){ return 1; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    u = v = w = 0.;
+    weight = 1.;
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    switch(num) {
+    case 0  : s = 1.; break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    s[0] = s[1] = s[2] = 0.;
+  }
+  void xyz2uvw(double xyz[3], double uvw[3])
+  {
+    uvw[0] = uvw[1] = uvw[2] = 0.;
+  }
+  int isInside(double u, double v, double w)
+  {
+    return 1;
+  }
+};
+
+class line : public element{
+public:
+  line(double *x, double *y, double *z) : element(x, y, z) {}
+  inline int getDimension(){ return 1; }
+  inline int getNumNodes(){ return 2; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    v = w = 0.;
+    switch(num) {
+    case 0 : u = -1.; break;
+    case 1 : u =  1.; break;
+    default: u =  0.; break;
+    }
+  }
+  inline int getNumEdges(){ return 1; }
+  void getEdge(int num, int &start, int &end)
+  {
+    start = 0; end = 1;
+  }
+  inline int getNumGaussPoints(){ return 1; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    if(num < 0 || num > 0) return;
+    u = v = w = 0.;
+    weight = 2.;
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    switch(num) {
+    case 0  : s = 0.5 * (1.-u); break;
+    case 1  : s = 0.5 * (1.+u); break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    switch(num) {
+    case 0  : s[0] = -0.5; s[1] = 0.; s[2] = 0.; break;
+    case 1  : s[0] =  0.5; s[1] = 0.; s[2] = 0.; break;
+    default : s[0] = s[1] = s[2] = 0.; break;
+    }
+  }
+  double integrateCirculation(double val[])
+  {
+    double t[3] = {_x[1]-_x[0], _y[1]-_y[0], _z[1]-_z[0]};
+    norme(t);
+    double v[3];
+    for(int i = 0; i < 3; i++)
+      v[i] = integrate(&val[i], 3);
+    double d;
+    prosca(t, v, &d);
+    return d;
+  }
+  int isInside(double u, double v, double w)
+  {
+    if(u < -ONE || u > ONE)
+      return 0; 
+    return 1;
+  }
+};
+
+class triangle : public element{
+public:
+  triangle(double *x, double *y, double *z) : element(x, y, z) {}
+  inline int getDimension(){ return 2; }
+  inline int getNumNodes(){ return 3; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    w = 0.;
+    switch(num) {
+    case 0 : u = 0.; v = 0.; break;
+    case 1 : u = 1.; v = 0.; break;
+    case 2 : u = 0.; v = 1.; break;
+    default: u = 0.; v = 0.; break;
+    }
+  }
+  inline int getNumEdges(){ return 3; }
+  void getEdge(int num, int &start, int &end)
+  {
+    switch(num) {
+    case 0 : start = 0; end = 1; break;
+    case 1 : start = 1; end = 2; break;
+    case 2 : start = 2; end = 0; break;
+    default: start = end = 0; break;
+    }
+  }
+  inline int getNumGaussPoints(){ return 3; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    double u3[3] = {0.16666666666666,0.66666666666666,0.16666666666666};
+    double v3[3] = {0.16666666666666,0.16666666666666,0.66666666666666};
+    double p3[3] = {0.16666666666666,0.16666666666666,0.16666666666666};
+    if(num < 0 || num > 2) return;
+    u = u3[num];
+    v = v3[num];
+    w = 0.;
+    weight = p3[num];
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    switch(num){
+    case 0  : s = 1.-u-v; break;
+    case 1  : s =    u  ; break;
+    case 2  : s =      v; break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    switch(num) {
+    case 0  : s[0] = -1.; s[1] = -1.; s[2] =  0.; break;
+    case 1  : s[0] =  1.; s[1] =  0.; s[2] =  0.; break;
+    case 2  : s[0] =  0.; s[1] =  1.; s[2] =  0.; break;
+    default : s[0] = s[1] = s[2] = 0.; break;
+    }
+  }
+  double integrateFlux(double val[])
+  {
+    double t1[3] = {_x[1]-_x[0], _y[1]-_y[0], _z[1]-_z[0]};
+    double t2[3] = {_x[2]-_x[0], _y[2]-_y[0], _z[2]-_z[0]};
+    double n[3];
+    prodve(t1, t2, n);
+    norme(n);
+    double v[3];
+    for(int i = 0; i < 3; i++)
+      v[i] = integrate(&val[i], 3);
+    double d;
+    prosca(n, v, &d);
+    return d;
+  }
+#if 0 // faster, but only valid for triangles in the z=0 plane 
+  void xyz2uvw(double xyz[3], double uvw[3])
+  {
+    double mat[2][2], b[2];
+    mat[0][0] = _x[1] - _x[0];
+    mat[0][1] = _x[2] - _x[0];
+    mat[1][0] = _y[1] - _y[0];
+    mat[1][1] = _y[2] - _y[0];
+    b[0] = xyz[0] - _x[0];
+    b[1] = xyz[1] - _y[0];
+    sys2x2(mat, b, uvw);
+    uvw[2] = 0.;
+  }
+#endif
+  int isInside(double u, double v, double w)
+  {
+    if(u < ZERO || v < ZERO || u > (ONE - v))
+      return 0; 
+    return 1;
+  }
+};
+
+class quadrangle : public element{
+public:
+  quadrangle(double *x, double *y, double *z) : element(x, y, z) {}
+  inline int getDimension(){ return 2; }
+  inline int getNumNodes(){ return 4; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    w = 0.;
+    switch(num) {
+    case 0 : u = -1.; v = -1.; break;
+    case 1 : u =  1.; v = -1.; break;
+    case 2 : u =  1.; v =  1.; break;
+    case 3 : u = -1.; v =  1.; break;
+    default: u =  0.; v =  0.; break;
+    }
+  }
+  inline int getNumEdges(){ return 4; }
+  void getEdge(int num, int &start, int &end)
+  {
+    switch(num) {
+    case 0 : start = 0; end = 1; break;
+    case 1 : start = 1; end = 2; break;
+    case 2 : start = 2; end = 3; break;
+    case 3 : start = 3; end = 0; break;
+    default: start = end = 0; break;
+    }
+  }
+  inline int getNumGaussPoints(){ return 4; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    double u4[4] = {0.577350269189,-0.577350269189,0.577350269189,-0.577350269189};
+    double v4[4] = {0.577350269189,0.577350269189,-0.577350269189,-0.577350269189};
+    double p4[4] = {1.,1.,1.,1.};
+    if(num < 0 || num > 3) return;
+    u = u4[num];
+    v = v4[num];
+    w = 0.;
+    weight = p4[num];
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    switch(num) {
+    case 0  : s = 0.25 * (1.-u) * (1.-v); break;
+    case 1  : s = 0.25 * (1.+u) * (1.-v); break;
+    case 2  : s = 0.25 * (1.+u) * (1.+v); break;
+    case 3  : s = 0.25 * (1.-u) * (1.+v); break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    switch(num) {
+    case 0  : s[0] = -0.25 * (1.-v); s[1] = -0.25 * (1.-u); s[2] = 0.; break;
+    case 1  : s[0] =  0.25 * (1.-v); s[1] = -0.25 * (1.+u); s[2] = 0.; break;
+    case 2  : s[0] =  0.25 * (1.+v); s[1] =  0.25 * (1.+u); s[2] = 0.; break;
+    case 3  : s[0] = -0.25 * (1.+v); s[1] =  0.25 * (1.-u); s[2] = 0.; break;
+    default : s[0] = s[1] = s[2] = 0.; break;
+    }
+  }
+  double integrateFlux(double val[])
+  {
+    double t1[3] = {_x[1]-_x[0], _y[1]-_y[0], _z[1]-_z[0]};
+    double t2[3] = {_x[2]-_x[0], _y[2]-_y[0], _z[2]-_z[0]};
+    double n[3];
+    prodve(t1, t2, n);
+    norme(n);
+    double v[3];
+    for(int i = 0; i < 3; i++)
+      v[i] = integrate(&val[i], 3);
+    double d;
+    prosca(n, v, &d);
+    return d;
+  }
+  int isInside(double u, double v, double w)
+  {
+    if(u < -ONE || v < -ONE || u > ONE || v > ONE)
+      return 0;
+    return 1;
+  }
+};
+
+class tetrahedron : public element{
+public:
+  tetrahedron(double *x, double *y, double *z) : element(x, y, z) {}
+  inline int getDimension(){ return 3; }
+  inline int getNumNodes(){ return 4; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    switch(num) {
+    case 0 : u = 0.; v = 0.; w = 0.; break;
+    case 1 : u = 1.; v = 0.; w = 0.; break;
+    case 2 : u = 0.; v = 1.; w = 0.; break;
+    case 3 : u = 0.; v = 0.; w = 1.; break;
+    default: u = 0.; v = 0.; w = 0.; break;
+    }
+  }
+  inline int getNumEdges(){ return 6; }
+  void getEdge(int num, int &start, int &end)
+  {
+    switch(num) {
+    case 0 : start = 0; end = 1; break;
+    case 1 : start = 1; end = 2; break;
+    case 2 : start = 2; end = 0; break;
+    case 3 : start = 3; end = 0; break;
+    case 4 : start = 3; end = 2; break;
+    case 5 : start = 3; end = 1; break;
+    default: start = end = 0; break;
+    }
+  }
+  inline int getNumGaussPoints(){ return 4; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    double u4[4] = {0.138196601125,0.138196601125,0.138196601125,0.585410196625};
+    double v4[4] = {0.138196601125,0.138196601125,0.585410196625,0.138196601125};
+    double w4[4] = {0.138196601125,0.585410196625,0.138196601125,0.138196601125};
+    double p4[4] = {0.0416666666667,0.0416666666667,0.0416666666667,0.0416666666667};
+    if(num < 0 || num > 3) return;
+    u = u4[num];
+    v = v4[num];
+    w = w4[num];
+    weight = p4[num];
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    switch(num) {
+    case 0  : s = 1.-u-v-w; break;
+    case 1  : s =    u    ; break;
+    case 2  : s =      v  ; break;
+    case 3  : s =        w; break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    switch(num) {
+    case 0  : s[0] = -1.; s[1] = -1.; s[2] = -1.; break;
+    case 1  : s[0] =  1.; s[1] =  0.; s[2] =  0.; break;
+    case 2  : s[0] =  0.; s[1] =  1.; s[2] =  0.; break;
+    case 3  : s[0] =  0.; s[1] =  0.; s[2] =  1.; break;
+    default : s[0] = s[1] = s[2] = 0.; break;
+    }
+  }
+  void xyz2uvw(double xyz[3], double uvw[3])
+  {
+    double mat[3][3], b[3];
+    mat[0][0] = _x[1] - _x[0];
+    mat[0][1] = _x[2] - _x[0];
+    mat[0][2] = _x[3] - _x[0];
+    mat[1][0] = _y[1] - _y[0];
+    mat[1][1] = _y[2] - _y[0];
+    mat[1][2] = _y[3] - _y[0];
+    mat[2][0] = _z[1] - _z[0];
+    mat[2][1] = _z[2] - _z[0];
+    mat[2][2] = _z[3] - _z[0];
+    b[0] = xyz[0] - _x[0];
+    b[1] = xyz[1] - _y[0];
+    b[2] = xyz[2] - _z[0];
+    double det;
+    sys3x3(mat, b, uvw, &det);
+  }
+  int isInside(double u, double v, double w)
+  {
+    if(u < ZERO || v < ZERO || w < ZERO || u > (ONE - v - w))
+      return 0;
+    return 1;
+  }
+};
+
+class hexahedron : public element{
+public:
+  hexahedron(double *x, double *y, double *z) : element(x, y, z) {}
+  inline int getDimension(){ return 3; }
+  inline int getNumNodes(){ return 8; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    switch(num) {
+    case 0 : u = -1.; v = -1.; w = -1.; break;
+    case 1 : u =  1.; v = -1.; w = -1.; break;
+    case 2 : u =  1.; v =  1.; w = -1.; break;
+    case 3 : u = -1.; v =  1.; w = -1.; break;
+    case 4 : u = -1.; v = -1.; w =  1.; break;
+    case 5 : u =  1.; v = -1.; w =  1.; break;
+    case 6 : u =  1.; v =  1.; w =  1.; break;
+    case 7 : u = -1.; v =  1.; w =  1.; break;
+    default: u =  0.; v =  0.; w =  0.; break;
+    }
+  }
+  inline int getNumEdges(){ return 12; }
+  void getEdge(int num, int &start, int &end)
+  {
+    switch(num) {
+    case 0 : start = 0; end = 1; break;
+    case 1 : start = 0; end = 3; break;
+    case 2 : start = 0; end = 4; break;
+    case 3 : start = 1; end = 2; break;
+    case 4 : start = 1; end = 5; break;
+    case 5 : start = 2; end = 3; break;
+    case 6 : start = 2; end = 6; break;
+    case 7 : start = 3; end = 7; break;
+    case 8 : start = 4; end = 5; break;
+    case 9 : start = 4; end = 7; break;
+    case 10: start = 5; end = 6; break;
+    case 11: start = 6; end = 7; break;
+    default: start = end = 0; break;
+    }
+  }
+  inline int getNumGaussPoints(){ return 6; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    double u6[6] = { 0.40824826,  0.40824826, -0.40824826,
+                    -0.40824826, -0.81649658,  0.81649658};
+    double v6[6] = { 0.70710678, -0.70710678,  0.70710678, 
+                    -0.70710678,  0.,  0.};
+    double w6[6] = {-0.57735027, -0.57735027,  0.57735027,  
+                   0.57735027, -0.57735027,  0.57735027};
+    double p6[6] = { 1.3333333333,  1.3333333333,  1.3333333333,
+                     1.3333333333,  1.3333333333,  1.3333333333};
+    if(num < 0 || num > 5) return;
+    u = u6[num];
+    v = v6[num];
+    w = w6[num];
+    weight = p6[num];
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    switch(num) {
+    case 0  : s = (1.-u) * (1.-v) * (1.-w) * 0.125; break;
+    case 1  : s = (1.+u) * (1.-v) * (1.-w) * 0.125; break;
+    case 2  : s = (1.+u) * (1.+v) * (1.-w) * 0.125; break;
+    case 3  : s = (1.-u) * (1.+v) * (1.-w) * 0.125; break;
+    case 4  : s = (1.-u) * (1.-v) * (1.+w) * 0.125; break;
+    case 5  : s = (1.+u) * (1.-v) * (1.+w) * 0.125; break;
+    case 6  : s = (1.+u) * (1.+v) * (1.+w) * 0.125; break;
+    case 7  : s = (1.-u) * (1.+v) * (1.+w) * 0.125; break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    switch(num) {
+    case 0  : s[0] = -0.125 * (1.-v) * (1.-w);
+              s[1] = -0.125 * (1.-u) * (1.-w);
+              s[2] = -0.125 * (1.-u) * (1.-v); break;
+    case 1  : s[0] =  0.125 * (1.-v) * (1.-w);
+              s[1] = -0.125 * (1.+u) * (1.-w);
+              s[2] = -0.125 * (1.+u) * (1.-v); break;
+    case 2  : s[0] =  0.125 * (1.+v) * (1.-w);
+              s[1] =  0.125 * (1.+u) * (1.-w);
+              s[2] = -0.125 * (1.+u) * (1.+v); break;
+    case 3  : s[0] = -0.125 * (1.+v) * (1.-w);
+              s[1] =  0.125 * (1.-u) * (1.-w);
+              s[2] = -0.125 * (1.-u) * (1.+v); break;
+    case 4  : s[0] = -0.125 * (1.-v) * (1.+w);
+              s[1] = -0.125 * (1.-u) * (1.+w);
+              s[2] =  0.125 * (1.-u) * (1.-v); break;
+    case 5  : s[0] =  0.125 * (1.-v) * (1.+w);
+              s[1] = -0.125 * (1.+u) * (1.+w);
+              s[2] =  0.125 * (1.+u) * (1.-v); break;
+    case 6  : s[0] =  0.125 * (1.+v) * (1.+w);
+              s[1] =  0.125 * (1.+u) * (1.+w);
+              s[2] =  0.125 * (1.+u) * (1.+v); break;
+    case 7  : s[0] = -0.125 * (1.+v) * (1.+w);
+              s[1] =  0.125 * (1.-u) * (1.+w);
+              s[2] =  0.125 * (1.-u) * (1.+v); break;
+    default : s[0] = s[1] = s[2] = 0.; break;
+    }
+  }
+  int isInside(double u, double v, double w)
+  {
+    if(u < -ONE || v < -ONE || w < -ONE || u > ONE || v > ONE || w > ONE)
+      return 0;
+    return 1;
+  }
+};
+
+class prism : public element{
+public:
+  prism(double *x, double *y, double *z) : element(x, y, z) {};
+  inline int getDimension(){ return 3; }
+  inline int getNumNodes(){ return 6; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    switch(num) {
+    case 0 : u = 0.; v = 0.; w = -1.; break;
+    case 1 : u = 1.; v = 0.; w = -1.; break;
+    case 2 : u = 0.; v = 1.; w = -1.; break;
+    case 3 : u = 0.; v = 0.; w =  1.; break;
+    case 4 : u = 1.; v = 0.; w =  1.; break;
+    case 5 : u = 0.; v = 1.; w =  1.; break;
+    default: u = 0.; v = 0.; w =  0.; break;
+    }
+  }
+  inline int getNumEdges(){ return 9; }
+  void getEdge(int num, int &start, int &end)
+  {
+    switch(num) {
+    case 0 : start = 0; end = 1; break;
+    case 1 : start = 0; end = 2; break;
+    case 2 : start = 0; end = 3; break;
+    case 3 : start = 1; end = 2; break;
+    case 4 : start = 1; end = 4; break;
+    case 5 : start = 2; end = 5; break;
+    case 6 : start = 3; end = 4; break;
+    case 7 : start = 3; end = 5; break;
+    case 8 : start = 4; end = 5; break;
+    default: start = end = 0; break;
+    }
+  }
+  inline int getNumGaussPoints(){ return 6; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    double u6[6] = {0.166666666666666, 0.333333333333333, 0.166666666666666, 
+                   0.166666666666666, 0.333333333333333, 0.166666666666666};
+    double v6[6] = {0.166666666666666, 0.166666666666666, 0.333333333333333,
+                   0.166666666666666, 0.166666666666666, 0.333333333333333};
+    double w6[6] = {-0.577350269189, -0.577350269189, -0.577350269189,
+                   0.577350269189,  0.577350269189,  0.577350269189};
+    double p6[6] = {0.166666666666666,0.166666666666666,0.166666666666666,
+                    0.166666666666666,0.166666666666666,0.166666666666666,};
+    if(num < 0 || num > 5) return;
+    u = u6[num];
+    v = v6[num];
+    w = w6[num];
+    weight = p6[num];
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    switch(num) {
+    case 0  : s = (1.-u-v) * (1.-w) * 0.5; break;
+    case 1  : s =     u    * (1.-w) * 0.5; break;
+    case 2  : s =       v  * (1.-w) * 0.5; break;
+    case 3  : s = (1.-u-v) * (1.+w) * 0.5; break;
+    case 4  : s =     u    * (1.+w) * 0.5; break;
+    case 5  : s =       v  * (1.+w) * 0.5; break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    switch(num) {
+    case 0  : s[0] = -0.5 * (1.-w)   ; 
+              s[1] = -0.5 * (1.-w)   ;
+              s[2] = -0.5 * (1.-u-v) ; break ;
+    case 1  : s[0] =  0.5 * (1.-w)   ; 
+              s[1] =  0.             ;
+              s[2] = -0.5 * u        ; break ;
+    case 2  : s[0] =  0.             ; 
+              s[1] =  0.5 * (1.-w)   ;
+              s[2] = -0.5 * v        ; break ;
+    case 3  : s[0] = -0.5 * (1.+w)   ; 
+              s[1] = -0.5 * (1.+w)   ;
+              s[2] =  0.5 * (1.-u-v) ; break ;
+    case 4  : s[0] =  0.5 * (1.+w)   ; 
+              s[1] =  0.             ;
+              s[2] =  0.5 * u        ; break ;
+    case 5  : s[0] =  0.             ; 
+              s[1] =  0.5 * (1.+w)   ;
+              s[2] =  0.5 * v        ; break ;
+    default : s[0] = s[1] = s[2] = 0.; break;
+    }
+  }
+  int isInside(double u, double v, double w)
+  {
+    if(w > ONE || w < -ONE || u < ZERO || v < ZERO || u > (ONE - v))
+      return 0;
+    return 1;
+  }
+};
+
+class pyramid : public element{
+public:
+  pyramid(double *x, double *y, double *z) : element(x, y, z) {}
+  inline int getDimension(){ return 3; }
+  inline int getNumNodes(){ return 5; }
+  void getNode(int num, double &u, double &v, double &w)
+  {
+    switch(num) {
+    case 0 : u = -1.; v = -1.; w = 0.; break;
+    case 1 : u =  1.; v = -1.; w = 0.; break;
+    case 2 : u =  1.; v =  1.; w = 0.; break;
+    case 3 : u = -1.; v =  1.; w = 0.; break;
+    case 4 : u =  0.; v =  0.; w = 1.; break;
+    default: u =  0.; v =  0.; w = 0.; break;
+    }
+  }
+  inline int getNumEdges(){ return 8; }
+  void getEdge(int num, int &start, int &end)
+  {
+    switch(num) {
+    case 0 : start = 0; end = 1; break;
+    case 1 : start = 0; end = 3; break;
+    case 2 : start = 0; end = 4; break;
+    case 3 : start = 1; end = 2; break;
+    case 4 : start = 1; end = 4; break;
+    case 5 : start = 2; end = 3; break;
+    case 6 : start = 2; end = 4; break;
+    case 7 : start = 3; end = 4; break;
+    default: start = end = 0; break;
+    }
+  }
+  inline int getNumGaussPoints(){ return 8; }
+  void getGaussPoint(int num, double &u, double &v, double &w, double &weight)
+  {
+    double u8[8] = {0.3595161057791018,0.09633205020967324,
+                    0.3595161057791018,0.09633205020967324,
+                    0.6920507403468987,0.1854344369976602,
+                    0.6920507403468987,0.1854344369976602};
+    double v8[8] = {0.3595161057791018,0.3595161057791018,
+                    0.09633205020967324,0.09633205020967324,
+                    0.6920507403468987,0.6920507403468987,
+                    0.1854344369976602,0.1854344369976602};
+    double w8[8] = {0.544151844011225,0.544151844011225,
+                    0.544151844011225,0.544151844011225,
+                    0.122514822655441,0.122514822655441,
+                    0.122514822655441,0.122514822655441};
+    double p8[8] = {0.02519647051995625,0.02519647051995625,
+                    0.02519647051995625,0.02519647051995625,
+                    0.058136862813377,0.058136862813377,
+                    0.058136862813377,0.058136862813377};
+    if(num < 0 || num > 7) return;
+    u = u8[num];
+    v = v8[num];
+    w = w8[num];
+    weight = p8[num];
+  }
+  void getShapeFunction(int num, double u, double v, double w, double &s) 
+  {
+    double r;
+    if(w != 1. && num != 4) r = u*v*w / (1.-w);
+    else                    r = 0.;
+    switch(num) {
+    case 0  : s = 0.25 * ((1.-u) * (1.-v) - w + r); break;
+    case 1  : s = 0.25 * ((1.+u) * (1.-v) - w - r); break;
+    case 2  : s = 0.25 * ((1.+u) * (1.+v) - w + r); break;
+    case 3  : s = 0.25 * ((1.-u) * (1.+v) - w - r); break;
+    case 4  : s = w; break;
+    default : s = 0.; break;
+    }
+  }
+  void getGradShapeFunction(int num, double u, double v, double w, double s[3]) 
+  {
+    if(w == 1. && num != 4) {
+      s[0] =  0.25; 
+      s[1] =  0.25;
+      s[2] = -0.25; 
+    }
+    else{
+      switch(num) {
+      case 0  : s[0] = 0.25 * ( -(1.-v) + v*w/(1.-w) ) ;
+                s[1] = 0.25 * ( -(1.-u) + u*w/(1.-w) ) ;
+                s[2] = 0.25 * ( -1.     + u*v/SQR(1.-w) ) ; break ;
+      case 1  : s[0] = 0.25 * (  (1.-v) + v*w/(1.-w) ) ;
+                s[1] = 0.25 * ( -(1.+u) + u*w/(1.-w) ) ;
+                s[2] = 0.25 * ( -1.     + u*v/SQR(1.-w) ) ; break ;
+      case 2  : s[0] = 0.25 * (  (1.+v) + v*w/(1.-w) ) ;
+                s[1] = 0.25 * (  (1.+u) + u*w/(1.-w) ) ;
+                s[2] = 0.25 * ( -1.     + u*v/SQR(1.-w) ) ; break ;
+      case 3  : s[0] = 0.25 * ( -(1.+v) + v*w/(1.-w) ) ;
+                s[1] = 0.25 * (  (1.-u) + u*w/(1.-w) ) ;
+                s[2] = 0.25 * ( -1.     + u*v/SQR(1.-w) ) ; break ;
+      case 4  : s[0] = 0. ; 
+                s[1] = 0. ;
+                s[2] = 1. ; break ;
+      default : s[0] = s[1] = s[2] = 0.; break;
+      }
+    }
+  }
+  int isInside(double u, double v, double w)
+  {
+    if(u < (w - ONE) || u > (ONE - w) || v < (w - ONE) || v > (ONE - w) ||
+       w < ZERO || w > ONE)
+      return 0;
+    return 1;
+  }
+};
+
+class elementFactory{
+ public:
+  element* create(int numNodes, int dimension, double *x, double *y, double *z){
+    switch(dimension){
+    case 0: return new point(x, y, z);
+    case 1: return new line(x, y, z);
+    case 2: 
+      if(numNodes == 4) return new quadrangle(x, y, z);
+      else return new triangle(x, y, z);
+    case 3:
+      if(numNodes == 8) return new hexahedron(x, y, z);
+      else if(numNodes == 6) return new prism(x, y, z);
+      else if(numNodes == 5) return new pyramid(x, y, z);
+      else return new tetrahedron(x, y, z);
+    default: 
+      Msg::Error("Unknown type of element in factory");
+      return NULL;
+    }
+  }
+};
+
+#undef ONE
+#undef ZERO
+
+#endif
diff --git a/DataStr/List.cpp b/DataStr/List.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0d7d4c7ca1a12bafb42369d518bd4fec96a175b3
--- /dev/null
+++ b/DataStr/List.cpp
@@ -0,0 +1,625 @@
+// $Id: List.cpp,v 1.45 2008-05-04 08:31:11 geuzaine Exp $
+//
+// Copyright (C) 1997-2008 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>.
+//
+// Contributor(s):
+//   Marc Ume
+//
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "Malloc.h"
+#include "List.h"
+#include "Message.h"
+#include "SafeIO.h"
+
+static char *startptr;
+
+List_T *List_Create(int n, int incr, int size)
+{
+  List_T *liste;
+
+  if(n <= 0)
+    n = 1;
+  if(incr <= 0)
+    incr = 1;
+
+  liste = (List_T *) Malloc(sizeof(List_T));
+
+  liste->nmax = 0;
+  liste->incr = incr;
+  liste->size = size;
+  liste->n = 0;
+  liste->isorder = 0;
+  liste->array = NULL;
+
+  List_Realloc(liste, n);
+  return (liste);
+}
+
+void List_Delete(List_T * liste)
+{
+  if(!liste)
+    return;
+  Free(liste->array);
+  Free(liste);
+}
+
+void List_Realloc(List_T * liste, int n)
+{
+  if(n <= 0)
+    return;
+
+  if(liste->array == NULL) {
+    // This does not permit to allocate lists smaller that liste->incr:
+    //liste->nmax = ((n - 1) / liste->incr + 1) * liste->incr;
+    // So this is much better
+    liste->nmax = n;
+    liste->array = (char *)Malloc(liste->nmax * liste->size);
+  }
+  else if(n > liste->nmax) {
+    liste->nmax = ((n - 1) / liste->incr + 1) * liste->incr;
+    liste->array = (char *)Realloc(liste->array, liste->nmax * liste->size);
+  }
+}
+
+void List_Add(List_T * liste, void *data)
+{
+  liste->n++;
+
+  List_Realloc(liste, liste->n);
+  liste->isorder = 0;
+  memcpy(&liste->array[(liste->n - 1) * liste->size], data, liste->size);
+}
+
+int List_Nbr(List_T * liste)
+{
+  return (liste) ? liste->n : 0;
+}
+
+void List_Insert(List_T * liste, void *data,
+                 int (*fcmp) (const void *a, const void *b))
+{
+  if(List_Search(liste, data, fcmp) == 0)
+    List_Add(liste, data);
+}
+
+int List_Replace(List_T * liste, void *data,
+                 int (*fcmp) (const void *a, const void *b))
+{
+  void *ptr;
+
+  if(liste->isorder != 1)
+    List_Sort(liste, fcmp);
+  liste->isorder = 1;
+  ptr = (void *)bsearch(data, liste->array, liste->n, liste->size, fcmp);
+  if(ptr == NULL) {
+    List_Add(liste, data);
+    return (0);
+  }
+  else {
+    memcpy(ptr, data, liste->size);
+    return (1);
+  }
+}
+
+void List_Read(List_T * liste, int index, void *data)
+{
+  if((index < 0) || (index >= liste->n))
+    Msg::Fatal("Wrong list index (read)");
+  memcpy(data, &liste->array[index * liste->size], liste->size);
+}
+
+void List_Write(List_T * liste, int index, void *data)
+{
+  if((index < 0) || (index >= liste->n))
+    Msg::Error("Wrong list index (write)");
+  else {
+    liste->isorder = 0;
+    memcpy(&liste->array[index * liste->size], data, liste->size);
+  }
+}
+
+void List_Put(List_T * liste, int index, void *data)
+{
+  if(index < 0)
+    Msg::Error("Wrong list index (put)");
+  else {
+    if(index >= liste->n) {
+      liste->n = index + 1;
+      List_Realloc(liste, liste->n);
+      List_Write(liste, index, data);
+    }
+    else {
+      List_Write(liste, index, data);
+    }
+  }
+}
+
+void List_Pop(List_T * liste)
+{
+  if(liste->n > 0)
+    liste->n--;
+}
+
+void *List_Pointer(List_T * liste, int index)
+{
+  if((index < 0) || (index >= liste->n))
+    Msg::Fatal("Wrong list index (pointer)");
+
+  liste->isorder = 0;
+  return (&liste->array[index * liste->size]);
+}
+
+void *List_Pointer_NoChange(List_T * liste, int index)
+{
+  if((index < 0) || (index >= liste->n))
+    Msg::Fatal("Wrong list index (pointer)");
+
+  return (&liste->array[index * liste->size]);
+}
+
+void *List_Pointer_Fast(List_T * liste, int index)
+{
+  return (&liste->array[index * liste->size]);
+}
+
+void *List_Pointer_Test(List_T * liste, int index)
+{
+  if(!liste || (index < 0) || (index >= liste->n))
+    return NULL;
+
+  liste->isorder = 0;
+  return (&liste->array[index * liste->size]);
+}
+
+void List_Sort(List_T * liste, int (*fcmp) (const void *a, const void *b))
+{
+  qsort(liste->array, liste->n, liste->size, fcmp);
+}
+
+int List_Search(List_T * liste, void *data,
+                int (*fcmp) (const void *a, const void *b))
+{
+  void *ptr;
+
+  if(liste->isorder != 1) {
+    List_Sort(liste, fcmp);
+    liste->isorder = 1;
+  }
+  ptr = (void *)bsearch(data, liste->array, liste->n, liste->size, fcmp);
+  if(ptr == NULL)
+    return (0);
+  return (1);
+}
+
+int List_ISearch(List_T * liste, void *data,
+                 int (*fcmp) (const void *a, const void *b))
+{
+  void *ptr;
+
+  if(liste->isorder != 1)
+    List_Sort(liste, fcmp);
+  liste->isorder = 1;
+  ptr = (void *)bsearch(data, liste->array, liste->n, liste->size, fcmp);
+  if(ptr == NULL)
+    return (-1);
+  return (((long)ptr - (long)liste->array) / liste->size);
+}
+
+int List_ISearchSeq(List_T * liste, void *data,
+                    int (*fcmp) (const void *a, const void *b))
+{
+  int i;
+
+  if(!liste)
+    return -1;
+  i = 0;
+  while((i < List_Nbr(liste)) && fcmp(data, (void *)List_Pointer(liste, i)))
+    i++;
+  if(i == List_Nbr(liste))
+    i = -1;
+  return i;
+}
+
+int List_ISearchSeqPartial(List_T * liste, void *data, int i_Start,
+                           int (*fcmp) (const void *a, const void *b))
+{
+  int i;
+
+  if(!liste)
+    return -1;
+  i = i_Start;
+  while((i < List_Nbr(liste)) && fcmp(data, (void *)List_Pointer(liste, i)))
+    i++;
+  if(i == List_Nbr(liste))
+    i = -1;
+  return i;
+}
+
+int List_Query(List_T * liste, void *data,
+               int (*fcmp) (const void *a, const void *b))
+{
+  void *ptr;
+
+  if(liste->isorder != 1)
+    List_Sort(liste, fcmp);
+  liste->isorder = 1;
+  ptr = (void *)bsearch(data, liste->array, liste->n, liste->size, fcmp);
+  if(ptr == NULL)
+    return (0);
+
+  memcpy(data, ptr, liste->size);
+  return (1);
+}
+
+static void *lolofind(void *data, void *array, int n, int size,
+                      int (*fcmp) (const void *a, const void *b))
+{
+  char *ptr;
+  int i;
+
+  ptr = (char *)array;
+  for(i = 0; i < n; i++) {
+    if(fcmp(ptr, data) == 0)
+      break;
+    ptr += size;
+  }
+  if(i < n)
+    return (ptr);
+  return (NULL);
+}
+
+int List_LQuery(List_T *liste, void *data,
+                 int (*fcmp)(const void *a, const void *b), int first)
+{
+  char *ptr;
+  
+  if (first == 1) { 
+    ptr = (char *) lolofind(data,liste->array,liste->n,liste->size,fcmp);
+  }
+  else {
+    if (startptr != NULL)
+      ptr = (char *) lolofind(data,startptr,
+                              liste->n - (startptr-liste->array)/liste->size,
+                              liste->size,fcmp);
+    else
+      return(0);
+  }
+
+  if (ptr == NULL) return(0);
+
+  startptr =  ptr + liste->size;
+  if ( startptr >= ( liste->array + liste->n * liste->size))
+    startptr = NULL;
+  memcpy(data,ptr,liste->size);
+  return (1);
+}
+
+void *List_PQuery(List_T * liste, void *data,
+                  int (*fcmp) (const void *a, const void *b))
+{
+  void *ptr;
+
+  if(liste->isorder != 1)
+    List_Sort(liste, fcmp);
+  liste->isorder = 1;
+  ptr = (void *)bsearch(data, liste->array, liste->n, liste->size, fcmp);
+  return (ptr);
+}
+
+int List_Suppress(List_T * liste, void *data,
+                  int (*fcmp) (const void *a, const void *b))
+{
+  char *ptr;
+  int len;
+
+  ptr = (char *)List_PQuery(liste, data, fcmp);
+  if(ptr == NULL)
+    return (0);
+
+  liste->n--;
+  len = liste->n - (((long)ptr - (long)liste->array) / liste->size);
+  if(len > 0)
+    memmove(ptr, ptr + liste->size, len * liste->size);
+  return (1);
+}
+
+int List_PSuppress(List_T * liste, int index)
+{
+  char *ptr;
+  int len;
+
+  ptr = (char *)List_Pointer_NoChange(liste, index);
+  if(ptr == NULL)
+    return (0);
+
+  liste->n--;
+  len = liste->n - (((long)ptr - (long)liste->array) / liste->size);
+  if(len > 0)
+    memmove(ptr, ptr + liste->size, len * liste->size);
+  return (1);
+}
+
+void List_Invert(List_T * a, List_T * b)
+{
+  int i, N;
+  N = List_Nbr(a);
+  for(i = 0; i < N; i++) {
+    List_Add(b, List_Pointer(a, N - i - 1));
+  }
+}
+
+void List_Reset(List_T * liste)
+{
+  if(!liste)
+    return;
+  liste->n = 0;
+}
+
+void List_Action(List_T * liste, void (*action) (void *data, void *dummy))
+{
+  int i, dummy;
+
+  for(i = 0; i < List_Nbr(liste); i++) {
+    (*action) (List_Pointer_NoChange(liste, i), &dummy);
+  }
+
+}
+
+void List_Action_Inverse(List_T * liste,
+                         void (*action) (void *data, void *dummy))
+{
+  int i, dummy;
+
+  for(i = List_Nbr(liste); i > 0; i--) {
+    (*action) (List_Pointer_NoChange(liste, i - 1), &dummy);
+  }
+
+}
+
+void List_Copy(List_T * a, List_T * b)
+{
+  int i, N;
+  N = List_Nbr(a);
+  for(i = 0; i < N; i++) {
+    List_Add(b, List_Pointer(a, i));
+  }
+}
+
+void List_Merge(List_T * a, List_T * b)
+{
+  int i;
+
+  if(!a || !b) return;
+  for(i = 0; i < List_Nbr(a); i++) {
+    List_Add(b, List_Pointer_Fast(a, i));
+  }
+}
+
+void swap_bytes(char *array, int size, int n)
+{
+  int i, c;
+  char *x, *a;
+
+  x = (char *)Malloc(size);
+
+  for(i = 0; i < n; i++) {
+    a = &array[i * size];
+    memcpy(x, a, size);
+    for(c = 0; c < size; c++)
+      a[size - 1 - c] = x[c];
+  }
+
+  Free(x);
+}
+
+List_T *List_CreateFromFile(int n, int incr, int size, FILE * file, int format,
+                            int swap)
+{
+  int i, error = 0;
+  List_T *liste;
+
+  if(!n){
+    liste = List_Create(1, incr, size);
+    return liste;
+  }
+
+  liste = List_Create(n, incr, size);
+  liste->n = n;
+  switch (format) {
+  case LIST_FORMAT_ASCII:
+    if(size == sizeof(double)){
+      for(i = 0; i < n; i++){
+        if(!fscanf(file, "%lf", (double *)&liste->array[i * size])){
+          error = 1;
+          break;
+        }
+      }
+    }
+    else if(size == sizeof(float)){
+      for(i = 0; i < n; i++){
+        if(!fscanf(file, "%f", (float *)&liste->array[i * size])){
+          error = 1;
+          break;
+        }
+      }
+    }
+    else if(size == sizeof(int)){
+      for(i = 0; i < n; i++){
+        if(!fscanf(file, "%d", (int *)&liste->array[i * size])){
+          error = 1;
+          break;
+        }
+      }
+    }
+    else if(size == sizeof(char)){
+      for(i = 0; i < n; i++){
+        char c = (char)fgetc(file);
+        if(c == EOF){
+          error = 1;
+          break;
+        }
+        else{
+          liste->array[i * size] = c;
+        }
+      }
+    }
+    else{
+      Msg::Error("Bad type of data to create list from (size = %d)", size);
+      error = 1;
+    }
+    break;
+  case LIST_FORMAT_BINARY:
+    if(!fread(liste->array, size, n, file)){
+      error = 1;
+      break;
+    }
+    if(swap)
+      swap_bytes(liste->array, size, n);
+    break;
+  default:
+    Msg::Error("Unknown list format");
+    error = 1;
+    break;
+  }
+
+  if(error){
+    Msg::Error("Read error");
+    liste->n = 0;
+  }
+
+  return liste;
+}
+
+void List_WriteToFile(List_T * liste, FILE * file, int format)
+{
+  int i, n;
+
+  if(!(n = List_Nbr(liste)))
+    return;
+
+  switch (format) {
+  case LIST_FORMAT_ASCII:
+    if(liste->size == sizeof(double))
+      for(i = 0; i < n; i++)
+        fprintf(file, " %.16g", *((double *)&liste->array[i * liste->size]));
+    else if(liste->size == sizeof(float))
+      for(i = 0; i < n; i++)
+        fprintf(file, " %.16g", *((float *)&liste->array[i * liste->size]));
+    else if(liste->size == sizeof(int))
+      for(i = 0; i < n; i++)
+        fprintf(file, " %d", *((int *)&liste->array[i * liste->size]));
+    else if(liste->size == sizeof(char))
+      for(i = 0; i < n; i++)
+        fputc(*((char *)&liste->array[i * liste->size]), file);
+    else
+      Msg::Error("Bad type of data to write list to file (size = %d)",
+          liste->size);
+    break;
+  case LIST_FORMAT_BINARY:
+    safe_fwrite(liste->array, liste->size, n, file);
+    break;
+  default:
+    Msg::Error("Unknown list format");
+    break;
+  }
+}
+
+// For backward compatibility purposes:
+
+List_T *List_CreateFromFileOld(int n, int incr, int size, FILE * file, int format,
+                               int swap)
+{
+  int i, error = 0;
+  List_T *liste;
+
+  if(!n){
+    liste = List_Create(1, incr, size);
+    return liste;
+  }
+
+  liste = List_Create(n, incr, size);
+  liste->n = n;
+  switch (format) {
+  case LIST_FORMAT_ASCII:
+    if(size == sizeof(double)){
+      for(i = 0; i < n; i++){
+        if(!fscanf(file, "%lf", (double *)&liste->array[i * size])){
+          error = 1;
+          break;
+        }
+      }
+    }
+    else if(size == sizeof(float)){
+      for(i = 0; i < n; i++){
+        if(!fscanf(file, "%f", (float *)&liste->array[i * size])){
+          error = 1;
+          break;
+        }
+      }
+    }
+    else if(size == sizeof(int)){
+      for(i = 0; i < n; i++){
+        if(!fscanf(file, "%d", (int *)&liste->array[i * size])){
+          error = 1;
+          break;
+        }
+      }
+    }
+    else if(size == sizeof(char)){
+      for(i = 0; i < n; i++){
+        if(!fscanf(file, "%c", (char *)&liste->array[i * size])){
+          error = 1;
+          break;
+        }
+        if(liste->array[i * size] == '^')
+          liste->array[i * size] = '\0';
+      }
+    }
+    else {
+      Msg::Error("Bad type of data to create list from (size = %d)", size);
+      error = 1;
+    }
+    return liste;
+  case LIST_FORMAT_BINARY:
+    if(!fread(liste->array, size, n, file)){
+      error = 1;
+      break;
+    }
+    if(swap)
+      swap_bytes(liste->array, size, n);
+    return liste;
+  default:
+    Msg::Error("Unknown list format");
+    error = 1;
+    break;
+  }
+
+  if(error){
+    Msg::Error("Read error");
+    liste->n = 0;
+  }
+
+  return liste;
+}
diff --git a/DataStr/List.h b/DataStr/List.h
new file mode 100644
index 0000000000000000000000000000000000000000..a352caa8d60541fb2f53b1c3d62c5d6b5c121815
--- /dev/null
+++ b/DataStr/List.h
@@ -0,0 +1,81 @@
+#ifndef _LIST_H_
+#define _LIST_H_
+
+// Copyright (C) 1997-2008 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>.
+//
+// Contributor(s):
+//   Marc Ume
+//
+
+#include <stdio.h>
+
+#define LIST_FORMAT_ASCII       0
+#define LIST_FORMAT_BINARY      1
+
+class List_T {
+public:
+  int nmax;
+  int size;
+  int incr;
+  int n;
+  int isorder;
+  char *array;
+};
+
+List_T *List_Create(int n, int incr, int size);
+void    List_Delete(List_T *liste);
+void    List_Realloc(List_T *liste,int n);
+void    List_Add(List_T *liste, void *data);
+int     List_Nbr(List_T *liste);
+void    List_Insert(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b));
+int     List_Replace(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b));
+void    List_Read(List_T *liste, int index, void *data);
+void    List_Write(List_T *liste, int index, void *data);
+void    List_Put(List_T *liste, int index, void *data);
+void    List_Pop(List_T *liste);
+void   *List_Pointer(List_T *liste, int index);
+void   *List_Pointer_NoChange(List_T *liste, int index);
+void   *List_Pointer_Fast(List_T *liste, int index);
+void   *List_Pointer_Test(List_T *liste, int index);
+void    List_Sort(List_T *liste, int (*fcmp)(const void *a, const void *b));
+int     List_Search(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b));
+int     List_ISearch(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b));
+int     List_ISearchSeq(List_T *liste, void * data, int (*fcmp)(const void *a, const void *b));
+int     List_ISearchSeqPartial(List_T *liste, void * data, int i_Start,
+                               int (*fcmp)(const void *a, const void *b)) ;
+int     List_Query(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b));
+int     List_LQuery(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b), int first);
+void   *List_PQuery(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b));
+int     List_Suppress(List_T *liste, void *data, int (*fcmp)(const void *a, const void *b));
+int     List_PSuppress(List_T *liste, int index);
+void    List_Invert(List_T *a, List_T *b);
+void    List_Reset(List_T *liste);
+void    List_Action(List_T *liste, void (*action)(void *data, void *dummy));
+void    List_Action_Inverse(List_T *liste, void (*action)(void *data, void *dummy));
+void    List_Copy(List_T *a , List_T *b);
+void    List_Merge(List_T *a , List_T *b);
+List_T *List_CreateFromFile(int n, int incr, int size, FILE *file, int format, int swap);
+void    List_WriteToFile(List_T *liste, FILE *file, int format);
+
+// for backward compatibility
+List_T *List_CreateFromFileOld(int n, int incr, int size, FILE *file, int format, int swap);
+
+#endif
+
diff --git a/benchmarks/2d/Square-03.geo b/benchmarks/2d/Square-03.geo
new file mode 100644
index 0000000000000000000000000000000000000000..b303fff71b5032ba2f4dfbfbb591ec18f1e7ef78
--- /dev/null
+++ b/benchmarks/2d/Square-03.geo
@@ -0,0 +1,16 @@
+/******************************       
+Square uniformly meshed       
+******************************/       
+lc = .49999;        
+Point(1) = {0.0,0.0,0,lc};        
+Point(2) = {1,0.0,0,lc};        
+Point(3) = {1,1,0,lc};        
+Point(4) = {0,1,0,lc};  
+Point(5) = {0,2,0,lc};       
+Line(1) = {3,2};        
+Line(2) = {2,1};        
+Line(3) = {1,4};        
+Line(4) = {4,3};        
+Line Loop(5) = {1,2,3,4};        
+Plane Surface(6) = {5};        
+Line(7) = {4,5};
diff --git a/examples/cube.geo b/examples/cube.geo
deleted file mode 100644
index decdd4a696bb42dae6ae5bda42e91f3bb5b099e1..0000000000000000000000000000000000000000
--- a/examples/cube.geo
+++ /dev/null
@@ -1,83 +0,0 @@
-lcar1 = .0275;
-
-length = 0.25;
-height = 1.0;
-depth = 0.25;
-
-Point(newp) = {length/2,height/2,depth,lcar1}; /* Point      1 */
-Point(newp) = {length/2,height/2,0,lcar1}; /* Point      2 */
-Point(newp) = {-length/2,height/2,depth,lcar1}; /* Point      3 */
-Point(newp) = {-length/2,-height/2,depth,lcar1}; /* Point      4 */
-Point(newp) = {length/2,-height/2,depth,lcar1}; /* Point      5 */
-Point(newp) = {length/2,-height/2,0,lcar1}; /* Point      6 */
-Point(newp) = {-length/2,height/2,0,lcar1}; /* Point      7 */
-Point(newp) = {-length/2,-height/2,0,lcar1}; /* Point      8 */
-Line(1) = {3,1};
-Line(2) = {3,7};
-Line(3) = {7,2};
-Line(4) = {2,1};
-Line(5) = {1,5};
-Line(6) = {5,4};
-Line(7) = {4,8};
-Line(8) = {8,6};
-Line(9) = {6,5};
-Line(10) = {6,2};
-Line(11) = {3,4};
-Line(12) = {8,7};
-Line Loop(13) = {-6,-5,-1,11};
-Plane Surface(14) = {13};
-Line Loop(15) = {4,5,-9,10};
-Plane Surface(16) = {15};
-Line Loop(17) = {-3,-12,8,10};
-Plane Surface(18) = {17};
-Line Loop(19) = {7,12,-2,11};
-Plane Surface(20) = {19};
-Line Loop(21) = {-4,-3,-2,1};
-Plane Surface(22) = {21};
-Line Loop(23) = {8,9,6,7};
-Plane Surface(24) = {23};
-
-Surface Loop(25) = {14,24,-18,22,16,-20};
-Complex Volume(26) = {25};
-
-n = 21;
-
-/*
-sizex = 4;
-sizey = 6;
-sizez = 4;
-*/
-sizex = n*length;
-sizey = n*height;
-sizez = n*depth;
-
-sizex = 9;
-sizey = 33;
-sizez = 9;
-
-
-Transfinite Line {2,4,9,7} = sizez;
-Transfinite Line {11,5,10,12} = sizey;
-Transfinite Line {3,1,6,8} = sizex;
-
-Transfinite Surface {14} = {5,4,3,1};
-Transfinite Surface {16} = {6,2,1,5};
-Transfinite Surface {18} = {6,2,7,8};
-Transfinite Surface {20} = {3,7,8,4};
-Transfinite Surface {22} = {3,7,2,1};
-Transfinite Surface {24} = {4,8,6,5};
-
-Recombine Surface {14,16,18,20,22,24};
-
-Transfinite Volume {26} = {3,7,2,1,4,8,6,5};
-
-Physical Surface(200) = {14,16,18,20,24};
-
-Physical Volume(100) = {26};
-/*
-Mesh.use_cut_plane = 1;
-Mesh.cut_planea = 0;
-Mesh.cut_planeb = 0;
-Mesh.cut_planec = 1;
-Mesh.cut_planed = -0.125;
-*/
\ No newline at end of file
diff --git a/variables.msvc b/variables.msvc
new file mode 100644
index 0000000000000000000000000000000000000000..966725cab25d2cbbf3d005ab3a350770085f5297
--- /dev/null
+++ b/variables.msvc
@@ -0,0 +1,68 @@
+# This is a pre-filled variables file for building a blackbox version
+# of Gmsh with Microsoft Visual C++ (MSVC).
+#
+# This has been tested with MSVC 2003 and MSVC 2008.  See
+# doc/README.msvc for building instructions.
+
+# OS and host
+UNAME=WIN32MSVC
+HOSTNAME=localhost
+
+# The names of the C and C++ compilers
+CC=cl
+CXX=cl /EHsc /nologo /GR /MT
+
+# Use /MLd for single-thread debug mode
+#     /MTd for multi-thread debug mode
+#     /MT for multi-thread release mode
+
+# append different suffix for release or debug version of library
+ifneq (,${findstring MTd,${CXX}})
+  LIBSUFFIX=_d
+else
+  LIBSUFFIX=_r
+endif
+
+# increase stack size to 16Mb to avoid stack overflows in recursive 
+# tet classification for large 3D Delaunay grids
+LINKER=cl /F16777216
+
+# All compiler flags except optimization flags
+FLAGS=/DWIN32 /D_USE_MATH_DEFINES /DHAVE_NO_DLL /DHAVE_NO_VSNPRINTF /DHAVE_NO_SNPRINTF /DHAVE_NO_SOCKLEN_T /DHAVE_ANN /DHAVE_MATH_EVAL /DHAVE_TETGEN
+
+# Additional system includes ($INCLUDE is automatically defined by MSVC when
+# you launch the MSVC command prompt)
+SYSINCLUDE=/I"${INCLUDE}"
+
+# Compiler optimization flags
+OPTIM=/O2
+
+# Gmsh subdirectories
+GMSH_DIRS=Common DataStr Geo Mesh Post Numeric Parallel Parser Plugin contrib/ANN contrib/MathEval contrib/NR contrib/Tetgen
+
+# Gmsh libraries
+GMSH_LIBS=Common/Main.obj lib/*.lib
+
+# How you create a static library on this machine
+AR=LIB
+ARFLAGS=/OUT:
+RANLIB=true
+
+# The symbol used in front of compiler flags
+DASH=/
+
+# The extension to use for object files, libraries and executables
+OBJEXT=.obj
+LIBEXT=.lib
+EXEEXT=.exe
+
+# Installation directories
+prefix="S:\Lib\gmsh"
+exec_prefix=${prefix}
+bindir=${exec_prefix}/bin
+datadir=${datarootdir}
+datarootdir=${prefix}/share
+includedir=${prefix}/include
+libdir=${exec_prefix}/lib
+mandir=${datarootdir}/man
+infodir=${datarootdir}/info