// Created on: 1996-01-11 // Created by: Jacques GOUSSARD // Copyright (c) 1996-1999 Matra Datavision // Copyright (c) 1999-2014 OPEN CASCADE SAS // // This file is part of Open CASCADE Technology software library. // // This library is free software; you can redistribute it and/or modify it under // the terms of the GNU Lesser General Public License version 2.1 as published // by the Free Software Foundation, with special exception defined in the file // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT // distribution for complete text of the license and disclaimer of any warranty. // // Alternatively, this file may be used under the terms of Open CASCADE // commercial license or contractual agreement. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IMPLEMENT_STANDARD_RTTIEXT(LocOpe_WiresOnShape,MMgt_TShared) static Standard_Boolean Project(const TopoDS_Vertex&, const gp_Pnt2d&, const TopoDS_Face&, TopoDS_Edge&, Standard_Real&); static Standard_Real Project(const TopoDS_Vertex&, const TopoDS_Edge&); static Standard_Real Project(const TopoDS_Vertex&, const gp_Pnt2d&, const TopoDS_Edge&, const TopoDS_Face&); static void PutPCurve(const TopoDS_Edge&, const TopoDS_Face&); static void PutPCurves(const TopoDS_Edge&, const TopoDS_Edge&, const TopoDS_Shape&); static void FindInternalIntersections(const TopoDS_Edge&, const TopoDS_Face&, TopTools_IndexedDataMapOfShapeListOfShape&, Standard_Boolean&); //======================================================================= //function : LocOpe_WiresOnShape //purpose : //======================================================================= LocOpe_WiresOnShape::LocOpe_WiresOnShape(const TopoDS_Shape& S): myShape(S),myCheckInterior(Standard_True),myDone(Standard_False) {} //======================================================================= //function : Init //purpose : //======================================================================= void LocOpe_WiresOnShape::Init(const TopoDS_Shape& S) { myShape = S; myCheckInterior = Standard_True; myDone = Standard_False; myMap.Clear(); myMapEF.Clear(); } //======================================================================= //function : Bind //purpose : //======================================================================= void LocOpe_WiresOnShape::Bind(const TopoDS_Wire& W, const TopoDS_Face& F) { for (TopExp_Explorer exp(W, TopAbs_EDGE); exp.More(); exp.Next()) { Bind(TopoDS::Edge(exp.Current()),F); } } //======================================================================= //function : Bind //purpose : //======================================================================= void LocOpe_WiresOnShape::Bind(const TopoDS_Compound& Comp, const TopoDS_Face& F) { for (TopExp_Explorer exp(Comp, TopAbs_EDGE); exp.More(); exp.Next()) { Bind(TopoDS::Edge(exp.Current()),F); } myFacesWithSection.Add(F); } //======================================================================= //function : Bind //purpose : //======================================================================= void LocOpe_WiresOnShape::Bind(const TopoDS_Edge& E, const TopoDS_Face& F) { // if (!myMapEF.IsBound(E)) { if (!myMapEF.Contains(E)) { // for (TopExp_Explorer exp(F,TopAbs_EDGE);exp.More();exp.Next()) { TopExp_Explorer exp(F,TopAbs_EDGE) ; for ( ;exp.More();exp.Next()) { if (exp.Current().IsSame(E)) { break; } } if (!exp.More()) { // myMapEF.Bind(E,F); myMapEF.Add(E,F); } } else { Standard_ConstructionError::Raise(); } } //======================================================================= //function : Bind //purpose : //======================================================================= void LocOpe_WiresOnShape::Bind(const TopoDS_Edge& Ewir, const TopoDS_Edge& Efac) { myMap.Bind(Ewir,Efac); } //======================================================================= //function : BindAll //purpose : //======================================================================= void LocOpe_WiresOnShape::BindAll() { if (myDone) { return; } TopTools_MapOfShape theMap; // Detection des vertex a projeter ou a "binder" avec des vertex existants TopTools_DataMapOfShapeShape mapV; TopTools_DataMapIteratorOfDataMapOfShapeShape ite(myMap); TopExp_Explorer exp,exp2; for (; ite.More(); ite.Next()) { const TopoDS_Edge& eref = TopoDS::Edge(ite.Key()); const TopoDS_Edge& eimg = TopoDS::Edge(ite.Value()); PutPCurves(eref,eimg,myShape); for (exp.Init(eref,TopAbs_VERTEX); exp.More(); exp.Next()) { const TopoDS_Vertex& vtx = TopoDS::Vertex(exp.Current()); if (!theMap.Contains(vtx)) { // pas deja traite for (exp2.Init(eimg,TopAbs_VERTEX); exp2.More(); exp2.Next()) { const TopoDS_Vertex& vtx2 = TopoDS::Vertex(exp2.Current()); if (vtx2.IsSame(vtx)) { break; } else if (BRepTools::Compare(vtx,vtx2)) { mapV.Bind(vtx,vtx2); break; } } if (!exp2.More()) { mapV.Bind(vtx,eimg); } theMap.Add(vtx); } } } for (ite.Initialize(mapV); ite.More(); ite.Next()) { myMap.Bind(ite.Key(),ite.Value()); } TopTools_IndexedDataMapOfShapeListOfShape Splits; Standard_Integer Ind; TopTools_MapOfShape anOverlappedEdges; for (Ind = 1; Ind <= myMapEF.Extent(); Ind++) { const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(Ind)); const TopoDS_Face& fac = TopoDS::Face(myMapEF(Ind)); PutPCurve(edg,fac); Standard_Real pf, pl; Handle(Geom2d_Curve) aPCurve = BRep_Tool::CurveOnSurface(edg, fac, pf, pl); if (aPCurve.IsNull()) continue; if (myCheckInterior) { Standard_Boolean isOverlapped = Standard_False; FindInternalIntersections(edg, fac, Splits, isOverlapped); if(isOverlapped) anOverlappedEdges.Add(edg); } } for (Ind = 1; Ind <= Splits.Extent(); Ind++) { TopoDS_Shape anEdge = Splits.FindKey(Ind); if(anOverlappedEdges.Contains(anEdge)) continue; TopoDS_Shape aFace = myMapEF.FindFromKey(anEdge); //Remove "anEdge" from "myMapEF" TopoDS_Shape LastEdge = myMapEF.FindKey(myMapEF.Extent()); TopoDS_Shape LastFace = myMapEF(myMapEF.Extent()); myMapEF.RemoveLast(); if (myMapEF.FindIndex(anEdge) != 0) myMapEF.Substitute(myMapEF.FindIndex(anEdge), LastEdge, LastFace); //////////////////////////////// TopTools_ListIteratorOfListOfShape itl(Splits(Ind)); for (; itl.More(); itl.Next()) myMapEF.Add(itl.Value(), aFace); } TopTools_DataMapOfShapeReal aVertParam; for (Ind = 1; Ind <= myMapEF.Extent(); Ind++) { const TopoDS_Edge& edg = TopoDS::Edge(myMapEF.FindKey(Ind)); const TopoDS_Face& fac = TopoDS::Face(myMapEF(Ind)); // JAG 02.02.96 : On verifie les pcurves... //PutPCurve(edg,fac); for (exp.Init(edg,TopAbs_VERTEX); exp.More(); exp.Next()) { const TopoDS_Vertex& vtx = TopoDS::Vertex(exp.Current()); if (theMap.Contains(vtx)) { continue; } Standard_Real vtx_param = BRep_Tool::Parameter(vtx, edg); BRepAdaptor_Curve2d BAcurve2d(edg, fac); gp_Pnt2d p2d = (!BAcurve2d.Curve().IsNull() ? BAcurve2d.Value(vtx_param) : gp_Pnt2d(Precision::Infinite(), Precision::Infinite())); TopoDS_Edge Epro; Standard_Real prm = Precision::Infinite(); Standard_Boolean isProjected = myMap.IsBound(vtx); //if vertex was already projected on the current edge on the previous face //it is necessary to check tolerance of the vertex in the 2D space on the current //face without projection and update tolerance of vertex if it is necessary if (isProjected) { TopoDS_Shape aSh = myMap.Find(vtx); if (aSh.ShapeType() != TopAbs_EDGE) continue; Epro = TopoDS::Edge(myMap.Find(vtx)); if (aVertParam.IsBound(vtx)) prm = aVertParam.Find(vtx); } Standard_Boolean ok = Project(vtx, p2d, fac, Epro, prm); if (ok && !isProjected) { for (exp2.Init(Epro, TopAbs_VERTEX); exp2.More(); exp2.Next()) { const TopoDS_Vertex& vtx2 = TopoDS::Vertex(exp2.Current()); if (vtx2.IsSame(vtx)) { myMap.Bind(vtx, vtx2); theMap.Add(vtx); break; } else if (BRepTools::Compare(vtx, vtx2)) { Standard_Real aF1, aL1; BRep_Tool::Range(Epro, fac, aF1, aL1); if (!BRep_Tool::Degenerated(Epro) && ( Abs(prm - aF1) <= Precision::PConfusion() || Abs(prm - aL1) <= Precision::PConfusion())) { myMap.Bind(vtx, vtx2); theMap.Add(vtx); break; } } } if (!exp2.More()) { myMap.Bind(vtx,Epro); aVertParam.Bind(vtx, prm); } } } } // Modified by Sergey KHROMOV - Mon Feb 12 16:26:50 2001 Begin for (ite.Initialize(myMap); ite.More(); ite.Next()) if ((ite.Key()).ShapeType() == TopAbs_EDGE) myMapEF.Add(ite.Key(),ite.Value()); // Modified by Sergey KHROMOV - Mon Feb 12 16:26:52 2001 End myDone = Standard_True; } //======================================================================= //function : InitEdgeIterator //purpose : //======================================================================= void LocOpe_WiresOnShape::InitEdgeIterator() { BindAll(); // myIt.Initialize(myMapEF); myIndex = 1; } //======================================================================= //function : MoreEdge //purpose : //======================================================================= Standard_Boolean LocOpe_WiresOnShape::MoreEdge() { // return myIt.More(); return (myIndex <= myMapEF.Extent()); } //======================================================================= //function : Edge //purpose : //======================================================================= TopoDS_Edge LocOpe_WiresOnShape::Edge() { // return TopoDS::Edge(myIt.Key()); return TopoDS::Edge(myMapEF.FindKey(myIndex)); } //======================================================================= //function : Face //purpose : //======================================================================= TopoDS_Face LocOpe_WiresOnShape::OnFace() { // return TopoDS::Face(myIt.Value()); return TopoDS::Face(myMapEF(myIndex)); } //======================================================================= //function : OnEdge //purpose : //======================================================================= Standard_Boolean LocOpe_WiresOnShape::OnEdge(TopoDS_Edge& E) { // if (myMap.IsBound(myIt.Key())) { if (myMap.IsBound(myMapEF.FindKey(myIndex))) { // E = TopoDS::Edge(myMap(myIt.Key())); E = TopoDS::Edge(myMap(myMapEF.FindKey(myIndex))); return Standard_True; } return Standard_False; } //======================================================================= //function : NextEdge //purpose : //======================================================================= void LocOpe_WiresOnShape::NextEdge() { // myIt.Next(); myIndex++; } //======================================================================= //function : OnVertex //purpose : //======================================================================= Standard_Boolean LocOpe_WiresOnShape::OnVertex(const TopoDS_Vertex& Vw, TopoDS_Vertex& Vs) { if (myMap.IsBound(Vw)) { if (myMap(Vw).ShapeType() == TopAbs_VERTEX) { Vs = TopoDS::Vertex(myMap(Vw)); return Standard_True; } return Standard_False; } return Standard_False; } //======================================================================= //function : OnEdge //purpose : //======================================================================= Standard_Boolean LocOpe_WiresOnShape::OnEdge(const TopoDS_Vertex& V, TopoDS_Edge& Ed, Standard_Real& prm) { if (!myMap.IsBound(V) || myMap(V).ShapeType() == TopAbs_VERTEX) { return Standard_False; } Ed = TopoDS::Edge(myMap(V)); prm = Project(V,Ed); return Standard_True; } //======================================================================= //function : OnEdge //purpose : //======================================================================= Standard_Boolean LocOpe_WiresOnShape::OnEdge(const TopoDS_Vertex& V, const TopoDS_Edge& EdgeFrom, TopoDS_Edge& Ed, Standard_Real& prm) { if (!myMap.IsBound(V) || myMap(V).ShapeType() == TopAbs_VERTEX) { return Standard_False; } Ed = TopoDS::Edge(myMap(V)); if(!myMapEF.Contains(EdgeFrom)) return Standard_False; TopoDS_Shape aShape = myMapEF.FindFromKey(EdgeFrom); Standard_Real aF, aL; Handle(Geom_Curve) aC = BRep_Tool::Curve(Ed, aF, aL); if (aC.IsNull() && aShape.ShapeType() == TopAbs_FACE) { TopoDS_Face aFace = TopoDS::Face(aShape); Standard_Real vtx_param = BRep_Tool::Parameter(V, EdgeFrom); BRepAdaptor_Curve2d BAcurve2d(EdgeFrom, aFace); gp_Pnt2d p2d = BAcurve2d.Value(vtx_param); prm = Project(V, p2d, Ed, aFace); } else prm = Project( V, TopoDS::Edge(Ed)); return Standard_True; } //======================================================================= //function : Project //purpose : //======================================================================= Standard_Boolean Project(const TopoDS_Vertex& V, const gp_Pnt2d& p2d, const TopoDS_Face& F, TopoDS_Edge& theEdge, Standard_Real& param) { Standard_Real aTolV = BRep_Tool::Tolerance(V); Standard_Real dmin = (theEdge.IsNull() ? RealLast() : aTolV * aTolV); Standard_Boolean valret = Standard_False; Handle(Geom_Surface) aSurf = BRep_Tool::Surface(F); if (theEdge.IsNull()) { gp_Pnt toproj(BRep_Tool::Pnt(V)); for (TopExp_Explorer exp(F.Oriented(TopAbs_FORWARD), TopAbs_EDGE); exp.More(); exp.Next()) { const TopoDS_Edge& edg = TopoDS::Edge(exp.Current()); Standard_Real f, l; Handle(Geom_Curve) C = BRep_Tool::Curve(edg, f, l); Standard_Real aCurDist = Precision::Infinite(); Standard_Real aCurPar = Precision::Infinite(); if (!C.IsNull()) { aCurPar = Project(V, edg); if (Precision::IsInfinite(aCurPar)) continue; gp_Pnt aCurPBound; C->D0(aCurPar, aCurPBound); aCurDist = aCurPBound.SquareDistance(toproj); } else if(!Precision::IsInfinite(p2d.X())) { //Geom2dAPI_ProjectPointOnCurve proj; Handle(Geom2d_Curve) aC2d = BRep_Tool::CurveOnSurface(edg,F , f, l); if(aC2d.IsNull()) continue; aCurPar = Project(V, p2d, edg, F); if (Precision::IsInfinite(aCurPar)) continue; Handle(Geom2d_Curve) PC = BRep_Tool::CurveOnSurface(edg, F, f, l); gp_Pnt2d aPProj; PC->D0(aCurPar, aPProj); gp_Pnt aCurPBound; aSurf->D0(aPProj.X(), aPProj.Y(), aCurPBound); aCurDist = aCurPBound.SquareDistance(toproj); } if (aCurDist < dmin) { theEdge = edg; theEdge.Orientation(edg.Orientation()); dmin = aCurDist; param = aCurPar; } } if (theEdge.IsNull()) return Standard_False; } else if (Precision::IsInfinite(param)) { Standard_Real f, l; Handle(Geom_Curve) C = BRep_Tool::Curve(theEdge, f, l); param = (!C.IsNull() ? Project(V, theEdge) : Project(V, p2d, theEdge, F)); } Standard_Real ttol = aTolV + BRep_Tool::Tolerance(theEdge); if (dmin <= ttol* ttol) { valret = Standard_True; GeomAdaptor_Surface adSurf(aSurf); Standard_Real anUResolution = adSurf.UResolution(1.); Standard_Real aVResolution = adSurf.UResolution(1.); Standard_Real f, l; Handle(Geom2d_Curve) aCrvBound = BRep_Tool::CurveOnSurface(theEdge, F, f, l); if (!aCrvBound.IsNull()) { gp_Pnt2d aPBound2d; aCrvBound->D0(param, aPBound2d); //distance in 2D space recomputed in the 3D space in order to tolerance of vertex //cover gap in 2D space. For consistency with check of the validity in the BRepCheck_Wire Standard_Real aDist3d = p2d.Distance(aPBound2d) / Min(anUResolution, aVResolution); gp_Pnt aPBound; aSurf->D0(aPBound2d.X(), aPBound2d.Y(), aPBound); gp_Pnt aPV2d; aSurf->D0(p2d.X(), p2d.Y(), aPV2d); Standard_Real aDistPoints_3D = aPV2d.SquareDistance(aPBound); Standard_Real aDist2d = Max(aDistPoints_3D, aDist3d * aDist3d); BRep_Builder B; if (aTolV * aTolV < aDist2d) { Standard_Real aNewTol = sqrt(aDist2d) + Precision::Confusion(); B.UpdateVertex(V, aNewTol); } } } #ifdef OCCT_DEBUG_MESH else { cout <<"LocOpe_WiresOnShape::Project --> le vertex projete est a une "; cout <<"distance / la face = "<= 2) //intersection is inside "theEdge" => split { gp_Pnt aPoint = aCurve->Value(anIntPar); gp_Pnt aPointInt = theCurve->Value(theIntPar); if (aPointInt.SquareDistance(thePnt[0]) > aTolV[0] * aTolV[0] && aPointInt.SquareDistance(thePnt[1]) > aTolV[1] * aTolV[1] && aPoint.SquareDistance(thePnt[0]) > aTolV[0] * aTolV[0] && aPoint.SquareDistance(thePnt[1]) > aTolV[1] * aTolV[1]) { SplitPars.Append(theIntPar); if( aDist > aDistMax) aDistMax = aDist; } } } } if (SplitPars.IsEmpty()) return; //Sort for (i = 1; i < SplitPars.Length(); i++) for (j = i+1; j <= SplitPars.Length(); j++) if (SplitPars(i) > SplitPars(j)) { Standard_Real Tmp = SplitPars(i); SplitPars(i) = SplitPars(j); SplitPars(j) = Tmp; } //Remove repeating points i = 1; while (i < SplitPars.Length()) { gp_Pnt Pnt1 = theCurve->Value(SplitPars(i)); gp_Pnt Pnt2 = theCurve->Value(SplitPars(i+1)); if (Pnt1.SquareDistance(Pnt2) <= Precision::Confusion()* Precision::Confusion()) SplitPars.Remove(i+1); else i++; } //Split TopTools_ListOfShape NewEdges; BRep_Builder BB; TopoDS_Vertex FirstVertex = theVertices[0], LastVertex; Standard_Real FirstPar = thePar[0], LastPar; for (i = 1; i <= SplitPars.Length()+1; i++) { FirstVertex.Orientation(TopAbs_FORWARD); if (i <= SplitPars.Length()) { LastPar = SplitPars(i); gp_Pnt LastPoint = theCurve->Value(LastPar); LastVertex = BRepLib_MakeVertex(LastPoint); BRep_Builder aB; aB.UpdateVertex(LastVertex, sqrt(aDistMax)); } else { LastPar = thePar[1]; LastVertex = theVertices[1]; } LastVertex.Orientation(TopAbs_REVERSED); TopoDS_Shape aLocalShape = theEdge.EmptyCopied(); TopAbs_Orientation anOrient = aLocalShape.Orientation(); aLocalShape.Orientation(TopAbs_FORWARD); TopoDS_Edge NewEdge = TopoDS::Edge(aLocalShape); BB.Range(NewEdge, FirstPar, LastPar); BB.Add(NewEdge, FirstVertex); BB.Add(NewEdge, LastVertex); NewEdge.Orientation(anOrient); ShapeAnalysis_Edge aSae; Standard_Real amaxdev =0.; if (aSae.CheckSameParameter(NewEdge, theFace, amaxdev)) { BRep_Builder aB; aB.UpdateEdge(NewEdge, amaxdev); } if (anOrient == TopAbs_FORWARD) NewEdges.Append(NewEdge); else NewEdges.Prepend(NewEdge); FirstVertex = LastVertex; FirstPar = LastPar; } if (!NewEdges.IsEmpty()) Splits.Add(theEdge, NewEdges); } //======================================================================= //function : AddSplittingEdges //purpose : //======================================================================= Standard_Boolean LocOpe_WiresOnShape::Add(const TopTools_SequenceOfShape& theEdges) { TopTools_SequenceOfShape anEdges; Bnd_SeqOfBox anEdgeBoxes; Standard_Integer i = 1, nb = theEdges.Length(); for (; i <= nb; i++) { const TopoDS_Shape& aCurSplit = theEdges(i); TopExp_Explorer anExpE(aCurSplit, TopAbs_EDGE); for (; anExpE.More(); anExpE.Next()) { const TopoDS_Shape& aCurE = anExpE.Current(); Bnd_Box aBoxE; BRepBndLib::AddClose(aCurE, aBoxE); if (aBoxE.IsVoid()) continue; Standard_Real aTolE = BRep_Tool::Tolerance(TopoDS::Edge(aCurE)); aBoxE.SetGap(aTolE); anEdgeBoxes.Append(aBoxE); anEdges.Append(aCurE); } } TopExp_Explorer anExpFaces(myShape, TopAbs_FACE); Standard_Integer numF = 1; TColStd_PackedMapOfInteger anUsedEdges; for (; anExpFaces.More(); anExpFaces.Next(), numF++) { const TopoDS_Face& aCurF = TopoDS::Face(anExpFaces.Current()); Bnd_Box aBoxF; BRepBndLib::Add(aCurF, aBoxF); if (aBoxF.IsVoid()) continue; BRepAdaptor_Surface anAdF(aCurF, Standard_False); NCollection_Handle aCheckStateTool; i = 1; nb = anEdgeBoxes.Length(); for (; i <= nb; i++) { if (anUsedEdges.Contains(i)) continue; if (aBoxF.IsOut(anEdgeBoxes(i))) continue; const TopoDS_Edge& aCurE = TopoDS::Edge(anEdges(i)); Standard_Real aF, aL; Handle(Geom_Curve) aC = BRep_Tool::Curve(aCurE, aF, aL); if (aC.IsNull()) { anUsedEdges.Add(i); continue; } gp_Pnt aP = aC->Value((aF + aL)* 0.5); Extrema_ExtPS anExtr(aP, anAdF, Precision::Confusion(), Precision::Confusion()); if (!anExtr.IsDone() || !anExtr.NbExt()) continue; Standard_Real aTolE = BRep_Tool::Tolerance(TopoDS::Edge(aCurE)); Standard_Real aTol2 = (aTolE + Precision::Confusion()) * (aTolE + Precision::Confusion()); Standard_Integer n = 1; for (; n <= anExtr.NbExt(); n++) { Standard_Real aDist2 = anExtr.SquareDistance(n); if (aDist2 > aTol2) continue; const Extrema_POnSurf& aPS = anExtr.Point(n); Standard_Real aU, aV; aPS.Parameter(aU, aV); if (aCheckStateTool.IsNull()) { aCheckStateTool = new BRepTopAdaptor_FClass2d(aCurF, Precision::PConfusion()); } if (aCheckStateTool->Perform(gp_Pnt2d(aU, aV)) == TopAbs_IN) { Bind(aCurE, aCurF); anUsedEdges.Add(i); } } } } return !anUsedEdges.IsEmpty(); }