diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index 4c36342817995af01719b56eceb07fb341033002..25aa269c9a3efb2814f97a9bc0f1c2063e07f705 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -355,6 +355,12 @@ void GModel::remove(int dim, int tag)
   }
 }
 
+void GModel::remove(const std::vector<std::pair<int, int> > &dimTags)
+{
+  for(unsigned int i = 0; i < dimTags.size(); i++)
+    remove(dimTags[i].first, dimTags[i].second);
+}
+
 void GModel::snapVertices()
 {
   viter vit = firstVertex();
@@ -431,73 +437,83 @@ void GModel::getEntitiesInBox(std::vector<GEntity*> &entities, SBoundingBox3d bo
   }
 }
 
-void GModel::getBoundaryTags(std::vector<int> inTags[4], std::vector<int> outTags[4],
+void GModel::getBoundaryTags(const std::vector<std::pair<int, int> > &inDimTags,
+                             std::vector<std::pair<int, int> > &outDimTags,
                              bool combined, bool oriented)
 {
-  for(int dim = 1; dim < 4; dim++){
-    for(unsigned int i = 0; i < inTags[dim].size(); i++){
-      if(dim == 3){
-        GRegion *gr = getRegionByTag(inTags[3][i]);
-        if(gr){
-          std::list<GFace*> faces(gr->faces());
-          std::list<int> orientations(gr->faceOrientations());
-          std::list<int>::iterator ito = orientations.begin();
-          for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
-            int tag = (*it)->tag();
-            if(oriented && ito != orientations.end()){
-              tag *= *ito;
-              ito++;
-            }
-            outTags[2].push_back(tag);
+  for(unsigned int i = 0; i < inDimTags.size(); i++){
+    int dim = inDimTags[i].first;
+    int tag = inDimTags[i].second;
+    if(dim == 3){
+      GRegion *gr = getRegionByTag(tag);
+      if(gr){
+        std::list<GFace*> faces(gr->faces());
+        std::list<int> orientations(gr->faceOrientations());
+        std::list<int>::iterator ito = orientations.begin();
+        for(std::list<GFace*>::iterator it = faces.begin(); it != faces.end(); it++){
+          int t = (*it)->tag();
+          if(oriented && ito != orientations.end()){
+            t *= *ito;
+            ito++;
           }
+          outDimTags.push_back(std::pair<int, int>(2, t));
         }
-        else
-          Msg::Error("Unknown model region with tag %d", inTags[3][i]);
-      }
-      else if(dim == 2){
-        GFace *gf = getFaceByTag(inTags[2][i]);
-        if(gf){
-          std::list<GEdge*> edges(gf->edges());
-          std::list<int> orientations(gf->edgeOrientations());
-          std::list<int>::iterator ito = orientations.begin();
-          for(std::list<GEdge*>::iterator it = edges.begin(); it != edges.end(); it++){
-            int tag = (*it)->tag();
-            if(oriented && ito != orientations.end()){
-              tag *= *ito;
-              ito++;
-            }
-            outTags[1].push_back(tag);
+      }
+      else
+        Msg::Error("Unknown model region with tag %d", tag);
+    }
+    else if(dim == 2){
+      GFace *gf = getFaceByTag(tag);
+      if(gf){
+        std::list<GEdge*> edges(gf->edges());
+        std::list<int> orientations(gf->edgeOrientations());
+        std::list<int>::iterator ito = orientations.begin();
+        for(std::list<GEdge*>::iterator it = edges.begin(); it != edges.end(); it++){
+          int t = (*it)->tag();
+          if(oriented && ito != orientations.end()){
+            t *= *ito;
+            ito++;
           }
+          outDimTags.push_back(std::pair<int, int>(1, t));
         }
-        else
-          Msg::Error("Unknown model face with tag %d", inTags[2][i]);
-      }
-      else if(dim == 1){
-        GEdge *ge = getEdgeByTag(inTags[1][i]);
-        if(ge){
-          if(ge->getBeginVertex())
-            outTags[0].push_back(ge->getBeginVertex()->tag());
-          if(ge->getEndVertex())
-            outTags[0].push_back(ge->getEndVertex()->tag());
-        }
-        else
-          Msg::Error("Unknown model edge with tag %d", inTags[1][i]);
       }
+      else
+        Msg::Error("Unknown model face with tag %d", tag);
+    }
+    else if(dim == 1){
+      GEdge *ge = getEdgeByTag(tag);
+      if(ge){
+        if(ge->getBeginVertex())
+          outDimTags.push_back(std::pair<int, int>(0, ge->getBeginVertex()->tag()));
+        if(ge->getEndVertex())
+          outDimTags.push_back(std::pair<int, int>(0, ge->getEndVertex()->tag()));
+      }
+      else
+        Msg::Error("Unknown model edge with tag %d", tag);
     }
+  }
 
-    if(combined){
-      // compute boundary of the combined shapes
-      std::set<int> comb;
-      for(unsigned int i = 0; i < outTags[dim-1].size(); i++){
-        std::set<int>::iterator it = comb.find(outTags[dim-1][i]);
-        if(it == comb.end())
-          comb.insert(outTags[dim-1][i]);
-        else
-          comb.erase(it);
+  if(combined){
+    // compute boundary of the combined shapes
+    std::set<int> c[3];
+    for(unsigned int i = 0; i < outDimTags.size(); i++){
+      int dim = outDimTags[i].first;
+      int tag = outDimTags[i].second;
+      if(dim >= 0 && dim < 3){
+        std::set<int>::iterator it = c[dim].find(tag);
+        std::set<int>::iterator itr = (oriented ? c[dim].find(-tag) : c[dim].end());
+        if(it == c[dim].end() && itr == c[dim].end())
+          c[dim].insert(tag);
+        else{
+          if(it != c[dim].end()) c[dim].erase(it);
+          if(oriented && itr != c[dim].end()) c[dim].erase(itr);
+        }
       }
-      outTags[dim-1].clear();
-      for(std::set<int>::iterator it = comb.begin(); it != comb.end(); it++)
-        outTags[dim-1].push_back(*it);
+    }
+    outDimTags.clear();
+    for(int dim = 0; dim < 3; dim++){
+      for(std::set<int>::iterator it = c[dim].begin(); it != c[dim].end(); it++)
+        outDimTags.push_back(std::pair<int, int>(dim, *it));
     }
   }
 }
diff --git a/Geo/GModel.h b/Geo/GModel.h
index 09961b1972df4ac8542f8488ea6e53afd59de924..46d2a762a9154f7f662ba95560ee269a72f66944 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -278,6 +278,7 @@ class GModel {
   void remove(GEdge *e);
   void remove(GVertex *v);
   void remove(int dim, int tag);
+  void remove(const std::vector<std::pair<int, int> > &dimTags);
 
   // snap vertices on model edges by using geometry tolerance
   void snapVertices();
@@ -290,7 +291,8 @@ class GModel {
                         int dim=-1) const;
 
   // get tags of entities of the boundary of the given input entities
-  void getBoundaryTags(std::vector<int> inTags[4], std::vector<int> outTags[4],
+  void getBoundaryTags(const std::vector<std::pair<int, int> > &inDimTags,
+                       std::vector<std::pair<int, int> > &outDimTags,
                        bool combined, bool oriented);
 
   // return the highest number associated with an elementary entity of
diff --git a/Geo/GModelIO_GEO.cpp b/Geo/GModelIO_GEO.cpp
index 42e138dedb048e1322f193b6c4c6af61c8b366b6..41f21f3db9e8754921846a1075895f1d0f856f0b 100644
--- a/Geo/GModelIO_GEO.cpp
+++ b/Geo/GModelIO_GEO.cpp
@@ -446,23 +446,97 @@ void GEO_Internals::addCompoundVolume(int num, std::vector<int> regionTags)
   _changed = true;
 }
 
-void GEO_Internals::_transform(std::vector<int> tags[4], int mode,
+void GEO_Internals::_extrude(int mode,
+                             const std::vector<std::pair<int, int> > &inDimTags,
+                             double x, double y, double z,
+                             double dx, double dy, double dz,
+                             double ax, double ay, double az, double angle,
+                             std::vector<std::pair<int, int> > &outDimTags,
+                             ExtrudeParams *e)
+{
+  List_T *in = List_Create(inDimTags.size() + 1, 10, sizeof(Shape));
+  List_T *out = List_Create(3 * inDimTags.size() + 1, 10, sizeof(Shape));
+
+  for(unsigned int i = 0; i < inDimTags.size(); i++){
+    int dim = inDimTags[i].first;
+    int tag = inDimTags[i].second;
+    Shape s;
+    s.Type = (dim == 3) ? MSH_VOLUME : (dim == 2) ? MSH_SURF_PLAN :
+      (dim == 1) ? MSH_SEGM_LINE : MSH_POINT;
+    s.Num = tag;
+    List_Add(in, &s);
+  }
+
+  if(mode == 0){ // extrude
+    ExtrudeShapes(TRANSLATE, in, dx, dy, dz, 0., 0., 0., 0., 0., 0., 0., e, out);
+  }
+  else if(mode == 1){ // revolve
+    ExtrudeShapes(ROTATE, in, 0., 0., 0., ax, ay, az, x, y, z, angle, e, out);
+  }
+  else if(mode == 2){ // extrude+revolve
+    ExtrudeShapes(TRANSLATE_ROTATE, in, dx, dy, dz, ax, ay, az, x, y, z, angle, e, out);
+  }
+  else if(mode == 3){ // boundary layer
+    ExtrudeShapes(BOUNDARY_LAYER, in, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., e, out);
+  }
+
+  for(int i = 0; i < List_Nbr(out); i++){
+    Shape s;
+    List_Read(out, i, &s);
+    int dim = s.Type / 100 - 1;
+    if(dim >= 0 && dim <= 3) outDimTags.push_back(std::pair<int, int>(dim, s.Num));
+  }
+}
+
+void GEO_Internals::extrude(const std::vector<std::pair<int, int> > &inDimTags,
+                            double dx, double dy, double dz,
+                            std::vector<std::pair<int, int> > &outDimTags,
+                            ExtrudeParams *e)
+{
+  _extrude(0, inDimTags, 0., 0., 0., dx, dy, dz, 0., 0., 0., 0., outDimTags, e);
+}
+
+void GEO_Internals::revolve(const std::vector<std::pair<int, int> > &inDimTags,
+                            double x, double y, double z,
+                            double ax, double ay, double az, double angle,
+                            std::vector<std::pair<int, int> > &outDimTags,
+                            ExtrudeParams *e)
+{
+  _extrude(1, inDimTags, x, y, z, 0., 0., 0., ax, ay, az, angle, outDimTags, e);
+}
+
+void GEO_Internals::twist(const std::vector<std::pair<int, int> > &inDimTags,
+                          double x, double y, double z,
+                          double dx, double dy, double dz,
+                          double ax, double ay, double az, double angle,
+                          std::vector<std::pair<int, int> > &outDimTags,
+                          ExtrudeParams *e)
+{
+  _extrude(2, inDimTags, x, y, z, dx, dy, dz, ax, ay, az, angle, outDimTags, e);
+}
+
+void GEO_Internals::boundaryLayer(const std::vector<std::pair<int, int> > &inDimTags,
+                                  std::vector<std::pair<int, int> > &outDimTags,
+                                  ExtrudeParams *e)
+{
+  _extrude(3, inDimTags, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., outDimTags, e);
+}
+
+void GEO_Internals::_transform(int mode,
+                               const std::vector<std::pair<int, int> > &dimTags,
                                double x, double y, double z,
                                double dx, double dy, double dz,
                                double a, double b, double c, double d)
 {
-  List_T *list = List_Create(10, 10, sizeof(Shape));
-  for(int dim = 0; dim < 4; dim++){
+  List_T *list = List_Create(dimTags.size() + 1, 10, sizeof(Shape));
+  for(unsigned int i = 0; i < dimTags.size(); i++){
+    int dim = dimTags[i].first;
+    int tag = dimTags[i].second;
     Shape s;
-    s.Type =
-      (dim == 3) ? MSH_VOLUME :
-      (dim == 2) ? MSH_SURF_PLAN :
-      (dim == 1) ? MSH_SEGM_LINE :
-      MSH_POINT;
-    for(unsigned int i = 0; i < tags[dim].size(); i++){
-      s.Num = tags[dim][i];
-      List_Add(list, &s);
-    }
+    s.Type = (dim == 3) ? MSH_VOLUME : (dim == 2) ? MSH_SURF_PLAN :
+      (dim == 1) ? MSH_SEGM_LINE : MSH_POINT;
+    s.Num = tag;
+    List_Add(list, &s);
   }
   switch(mode){
   case 0: TranslateShapes(dx, dy, dz, list); break;
@@ -473,71 +547,122 @@ void GEO_Internals::_transform(std::vector<int> tags[4], int mode,
   _changed = true;
 }
 
-void GEO_Internals::translate(std::vector<int> tags[4],
+void GEO_Internals::translate(const std::vector<std::pair<int, int> > &dimTags,
                               double dx, double dy, double dz)
 {
-  _transform(tags, 0, 0, 0, 0, dx, dy, dz, 0, 0, 0, 0);
+  _transform(0, dimTags, 0, 0, 0, dx, dy, dz, 0, 0, 0, 0);
 }
 
-void GEO_Internals::rotate(std::vector<int> tags[4],
+void GEO_Internals::rotate(const std::vector<std::pair<int, int> > &dimTags,
                            double x, double y, double z,
-                           double dx, double dy, double dz, double angle)
+                           double ax, double ay, double az, double angle)
 {
-  _transform(tags, 1, x, y, z, dx, dy, dz, angle, 0, 0, 0);
+  _transform(1, dimTags, x, y, z, ax, ay, az, angle, 0, 0, 0);
 }
 
-void GEO_Internals::dilate(std::vector<int> tags[4],
+void GEO_Internals::dilate(const std::vector<std::pair<int, int> > &dimTags,
                            double x, double y, double z,
                            double a, double b, double c)
 {
-  _transform(tags, 2, x, y, z, 0, 0, 0, a, b, c, 0);
+  _transform(2, dimTags, x, y, z, 0, 0, 0, a, b, c, 0);
 }
 
-void GEO_Internals::symmetry(std::vector<int> tags[4],
+void GEO_Internals::symmetry(const std::vector<std::pair<int, int> > &dimTags,
                              double a, double b, double c, double d)
 {
-  _transform(tags, 3, 0, 0, 0, 0, 0, 0, a, b, c, d);
+  _transform(3, dimTags, 0, 0, 0, 0, 0, 0, a, b, c, d);
 }
 
-int GEO_Internals::copy(int dim, int tag)
+void GEO_Internals::splitCurve(int tag, const std::vector<int> &vertexTags,
+                               std::vector<int> &edgeTags)
 {
-  _changed = true;
-  if(dim == 0){
-    Vertex *v = FindPoint(tag);
-    if(!v){
-      Msg::Error("Unknown GEO vertex with tag %d", tag);
-      return tag;
-    }
-    Vertex *newv = DuplicateVertex(v);
-    return newv->Num;
+  List_T *tmp = List_Create(10, 10, sizeof(int));
+  for(unsigned int i = 0; i < vertexTags.size(); i++){
+    int t = vertexTags[i];
+    List_Add(tmp, &t);
+  }
+  List_T *curves = List_Create(10, 10, sizeof(Curve *));
+  SplitCurve(tag, tmp, curves);
+  for(int i = 0; i < List_Nbr(curves); i++){
+    Curve *c;
+    List_Read(curves, i, &c);
+    edgeTags.push_back(c->Num);
   }
-  else if(dim == 1){
-    Curve *c = FindCurve(tag);
-    if(!c){
-      Msg::Error("Unknown GEO curve with tag %d", tag);
-      return tag;
+  List_Delete(tmp);
+  List_Delete(curves);
+}
+
+void GEO_Internals::intersectCurvesWithSurface(const std::vector<int> &edgeTags,
+                                               int faceTag,
+                                               std::vector<int> &vertexTags)
+{
+  List_T *curves = List_Create(10, 10, sizeof(double));
+  List_T *shapes = List_Create(10, 10, sizeof(Shape));
+  for(unsigned int i = 0; i < edgeTags.size(); i++){
+    double d = edgeTags[i];
+    List_Add(curves, &d);
+  }
+  IntersectCurvesWithSurface(curves, faceTag, shapes);
+  for(int i = 0; i < List_Nbr(shapes); i++){
+    Shape s;
+    List_Read(shapes, i, &s);
+    if(s.Type == MSH_POINT){
+      vertexTags.push_back(s.Num);
     }
-    Curve *newc = DuplicateCurve(c);
-    return newc->Num;
-  }
-  else if(dim == 2){
-    Surface *s = FindSurface(tag);
-    if(!s){
-      Msg::Error("Unknown GEO surface with tag %d", tag);
-      return tag;
+    else{
+      Msg::Error("Degenrated curve surface intersection not implemented");
     }
-    Surface *news = DuplicateSurface(s);
-    return news->Num;
   }
-  else{
-    Volume *v = FindVolume(tag);
-    if(!v){
-      Msg::Error("Unknown GEO region with tag %d", tag);
-      return tag;
+}
+
+void GEO_Internals::copy(const std::vector<std::pair<int, int> > &inDimTags,
+                         std::vector<std::pair<int, int> > &outDimTags)
+{
+  for(unsigned int i = 0; i < inDimTags.size(); i++){
+    int dim = inDimTags[i].first;
+    int tag = inDimTags[i].second;
+    if(dim == 0){
+      Vertex *v = FindPoint(tag);
+      if(!v){
+        Msg::Error("Unknown GEO vertex with tag %d", tag);
+      }
+      else{
+        Vertex *newv = DuplicateVertex(v);
+        outDimTags.push_back(std::pair<int, int>(0, newv->Num));
+      }
+    }
+    else if(dim == 1){
+      Curve *c = FindCurve(tag);
+      if(!c){
+        Msg::Error("Unknown GEO curve with tag %d", tag);
+      }
+      else{
+        Curve *newc = DuplicateCurve(c);
+        outDimTags.push_back(std::pair<int, int>(1, newc->Num));
+      }
+    }
+    else if(dim == 2){
+      Surface *s = FindSurface(tag);
+      if(!s){
+        Msg::Error("Unknown GEO surface with tag %d", tag);
+      }
+      else{
+        Surface *news = DuplicateSurface(s);
+        outDimTags.push_back(std::pair<int, int>(2, news->Num));
+      }
+    }
+    else if(dim == 3){
+      Volume *v = FindVolume(tag);
+      if(!v){
+        Msg::Error("Unknown GEO region with tag %d", tag);
+      }
+      else{
+        Volume *newv = DuplicateVolume(v);
+        outDimTags.push_back(std::pair<int, int>(3, newv->Num));
+      }
     }
-    Volume *newv = DuplicateVolume(v);
-    return newv->Num;
   }
+  _changed = true;
 }
 
 void GEO_Internals::remove(int dim, int tag)
@@ -550,6 +675,12 @@ void GEO_Internals::remove(int dim, int tag)
   }
 }
 
+void GEO_Internals::remove(const std::vector<std::pair<int, int> > &dimTags)
+{
+  for(unsigned int i = 0; i < dimTags.size(); i++)
+    remove(dimTags[i].first, dimTags[i].second);
+}
+
 void GEO_Internals::resetPhysicalGroups()
 {
   List_Action(PhysicalGroups, FreePhysicalGroup);
diff --git a/Geo/GModelIO_GEO.h b/Geo/GModelIO_GEO.h
index ad6089b8a5f6baf0c90479115da6fb1cfa81f399..34d08fac22d57eb2923774fc50782e3e04fd8dc6 100644
--- a/Geo/GModelIO_GEO.h
+++ b/Geo/GModelIO_GEO.h
@@ -9,8 +9,9 @@
 #include "ListUtils.h"
 #include "TreeUtils.h"
 
-class gmshSurface;
 class GModel;
+class ExtrudeParams;
+class gmshSurface;
 
 class GEO_Internals{
  public:
@@ -24,10 +25,16 @@ class GEO_Internals{
   void _allocateAll();
   void _freeAll();
   bool _changed;
-  void _transform(std::vector<int> tags[4], int mode,
+  void _transform(int mode, const std::vector<std::pair<int, int> > &dimTags,
                   double x, double y, double z,
                   double dx, double dy, double dz,
                   double a, double b, double c, double d);
+  void _extrude(int mode, const std::vector<std::pair<int, int> > &inDimTags,
+                double x, double y, double z,
+                double dx, double dy, double dz,
+                double ax, double ay, double az, double angle,
+                std::vector<std::pair<int, int> > &outDimTags,
+                ExtrudeParams *e=0);
  public:
   GEO_Internals(){ _allocateAll(); }
   ~GEO_Internals(){ _freeAll(); }
@@ -65,17 +72,48 @@ class GEO_Internals{
   void addVolume(int num, std::vector<int> shellTags);
   void addCompoundVolume(int num, std::vector<int> regionTags);
 
+  // extrude and revolve
+  void extrude(const std::vector<std::pair<int, int> > &inDimTags,
+               double dx, double dy, double dz,
+               std::vector<std::pair<int, int> > &outDimTags,
+               ExtrudeParams *e=0);
+  void revolve(const std::vector<std::pair<int, int> > &inDimTags,
+               double x, double y, double z,
+               double ax, double ay, double az, double angle,
+               std::vector<std::pair<int, int> > &outDimTags,
+               ExtrudeParams *e=0);
+  void twist(const std::vector<std::pair<int, int> > &inDimTags,
+             double x, double y, double z,
+             double dx, double dy, double dz,
+             double ax, double ay, double az, double angle,
+             std::vector<std::pair<int, int> > &outDimTags,
+             ExtrudeParams *e=0);
+  void boundaryLayer(const std::vector<std::pair<int, int> > &inDimTags,
+                     std::vector<std::pair<int, int> > &outDimTags,
+                     ExtrudeParams *e=0);
+
   // apply transformations
-  void translate(std::vector<int> tags[4], double dx, double dy, double dz);
-  void rotate(std::vector<int> tags[4], double x, double y, double z,
-              double dx, double dy, double dz, double angle);
-  void dilate(std::vector<int> tags[4], double x, double y, double z,
-              double a, double b, double c);
-  void symmetry(std::vector<int> tags[4], double a, double b, double c, double d);
+  void translate(const std::vector<std::pair<int, int> > &dimTags,
+                 double dx, double dy, double dz);
+  void rotate(const std::vector<std::pair<int, int> > &dimTags,
+              double x, double y, double z, double ax, double ay, double az,
+              double angle);
+  void dilate(const std::vector<std::pair<int, int> > &dimTags,
+              double x, double y, double z, double a, double b, double c);
+  void symmetry(const std::vector<std::pair<int, int> > &dimTags,
+                double a, double b, double c, double d);
+
+  // split entities
+  void splitCurve(int tag, const std::vector<int> &vertexTags,
+                  std::vector<int> &edgeTags);
+  void intersectCurvesWithSurface(const std::vector<int> &edgeTags,
+                                  int faceTag, std::vector<int> &vertexTags);
 
   // copy and remove
-  int copy(int dim, int tag);
+  void copy(const std::vector<std::pair<int, int> > &inDimTags,
+            std::vector<std::pair<int, int> > &outDimTags);
   void remove(int dim, int tag);
+  void remove(const std::vector<std::pair<int, int> > &dimTags);
 
   // manipulate physical groups
   void resetPhysicalGroups();
diff --git a/Geo/GModelIO_OCC.cpp b/Geo/GModelIO_OCC.cpp
index 1ae58754722c7b7d3a7f85c0308067f610307a0d..52b4f7b9430d620adf7c94cf1b6c4d6f9cfc2192 100644
--- a/Geo/GModelIO_OCC.cpp
+++ b/Geo/GModelIO_OCC.cpp
@@ -87,7 +87,7 @@ OCC_Internals::OCC_Internals()
 void OCC_Internals::reset()
 {
   for(int i = 0; i < 6; i++) _maxTagConstraints[i] = 0;
-  for(int i = 0; i < 4; i++) meshAttributes[i].clear();
+  for(int i = 0; i < 4; i++) _meshAttributes[i].clear();
   _somap.Clear(); _shmap.Clear(); _fmap.Clear(); _wmap.Clear(); _emap.Clear();
   _vmap.Clear();
   _vertexTag.Clear(); _edgeTag.Clear(); _faceTag.Clear(); _solidTag.Clear();
@@ -99,6 +99,10 @@ void OCC_Internals::reset()
 
 void OCC_Internals::bind(TopoDS_Vertex vertex, int tag)
 {
+  if(_vertexTag.IsBound(vertex) && _vertexTag.Find(vertex) != tag){
+    Msg::Debug("OpenCASCADE vertex %d is already bound to another tag", tag);
+    return;
+  }
   _vertexTag.Bind(vertex, tag);
   _tagVertex.Bind(tag, vertex);
   _changed = true;
@@ -106,6 +110,10 @@ void OCC_Internals::bind(TopoDS_Vertex vertex, int tag)
 
 void OCC_Internals::bind(TopoDS_Edge edge, int tag)
 {
+  if(_edgeTag.IsBound(edge) && _edgeTag.Find(edge) != tag){
+    Msg::Debug("OpenCASCADE edge %d is already bound to another tag", tag);
+    return;
+  }
   _edgeTag.Bind(edge, tag);
   _tagEdge.Bind(tag, edge);
   _changed = true;
@@ -113,6 +121,10 @@ void OCC_Internals::bind(TopoDS_Edge edge, int tag)
 
 void OCC_Internals::bind(TopoDS_Wire wire, int tag)
 {
+  if(_wireTag.IsBound(wire) && _wireTag.Find(wire) != tag){
+    Msg::Debug("OpenCASCADE wire %d is already bound to anthor tag", tag);
+    return;
+  }
   _wireTag.Bind(wire, tag);
   _tagWire.Bind(tag, wire);
   _changed = true;
@@ -120,6 +132,10 @@ void OCC_Internals::bind(TopoDS_Wire wire, int tag)
 
 void OCC_Internals::bind(TopoDS_Face face, int tag)
 {
+  if(_faceTag.IsBound(face) && _faceTag.Find(face) != tag){
+    Msg::Debug("OpenCASCADE face %d is already bound to another tag", tag);
+    return;
+  }
   _faceTag.Bind(face, tag);
   _tagFace.Bind(tag, face);
   _changed = true;
@@ -127,6 +143,10 @@ void OCC_Internals::bind(TopoDS_Face face, int tag)
 
 void OCC_Internals::bind(TopoDS_Shell shell, int tag)
 {
+  if(_shellTag.IsBound(shell) && _shellTag.Find(shell) != tag){
+    Msg::Debug("OpenCASCADE shell %d is already bound to another tag", tag);
+    return;
+  }
   _shellTag.Bind(shell, tag);
   _tagShell.Bind(tag, shell);
   _changed = true;
@@ -134,6 +154,10 @@ void OCC_Internals::bind(TopoDS_Shell shell, int tag)
 
 void OCC_Internals::bind(TopoDS_Solid solid, int tag)
 {
+  if(_solidTag.IsBound(solid) && _solidTag.Find(solid) != tag){
+    Msg::Debug("OpenCASCADE solid %d is already bound to another tag", tag);
+    return;
+  }
   _solidTag.Bind(solid, tag);
   _tagSolid.Bind(tag, solid);
   _changed = true;
@@ -208,44 +232,79 @@ void OCC_Internals::unbind(TopoDS_Shape shape, int dim, int tag)
 }
 
 void OCC_Internals::bind(TopoDS_Shape shape, bool highestDimOnly, int tag,
-                         std::vector<int> outTags[4])
+                         std::vector<std::pair<int, int> > &outDimTags)
 {
   TopExp_Explorer exp0;
   bool first = true;
   for(exp0.Init(shape, TopAbs_SOLID); exp0.More(); exp0.Next()){
+    TopoDS_Solid solid = TopoDS::Solid(exp0.Current());
+    bool exists = false;
     int t = tag;
-    if(t <= 0){ t = getMaxTag(3) + 1; }
+    if(t <= 0){
+      if(_solidTag.IsBound(solid)){
+        t = _solidTag.Find(solid);
+        exists = true;
+      }
+      else
+        t = getMaxTag(3) + 1;
+    }
     else if(first){ first = false; }
     else{ Msg::Error("Cannot bind multiple regions to single tag %d", t); return; }
-    bind(TopoDS::Solid(exp0.Current()), t);
-    outTags[3].push_back(t);
+    if(!exists) bind(solid, t);
+    outDimTags.push_back(std::pair<int, int>(3, t));
   }
-  if(highestDimOnly && outTags[3].size()) return;
+  if(highestDimOnly && outDimTags.size()) return;
   for(exp0.Init(shape, TopAbs_FACE); exp0.More(); exp0.Next()){
+    TopoDS_Face face = TopoDS::Face(exp0.Current());
+    bool exists = false;
     int t = tag;
-    if(t <= 0){ t = getMaxTag(2) + 1; }
+    if(t <= 0){
+      if(_faceTag.IsBound(face)){
+        t = _faceTag.Find(face);
+        exists = true;
+      }
+      else
+        t = getMaxTag(2) + 1;
+    }
     else if(first){ first = false; }
     else{ Msg::Error("Cannot bind multiple faces to single tag %d", t); return; }
-    bind(TopoDS::Face(exp0.Current()), t);
-    outTags[2].push_back(t);
+    if(!exists) bind(face, t);
+    outDimTags.push_back(std::pair<int, int>(2, t));
   }
-  if(highestDimOnly && outTags[2].size()) return;
+  if(highestDimOnly && outDimTags.size()) return;
   for(exp0.Init(shape, TopAbs_EDGE); exp0.More(); exp0.Next()){
+    TopoDS_Edge edge = TopoDS::Edge(exp0.Current());
+    bool exists = false;
     int t = tag;
-    if(t <= 0){ t = getMaxTag(1) + 1; }
+    if(t <= 0){
+      if(_edgeTag.IsBound(edge)){
+        t = _edgeTag.Find(edge);
+        exists = true;
+      }
+      else
+        t = getMaxTag(1) + 1;
+    }
     else if(first){ first = false; }
     else{ Msg::Error("Cannot bind multiple edges to single tag %d", t); return; }
-    bind(TopoDS::Edge(exp0.Current()), t);
-    outTags[1].push_back(t);
+    if(!exists) bind(edge, t);
+    outDimTags.push_back(std::pair<int, int>(1, t));
   }
-  if(highestDimOnly && outTags[1].size()) return;
+  if(highestDimOnly && outDimTags.size()) return;
   for(exp0.Init(shape, TopAbs_VERTEX); exp0.More(); exp0.Next()){
+    TopoDS_Vertex vertex = TopoDS::Vertex(exp0.Current());
+    bool exists = false;
     int t = tag;
-    if(t <= 0){ t = getMaxTag(0) + 1; }
+    if(t <= 0){
+      if(_vertexTag.IsBound(vertex)){
+        t = _vertexTag.Find(vertex);
+        exists = false;
+      }
+      t = getMaxTag(0) + 1;
+    }
     else if(first){ first = false; }
     else{ Msg::Error("Cannot bind multiple vertices to single tag %d", t); return; }
-    bind(TopoDS::Vertex(exp0.Current()), t);
-    outTags[0].push_back(t);
+    if(!exists) bind(vertex, t);
+    outDimTags.push_back(std::pair<int, int>(0, t));
   }
 }
 
@@ -324,7 +383,7 @@ void OCC_Internals::addVertex(int tag, double x, double y, double z,
   if(tag <= 0) tag = getMaxTag(0) + 1;
   bind(result, tag);
   if(meshSize > 0 && meshSize < MAX_LC)
-    meshAttributes[0][tag].size = meshSize;
+    _meshAttributes[0][tag].size = meshSize;
 }
 
 void OCC_Internals::addLine(int tag, int startTag, int endTag)
@@ -362,7 +421,7 @@ void OCC_Internals::addLine(int tag, int startTag, int endTag)
   bind(result, tag);
 }
 
-void OCC_Internals::addLine(int tag, std::vector<int> vertexTags)
+void OCC_Internals::addLine(int tag, const std::vector<int> &vertexTags)
 {
   if(vertexTags.size() == 2)
     addLine(tag, vertexTags[0], vertexTags[1]);
@@ -525,7 +584,7 @@ void OCC_Internals::addEllipse(int tag, double x, double y, double z, double r1,
   bind(result, tag);
 }
 
-void OCC_Internals::_addSpline(int tag, std::vector<int> vertexTags, int mode)
+void OCC_Internals::_addSpline(int tag, const std::vector<int> &vertexTags, int mode)
 {
   if(tag > 0 && _tagEdge.IsBound(tag)){
     Msg::Error("OpenCASCADE edge with tag %d already exists", tag);
@@ -577,17 +636,18 @@ void OCC_Internals::_addSpline(int tag, std::vector<int> vertexTags, int mode)
   bind(result, tag);
 }
 
-void OCC_Internals::addBezier(int tag, std::vector<int> vertexTags)
+void OCC_Internals::addBezier(int tag, const std::vector<int> &vertexTags)
 {
   _addSpline(tag, vertexTags, 0);
 }
 
-void OCC_Internals::addBSpline(int tag, std::vector<int> vertexTags)
+void OCC_Internals::addBSpline(int tag, const std::vector<int> &vertexTags)
 {
   _addSpline(tag, vertexTags, 1);
 }
 
-void OCC_Internals::addWire(int tag, std::vector<int> edgeTags, bool checkClosed)
+void OCC_Internals::addWire(int tag, const std::vector<int> &edgeTags,
+                            bool checkClosed)
 {
   if(tag > 0 && _tagWire.IsBound(tag)){
     Msg::Error("OpenCASCADE wire or line loop with tag %d already exists", tag);
@@ -619,7 +679,7 @@ void OCC_Internals::addWire(int tag, std::vector<int> edgeTags, bool checkClosed
   bind(result, tag);
 }
 
-void OCC_Internals::addLineLoop(int tag, std::vector<int> edgeTags)
+void OCC_Internals::addLineLoop(int tag, const std::vector<int> &edgeTags)
 {
   addWire(tag, edgeTags, true);
 }
@@ -728,7 +788,7 @@ void OCC_Internals::addDisk(int tag, double xc, double yc, double zc,
   bind(result, tag);
 }
 
-void OCC_Internals::addPlaneSurface(int tag, std::vector<int> wireTags)
+void OCC_Internals::addPlaneSurface(int tag, const std::vector<int> &wireTags)
 {
   const bool autoFix = true;
 
@@ -840,7 +900,7 @@ void OCC_Internals::addSurfaceFilling(int tag, int wireTag)
   bind(result, tag);
 }
 
-void OCC_Internals::addSurfaceLoop(int tag, std::vector<int> faceTags)
+void OCC_Internals::addSurfaceLoop(int tag, const std::vector<int> &faceTags)
 {
   const bool autoFix = true;
 
@@ -890,7 +950,7 @@ void OCC_Internals::addSurfaceLoop(int tag, std::vector<int> faceTags)
   }
 }
 
-void OCC_Internals::addVolume(int tag, std::vector<int> shellTags)
+void OCC_Internals::addVolume(int tag, const std::vector<int> &shellTags)
 {
   const bool autoFix = true;
 
@@ -1112,8 +1172,8 @@ void OCC_Internals::addWedge(int tag, double x, double y, double z, double dx, d
   bind(result, tag);
 }
 
-void OCC_Internals::addThruSections(int tag, std::vector<int> wireTags,
-                                    std::vector<int> outTags[4],
+void OCC_Internals::addThruSections(int tag, const std::vector<int> &wireTags,
+                                    std::vector<std::pair<int, int> > &outDimTags,
                                     bool makeSolid, bool makeRuled)
 {
   int dim = makeSolid ? 3 : 2;
@@ -1155,11 +1215,12 @@ void OCC_Internals::addThruSections(int tag, std::vector<int> wireTags,
     return;
   }
 
-  bind(result, true, tag, outTags);
+  bind(result, true, tag, outDimTags);
 }
 
 void OCC_Internals::addThickSolid(int tag, int solidTag,
-                                  std::vector<int> excludeFaceTags, double offset)
+                                  const std::vector<int> &excludeFaceTags,
+                                  double offset)
 {
   if(tag > 0 && isBound(3, tag)){
     Msg::Error("OpenCASCADE region with tag %d already exists", tag);
@@ -1195,38 +1256,33 @@ void OCC_Internals::addThickSolid(int tag, int solidTag,
     return;
   }
 
-  std::vector<int> out[4];
+  std::vector<std::pair<int, int> > out;
   bind(result, true, tag, out);
 }
 
-void OCC_Internals::_extrude(int tag, int mode, std::vector<int> inTags[4],
+void OCC_Internals::_extrude(int mode,
+                             const std::vector<std::pair<int, int> > &inDimTags,
                              double x, double y, double z,
-                             double dx, double dy, double dz, double angle,
-                             int wireTag, std::vector<int> outTags[4])
+                             double dx, double dy, double dz,
+                             double ax, double ay, double az, double angle,
+                             int wireTag,
+                             std::vector<std::pair<int, int> > &outDimTags,
+                             ExtrudeParams *e)
 {
-  for(int dim = 0; dim < 3; dim++){
-    if(tag > 0 && inTags[dim].size() && isBound(tag, dim + 1)){
-      Msg::Error("OpenCASCADE region of dimension %d with tag %d already exists",
-                 dim + 1, tag);
-      return;
-    }
-  }
-
   // build a single compound shape, so that we won't duplicate internal
   // boundaries
   BRep_Builder b;
   TopoDS_Compound c;
   b.MakeCompound(c);
-  for(int dim = 0; dim < 4; dim++){
-    for(unsigned int i = 0; i < inTags[dim].size(); i++){
-      if(!isBound(dim, inTags[dim][i])){
-        Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
-                   dim, inTags[dim][i]);
-        return;
-      }
-      TopoDS_Shape shape = find(dim, inTags[dim][i]);
-      b.Add(c, shape);
+  for(unsigned int i = 0; i < inDimTags.size(); i++){
+    int dim = inDimTags[i].first;
+    int tag = inDimTags[i].second;
+    if(!isBound(dim, tag)){
+      Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim, tag);
+      return;
     }
+    TopoDS_Shape shape = find(dim, tag);
+    b.Add(c, shape);
   }
   TopoDS_Shape result;
   try{
@@ -1240,7 +1296,7 @@ void OCC_Internals::_extrude(int tag, int mode, std::vector<int> inTags[4],
       result = p.Shape();
     }
     else if(mode == 1){ // revolve
-      gp_Ax1 axisOfRevolution(gp_Pnt(x, y, z), gp_Dir(dx, dy, dz));
+      gp_Ax1 axisOfRevolution(gp_Pnt(x, y, z), gp_Dir(ax, ay, az));
       BRepPrimAPI_MakeRevol r(c, axisOfRevolution, angle, Standard_False);
       r.Build();
       if(!r.IsDone()){
@@ -1269,32 +1325,35 @@ void OCC_Internals::_extrude(int tag, int mode, std::vector<int> inTags[4],
     return;
   }
 
-  bind(result, true, tag, outTags);
+  bind(result, true, -1, outDimTags);
 }
 
-void OCC_Internals::extrude(int tag, std::vector<int> inTags[4],
+void OCC_Internals::extrude(const std::vector<std::pair<int, int> > &inDimTags,
                             double dx, double dy, double dz,
-                            std::vector<int> outTags[4])
+                            std::vector<std::pair<int, int> > &outDimTags,
+                            ExtrudeParams *e)
 {
-  _extrude(tag, 0, inTags, 0, 0, 0, dx, dy, dz, 0, 0, outTags);
+  _extrude(0, inDimTags, 0., 0., 0., dx, dy, dz, 0., 0., 0., 0., 0, outDimTags, e);
 }
 
-void OCC_Internals::revolve(int tag, std::vector<int> inTags[4],
+void OCC_Internals::revolve(const std::vector<std::pair<int, int> > &inDimTags,
                             double x, double y, double z,
-                            double dx, double dy, double dz, double angle,
-                            std::vector<int> outTags[4])
+                            double ax, double ay, double az, double angle,
+                            std::vector<std::pair<int, int> > &outDimTags,
+                            ExtrudeParams *e)
 {
-  _extrude(tag, 1, inTags, x, y, z, dx, dy, dz, angle, 0, outTags);
+  _extrude(1, inDimTags, x, y, z, 0., 0., 0., ax, ay, az, angle, 0, outDimTags, e);
 }
 
-void OCC_Internals::addPipe(int tag, std::vector<int> inTags[4],
-                            int wireTag, std::vector<int> outTags[4])
+void OCC_Internals::addPipe(const std::vector<std::pair<int, int> > &inDimTags,
+                            int wireTag, std::vector<std::pair<int, int> > &outDimTags)
 {
-  _extrude(tag, 2, inTags, 0, 0, 0, 0, 0, 0, 0, wireTag, outTags);
+  _extrude(2, inDimTags, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., wireTag, outDimTags);
 }
 
-void OCC_Internals::fillet(std::vector<int> regionTags, std::vector<int> edgeTags,
-                           double radius, std::vector<int> outTags[4])
+void OCC_Internals::fillet(const std::vector<int> &regionTags,
+                           const std::vector<int> &edgeTags, double radius,
+                           std::vector<std::pair<int, int> > &outDimTags)
 {
   // build a single compound shape
   BRep_Builder b;
@@ -1338,52 +1397,51 @@ void OCC_Internals::fillet(std::vector<int> regionTags, std::vector<int> edgeTag
     Msg::Error("Fillet produces empty shape");
     return;
   }
-  bind(result, true, -1, outTags);
+  bind(result, true, -1, outDimTags);
 }
 
-void OCC_Internals::applyBooleanOperator(int tag, BooleanOperator op,
-                                         std::vector<int> objectTags[4],
-                                         std::vector<int> toolTags[4],
-                                         std::vector<int> outTags[4],
-                                         bool removeObject, bool removeTool)
+void OCC_Internals::applyBooleanOperator
+                    (int tag, BooleanOperator op,
+                     const std::vector<std::pair<int, int> > &objectDimTags,
+                     const std::vector<std::pair<int, int> > &toolDimTags,
+                     std::vector<std::pair<int, int> > &outDimTags,
+                     bool removeObject, bool removeTool)
 {
   double tolerance = CTX::instance()->geom.toleranceBoolean;
   bool parallel = CTX::instance()->geom.occParallel;
 
-  if(tag > 0){
-    for(int dim = 0; dim < 4; dim++){
-      if(objectTags[dim].size() && isBound(dim, tag)){
-        Msg::Error("OpenCASCADE entity with tag %d already exists", tag);
-        return;
-      }
-    }
+  if(objectDimTags.empty()) return;
+
+  if(tag > 0 && isBound(objectDimTags[0].first, tag)){
+    Msg::Error("OpenCASCADE entity with tag %d already exists", tag);
+    return;
   }
 
   std::vector<TopoDS_Shape> objects[4], tools[4];
-  for(unsigned int dim = 0; dim < 4; dim++){
-    for(unsigned int i = 0; i < objectTags[dim].size(); i++){
-      if(!isBound(dim, objectTags[dim][i])){
-        Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
-                   dim, objectTags[dim][i]);
-        return;
-      }
-      else{
-        TopoDS_Shape object = find(dim, objectTags[dim][i]);
-        objects[dim].push_back(object);
-        if(removeObject) unbind(object, dim, objectTags[dim][i]);
-      }
+  for(unsigned int i = 0; i < objectDimTags.size(); i++){
+    int dim = objectDimTags[i].first;
+    int t = objectDimTags[i].second;
+    if(!isBound(dim, t)){
+      Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim, t);
+      return;
     }
-    for(unsigned int i = 0; i < toolTags[dim].size(); i++){
-      if(!isBound(dim, toolTags[dim][i])){
-        Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
-                   dim, toolTags[dim][i]);
-        return;
-      }
-      else{
-        TopoDS_Shape tool = find(dim, toolTags[dim][i]);
-        tools[dim].push_back(tool);
-        if(removeTool) unbind(tool, dim, toolTags[dim][i]);
-      }
+    else{
+      TopoDS_Shape object = find(dim, t);
+      objects[dim].push_back(object);
+      if(removeObject) unbind(object, dim, t);
+    }
+  }
+  for(unsigned int i = 0; i < toolDimTags.size(); i++){
+    int dim = toolDimTags[i].first;
+    int t = toolDimTags[i].second;
+    if(!isBound(dim, t)){
+      Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d", dim, t);
+      return;
+    }
+    else{
+      TopoDS_Shape tool = find(dim, t);
+      tools[dim].push_back(tool);
+      if(removeTool) unbind(tool, dim, t);
     }
   }
 
@@ -1553,62 +1611,65 @@ void OCC_Internals::applyBooleanOperator(int tag, BooleanOperator op,
     return;
   }
 
-  bind(result, true, tag, outTags);
+  bind(result, true, tag, outDimTags);
 }
 
-void OCC_Internals::_transform(std::vector<int> inTags[4],
+void OCC_Internals::_transform(const std::vector<std::pair<int, int> > &inDimTags,
                                BRepBuilderAPI_Transform &tfo)
 {
-  for(unsigned int dim = 0; dim < 4; dim++){
-    for(unsigned int i = 0; i < inTags[dim].size(); i++){
-      int tag = inTags[dim][i];
-      if(!isBound(dim, tag)){
-        Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
-                   dim, tag);
-        return;
-      }
-      tfo.Perform(find(dim, tag), Standard_False);
-      if(!tfo.IsDone()){
-        Msg::Error("Could not apply transformation");
-        return;
-      }
-      bind(tfo.Shape(), dim, tag);
+  for(unsigned int i = 0; i < inDimTags.size(); i++){
+    int dim = inDimTags[i].first;
+    int tag = inDimTags[i].second;
+    if(!isBound(dim, tag)){
+      Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
+                 dim, tag);
+      return;
+    }
+    tfo.Perform(find(dim, tag), Standard_False);
+    if(!tfo.IsDone()){
+      Msg::Error("Could not apply transformation");
+      return;
     }
+    bind(tfo.Shape(), dim, tag);
   }
 }
 
-void OCC_Internals::translate(std::vector<int> inTags[4],
+void OCC_Internals::translate(const std::vector<std::pair<int, int> > &inDimTags,
                               double dx, double dy, double dz)
 {
   gp_Trsf t;
   t.SetTranslation(gp_Pnt(0, 0, 0), gp_Pnt(dx, dy, dz));
   BRepBuilderAPI_Transform tfo(t);
-  _transform(inTags, tfo);
+  _transform(inDimTags, tfo);
 }
 
-void OCC_Internals::rotate(std::vector<int> inTags[4],
+void OCC_Internals::rotate(const std::vector<std::pair<int, int> > &inDimTags,
                            double x, double y, double z,
-                           double dx, double dy, double dz,
-                           double angle)
+                           double ax, double ay, double az, double angle)
 {
   gp_Trsf t;
-  gp_Ax1 axisOfRevolution(gp_Pnt(x, y, z), gp_Dir(dx, dy, dz));
+  gp_Ax1 axisOfRevolution(gp_Pnt(x, y, z), gp_Dir(ax, ay, az));
   t.SetRotation(axisOfRevolution, angle);
   BRepBuilderAPI_Transform tfo(t);
-  _transform(inTags, tfo);
+  _transform(inDimTags, tfo);
 }
 
-int OCC_Internals::copy(int dim, int tag)
+void OCC_Internals::copy(const std::vector<std::pair<int, int> > &inDimTags,
+                         std::vector<std::pair<int, int> > &outDimTags)
 {
-  if(!isBound(dim, tag)){
-    Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
-               dim, tag);
-    return tag;
+  for(unsigned int i = 0; i < inDimTags.size(); i++){
+    int dim = inDimTags[i].first;
+    int tag = inDimTags[i].second;
+    if(!isBound(dim, tag)){
+      Msg::Error("Unknown OpenCASCADE entity of dimension %d with tag %d",
+                 dim, tag);
+      continue;
+    }
+    TopoDS_Shape result = BRepBuilderAPI_Copy(find(dim, tag)).Shape();
+    int newtag = getMaxTag(dim) + 1;
+    bind(result, dim, newtag);
+    outDimTags.push_back(std::pair<int, int>(dim, newtag));
   }
-  TopoDS_Shape result = BRepBuilderAPI_Copy(find(dim, tag)).Shape();
-  int newtag = getMaxTag(dim) + 1;
-  bind(result, dim, newtag);
-  return newtag;
 }
 
 void OCC_Internals::remove(int dim, int tag)
@@ -1621,8 +1682,15 @@ void OCC_Internals::remove(int dim, int tag)
   unbind(find(dim, tag), dim, tag);
 }
 
+void OCC_Internals::remove(const std::vector<std::pair<int, int> > &dimTags)
+{
+  for(unsigned int i = 0; i < dimTags.size(); i++)
+    remove(dimTags[i].first, dimTags[i].second);
+}
+
 void OCC_Internals::importShapes(const std::string &fileName, bool highestDimOnly,
-                                 std::vector<int> outTags[4], const std::string &format)
+                                 std::vector<std::pair<int, int> > &outDimTags,
+                                 const std::string &format)
 {
   std::vector<std::string> split = SplitFileName(fileName);
   TopoDS_Shape result;
@@ -1673,13 +1741,13 @@ void OCC_Internals::importShapes(const std::string &fileName, bool highestDimOnl
              CTX::instance()->geom.occFixSmallFaces,
              CTX::instance()->geom.occSewFaces,
              false, CTX::instance()->geom.occScaling);
-  bind(result, highestDimOnly, -1, outTags);
+  bind(result, highestDimOnly, -1, outDimTags);
 }
 
 void OCC_Internals::importShapes(const TopoDS_Shape *shape, bool highestDimOnly,
-                                 std::vector<int> outTags[4])
+                                 std::vector<std::pair<int, int> > &outDimTags)
 {
-  bind(*shape, highestDimOnly, -1, outTags);
+  bind(*shape, highestDimOnly, -1, outDimTags);
 }
 
 void OCC_Internals::exportShapes(const std::string &fileName,
@@ -1735,7 +1803,7 @@ void OCC_Internals::exportShapes(const std::string &fileName,
 void OCC_Internals::setMeshSize(int dim, int tag, double size)
 {
   if(dim < 0 || dim > 3) return;
-  meshAttributes[dim][tag].size = size;
+  _meshAttributes[dim][tag].size = size;
 }
 
 void OCC_Internals::synchronize(GModel *model)
@@ -1764,8 +1832,48 @@ void OCC_Internals::synchronize(GModel *model)
   TopTools_DataMapIteratorOfDataMapOfIntegerShape exp3(_tagSolid);
   for(; exp3.More(); exp3.Next()) _addShapeToMaps(exp3.Value());
 
-  // import all shapes in _maps into the GModel, preserving all explicit tags
+  // remove all OCC entities in the model that are not in the maps (because they
+  // have been deleted in OCC_Internals after being previously added to
+  // GModel). This can currently only happen when doing boolean operations when
+  // we remove the object and/or tool; all other removals are explicit and done
+  // both in the internal CAD data and the GModel
+  std::vector<std::pair<int, int> > toRemove;
+  for(GModel::viter it = model->firstVertex(); it != model->lastVertex(); ++it){
+    if((*it)->getNativeType() == GEntity::OpenCascadeModel){
+      OCCVertex *occ = (OCCVertex*)(*it);
+      TopoDS_Vertex v = *(TopoDS_Vertex*)occ->getNativePtr();
+      if(_vmap.FindIndex(v) < 1)
+        toRemove.push_back(std::pair<int, int>(0, occ->tag()));
+    }
+  }
+  for(GModel::eiter it = model->firstEdge(); it != model->lastEdge(); ++it){
+    if((*it)->getNativeType() == GEntity::OpenCascadeModel){
+      OCCEdge *occ = (OCCEdge*)(*it);
+      TopoDS_Edge v = *(TopoDS_Edge*)occ->getNativePtr();
+      if(_emap.FindIndex(v) < 1)
+        toRemove.push_back(std::pair<int, int>(1, occ->tag()));
+    }
+  }
+  for(GModel::fiter it = model->firstFace(); it != model->lastFace(); ++it){
+    if((*it)->getNativeType() == GEntity::OpenCascadeModel){
+      OCCFace *occ = (OCCFace*)(*it);
+      TopoDS_Face v = *(TopoDS_Face*)occ->getNativePtr();
+      if(_fmap.FindIndex(v) < 1)
+        toRemove.push_back(std::pair<int, int>(2, occ->tag()));
+    }
+  }
+  for(GModel::riter it = model->firstRegion(); it != model->lastRegion(); ++it){
+    if((*it)->getNativeType() == GEntity::OpenCascadeModel){
+      OCCRegion *occ = (OCCRegion*)(*it);
+      TopoDS_Solid v = *(TopoDS_Solid*)occ->getNativePtr();
+      if(_somap.FindIndex(v) < 1)
+        toRemove.push_back(std::pair<int, int>(3, occ->tag()));
+    }
+  }
+  Msg::Debug("Sync is removing %d model entities", toRemove.size());
+  model->remove(toRemove);
 
+  // import all shapes in _maps into the GModel, preserving all explicit tags
   for(int i = 1; i <= _vmap.Extent(); i++){
     TopoDS_Vertex vertex = TopoDS::Vertex(_vmap(i));
     if(!getOCCVertexByNativePtr(model, vertex)){
@@ -1778,12 +1886,11 @@ void OCC_Internals::synchronize(GModel *model)
         vTagMax++;
       }
       std::map<int, meshAttribute>::iterator it =
-        meshAttributes[0].find(tag);
-      double lc = (it == meshAttributes[0].end()) ? MAX_LC : it->second.size;
+        _meshAttributes[0].find(tag);
+      double lc = (it == _meshAttributes[0].end()) ? MAX_LC : it->second.size;
       model->add(new OCCVertex(model, tag, vertex, lc));
     }
   }
-
   for(int i = 1; i <= _emap.Extent(); i++){
     TopoDS_Edge edge = TopoDS::Edge(_emap(i));
     if(!getOCCEdgeByNativePtr(model, edge)){
@@ -1800,7 +1907,6 @@ void OCC_Internals::synchronize(GModel *model)
       model->add(new OCCEdge(model, edge, tag, v1, v2));
     }
   }
-
   for(int i = 1; i <= _fmap.Extent(); i++){
     TopoDS_Face face = TopoDS::Face(_fmap(i));
     if(!getOCCFaceByNativePtr(model, face)){
@@ -1815,7 +1921,6 @@ void OCC_Internals::synchronize(GModel *model)
       model->add(new OCCFace(model, face, tag));
     }
   }
-
   for(int i = 1; i <= _somap.Extent(); i++){
     TopoDS_Solid region = TopoDS::Solid(_somap(i));
     if(!getOCCRegionByNativePtr(model, region)){
@@ -2831,8 +2936,8 @@ int GModel::readOCCBREP(const std::string &fn)
 {
   if(!_occ_internals)
     _occ_internals = new OCC_Internals;
-  std::vector<int> tags[4];
-  _occ_internals->importShapes(fn, false, tags, "brep");
+  std::vector<std::pair<int, int> > outDimTags;
+  _occ_internals->importShapes(fn, false, outDimTags, "brep");
   _occ_internals->synchronize(this);
   snapVertices();
   return 1;
@@ -2842,8 +2947,8 @@ int GModel::readOCCSTEP(const std::string &fn)
 {
   if(!_occ_internals)
     _occ_internals = new OCC_Internals;
-  std::vector<int> tags[4];
-  _occ_internals->importShapes(fn, false, tags, "step");
+  std::vector<std::pair<int, int> > outDimTags;
+  _occ_internals->importShapes(fn, false, outDimTags, "step");
   _occ_internals->synchronize(this);
   return 1;
 }
@@ -2852,8 +2957,8 @@ int GModel::readOCCIGES(const std::string &fn)
 {
   if(!_occ_internals)
     _occ_internals = new OCC_Internals;
-  std::vector<int> tags[4];
-  _occ_internals->importShapes(fn, false, tags, "iges");
+  std::vector<std::pair<int, int> > outDimTags;
+  _occ_internals->importShapes(fn, false, outDimTags, "iges");
   _occ_internals->synchronize(this);
   return 1;
 }
@@ -2883,8 +2988,8 @@ int GModel::importOCCShape(const void *shape)
   if(!_occ_internals)
     _occ_internals = new OCC_Internals;
 #if defined(HAVE_OCC)
-  std::vector<int> tags[4];
-  _occ_internals->importShapes((TopoDS_Shape*)shape, false, tags);
+  std::vector<std::pair<int, int> > outDimTags;
+  _occ_internals->importShapes((TopoDS_Shape*)shape, false, outDimTags);
 #else
   Msg::Error("Gmsh requires OpenCASCADE to import TopoDS_Shape");
 #endif
diff --git a/Geo/GModelIO_OCC.h b/Geo/GModelIO_OCC.h
index 49ed18d5f69faa1035ed61ab18128ca07122f224..0fe219e0a073975d39b45b0c72348e371cc3689a 100644
--- a/Geo/GModelIO_OCC.h
+++ b/Geo/GModelIO_OCC.h
@@ -12,6 +12,8 @@
 #include "GmshMessage.h"
 #include "GModel.h"
 
+class ExtrudeParams;
+
 #if defined(HAVE_OCC)
 
 #include <TopoDS_Shape.hxx>
@@ -58,7 +60,7 @@ class OCC_Internals {
     double size;
     ExtrudeParams *extrude;
   };
-  std::map<int, meshAttribute> meshAttributes[4];
+  std::map<int, meshAttribute> _meshAttributes[4];
 
   // add a shape and all its subshapes to _vmap, _emap, ..., _somap
   void _addShapeToMaps(TopoDS_Shape shape);
@@ -69,19 +71,21 @@ class OCC_Internals {
                   bool makesolids=false, double scaling=0.0);
 
   // apply a geometrical transformation
-  void _transform(std::vector<int> inTags[4], BRepBuilderAPI_Transform &tfo);
+  void _transform(const std::vector<std::pair<int, int> > &inDimTags,
+                  BRepBuilderAPI_Transform &tfo);
 
   // add circle or ellipse arc
   void _addArc(int tag, int startTag, int centerTag, int endTag, int mode);
 
   // add bezier or bspline
-  void _addSpline(int tag, std::vector<int> vertexTags, int mode);
+  void _addSpline(int tag, const std::vector<int> &vertexTags, int mode);
 
   // apply extrusion-like operations
-  void _extrude(int tag, int mode, std::vector<int> inTags[4],
-                double x, double y, double z,
-                double dx, double dy, double dz, double angle,
-                int wireTag, std::vector<int> outTags[4]);
+  void _extrude(int mode, const std::vector<std::pair<int, int> > &inDimTags,
+                double x, double y, double z, double dx, double dy, double dz,
+                double ax, double ay, double az, double angle, int wireTag,
+                std::vector<std::pair<int, int> > &outDimTags,
+                ExtrudeParams *e=0);
 
  public:
   OCC_Internals();
@@ -113,7 +117,7 @@ class OCC_Internals {
   // highestDimOnly is true, only bind the entities of the highest
   // dimension
   void bind(TopoDS_Shape shape, bool highestDimOnly, int tag,
-            std::vector<int> outTags[4]);
+            std::vector<std::pair<int, int> > &outDimTags);
 
   // is the entity of a given dimension and tag bound?
   bool isBound(int dim, int tag);
@@ -129,24 +133,24 @@ class OCC_Internals {
   // add shapes
   void addVertex(int tag, double x, double y, double z, double meshSize=MAX_LC);
   void addLine(int tag, int startTag, int endTag);
-  void addLine(int tag, std::vector<int> vertexTags);
+  void addLine(int tag, const std::vector<int> &vertexTags);
   void addCircleArc(int tag, int startTag, int centerTag, int endTag);
   void addCircle(int tag, double x, double y, double z, double r, double angle1,
                  double angle2);
   void addEllipseArc(int tag, int startTag, int centerTag, int endTag);
   void addEllipse(int tag, double x, double y, double z, double r1, double r2,
                   double angle1, double angle2);
-  void addBezier(int tag, std::vector<int> vertexTags);
-  void addBSpline(int tag, std::vector<int> vertexTags);
-  void addWire(int tag, std::vector<int> edgeTags, bool checkClosed);
-  void addLineLoop(int tag, std::vector<int> edgeTags);
+  void addBezier(int tag, const std::vector<int> &vertexTags);
+  void addBSpline(int tag, const std::vector<int> &vertexTags);
+  void addWire(int tag, const std::vector<int> &edgeTags, bool checkClosed);
+  void addLineLoop(int tag, const std::vector<int> &edgeTags);
   void addRectangle(int tag, double x1, double y1, double z1,
                     double x2, double y2, double z2, double roundedRadius=0.);
   void addDisk(int tag, double xc, double yc, double zc, double rx, double ry);
-  void addPlaneSurface(int tag, std::vector<int> wireTags);
+  void addPlaneSurface(int tag, const std::vector<int> &wireTags);
   void addSurfaceFilling(int tag, int wireTag);
-  void addSurfaceLoop(int tag, std::vector<int> faceTags);
-  void addVolume(int tag, std::vector<int> shellTags);
+  void addSurfaceLoop(int tag, const std::vector<int> &faceTags);
+  void addVolume(int tag, const std::vector<int> &shellTags);
   void addSphere(int tag, double xc, double yc, double zc, double radius,
                  double angle1, double angle2, double angle3);
   void addBlock(int tag, double x1, double y1, double z1,
@@ -159,50 +163,56 @@ class OCC_Internals {
                 double dz, double ltx);
   void addTorus(int tag, double x, double y, double z, double r1, double r2,
                 double angle);
-  void addThruSections(int tag, std::vector<int> wireTags,
-                       std::vector<int> outTags[4],
+  void addThruSections(int tag, const std::vector<int> &wireTags,
+                       std::vector<std::pair<int, int> > &outDimTags,
                        bool makeSolid, bool makeRuled);
-  void addThickSolid(int tag, int solidTag, std::vector<int> excludeFaceTags,
+  void addThickSolid(int tag, int solidTag, const std::vector<int> &excludeFaceTags,
                      double offset);
 
   // extrude and revolve
-  void extrude(int tag, std::vector<int> inTags[4],
+  void extrude(const std::vector<std::pair<int, int> > &inDimTags,
                double dx, double dy, double dz,
-               std::vector<int> outTags[4]);
-  void revolve(int tag, std::vector<int> inTags[4],
-               double x, double y, double z, double dx, double dy, double dz,
-               double angle, std::vector<int> outTags[4]);
-  void addPipe(int tag, std::vector<int> inTags[4], int wireTag,
-               std::vector<int> outTags[4]);
+               std::vector<std::pair<int, int> > &outDimTags,
+               ExtrudeParams *e=0);
+  void revolve(const std::vector<std::pair<int, int> > &inDimTags,
+               double x, double y, double z, double ax, double ay, double az,
+               double angle, std::vector<std::pair<int, int> > &outDimTags,
+               ExtrudeParams *e=0);
+  void addPipe(const std::vector<std::pair<int, int> > &inDimTags, int wireTag,
+               std::vector<std::pair<int, int> > &outDimTags);
 
   // fillet
-  void fillet(std::vector<int> regionTags, std::vector<int> edgeTags,
-              double radius, std::vector<int> outTags[4]);
+  void fillet(const std::vector<int> &regionTags, const std::vector<int> &edgeTags,
+              double radius, std::vector<std::pair<int, int> > &ouDimTags);
 
   // apply boolean operator
   void applyBooleanOperator(int tag, BooleanOperator op,
-                            std::vector<int> shapeTags[4],
-                            std::vector<int> toolTags[4],
-                            std::vector<int> outTags[4],
-                            bool removeShape=true,
-                            bool removeTool=true);
+                            const std::vector<std::pair<int, int> > &objectDimTags,
+                            const std::vector<std::pair<int, int> > &toolDimTags,
+                            std::vector<std::pair<int, int> > &outDimTags,
+                            bool removeObject, bool removeTool);
 
   // apply transformations
-  void translate(std::vector<int> inTags[4], double dx, double dy, double dz);
-  void rotate(std::vector<int> inTags[4], double x, double y, double z,
-              double dx, double dy, double dz, double angle);
+  void translate(const std::vector<std::pair<int, int> > &inDimTags,
+                 double dx, double dy, double dz);
+  void rotate(const std::vector<std::pair<int, int> > &inDimTags,
+              double x, double y, double z, double ax, double ay, double az,
+              double angle);
 
   // copy and remove
-  int copy(int dim, int tag);
+  void copy(const std::vector<std::pair<int, int> > &inDimTags,
+            std::vector<std::pair<int, int> > &outDimTags);
   void remove(int dim, int tag);
+  void remove(const std::vector<std::pair<int, int> > &dimTags);
 
   // import shapes from file
   void importShapes(const std::string &fileName, bool highestDimOnly,
-                    std::vector<int> outTags[4], const std::string &format="");
+                    std::vector<std::pair<int, int> > &outDimTags,
+                    const std::string &format="");
 
   // import shapes from TopoDS_Shape
   void importShapes(const TopoDS_Shape *shape, bool highestDimOnly,
-                    std::vector<int> outTags[4]);
+                    std::vector<std::pair<int, int> > &outDimTags);
 
   // export all bound shapes to file
   void exportShapes(const std::string &fileName, const std::string &format="");
@@ -242,7 +252,8 @@ class OCC_Internals {
   void buildGModel(GModel *gm);
   void loadShape(const TopoDS_Shape *s)
   {
-    std::vector<int> tags[4]; importShapes(s, false, tags);
+    std::vector<std::pair<int, int> > outDimTags;
+    importShapes(s, false, outDimTags);
   }
   GVertex *addVertexToModel(GModel *model, TopoDS_Vertex v);
   GEdge *addEdgeToModel(GModel *model, TopoDS_Edge e);
@@ -267,75 +278,174 @@ public:
   void setMaxTag(int dim, int val){}
   int getMaxTag(int dim) const { return 0; }
   void addVertex(int tag, double x, double y, double z, double meshSize=MAX_LC)
-  { _error("add vertex"); }
-  void addLine(int tag, int startTag, int endTag){ _error("add line"); }
-  void addLine(int tag, std::vector<int> vertexTags){ _error("add line"); }
+  {
+    _error("add vertex");
+  }
+  void addLine(int tag, int startTag, int endTag)
+  {
+    _error("add line");
+  }
+  void addLine(int tag, const std::vector<int> &vertexTags)
+  {
+    _error("add line");
+  }
   void addCircleArc(int tag, int startTag, int centerTag, int endTag)
-  { _error("add circle arc"); }
+  {
+    _error("add circle arc");
+  }
   void addCircle(int tag, double x, double y, double z, double r, double angle1,
-                 double angle2){ _error("add circle"); }
+                 double angle2)
+  {
+    _error("add circle");
+  }
   void addEllipseArc(int tag, int startTag, int centerTag, int endTag)
-  { _error("add ellipse arc"); }
+  {
+    _error("add ellipse arc");
+  }
   void addEllipse(int tag, double x, double y, double z, double r1, double r2,
-                  double angle1, double angle2){ _error("add ellipse"); }
-  void addBezier(int tag, std::vector<int> vertexTags){ _error("add Bezier"); }
-  void addBSpline(int tag, std::vector<int> vertexTags){ _error("add BSpline"); }
-  void addWire(int tag, std::vector<int> edgeTags, bool closed){ _error("add wire"); }
-  void addLineLoop(int tag, std::vector<int> edgeTags){ _error("add line loop"); }
+                  double angle1, double angle2)
+  {
+    _error("add ellipse");
+  }
+  void addBezier(int tag, const std::vector<int> &vertexTags)
+  {
+    _error("add Bezier");
+  }
+  void addBSpline(int tag, const std::vector<int> &vertexTags)
+  {
+    _error("add BSpline");
+  }
+  void addWire(int tag, const std::vector<int> &edgeTags, bool closed)
+  {
+    _error("add wire");
+  }
+  void addLineLoop(int tag, const std::vector<int> &edgeTags)
+  {
+    _error("add line loop");
+  }
   void addRectangle(int tag, double x1, double y1, double z1,
                     double x2, double y2, double z2, double roundedRadius=0.)
-  { _error("add rectangle"); }
+  {
+    _error("add rectangle");
+  }
   void addDisk(int tag, double xc, double yc, double zc, double rx, double ry)
-  { _error("add disk"); }
-  void addPlaneSurface(int tag, std::vector<int> wireTags)
-  { _error("add plane surface"); }
-  void addSurfaceFilling(int tag, int wireTag){ _error("add surface filling"); }
-  void addSurfaceLoop(int tag, std::vector<int> faceTags){ _error("add surface loop"); }
-  void addVolume(int tag, std::vector<int> shellTags){ _error("add volume"); }
+  {
+    _error("add disk");
+  }
+  void addPlaneSurface(int tag, const std::vector<int> &wireTags)
+  {
+    _error("add plane surface");
+  }
+  void addSurfaceFilling(int tag, int wireTag)
+  {
+    _error("add surface filling");
+  }
+  void addSurfaceLoop(int tag, const std::vector<int> &faceTags)
+  {
+    _error("add surface loop");
+  }
+  void addVolume(int tag, const std::vector<int> &shellTags)
+  {
+    _error("add volume");
+  }
   void addSphere(int tag, double xc, double yc, double zc, double radius,
-                 double angle1, double angle2, double angle3){ _error("add sphere"); }
+                 double angle1, double angle2, double angle3)
+  {
+    _error("add sphere");
+  }
   void addBlock(int tag, double x1, double y1, double z1,
-                double x2, double y2, double z2){ _error("add block"); }
+                double x2, double y2, double z2)
+  {
+    _error("add block");
+  }
   void addCylinder(int tag, double x1, double y1, double z1, double x2, double y2,
-                   double z2, double r, double angle){ _error("add cylinder"); }
+                   double z2, double r, double angle)
+  {
+    _error("add cylinder");
+  }
   void addCone(int tag, double x1, double y1, double z1, double x2, double y2,
-               double z2, double r1, double r2, double angle){ _error("add cone"); }
+               double z2, double r1, double r2, double angle)
+  {
+    _error("add cone");
+  }
   void addWedge(int tag, double x, double y, double z, double dx, double dy,
-                double dz, double ltx){ _error("add wedge"); }
+                double dz, double ltx)
+
+  { _error("add wedge");
+  }
   void addTorus(int tag, double x, double y, double z, double r1, double r2,
-                double angle){ _error("add torus"); }
-  void addThruSections(int tag, std::vector<int> wireTags,
-                       std::vector<int> outTags[4],
-                       bool makeSolid, bool makeRuled){ _error("add thrusection"); }
-  void addThickSolid(int tag, int solidTag, std::vector<int> excludeFaceTags,
-                     double offset){ _error("add thick solid"); }
-  void extrude(int tag, std::vector<int> inTags[4],
+                double angle)
+  {
+    _error("add torus");
+  }
+  void addThruSections(int tag, const std::vector<int> &wireTags,
+                       std::vector<std::pair<int, int> > &outDimTags,
+                       bool makeSolid, bool makeRuled)
+  {
+    _error("add thrusection");
+  }
+  void addThickSolid(int tag, int solidTag, const std::vector<int> &excludeFaceTags,
+                     double offset)
+  {
+    _error("add thick solid");
+  }
+  void extrude(const std::vector<std::pair<int, int> > &inDimTags,
                double dx, double dy, double dz,
-               std::vector<int> outTags[4]){ _error("create extrusion"); }
-  void revolve(int tag, std::vector<int> inTags[4],
-               double x, double y, double z, double dx, double dy, double dz,
-               double angle, std::vector<int> outTags[4]){}
-  void addPipe(int tag, std::vector<int> inTags[4], int wireTag,
-               std::vector<int> outTags[4]){ _error("add pipe"); }
-  void fillet(std::vector<int> regionTags, std::vector<int> edgeTags,
-              double radius, std::vector<int> outTags[4]){ _error("create fillet"); }
+               std::vector<std::pair<int, int> > &outDimTags)
+  {
+    _error("extrude");
+  }
+  void revolve(const std::vector<std::pair<int, int> > &inDimTags,
+               double x, double y, double z, double ax, double ay, double az,
+               double angle, std::vector<std::pair<int, int> > &outDimTags)
+  {
+    _error("revolve");
+  }
+  void addPipe(const std::vector<std::pair<int, int> > &inDimTags, int wireTag,
+               std::vector<std::pair<int, int> > &outDimTags)
+  {
+    _error("add pipe");
+  }
+  void fillet(const std::vector<int> &regionTags, const std::vector<int> &edgeTags,
+              double radius, std::vector<std::pair<int, int> > &outDimTags)
+  {
+    _error("create fillet");
+  }
   void applyBooleanOperator(int tag, BooleanOperator op,
-                            std::vector<int> shapeTags[4],
-                            std::vector<int> toolTags[4],
-                            std::vector<int> outTags[4],
-                            bool removeShape=true,
-                            bool removeTool=true){ _error("apply boolean operator"); }
-  void translate(std::vector<int> inTags[4], double dx, double dy, double dz)
-  { _error("apply translation"); }
-  void rotate(std::vector<int> inTags[4], double x, double y, double z,
-              double dx, double dy, double dz, double angle){ _error("apply rotation"); }
-  int copy(int dim, int tag){ _error("copy shape"); return 0; }
+                            const std::vector<std::pair<int, int> > &objectDimTags
+                            const std::vector<std::pair<int, int> > &toolDimTags
+                            std::vector<std::pair<int, int> > &outDimTags,
+                             bool removeObject, bool removeTool)
+  {
+    _error("apply boolean operator");
+  }
+  void translate(const std::vector<std::pair<int, int> > &inDimTags,
+                 double dx, double dy, double dz)
+  {
+    _error("apply translation");
+  }
+  void rotate(const std::vector<std::pair<int, int> > &inDimTags,
+              double x, double y, double z, double ax, double ay, double az,
+              double angle)
+  {
+    _error("apply rotation");
+  }
+  void copy(const std::vector<std::pair<int, int> > &inDimTags,
+            std::vector<std::pair<int, int> > &outDimTags)
+  {
+    _error("copy shape");
+  }
   void remove(int dim, int tag){}
   void importShapes(const std::string &fileName, bool highestDimOnly,
-                    std::vector<int> outTags[4], const std::string &format="")
-  { _error("import shape"); }
+                    std::vector<std::pair<int, int> > &outDimTags,
+                    sconst std::string &format="")
+  {
+    _error("import shape");
+  }
   void exportShapes(const std::string &fileName, const std::string &format="")
-  { _error("export shape"); }
+  {
+    _error("export shape");
+  }
   void setMeshSize(int dim, int tag, double size){}
   void synchronize(GModel *model){}
   bool getVertex(int tag, double &x, double &y, double &z){ return false; }
diff --git a/Geo/Geo.cpp b/Geo/Geo.cpp
index 04528aa3988723e3a7ee43f08568019aced3ae7b..47cd8982cac1b28ac47170427193a2c545e4ed3f 100644
--- a/Geo/Geo.cpp
+++ b/Geo/Geo.cpp
@@ -3381,7 +3381,7 @@ static Curve *_create_splitted_curve(Curve *c, List_T *nodes)
   return cnew;
 }
 
-bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
+bool SplitCurve(int line_id, List_T *vertices_id, List_T *curves)
 {
   Curve *c = FindCurve(line_id);
   if(!c){
@@ -3415,9 +3415,9 @@ bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
     if(v_break.find(pv->Num) != v_break.end() && List_Nbr(new_list) > 1){
       if(last_periodic)
         break;
-      if(!(is_periodic&&first_periodic)){
+      if(!(is_periodic && first_periodic)){
         Curve *cnew = _create_splitted_curve(c, new_list);
-        List_Add(shapes, &cnew);
+        List_Add(curves, &cnew);
         List_Add(num_shapes, &cnew->Num);
       }
       first_periodic = false;
@@ -3431,18 +3431,18 @@ bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
   }
   if(List_Nbr(new_list) > 1){
     Curve *cnew = _create_splitted_curve(c, new_list);
-    List_Add(shapes, &cnew);
+    List_Add(curves, &cnew);
     List_Add(num_shapes, &cnew->Num);
   }
   // replace original curve by the new curves in all surfaces (and for
   // the opposite curve)
-  List_T *rshapes = List_Create(2, 1, sizeof(Shape));
-  int N = List_Nbr(shapes);
-  for(int i = 0; i < List_Nbr(shapes); i++){
+  List_T *rcurves = List_Create(2, 1, sizeof(Curve *));
+  int N = List_Nbr(curves);
+  for(int i = 0; i < List_Nbr(curves); i++){
     Curve *cc, *rcc;
-    List_Read(shapes, N - i - 1, &cc);
+    List_Read(curves, N - i - 1, &cc);
     rcc=FindCurve(-cc->Num);
-    List_Add(rshapes, &rcc);
+    List_Add(rcurves, &rcc);
   }
   List_T *Surfs = Tree2List(GModel::current()->getGEOInternals()->Surfaces);
   for(int i = 0; i < List_Nbr(Surfs); i++) {
@@ -3453,13 +3453,13 @@ bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
       List_Read(s->Generatrices, j, &surface_curve);
       if(surface_curve->Num == c->Num){
         List_Remove(s->Generatrices, j);
-        List_Insert_In_List(shapes, j, s->Generatrices);
-        j += List_Nbr(shapes) - 1;
+        List_Insert_In_List(curves, j, s->Generatrices);
+        j += List_Nbr(curves) - 1;
       }
       else if(surface_curve->Num == -c->Num){
         List_Remove(s->Generatrices, j);
-        List_Insert_In_List(rshapes, j, s->Generatrices);
-        j += List_Nbr(shapes) - 1;
+        List_Insert_In_List(rcurves, j, s->Generatrices);
+        j += List_Nbr(curves) - 1;
       }
     }
   }
@@ -3485,7 +3485,7 @@ bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes)
   DeleteCurve(c->Num);
   DeleteCurve(-c->Num);
   List_Delete(new_list);
-  List_Delete(rshapes);
+  List_Delete(rcurves);
   List_Delete(num_shapes);
   return true;
 }
@@ -3506,7 +3506,6 @@ static bool intersectCS(fullVector<double> &uvt, fullVector<double> &res, void *
   return true;
 }
 
-
 bool IntersectCurvesWithSurface(List_T *curve_ids, int surface_id, List_T *shapes)
 {
   Surface *s = FindSurface(surface_id);
diff --git a/Geo/Geo.h b/Geo/Geo.h
index 90af450373eb1d20678f931756380f3311335ed2..4435baff161869d804ffa19636f909713ac26a23 100644
--- a/Geo/Geo.h
+++ b/Geo/Geo.h
@@ -221,23 +221,6 @@ void ExtrudeShapes(int extrude_type, List_T *in,
                    double X0, double X1, double X2, double alpha,
                    ExtrudeParams *e,
                    List_T *out);
-int ExtrudePoint(int type, int ip,
-                 double T0, double T1, double T2,
-                 double A0, double A1, double A2,
-                 double X0, double X1, double X2, double alpha,
-                 Curve **pc, Curve **prc, int final,
-                 ExtrudeParams *e);
-int ExtrudeCurve(int type, int ic,
-                 double T0, double T1, double T2,
-                 double A0, double A1, double A2,
-                 double X0, double X1, double X2, double alpha,
-                 Surface **ps, int final,
-                 ExtrudeParams *e);
-int ExtrudeSurface(int type, int is,
-                   double T0, double T1, double T2,
-                   double A0, double A1, double A2,
-                   double X0, double X1, double X2, double alpha,
-                   Volume **pv, ExtrudeParams *e);
 void ProtudeXYZ(double &x, double &y, double &z, ExtrudeParams *e);
 
 void ReplaceAllDuplicates();
@@ -245,7 +228,7 @@ void ReplaceAllDuplicatesNew(double tol = -1.);
 
 bool ProjectPointOnSurface(Surface *s, Vertex &p, double uv[2]);
 bool IntersectCurvesWithSurface(List_T *curve_ids, int surface_id, List_T *shapes);
-bool SplitCurve(int line_id, List_T *vertices_id, List_T *shapes);
+bool SplitCurve(int line_id, List_T *vertices_id, List_T *curves);
 
 int RecognizeLineLoop(List_T *liste, int *loop);
 int RecognizeSurfaceLoop(List_T *liste, int *loop);
diff --git a/Parser/Gmsh.tab.cpp b/Parser/Gmsh.tab.cpp
index adbef9afc34c181d84e93d3d9dd1d124f804ea79..30dc7ca7de621a3d4ba5e096f3c8dce1926b702e 100644
--- a/Parser/Gmsh.tab.cpp
+++ b/Parser/Gmsh.tab.cpp
@@ -543,7 +543,6 @@
 #include "GModelIO_GEO.h"
 #include "GModelIO_OCC.h"
 #include "GeoDefines.h"
-#include "Geo.h" // FIXME: remove once Extrusion has been refactored
 #include "ExtrudeParams.h"
 #include "Options.h"
 #include "Parser.h"
@@ -629,8 +628,8 @@ int printListOfDouble(char *format, List_T *list, char *buffer);
 fullMatrix<double> ListOfListOfDouble2Matrix(List_T *list);
 void ListOfDouble2Vector(List_T *list, std::vector<int> &v);
 void ListOfDouble2Vector(List_T *list, std::vector<double> &v);
-void ListOfShapes2Vectors(List_T *list, std::vector<int> v[4]);
-void Vectors2ListOfShapes(std::vector<int> tags[4], List_T *list);
+void ListOfShapes2VectorOfPairs(List_T *list, std::vector<std::pair<int, int> > &v);
+void VectorOfPairs2ListOfShapes(const std::vector<std::pair<int, int> > &v, List_T *list);
 void addPeriodicEdge(int, int, const std::vector<double>&);
 void addPeriodicFace(int, int, const std::map<int, int>&);
 void addPeriodicFace(int, int, const std::vector<double>&);
@@ -643,8 +642,10 @@ void getElementaryTagsForPhysicalGroups(int dim, List_T *in, List_T *out);
 void getElementaryTagsInBoundingBox(int dim, double x1, double y1, double z1,
                                     double x2, double y2, double z2, List_T *out);
 void setVisibility(int dim, int visible, bool recursive);
-void setVisibility(std::vector<int> tags[4], int visible, bool recursive);
-void setColor(std::vector<int> tags[4], unsigned int val, bool recursive);
+void setVisibility(const std::vector<std::pair<int, int> > &dimTags, int visible,
+                   bool recursive);
+void setColor(const std::vector<std::pair<int, int> > &dimTags, unsigned int val,
+              bool recursive);
 
 double treat_Struct_FullName_dot_tSTRING_Float(char* c1, char* c2, char* c3);
 char* treat_Struct_FullName_dot_tSTRING_String(char* c1, char* c2, char* c3);
@@ -676,7 +677,7 @@ struct doubleXstring{
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 138 "Gmsh.y"
+#line 139 "Gmsh.y"
 {
   char *c;
   int i;
@@ -688,7 +689,7 @@ typedef union YYSTYPE
   struct TwoChar c2;
 }
 /* Line 193 of yacc.c.  */
-#line 692 "Gmsh.tab.cpp"
+#line 693 "Gmsh.tab.cpp"
 	YYSTYPE;
 # define yystype YYSTYPE /* obsolescent; will be withdrawn */
 # define YYSTYPE_IS_DECLARED 1
@@ -701,7 +702,7 @@ typedef union YYSTYPE
 
 
 /* Line 216 of yacc.c.  */
-#line 705 "Gmsh.tab.cpp"
+#line 706 "Gmsh.tab.cpp"
 
 #ifdef short
 # undef short
@@ -1367,62 +1368,62 @@ static const yytype_int16 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   237,   237,   238,   243,   245,   249,   250,   251,   252,
-     269,   270,   271,   272,   273,   274,   275,   276,   277,   278,
-     279,   280,   281,   282,   283,   284,   288,   292,   299,   304,
-     309,   323,   336,   349,   377,   391,   404,   417,   436,   441,
-     442,   443,   444,   445,   449,   451,   456,   458,   464,   568,
-     463,   586,   593,   604,   603,   621,   628,   639,   638,   655,
-     672,   695,   694,   708,   709,   710,   711,   712,   716,   717,
-     723,   723,   724,   724,   730,   731,   732,   733,   738,   744,
-     806,   822,   852,   862,   867,   875,   880,   888,   897,   902,
-     914,   931,   938,   947,   966,   985,   995,  1007,  1013,  1021,
-    1042,  1065,  1076,  1084,  1106,  1129,  1167,  1188,  1200,  1214,
-    1214,  1216,  1218,  1227,  1237,  1236,  1257,  1256,  1274,  1284,
-    1283,  1297,  1299,  1307,  1313,  1318,  1344,  1345,  1349,  1360,
-    1375,  1385,  1386,  1391,  1399,  1408,  1416,  1434,  1438,  1445,
-    1453,  1457,  1464,  1472,  1476,  1483,  1491,  1495,  1502,  1511,
-    1514,  1521,  1524,  1531,  1552,  1566,  1580,  1615,  1653,  1667,
-    1681,  1701,  1710,  1724,  1739,  1753,  1772,  1782,  1788,  1794,
-    1801,  1830,  1845,  1865,  1886,  1907,  1928,  1950,  1972,  1993,
-    2016,  2025,  2046,  2061,  2075,  2090,  2105,  2114,  2124,  2134,
-    2144,  2159,  2170,  2183,  2195,  2207,  2219,  2261,  2272,  2288,
-    2289,  2294,  2297,  2301,  2312,  2323,  2334,  2350,  2369,  2390,
-    2405,  2421,  2439,  2490,  2511,  2533,  2556,  2661,  2677,  2712,
-    2727,  2733,  2748,  2776,  2793,  2799,  2810,  2829,  2835,  2841,
-    2847,  2853,  2859,  2870,  2943,  2961,  2978,  2993,  3026,  3038,
-    3062,  3066,  3071,  3078,  3083,  3093,  3098,  3104,  3112,  3116,
-    3120,  3129,  3193,  3209,  3226,  3243,  3265,  3287,  3322,  3330,
-    3338,  3344,  3351,  3358,  3378,  3404,  3416,  3428,  3444,  3460,
-    3469,  3468,  3483,  3482,  3497,  3496,  3511,  3510,  3523,  3536,
-    3550,  3564,  3583,  3586,  3592,  3604,  3624,  3628,  3632,  3636,
-    3640,  3644,  3648,  3652,  3661,  3674,  3675,  3676,  3677,  3678,
-    3682,  3683,  3684,  3687,  3705,  3722,  3739,  3742,  3758,  3761,
-    3778,  3781,  3787,  3790,  3797,  3800,  3807,  3824,  3865,  3909,
-    3948,  3973,  3982,  4012,  4038,  4064,  4096,  4123,  4149,  4175,
-    4201,  4227,  4249,  4255,  4261,  4267,  4273,  4279,  4305,  4331,
-    4348,  4365,  4382,  4394,  4400,  4406,  4418,  4422,  4432,  4443,
-    4444,  4445,  4449,  4455,  4467,  4485,  4513,  4514,  4515,  4516,
-    4517,  4518,  4519,  4520,  4521,  4528,  4529,  4530,  4531,  4532,
-    4533,  4534,  4535,  4536,  4537,  4538,  4539,  4540,  4541,  4542,
-    4543,  4544,  4545,  4546,  4547,  4548,  4549,  4550,  4551,  4552,
-    4553,  4554,  4555,  4556,  4557,  4558,  4559,  4560,  4561,  4570,
-    4571,  4572,  4573,  4574,  4575,  4576,  4577,  4578,  4579,  4580,
-    4585,  4584,  4592,  4594,  4599,  4605,  4629,  4647,  4665,  4670,
-    4676,  4692,  4698,  4704,  4723,  4744,  4777,  4801,  4804,  4810,
-    4821,  4831,  4836,  4847,  4856,  4861,  4866,  4895,  4894,  4924,
-    4926,  4931,  4940,  4942,  4948,  4949,  4955,  4959,  4963,  4967,
-    4971,  4978,  4982,  4986,  4990,  4997,  5002,  5009,  5014,  5018,
-    5023,  5027,  5035,  5046,  5050,  5062,  5070,  5078,  5085,  5095,
-    5118,  5124,  5130,  5136,  5142,  5153,  5164,  5175,  5186,  5192,
-    5198,  5204,  5210,  5220,  5230,  5240,  5253,  5265,  5269,  5273,
-    5277,  5295,  5303,  5311,  5340,  5350,  5366,  5384,  5395,  5400,
-    5404,  5408,  5420,  5424,  5436,  5453,  5463,  5467,  5482,  5487,
-    5494,  5498,  5511,  5525,  5542,  5568,  5572,  5580,  5586,  5592,
-    5598,  5607,  5611,  5615,  5623,  5629,  5635,  5643,  5651,  5658,
-    5666,  5681,  5695,  5709,  5721,  5737,  5746,  5755,  5765,  5776,
-    5784,  5792,  5796,  5815,  5822,  5828,  5835,  5843,  5842,  5852,
-    5876,  5878,  5884,  5889,  5897,  5906,  5919,  5922,  5926
+       0,   238,   238,   239,   244,   246,   250,   251,   252,   253,
+     270,   271,   272,   273,   274,   275,   276,   277,   278,   279,
+     280,   281,   282,   283,   284,   285,   289,   293,   300,   305,
+     310,   324,   337,   350,   378,   392,   405,   418,   437,   442,
+     443,   444,   445,   446,   450,   452,   457,   459,   465,   569,
+     464,   587,   594,   605,   604,   622,   629,   640,   639,   656,
+     673,   696,   695,   709,   710,   711,   712,   713,   717,   718,
+     724,   724,   725,   725,   731,   732,   733,   734,   739,   745,
+     807,   823,   853,   863,   868,   876,   881,   889,   898,   903,
+     915,   932,   939,   948,   967,   986,   996,  1008,  1014,  1022,
+    1043,  1066,  1077,  1085,  1107,  1130,  1168,  1189,  1201,  1215,
+    1215,  1217,  1219,  1228,  1238,  1237,  1258,  1257,  1275,  1285,
+    1284,  1298,  1300,  1308,  1314,  1319,  1345,  1346,  1350,  1361,
+    1376,  1386,  1387,  1392,  1400,  1409,  1417,  1435,  1439,  1446,
+    1454,  1458,  1465,  1473,  1477,  1484,  1492,  1496,  1503,  1512,
+    1515,  1522,  1525,  1532,  1553,  1567,  1581,  1616,  1654,  1668,
+    1682,  1702,  1711,  1725,  1740,  1754,  1773,  1783,  1789,  1795,
+    1802,  1831,  1846,  1866,  1887,  1908,  1929,  1951,  1973,  1994,
+    2017,  2026,  2047,  2062,  2076,  2092,  2108,  2117,  2127,  2137,
+    2147,  2162,  2174,  2188,  2201,  2214,  2227,  2264,  2284,  2306,
+    2307,  2312,  2315,  2319,  2330,  2341,  2352,  2368,  2387,  2408,
+    2423,  2439,  2457,  2508,  2529,  2551,  2574,  2679,  2695,  2730,
+    2741,  2747,  2762,  2790,  2807,  2814,  2826,  2845,  2851,  2857,
+    2864,  2871,  2878,  2890,  2963,  2981,  2998,  3013,  3046,  3058,
+    3082,  3086,  3091,  3098,  3103,  3113,  3118,  3124,  3132,  3136,
+    3140,  3149,  3213,  3229,  3246,  3263,  3285,  3307,  3342,  3350,
+    3358,  3364,  3371,  3378,  3398,  3424,  3436,  3448,  3464,  3480,
+    3497,  3496,  3519,  3518,  3543,  3542,  3565,  3564,  3585,  3599,
+    3614,  3629,  3650,  3653,  3659,  3671,  3691,  3695,  3699,  3703,
+    3707,  3711,  3715,  3719,  3728,  3741,  3742,  3743,  3744,  3745,
+    3749,  3750,  3751,  3754,  3772,  3789,  3806,  3809,  3825,  3828,
+    3845,  3848,  3854,  3857,  3864,  3867,  3874,  3891,  3932,  3976,
+    4015,  4040,  4049,  4079,  4105,  4131,  4163,  4190,  4216,  4242,
+    4268,  4294,  4316,  4322,  4328,  4334,  4340,  4346,  4372,  4398,
+    4415,  4432,  4449,  4461,  4467,  4473,  4485,  4489,  4499,  4510,
+    4511,  4512,  4516,  4522,  4534,  4552,  4580,  4581,  4582,  4583,
+    4584,  4585,  4586,  4587,  4588,  4595,  4596,  4597,  4598,  4599,
+    4600,  4601,  4602,  4603,  4604,  4605,  4606,  4607,  4608,  4609,
+    4610,  4611,  4612,  4613,  4614,  4615,  4616,  4617,  4618,  4619,
+    4620,  4621,  4622,  4623,  4624,  4625,  4626,  4627,  4628,  4637,
+    4638,  4639,  4640,  4641,  4642,  4643,  4644,  4645,  4646,  4647,
+    4652,  4651,  4659,  4661,  4666,  4672,  4696,  4714,  4732,  4737,
+    4743,  4759,  4765,  4771,  4790,  4811,  4844,  4868,  4871,  4877,
+    4888,  4898,  4903,  4914,  4923,  4928,  4933,  4962,  4961,  4991,
+    4993,  4998,  5007,  5009,  5015,  5016,  5022,  5026,  5030,  5034,
+    5038,  5045,  5049,  5053,  5057,  5064,  5069,  5076,  5081,  5085,
+    5090,  5094,  5102,  5113,  5117,  5129,  5137,  5145,  5152,  5162,
+    5185,  5191,  5197,  5203,  5209,  5220,  5231,  5242,  5253,  5259,
+    5265,  5271,  5277,  5287,  5297,  5307,  5320,  5332,  5336,  5340,
+    5344,  5362,  5370,  5378,  5407,  5417,  5433,  5451,  5462,  5467,
+    5471,  5475,  5487,  5491,  5503,  5520,  5530,  5534,  5549,  5554,
+    5561,  5565,  5578,  5592,  5609,  5635,  5639,  5647,  5653,  5659,
+    5665,  5674,  5678,  5682,  5690,  5696,  5702,  5710,  5718,  5725,
+    5733,  5748,  5762,  5776,  5788,  5804,  5813,  5822,  5832,  5843,
+    5851,  5859,  5863,  5882,  5889,  5895,  5902,  5910,  5909,  5919,
+    5943,  5945,  5951,  5956,  5964,  5973,  5986,  5989,  5993
 };
 #endif
 
@@ -5895,27 +5896,27 @@ yyreduce:
   switch (yyn)
     {
         case 3:
-#line 238 "Gmsh.y"
+#line 239 "Gmsh.y"
     { yyerrok; return 1; ;}
     break;
 
   case 6:
-#line 249 "Gmsh.y"
+#line 250 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 7:
-#line 250 "Gmsh.y"
+#line 251 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 8:
-#line 251 "Gmsh.y"
+#line 252 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 9:
-#line 253 "Gmsh.y"
+#line 254 "Gmsh.y"
     {
       factory = (yyvsp[(3) - (5)].c);
       if(factory == "OpenCASCADE"){
@@ -5935,101 +5936,101 @@ yyreduce:
     break;
 
   case 10:
-#line 269 "Gmsh.y"
+#line 270 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 11:
-#line 270 "Gmsh.y"
+#line 271 "Gmsh.y"
     { List_Delete((yyvsp[(1) - (1)].l)); return 1; ;}
     break;
 
   case 12:
-#line 271 "Gmsh.y"
+#line 272 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 13:
-#line 272 "Gmsh.y"
+#line 273 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 14:
-#line 273 "Gmsh.y"
+#line 274 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 15:
-#line 274 "Gmsh.y"
+#line 275 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 16:
-#line 275 "Gmsh.y"
+#line 276 "Gmsh.y"
     { List_Delete((yyvsp[(1) - (1)].l)); return 1; ;}
     break;
 
   case 17:
-#line 276 "Gmsh.y"
+#line 277 "Gmsh.y"
     { List_Delete((yyvsp[(1) - (1)].l)); return 1; ;}
     break;
 
   case 18:
-#line 277 "Gmsh.y"
+#line 278 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 19:
-#line 278 "Gmsh.y"
+#line 279 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 20:
-#line 279 "Gmsh.y"
+#line 280 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 21:
-#line 280 "Gmsh.y"
+#line 281 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 22:
-#line 281 "Gmsh.y"
+#line 282 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 23:
-#line 282 "Gmsh.y"
+#line 283 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 24:
-#line 283 "Gmsh.y"
+#line 284 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 25:
-#line 284 "Gmsh.y"
+#line 285 "Gmsh.y"
     { return 1; ;}
     break;
 
   case 26:
-#line 289 "Gmsh.y"
+#line 290 "Gmsh.y"
     {
       (yyval.c) = (char*)"w";
     ;}
     break;
 
   case 27:
-#line 293 "Gmsh.y"
+#line 294 "Gmsh.y"
     {
       (yyval.c) = (char*)"a";
     ;}
     break;
 
   case 28:
-#line 300 "Gmsh.y"
+#line 301 "Gmsh.y"
     {
       Msg::Direct((yyvsp[(3) - (5)].c));
       Free((yyvsp[(3) - (5)].c));
@@ -6037,7 +6038,7 @@ yyreduce:
     break;
 
   case 29:
-#line 305 "Gmsh.y"
+#line 306 "Gmsh.y"
     {
       Msg::Error((yyvsp[(3) - (5)].c));
       Free((yyvsp[(3) - (5)].c));
@@ -6045,7 +6046,7 @@ yyreduce:
     break;
 
   case 30:
-#line 310 "Gmsh.y"
+#line 311 "Gmsh.y"
     {
       std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(6) - (7)].c));
       FILE *fp = Fopen(tmp.c_str(), (yyvsp[(5) - (7)].c));
@@ -6062,7 +6063,7 @@ yyreduce:
     break;
 
   case 31:
-#line 324 "Gmsh.y"
+#line 325 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = printListOfDouble((yyvsp[(3) - (7)].c), (yyvsp[(5) - (7)].l), tmpstring);
@@ -6078,7 +6079,7 @@ yyreduce:
     break;
 
   case 32:
-#line 337 "Gmsh.y"
+#line 338 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = printListOfDouble((yyvsp[(3) - (7)].c), (yyvsp[(5) - (7)].l), tmpstring);
@@ -6094,7 +6095,7 @@ yyreduce:
     break;
 
   case 33:
-#line 350 "Gmsh.y"
+#line 351 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = printListOfDouble((yyvsp[(3) - (9)].c), (yyvsp[(5) - (9)].l), tmpstring);
@@ -6120,7 +6121,7 @@ yyreduce:
     break;
 
   case 34:
-#line 378 "Gmsh.y"
+#line 379 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(1) - (6)].c), "View") && ViewData->finalize()){
@@ -6137,7 +6138,7 @@ yyreduce:
     break;
 
   case 35:
-#line 392 "Gmsh.y"
+#line 393 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (6)].c), "View")){
@@ -6153,7 +6154,7 @@ yyreduce:
     break;
 
   case 36:
-#line 405 "Gmsh.y"
+#line 406 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (6)].c), "View")){
@@ -6169,7 +6170,7 @@ yyreduce:
     break;
 
   case 37:
-#line 418 "Gmsh.y"
+#line 419 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (8)].c), "View")){
@@ -6187,7 +6188,7 @@ yyreduce:
     break;
 
   case 38:
-#line 436 "Gmsh.y"
+#line 437 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData = new PViewDataList();
@@ -6196,27 +6197,27 @@ yyreduce:
     break;
 
   case 44:
-#line 450 "Gmsh.y"
+#line 451 "Gmsh.y"
     { ViewCoord.push_back((yyvsp[(1) - (1)].d)); ;}
     break;
 
   case 45:
-#line 452 "Gmsh.y"
+#line 453 "Gmsh.y"
     { ViewCoord.push_back((yyvsp[(3) - (3)].d)); ;}
     break;
 
   case 46:
-#line 457 "Gmsh.y"
+#line 458 "Gmsh.y"
     { if(ViewValueList) ViewValueList->push_back((yyvsp[(1) - (1)].d)); ;}
     break;
 
   case 47:
-#line 459 "Gmsh.y"
+#line 460 "Gmsh.y"
     { if(ViewValueList) ViewValueList->push_back((yyvsp[(3) - (3)].d)); ;}
     break;
 
   case 48:
-#line 464 "Gmsh.y"
+#line 465 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strncmp((yyvsp[(1) - (1)].c), "SP", 2)){
@@ -6323,7 +6324,7 @@ yyreduce:
     break;
 
   case 49:
-#line 568 "Gmsh.y"
+#line 569 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(ViewValueList){
@@ -6336,7 +6337,7 @@ yyreduce:
     break;
 
   case 50:
-#line 578 "Gmsh.y"
+#line 579 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(ViewValueList) (*ViewNumList)++;
@@ -6345,7 +6346,7 @@ yyreduce:
     break;
 
   case 51:
-#line 587 "Gmsh.y"
+#line 588 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(1) - (1)].c)) + 1; i++) ViewData->T2C.push_back((yyvsp[(1) - (1)].c)[i]);
@@ -6355,7 +6356,7 @@ yyreduce:
     break;
 
   case 52:
-#line 594 "Gmsh.y"
+#line 595 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(3) - (3)].c)) + 1; i++) ViewData->T2C.push_back((yyvsp[(3) - (3)].c)[i]);
@@ -6365,7 +6366,7 @@ yyreduce:
     break;
 
   case 53:
-#line 604 "Gmsh.y"
+#line 605 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->T2D.push_back((yyvsp[(3) - (8)].d));
@@ -6377,7 +6378,7 @@ yyreduce:
     break;
 
   case 54:
-#line 613 "Gmsh.y"
+#line 614 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->NbT2++;
@@ -6386,7 +6387,7 @@ yyreduce:
     break;
 
   case 55:
-#line 622 "Gmsh.y"
+#line 623 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(1) - (1)].c)) + 1; i++) ViewData->T3C.push_back((yyvsp[(1) - (1)].c)[i]);
@@ -6396,7 +6397,7 @@ yyreduce:
     break;
 
   case 56:
-#line 629 "Gmsh.y"
+#line 630 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       for(int i = 0; i < (int)strlen((yyvsp[(3) - (3)].c)) + 1; i++) ViewData->T3C.push_back((yyvsp[(3) - (3)].c)[i]);
@@ -6406,7 +6407,7 @@ yyreduce:
     break;
 
   case 57:
-#line 639 "Gmsh.y"
+#line 640 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->T3D.push_back((yyvsp[(3) - (10)].d)); ViewData->T3D.push_back((yyvsp[(5) - (10)].d));
@@ -6417,7 +6418,7 @@ yyreduce:
     break;
 
   case 58:
-#line 647 "Gmsh.y"
+#line 648 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewData->NbT3++;
@@ -6426,7 +6427,7 @@ yyreduce:
     break;
 
   case 59:
-#line 657 "Gmsh.y"
+#line 658 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       int type =
@@ -6445,7 +6446,7 @@ yyreduce:
     break;
 
   case 60:
-#line 676 "Gmsh.y"
+#line 677 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       int type =
@@ -6464,7 +6465,7 @@ yyreduce:
     break;
 
   case 61:
-#line 695 "Gmsh.y"
+#line 696 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       ViewValueList = &ViewData->Time;
@@ -6473,68 +6474,68 @@ yyreduce:
     break;
 
   case 62:
-#line 701 "Gmsh.y"
+#line 702 "Gmsh.y"
     {
     ;}
     break;
 
   case 63:
-#line 708 "Gmsh.y"
+#line 709 "Gmsh.y"
     { (yyval.i) = 0; ;}
     break;
 
   case 64:
-#line 709 "Gmsh.y"
+#line 710 "Gmsh.y"
     { (yyval.i) = 1; ;}
     break;
 
   case 65:
-#line 710 "Gmsh.y"
+#line 711 "Gmsh.y"
     { (yyval.i) = 2; ;}
     break;
 
   case 66:
-#line 711 "Gmsh.y"
+#line 712 "Gmsh.y"
     { (yyval.i) = 3; ;}
     break;
 
   case 67:
-#line 712 "Gmsh.y"
+#line 713 "Gmsh.y"
     { (yyval.i) = 4; ;}
     break;
 
   case 68:
-#line 716 "Gmsh.y"
+#line 717 "Gmsh.y"
     { (yyval.i) = 1; ;}
     break;
 
   case 69:
-#line 717 "Gmsh.y"
+#line 718 "Gmsh.y"
     { (yyval.i) = -1; ;}
     break;
 
   case 70:
-#line 723 "Gmsh.y"
+#line 724 "Gmsh.y"
     { (yyval.c) = (char*)"("; ;}
     break;
 
   case 71:
-#line 723 "Gmsh.y"
+#line 724 "Gmsh.y"
     { (yyval.c) = (char*)"["; ;}
     break;
 
   case 72:
-#line 724 "Gmsh.y"
+#line 725 "Gmsh.y"
     { (yyval.c) = (char*)")"; ;}
     break;
 
   case 73:
-#line 724 "Gmsh.y"
+#line 725 "Gmsh.y"
     { (yyval.c) = (char*)"]"; ;}
     break;
 
   case 77:
-#line 734 "Gmsh.y"
+#line 735 "Gmsh.y"
     {
       Msg::SetOnelabNumber((yyvsp[(3) - (7)].c), (yyvsp[(5) - (7)].d));
       Free((yyvsp[(3) - (7)].c));
@@ -6542,7 +6543,7 @@ yyreduce:
     break;
 
   case 78:
-#line 739 "Gmsh.y"
+#line 740 "Gmsh.y"
     {
       Msg::SetOnelabString((yyvsp[(3) - (7)].c), (yyvsp[(5) - (7)].c));
       Free((yyvsp[(3) - (7)].c));
@@ -6551,7 +6552,7 @@ yyreduce:
     break;
 
   case 79:
-#line 745 "Gmsh.y"
+#line 746 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(1) - (4)].c)) && (yyvsp[(2) - (4)].i) && List_Nbr((yyvsp[(3) - (4)].l)) == 1){
         yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (4)].c));
@@ -6616,7 +6617,7 @@ yyreduce:
     break;
 
   case 80:
-#line 807 "Gmsh.y"
+#line 808 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(1) - (3)].c)))
 	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (3)].c));
@@ -6634,7 +6635,7 @@ yyreduce:
     break;
 
   case 81:
-#line 823 "Gmsh.y"
+#line 824 "Gmsh.y"
     {
       gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (6)].c)]);
       s.list = true;
@@ -6666,7 +6667,7 @@ yyreduce:
     break;
 
   case 82:
-#line 853 "Gmsh.y"
+#line 854 "Gmsh.y"
     {
       assignVariables((yyvsp[(1) - (9)].c), (yyvsp[(4) - (9)].l), (yyvsp[(7) - (9)].i), (yyvsp[(8) - (9)].l));
       Free((yyvsp[(1) - (9)].c));
@@ -6676,7 +6677,7 @@ yyreduce:
     break;
 
   case 83:
-#line 863 "Gmsh.y"
+#line 864 "Gmsh.y"
     {
       assignVariable((yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(5) - (7)].i), (yyvsp[(6) - (7)].d));
       Free((yyvsp[(1) - (7)].c));
@@ -6684,7 +6685,7 @@ yyreduce:
     break;
 
   case 84:
-#line 868 "Gmsh.y"
+#line 869 "Gmsh.y"
     {
       incrementVariable((yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].i));
       Free((yyvsp[(1) - (6)].c));
@@ -6692,7 +6693,7 @@ yyreduce:
     break;
 
   case 85:
-#line 876 "Gmsh.y"
+#line 877 "Gmsh.y"
     {
       assignVariable((yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(5) - (7)].i), (yyvsp[(6) - (7)].d));
       Free((yyvsp[(1) - (7)].c));
@@ -6700,7 +6701,7 @@ yyreduce:
     break;
 
   case 86:
-#line 881 "Gmsh.y"
+#line 882 "Gmsh.y"
     {
       incrementVariable((yyvsp[(1) - (6)].c), (yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].i));
       Free((yyvsp[(1) - (6)].c));
@@ -6708,7 +6709,7 @@ yyreduce:
     break;
 
   case 87:
-#line 889 "Gmsh.y"
+#line 890 "Gmsh.y"
     {
       gmsh_yystringsymbols[(yyvsp[(1) - (4)].c)] = std::vector<std::string>(1, (yyvsp[(3) - (4)].c));
       Free((yyvsp[(1) - (4)].c));
@@ -6717,7 +6718,7 @@ yyreduce:
     break;
 
   case 88:
-#line 898 "Gmsh.y"
+#line 899 "Gmsh.y"
     {
       gmsh_yystringsymbols[(yyvsp[(1) - (8)].c)] = std::vector<std::string>();
       Free((yyvsp[(1) - (8)].c));
@@ -6725,7 +6726,7 @@ yyreduce:
     break;
 
   case 89:
-#line 903 "Gmsh.y"
+#line 904 "Gmsh.y"
     {
       std::vector<std::string> s;
       for(int i = 0; i < List_Nbr((yyvsp[(7) - (9)].l)); i++){
@@ -6740,7 +6741,7 @@ yyreduce:
     break;
 
   case 90:
-#line 915 "Gmsh.y"
+#line 916 "Gmsh.y"
     {
       if(gmsh_yystringsymbols.count((yyvsp[(1) - (9)].c))){
         for(int i = 0; i < List_Nbr((yyvsp[(7) - (9)].l)); i++){
@@ -6757,7 +6758,7 @@ yyreduce:
     break;
 
   case 91:
-#line 932 "Gmsh.y"
+#line 933 "Gmsh.y"
     {
       std::string tmp((yyvsp[(5) - (6)].c));
       StringOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (6)].c), 0, (yyvsp[(3) - (6)].c), tmp);
@@ -6766,7 +6767,7 @@ yyreduce:
     break;
 
   case 92:
-#line 939 "Gmsh.y"
+#line 940 "Gmsh.y"
     {
       std::string tmp((yyvsp[(8) - (9)].c));
       StringOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), tmp);
@@ -6775,7 +6776,7 @@ yyreduce:
     break;
 
   case 93:
-#line 948 "Gmsh.y"
+#line 949 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (6)].c), 0, (yyvsp[(3) - (6)].c), d)){
@@ -6796,7 +6797,7 @@ yyreduce:
     break;
 
   case 94:
-#line 967 "Gmsh.y"
+#line 968 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (9)].c), (int)(yyvsp[(3) - (9)].d), (yyvsp[(6) - (9)].c), d)){
@@ -6817,7 +6818,7 @@ yyreduce:
     break;
 
   case 95:
-#line 986 "Gmsh.y"
+#line 987 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (5)].c), 0, (yyvsp[(3) - (5)].c), d)){
@@ -6829,7 +6830,7 @@ yyreduce:
     break;
 
   case 96:
-#line 996 "Gmsh.y"
+#line 997 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (8)].c), (int)(yyvsp[(3) - (8)].d), (yyvsp[(6) - (8)].c), d)){
@@ -6841,7 +6842,7 @@ yyreduce:
     break;
 
   case 97:
-#line 1008 "Gmsh.y"
+#line 1009 "Gmsh.y"
     {
       ColorOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (8)].c), 0, (yyvsp[(5) - (8)].c), (yyvsp[(7) - (8)].u));
       Free((yyvsp[(1) - (8)].c)); Free((yyvsp[(5) - (8)].c));
@@ -6849,7 +6850,7 @@ yyreduce:
     break;
 
   case 98:
-#line 1014 "Gmsh.y"
+#line 1015 "Gmsh.y"
     {
       ColorOption(GMSH_SET|GMSH_GUI, (yyvsp[(1) - (11)].c), (int)(yyvsp[(3) - (11)].d), (yyvsp[(8) - (11)].c), (yyvsp[(10) - (11)].u));
       Free((yyvsp[(1) - (11)].c)); Free((yyvsp[(8) - (11)].c));
@@ -6857,7 +6858,7 @@ yyreduce:
     break;
 
   case 99:
-#line 1022 "Gmsh.y"
+#line 1023 "Gmsh.y"
     {
       GmshColorTable *ct = GetColorTable(0);
       if(!ct)
@@ -6880,7 +6881,7 @@ yyreduce:
     break;
 
   case 100:
-#line 1043 "Gmsh.y"
+#line 1044 "Gmsh.y"
     {
       GmshColorTable *ct = GetColorTable((int)(yyvsp[(3) - (9)].d));
       if(!ct)
@@ -6903,7 +6904,7 @@ yyreduce:
     break;
 
   case 101:
-#line 1066 "Gmsh.y"
+#line 1067 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       if(!strcmp((yyvsp[(1) - (5)].c),"Background"))
@@ -6917,7 +6918,7 @@ yyreduce:
     break;
 
   case 102:
-#line 1077 "Gmsh.y"
+#line 1078 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       if(!GModel::current()->getFields()->newField((int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c)))
@@ -6928,7 +6929,7 @@ yyreduce:
     break;
 
   case 103:
-#line 1085 "Gmsh.y"
+#line 1086 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (9)].d));
@@ -6953,7 +6954,7 @@ yyreduce:
     break;
 
   case 104:
-#line 1107 "Gmsh.y"
+#line 1108 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (9)].d));
@@ -6979,7 +6980,7 @@ yyreduce:
     break;
 
   case 105:
-#line 1130 "Gmsh.y"
+#line 1131 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (11)].d));
@@ -7020,7 +7021,7 @@ yyreduce:
     break;
 
   case 106:
-#line 1168 "Gmsh.y"
+#line 1169 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       Field *field = GModel::current()->getFields()->get((int)(yyvsp[(3) - (7)].d));
@@ -7041,7 +7042,7 @@ yyreduce:
     break;
 
   case 107:
-#line 1189 "Gmsh.y"
+#line 1190 "Gmsh.y"
     {
 #if defined(HAVE_PLUGINS)
       try {
@@ -7056,7 +7057,7 @@ yyreduce:
     break;
 
   case 108:
-#line 1201 "Gmsh.y"
+#line 1202 "Gmsh.y"
     {
 #if defined(HAVE_PLUGINS)
       try {
@@ -7071,7 +7072,7 @@ yyreduce:
     break;
 
   case 112:
-#line 1219 "Gmsh.y"
+#line 1220 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (3)].c));
       std::vector<double> val(1, 0.);
@@ -7083,7 +7084,7 @@ yyreduce:
     break;
 
   case 113:
-#line 1228 "Gmsh.y"
+#line 1229 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (5)].c));
       std::vector<double> val(1, (yyvsp[(5) - (5)].d));
@@ -7095,12 +7096,12 @@ yyreduce:
     break;
 
   case 114:
-#line 1237 "Gmsh.y"
+#line 1238 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
   case 115:
-#line 1239 "Gmsh.y"
+#line 1240 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(6) - (9)].l)) != 1)
 	yymsg(1, "List notation should be used to define list '%s[]'", (yyvsp[(3) - (9)].c));
@@ -7121,12 +7122,12 @@ yyreduce:
     break;
 
   case 116:
-#line 1257 "Gmsh.y"
+#line 1258 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
   case 117:
-#line 1259 "Gmsh.y"
+#line 1260 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (11)].c));
       std::vector<double> val;
@@ -7145,7 +7146,7 @@ yyreduce:
     break;
 
   case 118:
-#line 1275 "Gmsh.y"
+#line 1276 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (5)].c)), val((yyvsp[(5) - (5)].c));
       if(!gmsh_yystringsymbols.count(key)){
@@ -7157,12 +7158,12 @@ yyreduce:
     break;
 
   case 119:
-#line 1284 "Gmsh.y"
+#line 1285 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
   case 120:
-#line 1286 "Gmsh.y"
+#line 1287 "Gmsh.y"
     {
       std::string key((yyvsp[(3) - (9)].c)), val((yyvsp[(6) - (9)].c));
       if(!gmsh_yysymbols.count(key)){
@@ -7175,7 +7176,7 @@ yyreduce:
     break;
 
   case 122:
-#line 1300 "Gmsh.y"
+#line 1301 "Gmsh.y"
     {
       std::string name((yyvsp[(3) - (3)].c));
       Msg::UndefineOnelabParameter(name);
@@ -7184,7 +7185,7 @@ yyreduce:
     break;
 
   case 123:
-#line 1308 "Gmsh.y"
+#line 1309 "Gmsh.y"
     {
       (yyval.l) = List_Create(20,20,sizeof(doubleXstring));
       doubleXstring v = {(yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].c)};
@@ -7193,7 +7194,7 @@ yyreduce:
     break;
 
   case 124:
-#line 1314 "Gmsh.y"
+#line 1315 "Gmsh.y"
     {
       doubleXstring v = {(yyvsp[(3) - (5)].d), (yyvsp[(5) - (5)].c)};
       List_Add((yyval.l), &v);
@@ -7201,7 +7202,7 @@ yyreduce:
     break;
 
   case 125:
-#line 1319 "Gmsh.y"
+#line 1320 "Gmsh.y"
     {
       (yyval.l) = List_Create(20,20,sizeof(doubleXstring));
       int n = List_Nbr((yyvsp[(1) - (5)].l));
@@ -7228,7 +7229,7 @@ yyreduce:
     break;
 
   case 128:
-#line 1350 "Gmsh.y"
+#line 1351 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (3)].l)); i++){
@@ -7242,7 +7243,7 @@ yyreduce:
     break;
 
   case 129:
-#line 1361 "Gmsh.y"
+#line 1362 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (5)].c));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -7259,7 +7260,7 @@ yyreduce:
     break;
 
   case 130:
-#line 1376 "Gmsh.y"
+#line 1377 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       std::string val((yyvsp[(3) - (3)].c));
@@ -7270,7 +7271,7 @@ yyreduce:
     break;
 
   case 133:
-#line 1392 "Gmsh.y"
+#line 1393 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       double val = (yyvsp[(3) - (3)].d);
@@ -7280,7 +7281,7 @@ yyreduce:
     break;
 
   case 134:
-#line 1400 "Gmsh.y"
+#line 1401 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (3)].c));
       std::string val((yyvsp[(3) - (3)].c));
@@ -7291,7 +7292,7 @@ yyreduce:
     break;
 
   case 135:
-#line 1409 "Gmsh.y"
+#line 1410 "Gmsh.y"
     {
       std::string key("Macro");
       std::string val((yyvsp[(3) - (3)].c));
@@ -7301,7 +7302,7 @@ yyreduce:
     break;
 
   case 136:
-#line 1417 "Gmsh.y"
+#line 1418 "Gmsh.y"
     {
       std::string key((yyvsp[(2) - (5)].c));
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (5)].l)); i++){
@@ -7317,14 +7318,14 @@ yyreduce:
     break;
 
   case 137:
-#line 1435 "Gmsh.y"
+#line 1436 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(1) - (1)].d);
     ;}
     break;
 
   case 138:
-#line 1439 "Gmsh.y"
+#line 1440 "Gmsh.y"
     {
       int t = GModel::current()->getGEOInternals()->getMaxPhysicalTag();
       GModel::current()->getGEOInternals()->setMaxPhysicalTag(t + 1);
@@ -7334,7 +7335,7 @@ yyreduce:
     break;
 
   case 139:
-#line 1446 "Gmsh.y"
+#line 1447 "Gmsh.y"
     {
       (yyval.i) = GModel::current()->setPhysicalName(std::string((yyvsp[(1) - (3)].c)), 0, (yyvsp[(3) - (3)].d));
       Free((yyvsp[(1) - (3)].c));
@@ -7342,14 +7343,14 @@ yyreduce:
     break;
 
   case 140:
-#line 1454 "Gmsh.y"
+#line 1455 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(1) - (1)].d);
     ;}
     break;
 
   case 141:
-#line 1458 "Gmsh.y"
+#line 1459 "Gmsh.y"
     {
       int t = GModel::current()->getGEOInternals()->getMaxPhysicalTag();
       GModel::current()->getGEOInternals()->setMaxPhysicalTag(t + 1);
@@ -7359,7 +7360,7 @@ yyreduce:
     break;
 
   case 142:
-#line 1465 "Gmsh.y"
+#line 1466 "Gmsh.y"
     {
       (yyval.i) = GModel::current()->setPhysicalName(std::string((yyvsp[(1) - (3)].c)), 1, (yyvsp[(3) - (3)].d));
       Free((yyvsp[(1) - (3)].c));
@@ -7367,14 +7368,14 @@ yyreduce:
     break;
 
   case 143:
-#line 1473 "Gmsh.y"
+#line 1474 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(1) - (1)].d);
     ;}
     break;
 
   case 144:
-#line 1477 "Gmsh.y"
+#line 1478 "Gmsh.y"
     {
       int t = GModel::current()->getGEOInternals()->getMaxPhysicalTag();
       GModel::current()->getGEOInternals()->setMaxPhysicalTag(t + 1);
@@ -7384,7 +7385,7 @@ yyreduce:
     break;
 
   case 145:
-#line 1484 "Gmsh.y"
+#line 1485 "Gmsh.y"
     {
       (yyval.i) = GModel::current()->setPhysicalName(std::string((yyvsp[(1) - (3)].c)), 2, (yyvsp[(3) - (3)].d));
       Free((yyvsp[(1) - (3)].c));
@@ -7392,14 +7393,14 @@ yyreduce:
     break;
 
   case 146:
-#line 1492 "Gmsh.y"
+#line 1493 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(1) - (1)].d);
     ;}
     break;
 
   case 147:
-#line 1496 "Gmsh.y"
+#line 1497 "Gmsh.y"
     {
       int t = GModel::current()->getGEOInternals()->getMaxPhysicalTag();
       GModel::current()->getGEOInternals()->setMaxPhysicalTag(t + 1);
@@ -7409,7 +7410,7 @@ yyreduce:
     break;
 
   case 148:
-#line 1503 "Gmsh.y"
+#line 1504 "Gmsh.y"
     {
       (yyval.i) = GModel::current()->setPhysicalName(std::string((yyvsp[(1) - (3)].c)), 3, (yyvsp[(3) - (3)].d));
       Free((yyvsp[(1) - (3)].c));
@@ -7417,35 +7418,35 @@ yyreduce:
     break;
 
   case 149:
-#line 1511 "Gmsh.y"
+#line 1512 "Gmsh.y"
     {
       (yyval.i) = -1;
     ;}
     break;
 
   case 150:
-#line 1515 "Gmsh.y"
+#line 1516 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(4) - (5)].d);
     ;}
     break;
 
   case 151:
-#line 1521 "Gmsh.y"
+#line 1522 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++) (yyval.v)[i] = 0.;
     ;}
     break;
 
   case 152:
-#line 1525 "Gmsh.y"
+#line 1526 "Gmsh.y"
     {
       for(int i = 0; i < 4; i++) (yyval.v)[i] = (yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
   case 153:
-#line 1532 "Gmsh.y"
+#line 1533 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       double x = CTX::instance()->geom.scalingFactor * (yyvsp[(6) - (7)].v)[0];
@@ -7469,7 +7470,7 @@ yyreduce:
     break;
 
   case 154:
-#line 1553 "Gmsh.y"
+#line 1554 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -7486,7 +7487,7 @@ yyreduce:
     break;
 
   case 155:
-#line 1567 "Gmsh.y"
+#line 1568 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -7503,7 +7504,7 @@ yyreduce:
     break;
 
   case 156:
-#line 1581 "Gmsh.y"
+#line 1582 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (8)].l), tags);
@@ -7541,7 +7542,7 @@ yyreduce:
     break;
 
   case 157:
-#line 1616 "Gmsh.y"
+#line 1617 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (8)].l), tags);
@@ -7582,7 +7583,7 @@ yyreduce:
     break;
 
   case 158:
-#line 1654 "Gmsh.y"
+#line 1655 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -7599,7 +7600,7 @@ yyreduce:
     break;
 
   case 159:
-#line 1668 "Gmsh.y"
+#line 1669 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -7616,7 +7617,7 @@ yyreduce:
     break;
 
   case 160:
-#line 1683 "Gmsh.y"
+#line 1684 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (11)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (11)].l), tags);
@@ -7638,7 +7639,7 @@ yyreduce:
     break;
 
   case 161:
-#line 1702 "Gmsh.y"
+#line 1703 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(7) - (8)].l), tags);
@@ -7650,7 +7651,7 @@ yyreduce:
     break;
 
   case 162:
-#line 1711 "Gmsh.y"
+#line 1712 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -7667,7 +7668,7 @@ yyreduce:
     break;
 
   case 163:
-#line 1725 "Gmsh.y"
+#line 1726 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(7) - (8)].l), tags);
@@ -7685,7 +7686,7 @@ yyreduce:
     break;
 
   case 164:
-#line 1740 "Gmsh.y"
+#line 1741 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(7) - (8)].l), tags);
@@ -7702,7 +7703,7 @@ yyreduce:
     break;
 
   case 165:
-#line 1754 "Gmsh.y"
+#line 1755 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (8)].d);
       std::vector<int> wires; ListOfDouble2Vector((yyvsp[(6) - (8)].l), wires);
@@ -7724,7 +7725,7 @@ yyreduce:
     break;
 
   case 166:
-#line 1773 "Gmsh.y"
+#line 1774 "Gmsh.y"
     {
       yymsg(2, "'Ruled Surface' command is deprecated: use 'Surface' instead");
       int num = (int)(yyvsp[(4) - (9)].d);
@@ -7737,7 +7738,7 @@ yyreduce:
     break;
 
   case 167:
-#line 1783 "Gmsh.y"
+#line 1784 "Gmsh.y"
     {
       myGmshSurface = 0;
       (yyval.s).Type = 0;
@@ -7746,7 +7747,7 @@ yyreduce:
     break;
 
   case 168:
-#line 1789 "Gmsh.y"
+#line 1790 "Gmsh.y"
     {
       myGmshSurface = gmshSurface::getSurface((int)(yyvsp[(3) - (4)].d));
       (yyval.s).Type = 0;
@@ -7755,7 +7756,7 @@ yyreduce:
     break;
 
   case 169:
-#line 1795 "Gmsh.y"
+#line 1796 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (10)].d);
       myGmshSurface = gmshParametricSurface::NewParametricSurface(num, (yyvsp[(7) - (10)].c), (yyvsp[(8) - (10)].c), (yyvsp[(9) - (10)].c));
@@ -7765,7 +7766,7 @@ yyreduce:
     break;
 
   case 170:
-#line 1802 "Gmsh.y"
+#line 1803 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -7797,7 +7798,7 @@ yyreduce:
     break;
 
   case 171:
-#line 1831 "Gmsh.y"
+#line 1832 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -7815,7 +7816,7 @@ yyreduce:
     break;
 
   case 172:
-#line 1846 "Gmsh.y"
+#line 1847 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -7838,7 +7839,7 @@ yyreduce:
     break;
 
   case 173:
-#line 1866 "Gmsh.y"
+#line 1867 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -7862,7 +7863,7 @@ yyreduce:
     break;
 
   case 174:
-#line 1887 "Gmsh.y"
+#line 1888 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -7886,7 +7887,7 @@ yyreduce:
     break;
 
   case 175:
-#line 1908 "Gmsh.y"
+#line 1909 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -7910,7 +7911,7 @@ yyreduce:
     break;
 
   case 176:
-#line 1929 "Gmsh.y"
+#line 1930 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -7935,7 +7936,7 @@ yyreduce:
     break;
 
   case 177:
-#line 1951 "Gmsh.y"
+#line 1952 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -7960,7 +7961,7 @@ yyreduce:
     break;
 
   case 178:
-#line 1973 "Gmsh.y"
+#line 1974 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -7984,7 +7985,7 @@ yyreduce:
     break;
 
   case 179:
-#line 1994 "Gmsh.y"
+#line 1995 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<double> param; ListOfDouble2Vector((yyvsp[(6) - (7)].l), param);
@@ -8010,7 +8011,7 @@ yyreduce:
     break;
 
   case 180:
-#line 2017 "Gmsh.y"
+#line 2018 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(7) - (8)].l), tags);
@@ -8022,7 +8023,7 @@ yyreduce:
     break;
 
   case 181:
-#line 2027 "Gmsh.y"
+#line 2028 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (12)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(7) - (12)].l), tags);
@@ -8045,7 +8046,7 @@ yyreduce:
     break;
 
   case 182:
-#line 2047 "Gmsh.y"
+#line 2048 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(7) - (8)].l), tags);
@@ -8063,7 +8064,7 @@ yyreduce:
     break;
 
   case 183:
-#line 2062 "Gmsh.y"
+#line 2063 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (7)].l), tags);
@@ -8080,13 +8081,14 @@ yyreduce:
     break;
 
   case 184:
-#line 2076 "Gmsh.y"
+#line 2077 "Gmsh.y"
     {
       int num = (int)(yyvsp[(3) - (7)].d);
-      std::vector<int> wires, out[4]; ListOfDouble2Vector((yyvsp[(6) - (7)].l), wires);
+      std::vector<int> wires; ListOfDouble2Vector((yyvsp[(6) - (7)].l), wires);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        std::vector<std::pair<int, int> > outDimTags;
         GModel::current()->getOCCInternals()->addThruSections
-          (num, wires, out, true, false);
+          (num, wires, outDimTags, true, false);
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -8098,13 +8100,14 @@ yyreduce:
     break;
 
   case 185:
-#line 2091 "Gmsh.y"
+#line 2093 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
-      std::vector<int> wires, out[4]; ListOfDouble2Vector((yyvsp[(7) - (8)].l), wires);
+      std::vector<int> wires; ListOfDouble2Vector((yyvsp[(7) - (8)].l), wires);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        std::vector<std::pair<int, int> > outDimTags;
         GModel::current()->getOCCInternals()->addThruSections
-          (num, wires, out, true, true);
+          (num, wires, outDimTags, true, true);
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -8116,7 +8119,7 @@ yyreduce:
     break;
 
   case 186:
-#line 2106 "Gmsh.y"
+#line 2109 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].d);
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(7) - (8)].l), tags);
@@ -8128,7 +8131,7 @@ yyreduce:
     break;
 
   case 187:
-#line 2115 "Gmsh.y"
+#line 2118 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       int op = (yyvsp[(6) - (8)].i);
@@ -8141,7 +8144,7 @@ yyreduce:
     break;
 
   case 188:
-#line 2125 "Gmsh.y"
+#line 2128 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       int op = (yyvsp[(6) - (8)].i);
@@ -8154,7 +8157,7 @@ yyreduce:
     break;
 
   case 189:
-#line 2135 "Gmsh.y"
+#line 2138 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       int op = (yyvsp[(6) - (8)].i);
@@ -8167,7 +8170,7 @@ yyreduce:
     break;
 
   case 190:
-#line 2145 "Gmsh.y"
+#line 2148 "Gmsh.y"
     {
       int num = (int)(yyvsp[(4) - (8)].i);
       int op = (yyvsp[(6) - (8)].i);
@@ -8180,97 +8183,99 @@ yyreduce:
     break;
 
   case 191:
-#line 2160 "Gmsh.y"
+#line 2163 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(4) - (5)].l), tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (5)].l), dimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        GModel::current()->getOCCInternals()->translate(tags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2]);
+        GModel::current()->getOCCInternals()->translate(dimTags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2]);
       }
       else{
-        GModel::current()->getGEOInternals()->translate(tags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2]);
+        GModel::current()->getGEOInternals()->translate(dimTags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2]);
       }
       (yyval.l) = (yyvsp[(4) - (5)].l);
     ;}
     break;
 
   case 192:
-#line 2171 "Gmsh.y"
+#line 2175 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(10) - (11)].l), tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(10) - (11)].l), dimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
         GModel::current()->getOCCInternals()->rotate
-          (tags, (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(7) - (11)].d));
+          (dimTags, (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(7) - (11)].d));
       }
       else{
         GModel::current()->getGEOInternals()->rotate
-          (tags, (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(7) - (11)].d));
+          (dimTags, (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(7) - (11)].d));
       }
       (yyval.l) = (yyvsp[(10) - (11)].l);
     ;}
     break;
 
   case 193:
-#line 2184 "Gmsh.y"
+#line 2189 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(4) - (5)].l), tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (5)].l), dimTags);
       if(factory == "OpenCASCADE"){
         Msg::Error("Symmetry not implemented yet with OpenCASCADE factory");
       }
       else{
         GModel::current()->getGEOInternals()->symmetry
-          (tags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], (yyvsp[(2) - (5)].v)[3]);
+          (dimTags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], (yyvsp[(2) - (5)].v)[3]);
       }
       (yyval.l) = (yyvsp[(4) - (5)].l);
     ;}
     break;
 
   case 194:
-#line 2196 "Gmsh.y"
+#line 2202 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(8) - (9)].l), tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(8) - (9)].l), dimTags);
       if(factory == "OpenCASCADE"){
         yymsg(0, "Dilate not implemented yet with OpenCASCADE factory");
       }
       else{
         GModel::current()->getGEOInternals()->dilate
-          (tags, (yyvsp[(3) - (9)].v)[0], (yyvsp[(3) - (9)].v)[1], (yyvsp[(3) - (9)].v)[2], (yyvsp[(5) - (9)].d), (yyvsp[(5) - (9)].d), (yyvsp[(5) - (9)].d));
+          (dimTags, (yyvsp[(3) - (9)].v)[0], (yyvsp[(3) - (9)].v)[1], (yyvsp[(3) - (9)].v)[2], (yyvsp[(5) - (9)].d), (yyvsp[(5) - (9)].d), (yyvsp[(5) - (9)].d));
       }
       (yyval.l) = (yyvsp[(8) - (9)].l);
     ;}
     break;
 
   case 195:
-#line 2208 "Gmsh.y"
+#line 2215 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(8) - (9)].l), tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(8) - (9)].l), dimTags);
       if(factory == "OpenCASCADE"){
         yymsg(0, "Dilate not implemented yet with OpenCASCADE factory");
       }
       else{
         GModel::current()->getGEOInternals()->dilate
-          (tags, (yyvsp[(3) - (9)].v)[0], (yyvsp[(3) - (9)].v)[1], (yyvsp[(3) - (9)].v)[2], (yyvsp[(5) - (9)].v)[0], (yyvsp[(5) - (9)].v)[1], (yyvsp[(5) - (9)].v)[2]);
+          (dimTags, (yyvsp[(3) - (9)].v)[0], (yyvsp[(3) - (9)].v)[1], (yyvsp[(3) - (9)].v)[2], (yyvsp[(5) - (9)].v)[0], (yyvsp[(5) - (9)].v)[1], (yyvsp[(5) - (9)].v)[2]);
       }
       (yyval.l) = (yyvsp[(8) - (9)].l);
     ;}
     break;
 
   case 196:
-#line 2220 "Gmsh.y"
+#line 2228 "Gmsh.y"
     {
-      (yyval.l) = List_Create(3, 3, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(3) - (4)].l), inDimTags);
+      (yyval.l) = (yyvsp[(3) - (4)].l);
+      List_Reset((yyval.l));
       std::string action((yyvsp[(1) - (4)].c));
       if(action == "Duplicata"){
-        // don't use per-dimension vectors here, in order to respect the input
-        // ordering (points can e.g. be given after surfaces) in the output
-        for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
-          Shape s; List_Read((yyvsp[(3) - (4)].l), i, &s); int dim = s.Type / 100 - 1;
-          if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-            s.Num = GModel::current()->getOCCInternals()->copy(dim, s.Num);
-          }
-          else{
-            s.Num = GModel::current()->getGEOInternals()->copy(dim, s.Num);
-          }
-          List_Add((yyval.l), &s);
+        if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+          GModel::current()->getOCCInternals()->copy(inDimTags, outDimTags);
+        }
+        else{
+          GModel::current()->getGEOInternals()->copy(inDimTags, outDimTags);
         }
       }
       else if(action == "Boundary" ||
@@ -8285,76 +8290,88 @@ yyreduce:
           GModel::current()->getOCCInternals()->synchronize(GModel::current());
         if(GModel::current()->getGEOInternals()->getChanged())
           GModel::current()->getGEOInternals()->synchronize(GModel::current());
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors((yyvsp[(3) - (4)].l), in);
         GModel::current()->getBoundaryTags
-          (in, out, action.find("Combined") != std::string::npos,
+          (inDimTags, outDimTags, action.find("Combined") != std::string::npos,
            action.find("Oriented") != std::string::npos);
-        Vectors2ListOfShapes(out, (yyval.l));
       }
       else{
         yymsg(0, "Unknown action on multiple shapes: %s", (yyvsp[(1) - (4)].c));
       }
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
       Free((yyvsp[(1) - (4)].c));
-      List_Delete((yyvsp[(3) - (4)].l));
     ;}
     break;
 
   case 197:
-#line 2262 "Gmsh.y"
+#line 2265 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE"){
-        yymsg(0, "Intersect Line not available with OpenCASCADE");
+        yymsg(0, "Intersect line not available with OpenCASCADE");
       }
       else{
-        IntersectCurvesWithSurface((yyvsp[(4) - (9)].l), (int)(yyvsp[(8) - (9)].d), (yyval.l));
+        std::vector<int> in, out; ListOfDouble2Vector((yyvsp[(4) - (9)].l), in);
+        GModel::current()->getGEOInternals()->intersectCurvesWithSurface
+          (in, (int)(yyvsp[(8) - (9)].d), out);
+        for(unsigned int i = 0; i < out.size(); i++){
+          Shape s;
+          s.Type = MSH_POINT;
+          s.Num = out[i];
+          List_Add((yyval.l), &s);
+        }
       }
       List_Delete((yyvsp[(4) - (9)].l));
     ;}
     break;
 
   case 198:
-#line 2273 "Gmsh.y"
+#line 2285 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape*));
+      (yyval.l) = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE"){
         yymsg(0, "Split Line not available with OpenCASCADE");
       }
       else{
-        List_T *tmp = ListOfDouble2ListOfInt((yyvsp[(7) - (9)].l));
-        SplitCurve((int)(yyvsp[(4) - (9)].d), tmp, (yyval.l));
-        List_Delete(tmp);
+        std::vector<int> vertices, curves; ListOfDouble2Vector((yyvsp[(7) - (9)].l), vertices);
+        GModel::current()->getGEOInternals()->splitCurve
+          ((int)(yyvsp[(4) - (9)].d), vertices, curves);
+        for(unsigned int i = 0; i < curves.size(); i++){
+          Shape s;
+          s.Type = MSH_SEGM_LINE;
+          s.Num = curves[i];
+          List_Add((yyval.l), &s);
+        }
       }
       List_Delete((yyvsp[(7) - (9)].l));
     ;}
     break;
 
   case 199:
-#line 2288 "Gmsh.y"
+#line 2306 "Gmsh.y"
     { (yyval.l) = (yyvsp[(1) - (1)].l); ;}
     break;
 
   case 200:
-#line 2289 "Gmsh.y"
+#line 2307 "Gmsh.y"
     { (yyval.l) = (yyvsp[(1) - (1)].l); ;}
     break;
 
   case 201:
-#line 2294 "Gmsh.y"
+#line 2312 "Gmsh.y"
     {
       (yyval.l) = List_Create(3, 3, sizeof(Shape));
     ;}
     break;
 
   case 202:
-#line 2298 "Gmsh.y"
+#line 2316 "Gmsh.y"
     {
       List_Add((yyval.l), &(yyvsp[(2) - (2)].s));
     ;}
     break;
 
   case 203:
-#line 2302 "Gmsh.y"
+#line 2320 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -8368,7 +8385,7 @@ yyreduce:
     break;
 
   case 204:
-#line 2313 "Gmsh.y"
+#line 2331 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -8382,7 +8399,7 @@ yyreduce:
     break;
 
   case 205:
-#line 2324 "Gmsh.y"
+#line 2342 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -8396,7 +8413,7 @@ yyreduce:
     break;
 
   case 206:
-#line 2335 "Gmsh.y"
+#line 2353 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (6)].l)); i++){
 	double d;
@@ -8410,7 +8427,7 @@ yyreduce:
     break;
 
   case 207:
-#line 2351 "Gmsh.y"
+#line 2369 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(7) - (8)].l)) == 4){
         int t = (int)(yyvsp[(4) - (8)].d);
@@ -8432,7 +8449,7 @@ yyreduce:
     break;
 
   case 208:
-#line 2370 "Gmsh.y"
+#line 2388 "Gmsh.y"
     {
       int t = (int)(yyvsp[(4) - (10)].d);
       if(gLevelset::find(t)){
@@ -8456,7 +8473,7 @@ yyreduce:
     break;
 
   case 209:
-#line 2392 "Gmsh.y"
+#line 2410 "Gmsh.y"
     {
       int t = (int)(yyvsp[(4) - (14)].d);
       if(gLevelset::find(t)){
@@ -8473,7 +8490,7 @@ yyreduce:
     break;
 
   case 210:
-#line 2407 "Gmsh.y"
+#line 2425 "Gmsh.y"
     {
       int t = (int)(yyvsp[(4) - (16)].d);
       if(gLevelset::find(t)){
@@ -8491,7 +8508,7 @@ yyreduce:
     break;
 
   case 211:
-#line 2422 "Gmsh.y"
+#line 2440 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(10) - (12)].l)) == 1){
         int t = (int)(yyvsp[(4) - (12)].d);
@@ -8512,7 +8529,7 @@ yyreduce:
     break;
 
   case 212:
-#line 2441 "Gmsh.y"
+#line 2459 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(12) - (14)].l)) == 1){
         int t = (int)(yyvsp[(4) - (14)].d);
@@ -8565,7 +8582,7 @@ yyreduce:
     break;
 
   case 213:
-#line 2492 "Gmsh.y"
+#line 2510 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(12) - (14)].l)) == 1){
         int t = (int)(yyvsp[(4) - (14)].d);
@@ -8588,7 +8605,7 @@ yyreduce:
     break;
 
   case 214:
-#line 2513 "Gmsh.y"
+#line 2531 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(12) - (14)].l)) == 3){
         int t = (int)(yyvsp[(4) - (14)].d);
@@ -8612,7 +8629,7 @@ yyreduce:
     break;
 
   case 215:
-#line 2535 "Gmsh.y"
+#line 2553 "Gmsh.y"
     {
       if(List_Nbr((yyvsp[(12) - (14)].l)) == 5){
         int t = (int)(yyvsp[(4) - (14)].d);
@@ -8637,7 +8654,7 @@ yyreduce:
     break;
 
   case 216:
-#line 2557 "Gmsh.y"
+#line 2575 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (8)].c), "Union")){
         int t = (int)(yyvsp[(4) - (8)].d);
@@ -8745,7 +8762,7 @@ yyreduce:
     break;
 
   case 217:
-#line 2662 "Gmsh.y"
+#line 2680 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (8)].c), "MathEval")){
         int t = (int)(yyvsp[(4) - (8)].d);
@@ -8764,7 +8781,7 @@ yyreduce:
     break;
 
   case 218:
-#line 2678 "Gmsh.y"
+#line 2696 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (6)].c), "CutMesh")){
         int t = (int)(yyvsp[(4) - (6)].d);
@@ -8797,25 +8814,21 @@ yyreduce:
     break;
 
   case 219:
-#line 2713 "Gmsh.y"
+#line 2731 "Gmsh.y"
     {
-      // don't use per-dimension vectors here, in order to respect the input
-      // ordering when deleting (important in GEO for dependencies, e.g. cannot
-      // delete boundary before the bounded entity)
-      for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
-        Shape s; List_Read((yyvsp[(3) - (4)].l), i, &s); int dim = s.Type / 100 - 1;
-        if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-          GModel::current()->getOCCInternals()->remove(dim, s.Num);
-        }
-        GModel::current()->getGEOInternals()->remove(dim, s.Num);
-        GModel::current()->remove(dim, s.Num);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(3) - (4)].l), dimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        GModel::current()->getOCCInternals()->remove(dimTags);
       }
+      GModel::current()->getGEOInternals()->remove(dimTags);
+      GModel::current()->remove(dimTags);
       List_Delete((yyvsp[(3) - (4)].l));
     ;}
     break;
 
   case 220:
-#line 2728 "Gmsh.y"
+#line 2742 "Gmsh.y"
     {
 #if defined(HAVE_MESH)
       GModel::current()->getFields()->deleteField((int)(yyvsp[(4) - (6)].d));
@@ -8824,7 +8837,7 @@ yyreduce:
     break;
 
   case 221:
-#line 2734 "Gmsh.y"
+#line 2748 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (6)].c), "View")){
@@ -8842,7 +8855,7 @@ yyreduce:
     break;
 
   case 222:
-#line 2749 "Gmsh.y"
+#line 2763 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (3)].c), "Meshes") || !strcmp((yyvsp[(2) - (3)].c), "All")){
         ClearProject();
@@ -8873,7 +8886,7 @@ yyreduce:
     break;
 
   case 223:
-#line 2777 "Gmsh.y"
+#line 2791 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (4)].c), "Empty") && !strcmp((yyvsp[(3) - (4)].c), "Views")){
@@ -8888,34 +8901,36 @@ yyreduce:
     break;
 
   case 224:
-#line 2794 "Gmsh.y"
+#line 2808 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(4) - (5)].l), tags);
-      setColor(tags, (yyvsp[(2) - (5)].u), false);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (5)].l), dimTags);
+      setColor(dimTags, (yyvsp[(2) - (5)].u), false);
       List_Delete((yyvsp[(4) - (5)].l));
     ;}
     break;
 
   case 225:
-#line 2800 "Gmsh.y"
+#line 2815 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(5) - (6)].l), tags);
-      setColor(tags, (yyvsp[(3) - (6)].u), true);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(5) - (6)].l), dimTags);
+      setColor(dimTags, (yyvsp[(3) - (6)].u), true);
       List_Delete((yyvsp[(5) - (6)].l));
     ;}
     break;
 
   case 226:
-#line 2811 "Gmsh.y"
-    {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(4) - (5)].l), tags);
-      for(int dim = 0; dim < 4; dim++){
-        for(unsigned int i = 0; i < tags[dim].size(); i++){
-          GEntity *ge = GModel::current()->getEntityByTag(dim, tags[dim][i]);
-          if(ge){
-            for(unsigned int j = 0; j < ge->getNumMeshElements(); j++)
-              ge->getMeshElement(j)->setPartition((int)(yyvsp[(2) - (5)].d));
-          }
+#line 2827 "Gmsh.y"
+    {
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (5)].l), dimTags);
+      for(unsigned int i = 0; i < dimTags.size(); i++){
+        GEntity *ge = GModel::current()->getEntityByTag
+          (dimTags[i].first, dimTags[i].second);
+        if(ge){
+          for(unsigned int j = 0; j < ge->getNumMeshElements(); j++)
+            ge->getMeshElement(j)->setPartition((int)(yyvsp[(2) - (5)].d));
         }
       }
       List_Delete((yyvsp[(4) - (5)].l));
@@ -8923,7 +8938,7 @@ yyreduce:
     break;
 
   case 227:
-#line 2830 "Gmsh.y"
+#line 2846 "Gmsh.y"
     {
       std::string what = (yyvsp[(2) - (3)].c);
       setVisibility(-1, 1, false);
@@ -8932,7 +8947,7 @@ yyreduce:
     break;
 
   case 228:
-#line 2836 "Gmsh.y"
+#line 2852 "Gmsh.y"
     {
       std::string what = (yyvsp[(2) - (3)].c);
       setVisibility(-1, 0, false);
@@ -8941,43 +8956,47 @@ yyreduce:
     break;
 
   case 229:
-#line 2842 "Gmsh.y"
+#line 2858 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(3) - (4)].l), tags);
-      setVisibility(tags, 1, false);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(3) - (4)].l), dimTags);
+      setVisibility(dimTags, 1, false);
       List_Delete((yyvsp[(3) - (4)].l));
     ;}
     break;
 
   case 230:
-#line 2848 "Gmsh.y"
+#line 2865 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(4) - (5)].l), tags);
-      setVisibility(tags, 1, true);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (5)].l), dimTags);
+      setVisibility(dimTags, 1, true);
       List_Delete((yyvsp[(4) - (5)].l));
     ;}
     break;
 
   case 231:
-#line 2854 "Gmsh.y"
+#line 2872 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(3) - (4)].l), tags);
-      setVisibility(tags, 0, false);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(3) - (4)].l), dimTags);
+      setVisibility(dimTags, 0, false);
       List_Delete((yyvsp[(3) - (4)].l));
     ;}
     break;
 
   case 232:
-#line 2860 "Gmsh.y"
+#line 2879 "Gmsh.y"
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors((yyvsp[(4) - (5)].l), tags);
-      setVisibility(tags, 0, true);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (5)].l), dimTags);
+      setVisibility(dimTags, 0, true);
       List_Delete((yyvsp[(4) - (5)].l));
     ;}
     break;
 
   case 233:
-#line 2871 "Gmsh.y"
+#line 2891 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (3)].c), "Include")){
         std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(2) - (3)].c));
@@ -9053,7 +9072,7 @@ yyreduce:
     break;
 
   case 234:
-#line 2944 "Gmsh.y"
+#line 2964 "Gmsh.y"
     {
       int n = List_Nbr((yyvsp[(3) - (5)].l));
       if(n == 1){
@@ -9074,7 +9093,7 @@ yyreduce:
     break;
 
   case 235:
-#line 2962 "Gmsh.y"
+#line 2982 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(1) - (7)].c), "Save") && !strcmp((yyvsp[(2) - (7)].c), "View")){
@@ -9094,7 +9113,7 @@ yyreduce:
     break;
 
   case 236:
-#line 2979 "Gmsh.y"
+#line 2999 "Gmsh.y"
     {
 #if defined(HAVE_POST) && defined(HAVE_MESH)
       if(!strcmp((yyvsp[(1) - (7)].c), "Background") && !strcmp((yyvsp[(2) - (7)].c), "Mesh")  && !strcmp((yyvsp[(3) - (7)].c), "View")){
@@ -9112,7 +9131,7 @@ yyreduce:
     break;
 
   case 237:
-#line 2994 "Gmsh.y"
+#line 3014 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (3)].c), "Sleep")){
 	SleepInSeconds((yyvsp[(2) - (3)].d));
@@ -9148,7 +9167,7 @@ yyreduce:
     break;
 
   case 238:
-#line 3027 "Gmsh.y"
+#line 3047 "Gmsh.y"
     {
 #if defined(HAVE_PLUGINS)
        try {
@@ -9163,7 +9182,7 @@ yyreduce:
     break;
 
   case 239:
-#line 3039 "Gmsh.y"
+#line 3059 "Gmsh.y"
     {
 #if defined(HAVE_POST)
       if(!strcmp((yyvsp[(2) - (3)].c), "ElementsFromAllViews"))
@@ -9190,14 +9209,14 @@ yyreduce:
     break;
 
   case 240:
-#line 3063 "Gmsh.y"
+#line 3083 "Gmsh.y"
     {
       Msg::Exit(0);
     ;}
     break;
 
   case 241:
-#line 3067 "Gmsh.y"
+#line 3087 "Gmsh.y"
     {
       gmsh_yyerrorstate = 999; // this will be checked when yyparse returns
       YYABORT;
@@ -9205,7 +9224,7 @@ yyreduce:
     break;
 
   case 242:
-#line 3072 "Gmsh.y"
+#line 3092 "Gmsh.y"
     {
       // force sync
       if(GModel::current()->getOCCInternals())
@@ -9215,7 +9234,7 @@ yyreduce:
     break;
 
   case 243:
-#line 3079 "Gmsh.y"
+#line 3099 "Gmsh.y"
     {
       new GModel();
       GModel::current(GModel::list.size() - 1);
@@ -9223,7 +9242,7 @@ yyreduce:
     break;
 
   case 244:
-#line 3084 "Gmsh.y"
+#line 3104 "Gmsh.y"
     {
       CTX::instance()->forcedBBox = 0;
       if(GModel::current()->getOCCInternals() &&
@@ -9236,7 +9255,7 @@ yyreduce:
     break;
 
   case 245:
-#line 3094 "Gmsh.y"
+#line 3114 "Gmsh.y"
     {
       CTX::instance()->forcedBBox = 1;
       SetBoundingBox((yyvsp[(3) - (15)].d), (yyvsp[(5) - (15)].d), (yyvsp[(7) - (15)].d), (yyvsp[(9) - (15)].d), (yyvsp[(11) - (15)].d), (yyvsp[(13) - (15)].d));
@@ -9244,7 +9263,7 @@ yyreduce:
     break;
 
   case 246:
-#line 3099 "Gmsh.y"
+#line 3119 "Gmsh.y"
     {
 #if defined(HAVE_OPENGL)
       drawContext::global()->draw();
@@ -9253,7 +9272,7 @@ yyreduce:
     break;
 
   case 247:
-#line 3105 "Gmsh.y"
+#line 3125 "Gmsh.y"
     {
 #if defined(HAVE_OPENGL)
      CTX::instance()->mesh.changed = ENT_ALL;
@@ -9264,21 +9283,21 @@ yyreduce:
     break;
 
   case 248:
-#line 3113 "Gmsh.y"
+#line 3133 "Gmsh.y"
     {
       GModel::current()->createTopologyFromMesh();
     ;}
     break;
 
   case 249:
-#line 3117 "Gmsh.y"
+#line 3137 "Gmsh.y"
     {
       GModel::current()->createTopologyFromMesh(1);
     ;}
     break;
 
   case 250:
-#line 3121 "Gmsh.y"
+#line 3141 "Gmsh.y"
     {
       if(GModel::current()->getOCCInternals() &&
          GModel::current()->getOCCInternals()->getChanged())
@@ -9290,7 +9309,7 @@ yyreduce:
     break;
 
   case 251:
-#line 3131 "Gmsh.y"
+#line 3151 "Gmsh.y"
     {
       int lock = CTX::instance()->lock;
       CTX::instance()->lock = 0;
@@ -9351,7 +9370,7 @@ yyreduce:
     break;
 
   case 252:
-#line 3194 "Gmsh.y"
+#line 3214 "Gmsh.y"
     {
 #if defined(HAVE_POPPLER)
        std::vector<int> is;
@@ -9366,7 +9385,7 @@ yyreduce:
     break;
 
   case 253:
-#line 3210 "Gmsh.y"
+#line 3230 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(3) - (6)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(5) - (6)].d);
@@ -9386,7 +9405,7 @@ yyreduce:
     break;
 
   case 254:
-#line 3227 "Gmsh.y"
+#line 3247 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(3) - (8)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(5) - (8)].d);
@@ -9406,7 +9425,7 @@ yyreduce:
     break;
 
   case 255:
-#line 3244 "Gmsh.y"
+#line 3264 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(5) - (8)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(7) - (8)].d);
@@ -9431,7 +9450,7 @@ yyreduce:
     break;
 
   case 256:
-#line 3266 "Gmsh.y"
+#line 3286 "Gmsh.y"
     {
       LoopControlVariablesTab[ImbricatedLoop][0] = (yyvsp[(5) - (10)].d);
       LoopControlVariablesTab[ImbricatedLoop][1] = (yyvsp[(7) - (10)].d);
@@ -9456,7 +9475,7 @@ yyreduce:
     break;
 
   case 257:
-#line 3288 "Gmsh.y"
+#line 3308 "Gmsh.y"
     {
       if(ImbricatedLoop <= 0){
 	yymsg(0, "Invalid For/EndFor loop");
@@ -9494,7 +9513,7 @@ yyreduce:
     break;
 
   case 258:
-#line 3323 "Gmsh.y"
+#line 3343 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->createFunction
          (std::string((yyvsp[(2) - (2)].c)), gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -9505,7 +9524,7 @@ yyreduce:
     break;
 
   case 259:
-#line 3331 "Gmsh.y"
+#line 3351 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->createFunction
          (std::string((yyvsp[(2) - (2)].c)), gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -9516,7 +9535,7 @@ yyreduce:
     break;
 
   case 260:
-#line 3339 "Gmsh.y"
+#line 3359 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->leaveFunction
          (&gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -9525,7 +9544,7 @@ yyreduce:
     break;
 
   case 261:
-#line 3345 "Gmsh.y"
+#line 3365 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->enterFunction
          (std::string((yyvsp[(2) - (3)].c)), &gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -9535,7 +9554,7 @@ yyreduce:
     break;
 
   case 262:
-#line 3352 "Gmsh.y"
+#line 3372 "Gmsh.y"
     {
       if(!FunctionManager::Instance()->enterFunction
          (std::string((yyvsp[(2) - (3)].c)), &gmsh_yyin, gmsh_yyname, gmsh_yylineno))
@@ -9545,7 +9564,7 @@ yyreduce:
     break;
 
   case 263:
-#line 3359 "Gmsh.y"
+#line 3379 "Gmsh.y"
     {
       ImbricatedTest++;
       if(ImbricatedTest > MAX_RECUR_TESTS-1){
@@ -9568,7 +9587,7 @@ yyreduce:
     break;
 
   case 264:
-#line 3379 "Gmsh.y"
+#line 3399 "Gmsh.y"
     {
       if(ImbricatedTest > 0){
         if (statusImbricatedTests[ImbricatedTest]){
@@ -9597,7 +9616,7 @@ yyreduce:
     break;
 
   case 265:
-#line 3405 "Gmsh.y"
+#line 3425 "Gmsh.y"
     {
       if(ImbricatedTest > 0){
         if(statusImbricatedTests[ImbricatedTest]){
@@ -9612,7 +9631,7 @@ yyreduce:
     break;
 
   case 266:
-#line 3417 "Gmsh.y"
+#line 3437 "Gmsh.y"
     {
       ImbricatedTest--;
       if(ImbricatedTest < 0)
@@ -9621,56 +9640,64 @@ yyreduce:
     break;
 
   case 267:
-#line 3429 "Gmsh.y"
+#line 3449 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (5)].l), inDimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors((yyvsp[(4) - (5)].l), in);
-        GModel::current()->getOCCInternals()->extrude(-1, in, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], out);
-        Vectors2ListOfShapes(out, (yyval.l));
+        GModel::current()->getOCCInternals()->extrude
+          (inDimTags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], outDimTags);
       }
       else{
-        // FIXME use GEOInternals + int api -- SAME FOR ALL BELOW!
-        ExtrudeShapes(TRANSLATE, (yyvsp[(4) - (5)].l),
-                      (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], 0., 0., 0., 0., 0., 0., 0.,
-                      NULL, (yyval.l));
+        GModel::current()->getGEOInternals()->extrude
+          (inDimTags, (yyvsp[(2) - (5)].v)[0], (yyvsp[(2) - (5)].v)[1], (yyvsp[(2) - (5)].v)[2], outDimTags);
       }
-      List_Delete((yyvsp[(4) - (5)].l));
+      (yyval.l) = (yyvsp[(4) - (5)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 268:
-#line 3445 "Gmsh.y"
+#line 3465 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(10) - (11)].l), inDimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors((yyvsp[(10) - (11)].l), in);
-        GModel::current()->getOCCInternals()->revolve(-1, in, (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2],
-                                                      (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(7) - (11)].d), out);
-        Vectors2ListOfShapes(out, (yyval.l));
+        GModel::current()->getOCCInternals()->revolve
+          (inDimTags, (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(7) - (11)].d), outDimTags);
       }
       else{
-        ExtrudeShapes(ROTATE, (yyvsp[(10) - (11)].l),
-                      0., 0., 0., (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(7) - (11)].d),
-                      NULL, (yyval.l));
+        GModel::current()->getGEOInternals()->revolve
+          (inDimTags, (yyvsp[(5) - (11)].v)[0], (yyvsp[(5) - (11)].v)[1], (yyvsp[(5) - (11)].v)[2], (yyvsp[(3) - (11)].v)[0], (yyvsp[(3) - (11)].v)[1], (yyvsp[(3) - (11)].v)[2], (yyvsp[(7) - (11)].d), outDimTags);
       }
-      List_Delete((yyvsp[(10) - (11)].l));
+      (yyval.l) = (yyvsp[(10) - (11)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 269:
-#line 3461 "Gmsh.y"
+#line 3481 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(TRANSLATE_ROTATE, (yyvsp[(12) - (13)].l),
-		    (yyvsp[(3) - (13)].v)[0], (yyvsp[(3) - (13)].v)[1], (yyvsp[(3) - (13)].v)[2], (yyvsp[(5) - (13)].v)[0], (yyvsp[(5) - (13)].v)[1], (yyvsp[(5) - (13)].v)[2], (yyvsp[(7) - (13)].v)[0], (yyvsp[(7) - (13)].v)[1], (yyvsp[(7) - (13)].v)[2], (yyvsp[(9) - (13)].d),
-		    NULL, (yyval.l));
-      List_Delete((yyvsp[(12) - (13)].l));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(12) - (13)].l), inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        yymsg(0, "Twisting extrude not available with OpenCASCADE factory");
+      }
+      else{
+        GModel::current()->getGEOInternals()->twist
+          (inDimTags, (yyvsp[(7) - (13)].v)[0], (yyvsp[(7) - (13)].v)[1], (yyvsp[(7) - (13)].v)[2], (yyvsp[(3) - (13)].v)[0], (yyvsp[(3) - (13)].v)[1], (yyvsp[(3) - (13)].v)[2], (yyvsp[(5) - (13)].v)[0], (yyvsp[(5) - (13)].v)[1], (yyvsp[(5) - (13)].v)[2],
+           (yyvsp[(9) - (13)].d),  outDimTags);
+      }
+      (yyval.l) = (yyvsp[(12) - (13)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 270:
-#line 3469 "Gmsh.y"
+#line 3497 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -9679,18 +9706,26 @@ yyreduce:
     break;
 
   case 271:
-#line 3475 "Gmsh.y"
+#line 3503 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(TRANSLATE, (yyvsp[(4) - (7)].l),
-		    (yyvsp[(2) - (7)].v)[0], (yyvsp[(2) - (7)].v)[1], (yyvsp[(2) - (7)].v)[2], 0., 0., 0., 0., 0., 0., 0.,
-		    &extr, (yyval.l));
-      List_Delete((yyvsp[(4) - (7)].l));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(4) - (7)].l), inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        GModel::current()->getOCCInternals()->extrude
+          (inDimTags, (yyvsp[(2) - (7)].v)[0], (yyvsp[(2) - (7)].v)[1], (yyvsp[(2) - (7)].v)[2], outDimTags, &extr);
+      }
+      else{
+        GModel::current()->getGEOInternals()->extrude
+          (inDimTags, (yyvsp[(2) - (7)].v)[0], (yyvsp[(2) - (7)].v)[1], (yyvsp[(2) - (7)].v)[2], outDimTags, &extr);
+      }
+      (yyval.l) = (yyvsp[(4) - (7)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 272:
-#line 3483 "Gmsh.y"
+#line 3519 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -9699,18 +9734,28 @@ yyreduce:
     break;
 
   case 273:
-#line 3489 "Gmsh.y"
+#line 3525 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(ROTATE, (yyvsp[(10) - (13)].l),
-		    0., 0., 0., (yyvsp[(3) - (13)].v)[0], (yyvsp[(3) - (13)].v)[1], (yyvsp[(3) - (13)].v)[2], (yyvsp[(5) - (13)].v)[0], (yyvsp[(5) - (13)].v)[1], (yyvsp[(5) - (13)].v)[2], (yyvsp[(7) - (13)].d),
-		    &extr, (yyval.l));
-      List_Delete((yyvsp[(10) - (13)].l));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(10) - (13)].l), inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        GModel::current()->getOCCInternals()->revolve
+          (inDimTags, (yyvsp[(5) - (13)].v)[0], (yyvsp[(5) - (13)].v)[1], (yyvsp[(5) - (13)].v)[2], (yyvsp[(3) - (13)].v)[0], (yyvsp[(3) - (13)].v)[1], (yyvsp[(3) - (13)].v)[2], (yyvsp[(7) - (13)].d), outDimTags,
+           &extr);
+      }
+      else{
+        GModel::current()->getGEOInternals()->revolve
+          (inDimTags, (yyvsp[(5) - (13)].v)[0], (yyvsp[(5) - (13)].v)[1], (yyvsp[(5) - (13)].v)[2], (yyvsp[(3) - (13)].v)[0], (yyvsp[(3) - (13)].v)[1], (yyvsp[(3) - (13)].v)[2], (yyvsp[(7) - (13)].d), outDimTags,
+           &extr);
+      }
+      (yyval.l) = (yyvsp[(10) - (13)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 274:
-#line 3497 "Gmsh.y"
+#line 3543 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -9719,18 +9764,26 @@ yyreduce:
     break;
 
   case 275:
-#line 3503 "Gmsh.y"
+#line 3549 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(TRANSLATE_ROTATE, (yyvsp[(12) - (15)].l),
-		    (yyvsp[(3) - (15)].v)[0], (yyvsp[(3) - (15)].v)[1], (yyvsp[(3) - (15)].v)[2], (yyvsp[(5) - (15)].v)[0], (yyvsp[(5) - (15)].v)[1], (yyvsp[(5) - (15)].v)[2], (yyvsp[(7) - (15)].v)[0], (yyvsp[(7) - (15)].v)[1], (yyvsp[(7) - (15)].v)[2], (yyvsp[(9) - (15)].d),
-		    &extr, (yyval.l));
-      List_Delete((yyvsp[(12) - (15)].l));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(12) - (15)].l), inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        yymsg(0, "Twisting extrude not available with OpenCASCADE factory");
+      }
+      else{
+        GModel::current()->getGEOInternals()->twist
+          (inDimTags, (yyvsp[(7) - (15)].v)[0], (yyvsp[(7) - (15)].v)[1], (yyvsp[(7) - (15)].v)[2], (yyvsp[(3) - (15)].v)[0], (yyvsp[(3) - (15)].v)[1], (yyvsp[(3) - (15)].v)[2], (yyvsp[(5) - (15)].v)[0], (yyvsp[(5) - (15)].v)[1], (yyvsp[(5) - (15)].v)[2],
+           (yyvsp[(9) - (15)].d),  outDimTags, &extr);
+      }
+      (yyval.l) = (yyvsp[(12) - (15)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 276:
-#line 3511 "Gmsh.y"
+#line 3565 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = extr.mesh.Recombine = false;
       extr.mesh.QuadToTri = NO_QUADTRI;
@@ -9739,40 +9792,50 @@ yyreduce:
     break;
 
   case 277:
-#line 3517 "Gmsh.y"
+#line 3571 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(BOUNDARY_LAYER, (yyvsp[(3) - (6)].l), 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
-		    &extr, (yyval.l));
-      List_Delete((yyvsp[(3) - (6)].l));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(3) - (6)].l), inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        yymsg(0, "Boundary layer extrusion not available with OpenCASCADE factory");
+      }
+      else{
+        GModel::current()->getGEOInternals()->boundaryLayer
+          (inDimTags, outDimTags, &extr);
+      }
+      (yyval.l) = (yyvsp[(3) - (6)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 278:
-#line 3524 "Gmsh.y"
+#line 3586 "Gmsh.y"
     {
-      (yyval.l) = List_Create(2, 1, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs((yyvsp[(3) - (9)].l), inDimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors((yyvsp[(3) - (9)].l), in);
-        GModel::current()->getOCCInternals()->addPipe(-1, in, (int)(yyvsp[(8) - (9)].d), out);
-        Vectors2ListOfShapes(out, (yyval.l));
+        GModel::current()->getOCCInternals()->addPipe(inDimTags, (int)(yyvsp[(8) - (9)].d), outDimTags);
       }
       else{
         yymsg(0, "Pipe only available with OpenCASCADE factory");
       }
-      List_Delete((yyvsp[(3) - (9)].l));
+      (yyval.l) = (yyvsp[(3) - (9)].l);
+      List_Reset((yyval.l));
+      VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
     ;}
     break;
 
   case 279:
-#line 3537 "Gmsh.y"
+#line 3600 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> wires, out[4]; ListOfDouble2Vector((yyvsp[(2) - (2)].l), wires);
-        GModel::current()->getOCCInternals()->addThruSections(-1, wires, out,
-                                                              false, false);
-        Vectors2ListOfShapes(out, (yyval.l));
+        std::vector<int> wires; ListOfDouble2Vector((yyvsp[(2) - (2)].l), wires);
+        std::vector<std::pair<int, int> > outDimTags;
+        GModel::current()->getOCCInternals()->addThruSections
+          (-1, wires, outDimTags, false, false);
+        VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -9782,14 +9845,15 @@ yyreduce:
     break;
 
   case 280:
-#line 3551 "Gmsh.y"
+#line 3615 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> wires, out[4]; ListOfDouble2Vector((yyvsp[(3) - (3)].l), wires);
-        GModel::current()->getOCCInternals()->addThruSections(-1, wires, out,
-                                                              false, true);
-        Vectors2ListOfShapes(out, (yyval.l));
+        std::vector<int> wires; ListOfDouble2Vector((yyvsp[(3) - (3)].l), wires);
+        std::vector<std::pair<int, int> > outDimTags;
+        GModel::current()->getOCCInternals()->addThruSections
+          (-1, wires, outDimTags, false, true);
+        VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -9799,15 +9863,17 @@ yyreduce:
     break;
 
   case 281:
-#line 3565 "Gmsh.y"
+#line 3630 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
         double radius = (yyvsp[(9) - (10)].d);
-        std::vector<int> regions, edges, out[4];
+        std::vector<int> regions, edges;
         ListOfDouble2Vector((yyvsp[(3) - (10)].l), regions); ListOfDouble2Vector((yyvsp[(6) - (10)].l), edges);
-        GModel::current()->getOCCInternals()->fillet(regions, edges, radius, out);
-        Vectors2ListOfShapes(out, (yyval.l));
+        std::vector<std::pair<int, int> > outDimTags;
+        GModel::current()->getOCCInternals()->fillet
+          (regions, edges, radius, outDimTags);
+        VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
       }
       else{
         yymsg(0, "Fillet only available with OpenCASCADE factory");
@@ -9818,19 +9884,19 @@ yyreduce:
     break;
 
   case 282:
-#line 3584 "Gmsh.y"
+#line 3651 "Gmsh.y"
     {
     ;}
     break;
 
   case 283:
-#line 3587 "Gmsh.y"
+#line 3654 "Gmsh.y"
     {
     ;}
     break;
 
   case 284:
-#line 3593 "Gmsh.y"
+#line 3660 "Gmsh.y"
     {
       int n = (int)fabs((yyvsp[(3) - (5)].d));
       if(n){ // we accept n==0 to easily disable layers
@@ -9845,7 +9911,7 @@ yyreduce:
     break;
 
   case 285:
-#line 3605 "Gmsh.y"
+#line 3672 "Gmsh.y"
     {
       extr.mesh.ExtrudeMesh = true;
       extr.mesh.NbLayer = List_Nbr((yyvsp[(3) - (7)].l));
@@ -9868,56 +9934,56 @@ yyreduce:
     break;
 
   case 286:
-#line 3625 "Gmsh.y"
+#line 3692 "Gmsh.y"
     {
       extr.mesh.ScaleLast = true;
     ;}
     break;
 
   case 287:
-#line 3629 "Gmsh.y"
+#line 3696 "Gmsh.y"
     {
       extr.mesh.Recombine = true;
     ;}
     break;
 
   case 288:
-#line 3633 "Gmsh.y"
+#line 3700 "Gmsh.y"
     {
       extr.mesh.Recombine = (yyvsp[(2) - (3)].d) ? true : false;
     ;}
     break;
 
   case 289:
-#line 3637 "Gmsh.y"
+#line 3704 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_ADDVERTS_1;
     ;}
     break;
 
   case 290:
-#line 3641 "Gmsh.y"
+#line 3708 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_ADDVERTS_1_RECOMB;
     ;}
     break;
 
   case 291:
-#line 3645 "Gmsh.y"
+#line 3712 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_NOVERTS_1;
     ;}
     break;
 
   case 292:
-#line 3649 "Gmsh.y"
+#line 3716 "Gmsh.y"
     {
       extr.mesh.QuadToTri = QUADTRI_NOVERTS_1_RECOMB;
     ;}
     break;
 
   case 293:
-#line 3653 "Gmsh.y"
+#line 3720 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(6) - (9)].l), tags);
       int num = (int)(yyvsp[(3) - (9)].d);
@@ -9929,7 +9995,7 @@ yyreduce:
     break;
 
   case 294:
-#line 3662 "Gmsh.y"
+#line 3729 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (6)].c), "Index"))
         extr.mesh.BoundaryLayerIndex = (yyvsp[(4) - (6)].d);
@@ -9940,56 +10006,56 @@ yyreduce:
     break;
 
   case 295:
-#line 3674 "Gmsh.y"
+#line 3741 "Gmsh.y"
     { (yyval.i) = OCC_Internals::Union; ;}
     break;
 
   case 296:
-#line 3675 "Gmsh.y"
+#line 3742 "Gmsh.y"
     { (yyval.i) = OCC_Internals::Intersection; ;}
     break;
 
   case 297:
-#line 3676 "Gmsh.y"
+#line 3743 "Gmsh.y"
     { (yyval.i) = OCC_Internals::Difference; ;}
     break;
 
   case 298:
-#line 3677 "Gmsh.y"
+#line 3744 "Gmsh.y"
     { (yyval.i) = OCC_Internals::Section; ;}
     break;
 
   case 299:
-#line 3678 "Gmsh.y"
+#line 3745 "Gmsh.y"
     { (yyval.i) = OCC_Internals::Fragments; ;}
     break;
 
   case 300:
-#line 3682 "Gmsh.y"
+#line 3749 "Gmsh.y"
     { (yyval.i) = 0; ;}
     break;
 
   case 301:
-#line 3683 "Gmsh.y"
+#line 3750 "Gmsh.y"
     { (yyval.i) = 1; ;}
     break;
 
   case 302:
-#line 3684 "Gmsh.y"
+#line 3751 "Gmsh.y"
     { (yyval.i) = (yyvsp[(2) - (3)].d); ;}
     break;
 
   case 303:
-#line 3689 "Gmsh.y"
+#line 3756 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> shape[4], tool[4], out[4];
-        ListOfShapes2Vectors((yyvsp[(3) - (9)].l), shape);
-        ListOfShapes2Vectors((yyvsp[(7) - (9)].l), tool);
+        std::vector<std::pair<int, int > > object, tool, out;
+        ListOfShapes2VectorOfPairs((yyvsp[(3) - (9)].l), object);
+        ListOfShapes2VectorOfPairs((yyvsp[(7) - (9)].l), tool);
         GModel::current()->getOCCInternals()->applyBooleanOperator
-          (-1, (OCC_Internals::BooleanOperator)(yyvsp[(1) - (9)].i), shape, tool, out, (yyvsp[(4) - (9)].i), (yyvsp[(8) - (9)].i));
-        Vectors2ListOfShapes(out, (yyval.l));
+          (-1, (OCC_Internals::BooleanOperator)(yyvsp[(1) - (9)].i), object, tool, out, (yyvsp[(4) - (9)].i), (yyvsp[(8) - (9)].i));
+        VectorOfPairs2ListOfShapes(out, (yyval.l));
       }
       else{
         yymsg(0, "Boolean operators only available with OpenCASCADE factory");
@@ -10000,14 +10066,14 @@ yyreduce:
     break;
 
   case 304:
-#line 3706 "Gmsh.y"
+#line 3773 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> out[4];
+        std::vector<std::pair<int, int> > out;
         std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(3) - (4)].c));
         GModel::current()->getOCCInternals()->importShapes(tmp, true, out);
-        Vectors2ListOfShapes(out, (yyval.l));
+        VectorOfPairs2ListOfShapes(out, (yyval.l));
       }
       else{
         yymsg(0, "ShapeFromFile only available with OpenCASCADE factory");
@@ -10017,14 +10083,14 @@ yyreduce:
     break;
 
   case 305:
-#line 3724 "Gmsh.y"
+#line 3791 "Gmsh.y"
     {
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> shape[4], tool[4], out[4];
-        ListOfShapes2Vectors((yyvsp[(7) - (14)].l), shape);
-        ListOfShapes2Vectors((yyvsp[(11) - (14)].l), tool);
+        std::vector<std::pair<int, int> > object, tool, out;
+        ListOfShapes2VectorOfPairs((yyvsp[(7) - (14)].l), object);
+        ListOfShapes2VectorOfPairs((yyvsp[(11) - (14)].l), tool);
         GModel::current()->getOCCInternals()->applyBooleanOperator
-          ((int)(yyvsp[(3) - (14)].d), (OCC_Internals::BooleanOperator)(yyvsp[(1) - (14)].i), shape, tool, out, (yyvsp[(8) - (14)].i), (yyvsp[(12) - (14)].i));
+          ((int)(yyvsp[(3) - (14)].d), (OCC_Internals::BooleanOperator)(yyvsp[(1) - (14)].i), object, tool, out, (yyvsp[(8) - (14)].i), (yyvsp[(12) - (14)].i));
       }
       List_Delete((yyvsp[(7) - (14)].l));
       List_Delete((yyvsp[(11) - (14)].l));
@@ -10032,14 +10098,14 @@ yyreduce:
     break;
 
   case 306:
-#line 3739 "Gmsh.y"
+#line 3806 "Gmsh.y"
     {
       (yyval.v)[0] = (yyval.v)[1] = 1.;
     ;}
     break;
 
   case 307:
-#line 3743 "Gmsh.y"
+#line 3810 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (3)].c), "Progression") || !strcmp((yyvsp[(2) - (3)].c), "Power"))
         (yyval.v)[0] = 1.;
@@ -10055,14 +10121,14 @@ yyreduce:
     break;
 
   case 308:
-#line 3758 "Gmsh.y"
+#line 3825 "Gmsh.y"
     {
       (yyval.i) = -1; // left
     ;}
     break;
 
   case 309:
-#line 3762 "Gmsh.y"
+#line 3829 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (1)].c), "Right"))
         (yyval.i) = 1;
@@ -10079,49 +10145,49 @@ yyreduce:
     break;
 
   case 310:
-#line 3778 "Gmsh.y"
+#line 3845 "Gmsh.y"
     {
      (yyval.l) = List_Create(1, 1, sizeof(double));
    ;}
     break;
 
   case 311:
-#line 3782 "Gmsh.y"
+#line 3849 "Gmsh.y"
     {
      (yyval.l) = (yyvsp[(2) - (2)].l);
    ;}
     break;
 
   case 312:
-#line 3787 "Gmsh.y"
+#line 3854 "Gmsh.y"
     {
       (yyval.i) = 45;
     ;}
     break;
 
   case 313:
-#line 3791 "Gmsh.y"
+#line 3858 "Gmsh.y"
     {
       (yyval.i) = (int)(yyvsp[(2) - (2)].d);
     ;}
     break;
 
   case 314:
-#line 3797 "Gmsh.y"
+#line 3864 "Gmsh.y"
     {
       (yyval.l) = List_Create(1, 1, sizeof(double));
     ;}
     break;
 
   case 315:
-#line 3801 "Gmsh.y"
+#line 3868 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (2)].l);
     ;}
     break;
 
   case 316:
-#line 3808 "Gmsh.y"
+#line 3875 "Gmsh.y"
     {
       // mesh sizes at vertices are stored in internal CAD data, as they can be
       // specified during vertex creation and copied around during CAD
@@ -10141,7 +10207,7 @@ yyreduce:
     break;
 
   case 317:
-#line 3825 "Gmsh.y"
+#line 3892 "Gmsh.y"
     {
       // transfinite constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10185,7 +10251,7 @@ yyreduce:
     break;
 
   case 318:
-#line 3866 "Gmsh.y"
+#line 3933 "Gmsh.y"
     {
       // transfinite constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10232,7 +10298,7 @@ yyreduce:
     break;
 
   case 319:
-#line 3910 "Gmsh.y"
+#line 3977 "Gmsh.y"
     {
       // transfinite constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10274,7 +10340,7 @@ yyreduce:
     break;
 
   case 320:
-#line 3949 "Gmsh.y"
+#line 4016 "Gmsh.y"
     {
       // transfinite constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10302,7 +10368,7 @@ yyreduce:
     break;
 
   case 321:
-#line 3974 "Gmsh.y"
+#line 4041 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(4) - (8)].l)); i++){
 	double d;
@@ -10314,7 +10380,7 @@ yyreduce:
     break;
 
   case 322:
-#line 3983 "Gmsh.y"
+#line 4050 "Gmsh.y"
     {
       // recombine constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10347,7 +10413,7 @@ yyreduce:
     break;
 
   case 323:
-#line 4013 "Gmsh.y"
+#line 4080 "Gmsh.y"
     {
       // recombine constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10376,7 +10442,7 @@ yyreduce:
     break;
 
   case 324:
-#line 4039 "Gmsh.y"
+#line 4106 "Gmsh.y"
     {
       // smoothing constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10405,7 +10471,7 @@ yyreduce:
     break;
 
   case 325:
-#line 4066 "Gmsh.y"
+#line 4133 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(4) - (11)].l)) != List_Nbr((yyvsp[(8) - (11)].l))){
         yymsg(0, "Number of master lines (%d) different from number of "
@@ -10439,7 +10505,7 @@ yyreduce:
     break;
 
   case 326:
-#line 4098 "Gmsh.y"
+#line 4165 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(4) - (11)].l)) != List_Nbr((yyvsp[(8) - (11)].l))){
         yymsg(0, "Number of master faces (%d) different from number of "
@@ -10468,7 +10534,7 @@ yyreduce:
     break;
 
   case 327:
-#line 4125 "Gmsh.y"
+#line 4192 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(4) - (18)].l)) != List_Nbr((yyvsp[(8) - (18)].l))){
         yymsg(0, "Number of master edges (%d) different from number of "
@@ -10496,7 +10562,7 @@ yyreduce:
     break;
 
   case 328:
-#line 4151 "Gmsh.y"
+#line 4218 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(4) - (18)].l)) != List_Nbr((yyvsp[(8) - (18)].l))){
         yymsg(0, "Number of master faces (%d) different from number of "
@@ -10524,7 +10590,7 @@ yyreduce:
     break;
 
   case 329:
-#line 4177 "Gmsh.y"
+#line 4244 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(4) - (12)].l)) != List_Nbr((yyvsp[(8) - (12)].l))){
         yymsg(0, "Number of master edges (%d) different from number of "
@@ -10552,7 +10618,7 @@ yyreduce:
     break;
 
   case 330:
-#line 4203 "Gmsh.y"
+#line 4270 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(4) - (12)].l)) != List_Nbr((yyvsp[(8) - (12)].l))){
         yymsg(0, "Number of master faces (%d) different from number of "
@@ -10580,7 +10646,7 @@ yyreduce:
     break;
 
   case 331:
-#line 4229 "Gmsh.y"
+#line 4296 "Gmsh.y"
     {
       if (List_Nbr((yyvsp[(5) - (12)].l)) != List_Nbr((yyvsp[(10) - (12)].l))){
         yymsg(0, "Number of master surface edges (%d) different from number of "
@@ -10604,7 +10670,7 @@ yyreduce:
     break;
 
   case 332:
-#line 4250 "Gmsh.y"
+#line 4317 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (10)].l), tags);
       addEmbedded(0, tags, 2, (int)(yyvsp[(8) - (10)].d));
@@ -10613,7 +10679,7 @@ yyreduce:
     break;
 
   case 333:
-#line 4256 "Gmsh.y"
+#line 4323 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (10)].l), tags);
       addEmbedded(1, tags, 2, (int)(yyvsp[(8) - (10)].d));
@@ -10622,7 +10688,7 @@ yyreduce:
     break;
 
   case 334:
-#line 4262 "Gmsh.y"
+#line 4329 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (10)].l), tags);
       addEmbedded(0, tags, 3, (int)(yyvsp[(8) - (10)].d));
@@ -10631,7 +10697,7 @@ yyreduce:
     break;
 
   case 335:
-#line 4268 "Gmsh.y"
+#line 4335 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (10)].l), tags);
       addEmbedded(1, tags, 3, (int)(yyvsp[(8) - (10)].d));
@@ -10640,7 +10706,7 @@ yyreduce:
     break;
 
   case 336:
-#line 4274 "Gmsh.y"
+#line 4341 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (10)].l), tags);
       addEmbedded(2, tags, 3, (int)(yyvsp[(8) - (10)].d));
@@ -10649,7 +10715,7 @@ yyreduce:
     break;
 
   case 337:
-#line 4280 "Gmsh.y"
+#line 4347 "Gmsh.y"
     {
       // reverse mesh constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10678,7 +10744,7 @@ yyreduce:
     break;
 
   case 338:
-#line 4306 "Gmsh.y"
+#line 4373 "Gmsh.y"
     {
       // reverse mesh constraints are stored in GEO internals in addition to
       // GModel, as they can be copied around during GEO operations
@@ -10707,7 +10773,7 @@ yyreduce:
     break;
 
   case 339:
-#line 4332 "Gmsh.y"
+#line 4399 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
         for(GModel::viter it = GModel::current()->firstVertex();
@@ -10727,7 +10793,7 @@ yyreduce:
     break;
 
   case 340:
-#line 4349 "Gmsh.y"
+#line 4416 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
         for(GModel::eiter it = GModel::current()->firstEdge();
@@ -10747,7 +10813,7 @@ yyreduce:
     break;
 
   case 341:
-#line 4366 "Gmsh.y"
+#line 4433 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (4)].l)){
         for(GModel::fiter it = GModel::current()->firstFace();
@@ -10767,7 +10833,7 @@ yyreduce:
     break;
 
   case 342:
-#line 4383 "Gmsh.y"
+#line 4450 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
 	double dnum;
@@ -10782,7 +10848,7 @@ yyreduce:
     break;
 
   case 343:
-#line 4395 "Gmsh.y"
+#line 4462 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (4)].l), tags);
       GModel::current()->getGEOInternals()->setCompoundMesh(1, tags);
@@ -10791,7 +10857,7 @@ yyreduce:
     break;
 
   case 344:
-#line 4401 "Gmsh.y"
+#line 4468 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (4)].l), tags);
       GModel::current()->getGEOInternals()->setCompoundMesh(2, tags);
@@ -10800,7 +10866,7 @@ yyreduce:
     break;
 
   case 345:
-#line 4407 "Gmsh.y"
+#line 4474 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(3) - (4)].l), tags);
       GModel::current()->getGEOInternals()->setCompoundMesh(3, tags);
@@ -10809,14 +10875,14 @@ yyreduce:
     break;
 
   case 346:
-#line 4419 "Gmsh.y"
+#line 4486 "Gmsh.y"
     {
       GModel::current()->getGEOInternals()->removeAllDuplicates();
     ;}
     break;
 
   case 347:
-#line 4423 "Gmsh.y"
+#line 4490 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(2) - (3)].c), "Geometry"))
         GModel::current()->getGEOInternals()->removeAllDuplicates();
@@ -10829,7 +10895,7 @@ yyreduce:
     break;
 
   case 348:
-#line 4433 "Gmsh.y"
+#line 4500 "Gmsh.y"
     {
       std::vector<int> tags; ListOfDouble2Vector((yyvsp[(4) - (6)].l), tags);
       GModel::current()->getGEOInternals()->mergeVertices(tags);
@@ -10838,22 +10904,22 @@ yyreduce:
     break;
 
   case 349:
-#line 4443 "Gmsh.y"
+#line 4510 "Gmsh.y"
     { (yyval.c) = (char*)"Homology"; ;}
     break;
 
   case 350:
-#line 4444 "Gmsh.y"
+#line 4511 "Gmsh.y"
     { (yyval.c) = (char*)"Cohomology"; ;}
     break;
 
   case 351:
-#line 4445 "Gmsh.y"
+#line 4512 "Gmsh.y"
     { (yyval.c) = (char*)"Betti"; ;}
     break;
 
   case 352:
-#line 4450 "Gmsh.y"
+#line 4517 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < 4; i++) dim.push_back(i);
@@ -10862,7 +10928,7 @@ yyreduce:
     break;
 
   case 353:
-#line 4456 "Gmsh.y"
+#line 4523 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (5)].l)); i++){
@@ -10877,7 +10943,7 @@ yyreduce:
     break;
 
   case 354:
-#line 4468 "Gmsh.y"
+#line 4535 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (7)].l)); i++){
@@ -10898,7 +10964,7 @@ yyreduce:
     break;
 
   case 355:
-#line 4486 "Gmsh.y"
+#line 4553 "Gmsh.y"
     {
       std::vector<int> domain, subdomain, dim;
       for(int i = 0; i < List_Nbr((yyvsp[(6) - (10)].l)); i++){
@@ -10924,47 +10990,47 @@ yyreduce:
     break;
 
   case 356:
-#line 4513 "Gmsh.y"
+#line 4580 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (1)].d);           ;}
     break;
 
   case 357:
-#line 4514 "Gmsh.y"
+#line 4581 "Gmsh.y"
     { (yyval.d) = (yyvsp[(2) - (3)].d);           ;}
     break;
 
   case 358:
-#line 4515 "Gmsh.y"
+#line 4582 "Gmsh.y"
     { (yyval.d) = -(yyvsp[(2) - (2)].d);          ;}
     break;
 
   case 359:
-#line 4516 "Gmsh.y"
+#line 4583 "Gmsh.y"
     { (yyval.d) = (yyvsp[(2) - (2)].d);           ;}
     break;
 
   case 360:
-#line 4517 "Gmsh.y"
+#line 4584 "Gmsh.y"
     { (yyval.d) = !(yyvsp[(2) - (2)].d);          ;}
     break;
 
   case 361:
-#line 4518 "Gmsh.y"
+#line 4585 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) - (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 362:
-#line 4519 "Gmsh.y"
+#line 4586 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) + (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 363:
-#line 4520 "Gmsh.y"
+#line 4587 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) * (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 364:
-#line 4522 "Gmsh.y"
+#line 4589 "Gmsh.y"
     {
       if(!(yyvsp[(3) - (3)].d))
 	yymsg(0, "Division by zero in '%g / %g'", (yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].d));
@@ -10974,237 +11040,237 @@ yyreduce:
     break;
 
   case 365:
-#line 4528 "Gmsh.y"
+#line 4595 "Gmsh.y"
     { (yyval.d) = (int)(yyvsp[(1) - (3)].d) % (int)(yyvsp[(3) - (3)].d);  ;}
     break;
 
   case 366:
-#line 4529 "Gmsh.y"
+#line 4596 "Gmsh.y"
     { (yyval.d) = pow((yyvsp[(1) - (3)].d), (yyvsp[(3) - (3)].d));  ;}
     break;
 
   case 367:
-#line 4530 "Gmsh.y"
+#line 4597 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 368:
-#line 4531 "Gmsh.y"
+#line 4598 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) > (yyvsp[(3) - (3)].d);      ;}
     break;
 
   case 369:
-#line 4532 "Gmsh.y"
+#line 4599 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) <= (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 370:
-#line 4533 "Gmsh.y"
+#line 4600 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) >= (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 371:
-#line 4534 "Gmsh.y"
+#line 4601 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) == (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 372:
-#line 4535 "Gmsh.y"
+#line 4602 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) != (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 373:
-#line 4536 "Gmsh.y"
+#line 4603 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) && (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 374:
-#line 4537 "Gmsh.y"
+#line 4604 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (3)].d) || (yyvsp[(3) - (3)].d);     ;}
     break;
 
   case 375:
-#line 4538 "Gmsh.y"
+#line 4605 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (5)].d) ? (yyvsp[(3) - (5)].d) : (yyvsp[(5) - (5)].d); ;}
     break;
 
   case 376:
-#line 4539 "Gmsh.y"
+#line 4606 "Gmsh.y"
     { (yyval.d) = exp((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 377:
-#line 4540 "Gmsh.y"
+#line 4607 "Gmsh.y"
     { (yyval.d) = log((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 378:
-#line 4541 "Gmsh.y"
+#line 4608 "Gmsh.y"
     { (yyval.d) = log10((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 379:
-#line 4542 "Gmsh.y"
+#line 4609 "Gmsh.y"
     { (yyval.d) = sqrt((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 380:
-#line 4543 "Gmsh.y"
+#line 4610 "Gmsh.y"
     { (yyval.d) = sin((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 381:
-#line 4544 "Gmsh.y"
+#line 4611 "Gmsh.y"
     { (yyval.d) = asin((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 382:
-#line 4545 "Gmsh.y"
+#line 4612 "Gmsh.y"
     { (yyval.d) = cos((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 383:
-#line 4546 "Gmsh.y"
+#line 4613 "Gmsh.y"
     { (yyval.d) = acos((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 384:
-#line 4547 "Gmsh.y"
+#line 4614 "Gmsh.y"
     { (yyval.d) = tan((yyvsp[(3) - (4)].d));      ;}
     break;
 
   case 385:
-#line 4548 "Gmsh.y"
+#line 4615 "Gmsh.y"
     { (yyval.d) = atan((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 386:
-#line 4549 "Gmsh.y"
+#line 4616 "Gmsh.y"
     { (yyval.d) = atan2((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d));;}
     break;
 
   case 387:
-#line 4550 "Gmsh.y"
+#line 4617 "Gmsh.y"
     { (yyval.d) = sinh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 388:
-#line 4551 "Gmsh.y"
+#line 4618 "Gmsh.y"
     { (yyval.d) = cosh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 389:
-#line 4552 "Gmsh.y"
+#line 4619 "Gmsh.y"
     { (yyval.d) = tanh((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 390:
-#line 4553 "Gmsh.y"
+#line 4620 "Gmsh.y"
     { (yyval.d) = fabs((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 391:
-#line 4554 "Gmsh.y"
+#line 4621 "Gmsh.y"
     { (yyval.d) = std::abs((yyvsp[(3) - (4)].d)); ;}
     break;
 
   case 392:
-#line 4555 "Gmsh.y"
+#line 4622 "Gmsh.y"
     { (yyval.d) = floor((yyvsp[(3) - (4)].d));    ;}
     break;
 
   case 393:
-#line 4556 "Gmsh.y"
+#line 4623 "Gmsh.y"
     { (yyval.d) = ceil((yyvsp[(3) - (4)].d));     ;}
     break;
 
   case 394:
-#line 4557 "Gmsh.y"
+#line 4624 "Gmsh.y"
     { (yyval.d) = floor((yyvsp[(3) - (4)].d) + 0.5); ;}
     break;
 
   case 395:
-#line 4558 "Gmsh.y"
+#line 4625 "Gmsh.y"
     { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 396:
-#line 4559 "Gmsh.y"
+#line 4626 "Gmsh.y"
     { (yyval.d) = fmod((yyvsp[(3) - (6)].d), (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 397:
-#line 4560 "Gmsh.y"
+#line 4627 "Gmsh.y"
     { (yyval.d) = sqrt((yyvsp[(3) - (6)].d) * (yyvsp[(3) - (6)].d) + (yyvsp[(5) - (6)].d) * (yyvsp[(5) - (6)].d)); ;}
     break;
 
   case 398:
-#line 4561 "Gmsh.y"
+#line 4628 "Gmsh.y"
     { (yyval.d) = (yyvsp[(3) - (4)].d) * (double)rand() / (double)RAND_MAX; ;}
     break;
 
   case 399:
-#line 4570 "Gmsh.y"
+#line 4637 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (1)].d); ;}
     break;
 
   case 400:
-#line 4571 "Gmsh.y"
+#line 4638 "Gmsh.y"
     { (yyval.d) = 3.141592653589793; ;}
     break;
 
   case 401:
-#line 4572 "Gmsh.y"
+#line 4639 "Gmsh.y"
     { (yyval.d) = (double)ImbricatedTest; ;}
     break;
 
   case 402:
-#line 4573 "Gmsh.y"
+#line 4640 "Gmsh.y"
     { (yyval.d) = Msg::GetCommRank(); ;}
     break;
 
   case 403:
-#line 4574 "Gmsh.y"
+#line 4641 "Gmsh.y"
     { (yyval.d) = Msg::GetCommSize(); ;}
     break;
 
   case 404:
-#line 4575 "Gmsh.y"
+#line 4642 "Gmsh.y"
     { (yyval.d) = GetGmshMajorVersion(); ;}
     break;
 
   case 405:
-#line 4576 "Gmsh.y"
+#line 4643 "Gmsh.y"
     { (yyval.d) = GetGmshMinorVersion(); ;}
     break;
 
   case 406:
-#line 4577 "Gmsh.y"
+#line 4644 "Gmsh.y"
     { (yyval.d) = GetGmshPatchVersion(); ;}
     break;
 
   case 407:
-#line 4578 "Gmsh.y"
+#line 4645 "Gmsh.y"
     { (yyval.d) = Cpu(); ;}
     break;
 
   case 408:
-#line 4579 "Gmsh.y"
+#line 4646 "Gmsh.y"
     { (yyval.d) = GetMemoryUsage()/1024./1024.; ;}
     break;
 
   case 409:
-#line 4580 "Gmsh.y"
+#line 4647 "Gmsh.y"
     { (yyval.d) = TotalRam(); ;}
     break;
 
   case 410:
-#line 4585 "Gmsh.y"
+#line 4652 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
   case 411:
-#line 4587 "Gmsh.y"
+#line 4654 "Gmsh.y"
     {
       std::vector<double> val(1, (yyvsp[(3) - (6)].d));
       Msg::ExchangeOnelabParameter("", val, floatOptions, charOptions);
@@ -11213,12 +11279,12 @@ yyreduce:
     break;
 
   case 412:
-#line 4593 "Gmsh.y"
+#line 4660 "Gmsh.y"
     { (yyval.d) = (yyvsp[(1) - (1)].d); ;}
     break;
 
   case 413:
-#line 4595 "Gmsh.y"
+#line 4662 "Gmsh.y"
     {
       (yyval.d) = Msg::GetOnelabNumber((yyvsp[(3) - (4)].c));
       Free((yyvsp[(3) - (4)].c));
@@ -11226,7 +11292,7 @@ yyreduce:
     break;
 
   case 414:
-#line 4600 "Gmsh.y"
+#line 4667 "Gmsh.y"
     {
       (yyval.d) = Msg::GetOnelabNumber((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].d));
       Free((yyvsp[(3) - (6)].c));
@@ -11234,7 +11300,7 @@ yyreduce:
     break;
 
   case 415:
-#line 4606 "Gmsh.y"
+#line 4673 "Gmsh.y"
     {
       if(gmsh_yysymbols.count((yyvsp[(1) - (1)].c2).char2)){
         gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(1) - (1)].c2).char2]);
@@ -11261,7 +11327,7 @@ yyreduce:
     break;
 
   case 416:
-#line 4630 "Gmsh.y"
+#line 4697 "Gmsh.y"
     {
       int index = (int)(yyvsp[(3) - (4)].d);
       if(!gmsh_yysymbols.count((yyvsp[(1) - (4)].c))){
@@ -11282,7 +11348,7 @@ yyreduce:
     break;
 
   case 417:
-#line 4648 "Gmsh.y"
+#line 4715 "Gmsh.y"
     {
       int index = (int)(yyvsp[(3) - (4)].d);
       if(!gmsh_yysymbols.count((yyvsp[(1) - (4)].c))){
@@ -11303,7 +11369,7 @@ yyreduce:
     break;
 
   case 418:
-#line 4666 "Gmsh.y"
+#line 4733 "Gmsh.y"
     {
       (yyval.d) = gmsh_yysymbols.count((yyvsp[(3) - (4)].c));
       Free((yyvsp[(3) - (4)].c));
@@ -11311,7 +11377,7 @@ yyreduce:
     break;
 
   case 419:
-#line 4671 "Gmsh.y"
+#line 4738 "Gmsh.y"
     {
       std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(3) - (4)].c));
       (yyval.d) = !StatFile(tmp);
@@ -11320,7 +11386,7 @@ yyreduce:
     break;
 
   case 420:
-#line 4677 "Gmsh.y"
+#line 4744 "Gmsh.y"
     {
       if(gmsh_yysymbols.count((yyvsp[(2) - (4)].c))){
         gmsh_yysymbol &s(gmsh_yysymbols[(yyvsp[(2) - (4)].c)]);
@@ -11338,7 +11404,7 @@ yyreduce:
     break;
 
   case 421:
-#line 4693 "Gmsh.y"
+#line 4760 "Gmsh.y"
     {
       std::string struct_namespace((yyvsp[(2) - (3)].c));
       (yyval.d) = (double)nameSpaces[struct_namespace].size();
@@ -11347,7 +11413,7 @@ yyreduce:
     break;
 
   case 422:
-#line 4699 "Gmsh.y"
+#line 4766 "Gmsh.y"
     {
       std::string struct_namespace(std::string(""));
       (yyval.d) = (double)nameSpaces[struct_namespace].size();
@@ -11355,7 +11421,7 @@ yyreduce:
     break;
 
   case 423:
-#line 4705 "Gmsh.y"
+#line 4772 "Gmsh.y"
     {
       if(!gmsh_yysymbols.count((yyvsp[(1) - (2)].c))){
 	yymsg(0, "Unknown variable '%s'", (yyvsp[(1) - (2)].c));
@@ -11377,7 +11443,7 @@ yyreduce:
     break;
 
   case 424:
-#line 4724 "Gmsh.y"
+#line 4791 "Gmsh.y"
     {
       int index = (int)(yyvsp[(3) - (5)].d);
       if(!gmsh_yysymbols.count((yyvsp[(1) - (5)].c))){
@@ -11400,7 +11466,7 @@ yyreduce:
     break;
 
   case 425:
-#line 4745 "Gmsh.y"
+#line 4812 "Gmsh.y"
     {
       int index = (int)(yyvsp[(3) - (5)].d);
       if(!gmsh_yysymbols.count((yyvsp[(1) - (5)].c))){
@@ -11423,7 +11489,7 @@ yyreduce:
     break;
 
   case 426:
-#line 4778 "Gmsh.y"
+#line 4845 "Gmsh.y"
     {
       (yyval.d) = treat_Struct_FullName_dot_tSTRING_Float(NULL, (yyvsp[(1) - (3)].c), (yyvsp[(3) - (3)].c));
       /*
@@ -11450,12 +11516,12 @@ yyreduce:
     break;
 
   case 427:
-#line 4802 "Gmsh.y"
+#line 4869 "Gmsh.y"
     { (yyval.d) = treat_Struct_FullName_dot_tSTRING_Float((yyvsp[(1) - (5)].c), (yyvsp[(3) - (5)].c), (yyvsp[(5) - (5)].c)); ;}
     break;
 
   case 428:
-#line 4805 "Gmsh.y"
+#line 4872 "Gmsh.y"
     {
       NumberOption(GMSH_GET, (yyvsp[(1) - (6)].c), (int)(yyvsp[(3) - (6)].d), (yyvsp[(6) - (6)].c), (yyval.d));
       Free((yyvsp[(1) - (6)].c)); Free((yyvsp[(6) - (6)].c));
@@ -11463,7 +11529,7 @@ yyreduce:
     break;
 
   case 429:
-#line 4811 "Gmsh.y"
+#line 4878 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (4)].c), 0, (yyvsp[(3) - (4)].c), d)){
@@ -11476,7 +11542,7 @@ yyreduce:
     break;
 
   case 430:
-#line 4822 "Gmsh.y"
+#line 4889 "Gmsh.y"
     {
       double d = 0.;
       if(NumberOption(GMSH_GET, (yyvsp[(1) - (7)].c), (int)(yyvsp[(3) - (7)].d), (yyvsp[(6) - (7)].c), d)){
@@ -11489,7 +11555,7 @@ yyreduce:
     break;
 
   case 431:
-#line 4832 "Gmsh.y"
+#line 4899 "Gmsh.y"
     {
       (yyval.d) = Msg::GetValue((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].d));
       Free((yyvsp[(3) - (6)].c));
@@ -11497,7 +11563,7 @@ yyreduce:
     break;
 
   case 432:
-#line 4837 "Gmsh.y"
+#line 4904 "Gmsh.y"
     {
       int matches = 0;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (6)].l)); i++){
@@ -11511,7 +11577,7 @@ yyreduce:
     break;
 
   case 433:
-#line 4848 "Gmsh.y"
+#line 4915 "Gmsh.y"
     {
       std::string s((yyvsp[(3) - (6)].c)), substr((yyvsp[(5) - (6)].c));
       if(s.find(substr) != std::string::npos)
@@ -11523,7 +11589,7 @@ yyreduce:
     break;
 
   case 434:
-#line 4857 "Gmsh.y"
+#line 4924 "Gmsh.y"
     {
       (yyval.d) = strlen((yyvsp[(3) - (4)].c));
       Free((yyvsp[(3) - (4)].c));
@@ -11531,7 +11597,7 @@ yyreduce:
     break;
 
   case 435:
-#line 4862 "Gmsh.y"
+#line 4929 "Gmsh.y"
     {
       (yyval.d) = strcmp((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].c));
       Free((yyvsp[(3) - (6)].c)); Free((yyvsp[(5) - (6)].c));
@@ -11539,7 +11605,7 @@ yyreduce:
     break;
 
   case 436:
-#line 4867 "Gmsh.y"
+#line 4934 "Gmsh.y"
     {
       int align = 0, font = 0, fontsize = CTX::instance()->glFontSize;
       if(List_Nbr((yyvsp[(3) - (4)].l)) % 2){
@@ -11566,12 +11632,12 @@ yyreduce:
     break;
 
   case 437:
-#line 4895 "Gmsh.y"
+#line 4962 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
   case 438:
-#line 4897 "Gmsh.y"
+#line 4964 "Gmsh.y"
     {
       std::string struct_namespace((yyvsp[(2) - (8)].c2).char1? (yyvsp[(2) - (8)].c2).char1 : std::string("")),
         struct_name((yyvsp[(2) - (8)].c2).char2);
@@ -11599,105 +11665,105 @@ yyreduce:
     break;
 
   case 439:
-#line 4925 "Gmsh.y"
+#line 4992 "Gmsh.y"
     { (yyval.c2).char1 = NULL; (yyval.c2).char2 = (yyvsp[(1) - (1)].c); ;}
     break;
 
   case 440:
-#line 4927 "Gmsh.y"
+#line 4994 "Gmsh.y"
     { (yyval.c2).char1 = (yyvsp[(1) - (3)].c); (yyval.c2).char2 = (yyvsp[(3) - (3)].c); ;}
     break;
 
   case 441:
-#line 4932 "Gmsh.y"
+#line 4999 "Gmsh.y"
     { (yyval.c) = (yyvsp[(1) - (1)].c); flag_tSTRING_alloc = 1; ;}
     break;
 
   case 442:
-#line 4941 "Gmsh.y"
+#line 5008 "Gmsh.y"
     { (yyval.i) = 99; ;}
     break;
 
   case 443:
-#line 4943 "Gmsh.y"
+#line 5010 "Gmsh.y"
     { (yyval.i) = (int)(yyvsp[(2) - (2)].d); ;}
     break;
 
   case 444:
-#line 4948 "Gmsh.y"
+#line 5015 "Gmsh.y"
     { (yyval.i) = 0; ;}
     break;
 
   case 445:
-#line 4950 "Gmsh.y"
+#line 5017 "Gmsh.y"
     { (yyval.i) = (yyvsp[(2) - (3)].i); ;}
     break;
 
   case 446:
-#line 4956 "Gmsh.y"
+#line 5023 "Gmsh.y"
     {
       memcpy((yyval.v), (yyvsp[(1) - (1)].v), 5*sizeof(double));
     ;}
     break;
 
   case 447:
-#line 4960 "Gmsh.y"
+#line 5027 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = -(yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
   case 448:
-#line 4964 "Gmsh.y"
+#line 5031 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(2) - (2)].v)[i];
     ;}
     break;
 
   case 449:
-#line 4968 "Gmsh.y"
+#line 5035 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(1) - (3)].v)[i] - (yyvsp[(3) - (3)].v)[i];
     ;}
     break;
 
   case 450:
-#line 4972 "Gmsh.y"
+#line 5039 "Gmsh.y"
     {
       for(int i = 0; i < 5; i++) (yyval.v)[i] = (yyvsp[(1) - (3)].v)[i] + (yyvsp[(3) - (3)].v)[i];
     ;}
     break;
 
   case 451:
-#line 4979 "Gmsh.y"
+#line 5046 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (11)].d);  (yyval.v)[1] = (yyvsp[(4) - (11)].d);  (yyval.v)[2] = (yyvsp[(6) - (11)].d);  (yyval.v)[3] = (yyvsp[(8) - (11)].d); (yyval.v)[4] = (yyvsp[(10) - (11)].d);
     ;}
     break;
 
   case 452:
-#line 4983 "Gmsh.y"
+#line 5050 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (9)].d);  (yyval.v)[1] = (yyvsp[(4) - (9)].d);  (yyval.v)[2] = (yyvsp[(6) - (9)].d);  (yyval.v)[3] = (yyvsp[(8) - (9)].d); (yyval.v)[4] = 1.0;
     ;}
     break;
 
   case 453:
-#line 4987 "Gmsh.y"
+#line 5054 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (7)].d);  (yyval.v)[1] = (yyvsp[(4) - (7)].d);  (yyval.v)[2] = (yyvsp[(6) - (7)].d);  (yyval.v)[3] = 0.0; (yyval.v)[4] = 1.0;
     ;}
     break;
 
   case 454:
-#line 4991 "Gmsh.y"
+#line 5058 "Gmsh.y"
     {
       (yyval.v)[0] = (yyvsp[(2) - (7)].d);  (yyval.v)[1] = (yyvsp[(4) - (7)].d);  (yyval.v)[2] = (yyvsp[(6) - (7)].d);  (yyval.v)[3] = 0.0; (yyval.v)[4] = 1.0;
     ;}
     break;
 
   case 455:
-#line 4998 "Gmsh.y"
+#line 5065 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(List_T*));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].l)));
@@ -11705,14 +11771,14 @@ yyreduce:
     break;
 
   case 456:
-#line 5003 "Gmsh.y"
+#line 5070 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].l)));
     ;}
     break;
 
   case 457:
-#line 5010 "Gmsh.y"
+#line 5077 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].d)));
@@ -11720,14 +11786,14 @@ yyreduce:
     break;
 
   case 458:
-#line 5015 "Gmsh.y"
+#line 5082 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
   case 459:
-#line 5019 "Gmsh.y"
+#line 5086 "Gmsh.y"
     {
       // creates an empty list
       (yyval.l) = List_Create(2, 1, sizeof(double));
@@ -11735,14 +11801,14 @@ yyreduce:
     break;
 
   case 460:
-#line 5024 "Gmsh.y"
+#line 5091 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (3)].l);
     ;}
     break;
 
   case 461:
-#line 5028 "Gmsh.y"
+#line 5095 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (4)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -11753,7 +11819,7 @@ yyreduce:
     break;
 
   case 462:
-#line 5036 "Gmsh.y"
+#line 5103 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(4) - (5)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -11764,14 +11830,14 @@ yyreduce:
     break;
 
   case 463:
-#line 5047 "Gmsh.y"
+#line 5114 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
   case 464:
-#line 5051 "Gmsh.y"
+#line 5118 "Gmsh.y"
     {
       if(!strcmp((yyvsp[(1) - (1)].c), "*") || !strcmp((yyvsp[(1) - (1)].c), "all"))
         (yyval.l) = 0;
@@ -11783,7 +11849,7 @@ yyreduce:
     break;
 
   case 465:
-#line 5063 "Gmsh.y"
+#line 5130 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (2)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -11794,7 +11860,7 @@ yyreduce:
     break;
 
   case 466:
-#line 5071 "Gmsh.y"
+#line 5138 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (3)].l);
       for(int i = 0; i < List_Nbr((yyval.l)); i++){
@@ -11805,7 +11871,7 @@ yyreduce:
     break;
 
   case 467:
-#line 5079 "Gmsh.y"
+#line 5146 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       for(double d = (yyvsp[(1) - (3)].d); ((yyvsp[(1) - (3)].d) < (yyvsp[(3) - (3)].d)) ? (d <= (yyvsp[(3) - (3)].d)) : (d >= (yyvsp[(3) - (3)].d));
@@ -11815,7 +11881,7 @@ yyreduce:
     break;
 
   case 468:
-#line 5086 "Gmsh.y"
+#line 5153 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!(yyvsp[(5) - (5)].d)){  //|| ($1 < $3 && $5 < 0) || ($1 > $3 && $5 > 0)
@@ -11828,7 +11894,7 @@ yyreduce:
     break;
 
   case 469:
-#line 5096 "Gmsh.y"
+#line 5163 "Gmsh.y"
     {
       (yyval.l) = List_Create(3, 1, sizeof(double));
       int tag = (int)(yyvsp[(3) - (4)].d);
@@ -11854,7 +11920,7 @@ yyreduce:
     break;
 
   case 470:
-#line 5119 "Gmsh.y"
+#line 5186 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getAllElementaryTags(0, (yyval.l));
@@ -11863,7 +11929,7 @@ yyreduce:
     break;
 
   case 471:
-#line 5125 "Gmsh.y"
+#line 5192 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getAllElementaryTags(1, (yyval.l));
@@ -11872,7 +11938,7 @@ yyreduce:
     break;
 
   case 472:
-#line 5131 "Gmsh.y"
+#line 5198 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getAllElementaryTags(2, (yyval.l));
@@ -11881,7 +11947,7 @@ yyreduce:
     break;
 
   case 473:
-#line 5137 "Gmsh.y"
+#line 5204 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getAllElementaryTags(3, (yyval.l));
@@ -11890,7 +11956,7 @@ yyreduce:
     break;
 
   case 474:
-#line 5143 "Gmsh.y"
+#line 5210 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       if(!(yyvsp[(3) - (3)].l)){
@@ -11904,7 +11970,7 @@ yyreduce:
     break;
 
   case 475:
-#line 5154 "Gmsh.y"
+#line 5221 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       if(!(yyvsp[(3) - (3)].l)){
@@ -11918,7 +11984,7 @@ yyreduce:
     break;
 
   case 476:
-#line 5165 "Gmsh.y"
+#line 5232 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       if(!(yyvsp[(3) - (3)].l)){
@@ -11932,7 +11998,7 @@ yyreduce:
     break;
 
   case 477:
-#line 5176 "Gmsh.y"
+#line 5243 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       if(!(yyvsp[(3) - (3)].l)){
@@ -11946,7 +12012,7 @@ yyreduce:
     break;
 
   case 478:
-#line 5188 "Gmsh.y"
+#line 5255 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getElementaryTagsInBoundingBox(0, (yyvsp[(5) - (16)].d), (yyvsp[(7) - (16)].d), (yyvsp[(9) - (16)].d), (yyvsp[(11) - (16)].d), (yyvsp[(13) - (16)].d), (yyvsp[(15) - (16)].d), (yyval.l));
@@ -11954,7 +12020,7 @@ yyreduce:
     break;
 
   case 479:
-#line 5194 "Gmsh.y"
+#line 5261 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getElementaryTagsInBoundingBox(1, (yyvsp[(5) - (16)].d), (yyvsp[(7) - (16)].d), (yyvsp[(9) - (16)].d), (yyvsp[(11) - (16)].d), (yyvsp[(13) - (16)].d), (yyvsp[(15) - (16)].d), (yyval.l));
@@ -11962,7 +12028,7 @@ yyreduce:
     break;
 
   case 480:
-#line 5200 "Gmsh.y"
+#line 5267 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getElementaryTagsInBoundingBox(2, (yyvsp[(5) - (16)].d), (yyvsp[(7) - (16)].d), (yyvsp[(9) - (16)].d), (yyvsp[(11) - (16)].d), (yyvsp[(13) - (16)].d), (yyvsp[(15) - (16)].d), (yyval.l));
@@ -11970,7 +12036,7 @@ yyreduce:
     break;
 
   case 481:
-#line 5206 "Gmsh.y"
+#line 5273 "Gmsh.y"
     {
       (yyval.l) = List_Create(10, 10, sizeof(double));
       getElementaryTagsInBoundingBox(3, (yyvsp[(5) - (16)].d), (yyvsp[(7) - (16)].d), (yyvsp[(9) - (16)].d), (yyvsp[(11) - (16)].d), (yyvsp[(13) - (16)].d), (yyvsp[(15) - (16)].d), (yyval.l));
@@ -11978,7 +12044,7 @@ yyreduce:
     break;
 
   case 482:
-#line 5211 "Gmsh.y"
+#line 5278 "Gmsh.y"
     {
       (yyval.l) = List_Create(List_Nbr((yyvsp[(1) - (1)].l)), 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(1) - (1)].l)); i++){
@@ -11991,7 +12057,7 @@ yyreduce:
     break;
 
   case 483:
-#line 5221 "Gmsh.y"
+#line 5288 "Gmsh.y"
     {
       (yyval.l) = List_Create(List_Nbr((yyvsp[(1) - (1)].l)), 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(1) - (1)].l)); i++){
@@ -12004,7 +12070,7 @@ yyreduce:
     break;
 
   case 484:
-#line 5231 "Gmsh.y"
+#line 5298 "Gmsh.y"
     {
       (yyval.l) = List_Create(List_Nbr((yyvsp[(1) - (1)].l)), 1, sizeof(double));
       for(int i = 0; i < List_Nbr((yyvsp[(1) - (1)].l)); i++){
@@ -12017,7 +12083,7 @@ yyreduce:
     break;
 
   case 485:
-#line 5241 "Gmsh.y"
+#line 5308 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count((yyvsp[(1) - (3)].c)))
@@ -12032,7 +12098,7 @@ yyreduce:
     break;
 
   case 486:
-#line 5254 "Gmsh.y"
+#line 5321 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count((yyvsp[(3) - (4)].c)))
@@ -12047,28 +12113,28 @@ yyreduce:
     break;
 
   case 487:
-#line 5266 "Gmsh.y"
+#line 5333 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (4)].l);
     ;}
     break;
 
   case 488:
-#line 5270 "Gmsh.y"
+#line 5337 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(3) - (4)].l);
     ;}
     break;
 
   case 489:
-#line 5274 "Gmsh.y"
+#line 5341 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(4) - (6)].l);
     ;}
     break;
 
   case 490:
-#line 5278 "Gmsh.y"
+#line 5345 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       if(!gmsh_yysymbols.count((yyvsp[(1) - (6)].c)))
@@ -12089,7 +12155,7 @@ yyreduce:
     break;
 
   case 491:
-#line 5296 "Gmsh.y"
+#line 5363 "Gmsh.y"
     {
       (yyval.l) = List_Create(20,20,sizeof(double));
       for(int i = 0; i < (int)(yyvsp[(7) - (8)].d); i++) {
@@ -12100,7 +12166,7 @@ yyreduce:
     break;
 
   case 492:
-#line 5304 "Gmsh.y"
+#line 5371 "Gmsh.y"
     {
       (yyval.l) = List_Create(20,20,sizeof(double));
       for(int i = 0; i < (int)(yyvsp[(7) - (8)].d); i++) {
@@ -12111,7 +12177,7 @@ yyreduce:
     break;
 
   case 493:
-#line 5312 "Gmsh.y"
+#line 5379 "Gmsh.y"
     {
       Msg::Barrier();
       FILE *File;
@@ -12143,7 +12209,7 @@ yyreduce:
     break;
 
   case 494:
-#line 5341 "Gmsh.y"
+#line 5408 "Gmsh.y"
     {
       double x0 = (yyvsp[(3) - (14)].d), x1 = (yyvsp[(5) - (14)].d), y0 = (yyvsp[(7) - (14)].d), y1 = (yyvsp[(9) - (14)].d), ys = (yyvsp[(11) - (14)].d);
       int N = (int)(yyvsp[(13) - (14)].d);
@@ -12156,7 +12222,7 @@ yyreduce:
     break;
 
   case 495:
-#line 5351 "Gmsh.y"
+#line 5418 "Gmsh.y"
     {
       std::vector<double> tmp;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
@@ -12175,7 +12241,7 @@ yyreduce:
     break;
 
   case 496:
-#line 5367 "Gmsh.y"
+#line 5434 "Gmsh.y"
     {
       std::set<double> c;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
@@ -12196,7 +12262,7 @@ yyreduce:
     break;
 
   case 497:
-#line 5385 "Gmsh.y"
+#line 5452 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++){
         double *d = (double*)List_Pointer((yyvsp[(3) - (4)].l), i);
@@ -12207,7 +12273,7 @@ yyreduce:
     break;
 
   case 498:
-#line 5396 "Gmsh.y"
+#line 5463 "Gmsh.y"
     {
       (yyval.l) = List_Create(2, 1, sizeof(double));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].d)));
@@ -12215,21 +12281,21 @@ yyreduce:
     break;
 
   case 499:
-#line 5401 "Gmsh.y"
+#line 5468 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(1) - (1)].l);
     ;}
     break;
 
   case 500:
-#line 5405 "Gmsh.y"
+#line 5472 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].d)));
     ;}
     break;
 
   case 501:
-#line 5409 "Gmsh.y"
+#line 5476 "Gmsh.y"
     {
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (3)].l)); i++){
 	double d;
@@ -12241,21 +12307,21 @@ yyreduce:
     break;
 
   case 502:
-#line 5421 "Gmsh.y"
+#line 5488 "Gmsh.y"
     {
       (yyval.u) = CTX::instance()->packColor((int)(yyvsp[(2) - (9)].d), (int)(yyvsp[(4) - (9)].d), (int)(yyvsp[(6) - (9)].d), (int)(yyvsp[(8) - (9)].d));
     ;}
     break;
 
   case 503:
-#line 5425 "Gmsh.y"
+#line 5492 "Gmsh.y"
     {
       (yyval.u) = CTX::instance()->packColor((int)(yyvsp[(2) - (7)].d), (int)(yyvsp[(4) - (7)].d), (int)(yyvsp[(6) - (7)].d), 255);
     ;}
     break;
 
   case 504:
-#line 5437 "Gmsh.y"
+#line 5504 "Gmsh.y"
     {
       int flag = 0;
       if(gmsh_yystringsymbols.count((yyvsp[(1) - (1)].c))){
@@ -12275,7 +12341,7 @@ yyreduce:
     break;
 
   case 505:
-#line 5454 "Gmsh.y"
+#line 5521 "Gmsh.y"
     {
       unsigned int val = 0;
       ColorOption(GMSH_GET, (yyvsp[(1) - (5)].c), 0, (yyvsp[(5) - (5)].c), val);
@@ -12285,14 +12351,14 @@ yyreduce:
     break;
 
   case 506:
-#line 5464 "Gmsh.y"
+#line 5531 "Gmsh.y"
     {
       (yyval.l) = (yyvsp[(2) - (3)].l);
     ;}
     break;
 
   case 507:
-#line 5468 "Gmsh.y"
+#line 5535 "Gmsh.y"
     {
       (yyval.l) = List_Create(256, 10, sizeof(unsigned int));
       GmshColorTable *ct = GetColorTable((int)(yyvsp[(3) - (6)].d));
@@ -12307,7 +12373,7 @@ yyreduce:
     break;
 
   case 508:
-#line 5483 "Gmsh.y"
+#line 5550 "Gmsh.y"
     {
       (yyval.l) = List_Create(256, 10, sizeof(unsigned int));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].u)));
@@ -12315,21 +12381,21 @@ yyreduce:
     break;
 
   case 509:
-#line 5488 "Gmsh.y"
+#line 5555 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].u)));
     ;}
     break;
 
   case 510:
-#line 5495 "Gmsh.y"
+#line 5562 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(1) - (1)].c);
     ;}
     break;
 
   case 511:
-#line 5499 "Gmsh.y"
+#line 5566 "Gmsh.y"
     {
       std::string val;
       if(!gmsh_yystringsymbols.count((yyvsp[(1) - (1)].c)))
@@ -12345,7 +12411,7 @@ yyreduce:
     break;
 
   case 512:
-#line 5512 "Gmsh.y"
+#line 5579 "Gmsh.y"
     {
       std::string val;
       int j = (int)(yyvsp[(3) - (4)].d);
@@ -12362,7 +12428,7 @@ yyreduce:
     break;
 
   case 513:
-#line 5526 "Gmsh.y"
+#line 5593 "Gmsh.y"
     {
       std::string val;
       int j = (int)(yyvsp[(3) - (4)].d);
@@ -12379,7 +12445,7 @@ yyreduce:
     break;
 
   case 514:
-#line 5543 "Gmsh.y"
+#line 5610 "Gmsh.y"
     {
       (yyval.c) = treat_Struct_FullName_dot_tSTRING_String(NULL, (yyvsp[(1) - (3)].c), (yyvsp[(3) - (3)].c));
       /*
@@ -12408,12 +12474,12 @@ yyreduce:
     break;
 
   case 515:
-#line 5569 "Gmsh.y"
+#line 5636 "Gmsh.y"
     { (yyval.c) = treat_Struct_FullName_dot_tSTRING_String((yyvsp[(1) - (5)].c), (yyvsp[(3) - (5)].c), (yyvsp[(5) - (5)].c)); ;}
     break;
 
   case 516:
-#line 5573 "Gmsh.y"
+#line 5640 "Gmsh.y"
     {
       std::string out;
       StringOption(GMSH_GET, (yyvsp[(1) - (6)].c), (int)(yyvsp[(3) - (6)].d), (yyvsp[(6) - (6)].c), out);
@@ -12424,7 +12490,7 @@ yyreduce:
     break;
 
   case 517:
-#line 5581 "Gmsh.y"
+#line 5648 "Gmsh.y"
     {
       std::string name = GModel::current()->getPhysicalName(0, (int)(yyvsp[(4) - (5)].d));
       (yyval.c) = (char*)Malloc((name.size() + 1) * sizeof(char));
@@ -12433,7 +12499,7 @@ yyreduce:
     break;
 
   case 518:
-#line 5587 "Gmsh.y"
+#line 5654 "Gmsh.y"
     {
       std::string name = GModel::current()->getPhysicalName(1, (int)(yyvsp[(4) - (5)].d));
       (yyval.c) = (char*)Malloc((name.size() + 1) * sizeof(char));
@@ -12442,7 +12508,7 @@ yyreduce:
     break;
 
   case 519:
-#line 5593 "Gmsh.y"
+#line 5660 "Gmsh.y"
     {
       std::string name = GModel::current()->getPhysicalName(2, (int)(yyvsp[(4) - (5)].d));
       (yyval.c) = (char*)Malloc((name.size() + 1) * sizeof(char));
@@ -12451,7 +12517,7 @@ yyreduce:
     break;
 
   case 520:
-#line 5599 "Gmsh.y"
+#line 5666 "Gmsh.y"
     {
       std::string name = GModel::current()->getPhysicalName(3, (int)(yyvsp[(4) - (5)].d));
       (yyval.c) = (char*)Malloc((name.size() + 1) * sizeof(char));
@@ -12460,21 +12526,21 @@ yyreduce:
     break;
 
   case 521:
-#line 5608 "Gmsh.y"
+#line 5675 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(1) - (1)].c);
     ;}
     break;
 
   case 522:
-#line 5612 "Gmsh.y"
+#line 5679 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(3) - (4)].c);
     ;}
     break;
 
   case 523:
-#line 5616 "Gmsh.y"
+#line 5683 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc(32 * sizeof(char));
       time_t now;
@@ -12485,7 +12551,7 @@ yyreduce:
     break;
 
   case 524:
-#line 5624 "Gmsh.y"
+#line 5691 "Gmsh.y"
     {
       std::string exe = Msg::GetExecutableName();
       (yyval.c) = (char *)Malloc(exe.size() + 1);
@@ -12494,7 +12560,7 @@ yyreduce:
     break;
 
   case 525:
-#line 5630 "Gmsh.y"
+#line 5697 "Gmsh.y"
     {
       std::string action = Msg::GetOnelabAction();
       (yyval.c) = (char *)Malloc(action.size() + 1);
@@ -12503,7 +12569,7 @@ yyreduce:
     break;
 
   case 526:
-#line 5636 "Gmsh.y"
+#line 5703 "Gmsh.y"
     {
       const char *env = GetEnvironmentVar((yyvsp[(3) - (4)].c));
       if(!env) env = "";
@@ -12514,7 +12580,7 @@ yyreduce:
     break;
 
   case 527:
-#line 5644 "Gmsh.y"
+#line 5711 "Gmsh.y"
     {
       std::string s = Msg::GetString((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].c));
       (yyval.c) = (char *)Malloc((s.size() + 1) * sizeof(char));
@@ -12525,7 +12591,7 @@ yyreduce:
     break;
 
   case 528:
-#line 5652 "Gmsh.y"
+#line 5719 "Gmsh.y"
     {
       std::string s = Msg::GetOnelabString((yyvsp[(3) - (4)].c));
       (yyval.c) = (char *)Malloc((s.size() + 1) * sizeof(char));
@@ -12535,7 +12601,7 @@ yyreduce:
     break;
 
   case 529:
-#line 5659 "Gmsh.y"
+#line 5726 "Gmsh.y"
     {
       std::string s = Msg::GetOnelabString((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].c));
       (yyval.c) = (char *)Malloc((s.size() + 1) * sizeof(char));
@@ -12546,7 +12612,7 @@ yyreduce:
     break;
 
   case 530:
-#line 5667 "Gmsh.y"
+#line 5734 "Gmsh.y"
     {
       int size = 1;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++)
@@ -12564,7 +12630,7 @@ yyreduce:
     break;
 
   case 531:
-#line 5682 "Gmsh.y"
+#line 5749 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (4)].c)) + 1) * sizeof(char));
       int i;
@@ -12581,7 +12647,7 @@ yyreduce:
     break;
 
   case 532:
-#line 5696 "Gmsh.y"
+#line 5763 "Gmsh.y"
     {
       (yyval.c) = (char *)Malloc((strlen((yyvsp[(3) - (4)].c)) + 1) * sizeof(char));
       int i;
@@ -12598,7 +12664,7 @@ yyreduce:
     break;
 
   case 533:
-#line 5710 "Gmsh.y"
+#line 5777 "Gmsh.y"
     {
       std::string input = (yyvsp[(3) - (8)].c);
       std::string substr_old = (yyvsp[(5) - (8)].c);
@@ -12613,7 +12679,7 @@ yyreduce:
     break;
 
   case 534:
-#line 5722 "Gmsh.y"
+#line 5789 "Gmsh.y"
     {
       int size = 1;
       for(int i = 0; i < List_Nbr((yyvsp[(3) - (4)].l)); i++)
@@ -12632,7 +12698,7 @@ yyreduce:
     break;
 
   case 535:
-#line 5738 "Gmsh.y"
+#line 5805 "Gmsh.y"
     {
       int i = 0;
       while ((yyvsp[(3) - (4)].c)[i]) {
@@ -12644,7 +12710,7 @@ yyreduce:
     break;
 
   case 536:
-#line 5747 "Gmsh.y"
+#line 5814 "Gmsh.y"
     {
       int i = 0;
       while ((yyvsp[(3) - (4)].c)[i]) {
@@ -12656,7 +12722,7 @@ yyreduce:
     break;
 
   case 537:
-#line 5756 "Gmsh.y"
+#line 5823 "Gmsh.y"
     {
       int i = 0;
       while ((yyvsp[(3) - (4)].c)[i]) {
@@ -12669,7 +12735,7 @@ yyreduce:
     break;
 
   case 538:
-#line 5766 "Gmsh.y"
+#line 5833 "Gmsh.y"
     {
       if((yyvsp[(3) - (8)].d)){
         (yyval.c) = (yyvsp[(5) - (8)].c);
@@ -12683,7 +12749,7 @@ yyreduce:
     break;
 
   case 539:
-#line 5777 "Gmsh.y"
+#line 5844 "Gmsh.y"
     {
       std::string in = (yyvsp[(3) - (8)].c);
       std::string out = in.substr((int)(yyvsp[(5) - (8)].d), (int)(yyvsp[(7) - (8)].d));
@@ -12694,7 +12760,7 @@ yyreduce:
     break;
 
   case 540:
-#line 5785 "Gmsh.y"
+#line 5852 "Gmsh.y"
     {
       std::string in = (yyvsp[(3) - (6)].c);
       std::string out = in.substr((int)(yyvsp[(5) - (6)].d), std::string::npos);
@@ -12705,14 +12771,14 @@ yyreduce:
     break;
 
   case 541:
-#line 5793 "Gmsh.y"
+#line 5860 "Gmsh.y"
     {
       (yyval.c) = (yyvsp[(3) - (4)].c);
     ;}
     break;
 
   case 542:
-#line 5797 "Gmsh.y"
+#line 5864 "Gmsh.y"
     {
       char tmpstring[5000];
       int i = printListOfDouble((yyvsp[(3) - (6)].c), (yyvsp[(5) - (6)].l), tmpstring);
@@ -12734,7 +12800,7 @@ yyreduce:
     break;
 
   case 543:
-#line 5816 "Gmsh.y"
+#line 5883 "Gmsh.y"
     {
       std::string tmp = FixRelativePath(gmsh_yyname, (yyvsp[(3) - (4)].c));
       (yyval.c) = (char*)Malloc((tmp.size() + 1) * sizeof(char));
@@ -12744,7 +12810,7 @@ yyreduce:
     break;
 
   case 544:
-#line 5823 "Gmsh.y"
+#line 5890 "Gmsh.y"
     {
       std::string tmp = SplitFileName(GetAbsolutePath(gmsh_yyname))[0];
       (yyval.c) = (char*)Malloc((tmp.size() + 1) * sizeof(char));
@@ -12753,7 +12819,7 @@ yyreduce:
     break;
 
   case 545:
-#line 5829 "Gmsh.y"
+#line 5896 "Gmsh.y"
     {
       std::string tmp = SplitFileName((yyvsp[(3) - (4)].c))[0];
       (yyval.c) = (char*)Malloc((tmp.size() + 1) * sizeof(char));
@@ -12763,7 +12829,7 @@ yyreduce:
     break;
 
   case 546:
-#line 5836 "Gmsh.y"
+#line 5903 "Gmsh.y"
     {
       std::string tmp = GetAbsolutePath((yyvsp[(3) - (4)].c));
       (yyval.c) = (char*)Malloc((tmp.size() + 1) * sizeof(char));
@@ -12773,12 +12839,12 @@ yyreduce:
     break;
 
   case 547:
-#line 5843 "Gmsh.y"
+#line 5910 "Gmsh.y"
     { floatOptions.clear(); charOptions.clear(); ;}
     break;
 
   case 548:
-#line 5845 "Gmsh.y"
+#line 5912 "Gmsh.y"
     {
       std::string val((yyvsp[(3) - (6)].c));
       Msg::ExchangeOnelabParameter("", val, floatOptions, charOptions);
@@ -12789,7 +12855,7 @@ yyreduce:
     break;
 
   case 549:
-#line 5853 "Gmsh.y"
+#line 5920 "Gmsh.y"
     {
       std::string out;
       const std::string * key_struct = NULL;
@@ -12813,17 +12879,17 @@ yyreduce:
     break;
 
   case 550:
-#line 5877 "Gmsh.y"
+#line 5944 "Gmsh.y"
     { struct_namespace = std::string(""); (yyval.d) = (yyvsp[(2) - (2)].d); ;}
     break;
 
   case 551:
-#line 5879 "Gmsh.y"
+#line 5946 "Gmsh.y"
     { struct_namespace = (yyvsp[(1) - (4)].c); Free((yyvsp[(1) - (4)].c)); (yyval.d) = (yyvsp[(4) - (4)].d); ;}
     break;
 
   case 552:
-#line 5885 "Gmsh.y"
+#line 5952 "Gmsh.y"
     {
       (yyval.l) = List_Create(20,20,sizeof(char*));
       List_Add((yyval.l), &((yyvsp[(1) - (1)].c)));
@@ -12831,14 +12897,14 @@ yyreduce:
     break;
 
   case 553:
-#line 5890 "Gmsh.y"
+#line 5957 "Gmsh.y"
     {
       List_Add((yyval.l), &((yyvsp[(3) - (3)].c)));
     ;}
     break;
 
   case 554:
-#line 5898 "Gmsh.y"
+#line 5965 "Gmsh.y"
     {
       char tmpstr[256];
       sprintf(tmpstr, "_%d", (int)(yyvsp[(4) - (5)].d));
@@ -12849,7 +12915,7 @@ yyreduce:
     break;
 
   case 555:
-#line 5907 "Gmsh.y"
+#line 5974 "Gmsh.y"
     {
       char tmpstr[256];
       sprintf(tmpstr, "_%d", (int)(yyvsp[(4) - (5)].d));
@@ -12860,23 +12926,23 @@ yyreduce:
     break;
 
   case 556:
-#line 5920 "Gmsh.y"
+#line 5987 "Gmsh.y"
     { (yyval.c) = (yyvsp[(1) - (1)].c); ;}
     break;
 
   case 557:
-#line 5923 "Gmsh.y"
+#line 5990 "Gmsh.y"
     { (yyval.c) = (yyvsp[(1) - (1)].c); ;}
     break;
 
   case 558:
-#line 5927 "Gmsh.y"
+#line 5994 "Gmsh.y"
     { (yyval.c) = (yyvsp[(3) - (4)].c); ;}
     break;
 
 
 /* Line 1267 of yacc.c.  */
-#line 12880 "Gmsh.tab.cpp"
+#line 12946 "Gmsh.tab.cpp"
       default: break;
     }
   YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
@@ -13090,7 +13156,7 @@ yyreturn:
 }
 
 
-#line 5930 "Gmsh.y"
+#line 5997 "Gmsh.y"
 
 
 void assignVariable(const std::string &name, int index, int assignType,
@@ -13332,29 +13398,26 @@ void ListOfDouble2Vector(List_T *list, std::vector<double> &v)
   }
 }
 
-void ListOfShapes2Vectors(List_T *list, std::vector<int> v[4])
+void ListOfShapes2VectorOfPairs(List_T *list, std::vector<std::pair<int, int> > &v)
 {
-  Shape s;
   for(int i = 0; i < List_Nbr(list); i++){
+    Shape s;
     List_Read(list, i, &s);
     int dim = s.Type / 100 - 1;
-    if(dim >= 0 && dim <= 3) v[dim].push_back(s.Num);
+    if(dim >= 0 && dim <= 3) v.push_back(std::pair<int, int>(dim, s.Num));
   }
 }
 
-void Vectors2ListOfShapes(std::vector<int> tags[4], List_T *list)
+void VectorOfPairs2ListOfShapes(const std::vector<std::pair<int, int> > &v, List_T *list)
 {
-  for(int dim = 0; dim < 4; dim++){
+  for(unsigned int i = 0; i < v.size(); i++){
+    int dim = v[i].first;
+    int tag = v[i].second;
     Shape s;
-    s.Type =
-      (dim == 3) ? MSH_VOLUME :
-      (dim == 2) ? MSH_SURF_PLAN :
-      (dim == 1) ? MSH_SEGM_LINE :
-      MSH_POINT;
-    for(unsigned int i = 0; i < tags[dim].size(); i++){
-      s.Num = tags[dim][i];
-      List_Add(list, &s);
-    }
+    s.Type = (dim == 3) ? MSH_VOLUME : (dim == 2) ? MSH_SURF_PLAN :
+      (dim == 1) ? MSH_SEGM_LINE : MSH_POINT;
+    s.Num = tag;
+    List_Add(list, &s);
   }
 }
 
@@ -13634,7 +13697,8 @@ void setVisibility(int dim, int visible, bool recursive)
   }
 }
 
-void setVisibility(std::vector<int> tags[4], int visible, bool recursive)
+void setVisibility(const std::vector<std::pair<int, int> > &dimTags,
+                   int visible, bool recursive)
 {
   if(GModel::current()->getOCCInternals() &&
      GModel::current()->getOCCInternals()->getChanged())
@@ -13642,15 +13706,15 @@ void setVisibility(std::vector<int> tags[4], int visible, bool recursive)
   if(GModel::current()->getGEOInternals()->getChanged())
     GModel::current()->getGEOInternals()->synchronize(GModel::current());
 
-  for(int dim = 0; dim < 4; dim++){
-    for(unsigned int i = 0; i < tags[dim].size(); i++){
-      GEntity *ge = GModel::current()->getEntityByTag(dim, std::abs(tags[dim][i]));
-      if(ge) ge->setVisibility(visible, recursive);
-    }
+  for(unsigned int i = 0; i < dimTags.size(); i++){
+    GEntity *ge = GModel::current()->getEntityByTag
+      (dimTags[i].first, dimTags[i].second);
+    if(ge) ge->setVisibility(visible, recursive);
   }
 }
 
-void setColor(std::vector<int> tags[4], unsigned int val, bool recursive)
+void setColor(const std::vector<std::pair<int, int> > &dimTags,
+              unsigned int val, bool recursive)
 {
   if(GModel::current()->getOCCInternals() &&
      GModel::current()->getOCCInternals()->getChanged())
@@ -13658,11 +13722,10 @@ void setColor(std::vector<int> tags[4], unsigned int val, bool recursive)
   if(GModel::current()->getGEOInternals()->getChanged())
     GModel::current()->getGEOInternals()->synchronize(GModel::current());
 
-  for(int dim = 0; dim < 4; dim++){
-    for(unsigned int i = 0; i < tags[dim].size(); i++){
-      GEntity *ge = GModel::current()->getEntityByTag(dim, std::abs(tags[dim][i]));
-      if(ge) ge->setColor(val, recursive);
-    }
+  for(unsigned int i = 0; i < dimTags.size(); i++){
+    GEntity *ge = GModel::current()->getEntityByTag
+      (dimTags[i].first, dimTags[i].second);
+    if(ge) ge->setColor(val, recursive);
   }
 }
 
diff --git a/Parser/Gmsh.tab.hpp b/Parser/Gmsh.tab.hpp
index a26fcdc0ffd63ce5dff3f6be7ef55150d41a59ee..fbfc63ffae0bcfe0b6c0f505c04d460d6bee1287 100644
--- a/Parser/Gmsh.tab.hpp
+++ b/Parser/Gmsh.tab.hpp
@@ -484,7 +484,7 @@
 
 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
 typedef union YYSTYPE
-#line 138 "Gmsh.y"
+#line 139 "Gmsh.y"
 {
   char *c;
   int i;
diff --git a/Parser/Gmsh.y b/Parser/Gmsh.y
index 49877be11987ee36d1b8e7ffd22f6b8ddf6ec1c9..a1ed44ee54bf4476181dd254b4f1f5a18d064881 100644
--- a/Parser/Gmsh.y
+++ b/Parser/Gmsh.y
@@ -22,7 +22,6 @@
 #include "GModelIO_GEO.h"
 #include "GModelIO_OCC.h"
 #include "GeoDefines.h"
-#include "Geo.h" // FIXME: remove once Extrusion has been refactored
 #include "ExtrudeParams.h"
 #include "Options.h"
 #include "Parser.h"
@@ -108,8 +107,8 @@ int printListOfDouble(char *format, List_T *list, char *buffer);
 fullMatrix<double> ListOfListOfDouble2Matrix(List_T *list);
 void ListOfDouble2Vector(List_T *list, std::vector<int> &v);
 void ListOfDouble2Vector(List_T *list, std::vector<double> &v);
-void ListOfShapes2Vectors(List_T *list, std::vector<int> v[4]);
-void Vectors2ListOfShapes(std::vector<int> tags[4], List_T *list);
+void ListOfShapes2VectorOfPairs(List_T *list, std::vector<std::pair<int, int> > &v);
+void VectorOfPairs2ListOfShapes(const std::vector<std::pair<int, int> > &v, List_T *list);
 void addPeriodicEdge(int, int, const std::vector<double>&);
 void addPeriodicFace(int, int, const std::map<int, int>&);
 void addPeriodicFace(int, int, const std::vector<double>&);
@@ -122,8 +121,10 @@ void getElementaryTagsForPhysicalGroups(int dim, List_T *in, List_T *out);
 void getElementaryTagsInBoundingBox(int dim, double x1, double y1, double z1,
                                     double x2, double y2, double z2, List_T *out);
 void setVisibility(int dim, int visible, bool recursive);
-void setVisibility(std::vector<int> tags[4], int visible, bool recursive);
-void setColor(std::vector<int> tags[4], unsigned int val, bool recursive);
+void setVisibility(const std::vector<std::pair<int, int> > &dimTags, int visible,
+                   bool recursive);
+void setColor(const std::vector<std::pair<int, int> > &dimTags, unsigned int val,
+              bool recursive);
 
 double treat_Struct_FullName_dot_tSTRING_Float(char* c1, char* c2, char* c3);
 char* treat_Struct_FullName_dot_tSTRING_String(char* c1, char* c2, char* c3);
@@ -2075,10 +2076,11 @@ Shape :
   | tThruSections '(' FExpr ')' tAFFECT ListOfDouble tEND
     {
       int num = (int)$3;
-      std::vector<int> wires, out[4]; ListOfDouble2Vector($6, wires);
+      std::vector<int> wires; ListOfDouble2Vector($6, wires);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        std::vector<std::pair<int, int> > outDimTags;
         GModel::current()->getOCCInternals()->addThruSections
-          (num, wires, out, true, false);
+          (num, wires, outDimTags, true, false);
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -2090,10 +2092,11 @@ Shape :
   | tRuled tThruSections '(' FExpr ')' tAFFECT ListOfDouble tEND
     {
       int num = (int)$4;
-      std::vector<int> wires, out[4]; ListOfDouble2Vector($7, wires);
+      std::vector<int> wires; ListOfDouble2Vector($7, wires);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        std::vector<std::pair<int, int> > outDimTags;
         GModel::current()->getOCCInternals()->addThruSections
-          (num, wires, out, true, true);
+          (num, wires, outDimTags, true, true);
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -2158,80 +2161,82 @@ Shape :
 Transform :
     tTranslate VExpr '{' MultipleShape '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($4, tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($4, dimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        GModel::current()->getOCCInternals()->translate(tags, $2[0], $2[1], $2[2]);
+        GModel::current()->getOCCInternals()->translate(dimTags, $2[0], $2[1], $2[2]);
       }
       else{
-        GModel::current()->getGEOInternals()->translate(tags, $2[0], $2[1], $2[2]);
+        GModel::current()->getGEOInternals()->translate(dimTags, $2[0], $2[1], $2[2]);
       }
       $$ = $4;
     }
   | tRotate '{' VExpr ',' VExpr ',' FExpr '}' '{' MultipleShape '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($10, tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($10, dimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
         GModel::current()->getOCCInternals()->rotate
-          (tags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7);
+          (dimTags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7);
       }
       else{
         GModel::current()->getGEOInternals()->rotate
-          (tags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7);
+          (dimTags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7);
       }
       $$ = $10;
     }
   | tSymmetry  VExpr '{' MultipleShape '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($4, tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($4, dimTags);
       if(factory == "OpenCASCADE"){
         Msg::Error("Symmetry not implemented yet with OpenCASCADE factory");
       }
       else{
         GModel::current()->getGEOInternals()->symmetry
-          (tags, $2[0], $2[1], $2[2], $2[3]);
+          (dimTags, $2[0], $2[1], $2[2], $2[3]);
       }
       $$ = $4;
     }
   | tDilate '{' VExpr ',' FExpr '}' '{' MultipleShape '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($8, tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($8, dimTags);
       if(factory == "OpenCASCADE"){
         yymsg(0, "Dilate not implemented yet with OpenCASCADE factory");
       }
       else{
         GModel::current()->getGEOInternals()->dilate
-          (tags, $3[0], $3[1], $3[2], $5, $5, $5);
+          (dimTags, $3[0], $3[1], $3[2], $5, $5, $5);
       }
       $$ = $8;
     }
   | tDilate '{' VExpr ',' VExpr '}' '{' MultipleShape '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($8, tags);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($8, dimTags);
       if(factory == "OpenCASCADE"){
         yymsg(0, "Dilate not implemented yet with OpenCASCADE factory");
       }
       else{
         GModel::current()->getGEOInternals()->dilate
-          (tags, $3[0], $3[1], $3[2], $5[0], $5[1], $5[2]);
+          (dimTags, $3[0], $3[1], $3[2], $5[0], $5[1], $5[2]);
       }
       $$ = $8;
     }
   | tSTRING '{' MultipleShape '}'
     {
-      $$ = List_Create(3, 3, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($3, inDimTags);
+      $$ = $3;
+      List_Reset($$);
       std::string action($1);
       if(action == "Duplicata"){
-        // don't use per-dimension vectors here, in order to respect the input
-        // ordering (points can e.g. be given after surfaces) in the output
-        for(int i = 0; i < List_Nbr($3); i++){
-          Shape s; List_Read($3, i, &s); int dim = s.Type / 100 - 1;
-          if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-            s.Num = GModel::current()->getOCCInternals()->copy(dim, s.Num);
-          }
-          else{
-            s.Num = GModel::current()->getGEOInternals()->copy(dim, s.Num);
-          }
-          List_Add($$, &s);
+        if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+          GModel::current()->getOCCInternals()->copy(inDimTags, outDimTags);
+        }
+        else{
+          GModel::current()->getGEOInternals()->copy(inDimTags, outDimTags);
         }
       }
       else if(action == "Boundary" ||
@@ -2246,39 +2251,52 @@ Transform :
           GModel::current()->getOCCInternals()->synchronize(GModel::current());
         if(GModel::current()->getGEOInternals()->getChanged())
           GModel::current()->getGEOInternals()->synchronize(GModel::current());
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors($3, in);
         GModel::current()->getBoundaryTags
-          (in, out, action.find("Combined") != std::string::npos,
+          (inDimTags, outDimTags, action.find("Combined") != std::string::npos,
            action.find("Oriented") != std::string::npos);
-        Vectors2ListOfShapes(out, $$);
       }
       else{
         yymsg(0, "Unknown action on multiple shapes: %s", $1);
       }
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
       Free($1);
-      List_Delete($3);
     }
   | tIntersect tLine '{' RecursiveListOfDouble '}' tSurface '{' FExpr '}'
     {
       $$ = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE"){
-        yymsg(0, "Intersect Line not available with OpenCASCADE");
+        yymsg(0, "Intersect line not available with OpenCASCADE");
       }
       else{
-        IntersectCurvesWithSurface($4, (int)$8, $$);
+        std::vector<int> in, out; ListOfDouble2Vector($4, in);
+        GModel::current()->getGEOInternals()->intersectCurvesWithSurface
+          (in, (int)$8, out);
+        for(unsigned int i = 0; i < out.size(); i++){
+          Shape s;
+          s.Type = MSH_POINT;
+          s.Num = out[i];
+          List_Add($$, &s);
+        }
       }
       List_Delete($4);
     }
+  // syntax is wrong: should use {} around FExpr
   | tSplit tLine '(' FExpr ')' '{' RecursiveListOfDouble '}' tEND
     {
-      $$ = List_Create(2, 1, sizeof(Shape*));
+      $$ = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE"){
         yymsg(0, "Split Line not available with OpenCASCADE");
       }
       else{
-        List_T *tmp = ListOfDouble2ListOfInt($7);
-        SplitCurve((int)$4, tmp, $$);
-        List_Delete(tmp);
+        std::vector<int> vertices, curves; ListOfDouble2Vector($7, vertices);
+        GModel::current()->getGEOInternals()->splitCurve
+          ((int)$4, vertices, curves);
+        for(unsigned int i = 0; i < curves.size(); i++){
+          Shape s;
+          s.Type = MSH_SEGM_LINE;
+          s.Num = curves[i];
+          List_Add($$, &s);
+        }
       }
       List_Delete($7);
     }
@@ -2711,17 +2729,13 @@ LevelSet :
 Delete :
     tDelete '{' ListOfShapes '}'
     {
-      // don't use per-dimension vectors here, in order to respect the input
-      // ordering when deleting (important in GEO for dependencies, e.g. cannot
-      // delete boundary before the bounded entity)
-      for(int i = 0; i < List_Nbr($3); i++){
-        Shape s; List_Read($3, i, &s); int dim = s.Type / 100 - 1;
-        if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-          GModel::current()->getOCCInternals()->remove(dim, s.Num);
-        }
-        GModel::current()->getGEOInternals()->remove(dim, s.Num);
-        GModel::current()->remove(dim, s.Num);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($3, dimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        GModel::current()->getOCCInternals()->remove(dimTags);
       }
+      GModel::current()->getGEOInternals()->remove(dimTags);
+      GModel::current()->remove(dimTags);
       List_Delete($3);
     }
   | tDelete tField '[' FExpr ']' tEND
@@ -2792,14 +2806,16 @@ Delete :
 Colorify :
     tColor ColorExpr '{' ListOfShapes '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($4, tags);
-      setColor(tags, $2, false);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($4, dimTags);
+      setColor(dimTags, $2, false);
       List_Delete($4);
     }
   | tRecursive tColor ColorExpr '{' ListOfShapes '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($5, tags);
-      setColor(tags, $3, true);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($5, dimTags);
+      setColor(dimTags, $3, true);
       List_Delete($5);
     }
 ;
@@ -2809,14 +2825,14 @@ Colorify :
 SetPartition :
     tSetPartition FExpr '{' ListOfShapes '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($4, tags);
-      for(int dim = 0; dim < 4; dim++){
-        for(unsigned int i = 0; i < tags[dim].size(); i++){
-          GEntity *ge = GModel::current()->getEntityByTag(dim, tags[dim][i]);
-          if(ge){
-            for(unsigned int j = 0; j < ge->getNumMeshElements(); j++)
-              ge->getMeshElement(j)->setPartition((int)$2);
-          }
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($4, dimTags);
+      for(unsigned int i = 0; i < dimTags.size(); i++){
+        GEntity *ge = GModel::current()->getEntityByTag
+          (dimTags[i].first, dimTags[i].second);
+        if(ge){
+          for(unsigned int j = 0; j < ge->getNumMeshElements(); j++)
+            ge->getMeshElement(j)->setPartition((int)$2);
         }
       }
       List_Delete($4);
@@ -2840,26 +2856,30 @@ Visibility :
     }
   | tShow '{' ListOfShapes '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($3, tags);
-      setVisibility(tags, 1, false);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($3, dimTags);
+      setVisibility(dimTags, 1, false);
       List_Delete($3);
     }
   | tRecursive tShow '{' ListOfShapes '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($4, tags);
-      setVisibility(tags, 1, true);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($4, dimTags);
+      setVisibility(dimTags, 1, true);
       List_Delete($4);
     }
   | tHide '{' ListOfShapes '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($3, tags);
-      setVisibility(tags, 0, false);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($3, dimTags);
+      setVisibility(dimTags, 0, false);
       List_Delete($3);
     }
   | tRecursive tHide '{' ListOfShapes '}'
     {
-      std::vector<int> tags[4]; ListOfShapes2Vectors($4, tags);
-      setVisibility(tags, 0, true);
+      std::vector<std::pair<int, int> > dimTags;
+      ListOfShapes2VectorOfPairs($4, dimTags);
+      setVisibility(dimTags, 0, true);
       List_Delete($4);
     }
 ;
@@ -3427,43 +3447,51 @@ Loop :
 Extrude :
     tExtrude VExpr '{' ListOfShapes '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($4, inDimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors($4, in);
-        GModel::current()->getOCCInternals()->extrude(-1, in, $2[0], $2[1], $2[2], out);
-        Vectors2ListOfShapes(out, $$);
+        GModel::current()->getOCCInternals()->extrude
+          (inDimTags, $2[0], $2[1], $2[2], outDimTags);
       }
       else{
-        // FIXME use GEOInternals + int api -- SAME FOR ALL BELOW!
-        ExtrudeShapes(TRANSLATE, $4,
-                      $2[0], $2[1], $2[2], 0., 0., 0., 0., 0., 0., 0.,
-                      NULL, $$);
+        GModel::current()->getGEOInternals()->extrude
+          (inDimTags, $2[0], $2[1], $2[2], outDimTags);
       }
-      List_Delete($4);
+      $$ = $4;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tExtrude '{' VExpr ',' VExpr ',' FExpr '}' '{' ListOfShapes '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($10, inDimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors($10, in);
-        GModel::current()->getOCCInternals()->revolve(-1, in, $5[0], $5[1], $5[2],
-                                                      $3[0], $3[1], $3[2], $7, out);
-        Vectors2ListOfShapes(out, $$);
+        GModel::current()->getOCCInternals()->revolve
+          (inDimTags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7, outDimTags);
       }
       else{
-        ExtrudeShapes(ROTATE, $10,
-                      0., 0., 0., $3[0], $3[1], $3[2], $5[0], $5[1], $5[2], $7,
-                      NULL, $$);
+        GModel::current()->getGEOInternals()->revolve
+          (inDimTags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7, outDimTags);
       }
-      List_Delete($10);
+      $$ = $10;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tExtrude '{' VExpr ',' VExpr ',' VExpr ',' FExpr '}' '{' ListOfShapes '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(TRANSLATE_ROTATE, $12,
-		    $3[0], $3[1], $3[2], $5[0], $5[1], $5[2], $7[0], $7[1], $7[2], $9,
-		    NULL, $$);
-      List_Delete($12);
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($12, inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        yymsg(0, "Twisting extrude not available with OpenCASCADE factory");
+      }
+      else{
+        GModel::current()->getGEOInternals()->twist
+          (inDimTags, $7[0], $7[1], $7[2], $3[0], $3[1], $3[2], $5[0], $5[1], $5[2],
+           $9,  outDimTags);
+      }
+      $$ = $12;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tExtrude VExpr '{' ListOfShapes
     {
@@ -3473,11 +3501,19 @@ Extrude :
     }
                        ExtrudeParameters '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(TRANSLATE, $4,
-		    $2[0], $2[1], $2[2], 0., 0., 0., 0., 0., 0., 0.,
-		    &extr, $$);
-      List_Delete($4);
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($4, inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        GModel::current()->getOCCInternals()->extrude
+          (inDimTags, $2[0], $2[1], $2[2], outDimTags, &extr);
+      }
+      else{
+        GModel::current()->getGEOInternals()->extrude
+          (inDimTags, $2[0], $2[1], $2[2], outDimTags, &extr);
+      }
+      $$ = $4;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tExtrude '{' VExpr ',' VExpr ',' FExpr '}' '{' ListOfShapes
     {
@@ -3487,11 +3523,21 @@ Extrude :
     }
                                                    ExtrudeParameters '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(ROTATE, $10,
-		    0., 0., 0., $3[0], $3[1], $3[2], $5[0], $5[1], $5[2], $7,
-		    &extr, $$);
-      List_Delete($10);
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($10, inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        GModel::current()->getOCCInternals()->revolve
+          (inDimTags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7, outDimTags,
+           &extr);
+      }
+      else{
+        GModel::current()->getGEOInternals()->revolve
+          (inDimTags, $5[0], $5[1], $5[2], $3[0], $3[1], $3[2], $7, outDimTags,
+           &extr);
+      }
+      $$ = $10;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tExtrude '{' VExpr ',' VExpr ',' VExpr ',' FExpr '}' '{' ListOfShapes
     {
@@ -3501,11 +3547,19 @@ Extrude :
     }
                                                              ExtrudeParameters '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(TRANSLATE_ROTATE, $12,
-		    $3[0], $3[1], $3[2], $5[0], $5[1], $5[2], $7[0], $7[1], $7[2], $9,
-		    &extr, $$);
-      List_Delete($12);
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($12, inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        yymsg(0, "Twisting extrude not available with OpenCASCADE factory");
+      }
+      else{
+        GModel::current()->getGEOInternals()->twist
+          (inDimTags, $7[0], $7[1], $7[2], $3[0], $3[1], $3[2], $5[0], $5[1], $5[2],
+           $9,  outDimTags, &extr);
+      }
+      $$ = $12;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tExtrude '{' ListOfShapes
     {
@@ -3515,32 +3569,42 @@ Extrude :
     }
                        ExtrudeParameters '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
-      ExtrudeShapes(BOUNDARY_LAYER, $3, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
-		    &extr, $$);
-      List_Delete($3);
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($3, inDimTags);
+      if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
+        yymsg(0, "Boundary layer extrusion not available with OpenCASCADE factory");
+      }
+      else{
+        GModel::current()->getGEOInternals()->boundaryLayer
+          (inDimTags, outDimTags, &extr);
+      }
+      $$ = $3;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tExtrude '{' ListOfShapes '}' tUsing tWire '{' FExpr '}'
     {
-      $$ = List_Create(2, 1, sizeof(Shape));
+      std::vector<std::pair<int, int> > inDimTags, outDimTags;
+      ListOfShapes2VectorOfPairs($3, inDimTags);
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> in[4], out[4]; ListOfShapes2Vectors($3, in);
-        GModel::current()->getOCCInternals()->addPipe(-1, in, (int)$8, out);
-        Vectors2ListOfShapes(out, $$);
+        GModel::current()->getOCCInternals()->addPipe(inDimTags, (int)$8, outDimTags);
       }
       else{
         yymsg(0, "Pipe only available with OpenCASCADE factory");
       }
-      List_Delete($3);
+      $$ = $3;
+      List_Reset($$);
+      VectorOfPairs2ListOfShapes(outDimTags, $$);
     }
   | tThruSections ListOfDouble
     {
       $$ = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> wires, out[4]; ListOfDouble2Vector($2, wires);
-        GModel::current()->getOCCInternals()->addThruSections(-1, wires, out,
-                                                              false, false);
-        Vectors2ListOfShapes(out, $$);
+        std::vector<int> wires; ListOfDouble2Vector($2, wires);
+        std::vector<std::pair<int, int> > outDimTags;
+        GModel::current()->getOCCInternals()->addThruSections
+          (-1, wires, outDimTags, false, false);
+        VectorOfPairs2ListOfShapes(outDimTags, $$);
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -3551,10 +3615,11 @@ Extrude :
     {
       $$ = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> wires, out[4]; ListOfDouble2Vector($3, wires);
-        GModel::current()->getOCCInternals()->addThruSections(-1, wires, out,
-                                                              false, true);
-        Vectors2ListOfShapes(out, $$);
+        std::vector<int> wires; ListOfDouble2Vector($3, wires);
+        std::vector<std::pair<int, int> > outDimTags;
+        GModel::current()->getOCCInternals()->addThruSections
+          (-1, wires, outDimTags, false, true);
+        VectorOfPairs2ListOfShapes(outDimTags, $$);
       }
       else{
         yymsg(0, "ThruSections only available with OpenCASCADE factory");
@@ -3566,10 +3631,12 @@ Extrude :
       $$ = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
         double radius = $9;
-        std::vector<int> regions, edges, out[4];
+        std::vector<int> regions, edges;
         ListOfDouble2Vector($3, regions); ListOfDouble2Vector($6, edges);
-        GModel::current()->getOCCInternals()->fillet(regions, edges, radius, out);
-        Vectors2ListOfShapes(out, $$);
+        std::vector<std::pair<int, int> > outDimTags;
+        GModel::current()->getOCCInternals()->fillet
+          (regions, edges, radius, outDimTags);
+        VectorOfPairs2ListOfShapes(outDimTags, $$);
       }
       else{
         yymsg(0, "Fillet only available with OpenCASCADE factory");
@@ -3689,12 +3756,12 @@ Boolean :
     {
       $$ = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> shape[4], tool[4], out[4];
-        ListOfShapes2Vectors($3, shape);
-        ListOfShapes2Vectors($7, tool);
+        std::vector<std::pair<int, int > > object, tool, out;
+        ListOfShapes2VectorOfPairs($3, object);
+        ListOfShapes2VectorOfPairs($7, tool);
         GModel::current()->getOCCInternals()->applyBooleanOperator
-          (-1, (OCC_Internals::BooleanOperator)$1, shape, tool, out, $4, $8);
-        Vectors2ListOfShapes(out, $$);
+          (-1, (OCC_Internals::BooleanOperator)$1, object, tool, out, $4, $8);
+        VectorOfPairs2ListOfShapes(out, $$);
       }
       else{
         yymsg(0, "Boolean operators only available with OpenCASCADE factory");
@@ -3706,10 +3773,10 @@ Boolean :
     {
       $$ = List_Create(2, 1, sizeof(Shape));
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> out[4];
+        std::vector<std::pair<int, int> > out;
         std::string tmp = FixRelativePath(gmsh_yyname, $3);
         GModel::current()->getOCCInternals()->importShapes(tmp, true, out);
-        Vectors2ListOfShapes(out, $$);
+        VectorOfPairs2ListOfShapes(out, $$);
       }
       else{
         yymsg(0, "ShapeFromFile only available with OpenCASCADE factory");
@@ -3723,11 +3790,11 @@ BooleanShape :
                                           '{' ListOfShapes BooleanOption '}' tEND
     {
       if(factory == "OpenCASCADE" && GModel::current()->getOCCInternals()){
-        std::vector<int> shape[4], tool[4], out[4];
-        ListOfShapes2Vectors($7, shape);
-        ListOfShapes2Vectors($11, tool);
+        std::vector<std::pair<int, int> > object, tool, out;
+        ListOfShapes2VectorOfPairs($7, object);
+        ListOfShapes2VectorOfPairs($11, tool);
         GModel::current()->getOCCInternals()->applyBooleanOperator
-          ((int)$3, (OCC_Internals::BooleanOperator)$1, shape, tool, out, $8, $12);
+          ((int)$3, (OCC_Internals::BooleanOperator)$1, object, tool, out, $8, $12);
       }
       List_Delete($7);
       List_Delete($11);
@@ -6168,29 +6235,26 @@ void ListOfDouble2Vector(List_T *list, std::vector<double> &v)
   }
 }
 
-void ListOfShapes2Vectors(List_T *list, std::vector<int> v[4])
+void ListOfShapes2VectorOfPairs(List_T *list, std::vector<std::pair<int, int> > &v)
 {
-  Shape s;
   for(int i = 0; i < List_Nbr(list); i++){
+    Shape s;
     List_Read(list, i, &s);
     int dim = s.Type / 100 - 1;
-    if(dim >= 0 && dim <= 3) v[dim].push_back(s.Num);
+    if(dim >= 0 && dim <= 3) v.push_back(std::pair<int, int>(dim, s.Num));
   }
 }
 
-void Vectors2ListOfShapes(std::vector<int> tags[4], List_T *list)
+void VectorOfPairs2ListOfShapes(const std::vector<std::pair<int, int> > &v, List_T *list)
 {
-  for(int dim = 0; dim < 4; dim++){
+  for(unsigned int i = 0; i < v.size(); i++){
+    int dim = v[i].first;
+    int tag = v[i].second;
     Shape s;
-    s.Type =
-      (dim == 3) ? MSH_VOLUME :
-      (dim == 2) ? MSH_SURF_PLAN :
-      (dim == 1) ? MSH_SEGM_LINE :
-      MSH_POINT;
-    for(unsigned int i = 0; i < tags[dim].size(); i++){
-      s.Num = tags[dim][i];
-      List_Add(list, &s);
-    }
+    s.Type = (dim == 3) ? MSH_VOLUME : (dim == 2) ? MSH_SURF_PLAN :
+      (dim == 1) ? MSH_SEGM_LINE : MSH_POINT;
+    s.Num = tag;
+    List_Add(list, &s);
   }
 }
 
@@ -6470,7 +6534,8 @@ void setVisibility(int dim, int visible, bool recursive)
   }
 }
 
-void setVisibility(std::vector<int> tags[4], int visible, bool recursive)
+void setVisibility(const std::vector<std::pair<int, int> > &dimTags,
+                   int visible, bool recursive)
 {
   if(GModel::current()->getOCCInternals() &&
      GModel::current()->getOCCInternals()->getChanged())
@@ -6478,15 +6543,15 @@ void setVisibility(std::vector<int> tags[4], int visible, bool recursive)
   if(GModel::current()->getGEOInternals()->getChanged())
     GModel::current()->getGEOInternals()->synchronize(GModel::current());
 
-  for(int dim = 0; dim < 4; dim++){
-    for(unsigned int i = 0; i < tags[dim].size(); i++){
-      GEntity *ge = GModel::current()->getEntityByTag(dim, std::abs(tags[dim][i]));
-      if(ge) ge->setVisibility(visible, recursive);
-    }
+  for(unsigned int i = 0; i < dimTags.size(); i++){
+    GEntity *ge = GModel::current()->getEntityByTag
+      (dimTags[i].first, dimTags[i].second);
+    if(ge) ge->setVisibility(visible, recursive);
   }
 }
 
-void setColor(std::vector<int> tags[4], unsigned int val, bool recursive)
+void setColor(const std::vector<std::pair<int, int> > &dimTags,
+              unsigned int val, bool recursive)
 {
   if(GModel::current()->getOCCInternals() &&
      GModel::current()->getOCCInternals()->getChanged())
@@ -6494,11 +6559,10 @@ void setColor(std::vector<int> tags[4], unsigned int val, bool recursive)
   if(GModel::current()->getGEOInternals()->getChanged())
     GModel::current()->getGEOInternals()->synchronize(GModel::current());
 
-  for(int dim = 0; dim < 4; dim++){
-    for(unsigned int i = 0; i < tags[dim].size(); i++){
-      GEntity *ge = GModel::current()->getEntityByTag(dim, std::abs(tags[dim][i]));
-      if(ge) ge->setColor(val, recursive);
-    }
+  for(unsigned int i = 0; i < dimTags.size(); i++){
+    GEntity *ge = GModel::current()->getEntityByTag
+      (dimTags[i].first, dimTags[i].second);
+    if(ge) ge->setColor(val, recursive);
   }
 }
 
diff --git a/contrib/mobile/androidUtils.cpp b/contrib/mobile/androidUtils.cpp
index 62e4791d18fa0226571cf9b315d9afe665a3dd13..b9d0748a664e07336b8e31a887245057639a2835 100644
--- a/contrib/mobile/androidUtils.cpp
+++ b/contrib/mobile/androidUtils.cpp
@@ -113,7 +113,7 @@ void getBitmapFromString(const char *text, int textsize, unsigned char **map,
                                          "(Ljava/lang/String;I)I");
   *height = env->CallStaticIntMethod(jClass, mid, jtext, textsize);
   mid = env->GetStaticMethodID(jClass, "getWidthFromString", "(Ljava/lang/String;I)I");
-  *width =env->CallStaticIntMethod(jClass, mid, jtext, textsize);
+  *width = env->CallStaticIntMethod(jClass, mid, jtext, textsize);
   if(realWidth != NULL){
     mid = env->GetStaticMethodID(jClass, "getRealWidthFromString", "(Ljava/lang/String;I)I");
     *realWidth = env->CallStaticIntMethod(jClass, mid, jtext, textsize);
diff --git a/contrib/mobile/utils/android_build.sh b/contrib/mobile/utils/android_build.sh
index ba51702be984eb67c8478c74d6d198258fc967fa..755df82db1af44e4359ff250fec63a205f276f20 100755
--- a/contrib/mobile/utils/android_build.sh
+++ b/contrib/mobile/utils/android_build.sh
@@ -125,3 +125,6 @@ check
 
 # to see stack traces after crashes:
 # ~/Library/Android/sdk/platform-tools/adb logcat | ~/Library/Android/ndk-bundle/ndk-stack -sym build_android_Onelab/
+
+# to run the emulator (this one uses a real ARM image - slower but allows to test the actual build!)
+# ~/Library/Android/sdk/tools/emulator -netdelay none -netspeed full -avd Nexus_6P_API_25
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index a2f6ecbd836e2269792a61ef4b85d6b1fbf505f8..72482311b7328a24515e8a15ce26cc537ae2eac8 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -2369,13 +2369,22 @@ the X, Y and Z components of the translation vector.
 
 @item Boundary @{ @var{transform-list} @}
 (Not a transformation per-se.) Returns the boundary of the elementary
-entities in @var{transform-list}.
+entities in @var{transform-list}. 
 
 @item CombinedBoundary @{ @var{transform-list} @}
 (Not a transformation per-se.) Returns the boundary of the elementary
 entities, combined as if a single entity, in
 @var{transform-list}. Useful to compute the boundary of a complex part.
 
+@item OrientedBoundary @{ @var{transform-list} @}
+(Not a transformation per-se.) Returns the boundary of the elementary
+entities in @var{transform-list}, with signs indicating their orientation.
+
+@item CombinedOrientedBoundary @{ @var{transform-list} @}
+(Not a transformation per-se.) Returns the (oriented) boundary of the
+elementary entities, combined as if a single entity, in
+@var{transform-list}. Useful to compute the boundary of a complex part.
+
 @c @item Intersect Line @{ @var{expression-list} @} Surface @{ @var{expression} @}
 @c (Not a transformation per-se.) Returns the intersections of the lines
 @c given in @var{expression-list} with the specified surface.