diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt
index 4ed98e91e6e4d97f60a2de3fabfd815ca77a6c0e..b8763bb79e0f4b306e85930e005d68384d9e7ff0 100644
--- a/Geo/CMakeLists.txt
+++ b/Geo/CMakeLists.txt
@@ -34,6 +34,7 @@ set(SRC
   SOrientedBoundingBox.cpp
   GeomMeshMatcher.cpp
   MVertex.cpp
+  MEdge.cpp
   MFace.cpp
   MElement.cpp MElementOctree.cpp
     MLine.cpp MTriangle.cpp MQuadrangle.cpp MTetrahedron.cpp
diff --git a/Geo/MEdge.cpp b/Geo/MEdge.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..18a83bb5a7473caee99d9ea5b451ec045878f790
--- /dev/null
+++ b/Geo/MEdge.cpp
@@ -0,0 +1,63 @@
+// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+
+#include "MEdge.h"
+#include "Numeric.h"
+
+bool MEdge::isInside(MVertex *v) const
+{
+  double tol = MVertexLessThanLexicographic::tolerance;
+  MVertex *v0 = _v[0];
+  MVertex *v1 = _v[1];
+  MVertexLessThanLexicographic lt;
+  if(lt(v0, v1)){
+    v0 = _v[1]; v1 = _v[0];
+  }
+  double x = v->x(), y = v->y(), z = v->z();
+  double x0 = v0->x(), y0 = v0->y(), z0 = v0->z();
+  double x1 = v1->x(), y1 = v1->y(), z1 = v1->z();
+  if(fabs(x - x0) < tol && fabs(y - y0) < tol && fabs(z - z0) < tol)
+    return true;
+  if(fabs(x - x1) < tol && fabs(y - y1) < tol && fabs(z - z1) < tol)
+    return true;
+  if(x < x0 - tol || x > x1 + tol ||
+     y < std::min(y0, y1) - tol || y > std::max(y0, y1) + tol ||
+     z < std::min(z0, z1) - tol || z > std::max(z0, z1) + tol)
+    ;return false;
+  if(fabs(x1 - x0) > tol){
+    double tx = (x - x0) / (x1 - x0);
+    if(fabs(y1 - y0) > tol){
+      double ty = (y - y0) / (y1 - y0);
+      if(fabs(z1 - z0) > tol){
+        double tz = (z - z0) / (z1 - z0);
+        if(fabs(tx - ty) > tol || fabs(tx - tz) > tol)
+          return false;
+      }
+      else{
+        if(fabs(tx - ty) > tol)
+          return false;
+      }
+    }
+    else{
+      if(fabs(z1 - z0) > tol){
+        double tz = (z - z0) / (z1 - z0);
+        if(fabs(tx - tz) > tol)
+          return false;
+      }
+    }
+  }
+  else{
+    if(fabs(y1 - y0) > tol){
+      double ty = (y - y0) / (y1 - y0);
+      if(fabs(z1 - z0) > tol){
+        double tz = (z - z0) / (z1 - z0);
+        if(fabs(ty - tz) > tol)
+          return false;
+      }
+    }
+  }
+  return true;
+}
+
diff --git a/Geo/MEdge.h b/Geo/MEdge.h
index c80a0cbba64e52bf1256da0192ec9efa27587dfa..700a788f9e079d2e5e046917e6450ec266dabde8 100644
--- a/Geo/MEdge.h
+++ b/Geo/MEdge.h
@@ -84,6 +84,7 @@ class MEdge {
                    t * _v[1]->y() + (1. - t) * _v[0]->y(),
                    t * _v[1]->z() + (1. - t) * _v[0]->z());
   }
+  bool isInside(MVertex *v) const;
 };
 
 inline bool operator==(const MEdge &e1, const MEdge &e2)
diff --git a/Geo/MElementCut.cpp b/Geo/MElementCut.cpp
index 866d52238506717bbd26c04cdd4c09ba88d66342..6ef38440f58528c03a8041fd706cfa6cacb1fe7a 100644
--- a/Geo/MElementCut.cpp
+++ b/Geo/MElementCut.cpp
@@ -169,20 +169,51 @@ void MPolygon::_initVertices()
     SVector3 ni = _parts[i]->getFace(0).normal();
     if(dot(n, ni) < 0.) _parts[i]->revert();
   }
-
-  std::vector<MEdge> edg; // outer edges
+  // select only outer edges in vector edg
+  std::vector<MEdge> edg;
+  std::vector<MEdge> multiEdges;
   for(int j = 0; j < _parts[0]->getNumEdges(); j++)
     edg.push_back(_parts[0]->getEdge(j));
   for(unsigned int i = 1; i < _parts.size(); i++) {
-    for(int j = 0; j < 3; j++) {
+    for(int j = 0; j < _parts[i]->getNumEdges(); j++) {
+      bool found = false;
+      MEdge ed = _parts[i]->getEdge(j);
       int k;
-      for(k = edg.size() - 1; k >= 0; k--)
-        if(_parts[i]->getEdge(j) == edg[k])
-          break;
-      if(k < 0)
-        edg.push_back(_parts[i]->getEdge(j));
-      else
-        edg.erase(edg.begin() + k);
+      for(k = edg.size() - 1; k >= 0; k--){
+        if(ed == edg[k]){
+          edg.erase(edg.begin() + k);
+          found = true; break;
+        }
+      }
+      if(!found){
+        for(k = 0; k < multiEdges.size(); k++)
+          if(multiEdges[k].isInside(ed.getVertex(0)) &&
+             multiEdges[k].isInside(ed.getVertex(1))){
+            found = true; break;
+          }
+      }
+      if(!found){
+        for(k = edg.size() - 1; k >= 0; k--){
+          if(edg[k].isInside(ed.getVertex(0)) && edg[k].isInside(ed.getVertex(1))){
+            multiEdges.push_back(edg[k]);
+            edg.erase(edg.begin() + k);
+            found = true; break;
+          }
+        }
+      }
+      if(!found){
+        for(k = edg.size() - 1; k >= 0; k--){
+          if(ed.isInside(edg[k].getVertex(0)) && ed.isInside(edg[k].getVertex(1))){
+            edg.erase(edg.begin() + k);
+            int nbME = multiEdges.size();
+            if(nbME == 0 || multiEdges[nbME - 1] != ed)
+              multiEdges.push_back(ed);
+            found = true;
+          }
+        }
+      }
+      if(!found)
+        edg.push_back(ed);
     }
   }
 
diff --git a/contrib/DiscreteIntegration/Integration3D.cpp b/contrib/DiscreteIntegration/Integration3D.cpp
index 8219446b601dfe4e7f140807e64c0d1ef445542e..afa922c70eb17e293cf469a6163064818b050347 100644
--- a/contrib/DiscreteIntegration/Integration3D.cpp
+++ b/contrib/DiscreteIntegration/Integration3D.cpp
@@ -639,22 +639,23 @@ void DI_Element::setPolynomialOrder (int o) {
     mid_ = NULL;
   }
   polOrder_ = o;
-  switch (o) {
-  case 1 :
-    return;
-  case 2 :
-    mid_ = new DI_Point[nbMid()];
-    for(int i = 0; i < nbMid(); i++) {
-      std::vector<int> s(nbVert()); int n;
-      midV(i, &s[0], n);
-      double xc = 0, yc = 0, zc = 0;
-      for(int j = 0; j < n; j++){
-        xc += x(s[j]); yc += y(s[j]); zc += z(s[j]); }
-      mid_[i] = DI_Point(xc/n, yc/n, zc/n);
-    }
-    return;
-  default :
-    printf("Order %d function space not implemented ", o); print();
+
+  if(o == 1) return;
+
+  const polynomialBasis *fs = getFunctionSpace(o);
+  if(!fs) Msg::Error("Function space not implemented for this type of element");
+
+  mid_ = new DI_Point[nbMid()];
+  int j = nbVert();
+  int dim = getDim();
+  double u, v, w;
+  double xyz[3];
+  for(int i = 0; i < nbMid(); i++, j++) {
+    u = fs->points(j,0);
+    v = (dim > 1) ? fs->points(j,1) : 0.;
+    w = (dim > 2) ? fs->points(j,2) : 0.;
+    evalC(u, v, w, xyz, 1);
+    mid_[i] = DI_Point(xyz[0], xyz[1], xyz[2]);
   }
 }
 void DI_Element::setPolynomialOrder (int o, const DI_Element *e, const std::vector<gLevelset *> &RPNi) {
@@ -664,22 +665,23 @@ void DI_Element::setPolynomialOrder (int o, const DI_Element *e, const std::vect
     mid_ = NULL;
   }
   polOrder_ = o;
-  switch (o) {
-  case 1 :
-    return;
-  case 2 :
-    mid_ = new DI_Point[nbMid()];
-    for(int i = 0; i < nbMid(); i++) {
-      std::vector<int> s(nbVert()); int n;
-      midV(i, &s[0], n);
-      double xc = 0, yc = 0, zc = 0;
-      for(int j = 0; j < n; j++){
-        xc += x(s[j]); yc += y(s[j]); zc += z(s[j]); }
-      mid_[i] = DI_Point(xc/n, yc/n, zc/n, e, RPNi);
-    }
-    return;
-  default :
-    printf("Order %d function space not implemented ", o); print();
+
+  if(o == 1) return;
+
+  const polynomialBasis *fs = getFunctionSpace(o);
+  if(!fs) Msg::Error("Function space not implemented for this type of element");
+
+  mid_ = new DI_Point[nbMid()];
+  int j = nbVert();
+  int dim = getDim();
+  double u, v, w;
+  double xyz[3];
+  for(int i = 0; i < nbMid(); i++, j++) {
+    u = fs->points(j,0);
+    v = (dim > 1) ? fs->points(j,1) : 0.;
+    w = (dim > 2) ? fs->points(j,2) : 0.;
+    evalC(u, v, w, xyz, 1);
+    mid_[i] = DI_Point(xyz[0], xyz[1], xyz[2], e, RPNi);
   }
 }
 void DI_Element::addLs (const double *ls) {
@@ -1042,21 +1044,8 @@ bool DI_ElementLessThan::operator()(const DI_Element *e1, const DI_Element *e2)
 // DI_Line methods --------------------------------------------------------------------------------
 const polynomialBasis* DI_Line::getFunctionSpace(int o) const{
   int order = (o == -1) ? getPolynomialOrder() : o;
-  switch (order) {
-  case 0: return polynomialBases::find(MSH_LIN_1);
-  case 1: return polynomialBases::find(MSH_LIN_2);
-  case 2: return polynomialBases::find(MSH_LIN_3);
-  case 3: return polynomialBases::find(MSH_LIN_4);
-  case 4: return polynomialBases::find(MSH_LIN_5);
-  case 5: return polynomialBases::find(MSH_LIN_6);
-  case 6: return polynomialBases::find(MSH_LIN_7);
-  case 7: return polynomialBases::find(MSH_LIN_8);
-  case 8: return polynomialBases::find(MSH_LIN_9);
-  case 9: return polynomialBases::find(MSH_LIN_10);
-  case 10: return polynomialBases::find(MSH_LIN_11);
-  default: Msg::Error("Order %d line function space not implemented", order);
-  }
-  return 0;
+  int tag = polynomialBasis::getTag(TYPE_LIN, order);
+  return polynomialBases::find(tag);
 }
 
 void DI_Line::computeIntegral() {
@@ -1076,20 +1065,8 @@ void DI_Line::computeIntegral() {
 const polynomialBasis* DI_Triangle::getFunctionSpace(int o) const
 {
   int order = (o == -1) ? getPolynomialOrder() : o;
-  switch (order) {
-    case 0: return polynomialBases::find(MSH_TRI_1);
-    case 1: return polynomialBases::find(MSH_TRI_3);
-    case 2: return polynomialBases::find(MSH_TRI_6);
-    case 3: return polynomialBases::find(MSH_TRI_10);
-    case 4: return polynomialBases::find(MSH_TRI_15);
-    case 5: return polynomialBases::find(MSH_TRI_21);
-    case 6: return polynomialBases::find(MSH_TRI_28);
-    case 7: return polynomialBases::find(MSH_TRI_36);
-    case 8: return polynomialBases::find(MSH_TRI_45);
-    case 9: return polynomialBases::find(MSH_TRI_55);
-    case 10: return polynomialBases::find(MSH_TRI_66);
-    default: Msg::Error("Order %d triangle function space not implemented", order);
-  }
+  int tag = polynomialBasis::getTag(TYPE_TRI, order);
+  return polynomialBases::find(tag);
 }
 void DI_Triangle::computeIntegral() {
   integral_ = TriSurf(pt(0), pt(1), pt(2));
@@ -1112,20 +1089,8 @@ double DI_Triangle::quality() const {
 // DI_Quad methods --------------------------------------------------------------------------------
 const polynomialBasis* DI_Quad::getFunctionSpace(int o) const{
  int order = (o == -1) ? getPolynomialOrder() : o;
- switch (order) {
-    case 0: return polynomialBases::find(MSH_QUA_1);
-    case 1: return polynomialBases::find(MSH_QUA_4);
-    case 2: return polynomialBases::find(MSH_QUA_9);
-    case 3: return polynomialBases::find(MSH_QUA_16);
-    case 4: return polynomialBases::find(MSH_QUA_25);
-    case 5: return polynomialBases::find(MSH_QUA_36);
-    case 6: return polynomialBases::find(MSH_QUA_49);
-    case 7: return polynomialBases::find(MSH_QUA_64);
-    case 8: return polynomialBases::find(MSH_QUA_81);
-    case 9: return polynomialBases::find(MSH_QUA_100);
-    case 10: return polynomialBases::find(MSH_QUA_121);
-    default: Msg::Error("Order %d quadrangle function space not implemented", order);
-  }
+  int tag = polynomialBasis::getTag(TYPE_QUA, order);
+  return polynomialBases::find(tag);
 }
 
 void DI_Quad::computeIntegral() {
@@ -1148,20 +1113,8 @@ void DI_Quad::computeIntegral() {
 // DI_Tetra methods -------------------------------------------------------------------------------
 const polynomialBasis* DI_Tetra::getFunctionSpace(int o) const{
  int order = (o == -1) ? getPolynomialOrder() : o;
- switch (order) {
-    case 0: return polynomialBases::find(MSH_TET_1);
-    case 1: return polynomialBases::find(MSH_TET_4);
-    case 2: return polynomialBases::find(MSH_TET_10);
-    case 3: return polynomialBases::find(MSH_TET_20);
-    case 4: return polynomialBases::find(MSH_TET_35);
-    case 5: return polynomialBases::find(MSH_TET_56);
-    case 6: return polynomialBases::find(MSH_TET_84);
-    case 7: return polynomialBases::find(MSH_TET_120);
-    case 8: return polynomialBases::find(MSH_TET_165);
-    case 9: return polynomialBases::find(MSH_TET_220);
-    case 10: return polynomialBases::find(MSH_TET_286);
-    default: Msg::Error("Order %d tetrahedron function space not implemented", order);
-    }
+  int tag = polynomialBasis::getTag(TYPE_TET, order);
+  return polynomialBases::find(tag);
 }
 
 void DI_Tetra::computeIntegral() {
@@ -1175,19 +1128,8 @@ double DI_Tetra::quality() const {
 // Hexahedron methods -----------------------------------------------------------------------------
 const polynomialBasis* DI_Hexa::getFunctionSpace(int o) const{
   int order = (o == -1) ? getPolynomialOrder() : o;
-  switch (order) {
-    case 0: return polynomialBases::find(MSH_HEX_1);
-    case 1: return polynomialBases::find(MSH_HEX_8);
-    case 2: return polynomialBases::find(MSH_HEX_27);
-    case 3: return polynomialBases::find(MSH_HEX_64);
-    case 4: return polynomialBases::find(MSH_HEX_125);
-    case 5: return polynomialBases::find(MSH_HEX_216);
-    case 6: return polynomialBases::find(MSH_HEX_343);
-    case 7: return polynomialBases::find(MSH_HEX_512);
-    case 8: return polynomialBases::find(MSH_HEX_729);
-    case 9: return polynomialBases::find(MSH_HEX_1000);
-    default: Msg::Error("Order %d hex function space not implemented", order);
-    }
+  int tag = polynomialBasis::getTag(TYPE_HEX, order);
+  return polynomialBases::find(tag);
 }
 void DI_Hexa::computeIntegral() {
     integral_ = TetraVol(pt(0), pt(1), pt(3), pt(4)) + TetraVol(pt(1), pt(4), pt(5), pt(7))