// Created on: 1995-06-27 // Created by: Jacques GOUSSARD // Copyright (c) 1995-1999 Matra Datavision // Copyright (c) 1999-2012 OPEN CASCADE SAS // // The content of this file is subject to the Open CASCADE Technology Public // License Version 6.5 (the "License"). You may not use the content of this file // except in compliance with the License. Please obtain a copy of the License // at http://www.opencascade.org and read it completely before using this file. // // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France. // // The Original Code and all software distributed under the License is // distributed on an "AS IS" basis, without warranty of any kind, and the // Initial Developer hereby disclaims all such warranties, including without // limitation, any warranties of merchantability, fitness for a particular // purpose or non-infringement. Please see the License for the specific terms // and conditions governing the rights and limitations under the License. #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 static Standard_Boolean IsInside(const TopoDS_Face&, const TopoDS_Wire&, const TopoDS_Wire&); static Standard_Boolean IsInside(const TopoDS_Face&, const TopoDS_Wire&); static void ChoixUV(const TopoDS_Edge&, const TopoDS_Face&, const TopTools_MapOfShape&, TopTools_MapIteratorOfMapOfShape&, gp_Pnt2d&, gp_Vec2d&, const Standard_Real tol); static TopoDS_Shape ChooseDirection(const TopoDS_Shape&, const TopoDS_Vertex&, const TopoDS_Face&, const TopTools_ListOfShape&); inline Standard_Boolean SameUV(const gp_Pnt2d& P1, const gp_Pnt2d& P2, const BRepAdaptor_Surface& theBAS)//const Standard_Real tol) { // Standard_Real tol = Precision::Confusion(); // return P1.SquareDistance(P2) < 10*tol; //gka Standard_Boolean isSame = Standard_True; if(theBAS.IsUPeriodic()) isSame = (fabs(P1.X() - P2.X()) < theBAS.UPeriod() *0.5); if(theBAS.IsVPeriodic()) isSame = (isSame && (fabs(P1.Y() - P2.Y()) < theBAS.VPeriod() *0.5)); return isSame; //return P1.SquareDistance(P2) < tol * tol; //IFV } //======================================================================= //function : Init //purpose : //======================================================================= void LocOpe_SplitShape::Init(const TopoDS_Shape& S) { myDone = Standard_False; myShape = S; myDblE.Clear(); myMap.Clear(); Put(myShape); } //======================================================================= //function : CanSplit //purpose : //======================================================================= Standard_Boolean LocOpe_SplitShape::CanSplit(const TopoDS_Edge& E) const { if (myDone) { return Standard_False; } if (myMap.IsEmpty()) { return Standard_False; } if (!myMap.IsBound(E)) { return Standard_False; } // On verifie que l`edge n`appartient pas a un wire deja reconstruit TopExp_Explorer exp; TopTools_DataMapIteratorOfDataMapOfShapeListOfShape itm(myMap); for (; itm.More(); itm.Next()) { if (itm.Key().ShapeType() == TopAbs_WIRE && !itm.Value().IsEmpty()) { for (exp.Init(itm.Key(),TopAbs_EDGE); exp.More(); exp.Next()) { if (exp.Current().IsSame(E)) { return Standard_False; } } } } return Standard_True; } //======================================================================= //function : Add //purpose : //======================================================================= void LocOpe_SplitShape::Add(const TopoDS_Vertex& V, const Standard_Real P, const TopoDS_Edge& E) { if (!CanSplit(E)) { Standard_ConstructionError::Raise(); } BRep_Builder B; TopTools_ListOfShape& le = myMap(E); if (le.IsEmpty()) { le.Append(E); } TopTools_ListIteratorOfListOfShape itl(le); Standard_Real f,l; for (; itl.More(); itl.Next()) { const TopoDS_Edge& edg = TopoDS::Edge(itl.Value()); BRep_Tool::Range(edg,f,l); if (P>f && P //======================================================================= void LocOpe_SplitShape::Add(const TopTools_ListOfShape& Lwires, const TopoDS_Face& F) { if (myDone) { Standard_ConstructionError::Raise(); } TopTools_ListOfShape& lf = myMap(F); if (lf.IsEmpty()) { Rebuild(F); } // On cherche la face descendante de F qui continent le wire lf = myMap(F); TopTools_ListIteratorOfListOfShape itl(lf); TopoDS_Vertex Vfirst,Vlast; BRepTools::Update(F); for (; itl.More(); itl.Next()) { const TopoDS_Face& fac = TopoDS::Face(itl.Value()); Standard_Boolean AllWiresInside = Standard_True; TopTools_ListIteratorOfListOfShape itwires(Lwires); for (; itwires.More(); itwires.Next()) { const TopoDS_Wire& aWire = TopoDS::Wire(itwires.Value()); if (!IsInside(fac, aWire)) { AllWiresInside = Standard_False; break; } } if (AllWiresInside) break; } if (!itl.More()) { Standard_ConstructionError::Raise(); } TopoDS_Face FaceRef = TopoDS::Face(itl.Value()); FaceRef.Orientation(TopAbs_FORWARD); lf.Remove(itl); TopTools_ListOfShape NewWires; TopTools_DataMapOfShapeInteger SectionsTimes; for (itl.Initialize(Lwires); itl.More(); itl.Next()) SectionsTimes.Bind(itl.Value(), 2); TopTools_ListOfShape BreakVertices; TopTools_ListOfShape BreakOnWires; TopTools_DataMapOfShapeShape VerWireMap; Standard_Integer i; TopExp_Explorer ExploF, ExploW; for (itl.Initialize(Lwires); itl.More(); itl.Next()) { const TopoDS_Wire& aSection = TopoDS::Wire(itl.Value()); TopoDS_Vertex Ver [2]; TopExp::Vertices(aSection, Ver[0], Ver[1]); for (i = 0; i < 2; i++) { if (VerWireMap.IsBound(Ver[i])) continue; for (ExploF.Init(FaceRef, TopAbs_WIRE); ExploF.More(); ExploF.Next()) { const TopoDS_Shape& aWire = ExploF.Current(); TopoDS_Shape aVer; for (ExploW.Init(aWire, TopAbs_VERTEX); ExploW.More(); ExploW.Next()) { aVer = ExploW.Current(); if (aVer.IsSame(Ver[i])) break; } if (aVer.IsSame(Ver[i])) { VerWireMap.Bind(aVer, aWire); break; } } } } TopTools_DataMapOfShapeListOfShape VerSecMap; for (itl.Initialize(Lwires); itl.More(); itl.Next()) { const TopoDS_Wire& aWire = TopoDS::Wire(itl.Value()); TopoDS_Vertex V1, V2; TopExp::Vertices(aWire, V1, V2); TopTools_ListOfShape LW1, LW2; if (!VerSecMap.IsBound(V1)) VerSecMap.Bind(V1, LW1); VerSecMap(V1).Append(aWire); if (!VerSecMap.IsBound(V2)) VerSecMap.Bind(V2, LW2); VerSecMap(V2).Append(aWire); } //TopTools_IndexedDataMapOfShapeShape InnerTouchingWiresOnVertex; TopoDS_Wire outerW = BRepTools::OuterWire(FaceRef); TopoDS_Wire CurWire = outerW; BRepLib_MakeWire *MW; MW = new BRepLib_MakeWire(); BRepTools_WireExplorer wexp(CurWire, FaceRef); for (;;) { TopoDS_Vertex theStartVertex = wexp.CurrentVertex(), CurVertex; TopoDS_Edge CurEdge = wexp.Current(); TopoDS_Edge LastEdge = CurEdge; MW->Add(CurEdge); TopoDS_Wire aSectionWire; TopoDS_Vertex aBreakVertex; wexp.Next(); if (!wexp.More()) wexp.Init(CurWire, FaceRef); for (;;) { if (MW->Wire().Closed()) break; CurVertex = wexp.CurrentVertex(); if (VerSecMap.IsBound(CurVertex)) { TopoDS_Shape aLocalWire = ChooseDirection(LastEdge, CurVertex, FaceRef, VerSecMap(CurVertex)); aSectionWire = TopoDS::Wire(aLocalWire); break; } CurEdge = wexp.Current(); MW->Add(CurEdge); LastEdge = CurEdge; wexp.Next(); if (!wexp.More()) wexp.Init(CurWire, FaceRef); } if (MW->Wire().Closed()) { NewWires.Append(MW->Wire()); theStartVertex = TopoDS::Vertex(BreakVertices.First()); BreakVertices.RemoveFirst(); CurWire = TopoDS::Wire(BreakOnWires.First()); BreakOnWires.RemoveFirst(); wexp.Init(CurWire, FaceRef); while (!wexp.CurrentVertex().IsSame(theStartVertex)) wexp.Next(); MW = new BRepLib_MakeWire(); continue; } aBreakVertex = CurVertex; BreakVertices.Append(aBreakVertex); BreakOnWires.Append(CurWire); for (;;) { MW->Add(aSectionWire); (SectionsTimes(aSectionWire))--; if (SectionsTimes(aSectionWire) == 0) SectionsTimes.UnBind(aSectionWire); if (MW->Wire().Closed()) { NewWires.Append(MW->Wire()); if (SectionsTimes.IsEmpty()) break; theStartVertex = TopoDS::Vertex(BreakVertices.First()); BreakVertices.RemoveFirst(); CurWire = TopoDS::Wire(BreakOnWires.First()); BreakOnWires.RemoveFirst(); wexp.Init(CurWire, FaceRef); while (!wexp.CurrentVertex().IsSame(theStartVertex)) wexp.Next(); MW = new BRepLib_MakeWire(); break; } else { TopoDS_Vertex V1, V2, aStartVertex; TopExp::Vertices(aSectionWire, V1, V2); aStartVertex = (V1.IsSame(aBreakVertex))? V2 : V1; CurWire = TopoDS::Wire(VerWireMap(aStartVertex)); wexp.Init(CurWire, FaceRef); while (!wexp.CurrentVertex().IsSame(aStartVertex)) wexp.Next(); const TopTools_ListOfShape& Lsections = VerSecMap(aStartVertex); if (Lsections.Extent() == 1) break; //else: choose the way TopoDS_Wire NextSectionWire = TopoDS::Wire((aSectionWire.IsSame(Lsections.First()))? Lsections.Last() : Lsections.First()); Standard_Integer Times = 0; TopTools_DataMapIteratorOfDataMapOfShapeShape itVW(VerWireMap); for (; itVW.More(); itVW.Next()) if (itVW.Value().IsSame(CurWire)) Times++; if (Times == 1) //it is inner touching wire { //InnerTouchingWiresOnVertex.Bind(aWire, aStartVertex); } else { //we have to choose the direction TopoDS_Edge aStartEdge = wexp.Current(); TopTools_ListOfShape Ldirs; Ldirs.Append(aStartEdge); Ldirs.Append(NextSectionWire); TopoDS_Shape theDirection = ChooseDirection(aSectionWire, aStartVertex, FaceRef, Ldirs); if (theDirection.IsSame(aStartEdge)) break; } aSectionWire = NextSectionWire; aBreakVertex = aStartVertex; } //end of else (MW is not closed) } //end of for (;;) (loop on section wires) if (SectionsTimes.IsEmpty()) break; } //end of global for (;;) TopTools_ListOfShape NewFaces; BRep_Builder BB; for (itl.Initialize(NewWires); itl.More(); itl.Next()) { TopoDS_Shape aLocalFace = FaceRef.EmptyCopied(); TopoDS_Face aNewFace = TopoDS::Face(aLocalFace); aNewFace.Orientation(TopAbs_FORWARD); BB.Add(aNewFace, itl.Value()); NewFaces.Append(aNewFace); } //Inserting holes TopTools_ListOfShape Holes; for (ExploF.Init(FaceRef, TopAbs_WIRE); ExploF.More(); ExploF.Next()) { const TopoDS_Shape& aWire = ExploF.Current(); ExploW.Init(aWire, TopAbs_EDGE); TopoDS_Shape anEdge = ExploW.Current(); Standard_Boolean found = Standard_False; for (itl.Initialize(NewWires); itl.More(); itl.Next()) { const TopoDS_Shape& aNewWire = itl.Value(); for (ExploW.Init(aNewWire, TopAbs_EDGE); ExploW.More(); ExploW.Next()) { if (anEdge.IsSame(ExploW.Current())) { found = Standard_True; break; } } if (found) break; } if (!found) Holes.Append(aWire); } TopTools_ListIteratorOfListOfShape itlNewF; for (itl.Initialize(Holes); itl.More(); itl.Next()) { const TopoDS_Wire& aHole = TopoDS::Wire(itl.Value()); for (itlNewF.Initialize(NewFaces); itlNewF.More(); itlNewF.Next()) { TopoDS_Face& aNewFace = TopoDS::Face(itlNewF.Value()); if (IsInside(aNewFace, aHole)) { BB.Add(aNewFace, aHole); break; } } } //Update "myMap" lf.Append(NewFaces); //Update of descendants of wires for (ExploF.Init(F, TopAbs_WIRE); ExploF.More(); ExploF.Next()) { TopTools_ListOfShape& ls = myMap(ExploF.Current()); ls.Clear(); } /////////////////// // JAG 10.11.95 Codage des regularites for (itl.Initialize(Lwires); itl.More(); itl.Next()) for (ExploW.Init(itl.Value(), TopAbs_EDGE); ExploW.More(); ExploW.Next()) { const TopoDS_Edge& edg = TopoDS::Edge(ExploW.Current()); if (!BRep_Tool::HasContinuity(edg,F,F)) { BB.Continuity(edg,F,F,GeomAbs_CN); } } } //======================================================================= //function : Add //purpose : //======================================================================= void LocOpe_SplitShape::Add(const TopoDS_Wire& W, const TopoDS_Face& F) { if (myDone) { Standard_ConstructionError::Raise(); } TopExp_Explorer exp; TopTools_ListOfShape& lf = myMap(F); if (lf.IsEmpty()) { Rebuild(F); } try { OCC_CATCH_SIGNALS if (!LocOpe::Closed(W,F)) { AddOpenWire(W,F); } else { AddClosedWire(W,F); } } catch (Standard_Failure ) { #ifdef DEB cout << "Warning: SpliShape internal problem detected, some faces may be lost. Check input edges/wires" <Value(f); } else { pfirst = C2d->Value(l); } for (exp.Init(W.Oriented(TopAbs_FORWARD),TopAbs_EDGE); exp.More(); exp.Next()) { const TopoDS_Edge& edg = TopoDS::Edge(exp.Current()); if( nbE>1 && edg.IsSame(LastEdge) ) continue; for (exp2.Init(edg,TopAbs_VERTEX); exp2.More(); exp2.Next()) { if (exp2.Current().IsSame(Vlast)) { break; } } if (exp2.More()) { LastEdge = edg; LastEdge.Orientation(edg.Orientation()); break; } } aLocalFace = FaceRef.Oriented(wfirst.Orientation()); C2d = BRep_Tool::CurveOnSurface(LastEdge, TopoDS::Face(aLocalFace), f, l); if (LastEdge.Orientation() == TopAbs_FORWARD) { C2d->D1(l,plast,dlast); } else { C2d->D1(f,plast,dlast); dlast.Reverse(); } Standard_Boolean cond; if(IsPeriodic) { cond = !(Vfirst.IsSame(Vlast) && SameUV(pfirst,plast,BAS)); } else { cond = !(Vfirst.IsSame(Vlast)); } while (cond) { PossE.Clear(); // On enchaine par la fin TopTools_ListIteratorOfListOfShape lexp(WiresFirst); for (; lexp.More(); lexp.Next()) { const TopoDS_Edge& edg = TopoDS::Edge(lexp.Value()); orient = edg.Orientation(); TopExp::Vertices(edg,vdeb,vfin); if (orient == TopAbs_FORWARD && Vlast.IsSame(vdeb)) { PossE.Add(edg.Oriented(orient)); } else if (orient == TopAbs_REVERSED && Vlast.IsSame(vfin)) { PossE.Add(edg.Oriented(orient)); } } nbPoss = PossE.Extent(); if (nbPoss == 0) { break; } if (nbPoss == 1) { itm.Initialize(PossE); TopoDS_Shape aLocalFace = FaceRef.Oriented(wfirst.Orientation()); C2d = BRep_Tool::CurveOnSurface(TopoDS::Edge(itm.Key()), TopoDS::Face(aLocalFace), f, l); if (itm.Key().Orientation() == TopAbs_FORWARD) { C2d->D1(l,plast,dlast); } else { C2d->D1(f,plast,dlast); dlast.Reverse(); } } else if (nbPoss > 1) { // Faire choix en U,V... TopoDS_Shape aLocalFace = FaceRef.Oriented(wfirst.Orientation()); ChoixUV(LastEdge, TopoDS::Face(aLocalFace), PossE, itm, plast, dlast, toll); } if (nbPoss >= 1) { if (MapE.Contains(itm.Key())) break; B.Add(newW1,itm.Key()); MapE.Add(itm.Key()); LastEdge = TopoDS::Edge(itm.Key()); if (LastEdge.Orientation() == TopAbs_FORWARD) { Vlast = TopExp::LastVertex(LastEdge); } else { Vlast = TopExp::FirstVertex(LastEdge); } toll = BRep_Tool::Tolerance(Vlast); tol1 = Max(tolf, toll); } //MODIFICATION PIERRE SMEYERS : si pas de possibilite, on sort avec erreur else{ cout<<"erreur Spliter : pas de chainage du wire"<Value(prm)); // BRepClass_FaceClassifier classif(newFace,pt2d,Precision::PConfusion()); // return (classif.State() == TopAbs_IN); if (!Reversed) { return (classif.Perform(pt2d) == TopAbs_IN); } else { return (classif.Perform(pt2d) == TopAbs_OUT); } } //======================================================================= //function : IsInside //purpose : //======================================================================= static Standard_Boolean IsInside(const TopoDS_Face& F, const TopoDS_Wire& W) { // Attention, c`est tres boeuf !!!! TopExp_Explorer exp(W,TopAbs_EDGE); for( ; exp.More(); exp.Next()) { const TopoDS_Edge& edg = TopoDS::Edge(exp.Current()); // TopExp_Explorer exp2(edg,TopAbs_VERTEX); // const TopoDS_Vertex& vtx = TopoDS::Vertex(exp2.Current()); // Standard_Real prm = BRep_Tool::Parameter(vtx,edg); Standard_Real f,l,prm; Handle(Geom2d_Curve) C2d = BRep_Tool::CurveOnSurface(edg,F,f,l); if (!Precision::IsNegativeInfinite(f) && !Precision::IsPositiveInfinite(l)) { prm = (f+l)/2.; } else { if (Precision::IsNegativeInfinite(f) && Precision::IsPositiveInfinite(l)){ prm = 0.; } else if (Precision::IsNegativeInfinite(f)) { prm = l-1.; } else { prm = f+1.; } } gp_Pnt2d pt2d(C2d->Value(prm)); // BRepClass_FaceClassifier classif(F,pt2d,Precision::PConfusion()); // return (classif.State() != TopAbs_OUT); BRepTopAdaptor_FClass2d classif(F,Precision::PConfusion()); TopAbs_State stat = classif.Perform(pt2d); // return (classif.Perform(pt2d) != TopAbs_OUT); if(stat == TopAbs_OUT) return Standard_False; if(stat == TopAbs_ON) { Standard_Integer nbPnt =10; Standard_Integer nbOut =0,nbIn =0,nbOn=0; Standard_Integer j =1; for( ; j<= nbPnt ; j++) { //check neighbouring point //prm = .66 * prm + .34 * l; prm = f + (l-f)/nbPnt*(j-1); pt2d = C2d->Value(prm); stat = classif.Perform(pt2d); if(stat == TopAbs_OUT ) nbOut++; else if(stat == TopAbs_IN) nbIn++; else nbOn++; } if(nbOut > nbIn + nbOn) return Standard_False; } } return Standard_True; } //======================================================================= //function : ChoixUV //purpose : //======================================================================= static void ChoixUV(const TopoDS_Edge& Last, const TopoDS_Face& F, const TopTools_MapOfShape& Poss, TopTools_MapIteratorOfMapOfShape& It, gp_Pnt2d& plst, gp_Vec2d& dlst, const Standard_Real toll) { Standard_Real f,l; gp_Pnt2d p2d; gp_Vec2d v2d; gp_Pnt aPCur, aPlst; BRepAdaptor_Surface surf(F,Standard_False); // no restriction surf.D0 (plst.X(), plst.Y(), aPlst); Standard_Real tol; TopoDS_Vertex vtx; gp_Dir2d ref2d(dlst); Handle(Geom2d_Curve) C2d; Standard_Integer index = 0, imin=0; Standard_Real angmax = -M_PI, dist, ang; for (It.Initialize(Poss); It.More(); It.Next()) { index++; C2d = BRep_Tool::CurveOnSurface(TopoDS::Edge(It.Key()),F,f,l); if (It.Key().Orientation() == TopAbs_FORWARD) { // p2d = C2d->Value(f); C2d->D1(f,p2d,v2d); vtx = TopExp::FirstVertex(TopoDS::Edge(It.Key())); } else { // p2d = C2d->Value(l); C2d->D1(l,p2d,v2d); v2d.Reverse(); vtx = TopExp::LastVertex(TopoDS::Edge(It.Key())); } surf.D0 (p2d.X(), p2d.Y(), aPCur); tol = BRep_Tool::Tolerance(vtx); tol = Max(toll, tol); tol *= tol; dist = aPCur.SquareDistance(aPlst); if (!Last.IsSame(It.Key())) { ang = ref2d.Angle(gp_Dir2d(v2d)); } else { ang = -M_PI; } //if ((dist < dmin - tol) || //(dist <= dmin+tol && ang > angmax)) { if ((dist < tol) && (ang > angmax)) { imin = index; // dmin = dist; angmax = ang; } } for (index = 1, It.Initialize(Poss); It.More(); It.Next()) { if (index == imin) { C2d = BRep_Tool::CurveOnSurface(TopoDS::Edge(It.Key()),F,f,l); if (It.Key().Orientation() == TopAbs_FORWARD) { // plst = C2d->Value(l); C2d->D1(l,plst,dlst); } else { // plst = C2d->Value(f); C2d->D1(f,plst,dlst); dlst.Reverse(); } break; } index++; } } //======================================================================= //function : ChooseDirection //purpose : //======================================================================= static TopoDS_Shape ChooseDirection(const TopoDS_Shape& RefDir, const TopoDS_Vertex& RefVertex, const TopoDS_Face& theFace, const TopTools_ListOfShape& Ldirs) { TopExp_Explorer Explo(RefDir, TopAbs_EDGE); TopoDS_Edge RefEdge; TopoDS_Vertex V1, V2; TopAbs_Orientation anOr; for (; Explo.More(); Explo.Next()) { RefEdge = TopoDS::Edge(Explo.Current()); TopExp::Vertices(RefEdge, V1, V2); if (V1.IsSame(RefVertex)) { anOr = TopAbs_REVERSED; break; } else if (V2.IsSame(RefVertex)) { anOr = TopAbs_FORWARD; break; } } Standard_Real RefFirst, RefLast; Handle(Geom2d_Curve) RefCurve = BRep_Tool::CurveOnSurface(RefEdge, theFace, RefFirst, RefLast); gp_Pnt2d RefPnt; gp_Vec2d RefVec; //Standard_Real RefPar = (RefEdge.Orientation() == TopAbs_FORWARD)? RefLast : RefFirst; Standard_Real RefPar = (anOr == TopAbs_FORWARD)? RefLast : RefFirst; RefCurve->D1(RefPar, RefPnt, RefVec); if (anOr == TopAbs_FORWARD) RefVec.Reverse(); Handle(Geom2d_Curve) aCurve; Standard_Real aFirst, aLast, aPar; gp_Vec2d aVec; Standard_Real MinAngle = RealLast(), anAngle; TopoDS_Shape TargetDir; TopTools_ListIteratorOfListOfShape itl(Ldirs); for (; itl.More(); itl.Next()) { const TopoDS_Shape& aShape = itl.Value(); TopoDS_Edge anEdge; for (Explo.Init(aShape, TopAbs_EDGE); Explo.More(); Explo.Next()) { anEdge = TopoDS::Edge(Explo.Current()); TopExp::Vertices(anEdge, V1, V2); if (V1.IsSame(RefVertex)) { anOr = TopAbs_FORWARD; break; } else if (V2.IsSame(RefVertex)) { anOr = TopAbs_REVERSED; break; } } aCurve = BRep_Tool::CurveOnSurface(anEdge, theFace, aFirst, aLast); aPar = (anOr == TopAbs_FORWARD)? aFirst : aLast; aCurve->D1(aPar, RefPnt, aVec); if (anOr == TopAbs_REVERSED) aVec.Reverse(); anAngle = aVec.Angle(RefVec); if (anAngle < 0.) anAngle += 2.*M_PI; if (anAngle < MinAngle) { MinAngle = anAngle; TargetDir = aShape; } } return TargetDir; }