diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt
index 6c6d16f45df13f6a6eef51b2a21e45da719090f5..a4c44720bbaecbf0116185a245247c7ee0e8bb8d 100644
--- a/Geo/CMakeLists.txt
+++ b/Geo/CMakeLists.txt
@@ -19,7 +19,8 @@ set(SRC
     GModelFactory.cpp
     GModelIO_Geo.cpp
     GModelIO_Mesh.cpp
-    GModelIO_OCC.cpp
+    GModelIO_OCC.cpp 
+      OCC_Connect.cpp
     GModelIO_ACIS.cpp
     GModelIO_Fourier.cpp
     GModelIO_CGNS.cpp
diff --git a/Geo/OCC_Connect.cpp b/Geo/OCC_Connect.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c34686ef84756558bd10e1456a9a09252a4001b3
--- /dev/null
+++ b/Geo/OCC_Connect.cpp
@@ -0,0 +1,1069 @@
+// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+//
+// Contributed by Mark van Doesburg, Technolution B.V.
+
+#include "OCC_Connect.h"
+
+#include <vector>
+#include <list>
+#include <deque>
+#include <iostream>
+#include <iterator>
+
+#if defined(HAVE_OCC)
+
+#include <Standard_Version.hxx>
+
+#include <TopoDS.hxx>
+#include <TopoDS_Vertex.hxx>
+#include <TopoDS_Solid.hxx>
+#include <TopoDS_Compound.hxx>
+
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopOpeBRep_Point2d.hxx>
+#include <TopOpeBRep_ShapeIntersector.hxx>
+#include <TopTools.hxx>
+
+#include <BRepTools.hxx>
+#include <BRepTools_ReShape.hxx>
+#include <BRepTools_WireExplorer.hxx>
+#include <BRepBuilderAPI_MakeVertex.hxx>
+#include <BRepBuilderAPI_MakeWire.hxx>
+#include <BRepExtrema_ExtCC.hxx>
+#include <BRepExtrema_ExtCF.hxx>
+#include <BRepExtrema_ExtFF.hxx>
+#include <BRepExtrema_ExtPF.hxx>
+#include <BRepExtrema_ExtPC.hxx>
+#include <BRep_Tool.hxx>
+#include <BRepClass_FaceClassifier.hxx>
+
+#include <IntTools_Context.hxx>
+
+#include <BRepExtrema_DistShapeShape.hxx>
+#include <BRepOffsetAPI_NormalProjection.hxx>
+#include <BRepTopAdaptor_FClass2d.hxx>
+#include <BRepTools_Substitution.hxx>
+#include <BRepAlgo_Loop.hxx>
+
+#include <BRep_TEdge.hxx>
+#include <TopoDS_TShape.hxx>
+#include <ShapeFix_Edge.hxx>
+#include <Geom_Surface.hxx>
+#include <gce_MakeScale.hxx>
+#include <BRepBuilderAPI_GTransform.hxx>
+#include <BRepBuilderAPI_Transform.hxx>
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Printing routines
+////////////////////////////////////////////////////////////////////////////////
+
+static inline ostream &operator <<(ostream &o,const TopAbs_ShapeEnum &A)
+{
+    switch(A) {
+    case TopAbs_COMPOUND: return o << "COMPOUND";
+    case TopAbs_COMPSOLID: return o << "COMPSOLID";
+    case TopAbs_SOLID: return o << "SOLID";
+    case TopAbs_SHELL: return o << "SHELL";
+    case TopAbs_FACE: return o << "FACE";
+    case TopAbs_WIRE: return o << "WIRE";
+    case TopAbs_EDGE: return o << "EDGE";
+    case TopAbs_VERTEX: return o << "VERTEX";
+    case TopAbs_SHAPE: return o << "SHAPE";
+    default: return o << "Unknown";
+    }
+}
+
+static inline ostream &operator <<(ostream &o,const TopAbs_State &A)
+{
+    switch(A) {
+    case TopAbs_IN: return o << "IN";
+    case TopAbs_OUT: return o << "OUT";
+    case TopAbs_ON: return o << "ON";
+    case TopAbs_UNKNOWN: return o << "UNKNOWN";
+    default: return o << "Unknown";
+    }
+}
+
+static inline ostream &operator <<(ostream &o,const gp_Pnt &p)
+{
+  return o << "(" << p.Coord(1) << "," << p.Coord(2) << "," << p.Coord(3) << ")";
+}
+
+static inline ostream &operator <<(ostream &o,const TopOpeBRep_P2Dstatus &A)
+{
+    switch(A) {
+    case TopOpeBRep_P2DUNK: return o << "P2DUNK";
+    case TopOpeBRep_P2DINT: return o << "P2DINT";
+    case TopOpeBRep_P2DSGF: return o << "P2DSGF";
+    case TopOpeBRep_P2DSGL: return o << "P2DSGL ";
+    case TopOpeBRep_P2DNEW: return o << "P2DNEW ";
+    default: return o << "Unknown";
+    }
+}
+
+template <typename T>
+static inline std::ostream &operator<<(std::ostream &out, std::set<T> const &a)
+{
+    std::copy(a.begin(),a.end(),std::ostream_iterator<T>(out," "));
+    return out;
+}
+
+bool OCC_Connect::LessThanIntegerSet::operator()(std::set<int> const &a,
+    std::set<int> const &b) const
+{
+    std::set<int>::const_iterator pa=a.begin(), pb=b.begin();
+    for(; pa!=a.end() && pb!=b.end(); pa++, pb++ ) {
+        if(*pa<*pb)
+            return 1;
+        if(*pb<*pa)
+            return 0;
+    }
+    if(pb!=b.end())
+        return 1;
+    return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// OCC_Connect
+////////////////////////////////////////////////////////////////////////////////
+
+int OCC_Connect::SaveBRep(char const *name)
+{
+    gp_Pnt center(0,0,0);
+    gce_MakeScale transform(center, 0.001);
+    BRepBuilderAPI_Transform scale(assembly.front(), transform.Value());
+    BRep_Builder BB;
+    TopoDS_Compound compound;
+    BB.MakeCompound(compound);
+    TopTools_ListOfShape p;
+    for(p=scale.Modified(assembly.front());
+        !p.IsEmpty();
+        p.RemoveFirst()
+    )
+        BB.Add(compound,p.First());
+    BRepTools::Write(compound, (char*)name);
+    return 1;
+}
+
+void OCC_Connect::Dump(ostream &out) const
+{
+    BRepTools::Dump(assembly.front(),out);
+}
+
+void OCC_Connect::Connect(void)
+{
+    while(assembly.size()>1) {
+        TopoDS_Compound result;
+        BRep_Builder BB;
+        BB.MakeCompound(result);
+        Intersect(BB,result,assembly.front(),assembly.back());
+        assembly.pop_front();
+        assembly.pop_back();
+        assembly.push_back(result);
+    }
+}
+
+void OCC_Connect::Collect(void)
+{
+    TopoDS_Compound result;
+    BRep_Builder BB;
+    BB.MakeCompound(result);
+    while(assembly.size()>0) {
+        if(verbose&Cutting)
+            cout << "Adding item\n";
+        BB.Add(result,assembly.front());
+        assembly.pop_front();
+    }
+    assembly.push_back(result);
+}
+
+void OCC_Connect::FaceCutters::Add(TopoDS_Edge const &edge)
+{
+    edges.push_back(edge);
+    rebuilt=0;
+}
+
+int OCC_Connect::FaceCutters::FindConnectedEdge(int v,
+    std::vector<int> &done,
+    std::vector<std::vector<int> > &v_edge
+)  {
+    int re_used=-1;
+    for(std::vector<int>::iterator p=v_edge[v].begin();p!=v_edge[v].end(); p++){
+        if(done[*p]) {
+            re_used=*p;
+            continue;
+        }
+        return *p;       // Found an unused edge
+    }
+    return re_used;
+}
+
+void dump(std::vector<std::pair<int,int> > const &e2v, std::ostream &out,
+    const char *name="name")
+{
+    out << "graph " << name << " {\n";
+    for(unsigned int e = 0; e < e2v.size(); e++) {
+      out << "    " << e2v[e].first << " -- " << e2v[e].second << "[label=" << e+1 << "]\n";
+    }
+    out << "}\n";
+}
+
+void FinishEdge(int edge,
+    std::vector<std::set<int> > &v2e,
+    std::vector<std::pair<int,int> > &e2v)
+{
+    int verbose=0;
+    if(verbose)
+      std::cout << "Finishing edge " << edge << "\n";
+
+    int fv=e2v[edge].first;
+    v2e[fv].erase(edge);
+    while(v2e[fv].size()>1) {
+        std::set<int>::iterator e=v2e[fv].begin();
+        int nv=v2e.size();
+        v2e.push_back(std::set<int>());
+        v2e[nv].insert(*e);
+        if(e2v[*e].first==fv)
+            e2v[*e].first=nv;
+        else
+            e2v[*e].second=nv;
+        if(verbose)
+          std::cout << "Created vertex " << nv << "(" << fv << "), edge[" << *e
+                    << "]=" << e2v[*e].first << " " << e2v[*e].second << "\n";
+        v2e[fv].erase(*e);
+    }
+
+    int sv=e2v[edge].second;
+    v2e[sv].erase(edge);
+    while(v2e[sv].size()>1) {
+        std::set<int>::iterator e=v2e[sv].begin();
+        int nv=v2e.size();
+        v2e.push_back(std::set<int>());
+        v2e[nv].insert(*e);
+        if(e2v[*e].first==sv)
+            e2v[*e].first=nv;
+        else
+            e2v[*e].second=nv;
+        if(verbose)
+          std::cout << "Created vertex " << nv << "(" << sv << "), edge[" << *e <<
+            "]=" << e2v[*e].first << " " << e2v[*e].second << "\n";
+        v2e[sv].erase(*e);
+    }
+}
+
+void OCC_Connect::FaceCutters::Build(TopoDS_Face const &face,
+    TopoDS_Shape &result, int verbose)
+{
+    clear();
+
+    /* First we create some data structures to access the topology */
+    TopTools_IndexedMapOfShape vertices;
+    std::vector<std::pair<int,int> > e2v;
+    for(unsigned int i = 0; i < edges.size(); i++) {
+        TopExp::MapShapes(edges[i],TopAbs_VERTEX,vertices);
+        TopoDS_Vertex v1, v2;
+        TopExp::Vertices(edges[i],v1,v2);
+        std::pair<int,int> t(vertices.FindIndex(v1),vertices.FindIndex(v2));
+        e2v.push_back(t);
+    }
+
+    std::vector<std::set<int> > v2e;
+    for(unsigned int e = 0; e < e2v.size(); e++) {
+      if(e2v[e].first >= (int)v2e.size())
+            v2e.resize(e2v[e].first+1);
+        v2e[e2v[e].first].insert(e);
+        if(e2v[e].second >= (int)v2e.size())
+            v2e.resize(e2v[e].second+1);
+        v2e[e2v[e].second].insert(e);
+    }
+
+    std::set<int> open, odd;
+    for(unsigned int i = 0; i < v2e.size(); i++) {
+        if(v2e[i].size()==0)
+            continue;
+        else if(v2e[i].size()==1)
+            open.insert(i);
+        else if(v2e[i].size()&1)
+            odd.insert(i);
+    }
+
+    if(open.size()&1)
+        std::cerr << "Inconsistent open loops\n";
+    if(odd.size()&1)
+        std::cerr << "Inconsistent odd loops\n";
+
+    for(;;) {
+        int open_mode = -1;
+        std::set<int> current_vertices;
+        for(unsigned int start = 0; start < v2e.size(); start++) {
+            if(v2e[start].size()==1) {
+                if(verbose&Cutting)
+                  std::cout << "start open at " << start << "\n";
+                current_vertices.insert(start);
+                open_mode=1;
+                break;
+            }
+        }
+        if(!current_vertices.size()) {
+            for(unsigned int start = 0; start < v2e.size(); start++) {
+                if(v2e[start].size()) {
+                    if(verbose&Cutting)
+                      std::cout << "start closed at " << start << "\n";
+                    current_vertices.insert(start);
+                    open_mode=0;
+                    break;
+                }
+            }
+        }
+        if(!current_vertices.size())
+            break;
+
+        std::map<int,std::deque<int> > wires;
+        std::set<int> processed_edges;
+        do {
+            std::set<int> next_vertices;
+            for(std::set<int>::iterator v=current_vertices.begin();
+                v!=current_vertices.end();
+                v++
+            ) {
+                for(std::set<int>::iterator e=v2e[*v].begin() ;
+                    e!=v2e[*v].end();
+                    e++
+                ) {
+                    if(processed_edges.count(*e))
+                        continue;
+
+                    int other=e2v[*e].first==*v?
+                        e2v[*e].second:e2v[*e].first;
+
+                    if(open_mode) {
+                        if(v2e[other].size()==1) {
+                            // Other is open end too, finish wire.
+                            wires[*v].push_back(*e);
+                            std::deque<int>::const_iterator p;
+                            BRepBuilderAPI_MakeWire wire;
+                            if(verbose&Cutting)
+                                std::cout << "CUT Open wire:";
+                            for(p=wires[*v].begin();
+                                p!=wires[*v].end();
+                                p++
+                            ) {
+                                FinishEdge(*p, v2e, e2v);
+                                wire.Add(edges[*p]);
+                                if(verbose&Cutting)
+                                    std::cout << ' ' << (*p)+1;
+                            }
+                            if(verbose&Cutting)
+                                std::cout << "\n";
+                            push_back(wire);
+                            goto next_vertex;
+                        }
+                    } else {
+                        if( current_vertices.count(other) ||
+                            next_vertices.count(other)
+                        ) {
+                            if(verbose&Cutting)
+                                std::cout << "CUT Closed wire:";
+                            wires[*v].push_back(*e);
+                            while(wires[other].front()
+                                ==wires[*v].front()
+                            ) {
+                                wires[other].pop_front();
+                                wires[*v].pop_front();
+                            }
+
+                            BRepBuilderAPI_MakeWire wire;
+                            std::deque<int>::const_iterator p;
+                            for(p=wires[other].begin();
+                                p!=wires[other].end();
+                                p++
+                            ) {
+                                FinishEdge(*p, v2e, e2v);
+                                wire.Add(edges[*p]);
+                                if(verbose&Cutting)
+                                    std::cout << ' ' << (*p)+1;
+                            }
+                            std::deque<int>::reverse_iterator rp;
+                            for(rp=wires[*v].rbegin();
+                                rp!=wires[*v].rend();
+                                rp++
+                            ) {
+                                FinishEdge(*rp, v2e, e2v);
+                                wire.Add(edges[*rp]);
+                                if(verbose&Cutting)
+                                    std::cout << ' ' << (*rp)+1;
+                            }
+                            if(verbose&Cutting)
+                                std::cout << "\n";
+                            push_back(wire);
+                            goto next_vertex;
+                        }
+                    }
+                    if(current_vertices.count(other)==0) {
+                        wires[other]=wires[*v];
+                        wires[other].push_back(*e);
+                        processed_edges.insert(*e);
+                        next_vertices.insert(other);
+                    }
+                }
+            }
+            current_vertices=next_vertices;
+        } while(current_vertices.size());
+        next_vertex: ;
+    }
+
+    if(size()>1 && verbose&CuttingIntermediate) {
+        if(verbose&Cutting)
+            std::cout << "Saving multiple cuts\n";
+        BRep_Builder BB;
+        TopoDS_Compound compound;
+        BB.MakeCompound(compound);
+        for(unsigned int i = 0; i < edges.size(); i++)
+            BB.Add(compound,edges[i]);
+        BRepTools::Write(compound,"cutter.brep");
+        ofstream out("cutter.dot",ios::trunc|ios::out);
+        dump(e2v,out);
+    }
+}
+
+inline OCC_Connect::cutmap_t OCC_Connect::SelectCuttingEdges(
+    TopTools_IndexedMapOfShape &edges,
+    TopTools_IndexedMapOfShape &faces)
+{
+    cutmap_t cutters;
+    for(int face=1;face<=faces.Extent();face++) {
+        for(int edge=1;edge<=edges.Extent();edge++) {
+            TopoDS_Edge c_edge=TopoDS::Edge(edges(edge));
+            TopoDS_Face c_face=TopoDS::Face(faces(face));
+
+            if(BRep_Tool::Degenerated(c_edge)) {
+                if(verbose&CuttingReject)
+                    cout << "Rejected(" << __LINE__ << ") edge " << edge
+                        << " in face " << face << endl;
+                continue;
+            }
+
+            TopTools_IndexedMapOfShape already_there;
+            TopExp::MapShapes(c_face,TopAbs_EDGE,already_there);
+            if(already_there.Contains(c_edge)) {
+                if(verbose&CuttingReject)
+                    cout << "Rejected(" << __LINE__ << ") edge " << edge
+                        << " in face " << face << endl;
+                continue;
+            }
+
+            BRepExtrema_DistShapeShape dist(c_edge,c_face);
+            double tol=BRep_Tool::Tolerance(c_face);
+            if(dist.Value()>tol) {
+                if(verbose&CuttingReject)
+                    cout << "Rejected(" << __LINE__ << ") edge " << edge
+                        << " in face " << face << endl;
+                continue;
+            }
+
+            Standard_Real s, e;
+            Handle(Geom_Curve) c3d=BRep_Tool::Curve(c_edge,s,e);
+            if(c3d.IsNull()) {
+                if(verbose&CuttingReject)
+                    cout << "Rejected(" << __LINE__ << ") edge " << edge
+                        << " in face " << face << endl;
+                continue;
+            }
+
+            // FIXME, checking only the middle may be a bit optimistic.
+            TopoDS_Vertex vm=BRepBuilderAPI_MakeVertex(c3d->Value((s+e)/2));
+            BRepExtrema_DistShapeShape dist_mf(vm,c_face);
+            if(dist_mf.Value()>tol) {
+                if(verbose&CuttingReject)
+                    cout << "Rejected(" << __LINE__ << ") edge " << edge
+                        << " in face " << face << endl;
+                continue;
+            }
+
+            if(verbose&Cutting)
+                cout << "Accepted edge " << edge << " in face " << face << endl;
+
+            // Add missing PCurve if necessary
+            Handle_Geom2d_Curve c=BRep_Tool::CurveOnSurface(c_edge,c_face,s,e);
+            if(c.IsNull()) {
+                if(verbose&Cutting)
+                    cout << "Adding missing PCurve\n";
+                ShapeFix_Edge().FixAddPCurve(c_edge,c_face,false,1e-7);
+            }
+            cutters[face].Add(c_edge);
+        }
+    }
+    return cutters;
+}
+
+void OCC_Connect::Intersect(BRep_Builder &BB, TopoDS_Shape &target,
+    TopoDS_Shape &shape, TopoDS_Shape &tool)
+{
+    /***************************************************************************
+        We start by splitting edges at all the edge-edge intersections.
+        This may generate new vertices and edges.
+    ***************************************************************************/
+    MergeVertices(shape,tool);
+    LocOpe_SplitShape splitter1(shape);
+    LocOpe_SplitShape splitter2(tool);
+    TopOpeBRep_ShapeIntersector intersector;
+    for(intersector.InitIntersection(shape,tool);
+        intersector.MoreIntersection();
+        intersector.NextIntersection()
+    ) {
+        if(verbose&Cutting) {
+            cout << "++++++++++++++++++++++++++++++++++++++++"
+                "++++++++++++++++++++++++++++++++++++++++\n";
+            intersector.DumpCurrent(1); cout << " --> ";
+            intersector.DumpCurrent(2); cout << '\n';
+        }
+
+        TopOpeBRep_EdgesIntersector &ee=intersector.ChangeEdgesIntersector();
+        if( intersector.CurrentGeomShape(1).ShapeType()==TopAbs_EDGE &&
+            intersector.CurrentGeomShape(2).ShapeType()==TopAbs_EDGE
+        ) {
+            for(ee.InitPoint(); ee.MorePoint(); ee.NextPoint()) {
+                TopOpeBRep_Point2d const &p=ee.Point();
+                if(verbose&Cutting)
+                    cout << "point loop " << p.Parameter(1) << '\n';
+                TopoDS_Vertex vertex;
+                if(p.IsVertex(1))
+                    vertex=p.Vertex(1);
+                else if(p.IsVertex(2))
+                    vertex=p.Vertex(2);
+                else
+                    vertex=BRepBuilderAPI_MakeVertex(p.Value());
+                if(!p.IsVertex(1)) {
+                    TopoDS_Edge edge=TopoDS::Edge(ee.Edge(1));
+                    if(!splitter1.CanSplit(edge)) {
+                        if(verbose&Cutting)
+                            cout << "Cannot split 1\n";;
+                    } else {
+                        if(verbose&Cutting)
+                            cout << "splitting model 1\n";
+                        try { splitter1.Add(vertex,p.Parameter(1),edge); }
+                        catch(Standard_ConstructionError c) {
+                            if(verbose&Cutting)
+                                cout << "Ooops \n";
+                        }
+                    }
+                }
+                if(!p.IsVertex(2)) {
+                    TopoDS_Edge edge=TopoDS::Edge(ee.Edge(2));
+                    if(!splitter2.CanSplit(edge)) {
+                        if(verbose&Cutting)
+                            cout << "Cannot split 2\n";;
+                    } else {
+                        if(verbose&Cutting)
+                            cout << "splitting model 2\n";
+                        try { splitter2.Add(vertex,p.Parameter(2),edge); }
+                        catch(Standard_ConstructionError c) {
+                            if(verbose&Cutting)
+                                cout << "Ooops \n";
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /***************************************************************************
+        Not all intersections seem to be caught, this is an attempt to catch
+        some missing intersections. FIXME, this is almost certainly incomplete.
+    ***************************************************************************/
+    TopTools_IndexedMapOfShape edges, faces, vertices;
+    vertices.Clear();
+    TopExp::MapShapes(shape,TopAbs_VERTEX,vertices);
+    TopExp::MapShapes(tool,TopAbs_VERTEX,vertices);
+
+    edges.Clear();
+    TopExp::MapShapes(shape,TopAbs_EDGE,edges);
+    for(int e=1; e<=edges.Extent(); e++) {
+        TopoDS_Edge edge=TopoDS::Edge(edges(e));
+        TopoDS_Vertex o1, o2;
+        TopExp::Vertices(edge,o1,o2);
+        int skip1=vertices.FindIndex(o1);
+        int skip2=vertices.FindIndex(o2);
+        for(int v=1; v<=vertices.Extent(); v++) {
+            if(v==skip1 || v==skip2)
+                continue;
+            TopoDS_Vertex vertex=TopoDS::Vertex(vertices(v));
+            BRepExtrema_ExtPC distance(vertex,edge);
+            if(!distance.IsDone())
+                continue;
+            double tolerance=std::max(BRep_Tool::Tolerance(edge),
+                                      BRep_Tool::Tolerance(vertex));
+            for(int i=1;i<=distance.NbExt();i++) {
+#if (OCC_VERSION_MAJOR == 6) && (OCC_VERSION_MINOR < 5)
+              double value = distance.Value(i);
+#else
+              double value = distance.SquareDistance(i);
+#endif
+              if(value<tolerance) {
+                    try {
+                        // No idea why this can fail
+                        splitter1.Add(vertex,distance.Parameter(i),edge);
+                    }
+                    catch(Standard_ConstructionError c) {
+                        if(verbose&Cutting) {
+                            cout << "Adding vertex to edge failed\n";
+                            TopoDS_Vertex v1, v2;
+                            TopExp::Vertices(edge,v1,v2);
+                            if(BRepTools::Compare(v1,vertex))
+                                cout << "Merge v1\n";
+                            if(BRepTools::Compare(v2,vertex))
+                                cout << "Merge v2\n";
+                            double d1=BRep_Tool::Pnt(v1).Distance(
+                                BRep_Tool::Pnt(vertex));
+                            double d2=BRep_Tool::Pnt(v2).Distance(
+                                BRep_Tool::Pnt(vertex));
+                            cout << "Adding " << i << " to edge " << e
+                                << " distance=" << value
+                                << " parameter=" << distance.Parameter(i)
+                                << " point=" << distance.Point(i)
+                                << " dv1=" << d1
+                                << " dv2=" << d2
+                                << endl;
+                            BRepTools::Dump(vertex,cout);
+                            BRepTools::Dump(edge,cout);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    edges.Clear();
+    TopExp::MapShapes(tool,TopAbs_EDGE,edges);
+    for(int e=1; e<=edges.Extent(); e++) {
+        TopoDS_Edge edge=TopoDS::Edge(edges(e));
+        TopoDS_Vertex o1, o2;
+        TopExp::Vertices(edge,o1,o2);
+        int skip1=vertices.FindIndex(o1);
+        int skip2=vertices.FindIndex(o2);
+        for(int v=1; v<=vertices.Extent(); v++) {
+            if(v==skip1 || v==skip2)
+                continue;
+            TopoDS_Vertex vertex=TopoDS::Vertex(vertices(v));
+            BRepExtrema_ExtPC distance(vertex,edge);
+            if(!distance.IsDone())
+                continue;
+            double tolerance=std::max(BRep_Tool::Tolerance(edge),
+                                      BRep_Tool::Tolerance(vertex));
+            for(int i=1;i<=distance.NbExt();i++) {
+#if (OCC_VERSION_MAJOR == 6) && (OCC_VERSION_MINOR < 5)
+              double value = distance.Value(i);
+#else
+              double value = distance.SquareDistance(i);
+#endif
+              if(value<tolerance) {
+                    try {
+                        splitter2.Add(vertex,distance.Parameter(i),edge);
+                    }
+                    catch(Standard_ConstructionError c) {
+                        if(verbose&Cutting) {
+                            cout << "Adding vertex to edge failed\n";
+                            TopoDS_Vertex v1, v2;
+                            TopExp::Vertices(edge,v1,v2);
+                            if(BRepTools::Compare(v1,vertex))
+                                cout << "Merge v1\n";
+                            if(BRepTools::Compare(v2,vertex))
+                                cout << "Merge v2\n";
+                            double d1=BRep_Tool::Pnt(v1).Distance(
+                                BRep_Tool::Pnt(vertex));
+                            double d2=BRep_Tool::Pnt(v2).Distance(
+                                BRep_Tool::Pnt(vertex));
+                            cout << "Adding " << i << " to edge " << e
+                                << " distance=" << value
+                                << " parameter=" << distance.Parameter(i)
+                                << " point=" << distance.Point(i)
+                                << " dv1=" << d1
+                                << " dv2=" << d2
+                                << endl;
+                            BRepTools::Dump(vertex,cout);
+                            BRepTools::Dump(edge,cout);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /***************************************************************************
+        We need the shapes with all the edge-edge intersections to split
+        all the faces. All vertices and edges which can be merged, will
+        be merged.
+    ***************************************************************************/
+    TopoDS_Compound intermediate1;
+    BB.MakeCompound(intermediate1);
+    for(TopTools_ListIteratorOfListOfShape p(splitter1.DescendantShapes(shape));
+        p.More();
+        p.Next()
+    ) {
+        BB.Add(intermediate1,p.Value());
+    }
+    TopoDS_Compound intermediate2;
+    BB.MakeCompound(intermediate2);
+    for(TopTools_ListIteratorOfListOfShape p(splitter2.DescendantShapes(tool));
+        p.More();
+        p.Next()
+    ) {
+        BB.Add(intermediate2,p.Value());
+    }
+    if(verbose&Cutting) {
+        cout << "Before merging vertices and edges\n";
+        TopoDS_Compound t;
+        BB.MakeCompound(t);
+        BB.Add(t,intermediate1);
+        BB.Add(t,intermediate2);
+        PrintItemCount(t);
+    }
+    MergeVertices(intermediate1,intermediate2);
+    MergeEdges(intermediate1,intermediate2);
+    if(verbose&Cutting) {
+        cout << "After merging vertices and edges\n";
+        TopoDS_Compound t;
+        BB.MakeCompound(t);
+        BB.Add(t,intermediate1);
+        BB.Add(t,intermediate2);
+        PrintItemCount(t);
+    }
+
+    // Create the result
+    TopoDS_Compound result;
+    BB.MakeCompound(result);
+    BB.Add(result,intermediate1);
+    BB.Add(result,intermediate2);
+
+    // Add any missing PCurves
+    for(TopExp_Explorer face(result,TopAbs_FACE); face.More(); face.Next()) {
+        for(TopExp_Explorer edge(face.Current(),TopAbs_EDGE);
+            edge.More();
+            edge.Next()
+        ) {
+            Standard_Real s, e;
+            TopoDS_Edge c_edge=TopoDS::Edge(edge.Current());
+            TopoDS_Face c_face=TopoDS::Face(face.Current());
+            Handle_Geom2d_Curve c=BRep_Tool::CurveOnSurface(c_edge,c_face,s,e);
+            if(c.IsNull()) {
+                if(verbose&Cutting)
+                    cout << "Adding missing PCurve\n";
+                ShapeFix_Edge().FixAddPCurve(c_edge,c_face,false,1e-7);
+            }
+        }
+    }
+
+    /***************************************************************************
+        We determine which edges/wires are going to cut a face. To do this
+        we create a map of FaceCutters which is indexed by the face number
+        in the faces map. The FaceCutters generate the correct cutting wires.
+    ***************************************************************************/
+    int retry;
+do {
+    if(verbose&Cutting)
+        std::cout << "STARTED CUTTING\n";
+    retry=0;
+    edges.Clear(); TopExp::MapShapes(result,TopAbs_EDGE,edges);
+    faces.Clear(); TopExp::MapShapes(result,TopAbs_FACE,faces);
+    cutmap_t cutters=SelectCuttingEdges(edges,faces);
+
+    /***************************************************************************
+        Apply all face splits stored in the map.
+    ***************************************************************************/
+    int cut_count=0;
+    LocOpe_SplitShape splitter(result);
+    for(cutmap_t::iterator f=cutters.begin(); f!=cutters.end(); f++) {
+        TopoDS_Face const &face=TopoDS::Face(faces(f->first));
+        FaceCutters &cutter=f->second;
+        cut_count+=cutter.size();
+        if(verbose&Cutting) {
+            cout << "Cutting face " << f->first << " *************************\n";
+            BRepTools::Dump(face,cout);
+        }
+        cutter.Build(face,result,verbose);
+        for(FaceCutters::iterator p=cutter.begin(); p!=cutter.end(); p++) {
+            TopTools_IndexedMapOfShape edges;
+            TopExp::MapShapes(*p,TopAbs_EDGE,edges);
+            if(edges.Extent()<3 && BRep_Tool::IsClosed(*p)) {
+                // FIXME This doesn't work.
+                cout << "IGNORED Closed wire with less than three edges\n";
+                continue;
+            }
+            //BRepTools::Dump(*p,cout);
+            try {
+                splitter.Add(*p,face);
+            }
+            catch(Standard_ConstructionError c) {
+                cout << "splitting the face failed\n";
+                retry=1;
+            }
+        }
+    }
+    if(verbose&Cutting)
+        cout << cut_count << " cuts in " << cutters.size() << " faces\n";
+
+    // Create the final shape with the cutted faces.
+    TopoDS_Compound cutted;
+    BB.MakeCompound(cutted);
+    int count=0;
+    for(TopTools_ListIteratorOfListOfShape p(splitter.DescendantShapes(result));
+        p.More();
+        p.Next()
+    ) {
+        if(++count==1) {
+            if(verbose&Cutting) {
+                cout << "--------- " << count << " ---------------------------\n";
+                BRepTools::Dump(p.Value(),cout);
+            }
+            BB.Add(cutted,p.Value());
+        }
+    }
+    MergeFaces(cutted);
+    result=cutted;
+} while(0 && retry);
+    target=result;
+}
+
+void OCC_Connect::MergeVertices(TopoDS_Shape &shape1,TopoDS_Shape &shape2) const
+{
+    TopTools_IndexedMapOfShape imap, omap;
+    TopExp::MapShapes(shape1,TopAbs_VERTEX,imap);
+    TopExp::MapShapes(shape2,TopAbs_VERTEX,imap);
+    BRepTools_ReShape replacer;
+    for(int i=0;i<imap.Extent();i++) {
+        for(int j=0;j<omap.Extent();j++) {
+            TopoDS_Vertex orig=TopoDS::Vertex(imap(i+1));
+            TopoDS_Vertex repl=TopoDS::Vertex(omap(j+1));
+            if(BRepTools::Compare(orig,repl)) {
+                repl.Orientation(orig.Orientation());
+                replacer.Replace(orig,repl);
+                // FIXME, tolerance and point should be updated
+                goto skip;
+            }
+        }
+        omap.Add(imap(i+1));
+    skip:;
+    }
+    TopoDS_Shape t=shape1;
+    shape1=replacer.Apply(t);
+    t=shape2;
+    shape2=replacer.Apply(t);
+}
+
+bool OCC_Connect::CanMergeCurve(TopoDS_Edge edge1,TopoDS_Edge edge2) const
+{
+    if(BRep_Tool::Degenerated(edge1) && BRep_Tool::Degenerated(edge2))
+        return 1;
+
+    double tol=1e-7;
+
+    Standard_Real s,e;
+    Handle(Geom_Curve) curve=BRep_Tool::Curve(edge1,s,e);
+    for(Standard_Real i=s;i<=e;i+=(e-s)/10) {
+        TopoDS_Vertex v=BRepBuilderAPI_MakeVertex(curve->Value(i));
+        double dist=BRepExtrema_DistShapeShape(edge2,v).Value();
+        if(dist>tol)
+            return 0;
+    }
+    return 1;
+}
+
+void OCC_Connect::MergeEdges(TopoDS_Shape &shape1, TopoDS_Shape &shape2) const
+{
+    TopTools_IndexedMapOfShape imap, omap;
+    TopExp::MapShapes(shape1,TopAbs_EDGE,imap);
+    TopExp::MapShapes(shape2,TopAbs_EDGE,imap);
+    BRepTools_ReShape replacer;
+    for(int i=0;i<imap.Extent();i++) {
+        for(int j=0;j<omap.Extent();j++) {
+            TopoDS_Edge orig=TopoDS::Edge(imap(i+1));
+            TopoDS_Edge repl=TopoDS::Edge(omap(j+1));
+
+            TopoDS_Vertex o1, o2, r1, r2;
+            TopExp::Vertices(orig,o1,o2,true);
+            TopExp::Vertices(repl,r1,r2,true);
+
+            if(o1.IsSame(o2)) {
+                if(!BRep_Tool::Degenerated(orig)) {
+                    if(verbose&Cutting) {
+                        cout << "Same vertex in edge\n";
+                        BRepTools::Dump(orig,cout);
+                    }
+                    replacer.Remove(orig);
+                    goto skip;
+                } else if(o1.IsSame(r1) && o1.IsSame(r2)
+                    && CanMergeCurve(orig,repl)
+                ) {
+                    if(verbose&Cutting) {
+                        cout << "Degenerated edge, replace " << i+1
+                            << " with " << j+1 << '\n';
+                        BRepTools::Dump(orig,cout);
+                        BRepTools::Dump(repl,cout);
+                    }
+                    // FIXME, update tolerance
+                    BRepTools::Dump(repl.Complemented(),cout);
+                    replacer.Replace(orig,repl.Complemented());
+                    goto skip;
+                }
+                cout << i+1 << " Degenerated\n";
+            }
+            if(o1.IsSame(r1) && o2.IsSame(r2) && CanMergeCurve(orig,repl))  {
+                if(verbose&Cutting) {
+                    cout << "Same order of vertices, replace " << i+1
+                        << " with " << j+1 << '\n';
+                    BRepTools::Dump(orig,cout);
+                    BRepTools::Dump(repl,cout);
+                }
+                // FIXME, update tolerance
+                replacer.Replace(orig,repl);
+                goto skip;
+            }
+            if(o1.IsSame(r2) && o2.IsSame(r1) && CanMergeCurve(orig,repl)) {
+                if(verbose&Cutting) {
+                    cout << "Reversed order of vertices, replace " << i+1
+                        << " with " << j+1 << '\n';
+                    BRepTools::Dump(orig,cout);
+                    BRepTools::Dump(repl,cout);
+                }
+                // FIXME, update tolerance
+                replacer.Replace(orig,repl.Complemented());
+                goto skip;
+            }
+        }
+        if(verbose&Cutting)
+            cout << "Adding " << i+1 << " as " << omap.Extent()+1<<" to keep map\n";
+        omap.Add(imap(i+1));
+    skip:;
+    }
+    TopoDS_Shape t=shape1;
+    shape1=replacer.Apply(t);
+    t=shape2;
+    shape2=replacer.Apply(t);
+}
+
+bool OCC_Connect::CanMergeFace(TopoDS_Face face1,TopoDS_Face face2) const
+{
+    // FIXME, this really does not work.
+    return 1;
+
+    //double tol=1e-7;
+
+    Handle(Geom_Surface) surface=BRep_Tool::Surface(face1);
+    Standard_Real u1, u2, v1, v2;
+    surface->Bounds(u1,u2,v1,v2);
+    cout << "u1=" << u1 << " u2=" << u2 << " v1=" << v1 << " v2=" << v2 << endl;
+    for(Standard_Real u=u1+(u2-u1)/10;u<u2;u+=(u2-u1)/10) {
+        for(Standard_Real v=v1+(v2-v1)/10;v<v2;v+=(v2-v1)/10) {
+            TopoDS_Vertex vtx=BRepBuilderAPI_MakeVertex(surface->Value(u,v));
+            BRepExtrema_DistShapeShape dss(face2,vtx);
+            dss.Perform();
+#if 0
+            double dist=dss.Value();
+            if(dist>tol) {
+                cout << "Distance=" << dist << " v=" << v << " u=" << u
+                    << " pnt=" << surface->Value(u,v) << endl;
+                BRepTools::Dump(face2,cout);
+                return 0;
+            }
+#else
+            dss.Dump(cout);
+#endif
+        }
+    }
+    return 1;
+}
+
+void OCC_Connect::MergeFaces(TopoDS_Shape &shape) const
+{
+    /***************************************************************************
+        We must find faces which are the same. Since all edges are already
+        merged, we know that faces which can be merged have identical edges.
+    ***************************************************************************/
+    TopTools_IndexedMapOfShape faces, edges;
+    TopExp::MapShapes(shape,TopAbs_FACE,faces);
+    TopExp::MapShapes(shape,TopAbs_EDGE,edges);
+    mapping_t mapping;
+    for(int i=0;i<faces.Extent();i++) {
+        std::set<int> face_edges;
+        for(TopExp_Explorer p(faces(i+1),TopAbs_EDGE); p.More(); p.Next()) {
+            int edge=edges.FindIndex(p.Current());
+            if(BRep_Tool::Degenerated(TopoDS::Edge(edges(edge)))) {
+                cout << "Degenerate edge " << edge << " inserted a 0\n";
+                face_edges.insert(0);
+            } else
+                face_edges.insert(edge);
+        }
+        mapping[face_edges].insert(i+1);
+    }
+
+    if(verbose&Cutting) {
+        for(mapping_t::iterator p=mapping.begin(); p!=mapping.end(); p++)
+            cout << "edges [ " << p->first << "] in face"
+                << (p->second.size()<2? " ":"s ") << "[ " << p->second << "]\n";
+    }
+
+    /***************************************************************************
+        If two faces have an identical set of edges, they can be merged
+        when the planes are never seperated by more than the tolerance.
+    ***************************************************************************/
+    BRepTools_ReShape replacer;
+    for(mapping_t::iterator p=mapping.begin(); p!=mapping.end(); p++) {
+        if(p->second.size()<2)
+            continue;
+        std::vector<int> uniq;
+        for(std::set<int>::iterator q=p->second.begin();
+            q!=p->second.end();
+            q++
+        ) {
+            for(std::vector<int>::iterator r=uniq.begin(); r!=uniq.end(); r++) {
+                TopoDS_Face orig=TopoDS::Face(faces(*q));
+                TopoDS_Face repl=TopoDS::Face(faces(*r));
+                if(verbose&Cutting)
+                    cout << "Check face " << *q << " and " << *r << endl;
+                if(CanMergeFace(orig,repl)) {
+                    if(verbose&Cutting) {
+                        cout << "replace face " << *q << " with " << *r << '\n';
+                    }
+                    repl.Orientation(orig.Orientation());
+                    replacer.Replace(orig,repl);
+                    // FIXME, tolerance should be updated
+                    goto skip;
+                }
+            }
+            uniq.push_back(*q);
+        skip:;
+        }
+    }
+
+    TopoDS_Shape t=shape;
+    shape=replacer.Apply(t);
+}
+
+void OCC_Connect::PrintItemCount(TopoDS_Shape const &shape) const
+{
+    TopTools_IndexedMapOfShape imap;
+    TopExp::MapShapes(shape,TopAbs_VERTEX,imap);
+    cout << "Input map contains " << imap.Extent() << " vertices\n";
+    imap.Clear();
+    TopExp::MapShapes(shape,TopAbs_EDGE,imap);
+    cout << "Input map contains " << imap.Extent() << " edges\n";
+    imap.Clear();
+    TopExp::MapShapes(shape,TopAbs_FACE,imap);
+    cout << "Input map contains " << imap.Extent() << " faces\n";
+    imap.Clear();
+    TopExp::MapShapes(shape,TopAbs_SOLID,imap);
+    cout << "Input map contains " << imap.Extent() << " solids\n";
+    imap.Clear();
+    TopExp::MapShapes(shape,TopAbs_COMPSOLID,imap);
+    cout << "Input map contains " << imap.Extent() << " compsolids\n";
+    imap.Clear();
+    TopExp::MapShapes(shape,TopAbs_COMPOUND,imap);
+    cout << "Input map contains " << imap.Extent() << " compounds\n";
+}
+
+#endif
diff --git a/Geo/OCC_Connect.h b/Geo/OCC_Connect.h
new file mode 100644
index 0000000000000000000000000000000000000000..1843f20e328d1807281b0b105f17904998bcc85e
--- /dev/null
+++ b/Geo/OCC_Connect.h
@@ -0,0 +1,87 @@
+// Gmsh - Copyright (C) 1997-2011 C. Geuzaine, J.-F. Remacle
+//
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+//
+// Contributed by Mark van Doesburg, Technolution B.V.
+
+#ifndef _OCC_CONNECT_H_
+#define _OCC_CONNECT_H_
+
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include <deque>
+#include <map>
+#include <vector>
+#include <set>
+
+#include "GmshConfig.h"
+
+#if defined(HAVE_OCC)
+
+#if !defined(HAVE_NO_OCC_CONFIG_H)
+#include <config.h>
+#endif
+
+#include <TopoDS_Shape.hxx>
+#include <TopoDS_Edge.hxx>
+#include <TopoDS_Wire.hxx>
+#include <TopoDS_Face.hxx>
+#include <TopTools_IndexedMapOfShape.hxx>
+
+#include <BRep_Builder.hxx>
+#include <LocOpe_SplitShape.hxx>
+
+////////////////////////////////////////////////////////////////////////////////
+//
+////////////////////////////////////////////////////////////////////////////////
+class OCC_Connect {
+    struct LessThanIntegerSet {
+        bool operator()(std::set<int> const &a, std::set<int> const &b) const;
+    };
+    typedef std::map<std::set<int>,std::set<int>,LessThanIntegerSet> mapping_t;
+
+    class FaceCutters:public std::vector<TopoDS_Wire> {
+        std::vector<TopoDS_Edge> edges;
+        int rebuilt;
+    public:
+        FaceCutters(void) { rebuilt=0; }
+        void Build(TopoDS_Face const &,TopoDS_Shape&,int);
+        void Add(TopoDS_Edge const&);
+    private:
+        int FindConnectedEdge(int v, std::vector<int> &done,
+            std::vector<std::vector<int> > &v_edge);
+    };
+    typedef std::map<int,FaceCutters> cutmap_t;
+
+    std::deque<TopoDS_Shape> assembly;
+protected:
+    int verbose;
+
+public:
+    enum Verbose { Cutting=1, CuttingReject=4, CuttingIntermediate=8 };
+    OCC_Connect(int v=0) { verbose=v; }
+    int SaveBRep(char const *);
+    void Connect(void);
+    void Collect(void);
+    void Add(TopoDS_Shape const &a) { assembly.push_back(a); }
+    void Dump(std::ostream &) const;
+    operator TopoDS_Shape(void) { return assembly.front(); }
+private:
+    void MergeVertices(TopoDS_Shape&,TopoDS_Shape&) const;
+    void MergeEdges(TopoDS_Shape&,TopoDS_Shape&) const;
+    void MergeFaces(TopoDS_Shape&) const;
+    void PerformBoolean(union tree*);
+    void Intersect(BRep_Builder &BB, TopoDS_Shape &target,
+        TopoDS_Shape &shape, TopoDS_Shape &tool);
+    bool CanMergeCurve(TopoDS_Edge edge1,TopoDS_Edge edge2) const;
+    bool CanMergeFace(TopoDS_Face face1,TopoDS_Face face2) const;
+    void PrintItemCount(TopoDS_Shape const &shape) const;
+    cutmap_t SelectCuttingEdges(TopTools_IndexedMapOfShape &edges,
+        TopTools_IndexedMapOfShape &faces);
+};
+
+#endif
+
+#endif