TopoDS_Shape BlockFix_UnionEdges::Perform(const TopoDS_Shape& Shape, const Standard_Real Tol) { myContext = new ShapeBuild_ReShape; myTolerance = Tol; TopoDS_Shape aResult = myContext->Apply(Shape); // processing each solid TopAbs_ShapeEnum aType = TopAbs_SOLID; TopExp_Explorer exps (Shape, aType); if (!exps.More()) { aType = TopAbs_SHELL; exps.Init(Shape, aType); } for (; exps.More(); exps.Next()) { //TopoDS_Solid aSolid = TopoDS::Solid(exps.Current()); TopoDS_Shape aSolid = exps.Current(); TopTools_IndexedMapOfShape ChangedFaces; // creating map of edge faces TopTools_IndexedDataMapOfShapeListOfShape aMapEdgeFaces; TopExp::MapShapesAndAncestors(aSolid, TopAbs_EDGE, TopAbs_FACE, aMapEdgeFaces); Handle(ShapeBuild_ReShape) aContext = new ShapeBuild_ReShape; TopoDS_Shape aRes = aSolid; aRes = aContext->Apply(aSolid); // processing each face TopExp_Explorer exp; for (exp.Init(aRes, TopAbs_FACE); exp.More(); exp.Next()) { TopoDS_Face aFace = TopoDS::Face(aContext->Apply(exp.Current().Oriented(TopAbs_FORWARD))); TopTools_IndexedDataMapOfShapeListOfShape aMapFacesEdges; for (TopExp_Explorer expe(aFace,TopAbs_EDGE); expe.More(); expe.Next()) { TopoDS_Edge edge = TopoDS::Edge(expe.Current()); if (!aMapEdgeFaces.Contains(edge)) continue; const TopTools_ListOfShape& aList = aMapEdgeFaces.FindFromKey(edge); TopTools_ListIteratorOfListOfShape anIter(aList); for ( ; anIter.More(); anIter.Next()) { TopoDS_Face face = TopoDS::Face(anIter.Value()); TopoDS_Face face1 = TopoDS::Face(aContext->Apply(anIter.Value())); if (face1.IsSame(aFace)) continue; if (aMapFacesEdges.Contains(face)) { aMapFacesEdges.ChangeFromKey(face).Append(edge); } else { TopTools_ListOfShape ListEdges; ListEdges.Append(edge); aMapFacesEdges.Add(face,ListEdges); } } } for (Standard_Integer i=1; i<=aMapFacesEdges.Extent(); i++) { const TopTools_ListOfShape& ListEdges = aMapFacesEdges.FindFromIndex(i); TopTools_SequenceOfShape SeqEdges; TopTools_ListIteratorOfListOfShape anIter(ListEdges); for ( ; anIter.More(); anIter.Next()) { SeqEdges.Append(anIter.Value()); } if (SeqEdges.Length()==1) continue; TopoDS_Edge E; if ( MergeEdges(SeqEdges,aFace,Tol,E) ) { // now we have only one edge - aChain.Value(1) // we have to replace old ListEdges with this new edge aContext->Replace(SeqEdges(1),E); for (Standard_Integer j=2; j<=SeqEdges.Length(); j++) { aContext->Remove(SeqEdges(j)); } TopoDS_Face tmpF = TopoDS::Face(exp.Current()); if ( !ChangedFaces.Contains(tmpF) ) ChangedFaces.Add(tmpF); tmpF = TopoDS::Face(aMapFacesEdges.FindKey(i)); if ( !ChangedFaces.Contains(tmpF) ) ChangedFaces.Add(tmpF); } } } // end processing each face // fix changed faces and replace them in the local context for (Standard_Integer i=1; i<=ChangedFaces.Extent(); i++) { TopoDS_Face aFace = TopoDS::Face(aContext->Apply(ChangedFaces.FindKey(i))); Handle(ShapeFix_Face) sff = new ShapeFix_Face(aFace); sff->SetContext(myContext); sff->SetPrecision(myTolerance); sff->SetMinTolerance(myTolerance); sff->SetMaxTolerance(Max(1.,myTolerance*1000.)); sff->Perform(); aContext->Replace(aFace,sff->Face()); } if (ChangedFaces.Extent() > 0) { // fix changed shell and replace it in the local context TopoDS_Shape aRes1 = aContext->Apply(aRes); TopExp_Explorer expsh; for (expsh.Init(aRes1, TopAbs_SHELL); expsh.More(); expsh.Next()) { TopoDS_Shell aShell = TopoDS::Shell(expsh.Current()); Handle(ShapeFix_Shell) sfsh = new ShapeFix_Shell; sfsh->FixFaceOrientation(aShell); aContext->Replace(aShell,sfsh->Shell()); } TopoDS_Shape aRes2 = aContext->Apply(aRes1); // put new solid into global context myContext->Replace(aSolid,aRes2); } } // end processing each solid aResult = myContext->Apply(Shape); return aResult; }
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; }